This commit is contained in:
syuilo 2017-12-14 16:24:41 +09:00
parent cd8b976b8e
commit 7069aea5bb
17 changed files with 295 additions and 44 deletions

View file

@ -13,6 +13,7 @@ import * as es from 'event-stream';
import cssnano = require('gulp-cssnano'); import cssnano = require('gulp-cssnano');
import * as uglifyComposer from 'gulp-uglify/composer'; import * as uglifyComposer from 'gulp-uglify/composer';
import pug = require('gulp-pug'); import pug = require('gulp-pug');
import stylus = require('gulp-stylus');
import * as rimraf from 'rimraf'; import * as rimraf from 'rimraf';
import chalk from 'chalk'; import chalk from 'chalk';
import imagemin = require('gulp-imagemin'); import imagemin = require('gulp-imagemin');
@ -47,15 +48,32 @@ if (isDebug) {
const constants = require('./src/const.json'); const constants = require('./src/const.json');
require('./src/web/docs/api/endpoints/gulpfile.ts');
gulp.task('build', [ gulp.task('build', [
'build:js', 'build:js',
'build:ts', 'build:ts',
'build:copy', 'build:copy',
'build:client' 'build:client',
'build:doc'
]); ]);
gulp.task('rebuild', ['clean', 'build']); gulp.task('rebuild', ['clean', 'build']);
gulp.task('build:doc', [
'doc:endpoints',
'doc:styles'
]);
gulp.task('doc:styles', () =>
gulp.src('./src/web/docs/**/*.styl')
.pipe(stylus())
.pipe(isProduction
? (cssnano as any)()
: gutil.noop())
.pipe(gulp.dest('./built/web/assets/docs/'))
);
gulp.task('build:js', () => gulp.task('build:js', () =>
gulp.src(['./src/**/*.js', '!./src/web/**/*.js']) gulp.src(['./src/**/*.js', '!./src/web/**/*.js'])
.pipe(gulp.dest('./built/')) .pipe(gulp.dest('./built/'))

View file

@ -53,6 +53,7 @@
"@types/is-root": "1.0.0", "@types/is-root": "1.0.0",
"@types/is-url": "1.2.28", "@types/is-url": "1.2.28",
"@types/js-yaml": "3.10.1", "@types/js-yaml": "3.10.1",
"@types/mkdirp": "^0.5.2",
"@types/mocha": "2.2.44", "@types/mocha": "2.2.44",
"@types/mongodb": "2.2.17", "@types/mongodb": "2.2.17",
"@types/monk": "1.0.6", "@types/monk": "1.0.6",
@ -62,6 +63,7 @@
"@types/node": "8.5.1", "@types/node": "8.5.1",
"@types/page": "1.5.32", "@types/page": "1.5.32",
"@types/proxy-addr": "2.0.0", "@types/proxy-addr": "2.0.0",
"@types/pug": "^2.0.4",
"@types/qrcode": "0.8.0", "@types/qrcode": "0.8.0",
"@types/ratelimiter": "2.1.28", "@types/ratelimiter": "2.1.28",
"@types/redis": "2.8.3", "@types/redis": "2.8.3",
@ -112,6 +114,7 @@
"gulp-pug": "3.3.0", "gulp-pug": "3.3.0",
"gulp-rename": "1.2.2", "gulp-rename": "1.2.2",
"gulp-replace": "0.6.1", "gulp-replace": "0.6.1",
"gulp-stylus": "^2.6.0",
"gulp-tslint": "8.1.2", "gulp-tslint": "8.1.2",
"gulp-typescript": "3.2.3", "gulp-typescript": "3.2.3",
"gulp-uglify": "3.0.0", "gulp-uglify": "3.0.0",
@ -122,6 +125,7 @@
"is-url": "1.2.2", "is-url": "1.2.2",
"js-yaml": "3.10.0", "js-yaml": "3.10.0",
"mecab-async": "0.1.2", "mecab-async": "0.1.2",
"mkdirp": "^0.5.1",
"mocha": "4.0.1", "mocha": "4.0.1",
"moji": "0.5.1", "moji": "0.5.1",
"mongodb": "2.2.33", "mongodb": "2.2.33",

View file

@ -1,29 +1,4 @@
json('../../const.json') @import "../style"
@charset 'utf-8'
$theme-color = themeColor
$theme-color-foreground = themeColorForeground
/*
::selection
background $theme-color
color #fff
*/
*
position relative
box-sizing border-box
background-clip padding-box !important
tap-highlight-color rgba($theme-color, 0.7)
-webkit-tap-highlight-color rgba($theme-color, 0.7)
html, body
margin 0
padding 0
scroll-behavior smooth
text-size-adjust 100%
font-family sans-serif
html html
&.progress &.progress
@ -96,17 +71,6 @@ body
100% 100%
transform rotate(360deg) transform rotate(360deg)
a
text-decoration none
color $theme-color
cursor pointer
&:hover
text-decoration underline
*
cursor pointer
code code
font-family Consolas, 'Courier New', Courier, Monaco, monospace font-family Consolas, 'Courier New', Courier, Monaco, monospace

View file

@ -0,0 +1,75 @@
/**
* Gulp tasks
*/
import * as fs from 'fs';
import * as path from 'path';
import * as glob from 'glob';
import * as gulp from 'gulp';
import * as pug from 'pug';
import * as yaml from 'js-yaml';
import * as mkdirp from 'mkdirp';
import config from './../../../../conf';
const parseParam = param => {
const id = param.type.match(/^id\((.+?)\)/);
const object = param.type.match(/^object\((.+?)\)/);
const isArray = /\[\]$/.test(param.type);
if (id) {
param.kind = 'id';
param.type = 'string';
param.entity = id[1];
if (isArray) {
param.type += '[]';
}
}
if (object) {
param.kind = 'object';
param.type = 'object';
param.def = object[1];
if (isArray) {
param.type += '[]';
}
}
return param;
};
gulp.task('doc:endpoints', () => {
glob('./src/web/docs/api/endpoints/**/*.yaml', (globErr, files) => {
if (globErr) {
console.error(globErr);
return;
}
//console.log(files);
files.forEach(file => {
const ep = yaml.safeLoad(fs.readFileSync(file, 'utf-8'));
const vars = {
endpoint: ep.endpoint,
url: `${config.api_url}/${ep.endpoint}`,
desc: ep.desc,
params: ep.params.map(p => parseParam(p)),
paramDefs: Object.keys(ep.paramDefs).map(key => ({
name: key,
params: ep.paramDefs[key].map(p => parseParam(p))
})),
res: ep.res.map(p => parseParam(p))
};
pug.renderFile('./src/web/docs/api/endpoints/view.pug', vars, (renderErr, html) => {
if (renderErr) {
console.error(renderErr);
return;
}
const htmlPath = `./built/web/docs/api/endpoints/${ep.endpoint}.html`;
mkdirp(path.dirname(htmlPath), (mkdirErr) => {
if (mkdirErr) {
console.error(mkdirErr);
return;
}
fs.writeFileSync(htmlPath, html, 'utf-8');
});
});
});
});
});

View file

@ -7,31 +7,31 @@ desc:
params: params:
- name: "text" - name: "text"
type: "string" type: "string"
required: true optional: false
desc: desc:
ja: "投稿の本文" ja: "投稿の本文"
en: "Text of a post" en: "Text of a post"
- name: "media_ids" - name: "media_ids"
type: "id(DriveFile)[]" type: "id(DriveFile)[]"
required: false optional: true
desc: desc:
ja: "添付するメディア" ja: "添付するメディア"
en: "Media you want to attach" en: "Media you want to attach"
- name: "reply_id" - name: "reply_id"
type: "id(Post)" type: "id(Post)"
required: false optional: true
desc: desc:
ja: "返信する投稿" ja: "返信する投稿"
en: "A post you want to reply" en: "A post you want to reply"
- name: "repost_id" - name: "repost_id"
type: "id(Post)" type: "id(Post)"
required: false optional: true
desc: desc:
ja: "引用する投稿" ja: "引用する投稿"
en: "A post you want to quote" en: "A post you want to quote"
- name: "poll" - name: "poll"
type: "object(poll)" type: "object(poll)"
required: false optional: true
desc: desc:
ja: "投票" ja: "投票"
en: "A poll" en: "A poll"
@ -40,7 +40,7 @@ paramDefs:
poll: poll:
- name: "choices" - name: "choices"
type: "string[]" type: "string[]"
required: true optional: false
desc: desc:
ja: "投票の選択肢" ja: "投票の選択肢"
en: "Choices of a poll" en: "Choices of a poll"
@ -48,6 +48,7 @@ paramDefs:
res: res:
- name: "created_post" - name: "created_post"
type: "entity(Post)" type: "entity(Post)"
optional: false
desc: desc:
ja: "作成した投稿" ja: "作成した投稿"
en: "A post that created" en: "A post that created"

View file

@ -0,0 +1,16 @@
@import "../../style"
#url
padding 8px 12px
font-family Consolas, 'Courier New', Courier, Monaco, monospace
color #fff
background #222e40
border-radius 4px
table
.name
font-weight bold
.type
font-family Consolas, 'Courier New', Courier, Monaco, monospace

View file

@ -0,0 +1,60 @@
doctype html
mixin i18n(xs)
each text, lang in xs
span(class=`i18n ${lang}`)= text
mixin table(params)
table
thead: tr
th Name
th Type
th Optional
th Description
tbody
each param in params
tr
td.name= param.name
td.type
if param.kind == 'id'
| #{param.type} (ID of
= ' '
a(href=`/docs/api/entities/${param.entity}`)= param.entity
| )
else if param.kind == 'object'
| #{param.type} (
a(href=`#${param.def}`)= param.def
| )
else
= param.type
td.optional= param.optional.toString()
td.desc: +i18n(param.desc)
html
head
meta(charset="UTF-8")
title #{endpoint} | Misskey API
link(rel="stylesheet" href="/assets/docs/api/endpoints/style.css")
body
main
h1= endpoint
p#url= url
p#desc: +i18n(desc)
section
h2 Params
+table(params)
if paramDefs
each paramDef in paramDefs
section(id= paramDef.name)
h3= paramDef.name
+table(paramDef.params)
section
h2 Response
+table(res)

69
src/web/docs/style.styl Normal file
View file

@ -0,0 +1,69 @@
@import "../style"
body
margin 0
color #34495e
main
padding 32px
width 100%
max-width 700px
footer
padding:32px 0 0 0
margin 32px 0 0 0
border-top solid 1px #eee
.copyright
margin 16px 0 0 0
color #aaa
section
margin 32px 0
h1
margin 0 0 24px 0
padding 16px 0
font-size 1.5em
border-bottom solid 2px #eee
h2
margin 0 0 24px 0
padding 0 0 16px 0
font-size 1.4em
border-bottom solid 1px #eee
h3
margin 0
padding 0
font-size 1.25em
h4
margin 0
p
margin 1em 0
line-height 1.6em
table
width 100%
border-spacing 0
border-collapse collapse
thead
font-weight bold
border-bottom solid 2px #eee
tr
th
text-align left
tbody
tr
border-bottom dashed 1px #eee
th, td
padding 8px 16px
.i18n:not(.ja)
display none

View file

@ -63,6 +63,12 @@ app.get('/manifest.json', (req, res) =>
*/ */
app.get(/\/api:url/, require('./service/url-preview')); app.get(/\/api:url/, require('./service/url-preview'));
/**
* Docs
*/
app.get(/^\/docs\/([a-z_\-\/]+?)$/, (req, res) =>
res.sendFile(`${__dirname}/docs/${req.params[0]}.html`));
/** /**
* Routing * Routing
*/ */

38
src/web/style.styl Normal file
View file

@ -0,0 +1,38 @@
json('../const.json')
@charset 'utf-8'
$theme-color = themeColor
$theme-color-foreground = themeColorForeground
/*
::selection
background $theme-color
color #fff
*/
*
position relative
box-sizing border-box
background-clip padding-box !important
tap-highlight-color rgba($theme-color, 0.7)
-webkit-tap-highlight-color rgba($theme-color, 0.7)
html, body
margin 0
padding 0
scroll-behavior smooth
text-size-adjust 100%
font-family sans-serif
a
text-decoration none
color $theme-color
cursor pointer
&:hover
text-decoration underline
*
cursor pointer