/** * generator.ts — OpenAPIGenerator(OpenAPI 3.0 文档生成器) * * 接收 RouteMetadata[] 路由元信息列表,生成完整的 OpenAPI 3.0.3 文档。 * * 核心职责: * 1. 遍历路由元信息,为每条路由构建 Operation 对象 * 2. 将 validate.param / query → parameters * 3. 将 validate.body → requestBody * 4. 将 docs.responses → responses(成功响应自动包装为 { code, data, requestId }) * 5. 从 middlewares 推断 security(auth → bearerAuth) * 6. 从 middlewares 推断 x-rate-limit 扩展 * 7. 自动推断 tags(从文件路径)和 operationId(从方法+路径) * 8. 注册通用 ErrorResponse / SuccessResponse components/schemas * * 路径格式转换: * vext: /users/:id → OpenAPI: /users/{id} * vext: /files/*path → OpenAPI: /files/{path} * * @module lib/openapi/generator * @see 14-openapi.md §5(OpenAPIGenerator — 文档生成器) */ import type { RouteMetadata, OpenAPIConfig, OpenAPIDocument } from "./types.js"; /** * OpenAPIGenerator — OpenAPI 3.0 文档生成器 * * 无状态生成器(converter 内部也无状态),可安全多次调用 generate()。 * * @example * ```typescript * const generator = new OpenAPIGenerator({ * title: 'My API', * version: '1.0.0', * servers: [{ url: 'http://localhost:3000', description: 'Development' }], * }) * * const routes = collector.getRoutes() * const doc = generator.generate(routes) * const json = generator.generateJSON(routes) * ``` */ export declare class OpenAPIGenerator { private converter; private config; constructor(config?: OpenAPIConfig); /** * 生成完整的 OpenAPI 3.0 文档 * * @param routes RouteMetadata[] 路由元信息列表(由 collector.getRoutes() 提供) * @returns OpenAPIDocument 完整的 OpenAPI 3.0 文档对象 */ generate(routes: RouteMetadata[]): OpenAPIDocument; /** * 生成 JSON 格式的 OpenAPI 文档字符串 * * @param routes RouteMetadata[] 路由元信息列表 * @returns JSON 字符串(格式化缩进 2 空格) */ generateJSON(routes: RouteMetadata[]): string; /** * 构建单个路由的 Operation 对象 * * 依次处理: * 1. summary / operationId / tags / deprecated / description * 2. 路径参数(validate.param → parameters[in=path]) * 3. 查询参数(validate.query → parameters[in=query]) * 4. 请求体(validate.body → requestBody,仅 POST/PUT/PATCH) * 5. 响应(docs.responses → responses,成功响应自动包装) * 6. 默认响应(未声明时添加 200 OK) * 7. 安全方案(从 middlewares 或 docs.security 推断) * 8. 自定义扩展(docs.extensions → x-* 字段) * 9. 速率限制(从 rate-limit 中间件推断 x-rate-limit) * 10. 清空空参数数组 * * @param route 单条路由的元信息 * @returns OpenAPIOperation 对象 */ private buildOperation; /** * 包装响应 schema 为 vext 标准格式 * * 成功响应(2xx,非 204): * { code: 0, data: <原始 schema>, requestId: string } * * 204 No Content: * 空对象(无响应体) * * 错误响应(4xx/5xx): * 直接使用原始 schema(通常是 ErrorResponse 格式) * * @param statusCode HTTP 状态码 * @param dataSchema 原始数据 schema * @returns 包装后的 JsonSchema */ private wrapResponseSchema; /** * 包装响应示例为 vext 标准格式 * * 成功响应(2xx,非 204)自动包装为 { code: 0, data: ..., requestId: '...' } * 错误响应直接返回原始示例 * * @param statusCode HTTP 状态码 * @param example 原始示例值 * @returns 包装后的示例值 */ private wrapResponseExample; /** * 转换路由路径格式 * * vext 使用 Express 风格的路径参数(:param), * OpenAPI 使用花括号风格({param})。 * * vext: /users/:id → OpenAPI: /users/{id} * vext: /files/*path → OpenAPI: /files/{path} * * @param path vext 格式的路由路径 * @returns OpenAPI 格式的路由路径 */ private convertPath; /** * 从 middlewares 推断 security * * 检测 middleware 名称是否匹配 guardSecurityMap 中的 key。 * middlewares 可以是 string 或 { name, options } 对象,需统一提取 name。 * * 默认映射: * - 'auth' → bearerAuth * - 'api-key' → apiKeyAuth * * 用户可通过 config.guardSecurityMap 自定义映射。 * * @param middlewares 路由级中间件列表 * @returns 推断出的 security 数组 */ private inferSecurityFromMiddlewares; /** * 构建 securitySchemes * * 优先使用用户配置的 securitySchemes。 * 若未配置,提供默认的 Bearer Token 方案。 * * @returns securitySchemes 对象 */ private buildSecuritySchemes; /** * 从路由列表推断 tags * * 收集所有路由的 tags(显式声明或从文件路径推断), * 去重排序后返回。 * * @param routes 路由元信息列表 * @returns tag 定义列表(按名称排序) */ /** * 构建标签分组(x-tagGroups) * * 优先级: * 1. 用户在 config.tagGroups 中显式配置 → 直接使用 * 2. 未配置 → 自动从路由文件路径推断分组 * * 自动推断逻辑: * - 提取每条路由文件路径在 routes/ 之后的第一层目录名作为分组名 * - 同一分组下的所有 tags 归入该分组 * - 直接位于 routes/ 下的文件(如 routes/index.ts)归入 "General" 分组 * - 分组名首字母大写(如 api → Api, admin → Admin) * - 如果所有路由都在同一个分组中(无多级),则不生成 x-tagGroups(避免冗余) * * @param routes 路由元信息列表 * @param tags 已生成的 tags 列表(用于确保所有 tag 都被分组覆盖) * @returns tagGroups 数组,空数组表示不需要分组 */ private buildTagGroups; /** * 从路由文件路径自动推断标签分组 * * 策略: * - 提取 routes/ 之后的第一层目录名作为 group name * - 直接在 routes/ 下的文件归入 "General" 组 * - 每个 group 收集其下所有 tag(去重排序) * - 如果只有一个分组,返回空数组(不需要分组) * * @example * routes/users.ts → group "General", tag "users" * routes/api/v1/users.ts → group "Api", tag 从 docs.tags 或推断 * routes/admin/dashboard.ts→ group "Admin", tag 从 docs.tags 或推断 */ private inferTagGroups; private inferTags; /** * 从文件路径推断 tag * * 提取 routes/ 后面的相对路径,移除扩展名: * routes/users.ts → 'users' * routes/admin/roles.ts → 'admin-roles' * routes/index.ts → 'default' * * @param sourceFile 路由文件的绝对路径 * @returns 推断的 tag 名称 */ private inferTagFromFile; }