UNPKG

mockm

Version:

Analog interface server, painless parallel development of front and back ends.

216 lines (193 loc) 8.01 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault"); require("core-js/modules/es.symbol.description.js"); var _assign = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/object/assign")); var _reduce = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/reduce")); var _entries = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/object/entries")); var _flat = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/flat")); var _includes = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/includes")); /** 生成接口文档 - 自动扫描现有接口生成文档 - 在插件配置中 - apiDocInit -- boolean, 是否启用文档,默认否 - apiDocDataRoute -- string, openApi 数据地址, 默认 `/doc/openApi.json` - docPage -- string, 接口文档地址, 默认 `/doc` - cssUrl -- string, swagger-ui css 地址, 默认使用 cdn, 当为相对地址时, 由生成路由并引用本地资源 - jsUrl -- string, swagger-ui js 地址, 规则同上 - apiDocData -- yaml/json, openApi 数据, 可以自定义混入, 默认自动生成 - 在 side 中 - 可以根据 side 中的 schema 数据生成 schema - 可以在 side 中配置常见接口属性 - deprecated -- boolean, 是否已废弃, 默认 false - tags -- string[], 标签 - summary -- string, 摘要 - noDoc -- boolean, 不生成接口文档, 默认 false - 可以在 side 中操作当前接口文档的任意属性 - apiDocData -- yaml/json, 混入当前接口, 优先级最高 - todo // todo - [ ] feat: 支持为动态添加的接口生成文档 - [ ] feat: 支持 db 中的接口 - [ ] feat: 支持混入 tags, 当为函数时则为自定义混入 - [ ] feat: 支持 webApi 中的接口 - [ ] feat: 支持配置某个接口不显示在文档中 - [ ] feat: 支持扩展 use 和 all-method 以及 ws - https://github.com/OAI/OpenAPI-Specification/issues/1747 - 由于 openApi 不支持, 所以做以下处理 - use -- 被中间件处理的路由 - 中间件 xxx, xxx 工作在这个路由 - 应隐藏按钮 `Try it out` - ws -- 这是 websocket 接口, 请使用 websocket 连接它 - 应隐藏按钮 `Try it out` - all-methods -- 支持所有请求方法, 例如 get/post/put/... - [ ] feat: 支持本地化 swagger-ui - 当 css/js url 为相对地址时, 自动初始化本地依赖 - 当 url 为绝对地址时, 视为 cdn - [ ] apiDocDataRoute 支持引用线上地址, 此时不生成本地路由 - [ ] feat: 支持混入 apiDocData - 以 yaml 形式 - 以 json 形式 - 若某节点为 function 时, 表示自定义混入, 例如: ``` js { paths: { '/weddings/{id}/{name}': { post: { parameters(rawArg){ // 只返回一部分参数 return rawArg.slice(2, 4) }, } } } } ``` */ module.exports = { key: `apiDoc`, summary: `生成接口文档`, hostVersion: [], async main({ hostInfo, pluginConfig, config, util }) { pluginConfig = { ...pluginConfig, apiDocInit: true, // 是否启用文档,默认否 apiDocDataRoute: `/doc/openApi.json`, // openApi 数据地址 docPage: `/doc`, // 接口文档地址 apiDocData: { openapi: `3.0.0`, servers: [{ url: `http://${config.osIp}:${config.port}/` }], // 这里声明标签, 然后在 method 中引用时可以有描述, 如果这里未声明时没有描述 tags: [] } }; return { async apiParsed(api, apiUtil) { (0, _assign.default)(api, { [`get ${pluginConfig.docPage}`](req, res) { res.send(` <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <title>SwaggerUI</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@4.5.0/swagger-ui.css" /> </head> <body> <div id="swagger-ui"></div> <script src="https://cdn.jsdelivr.net/npm/swagger-ui-dist@4.5.0/swagger-ui-bundle.js"></script> <script> // 参数文档 https://github.com/swagger-api/swagger-ui/blob/master/docs/usage/configuration.md window.ui = SwaggerUIBundle({ url: 'http://${config.osIp}:${config.port}${pluginConfig.apiDocDataRoute}', dom_id: '#swagger-ui', docExpansion: 'none', // 折叠所有 }); </script> </body> </html> `); }, [`get ${pluginConfig.apiDocDataRoute}`](req, res) { res.json(pluginConfig.apiDocData); } }); }, /** * config.api 中的每个接口已解析完成 * 可以在这里使用它, 例如生成接口列表 * @param {*} serverRouterList */ async apiListParsed(serverRouterList = []) { const j2s = await util.tool.generate.initPackge(`joi-to-swagger`); const pathsAcc = {}; for (let index = 0; index < serverRouterList.length; index++) { var _context, _context2, _context3; const serverRouterItem = serverRouterList[index]; const schemaOpenApiSchema = (0, _reduce.default)(_context = (0, _entries.default)(serverRouterItem.schema || {})).call(_context, (acc, [key, val]) => { // todo 研究关于 j2s 的其他参数以发掘更多功能 acc[key] = j2s(val).swagger; return acc; }, {}); const path = serverRouterItem.route.replace(/:([a-z]\w*)/ig, `{$1}`); const method = serverRouterItem.method; const parameters = (0, _flat.default)(_context2 = (0, _reduce.default)(_context3 = [`header`, `path`, `query`, `cookie`]).call(_context3, (accIn, valueIn) => { var _context4; const schema = schemaOpenApiSchema[valueIn] || {}; const parameters = (0, _reduce.default)(_context4 = (0, _entries.default)(schema.properties || {})).call(_context4, (acc, [key, val]) => { var _context5; acc.push({ name: key, in: valueIn, required: (0, _includes.default)(_context5 = schema.required || []).call(_context5, key), description: val.description, schema: val, example: val.example }); return acc; }, []); accIn.push(parameters); return accIn; }, [])).call(_context2); const requestBody = (() => { const schema = schemaOpenApiSchema.body; if (schema) { return { description: schema.description, required: !schema.nullable, content: { 'application/json': { schema: schema } } }; } })(); const item = { deprecated: serverRouterItem.deprecated, tags: serverRouterItem.tags, summary: serverRouterItem.summary, parameters, requestBody, responses: { '200': requestBody } }; pathsAcc[path] = pathsAcc[path] || {}; pathsAcc[path][method] = pathsAcc[path][method] || {}; (0, _assign.default)(pathsAcc[path][method], item); } pluginConfig.apiDocData.paths = pathsAcc; } }; } };