This commit is contained in:
syuilo 2018-07-07 13:34:42 +09:00
parent 5ea0f23389
commit 2cdcbcc80e
6 changed files with 127 additions and 117 deletions

View file

@ -30,3 +30,9 @@ block main
section section
h2= i18n('docs.api.endpoints.res') h2= i18n('docs.api.endpoints.res')
+propTable(res) +propTable(res)
if resDefs
each resDef in resDefs
section(id= resDef.name)
h3= resDef.name
+propTable(resDef.props)

View file

@ -5,169 +5,173 @@ desc:
en: "A user." en: "A user."
props: props:
- name: "id" id:
type: "id" type: "id"
optional: false optional: false
desc: desc:
ja: "ユーザーID" ja: "ユーザーID"
en: "The ID of this user" en: "The ID of this user"
- name: "createdAt"
createdAt:
type: "date" type: "date"
optional: false optional: false
desc: desc:
ja: "アカウント作成日時" ja: "アカウント作成日時"
en: "The registered date of this user" en: "The registered date of this user"
- name: "username"
username:
type: "string" type: "string"
optional: false optional: false
desc: desc:
ja: "ユーザー名" ja: "ユーザー名"
en: "The username of this user" en: "The username of this user"
- name: "description"
description:
type: "string" type: "string"
optional: false optional: false
desc: desc:
ja: "アカウントの説明(自己紹介)" ja: "アカウントの説明(自己紹介)"
en: "The description of this user" en: "The description of this user"
- name: "avatarId"
avatarId:
type: "id(DriveFile)" type: "id(DriveFile)"
optional: true optional: true
desc: desc:
ja: "アバターのID" ja: "アバターのID"
en: "The ID of the avatar of this user" en: "The ID of the avatar of this user"
- name: "avatarUrl"
avatarUrl:
type: "string" type: "string"
optional: false optional: false
desc: desc:
ja: "アバターのURL" ja: "アバターのURL"
en: "The URL of the avatar of this user" en: "The URL of the avatar of this user"
- name: "bannerId"
bannerId:
type: "id(DriveFile)" type: "id(DriveFile)"
optional: true optional: true
desc: desc:
ja: "バナーのID" ja: "バナーのID"
en: "The ID of the banner of this user" en: "The ID of the banner of this user"
- name: "bannerUrl"
bannerUrl:
type: "string" type: "string"
optional: false optional: false
desc: desc:
ja: "バナーのURL" ja: "バナーのURL"
en: "The URL of the banner of this user" en: "The URL of the banner of this user"
- name: "followersCount"
followersCount:
type: "number" type: "number"
optional: false optional: false
desc: desc:
ja: "フォロワーの数" ja: "フォロワーの数"
en: "The number of the followers for this user" en: "The number of the followers for this user"
- name: "followingCount"
followingCount:
type: "number" type: "number"
optional: false optional: false
desc: desc:
ja: "フォローしているユーザーの数" ja: "フォローしているユーザーの数"
en: "The number of the following users for this user" en: "The number of the following users for this user"
- name: "isFollowing"
isFollowing:
type: "boolean" type: "boolean"
optional: true optional: true
desc: desc:
ja: "自分がこのユーザーをフォローしているか" ja: "自分がこのユーザーをフォローしているか"
- name: "isFollowed"
isFollowed:
type: "boolean" type: "boolean"
optional: true optional: true
desc: desc:
ja: "自分がこのユーザーにフォローされているか" ja: "自分がこのユーザーにフォローされているか"
- name: "isMuted"
isMuted:
type: "boolean" type: "boolean"
optional: true optional: true
desc: desc:
ja: "自分がこのユーザーをミュートしているか" ja: "自分がこのユーザーをミュートしているか"
en: "Whether you muted this user" en: "Whether you muted this user"
- name: "notesCount"
notesCount:
type: "number" type: "number"
optional: false optional: false
desc: desc:
ja: "投稿の数" ja: "投稿の数"
en: "The number of the notes of this user" en: "The number of the notes of this user"
- name: "pinnedNote"
pinnedNote:
type: "entity(Note)" type: "entity(Note)"
optional: true optional: true
desc: desc:
ja: "ピン留めされた投稿" ja: "ピン留めされた投稿"
en: "The pinned note of this user" en: "The pinned note of this user"
- name: "pinnedNoteId"
pinnedNoteId:
type: "id(Note)" type: "id(Note)"
optional: true optional: true
desc: desc:
ja: "ピン留めされた投稿のID" ja: "ピン留めされた投稿のID"
en: "The ID of the pinned note of this user" en: "The ID of the pinned note of this user"
- name: "driveCapacity"
driveCapacity:
type: "number" type: "number"
optional: false optional: false
desc: desc:
ja: "ドライブの容量(bytes)" ja: "ドライブの容量(bytes)"
en: "The capacity of drive of this user (bytes)" en: "The capacity of drive of this user (bytes)"
- name: "host"
host:
type: "string | null" type: "string | null"
optional: false optional: false
desc: desc:
ja: "ホスト (例: example.com:3000)" ja: "ホスト (例: example.com:3000)"
en: "Host (e.g. example.com:3000)" en: "Host (e.g. example.com:3000)"
- name: "account"
twitter:
type: "object"
optional: true
desc:
ja: "連携されているTwitterアカウント情報"
en: "The info of the connected twitter account of this user"
props:
userId:
type: "string"
optional: false
desc:
ja: "ユーザーID"
en: "The user ID"
screenName:
type: "string"
optional: false
desc:
ja: "ユーザー名"
en: "The screen name of this user"
isBot:
type: "boolean"
optional: true
desc:
ja: "botか否か(自己申告であることに留意)"
en: "Whether is bot or not"
profile:
type: "object" type: "object"
optional: false optional: false
desc: desc:
ja: "このサーバーにおけるアカウント" ja: "プロフィール"
en: "The account of this user on this server" en: "The profile of this user"
defName: "account" props:
def: location:
- name: "lastUsedAt" type: "string"
type: "date"
optional: false
desc:
ja: "最終利用日時"
en: "The last used date of this user"
- name: "isBot"
type: "boolean"
optional: true optional: true
desc: desc:
ja: "botか否か(自己申告であることに留意)" ja: "場所"
en: "Whether is bot or not" en: "The location of this user"
- name: "twitter" birthday:
type: "object" type: "string"
optional: true optional: true
desc: desc:
ja: "連携されているTwitterアカウント情報" ja: "誕生日 (YYYY-MM-DD)"
en: "The info of the connected twitter account of this user" en: "The birthday of this user (YYYY-MM-DD)"
defName: "twitter"
def:
- name: "userId"
type: "string"
optional: false
desc:
ja: "ユーザーID"
en: "The user ID"
- name: "screenName"
type: "string"
optional: false
desc:
ja: "ユーザー名"
en: "The screen name of this user"
- name: "profile"
type: "object"
optional: false
desc:
ja: "プロフィール"
en: "The profile of this user"
defName: "profile"
def:
- name: "location"
type: "string"
optional: true
desc:
ja: "場所"
en: "The location of this user"
- name: "birthday"
type: "string"
optional: true
desc:
ja: "誕生日 (YYYY-MM-DD)"
en: "The birthday of this user (YYYY-MM-DD)"

