From c96ac73dcfa428f4f680b392886d1d455d71fb71 Mon Sep 17 00:00:00 2001 From: snowgitea Date: Wed, 1 Jul 2026 17:57:18 +0800 Subject: [PATCH] chore: src/modules/swagger/builder.ts --- src/modules/swagger/builder.ts | 316 +++++++++++++++++++++++++++++++++ 1 file changed, 316 insertions(+) create mode 100644 src/modules/swagger/builder.ts diff --git a/src/modules/swagger/builder.ts b/src/modules/swagger/builder.ts new file mode 100644 index 0000000..576db92 --- /dev/null +++ b/src/modules/swagger/builder.ts @@ -0,0 +1,316 @@ +import { CoolEps } from '@cool-midway/core'; +import { Config, Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core'; +import * as _ from 'lodash'; + +/** + * 构建文档 + */ +@Provide() +@Scope(ScopeEnum.Singleton) +export class SwaggerBuilder { + @Config('module.swagger.base') + swaggerBase; + + @Inject() + eps: CoolEps; + + json = {}; + + @Config('cool.eps') + epsConfig: boolean; + + /** + * 初始化 + */ + async init() { + if (this.epsConfig) { + this.build(); + } + } + + /** + * 构建文档 + */ + async build() { + const epsData = { + app: this.eps.app || [], + admin: this.eps.admin || [], + module: this.eps.module || {}, + }; + this.json = this.convertToSwagger(epsData); + } + + /** + * Epss转换为Swagger + * @param dataJson + * @returns + */ + convertToSwagger(dataJson) { + const swagger = { + ...this.swaggerBase, + paths: {}, + tags: Object.keys(dataJson.module) + .filter(item => item != 'swagger') + .map(moduleKey => { + return { + key: moduleKey, + name: dataJson.module[moduleKey].name || '', + description: dataJson.module[moduleKey].description || '', + }; + }), + }; + // 添加组件 + function addComponentSchemas(data) { + if (_.isEmpty(data.name)) return; + const schema = { + type: 'object', + properties: {}, + required: [], + }; + + data.columns.forEach(column => { + const swaggerType = mapTypeToSwagger(column.type); + schema.properties[column.propertyName] = { + type: swaggerType, + description: column.comment, + }; + + if (!column.nullable) { + schema.required.push(column.propertyName); + } + }); + + swagger.components.schemas[data.name] = schema; + return data.name; + } + // 转换类型 + function mapTypeToSwagger(type) { + const typeMapping = { + string: 'string', + number: 'number', + bigint: 'integer', + datetime: 'string', // assuming datetime is formatted as ISO8601 string + }; + return typeMapping[type] || 'string'; + } + // 添加请求体 + function addRequest(path, schemas, data) { + if (path == '/info' || path == '/list' || path == '/page') { + if (path == '/info') { + data.parameters = [ + { + name: 'id', + in: 'query', + description: 'ID', + required: true, + schema: { + type: 'integer', + }, + }, + ]; + } else { + data.requestBody = { + description: '动态请求体', + required: true, + content: { + 'application/json': { + schema: { + type: 'object', + properties: + path == '/page' + ? { + page: { + type: 'integer', + description: '第几页', + default: 1, + }, + size: { + type: 'integer', + description: '每页大小', + default: 20, + }, + } + : {}, + }, + }, + }, + }; + } + data.responses = { + '200': { + description: '成功响应', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + code: { + type: 'integer', + description: '状态码', + }, + message: { + type: 'string', + description: '响应消息', + }, + data: { + $ref: `#/components/schemas/${schemas}`, + }, + }, + }, + }, + }, + }, + }; + } + if (path == '/add' || path == '/update') { + data.requestBody = { + description: schemas, + required: true, + content: { + 'application/json': { + schema: { + $ref: `#/components/schemas/${schemas}`, + }, + }, + }, + }; + data.responses = { + '200': { + description: '成功响应', + content: { + 'application/json': { + example: { + code: 1000, + message: 'success', + data: { + id: 6, + }, + }, + }, + }, + }, + }; + } + if (path == '/delete') { + data.requestBody = { + description: schemas, + required: true, + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + ids: { + type: 'array', + description: 'ID数组', + items: { + type: 'integer', + }, + }, + }, + }, + }, + }, + }; + data.responses = { + '200': { + description: '成功响应', + content: { + 'application/json': { + example: { + code: 1000, + message: 'success', + }, + }, + }, + }, + }; + } + } + // 处理每个模块下的API接口 + function processModuleApis(moduleApis, moduleName) { + moduleApis.forEach(module => { + const schemas = addComponentSchemas({ + name: module.name, + columns: module.columns, + }); + if (Array.isArray(module.api)) { + module.api.forEach(api => { + const fullPath = `${api.prefix == '/' ? '' : api.prefix}${ + api.path + }`; + const method = api.method.toLowerCase(); + + if (!swagger.paths[fullPath]) { + swagger.paths[fullPath] = {}; + } + + swagger.paths[fullPath][method] = { + summary: + `【${module.info.type.description || module.info.type.name}】` + + api.summary || '', + security: api.ignoreToken + ? [] + : [ + { + ApiKeyAuth: [], + }, + ], + tags: [moduleName || '其他'], + requestBody: + method == 'post' + ? { + description: '请求体', + required: true, + content: { + 'application/json': { + schema: { + type: 'object', + properties: {}, + }, + }, + }, + } + : {}, + responses: schemas + ? { + '200': { + description: 'Success response', + content: { + 'application/json': { + schema: { + $ref: `#/components/schemas/${schemas}`, + }, + }, + }, + }, + } + : {}, + }; + addRequest(api.path, schemas, swagger.paths[fullPath][method]); + }); + } + }); + } + + // 遍历app和admin中的所有模块 + Object.keys(dataJson.app).forEach(moduleKey => { + if (Array.isArray(dataJson.app[moduleKey])) { + processModuleApis( + dataJson.app[moduleKey], + dataJson.module[moduleKey]?.name + ); + } + }); + Object.keys(dataJson.admin).forEach(moduleKey => { + if (Array.isArray(dataJson.admin[moduleKey])) { + processModuleApis( + dataJson.admin[moduleKey], + dataJson.module[moduleKey]?.name + ); + } + }); + + return swagger; + } +}