/** * schema-converter.ts — SchemaConverter(schema-dsl DSL → JSON Schema 转换器) * * 将 vext 路由 options 中的 schema-dsl DSL 字符串转换为标准 JSON Schema 格式, * 供 OpenAPIGenerator 嵌入 OpenAPI 3.0 文档的 parameters / requestBody / responses。 * * ⚡ v2.1 重构:使用 schema-dsl 的 toJsonSchema() 替代 toSchema() + 手动清理, * schema-dsl 现在直接输出纯净 JSON Schema(无 _required / _customMessages 等内部标记), * vext 无需再维护 cleanInternalMarkers() 和 SCHEMA_DSL_INTERNAL_KEYS。 * 仅保留 OpenAPI 特有的 description / example 富化作为后处理步骤。 * * 支持的 DSL 格式: * - 基础类型:string / number / integer / boolean / email / url / date / objectId / array / object / any * - 范围约束:string:1-50 / number:1-100 / integer:1- / string:8-! * - 必填标记:string:1-50! / email! / objectId!(后缀 `!`) * - 可选标记:url? / string:0-500?(后缀 `?`,映射为 nullable: true) * - 枚举类型:enum:a,b,c / enum:admin,user,guest! * - 嵌套对象:{ avatar: 'url?', bio: 'string:0-500?' } * - 嵌套数组:[{ productId: 'objectId!', name: 'string!' }] * - 引用字符串:'#/components/schemas/User'($ref) * * 转换规则详见设计文档 14-openapi.md §4.1。 * * @module lib/openapi/schema-converter * @see 14-openapi.md §4(SchemaConverter — schema-dsl → JSON Schema) */ import type { DslBuilder } from "../schema-adapter.js"; import type { JsonSchema, ConvertResult } from "./types.js"; /** * SchemaConverter — schema-dsl DSL → JSON Schema 转换器(v2.1 toJsonSchema 模式) * * 核心转换委托给 schemaAdapter(schema-dsl 防腐层), * 本类仅负责: * 1. 处理 schema-dsl 不支持的数组 DSL 语法([{...}]) * 2. 为 OpenAPI 文档添加 description / example 富化 * * 无状态转换器,所有方法均为纯函数(无副作用)。 * * @example * ```typescript * const converter = new SchemaConverter() * * // 转换 validate 对象 * const result = converter.convertValidateObject({ * name: 'string:1-50!', * email: 'email!', * age: 'integer:0-150?', * }) * // result.schema = { type: 'object', properties: { name: ..., email: ..., age: ... }, required: ['name', 'email'] } * // result.required = ['name', 'email'] * * // 转换单个 DSL 字符串 * const { schema, isRequired } = converter.convertDSLString('string:1-50!') * // schema = { type: 'string', minLength: 1, maxLength: 50, description: '...', example: '...' } * // isRequired = true * ``` */ export declare class SchemaConverter { /** * 将 schema-dsl 的 validate 对象转换为 JSON Schema * * 输入:schema-dsl 格式的对象(路由 options.validate.body / query / params 等) * 输出:JSON Schema 对象 + 必填字段列表 * * 支持三种值类型: * 1. 字符串 DSL:'string:1-50!' / 'email!' / 'number:1-100' * 2. 数组类型:[{ productId: 'objectId!', name: 'string!' }](嵌套对象数组) * 3. 嵌套对象:{ avatar: 'url?', bio: 'string:0-500?' } * * 实现策略: * - 字符串 DSL → 委托 schemaAdapter.compileField().toSchema() + 富化 * - 嵌套对象 → 委托 schemaAdapter.compile() 获取完整 schema + 逐字段富化 * - 数组 DSL → 自行处理(schema-dsl DslDefinition 不支持数组语法) * * @param dslObj schema-dsl 格式的对象 * @returns ConvertResult { schema, required } */ convertValidateObject(dslObj: Record): ConvertResult; /** * 转换单个 DSL 字符串 * * 委托 schemaAdapter.compileField() 获取 DslBuilder, * 调用 .toSchema() 获取基础 JSON Schema, * 然后叠加 OpenAPI 特有的 description / example 富化。 * * @param dsl schema-dsl 字符串(如 'string:1-50!' / 'email?' / 'enum:a,b,c') * @returns { schema: JsonSchema, isRequired: boolean } */ convertDSLString(dsl: string): { schema: JsonSchema; isRequired: boolean; }; /** * 转换字段级 DslBuilder。 * * 支持 schema-dsl 的 String 扩展写法: * `"string:1-50!".description("用户名")`,以及 `dsl("string!").description(...)`。 */ convertDSLBuilder(builder: DslBuilder): { schema: JsonSchema; isRequired: boolean; }; /** * 将 docs.responses 中的 schema 进行转换 * * response schema 支持两种格式: * 1. 引用字符串:'#/components/schemas/User' → { $ref: '...' } * 2. schema-dsl 对象(与 validate 格式一致)→ 递归转换 * * @param schema 响应 schema(字符串引用或 DSL 对象) * @returns JsonSchema 对象 */ convertResponseSchema(schema: Record | string): JsonSchema; /** * 根据 DSL 字符串自动生成人类可读的 description * * 示例: * 'string:1-50' + required → "Required. String, 1-50 chars." * 'email' + optional → "Optional (nullable). Email address." * 'enum:a,b,c' → "Optional. Enum: a, b, c." * 'integer:0-150' + optional → "Optional (nullable). Integer, range 0-150." * * @param dsl 不含后缀标记的 DSL 字符串 * @param required 是否必填 * @param nullable 是否可空 * @returns 描述字符串 */ private buildDescription; /** * 根据 JSON Schema 生成人类可读的兜底 description。 * * DslBuilder 可能没有原始 DSL 字符串可用,因此从 toJsonSchema() 输出反推 * 约束说明;用户调用 .description() 时会优先保留业务描述。 */ private buildSchemaDescription; /** * 将 DSL 类型名映射为人类可读名称 */ private humanTypeName; /** * 根据 schema 类型和 DSL 推断合理的 example 值 * * @param schema 已转换的 JSON Schema * @param dsl 不含后缀的 DSL 字符串 * @returns 示例值 */ private inferExample; }