View file

@ -17,4 +17,4 @@ block main
each propDef in propDefs each propDef in propDefs
section(id= propDef.name) section(id= propDef.name)
h3= propDef.name h3= propDef.name
+propTable(propDef.params) +propTable(propDef.props)

View file

@ -22,9 +22,9 @@ mixin propTable(props)
a(href=`/docs/${lang}/api/entities/${kebab(prop.entity)}`)= prop.entity a(href=`/docs/${lang}/api/entities/${kebab(prop.entity)}`)= prop.entity
| ) | )
else if prop.kind == 'object' else if prop.kind == 'object'
if prop.def if prop.hasDef
| ( | (
a(href=`#${prop.defName}`)= prop.defName a(href=`#${prop.name}`)= prop.name
| ) | )
else if prop.kind == 'date' else if prop.kind == 'date'
| (Date) | (Date)

View file

@ -90,7 +90,7 @@ export const meta = {
res: { res: {
type: 'object', type: 'object',
object: { props: {
createdNote: { createdNote: {
type: 'entity(Note)', type: 'entity(Note)',
desc: { desc: {

View file

@ -63,66 +63,64 @@ async function genVars(lang: string): Promise<{ [key: string]: any }> {
} }
// WIP type // WIP type
const parseEPDefParam = (key: string, param: Context) => { const parseParamDefinition = (key: string, param: Context) => {
return Object.assign({ return Object.assign({
name: key, name: key,
type: param.getType() type: param.getType()
}, param.data); }, param.data);
}; };
const parseParam = (param: any) => { const parsePropDefinition = (key: string, prop: any) => {
const id = param.type.match(/^id\((.+?)\)|^id/); const id = prop.type.match(/^id\((.+?)\)|^id/);
const entity = param.type.match(/^entity\((.+?)\)/); const entity = prop.type.match(/^entity\((.+?)\)/);
const isObject = /^object/.test(param.type); const isObject = /^object/.test(prop.type);
const isDate = /^date/.test(param.type); const isDate = /^date/.test(prop.type);
const isArray = /\[\]$/.test(param.type); const isArray = /\[\]$/.test(prop.type);
if (id) { if (id) {
param.kind = 'id'; prop.kind = 'id';
param.type = 'string'; prop.type = 'string';
param.entity = id[1]; prop.entity = id[1];
if (isArray) { if (isArray) {
param.type += '[]'; prop.type += '[]';
} }
} }
if (entity) { if (entity) {
param.kind = 'entity'; prop.kind = 'entity';
param.type = 'object'; prop.type = 'object';
param.entity = entity[1]; prop.entity = entity[1];
if (isArray) { if (isArray) {
param.type += '[]'; prop.type += '[]';
} }
} }
if (isObject) { if (isObject) {
param.kind = 'object'; prop.kind = 'object';
if (prop.props) {
prop.hasDef = true;
}
} }
if (isDate) { if (isDate) {
param.kind = 'date'; prop.kind = 'date';
param.type = 'string'; prop.type = 'string';
if (isArray) { if (isArray) {
param.type += '[]'; prop.type += '[]';
} }
} }
if (param.optional) { if (prop.optional) {
param.type += '?'; prop.type += '?';
} }
return param; prop.name = key;
return prop;
}; };
const sortParams = (params: Array<{name: string}>) => { const sortParams = (params: Array<{name: string}>) => {
params.sort((a, b) => {
if (a.name < b.name)
return -1;
if (a.name > b.name)
return 1;
return 0;
});
return params; return params;
}; };
// WIP type // WIP type
const extractEPDefs = (params: Context[]) => { const extractParamDefRef = (params: Context[]) => {
let defs: any[] = []; let defs: any[] = [];
params.forEach(param => { params.forEach(param => {
@ -130,10 +128,10 @@ const extractEPDefs = (params: Context[]) => {
const props = (param as ObjectContext<any>).props; const props = (param as ObjectContext<any>).props;
defs.push({ defs.push({
name: param.data.ref, name: param.data.ref,
params: sortParams(Object.keys(props).map(k => parseEPDefParam(k, props[k]))) params: sortParams(Object.keys(props).map(k => parseParamDefinition(k, props[k])))
}); });
const childDefs = extractEPDefs(Object.keys(props).map(k => props[k])); const childDefs = extractParamDefRef(Object.keys(props).map(k => props[k]));
defs = defs.concat(childDefs); defs = defs.concat(childDefs);
} }
@ -142,17 +140,17 @@ const extractEPDefs = (params: Context[]) => {
return sortParams(defs); return sortParams(defs);
}; };
const extractDefs = (params: any[]) => { const extractPropDefRef = (props: any[]) => {
let defs: any[] = []; let defs: any[] = [];
params.forEach(param => { Object.entries(props).forEach(([k, v]) => {
if (param.def) { if (v.props) {
defs.push({ defs.push({
name: param.defName, name: k,
params: sortParams(param.def.map((p: any) => parseParam(p))) props: sortParams(Object.entries(v.props).map(([k, v]) => parsePropDefinition(k, v)))
}); });
const childDefs = extractDefs(param.def); const childDefs = extractPropDefRef(v.props);
defs = defs.concat(childDefs); defs = defs.concat(childDefs);
} }
@ -184,8 +182,10 @@ router.get('/*/api/endpoints/*', async ctx => {
}, },
desc: ep.desc, desc: ep.desc,
// @ts-ignore // @ts-ignore
params: sortParams(Object.keys(ep.params).map(k => parseEPDefParam(k, ep.params[k]))), params: sortParams(Object.entries(ep.params).map(([k, v]) => parseParamDefinition(k, v))),
paramDefs: extractEPDefs(Object.keys(ep.params).map(k => ep.params[k])), paramDefs: extractParamDefRef(Object.entries(ep.params).map(([k, v]) => v)),
res: ep.res.props ? sortParams(Object.entries(ep.res.props).map(([k, v]) => parsePropDefinition(k, v))) : null,
resDefs: null//extractPropDefRef(Object.entries(ep.res.props).map(([k, v]) => parsePropDefinition(k, v)))
}; };
await ctx.render('../../../../src/client/docs/api/endpoints/view', Object.assign(await genVars(lang), vars)); await ctx.render('../../../../src/client/docs/api/endpoints/view', Object.assign(await genVars(lang), vars));
@ -200,8 +200,8 @@ router.get('/*/api/entities/*', async ctx => {
await ctx.render('../../../../src/client/docs/api/entities/view', Object.assign(await genVars(lang), { await ctx.render('../../../../src/client/docs/api/entities/view', Object.assign(await genVars(lang), {
name: x.name, name: x.name,
desc: x.desc, desc: x.desc,
props: sortParams(x.props.map((p: any) => parseParam(p))), props: sortParams(Object.entries(x.props).map(([k, v]) => parsePropDefinition(k, v))),
propDefs: extractDefs(x.props) propDefs: extractPropDefRef(x.props)
})); }));
}); });