✌️
This commit is contained in:
parent
a357d5c6a5
commit
d6ec5f2fe1
11 changed files with 305 additions and 80 deletions
|
@ -48,7 +48,7 @@ if (isDebug) {
|
||||||
|
|
||||||
const constants = require('./src/const.json');
|
const constants = require('./src/const.json');
|
||||||
|
|
||||||
require('./src/web/docs/api/endpoints/gulpfile.ts');
|
require('./src/web/docs/api/gulpfile.ts');
|
||||||
|
|
||||||
gulp.task('build', [
|
gulp.task('build', [
|
||||||
'build:js',
|
'build:js',
|
||||||
|
@ -61,7 +61,7 @@ gulp.task('build', [
|
||||||
gulp.task('rebuild', ['clean', 'build']);
|
gulp.task('rebuild', ['clean', 'build']);
|
||||||
|
|
||||||
gulp.task('build:doc', [
|
gulp.task('build:doc', [
|
||||||
'doc:endpoints',
|
'doc:api',
|
||||||
'doc:styles'
|
'doc:styles'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ params:
|
||||||
optional: true
|
optional: true
|
||||||
desc:
|
desc:
|
||||||
ja: "投稿の本文"
|
ja: "投稿の本文"
|
||||||
en: "Text of a post"
|
en: "The text of your post"
|
||||||
- name: "media_ids"
|
- name: "media_ids"
|
||||||
type: "id(DriveFile)[]"
|
type: "id(DriveFile)[]"
|
||||||
optional: true
|
optional: true
|
||||||
|
@ -22,19 +22,19 @@ params:
|
||||||
optional: true
|
optional: true
|
||||||
desc:
|
desc:
|
||||||
ja: "返信する投稿"
|
ja: "返信する投稿"
|
||||||
en: "A post you want to reply"
|
en: "The post you want to reply"
|
||||||
- name: "repost_id"
|
- name: "repost_id"
|
||||||
type: "id(Post)"
|
type: "id(Post)"
|
||||||
optional: true
|
optional: true
|
||||||
desc:
|
desc:
|
||||||
ja: "引用する投稿"
|
ja: "引用する投稿"
|
||||||
en: "A post you want to quote"
|
en: "The post you want to quote"
|
||||||
- name: "poll"
|
- name: "poll"
|
||||||
type: "object"
|
type: "object"
|
||||||
optional: true
|
optional: true
|
||||||
desc:
|
desc:
|
||||||
ja: "投票"
|
ja: "投票"
|
||||||
en: "A poll"
|
en: "The poll"
|
||||||
defName: "poll"
|
defName: "poll"
|
||||||
def:
|
def:
|
||||||
- name: "choices"
|
- name: "choices"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
@import "../../style"
|
@import "../style"
|
||||||
|
|
||||||
#url
|
#url
|
||||||
padding 8px 12px
|
padding 8px 12px
|
||||||
|
@ -6,13 +6,3 @@
|
||||||
color #fff
|
color #fff
|
||||||
background #222e40
|
background #222e40
|
||||||
border-radius 4px
|
border-radius 4px
|
||||||
|
|
||||||
table
|
|
||||||
.name
|
|
||||||
font-weight bold
|
|
||||||
|
|
||||||
.name
|
|
||||||
.type
|
|
||||||
.optional
|
|
||||||
font-family Consolas, 'Courier New', Courier, Monaco, monospace
|
|
||||||
|
|
||||||
|
|
|
@ -1,63 +1,30 @@
|
||||||
doctype html
|
extends ../../layout.pug
|
||||||
|
include ../mixins
|
||||||
|
|
||||||
mixin i18n(xs)
|
block title
|
||||||
each text, lang in xs
|
| #{endpoint} | Misskey API
|
||||||
span(class=`i18n ${lang}`)= text
|
|
||||||
|
|
||||||
mixin table(params)
|
block meta
|
||||||
table
|
link(rel="stylesheet" href="/assets/docs/api/endpoints/style.css")
|
||||||
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} (
|
|
||||||
a(href=`/docs/api/entities/${param.entity}`)= param.entity
|
|
||||||
| ID)
|
|
||||||
else if param.kind == 'entity'
|
|
||||||
| #{param.type} (
|
|
||||||
a(href=`/docs/api/entities/${param.entity}`)= param.entity
|
|
||||||
| )
|
|
||||||
else if param.kind == 'object'
|
|
||||||
| #{param.type} (
|
|
||||||
a(href=`#${param.defName}`)= param.defName
|
|
||||||
| )
|
|
||||||
else
|
|
||||||
= param.type
|
|
||||||
td.optional= param.optional.toString()
|
|
||||||
td.desc: +i18n(param.desc)
|
|
||||||
|
|
||||||
html
|
block main
|
||||||
head
|
h1= endpoint
|
||||||
meta(charset="UTF-8")
|
|
||||||
title #{endpoint} | Misskey API
|
|
||||||
link(rel="stylesheet" href="/assets/docs/api/endpoints/style.css")
|
|
||||||
|
|
||||||
body
|
p#url= url
|
||||||
main
|
|
||||||
h1= endpoint
|
|
||||||
|
|
||||||
p#url= url
|
p#desc: +i18n(desc)
|
||||||
|
|
||||||
p#desc: +i18n(desc)
|
section
|
||||||
|
h2 Params
|
||||||
|
+propTable(params)
|
||||||
|
|
||||||
section
|
if paramDefs
|
||||||
h2 Params
|
each paramDef in paramDefs
|
||||||
+table(params)
|
section(id= paramDef.name)
|
||||||
|
h3= paramDef.name
|
||||||
|
+propTable(paramDef.params)
|
||||||
|
|
||||||
if paramDefs
|
section
|
||||||
each paramDef in paramDefs
|
h2 Response
|
||||||
section(id= paramDef.name)
|
+propTable(res)
|
||||||
h3= paramDef.name
|
|
||||||
+table(paramDef.params)
|
|
||||||
|
|
||||||
section
|
|
||||||
h2 Response
|
|
||||||
+table(res)
|
|
||||||
|
|
||||||
|
|
124
src/web/docs/api/entities/post.yaml
Normal file
124
src/web/docs/api/entities/post.yaml
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
name: "Post"
|
||||||
|
|
||||||
|
desc:
|
||||||
|
ja: "投稿。"
|
||||||
|
en: "A post."
|
||||||
|
|
||||||
|
props:
|
||||||
|
- name: "id"
|
||||||
|
type: "id"
|
||||||
|
optional: false
|
||||||
|
desc:
|
||||||
|
ja: "投稿ID"
|
||||||
|
en: "The ID of this post"
|
||||||
|
- name: "created_at"
|
||||||
|
type: "date"
|
||||||
|
optional: false
|
||||||
|
desc:
|
||||||
|
ja: "投稿日時"
|
||||||
|
en: "The posted date of this post"
|
||||||
|
- name: "text"
|
||||||
|
type: "string"
|
||||||
|
optional: true
|
||||||
|
desc:
|
||||||
|
ja: "投稿の本文"
|
||||||
|
en: "The text of this post"
|
||||||
|
- name: "media_ids"
|
||||||
|
type: "id(DriveFile)[]"
|
||||||
|
optional: true
|
||||||
|
desc:
|
||||||
|
ja: "添付されているメディアのID"
|
||||||
|
en: "The IDs of the attached media"
|
||||||
|
- name: "media"
|
||||||
|
type: "entity(DriveFile)[]"
|
||||||
|
optional: true
|
||||||
|
desc:
|
||||||
|
ja: "添付されているメディア"
|
||||||
|
en: "The attached media"
|
||||||
|
- name: "user_id"
|
||||||
|
type: "id(User)"
|
||||||
|
optional: false
|
||||||
|
desc:
|
||||||
|
ja: "投稿者ID"
|
||||||
|
en: "The ID of author of this post"
|
||||||
|
- name: "user"
|
||||||
|
type: "entity(User)"
|
||||||
|
optional: true
|
||||||
|
desc:
|
||||||
|
ja: "投稿者"
|
||||||
|
en: "The author of this post"
|
||||||
|
- name: "my_reaction"
|
||||||
|
type: "string"
|
||||||
|
optional: true
|
||||||
|
desc:
|
||||||
|
ja: "この投稿に対する自分の<a href='/docs/api/reactions'>リアクション</a>"
|
||||||
|
en: "The your <a href='/docs/api/reactions'>reaction</a> of this post"
|
||||||
|
- name: "reaction_counts"
|
||||||
|
type: "object"
|
||||||
|
optional: false
|
||||||
|
desc:
|
||||||
|
ja: "<a href='/docs/api/reactions'>リアクション</a>をキーとし、この投稿に対するそのリアクションの数を値としたオブジェクト"
|
||||||
|
- name: "reply_id"
|
||||||
|
type: "id(Post)"
|
||||||
|
optional: true
|
||||||
|
desc:
|
||||||
|
ja: "返信した投稿のID"
|
||||||
|
en: "The ID of the replyed post"
|
||||||
|
- name: "reply"
|
||||||
|
type: "entity(Post)"
|
||||||
|
optional: true
|
||||||
|
desc:
|
||||||
|
ja: "返信した投稿"
|
||||||
|
en: "The replyed post"
|
||||||
|
- name: "repost_id"
|
||||||
|
type: "id(Post)"
|
||||||
|
optional: true
|
||||||
|
desc:
|
||||||
|
ja: "引用した投稿のID"
|
||||||
|
en: "The ID of the quoted post"
|
||||||
|
- name: "repost"
|
||||||
|
type: "entity(Post)"
|
||||||
|
optional: true
|
||||||
|
desc:
|
||||||
|
ja: "引用した投稿"
|
||||||
|
en: "The quoted post"
|
||||||
|
- name: "poll"
|
||||||
|
type: "object"
|
||||||
|
optional: true
|
||||||
|
desc:
|
||||||
|
ja: "投票"
|
||||||
|
en: "The poll"
|
||||||
|
defName: "poll"
|
||||||
|
def:
|
||||||
|
- name: "choices"
|
||||||
|
type: "object[]"
|
||||||
|
optional: false
|
||||||
|
desc:
|
||||||
|
ja: "投票の選択肢"
|
||||||
|
en: "The choices of this poll"
|
||||||
|
defName: "choice"
|
||||||
|
def:
|
||||||
|
- name: "id"
|
||||||
|
type: "number"
|
||||||
|
optional: false
|
||||||
|
desc:
|
||||||
|
ja: "選択肢ID"
|
||||||
|
en: "The ID of this choice"
|
||||||
|
- name: "is_voted"
|
||||||
|
type: "boolean"
|
||||||
|
optional: true
|
||||||
|
desc:
|
||||||
|
ja: "自分がこの選択肢に投票したかどうか"
|
||||||
|
en: "Whether you voted to this choice"
|
||||||
|
- name: "text"
|
||||||
|
type: "string"
|
||||||
|
optional: false
|
||||||
|
desc:
|
||||||
|
ja: "選択肢本文"
|
||||||
|
en: "The text of this choice"
|
||||||
|
- name: "votes"
|
||||||
|
type: "number"
|
||||||
|
optional: false
|
||||||
|
desc:
|
||||||
|
ja: "この選択肢に投票された数"
|
||||||
|
en: "The number voted for this choice"
|
1
src/web/docs/api/entities/style.styl
Normal file
1
src/web/docs/api/entities/style.styl
Normal file
|
@ -0,0 +1 @@
|
||||||
|
@import "../style"
|
23
src/web/docs/api/entities/view.pug
Normal file
23
src/web/docs/api/entities/view.pug
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
extends ../../layout.pug
|
||||||
|
include ../mixins
|
||||||
|
|
||||||
|
block title
|
||||||
|
| #{name} | Misskey API
|
||||||
|
|
||||||
|
block meta
|
||||||
|
link(rel="stylesheet" href="/assets/docs/api/entities/style.css")
|
||||||
|
|
||||||
|
block main
|
||||||
|
h1= name
|
||||||
|
|
||||||
|
p#desc: +i18n(desc)
|
||||||
|
|
||||||
|
section
|
||||||
|
h2 Properties
|
||||||
|
+propTable(props)
|
||||||
|
|
||||||
|
if propDefs
|
||||||
|
each propDef in propDefs
|
||||||
|
section(id= propDef.name)
|
||||||
|
h3= propDef.name
|
||||||
|
+propTable(propDef.params)
|
|
@ -10,12 +10,15 @@ import * as pug from 'pug';
|
||||||
import * as yaml from 'js-yaml';
|
import * as yaml from 'js-yaml';
|
||||||
import * as mkdirp from 'mkdirp';
|
import * as mkdirp from 'mkdirp';
|
||||||
|
|
||||||
import config from './../../../../conf';
|
import config from './../../../conf';
|
||||||
|
|
||||||
|
const kebab = string => string.replace(/([a-z])([A-Z])/g, '$1-$2').replace(/\s+/g, '-').toLowerCase();
|
||||||
|
|
||||||
const parseParam = param => {
|
const parseParam = param => {
|
||||||
const id = param.type.match(/^id\((.+?)\)/);
|
const id = param.type.match(/^id\((.+?)\)|^id/);
|
||||||
const entity = param.type.match(/^entity\((.+?)\)/);
|
const entity = param.type.match(/^entity\((.+?)\)/);
|
||||||
const isObject = /^object/.test(param.type);
|
const isObject = /^object/.test(param.type);
|
||||||
|
const isDate = /^date/.test(param.type);
|
||||||
const isArray = /\[\]$/.test(param.type);
|
const isArray = /\[\]$/.test(param.type);
|
||||||
if (id) {
|
if (id) {
|
||||||
param.kind = 'id';
|
param.kind = 'id';
|
||||||
|
@ -36,30 +39,53 @@ const parseParam = param => {
|
||||||
if (isObject) {
|
if (isObject) {
|
||||||
param.kind = 'object';
|
param.kind = 'object';
|
||||||
}
|
}
|
||||||
|
if (isDate) {
|
||||||
|
param.kind = 'date';
|
||||||
|
param.type = 'string';
|
||||||
|
if (isArray) {
|
||||||
|
param.type += '[]';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return param;
|
return param;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const sortParams = params => {
|
||||||
|
params.sort((a, b) => {
|
||||||
|
if (a.name < b.name)
|
||||||
|
return -1;
|
||||||
|
if (a.name > b.name)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
return params;
|
||||||
|
};
|
||||||
|
|
||||||
const extractDefs = params => {
|
const extractDefs = params => {
|
||||||
const defs = [];
|
let defs = [];
|
||||||
|
|
||||||
params.forEach(param => {
|
params.forEach(param => {
|
||||||
if (param.def) {
|
if (param.def) {
|
||||||
defs.push({
|
defs.push({
|
||||||
name: param.defName,
|
name: param.defName,
|
||||||
params: param.def.map(p => parseParam(p))
|
params: sortParams(param.def.map(p => parseParam(p)))
|
||||||
});
|
});
|
||||||
|
|
||||||
const childDefs = extractDefs(param.def);
|
const childDefs = extractDefs(param.def);
|
||||||
|
|
||||||
defs.concat(childDefs);
|
defs = defs.concat(childDefs);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return defs;
|
return defs;
|
||||||
};
|
};
|
||||||
|
|
||||||
gulp.task('doc:endpoints', () => {
|
gulp.task('doc:api', [
|
||||||
|
'doc:api:endpoints',
|
||||||
|
'doc:api:entities'
|
||||||
|
]);
|
||||||
|
|
||||||
|
gulp.task('doc:api:endpoints', () => {
|
||||||
glob('./src/web/docs/api/endpoints/**/*.yaml', (globErr, files) => {
|
glob('./src/web/docs/api/endpoints/**/*.yaml', (globErr, files) => {
|
||||||
if (globErr) {
|
if (globErr) {
|
||||||
console.error(globErr);
|
console.error(globErr);
|
||||||
|
@ -72,10 +98,11 @@ gulp.task('doc:endpoints', () => {
|
||||||
endpoint: ep.endpoint,
|
endpoint: ep.endpoint,
|
||||||
url: `${config.api_url}/${ep.endpoint}`,
|
url: `${config.api_url}/${ep.endpoint}`,
|
||||||
desc: ep.desc,
|
desc: ep.desc,
|
||||||
params: ep.params.map(p => parseParam(p)),
|
params: sortParams(ep.params.map(p => parseParam(p))),
|
||||||
paramDefs: extractDefs(ep.params),
|
paramDefs: extractDefs(ep.params),
|
||||||
res: ep.res.map(p => parseParam(p)),
|
res: sortParams(ep.res.map(p => parseParam(p))),
|
||||||
resDefs: extractDefs(ep.res)
|
resDefs: extractDefs(ep.res),
|
||||||
|
kebab
|
||||||
};
|
};
|
||||||
pug.renderFile('./src/web/docs/api/endpoints/view.pug', vars, (renderErr, html) => {
|
pug.renderFile('./src/web/docs/api/endpoints/view.pug', vars, (renderErr, html) => {
|
||||||
if (renderErr) {
|
if (renderErr) {
|
||||||
|
@ -94,3 +121,36 @@ gulp.task('doc:endpoints', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
gulp.task('doc:api:entities', () => {
|
||||||
|
glob('./src/web/docs/api/entities/**/*.yaml', (globErr, files) => {
|
||||||
|
if (globErr) {
|
||||||
|
console.error(globErr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
files.forEach(file => {
|
||||||
|
const entity = yaml.safeLoad(fs.readFileSync(file, 'utf-8'));
|
||||||
|
const vars = {
|
||||||
|
name: entity.name,
|
||||||
|
desc: entity.desc,
|
||||||
|
props: sortParams(entity.props.map(p => parseParam(p))),
|
||||||
|
propDefs: extractDefs(entity.props),
|
||||||
|
kebab
|
||||||
|
};
|
||||||
|
pug.renderFile('./src/web/docs/api/entities/view.pug', vars, (renderErr, html) => {
|
||||||
|
if (renderErr) {
|
||||||
|
console.error(renderErr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const htmlPath = `./built/web/docs/api/entities/${kebab(entity.name)}.html`;
|
||||||
|
mkdirp(path.dirname(htmlPath), (mkdirErr) => {
|
||||||
|
if (mkdirErr) {
|
||||||
|
console.error(mkdirErr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fs.writeFileSync(htmlPath, html, 'utf-8');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
33
src/web/docs/api/mixins.pug
Normal file
33
src/web/docs/api/mixins.pug
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
mixin propTable(props)
|
||||||
|
table.props
|
||||||
|
thead: tr
|
||||||
|
th Name
|
||||||
|
th Type
|
||||||
|
th Optional
|
||||||
|
th Description
|
||||||
|
tbody
|
||||||
|
each prop in props
|
||||||
|
tr
|
||||||
|
td.name= prop.name
|
||||||
|
td.type
|
||||||
|
i= prop.type
|
||||||
|
if prop.kind == 'id'
|
||||||
|
if prop.entity
|
||||||
|
| (
|
||||||
|
a(href=`/docs/api/entities/${kebab(prop.entity)}`)= prop.entity
|
||||||
|
| ID)
|
||||||
|
else
|
||||||
|
| (ID)
|
||||||
|
else if prop.kind == 'entity'
|
||||||
|
| (
|
||||||
|
a(href=`/docs/api/entities/${kebab(prop.entity)}`)= prop.entity
|
||||||
|
| )
|
||||||
|
else if prop.kind == 'object'
|
||||||
|
if prop.def
|
||||||
|
| (
|
||||||
|
a(href=`#${prop.defName}`)= prop.defName
|
||||||
|
| )
|
||||||
|
else if prop.kind == 'date'
|
||||||
|
| (Date)
|
||||||
|
td.optional= prop.optional.toString()
|
||||||
|
td.desc: +i18n(prop.desc)
|
11
src/web/docs/api/style.styl
Normal file
11
src/web/docs/api/style.styl
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
@import "../style"
|
||||||
|
|
||||||
|
table.props
|
||||||
|
.name
|
||||||
|
font-weight bold
|
||||||
|
|
||||||
|
.name
|
||||||
|
.type
|
||||||
|
.optional
|
||||||
|
font-family Consolas, 'Courier New', Courier, Monaco, monospace
|
||||||
|
|
16
src/web/docs/layout.pug
Normal file
16
src/web/docs/layout.pug
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
doctype html
|
||||||
|
|
||||||
|
mixin i18n(xs)
|
||||||
|
each text, lang in xs
|
||||||
|
span(class=`i18n ${lang}`)!= text
|
||||||
|
|
||||||
|
html
|
||||||
|
head
|
||||||
|
meta(charset="UTF-8")
|
||||||
|
title
|
||||||
|
block title
|
||||||
|
block meta
|
||||||
|
|
||||||
|
body
|
||||||
|
main
|
||||||
|
block main
|
Loading…
Reference in a new issue