diff options
Diffstat (limited to 'src/client/docs/api')
| -rw-r--r-- | src/client/docs/api/endpoints/posts/create.yaml | 53 | ||||
| -rw-r--r-- | src/client/docs/api/endpoints/posts/timeline.yaml | 32 | ||||
| -rw-r--r-- | src/client/docs/api/endpoints/style.styl | 21 | ||||
| -rw-r--r-- | src/client/docs/api/endpoints/view.pug | 32 | ||||
| -rw-r--r-- | src/client/docs/api/entities/drive-file.yaml | 73 | ||||
| -rw-r--r-- | src/client/docs/api/entities/post.yaml | 168 | ||||
| -rw-r--r-- | src/client/docs/api/entities/style.styl | 1 | ||||
| -rw-r--r-- | src/client/docs/api/entities/user.yaml | 173 | ||||
| -rw-r--r-- | src/client/docs/api/entities/view.pug | 20 | ||||
| -rw-r--r-- | src/client/docs/api/gulpfile.ts | 188 | ||||
| -rw-r--r-- | src/client/docs/api/mixins.pug | 37 | ||||
| -rw-r--r-- | src/client/docs/api/style.styl | 11 |
12 files changed, 809 insertions, 0 deletions
diff --git a/src/client/docs/api/endpoints/posts/create.yaml b/src/client/docs/api/endpoints/posts/create.yaml new file mode 100644 index 0000000000..11d9f40c54 --- /dev/null +++ b/src/client/docs/api/endpoints/posts/create.yaml @@ -0,0 +1,53 @@ +endpoint: "posts/create" + +desc: + ja: "投稿します。" + en: "Compose new post." + +params: + - name: "text" + type: "string" + optional: true + desc: + ja: "投稿の本文" + en: "The text of your post" + - name: "mediaIds" + type: "id(DriveFile)[]" + optional: true + desc: + ja: "添付するメディア(1~4つ)" + en: "Media you want to attach (1~4)" + - name: "replyId" + type: "id(Post)" + optional: true + desc: + ja: "返信する投稿" + en: "The post you want to reply" + - name: "repostId" + type: "id(Post)" + optional: true + desc: + ja: "引用する投稿" + en: "The post you want to quote" + - name: "poll" + type: "object" + optional: true + desc: + ja: "投票" + en: "The poll" + defName: "poll" + def: + - name: "choices" + type: "string[]" + optional: false + desc: + ja: "投票の選択肢" + en: "Choices of a poll" + +res: + - name: "createdPost" + type: "entity(Post)" + optional: false + desc: + ja: "作成した投稿" + en: "A post that created" diff --git a/src/client/docs/api/endpoints/posts/timeline.yaml b/src/client/docs/api/endpoints/posts/timeline.yaml new file mode 100644 index 0000000000..9c44dd736a --- /dev/null +++ b/src/client/docs/api/endpoints/posts/timeline.yaml @@ -0,0 +1,32 @@ +endpoint: "posts/timeline" + +desc: + ja: "タイムラインを取得します。" + en: "Get your timeline." + +params: + - name: "limit" + type: "number" + optional: true + desc: + ja: "取得する最大の数" + - name: "sinceId" + type: "id(Post)" + optional: true + desc: + ja: "指定すると、この投稿を基点としてより新しい投稿を取得します" + - name: "untilId" + type: "id(Post)" + optional: true + desc: + ja: "指定すると、この投稿を基点としてより古い投稿を取得します" + - name: "sinceDate" + type: "number" + optional: true + desc: + ja: "指定した時間を基点としてより新しい投稿を取得します。数値は、1970 年 1 月 1 日 00:00:00 UTC から指定した日時までの経過時間をミリ秒単位で表します。" + - name: "untilDate" + type: "number" + optional: true + desc: + ja: "指定した時間を基点としてより古い投稿を取得します。数値は、1970 年 1 月 1 日 00:00:00 UTC から指定した日時までの経過時間をミリ秒単位で表します。" diff --git a/src/client/docs/api/endpoints/style.styl b/src/client/docs/api/endpoints/style.styl new file mode 100644 index 0000000000..2af9fe9a77 --- /dev/null +++ b/src/client/docs/api/endpoints/style.styl @@ -0,0 +1,21 @@ +@import "../style" + +#url + padding 8px 12px 8px 8px + font-family Consolas, 'Courier New', Courier, Monaco, monospace + color #fff + background #222e40 + border-radius 4px + + > .method + display inline-block + margin 0 8px 0 0 + padding 0 6px + color #f4fcff + background #17afc7 + border-radius 4px + user-select none + pointer-events none + + > .host + opacity 0.7 diff --git a/src/client/docs/api/endpoints/view.pug b/src/client/docs/api/endpoints/view.pug new file mode 100644 index 0000000000..d271a5517a --- /dev/null +++ b/src/client/docs/api/endpoints/view.pug @@ -0,0 +1,32 @@ +extends ../../layout.pug +include ../mixins + +block meta + link(rel="stylesheet" href="/assets/api/endpoints/style.css") + +block main + h1= endpoint + + p#url + span.method POST + span.host + = url.host + | / + span.path= url.path + + p#desc= desc[lang] || desc['ja'] + + section + h2 %i18n:docs.api.endpoints.params% + +propTable(params) + + if paramDefs + each paramDef in paramDefs + section(id= paramDef.name) + h3= paramDef.name + +propTable(paramDef.params) + + if res + section + h2 %i18n:docs.api.endpoints.res% + +propTable(res) diff --git a/src/client/docs/api/entities/drive-file.yaml b/src/client/docs/api/entities/drive-file.yaml new file mode 100644 index 0000000000..02ab0d608e --- /dev/null +++ b/src/client/docs/api/entities/drive-file.yaml @@ -0,0 +1,73 @@ +name: "DriveFile" + +desc: + ja: "ドライブのファイル。" + en: "A file of Drive." + +props: + - name: "id" + type: "id" + optional: false + desc: + ja: "ファイルID" + en: "The ID of this file" + - name: "createdAt" + type: "date" + optional: false + desc: + ja: "アップロード日時" + en: "The upload date of this file" + - name: "userId" + type: "id(User)" + optional: false + desc: + ja: "所有者ID" + en: "The ID of the owner of this file" + - name: "user" + type: "entity(User)" + optional: true + desc: + ja: "所有者" + en: "The owner of this file" + - name: "name" + type: "string" + optional: false + desc: + ja: "ファイル名" + en: "The name of this file" + - name: "md5" + type: "string" + optional: false + desc: + ja: "ファイルのMD5ハッシュ値" + en: "The md5 hash value of this file" + - name: "type" + type: "string" + optional: false + desc: + ja: "ファイルの種類" + en: "The type of this file" + - name: "datasize" + type: "number" + optional: false + desc: + ja: "ファイルサイズ(bytes)" + en: "The size of this file (bytes)" + - name: "url" + type: "string" + optional: false + desc: + ja: "ファイルのURL" + en: "The URL of this file" + - name: "folderId" + type: "id(DriveFolder)" + optional: true + desc: + ja: "フォルダID" + en: "The ID of the folder of this file" + - name: "folder" + type: "entity(DriveFolder)" + optional: true + desc: + ja: "フォルダ" + en: "The folder of this file" diff --git a/src/client/docs/api/entities/post.yaml b/src/client/docs/api/entities/post.yaml new file mode 100644 index 0000000000..74d7973e38 --- /dev/null +++ b/src/client/docs/api/entities/post.yaml @@ -0,0 +1,168 @@ +name: "Post" + +desc: + ja: "投稿。" + en: "A post." + +props: + - name: "id" + type: "id" + optional: false + desc: + ja: "投稿ID" + en: "The ID of this post" + - name: "createdAt" + type: "date" + optional: false + desc: + ja: "投稿日時" + en: "The posted date of this post" + - name: "viaMobile" + type: "boolean" + optional: true + desc: + ja: "モバイル端末から投稿したか否か(自己申告であることに留意)" + en: "Whether this post sent via a mobile device" + - name: "text" + type: "string" + optional: true + desc: + ja: "投稿の本文" + en: "The text of this post" + - name: "mediaIds" + 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: "userId" + 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: "myReaction" + 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: "reactionCounts" + type: "object" + optional: false + desc: + ja: "<a href='/docs/api/reactions'>リアクション</a>をキーとし、この投稿に対するそのリアクションの数を値としたオブジェクト" + - name: "replyId" + 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: "repostId" + 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: "isVoted" + 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" + - name: "geo" + type: "object" + optional: true + desc: + ja: "位置情報" + en: "Geo location" + defName: "geo" + def: + - name: "coordinates" + type: "number[]" + optional: false + desc: + ja: "座標。最初に経度:-180〜180で表す。最後に緯度:-90〜90で表す。" + - name: "altitude" + type: "number" + optional: false + desc: + ja: "高度。メートル単位で表す。" + - name: "accuracy" + type: "number" + optional: false + desc: + ja: "緯度、経度の精度。メートル単位で表す。" + - name: "altitudeAccuracy" + type: "number" + optional: false + desc: + ja: "高度の精度。メートル単位で表す。" + - name: "heading" + type: "number" + optional: false + desc: + ja: "方角。0〜360の角度で表す。0が北、90が東、180が南、270が西。" + - name: "speed" + type: "number" + optional: false + desc: + ja: "速度。メートル / 秒数で表す。" diff --git a/src/client/docs/api/entities/style.styl b/src/client/docs/api/entities/style.styl new file mode 100644 index 0000000000..bddf0f53ab --- /dev/null +++ b/src/client/docs/api/entities/style.styl @@ -0,0 +1 @@ +@import "../style" diff --git a/src/client/docs/api/entities/user.yaml b/src/client/docs/api/entities/user.yaml new file mode 100644 index 0000000000..a1fae1482b --- /dev/null +++ b/src/client/docs/api/entities/user.yaml @@ -0,0 +1,173 @@ +name: "User" + +desc: + ja: "ユーザー。" + en: "A user." + +props: + - name: "id" + type: "id" + optional: false + desc: + ja: "ユーザーID" + en: "The ID of this user" + - name: "createdAt" + type: "date" + optional: false + desc: + ja: "アカウント作成日時" + en: "The registered date of this user" + - name: "username" + type: "string" + optional: false + desc: + ja: "ユーザー名" + en: "The username of this user" + - name: "description" + type: "string" + optional: false + desc: + ja: "アカウントの説明(自己紹介)" + en: "The description of this user" + - name: "avatarId" + type: "id(DriveFile)" + optional: true + desc: + ja: "アバターのID" + en: "The ID of the avatar of this user" + - name: "avatarUrl" + type: "string" + optional: false + desc: + ja: "アバターのURL" + en: "The URL of the avatar of this user" + - name: "bannerId" + type: "id(DriveFile)" + optional: true + desc: + ja: "バナーのID" + en: "The ID of the banner of this user" + - name: "bannerUrl" + type: "string" + optional: false + desc: + ja: "バナーのURL" + en: "The URL of the banner of this user" + - name: "followersCount" + type: "number" + optional: false + desc: + ja: "フォロワーの数" + en: "The number of the followers for this user" + - name: "followingCount" + type: "number" + optional: false + desc: + ja: "フォローしているユーザーの数" + en: "The number of the following users for this user" + - name: "isFollowing" + type: "boolean" + optional: true + desc: + ja: "自分がこのユーザーをフォローしているか" + - name: "isFollowed" + type: "boolean" + optional: true + desc: + ja: "自分がこのユーザーにフォローされているか" + - name: "isMuted" + type: "boolean" + optional: true + desc: + ja: "自分がこのユーザーをミュートしているか" + en: "Whether you muted this user" + - name: "postsCount" + type: "number" + optional: false + desc: + ja: "投稿の数" + en: "The number of the posts of this user" + - name: "pinnedPost" + type: "entity(Post)" + optional: true + desc: + ja: "ピン留めされた投稿" + en: "The pinned post of this user" + - name: "pinnedPostId" + type: "id(Post)" + optional: true + desc: + ja: "ピン留めされた投稿のID" + en: "The ID of the pinned post of this user" + - name: "driveCapacity" + type: "number" + optional: false + desc: + ja: "ドライブの容量(bytes)" + en: "The capacity of drive of this user (bytes)" + - name: "host" + type: "string | null" + optional: false + desc: + ja: "ホスト (例: example.com:3000)" + en: "Host (e.g. example.com:3000)" + - name: "account" + type: "object" + optional: false + desc: + ja: "このサーバーにおけるアカウント" + en: "The account of this user on this server" + defName: "account" + def: + - name: "lastUsedAt" + type: "date" + optional: false + desc: + ja: "最終利用日時" + en: "The last used date of this user" + - name: "isBot" + type: "boolean" + optional: true + desc: + ja: "botか否か(自己申告であることに留意)" + en: "Whether is bot or not" + - name: "twitter" + type: "object" + optional: true + desc: + ja: "連携されているTwitterアカウント情報" + en: "The info of the connected twitter account of this user" + 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)" diff --git a/src/client/docs/api/entities/view.pug b/src/client/docs/api/entities/view.pug new file mode 100644 index 0000000000..2156463dc7 --- /dev/null +++ b/src/client/docs/api/entities/view.pug @@ -0,0 +1,20 @@ +extends ../../layout.pug +include ../mixins + +block meta + link(rel="stylesheet" href="/assets/api/entities/style.css") + +block main + h1= name + + p#desc= desc[lang] || desc['ja'] + + section + h2 %i18n:docs.api.entities.properties% + +propTable(props) + + if propDefs + each propDef in propDefs + section(id= propDef.name) + h3= propDef.name + +propTable(propDef.params) diff --git a/src/client/docs/api/gulpfile.ts b/src/client/docs/api/gulpfile.ts new file mode 100644 index 0000000000..16066b0d2e --- /dev/null +++ b/src/client/docs/api/gulpfile.ts @@ -0,0 +1,188 @@ +/** + * 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 locales from '../../../../locales'; +import I18nReplacer from '../../../build/i18n'; +import fa from '../../../build/fa'; +import config from './../../../conf'; + +import generateVars from '../vars'; + +const langs = Object.keys(locales); + +const kebab = string => string.replace(/([a-z])([A-Z])/g, '$1-$2').replace(/\s+/g, '-').toLowerCase(); + +const parseParam = param => { + const id = param.type.match(/^id\((.+?)\)|^id/); + const entity = param.type.match(/^entity\((.+?)\)/); + const isObject = /^object/.test(param.type); + const isDate = /^date/.test(param.type); + const isArray = /\[\]$/.test(param.type); + if (id) { + param.kind = 'id'; + param.type = 'string'; + param.entity = id[1]; + if (isArray) { + param.type += '[]'; + } + } + if (entity) { + param.kind = 'entity'; + param.type = 'object'; + param.entity = entity[1]; + if (isArray) { + param.type += '[]'; + } + } + if (isObject) { + param.kind = 'object'; + } + if (isDate) { + param.kind = 'date'; + param.type = 'string'; + if (isArray) { + param.type += '[]'; + } + } + + 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 => { + let defs = []; + + params.forEach(param => { + if (param.def) { + defs.push({ + name: param.defName, + params: sortParams(param.def.map(p => parseParam(p))) + }); + + const childDefs = extractDefs(param.def); + + defs = defs.concat(childDefs); + } + }); + + return sortParams(defs); +}; + +gulp.task('doc:api', [ + 'doc:api:endpoints', + 'doc:api:entities' +]); + +gulp.task('doc:api:endpoints', async () => { + const commonVars = await generateVars(); + glob('./src/client/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: { + host: config.api_url, + path: ep.endpoint + }, + desc: ep.desc, + params: sortParams(ep.params.map(p => parseParam(p))), + paramDefs: extractDefs(ep.params), + res: ep.res ? sortParams(ep.res.map(p => parseParam(p))) : null, + resDefs: ep.res ? extractDefs(ep.res) : null, + }; + langs.forEach(lang => { + pug.renderFile('./src/client/docs/api/endpoints/view.pug', Object.assign({}, vars, { + lang, + title: ep.endpoint, + src: `https://github.com/syuilo/misskey/tree/master/src/client/docs/api/endpoints/${ep.endpoint}.yaml`, + kebab, + common: commonVars + }), (renderErr, html) => { + if (renderErr) { + console.error(renderErr); + return; + } + const i18n = new I18nReplacer(lang); + html = html.replace(i18n.pattern, i18n.replacement); + html = fa(html); + const htmlPath = `./built/client/docs/${lang}/api/endpoints/${ep.endpoint}.html`; + mkdirp(path.dirname(htmlPath), (mkdirErr) => { + if (mkdirErr) { + console.error(mkdirErr); + return; + } + fs.writeFileSync(htmlPath, html, 'utf-8'); + }); + }); + }); + }); + }); +}); + +gulp.task('doc:api:entities', async () => { + const commonVars = await generateVars(); + glob('./src/client/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), + }; + langs.forEach(lang => { + pug.renderFile('./src/client/docs/api/entities/view.pug', Object.assign({}, vars, { + lang, + title: entity.name, + src: `https://github.com/syuilo/misskey/tree/master/src/client/docs/api/entities/${kebab(entity.name)}.yaml`, + kebab, + common: commonVars + }), (renderErr, html) => { + if (renderErr) { + console.error(renderErr); + return; + } + const i18n = new I18nReplacer(lang); + html = html.replace(i18n.pattern, i18n.replacement); + html = fa(html); + const htmlPath = `./built/client/docs/${lang}/api/entities/${kebab(entity.name)}.html`; + mkdirp(path.dirname(htmlPath), (mkdirErr) => { + if (mkdirErr) { + console.error(mkdirErr); + return; + } + fs.writeFileSync(htmlPath, html, 'utf-8'); + }); + }); + }); + }); + }); +}); diff --git a/src/client/docs/api/mixins.pug b/src/client/docs/api/mixins.pug new file mode 100644 index 0000000000..686bf6a2b6 --- /dev/null +++ b/src/client/docs/api/mixins.pug @@ -0,0 +1,37 @@ +mixin propTable(props) + table.props + thead: tr + th %i18n:docs.api.props.name% + th %i18n:docs.api.props.type% + th %i18n:docs.api.props.optional% + th %i18n:docs.api.props.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=`/${lang}/api/entities/${kebab(prop.entity)}`)= prop.entity + | ID) + else + | (ID) + else if prop.kind == 'entity' + | ( + a(href=`/${lang}/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 + if prop.optional + | %i18n:docs.api.props.yes% + else + | %i18n:docs.api.props.no% + td.desc!= prop.desc[lang] || prop.desc['ja'] diff --git a/src/client/docs/api/style.styl b/src/client/docs/api/style.styl new file mode 100644 index 0000000000..3675a4da6f --- /dev/null +++ b/src/client/docs/api/style.styl @@ -0,0 +1,11 @@ +@import "../style" + +table.props + .name + font-weight bold + + .name + .type + .optional + font-family Consolas, 'Courier New', Courier, Monaco, monospace + |