@alt-stack/zod-openapi 1.1.2 → 1.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +8 -8
- package/dist/index.cjs +243 -34
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +243 -34
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/schema-dedup.ts +199 -0
- package/src/to-typescript.spec.ts +218 -0
- package/src/to-typescript.ts +228 -34
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/dependencies.ts","../src/types/boolean.ts","../src/types/number.ts","../src/registry.ts","../src/types/string.ts","../src/types/array.ts","../src/types/object.ts","../src/types/union.ts","../src/types/intersection.ts","../src/to-zod.ts","../src/routes.ts","../src/to-typescript.ts"],"sourcesContent":["import type { AnySchema } from \"./types/types\";\n\n/**\n * Extracts all schema references ($ref) from an OpenAPI schema by recursively\n * traversing its structure.\n *\n * This function is used during the OpenAPI-to-Zod conversion process to identify\n * which schemas a given schema depends on. It traverses all OpenAPI schema\n * structures including objects, arrays, unions (oneOf), intersections (allOf),\n * conditionals (if/then/else), and discriminator mappings to find all $ref\n * references that point to other schemas in the components/schemas section.\n *\n * The extracted dependency names are used by `topologicalSortSchemas` to build\n * a dependency graph and determine the correct order for generating Zod schemas,\n * ensuring that referenced schemas are defined before they are used in the\n * generated TypeScript code.\n *\n * @param schema - The OpenAPI schema to extract dependencies from\n * @returns An array of schema names that this schema references (via $ref)\n */\nexport function extractSchemaDependencies(schema: AnySchema): string[] {\n const dependencies: Set<string> = new Set();\n const visited = new WeakSet();\n\n function traverse(obj: any): void {\n if (!obj || typeof obj !== \"object\") return;\n\n if (visited.has(obj)) return;\n visited.add(obj);\n\n if (obj[\"$ref\"] && typeof obj[\"$ref\"] === \"string\") {\n const match = (obj[\"$ref\"] as string).match(\n /#\\/components\\/schemas\\/(.+)/,\n );\n if (match && match[1]) {\n dependencies.add(decodeURIComponent(match[1]));\n }\n return;\n }\n\n if (Array.isArray(obj)) {\n obj.forEach(traverse);\n return;\n }\n\n if (obj.properties && typeof obj.properties === \"object\") {\n for (const propValue of Object.values(obj.properties)) {\n traverse(propValue);\n }\n }\n\n const schemaKeys = [\n \"items\",\n \"oneOf\",\n \"allOf\",\n \"anyOf\",\n \"not\",\n \"if\",\n \"then\",\n \"else\",\n \"prefixItems\",\n \"contains\",\n \"propertyNames\",\n \"dependentSchemas\",\n ];\n\n for (const key of schemaKeys) {\n if (obj[key]) {\n traverse(obj[key]);\n }\n }\n\n if (\n obj.additionalProperties &&\n typeof obj.additionalProperties === \"object\"\n ) {\n traverse(obj.additionalProperties);\n }\n\n if (obj.discriminator?.mapping) {\n Object.values(obj.discriminator.mapping).forEach(traverse);\n }\n }\n\n traverse(schema);\n return Array.from(dependencies);\n}\n\n/**\n * Sorts OpenAPI schemas topologically based on their dependencies to ensure\n * correct generation order.\n *\n * When converting OpenAPI schemas to Zod schemas and generating TypeScript code,\n * schemas must be defined before they are referenced. For example, if `UserSchema`\n * references `ProfileSchema` (via $ref), then `ProfileSchema` must be generated\n * before `UserSchema` to avoid \"undefined variable\" errors in the generated code.\n *\n * This function uses Kahn's algorithm for topological sorting to order schemas\n * such that all dependencies come before their dependents. It:\n * 1. Extracts dependencies for each schema using `extractSchemaDependencies`\n * 2. Builds a dependency graph and computes in-degrees\n * 3. Sorts schemas starting with those that have no dependencies (in-degree 0)\n * 4. Handles circular dependencies gracefully by appending any remaining schemas\n * that couldn't be sorted (though this indicates a problematic schema structure)\n *\n * This function is called by `openApiToZodTsCode` to determine the order in which\n * schemas should be converted and emitted in the generated TypeScript file.\n *\n * @param schemas - A record mapping schema names to their OpenAPI schema definitions\n * @returns An array of schema names sorted in topological order (dependencies before dependents)\n */\nexport function topologicalSortSchemas(\n schemas: Record<string, AnySchema>,\n): string[] {\n const schemaNames = Object.keys(schemas);\n const dependencies: Map<string, string[]> = new Map();\n const inDegree: Map<string, number> = new Map();\n const sorted: string[] = [];\n const queue: string[] = [];\n const dependents: Map<string, string[]> = new Map();\n\n for (const name of schemaNames) {\n dependencies.set(name, []);\n dependents.set(name, []);\n inDegree.set(name, 0);\n }\n\n for (const name of schemaNames) {\n const schemaValue = schemas[name];\n if (schemaValue) {\n const deps = extractSchemaDependencies(schemaValue);\n const validDeps = deps.filter((dep) => schemaNames.includes(dep));\n dependencies.set(name, validDeps);\n\n for (const dep of validDeps) {\n const currentDependents = dependents.get(dep) || [];\n currentDependents.push(name);\n dependents.set(dep, currentDependents);\n }\n }\n }\n\n for (const [name, deps] of dependencies.entries()) {\n inDegree.set(name, deps.length);\n }\n\n for (const [name, degree] of inDegree.entries()) {\n if (degree === 0) {\n queue.push(name);\n }\n }\n\n while (queue.length > 0) {\n const current = queue.shift()!;\n sorted.push(current);\n\n const currentDependents = dependents.get(current) || [];\n for (const dependent of currentDependents) {\n const newDegree = (inDegree.get(dependent) || 0) - 1;\n inDegree.set(dependent, newDegree);\n if (newDegree === 0) {\n queue.push(dependent);\n }\n }\n }\n\n if (sorted.length !== schemaNames.length) {\n for (const name of schemaNames) {\n if (!sorted.includes(name)) {\n sorted.push(name);\n }\n }\n }\n\n return sorted;\n}\n","/**\n * Convert an OpenAPI v3 boolean schema to a Zod schema string\n */\nexport function convertOpenAPIBooleanToZod(_: { type: \"boolean\" }): string {\n return \"z.boolean()\";\n}\n","/**\n * Convert an OpenAPI v3 number/integer schema to a Zod schema string\n */\nexport function convertOpenAPINumberToZod(schema: {\n type: \"number\" | \"integer\";\n minimum?: number;\n maximum?: number;\n}): string {\n let result = \"z.number()\";\n if (schema.type === \"integer\") {\n result += \".int()\";\n }\n if (typeof schema.minimum === \"number\") {\n result += `.min(${schema.minimum})`;\n }\n if (typeof schema.maximum === \"number\") {\n result += `.max(${schema.maximum})`;\n }\n return result;\n}\n","import { z } from \"zod\";\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst SUPPORTED_STRING_FORMATS_MAP = {\n \"color-hex\": 1,\n date: 1,\n \"date-time\": 1,\n email: 1,\n \"iso-date\": 1,\n \"iso-date-time\": 1,\n objectid: 1,\n uri: 1,\n url: 1,\n uuid: 1,\n} as const;\n\nexport const SUPPORTED_STRING_FORMATS = Object.keys(\n SUPPORTED_STRING_FORMATS_MAP,\n) as unknown as keyof typeof SUPPORTED_STRING_FORMATS_MAP;\n\ntype SupportedStringFormat = typeof SUPPORTED_STRING_FORMATS;\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type ZodOpenApiRegistrationString<\n F extends SupportedStringFormat = SupportedStringFormat,\n> = {\n /** The name of the schema variable, IMPORTANT: must be named the same as the variable name */\n schemaExportedVariableName: string;\n type: \"string\";\n description?: string;\n format: F;\n};\n\nexport type ZodOpenApiRegistrationStrings<\n Fs extends\n readonly SupportedStringFormat[] = readonly SupportedStringFormat[],\n> = {\n /** The name of the schema variable, IMPORTANT: must be named the same as the variable name */\n schemaExportedVariableName: string;\n type: \"string\";\n description?: string;\n formats: Fs;\n};\n\nexport type ZodOpenApiRegistrationPrimitive = {\n /** The name of the schema variable, IMPORTANT: must be named the same as the variable name */\n schemaExportedVariableName: string;\n description?: string;\n type: \"number\" | \"integer\" | \"boolean\";\n};\n\nexport type ZodOpenApiRegistration =\n | ZodOpenApiRegistrationString\n | ZodOpenApiRegistrationStrings\n | ZodOpenApiRegistrationPrimitive;\n\n// ============================================================================\n// Type Guards\n// ============================================================================\n\nfunction isStringRegistration(\n reg: ZodOpenApiRegistration,\n): reg is ZodOpenApiRegistrationString {\n return reg.type === \"string\" && \"format\" in reg;\n}\n\nfunction isStringsRegistration(\n reg: ZodOpenApiRegistration,\n): reg is ZodOpenApiRegistrationStrings {\n return reg.type === \"string\" && \"formats\" in reg;\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\ntype TypeFormatPair = { type: string; format: string | undefined };\n\nfunction getTypeFormatPairs(reg: ZodOpenApiRegistration): TypeFormatPair[] {\n if (isStringRegistration(reg)) {\n return [{ type: \"string\", format: reg.format }];\n }\n\n if (isStringsRegistration(reg)) {\n return reg.formats.map((f) => ({ type: \"string\", format: f }));\n }\n\n return [];\n}\n\n// ============================================================================\n// Registry Class\n// ============================================================================\n\n/**\n * Global registry for mapping Zod schemas to OpenAPI schema representations\n */\nclass ZodSchemaRegistry {\n private readonly map = new Map<z.ZodTypeAny, ZodOpenApiRegistration>();\n\n /**\n * Register a Zod schema with its OpenAPI representation\n */\n register<F extends SupportedStringFormat>(\n schema: z.ZodTypeAny,\n registration: ZodOpenApiRegistrationString<F>,\n ): void;\n register<Fs extends readonly SupportedStringFormat[]>(\n schema: z.ZodTypeAny,\n registration: ZodOpenApiRegistrationStrings<Fs>,\n ): void;\n register(\n schema: z.ZodTypeAny,\n registration: ZodOpenApiRegistrationPrimitive,\n ): void;\n register(schema: z.ZodTypeAny, registration: ZodOpenApiRegistration): void {\n const newPairs = getTypeFormatPairs(registration);\n\n if (newPairs.length > 0) {\n for (const [existingSchema, existingRegistration] of this.map.entries()) {\n if (existingSchema === schema) continue;\n\n const existingPairs = getTypeFormatPairs(existingRegistration);\n for (const { type, format } of newPairs) {\n if (\n existingPairs.some((p) => p.type === type && p.format === format)\n ) {\n throw new Error(\n `duplicate Zod OpenAPI registration for (type, format)=('${type}', '${format as string}')`,\n );\n }\n }\n }\n }\n\n this.map.set(schema, registration);\n }\n\n /**\n * Get the OpenAPI schema for a given Zod schema\n */\n getOpenApiSchema(schema: z.ZodTypeAny): ZodOpenApiRegistration | undefined {\n return this.map.get(schema);\n }\n\n /**\n * Check if a Zod schema is registered\n */\n isRegistered(schema: z.ZodTypeAny): boolean {\n return this.map.has(schema);\n }\n\n /**\n * Clear all registered schemas\n */\n clear(): void {\n this.map.clear();\n }\n\n /**\n * Reverse-lookup helper: given a string format, return the registered schema's exported variable name\n */\n getSchemaExportedVariableNameForStringFormat(\n format: SupportedStringFormat,\n ): string | undefined {\n for (const registration of this.map.values()) {\n if (registration.type !== \"string\") continue;\n\n if (\n isStringRegistration(registration) &&\n registration.format === format\n ) {\n return registration.schemaExportedVariableName;\n }\n\n if (\n isStringsRegistration(registration) &&\n registration.formats.includes(format)\n ) {\n return registration.schemaExportedVariableName;\n }\n }\n return undefined;\n }\n}\n\n// ============================================================================\n// Global Registry Instance\n// ============================================================================\n\nexport const schemaRegistry = new ZodSchemaRegistry();\n\n// ============================================================================\n// Public API\n// ============================================================================\n\n/**\n * Helper function to register a Zod schema with its OpenAPI representation\n */\nexport function registerZodSchemaToOpenApiSchema(\n schema: z.ZodTypeAny,\n openApiSchema: ZodOpenApiRegistration,\n): void {\n schemaRegistry.register(schema, openApiSchema as any);\n}\n\n/**\n * Convenience helper to get an exported schema variable name for a given string format\n */\nexport function getSchemaExportedVariableNameForStringFormat(\n format: SupportedStringFormat,\n): string | undefined {\n return schemaRegistry.getSchemaExportedVariableNameForStringFormat(format);\n}\n\n/**\n * Clear all registered schemas in the global registry\n */\nexport function clearZodSchemaToOpenApiSchemaRegistry(): void {\n schemaRegistry.clear();\n}\n","import {\n getSchemaExportedVariableNameForStringFormat,\n SUPPORTED_STRING_FORMATS,\n} from \"../registry\";\n\n/**\n * Convert an OpenAPI v3 string schema to a Zod schema string\n */\nexport function convertOpenAPIStringToZod(schema: {\n type: \"string\";\n format?: typeof SUPPORTED_STRING_FORMATS;\n minLength?: number;\n maxLength?: number;\n pattern?: string;\n enum?: string[];\n}): string {\n // Handle enum values\n if (schema.enum) {\n return `z.enum([${schema.enum.map((value) => `'${value}'`).join(\", \")}])`;\n }\n\n // Check for custom registered format schemas\n if (schema.format && SUPPORTED_STRING_FORMATS.includes(schema.format)) {\n const customSchemaName = getSchemaExportedVariableNameForStringFormat(\n schema.format,\n );\n\n // Use custom schema if registered (ignores other constraints)\n if (customSchemaName) {\n return customSchemaName;\n }\n }\n\n // Build string schema with format modifiers\n let zodSchema = \"z.string()\";\n\n if (schema.format) {\n zodSchema += getFormatModifier(schema.format);\n }\n\n // Apply length constraints\n if (typeof schema.minLength === \"number\") {\n zodSchema += `.min(${schema.minLength})`;\n }\n\n if (typeof schema.maxLength === \"number\") {\n zodSchema += `.max(${schema.maxLength})`;\n }\n\n // Apply pattern constraint\n if (typeof schema.pattern === \"string\") {\n zodSchema += `.regex(/${schema.pattern}/)`;\n }\n\n return zodSchema;\n}\n\n/**\n * Get the Zod modifier for built-in string formats\n */\nfunction getFormatModifier(format: string): string {\n switch (format) {\n case \"email\":\n return \".email()\";\n case \"url\":\n case \"uri\":\n return \".url()\";\n case \"uuid\":\n return \".uuid()\";\n case \"color-hex\":\n return \".regex(/^[a-fA-F0-9]{6}$/)\";\n default:\n return \"\";\n }\n}\n","import type { AnySchema } from \"./types\";\n\nexport function convertOpenAPIArrayToZod(\n schema: {\n type: \"array\";\n items?: any;\n minItems?: number;\n maxItems?: number;\n },\n convertSchema: (schema: AnySchema) => string,\n): string {\n const item = schema.items;\n\n let itemZodString = \"z.unknown()\";\n if (item && typeof item === \"object\") {\n itemZodString = convertSchema(item);\n }\n\n let result = `z.array(${itemZodString})`;\n\n if (typeof schema.minItems === \"number\") {\n result += `.min(${schema.minItems})`;\n }\n if (typeof schema.maxItems === \"number\") {\n result += `.max(${schema.maxItems})`;\n }\n\n return result;\n}\n","import { AnySchema, OpenAPIObjectSchema } from \"./types\";\n\nconst validIdentifierRegex = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;\n\nfunction quotePropertyName(name: string): string {\n return validIdentifierRegex.test(name) ? name : `'${name}'`;\n}\n\nexport function convertOpenAPIObjectToZod(\n schema: OpenAPIObjectSchema,\n convertSchema: (schema: AnySchema) => string,\n): string {\n const properties = schema.properties || {};\n const propertyNames = Object.keys(properties);\n\n if (propertyNames.length === 0) {\n if (schema.additionalProperties === false) {\n return \"z.object({}).strict()\";\n }\n return \"z.record(z.string(), z.unknown())\";\n }\n\n const requiredSet = new Set(schema.required || []);\n\n const entries: string[] = [];\n for (const [propName, propSchema] of Object.entries(properties)) {\n let zodProp = \"z.unknown()\";\n\n if (propSchema && typeof propSchema === \"object\") {\n zodProp = convertSchema(propSchema);\n }\n\n if (!requiredSet.has(propName)) {\n zodProp += \".optional()\";\n }\n\n entries.push(`${quotePropertyName(propName)}: ${zodProp}`);\n }\n\n let result = `z.object({ ${entries.join(\", \")} })`;\n\n if (schema.additionalProperties === false) {\n result += \".strict()\";\n }\n\n return result;\n}\n","import type { AnySchema } from \"./types\";\n\nexport function convertOpenAPIUnionToZod(\n schema: { oneOf: AnySchema[] },\n convertSchema: (schema: AnySchema) => string,\n): string {\n const items = schema.oneOf.map((item) => convertSchema(item));\n return `z.union([${items.join(\", \")}])`;\n}\n\n","import type { AnySchema } from \"./types\";\n\nexport function convertOpenAPIIntersectionToZod(\n schema: { allOf: AnySchema[] },\n convertSchema: (schema: AnySchema) => string,\n): string {\n const items = schema.allOf.map((item) => convertSchema(item));\n\n if (schema.allOf.length === 0) return \"z.unknown()\";\n if (schema.allOf.length === 1) return convertSchema(schema.allOf[0]!);\n\n return `z.intersection(${items.join(\", \")})`;\n}\n\n","import { convertOpenAPIBooleanToZod } from \"./types/boolean\";\nimport { convertOpenAPINumberToZod } from \"./types/number\";\nimport { convertOpenAPIStringToZod } from \"./types/string\";\nimport { convertOpenAPIArrayToZod } from \"./types/array\";\nimport { convertOpenAPIObjectToZod } from \"./types/object\";\nimport { convertOpenAPIUnionToZod } from \"./types/union\";\nimport { convertOpenAPIIntersectionToZod } from \"./types/intersection\";\nimport type { AnySchema } from \"./types/types\";\n\nexport function convertSchemaToZodString(schema: AnySchema): string {\n if (!schema || typeof schema !== \"object\") return \"z.unknown()\";\n\n if (schema[\"$ref\"] && typeof schema[\"$ref\"] === \"string\") {\n const match = (schema[\"$ref\"] as string).match(\n /#\\/components\\/schemas\\/(.+)/,\n );\n let result = \"z.unknown()\";\n if (match && match[1]) {\n result = `${match[1]}Schema`;\n }\n if (schema[\"nullable\"] === true) {\n result = `z.union([${result}, z.null()])`;\n }\n return result;\n }\n let result: string = \"z.unknown()\";\n\n if (\"oneOf\" in schema && Array.isArray(schema[\"oneOf\"])) {\n result = convertOpenAPIUnionToZod(\n schema as { oneOf: AnySchema[] },\n convertSchemaToZodString,\n );\n } else if (\"allOf\" in schema && Array.isArray(schema[\"allOf\"])) {\n result = convertOpenAPIIntersectionToZod(\n schema as { allOf: AnySchema[] },\n convertSchemaToZodString,\n );\n } else {\n switch (schema[\"type\"]) {\n case \"string\":\n result = convertOpenAPIStringToZod({\n enum: schema[\"enum\"],\n format: schema[\"format\"],\n maxLength: schema[\"maxLength\"],\n minLength: schema[\"minLength\"],\n pattern: schema[\"pattern\"],\n type: \"string\",\n });\n break;\n case \"number\":\n result = convertOpenAPINumberToZod({\n maximum: schema[\"maximum\"],\n minimum: schema[\"minimum\"],\n type: \"number\",\n });\n break;\n case \"integer\":\n result = convertOpenAPINumberToZod({\n maximum: schema[\"maximum\"],\n minimum: schema[\"minimum\"],\n type: \"integer\",\n });\n break;\n case \"boolean\":\n result = convertOpenAPIBooleanToZod({ type: \"boolean\" });\n break;\n case \"array\":\n result = convertOpenAPIArrayToZod(\n {\n items: schema[\"items\"],\n maxItems: schema[\"maxItems\"],\n minItems: schema[\"minItems\"],\n type: \"array\",\n },\n convertSchemaToZodString,\n );\n break;\n case \"object\":\n result = convertOpenAPIObjectToZod(\n {\n additionalProperties: schema[\"additionalProperties\"],\n properties: schema[\"properties\"],\n required: schema[\"required\"],\n type: \"object\",\n },\n convertSchemaToZodString,\n );\n break;\n default:\n if (schema[\"properties\"]) {\n result = convertOpenAPIObjectToZod(\n {\n additionalProperties: schema[\"additionalProperties\"],\n properties: schema[\"properties\"],\n required: schema[\"required\"],\n type: \"object\",\n },\n convertSchemaToZodString,\n );\n } else {\n result = \"z.unknown()\";\n }\n break;\n }\n }\n\n if (schema[\"nullable\"] === true) {\n result = `z.union([${result}, z.null()])`;\n }\n\n return result;\n}\n","import type { AnySchema } from \"./types/types\";\n\nexport type HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\" | \"HEAD\" | \"OPTIONS\";\n\nexport interface RouteParameter {\n name: string;\n in: \"path\" | \"query\" | \"header\" | \"cookie\";\n required: boolean;\n schema: AnySchema;\n}\n\nexport interface RouteInfo {\n path: string;\n method: HttpMethod;\n parameters: RouteParameter[];\n requestBody?: AnySchema;\n responses: Record<string, AnySchema>;\n}\n\nexport interface RouteSchemaNames {\n paramsSchemaName?: string;\n querySchemaName?: string;\n headersSchemaName?: string;\n bodySchemaName?: string;\n responseSchemaName?: string;\n}\n\nfunction toUpperCaseMethod(method: string): HttpMethod {\n const upper = method.toUpperCase();\n if (\n upper === \"GET\" ||\n upper === \"POST\" ||\n upper === \"PUT\" ||\n upper === \"PATCH\" ||\n upper === \"DELETE\" ||\n upper === \"HEAD\" ||\n upper === \"OPTIONS\"\n ) {\n return upper as HttpMethod;\n }\n return \"GET\";\n}\n\nfunction toPascalCase(str: string): string {\n return str\n .replace(/[^a-zA-Z0-9]/g, \" \")\n .split(\" \")\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n .join(\"\");\n}\n\nfunction generateRouteSchemaName(\n path: string,\n method: HttpMethod,\n suffix: string,\n): string {\n const pathParts = path\n .split(\"/\")\n .filter((p) => p)\n .map((p) => {\n if (p.startsWith(\"{\") && p.endsWith(\"}\")) {\n return p.slice(1, -1);\n }\n return p;\n })\n .map(toPascalCase);\n const methodPrefix = method.charAt(0) + method.slice(1).toLowerCase();\n const parts = [methodPrefix, ...pathParts, suffix];\n return parts.join(\"\");\n}\n\nexport function parseOpenApiPaths(\n openapi: Record<string, unknown>,\n): RouteInfo[] {\n const paths = (openapi as AnySchema)[\"paths\"] as\n | Record<string, AnySchema>\n | undefined;\n if (!paths) {\n return [];\n }\n\n const routes: RouteInfo[] = [];\n\n for (const [path, pathItem] of Object.entries(paths)) {\n if (!pathItem || typeof pathItem !== \"object\") continue;\n\n const methods = [\n \"get\",\n \"post\",\n \"put\",\n \"patch\",\n \"delete\",\n \"head\",\n \"options\",\n ] as const;\n\n for (const method of methods) {\n const operation = pathItem[method] as AnySchema | undefined;\n if (!operation) continue;\n\n const parameters: RouteParameter[] = [];\n const responses: Record<string, AnySchema> = {};\n\n if (Array.isArray(pathItem[\"parameters\"])) {\n for (const param of pathItem[\"parameters\"]) {\n if (param && typeof param === \"object\") {\n parameters.push({\n name: String(param[\"name\"] || \"\"),\n in: param[\"in\"] || \"query\",\n required: Boolean(param[\"required\"]),\n schema: param[\"schema\"] || {},\n });\n }\n }\n }\n\n if (Array.isArray(operation[\"parameters\"])) {\n for (const param of operation[\"parameters\"]) {\n if (param && typeof param === \"object\") {\n parameters.push({\n name: String(param[\"name\"] || \"\"),\n in: param[\"in\"] || \"query\",\n required: Boolean(param[\"required\"]),\n schema: param[\"schema\"] || {},\n });\n }\n }\n }\n\n let requestBody: AnySchema | undefined;\n if (operation[\"requestBody\"]) {\n const rb = operation[\"requestBody\"];\n if (rb && typeof rb === \"object\") {\n const content = rb[\"content\"];\n if (content && typeof content === \"object\") {\n const jsonContent = content[\"application/json\"];\n if (jsonContent && typeof jsonContent === \"object\") {\n requestBody = jsonContent[\"schema\"] || {};\n }\n }\n }\n }\n\n if (operation[\"responses\"] && typeof operation[\"responses\"] === \"object\") {\n for (const [statusCode, response] of Object.entries(\n operation[\"responses\"],\n )) {\n if (response && typeof response === \"object\") {\n const responseSchema = response as AnySchema;\n const content = responseSchema[\"content\"];\n if (content && typeof content === \"object\") {\n const jsonContent = content[\"application/json\"];\n if (jsonContent && typeof jsonContent === \"object\") {\n const schema = jsonContent[\"schema\"];\n if (schema) {\n responses[statusCode] = schema;\n }\n }\n }\n }\n }\n }\n\n routes.push({\n path,\n method: toUpperCaseMethod(method),\n parameters,\n requestBody,\n responses,\n });\n }\n }\n\n return routes;\n}\n\nexport function generateRouteSchemaNames(\n route: RouteInfo,\n): RouteSchemaNames {\n const pathParams = route.parameters.filter((p) => p.in === \"path\");\n const queryParams = route.parameters.filter((p) => p.in === \"query\");\n const headerParams = route.parameters.filter((p) => p.in === \"header\");\n const successStatuses = Object.keys(route.responses).filter((s) =>\n s.startsWith(\"2\"),\n );\n\n const result: RouteSchemaNames = {\n responseSchemaName: successStatuses.length > 0\n ? generateRouteSchemaName(\n route.path,\n route.method,\n \"Response\",\n )\n : undefined,\n };\n\n if (pathParams.length > 0) {\n result.paramsSchemaName = generateRouteSchemaName(\n route.path,\n route.method,\n \"Params\",\n );\n }\n\n if (queryParams.length > 0) {\n result.querySchemaName = generateRouteSchemaName(\n route.path,\n route.method,\n \"Query\",\n );\n }\n\n if (headerParams.length > 0) {\n result.headersSchemaName = generateRouteSchemaName(\n route.path,\n route.method,\n \"Headers\",\n );\n }\n\n if (route.requestBody) {\n result.bodySchemaName = generateRouteSchemaName(\n route.path,\n route.method,\n \"Body\",\n );\n }\n\n return result;\n}\n\n","import { topologicalSortSchemas } from \"./dependencies\";\nimport { convertSchemaToZodString } from \"./to-zod\";\nimport type { AnySchema } from \"./types/types\";\nimport {\n parseOpenApiPaths,\n generateRouteSchemaNames,\n type RouteInfo,\n} from \"./routes\";\n\nconst validIdentifierRegex = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;\n\nfunction quotePropertyName(name: string): string {\n return validIdentifierRegex.test(name) ? name : `'${name}'`;\n}\n\nfunction generateRouteSchemaName(\n path: string,\n method: string,\n suffix: string,\n): string {\n const pathParts = path\n .split(\"/\")\n .filter((p) => p)\n .map((p) => {\n if (p.startsWith(\"{\") && p.endsWith(\"}\")) {\n return p.slice(1, -1);\n }\n return p;\n })\n .map((word) => {\n // Convert hyphenated words to PascalCase (e.g., \"timer-drafts\" -> \"TimerDrafts\")\n return word\n .split(/[-_]/)\n .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1).toLowerCase())\n .join(\"\");\n });\n const methodPrefix = method.charAt(0) + method.slice(1).toLowerCase();\n const parts = [methodPrefix, ...pathParts, suffix];\n return parts.join(\"\");\n}\n\nfunction generateRouteSchemas(\n routes: RouteInfo[],\n convertSchema: (schema: AnySchema) => string,\n): string[] {\n const lines: string[] = [];\n const schemaNames = new Set<string>();\n\n for (const route of routes) {\n const names = generateRouteSchemaNames(route);\n const pathParams = route.parameters.filter((p) => p.in === \"path\");\n const queryParams = route.parameters.filter((p) => p.in === \"query\");\n const headerParams = route.parameters.filter((p) => p.in === \"header\");\n\n if (names.paramsSchemaName && pathParams.length > 0) {\n if (!schemaNames.has(names.paramsSchemaName)) {\n schemaNames.add(names.paramsSchemaName);\n const properties: string[] = [];\n const required: string[] = [];\n for (const param of pathParams) {\n const zodExpr = convertSchema(param.schema);\n properties.push(`${quotePropertyName(param.name)}: ${zodExpr}`);\n if (param.required) {\n required.push(param.name);\n }\n }\n lines.push(\n `export const ${names.paramsSchemaName} = z.object({ ${properties.join(\", \")} });`,\n );\n }\n }\n\n if (names.querySchemaName && queryParams.length > 0) {\n if (!schemaNames.has(names.querySchemaName)) {\n schemaNames.add(names.querySchemaName);\n const properties: string[] = [];\n for (const param of queryParams) {\n let zodExpr = convertSchema(param.schema);\n if (!param.required) {\n zodExpr += \".optional()\";\n }\n properties.push(`${quotePropertyName(param.name)}: ${zodExpr}`);\n }\n lines.push(\n `export const ${names.querySchemaName} = z.object({ ${properties.join(\", \")} });`,\n );\n }\n }\n\n if (names.headersSchemaName && headerParams.length > 0) {\n if (!schemaNames.has(names.headersSchemaName)) {\n schemaNames.add(names.headersSchemaName);\n const properties: string[] = [];\n for (const param of headerParams) {\n let zodExpr = convertSchema(param.schema);\n if (!param.required) {\n zodExpr += \".optional()\";\n }\n properties.push(`${quotePropertyName(param.name)}: ${zodExpr}`);\n }\n lines.push(\n `export const ${names.headersSchemaName} = z.object({ ${properties.join(\", \")} });`,\n );\n }\n }\n\n if (names.bodySchemaName && route.requestBody) {\n if (!schemaNames.has(names.bodySchemaName)) {\n schemaNames.add(names.bodySchemaName);\n const zodExpr = convertSchema(route.requestBody);\n lines.push(`export const ${names.bodySchemaName} = ${zodExpr};`);\n }\n }\n\n // Generate schemas for ALL status codes, not just success\n for (const [statusCode, responseSchema] of Object.entries(\n route.responses,\n )) {\n if (!responseSchema) continue;\n\n const isSuccess = statusCode.startsWith(\"2\");\n const suffix = isSuccess\n ? `${statusCode}Response`\n : `${statusCode}ErrorResponse`;\n const responseSchemaName = generateRouteSchemaName(\n route.path,\n route.method,\n suffix,\n );\n\n if (!schemaNames.has(responseSchemaName)) {\n schemaNames.add(responseSchemaName);\n const zodExpr = convertSchema(responseSchema);\n lines.push(`export const ${responseSchemaName} = ${zodExpr};`);\n }\n }\n }\n\n return lines;\n}\n\nfunction generateRequestResponseObjects(routes: RouteInfo[]): string[] {\n const lines: string[] = [];\n const requestPaths: Record<string, Record<string, string[]>> = {};\n const responsePaths: Record<\n string,\n Record<string, Record<string, string>>\n > = {};\n\n for (const route of routes) {\n const names = generateRouteSchemaNames(route);\n const pathParams = route.parameters.filter((p) => p.in === \"path\");\n const queryParams = route.parameters.filter((p) => p.in === \"query\");\n const headerParams = route.parameters.filter((p) => p.in === \"header\");\n\n if (!requestPaths[route.path]) {\n requestPaths[route.path] = {};\n }\n const requestMethodObj = requestPaths[route.path]!;\n if (!requestMethodObj[route.method]) {\n requestMethodObj[route.method] = [];\n }\n\n const requestParts: string[] = [];\n if (names.paramsSchemaName && pathParams.length > 0) {\n requestParts.push(`params: ${names.paramsSchemaName}`);\n }\n if (names.querySchemaName && queryParams.length > 0) {\n requestParts.push(`query: ${names.querySchemaName}`);\n }\n if (names.headersSchemaName && headerParams.length > 0) {\n requestParts.push(`headers: ${names.headersSchemaName}`);\n }\n if (names.bodySchemaName && route.requestBody) {\n requestParts.push(`body: ${names.bodySchemaName}`);\n }\n\n if (requestParts.length > 0) {\n requestMethodObj[route.method] = requestParts;\n }\n\n // Store all status codes in nested structure\n if (!responsePaths[route.path]) {\n responsePaths[route.path] = {};\n }\n const responseMethodObj = responsePaths[route.path]!;\n if (!responseMethodObj[route.method]) {\n responseMethodObj[route.method] = {};\n }\n\n for (const [statusCode, responseSchema] of Object.entries(\n route.responses,\n )) {\n if (!responseSchema) continue;\n\n const isSuccess = statusCode.startsWith(\"2\");\n const suffix = isSuccess\n ? `${statusCode}Response`\n : `${statusCode}ErrorResponse`;\n const responseSchemaName = generateRouteSchemaName(\n route.path,\n route.method,\n suffix,\n );\n responseMethodObj[route.method]![statusCode] = responseSchemaName;\n }\n }\n\n lines.push(\"export const Request = {\");\n for (const [path, methods] of Object.entries(requestPaths)) {\n const methodEntries = Object.entries(methods).filter(\n ([, parts]) => parts.length > 0,\n );\n if (methodEntries.length > 0) {\n lines.push(` '${path}': {`);\n for (const [method, parts] of methodEntries) {\n lines.push(` ${method}: {`);\n for (const part of parts) {\n lines.push(` ${part},`);\n }\n lines.push(` },`);\n }\n lines.push(` },`);\n }\n }\n lines.push(\"} as const;\");\n lines.push(\"\");\n\n lines.push(\"export const Response = {\");\n for (const [path, methods] of Object.entries(responsePaths)) {\n const methodEntries = Object.entries(methods);\n if (methodEntries.length > 0) {\n lines.push(` '${path}': {`);\n for (const [method, statusCodes] of methodEntries) {\n lines.push(` ${method}: {`);\n for (const [statusCode, schemaName] of Object.entries(statusCodes)) {\n lines.push(` '${statusCode}': ${schemaName},`);\n }\n lines.push(` },`);\n }\n lines.push(` },`);\n }\n }\n lines.push(\"} as const;\");\n\n return lines;\n}\n\nexport const openApiToZodTsCode = (\n openapi: Record<string, unknown>,\n customImportLines?: string[],\n options?: { includeRoutes?: boolean },\n): string => {\n const components = (openapi as AnySchema)[\"components\"] as\n | AnySchema\n | undefined;\n const schemas: Record<string, AnySchema> =\n (components?.[\"schemas\"] as Record<string, AnySchema>) ?? {};\n\n const lines: string[] = [];\n lines.push(\"/**\");\n lines.push(\" * This file was automatically generated from OpenAPI schema\");\n lines.push(\" * Do not manually edit this file\");\n lines.push(\" */\");\n lines.push(\"\");\n lines.push(\"import { z } from 'zod';\");\n lines.push(...(customImportLines ?? []));\n lines.push(\"\");\n\n const sortedSchemaNames = topologicalSortSchemas(schemas);\n\n for (const name of sortedSchemaNames) {\n const schema = schemas[name];\n if (schema) {\n const zodExpr = convertSchemaToZodString(schema);\n const schemaName = `${name}Schema`;\n const typeName = name;\n lines.push(`export const ${schemaName} = ${zodExpr};`);\n lines.push(`export type ${typeName} = z.infer<typeof ${schemaName}>;`);\n lines.push(\"\");\n }\n }\n\n if (options?.includeRoutes) {\n const routes = parseOpenApiPaths(openapi);\n if (routes.length > 0) {\n const routeSchemas = generateRouteSchemas(\n routes,\n convertSchemaToZodString,\n );\n if (routeSchemas.length > 0) {\n lines.push(...routeSchemas);\n lines.push(\"\");\n const requestResponseObjs = generateRequestResponseObjects(routes);\n lines.push(...requestResponseObjs);\n }\n }\n }\n\n return lines.join(\"\\n\");\n};\n"],"mappings":";AAoBO,SAAS,0BAA0B,QAA6B;AACrE,QAAM,eAA4B,oBAAI,IAAI;AAC1C,QAAM,UAAU,oBAAI,QAAQ;AAE5B,WAAS,SAAS,KAAgB;AAChC,QAAI,CAAC,OAAO,OAAO,QAAQ,SAAU;AAErC,QAAI,QAAQ,IAAI,GAAG,EAAG;AACtB,YAAQ,IAAI,GAAG;AAEf,QAAI,IAAI,MAAM,KAAK,OAAO,IAAI,MAAM,MAAM,UAAU;AAClD,YAAM,QAAS,IAAI,MAAM,EAAa;AAAA,QACpC;AAAA,MACF;AACA,UAAI,SAAS,MAAM,CAAC,GAAG;AACrB,qBAAa,IAAI,mBAAmB,MAAM,CAAC,CAAC,CAAC;AAAA,MAC/C;AACA;AAAA,IACF;AAEA,QAAI,MAAM,QAAQ,GAAG,GAAG;AACtB,UAAI,QAAQ,QAAQ;AACpB;AAAA,IACF;AAEA,QAAI,IAAI,cAAc,OAAO,IAAI,eAAe,UAAU;AACxD,iBAAW,aAAa,OAAO,OAAO,IAAI,UAAU,GAAG;AACrD,iBAAS,SAAS;AAAA,MACpB;AAAA,IACF;AAEA,UAAM,aAAa;AAAA,MACjB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,eAAW,OAAO,YAAY;AAC5B,UAAI,IAAI,GAAG,GAAG;AACZ,iBAAS,IAAI,GAAG,CAAC;AAAA,MACnB;AAAA,IACF;AAEA,QACE,IAAI,wBACJ,OAAO,IAAI,yBAAyB,UACpC;AACA,eAAS,IAAI,oBAAoB;AAAA,IACnC;AAEA,QAAI,IAAI,eAAe,SAAS;AAC9B,aAAO,OAAO,IAAI,cAAc,OAAO,EAAE,QAAQ,QAAQ;AAAA,IAC3D;AAAA,EACF;AAEA,WAAS,MAAM;AACf,SAAO,MAAM,KAAK,YAAY;AAChC;AAyBO,SAAS,uBACd,SACU;AACV,QAAM,cAAc,OAAO,KAAK,OAAO;AACvC,QAAM,eAAsC,oBAAI,IAAI;AACpD,QAAM,WAAgC,oBAAI,IAAI;AAC9C,QAAM,SAAmB,CAAC;AAC1B,QAAM,QAAkB,CAAC;AACzB,QAAM,aAAoC,oBAAI,IAAI;AAElD,aAAW,QAAQ,aAAa;AAC9B,iBAAa,IAAI,MAAM,CAAC,CAAC;AACzB,eAAW,IAAI,MAAM,CAAC,CAAC;AACvB,aAAS,IAAI,MAAM,CAAC;AAAA,EACtB;AAEA,aAAW,QAAQ,aAAa;AAC9B,UAAM,cAAc,QAAQ,IAAI;AAChC,QAAI,aAAa;AACf,YAAM,OAAO,0BAA0B,WAAW;AAClD,YAAM,YAAY,KAAK,OAAO,CAAC,QAAQ,YAAY,SAAS,GAAG,CAAC;AAChE,mBAAa,IAAI,MAAM,SAAS;AAEhC,iBAAW,OAAO,WAAW;AAC3B,cAAM,oBAAoB,WAAW,IAAI,GAAG,KAAK,CAAC;AAClD,0BAAkB,KAAK,IAAI;AAC3B,mBAAW,IAAI,KAAK,iBAAiB;AAAA,MACvC;AAAA,IACF;AAAA,EACF;AAEA,aAAW,CAAC,MAAM,IAAI,KAAK,aAAa,QAAQ,GAAG;AACjD,aAAS,IAAI,MAAM,KAAK,MAAM;AAAA,EAChC;AAEA,aAAW,CAAC,MAAM,MAAM,KAAK,SAAS,QAAQ,GAAG;AAC/C,QAAI,WAAW,GAAG;AAChB,YAAM,KAAK,IAAI;AAAA,IACjB;AAAA,EACF;AAEA,SAAO,MAAM,SAAS,GAAG;AACvB,UAAM,UAAU,MAAM,MAAM;AAC5B,WAAO,KAAK,OAAO;AAEnB,UAAM,oBAAoB,WAAW,IAAI,OAAO,KAAK,CAAC;AACtD,eAAW,aAAa,mBAAmB;AACzC,YAAM,aAAa,SAAS,IAAI,SAAS,KAAK,KAAK;AACnD,eAAS,IAAI,WAAW,SAAS;AACjC,UAAI,cAAc,GAAG;AACnB,cAAM,KAAK,SAAS;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AAEA,MAAI,OAAO,WAAW,YAAY,QAAQ;AACxC,eAAW,QAAQ,aAAa;AAC9B,UAAI,CAAC,OAAO,SAAS,IAAI,GAAG;AAC1B,eAAO,KAAK,IAAI;AAAA,MAClB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;;;AC5KO,SAAS,2BAA2B,GAAgC;AACzE,SAAO;AACT;;;ACFO,SAAS,0BAA0B,QAI/B;AACT,MAAI,SAAS;AACb,MAAI,OAAO,SAAS,WAAW;AAC7B,cAAU;AAAA,EACZ;AACA,MAAI,OAAO,OAAO,YAAY,UAAU;AACtC,cAAU,QAAQ,OAAO,OAAO;AAAA,EAClC;AACA,MAAI,OAAO,OAAO,YAAY,UAAU;AACtC,cAAU,QAAQ,OAAO,OAAO;AAAA,EAClC;AACA,SAAO;AACT;;;ACbA,IAAM,+BAA+B;AAAA,EACnC,aAAa;AAAA,EACb,MAAM;AAAA,EACN,aAAa;AAAA,EACb,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,iBAAiB;AAAA,EACjB,UAAU;AAAA,EACV,KAAK;AAAA,EACL,KAAK;AAAA,EACL,MAAM;AACR;AAEO,IAAM,2BAA2B,OAAO;AAAA,EAC7C;AACF;AA6CA,SAAS,qBACP,KACqC;AACrC,SAAO,IAAI,SAAS,YAAY,YAAY;AAC9C;AAEA,SAAS,sBACP,KACsC;AACtC,SAAO,IAAI,SAAS,YAAY,aAAa;AAC/C;AAQA,SAAS,mBAAmB,KAA+C;AACzE,MAAI,qBAAqB,GAAG,GAAG;AAC7B,WAAO,CAAC,EAAE,MAAM,UAAU,QAAQ,IAAI,OAAO,CAAC;AAAA,EAChD;AAEA,MAAI,sBAAsB,GAAG,GAAG;AAC9B,WAAO,IAAI,QAAQ,IAAI,CAAC,OAAO,EAAE,MAAM,UAAU,QAAQ,EAAE,EAAE;AAAA,EAC/D;AAEA,SAAO,CAAC;AACV;AASA,IAAM,oBAAN,MAAwB;AAAA,EACL,MAAM,oBAAI,IAA0C;AAAA,EAiBrE,SAAS,QAAsB,cAA4C;AACzE,UAAM,WAAW,mBAAmB,YAAY;AAEhD,QAAI,SAAS,SAAS,GAAG;AACvB,iBAAW,CAAC,gBAAgB,oBAAoB,KAAK,KAAK,IAAI,QAAQ,GAAG;AACvE,YAAI,mBAAmB,OAAQ;AAE/B,cAAM,gBAAgB,mBAAmB,oBAAoB;AAC7D,mBAAW,EAAE,MAAM,OAAO,KAAK,UAAU;AACvC,cACE,cAAc,KAAK,CAAC,MAAM,EAAE,SAAS,QAAQ,EAAE,WAAW,MAAM,GAChE;AACA,kBAAM,IAAI;AAAA,cACR,2DAA2D,IAAI,OAAO,MAAgB;AAAA,YACxF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,SAAK,IAAI,IAAI,QAAQ,YAAY;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAKA,iBAAiB,QAA0D;AACzE,WAAO,KAAK,IAAI,IAAI,MAAM;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,QAA+B;AAC1C,WAAO,KAAK,IAAI,IAAI,MAAM;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACZ,SAAK,IAAI,MAAM;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA,EAKA,6CACE,QACoB;AACpB,eAAW,gBAAgB,KAAK,IAAI,OAAO,GAAG;AAC5C,UAAI,aAAa,SAAS,SAAU;AAEpC,UACE,qBAAqB,YAAY,KACjC,aAAa,WAAW,QACxB;AACA,eAAO,aAAa;AAAA,MACtB;AAEA,UACE,sBAAsB,YAAY,KAClC,aAAa,QAAQ,SAAS,MAAM,GACpC;AACA,eAAO,aAAa;AAAA,MACtB;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF;AAMO,IAAM,iBAAiB,IAAI,kBAAkB;AAS7C,SAAS,iCACd,QACA,eACM;AACN,iBAAe,SAAS,QAAQ,aAAoB;AACtD;AAKO,SAAS,6CACd,QACoB;AACpB,SAAO,eAAe,6CAA6C,MAAM;AAC3E;AAKO,SAAS,wCAA8C;AAC5D,iBAAe,MAAM;AACvB;;;AC1NO,SAAS,0BAA0B,QAO/B;AAET,MAAI,OAAO,MAAM;AACf,WAAO,WAAW,OAAO,KAAK,IAAI,CAAC,UAAU,IAAI,KAAK,GAAG,EAAE,KAAK,IAAI,CAAC;AAAA,EACvE;AAGA,MAAI,OAAO,UAAU,yBAAyB,SAAS,OAAO,MAAM,GAAG;AACrE,UAAM,mBAAmB;AAAA,MACvB,OAAO;AAAA,IACT;AAGA,QAAI,kBAAkB;AACpB,aAAO;AAAA,IACT;AAAA,EACF;AAGA,MAAI,YAAY;AAEhB,MAAI,OAAO,QAAQ;AACjB,iBAAa,kBAAkB,OAAO,MAAM;AAAA,EAC9C;AAGA,MAAI,OAAO,OAAO,cAAc,UAAU;AACxC,iBAAa,QAAQ,OAAO,SAAS;AAAA,EACvC;AAEA,MAAI,OAAO,OAAO,cAAc,UAAU;AACxC,iBAAa,QAAQ,OAAO,SAAS;AAAA,EACvC;AAGA,MAAI,OAAO,OAAO,YAAY,UAAU;AACtC,iBAAa,WAAW,OAAO,OAAO;AAAA,EACxC;AAEA,SAAO;AACT;AAKA,SAAS,kBAAkB,QAAwB;AACjD,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;;;ACxEO,SAAS,yBACd,QAMA,eACQ;AACR,QAAM,OAAO,OAAO;AAEpB,MAAI,gBAAgB;AACpB,MAAI,QAAQ,OAAO,SAAS,UAAU;AACpC,oBAAgB,cAAc,IAAI;AAAA,EACpC;AAEA,MAAI,SAAS,WAAW,aAAa;AAErC,MAAI,OAAO,OAAO,aAAa,UAAU;AACvC,cAAU,QAAQ,OAAO,QAAQ;AAAA,EACnC;AACA,MAAI,OAAO,OAAO,aAAa,UAAU;AACvC,cAAU,QAAQ,OAAO,QAAQ;AAAA,EACnC;AAEA,SAAO;AACT;;;AC1BA,IAAM,uBAAuB;AAE7B,SAAS,kBAAkB,MAAsB;AAC/C,SAAO,qBAAqB,KAAK,IAAI,IAAI,OAAO,IAAI,IAAI;AAC1D;AAEO,SAAS,0BACd,QACA,eACQ;AACR,QAAM,aAAa,OAAO,cAAc,CAAC;AACzC,QAAM,gBAAgB,OAAO,KAAK,UAAU;AAE5C,MAAI,cAAc,WAAW,GAAG;AAC9B,QAAI,OAAO,yBAAyB,OAAO;AACzC,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAEA,QAAM,cAAc,IAAI,IAAI,OAAO,YAAY,CAAC,CAAC;AAEjD,QAAM,UAAoB,CAAC;AAC3B,aAAW,CAAC,UAAU,UAAU,KAAK,OAAO,QAAQ,UAAU,GAAG;AAC/D,QAAI,UAAU;AAEd,QAAI,cAAc,OAAO,eAAe,UAAU;AAChD,gBAAU,cAAc,UAAU;AAAA,IACpC;AAEA,QAAI,CAAC,YAAY,IAAI,QAAQ,GAAG;AAC9B,iBAAW;AAAA,IACb;AAEA,YAAQ,KAAK,GAAG,kBAAkB,QAAQ,CAAC,KAAK,OAAO,EAAE;AAAA,EAC3D;AAEA,MAAI,SAAS,cAAc,QAAQ,KAAK,IAAI,CAAC;AAE7C,MAAI,OAAO,yBAAyB,OAAO;AACzC,cAAU;AAAA,EACZ;AAEA,SAAO;AACT;;;AC5CO,SAAS,yBACd,QACA,eACQ;AACR,QAAM,QAAQ,OAAO,MAAM,IAAI,CAAC,SAAS,cAAc,IAAI,CAAC;AAC5D,SAAO,YAAY,MAAM,KAAK,IAAI,CAAC;AACrC;;;ACNO,SAAS,gCACd,QACA,eACQ;AACR,QAAM,QAAQ,OAAO,MAAM,IAAI,CAAC,SAAS,cAAc,IAAI,CAAC;AAE5D,MAAI,OAAO,MAAM,WAAW,EAAG,QAAO;AACtC,MAAI,OAAO,MAAM,WAAW,EAAG,QAAO,cAAc,OAAO,MAAM,CAAC,CAAE;AAEpE,SAAO,kBAAkB,MAAM,KAAK,IAAI,CAAC;AAC3C;;;ACHO,SAAS,yBAAyB,QAA2B;AAClE,MAAI,CAAC,UAAU,OAAO,WAAW,SAAU,QAAO;AAElD,MAAI,OAAO,MAAM,KAAK,OAAO,OAAO,MAAM,MAAM,UAAU;AACxD,UAAM,QAAS,OAAO,MAAM,EAAa;AAAA,MACvC;AAAA,IACF;AACA,QAAIA,UAAS;AACb,QAAI,SAAS,MAAM,CAAC,GAAG;AACrB,MAAAA,UAAS,GAAG,MAAM,CAAC,CAAC;AAAA,IACtB;AACA,QAAI,OAAO,UAAU,MAAM,MAAM;AAC/B,MAAAA,UAAS,YAAYA,OAAM;AAAA,IAC7B;AACA,WAAOA;AAAA,EACT;AACA,MAAI,SAAiB;AAErB,MAAI,WAAW,UAAU,MAAM,QAAQ,OAAO,OAAO,CAAC,GAAG;AACvD,aAAS;AAAA,MACP;AAAA,MACA;AAAA,IACF;AAAA,EACF,WAAW,WAAW,UAAU,MAAM,QAAQ,OAAO,OAAO,CAAC,GAAG;AAC9D,aAAS;AAAA,MACP;AAAA,MACA;AAAA,IACF;AAAA,EACF,OAAO;AACL,YAAQ,OAAO,MAAM,GAAG;AAAA,MACtB,KAAK;AACH,iBAAS,0BAA0B;AAAA,UACjC,MAAM,OAAO,MAAM;AAAA,UACnB,QAAQ,OAAO,QAAQ;AAAA,UACvB,WAAW,OAAO,WAAW;AAAA,UAC7B,WAAW,OAAO,WAAW;AAAA,UAC7B,SAAS,OAAO,SAAS;AAAA,UACzB,MAAM;AAAA,QACR,CAAC;AACD;AAAA,MACF,KAAK;AACH,iBAAS,0BAA0B;AAAA,UACjC,SAAS,OAAO,SAAS;AAAA,UACzB,SAAS,OAAO,SAAS;AAAA,UACzB,MAAM;AAAA,QACR,CAAC;AACD;AAAA,MACF,KAAK;AACH,iBAAS,0BAA0B;AAAA,UACjC,SAAS,OAAO,SAAS;AAAA,UACzB,SAAS,OAAO,SAAS;AAAA,UACzB,MAAM;AAAA,QACR,CAAC;AACD;AAAA,MACF,KAAK;AACH,iBAAS,2BAA2B,EAAE,MAAM,UAAU,CAAC;AACvD;AAAA,MACF,KAAK;AACH,iBAAS;AAAA,UACP;AAAA,YACE,OAAO,OAAO,OAAO;AAAA,YACrB,UAAU,OAAO,UAAU;AAAA,YAC3B,UAAU,OAAO,UAAU;AAAA,YAC3B,MAAM;AAAA,UACR;AAAA,UACA;AAAA,QACF;AACA;AAAA,MACF,KAAK;AACH,iBAAS;AAAA,UACP;AAAA,YACE,sBAAsB,OAAO,sBAAsB;AAAA,YACnD,YAAY,OAAO,YAAY;AAAA,YAC/B,UAAU,OAAO,UAAU;AAAA,YAC3B,MAAM;AAAA,UACR;AAAA,UACA;AAAA,QACF;AACA;AAAA,MACF;AACE,YAAI,OAAO,YAAY,GAAG;AACxB,mBAAS;AAAA,YACP;AAAA,cACE,sBAAsB,OAAO,sBAAsB;AAAA,cACnD,YAAY,OAAO,YAAY;AAAA,cAC/B,UAAU,OAAO,UAAU;AAAA,cAC3B,MAAM;AAAA,YACR;AAAA,YACA;AAAA,UACF;AAAA,QACF,OAAO;AACL,mBAAS;AAAA,QACX;AACA;AAAA,IACJ;AAAA,EACF;AAEA,MAAI,OAAO,UAAU,MAAM,MAAM;AAC/B,aAAS,YAAY,MAAM;AAAA,EAC7B;AAEA,SAAO;AACT;;;ACpFA,SAAS,kBAAkB,QAA4B;AACrD,QAAM,QAAQ,OAAO,YAAY;AACjC,MACE,UAAU,SACV,UAAU,UACV,UAAU,SACV,UAAU,WACV,UAAU,YACV,UAAU,UACV,UAAU,WACV;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,SAAS,aAAa,KAAqB;AACzC,SAAO,IACJ,QAAQ,iBAAiB,GAAG,EAC5B,MAAM,GAAG,EACT,IAAI,CAAC,SAAS,KAAK,OAAO,CAAC,EAAE,YAAY,IAAI,KAAK,MAAM,CAAC,EAAE,YAAY,CAAC,EACxE,KAAK,EAAE;AACZ;AAEA,SAAS,wBACP,MACA,QACA,QACQ;AACR,QAAM,YAAY,KACf,MAAM,GAAG,EACT,OAAO,CAAC,MAAM,CAAC,EACf,IAAI,CAAC,MAAM;AACV,QAAI,EAAE,WAAW,GAAG,KAAK,EAAE,SAAS,GAAG,GAAG;AACxC,aAAO,EAAE,MAAM,GAAG,EAAE;AAAA,IACtB;AACA,WAAO;AAAA,EACT,CAAC,EACA,IAAI,YAAY;AACnB,QAAM,eAAe,OAAO,OAAO,CAAC,IAAI,OAAO,MAAM,CAAC,EAAE,YAAY;AACpE,QAAM,QAAQ,CAAC,cAAc,GAAG,WAAW,MAAM;AACjD,SAAO,MAAM,KAAK,EAAE;AACtB;AAEO,SAAS,kBACd,SACa;AACb,QAAM,QAAS,QAAsB,OAAO;AAG5C,MAAI,CAAC,OAAO;AACV,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,SAAsB,CAAC;AAE7B,aAAW,CAAC,MAAM,QAAQ,KAAK,OAAO,QAAQ,KAAK,GAAG;AACpD,QAAI,CAAC,YAAY,OAAO,aAAa,SAAU;AAE/C,UAAM,UAAU;AAAA,MACd;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,eAAW,UAAU,SAAS;AAC5B,YAAM,YAAY,SAAS,MAAM;AACjC,UAAI,CAAC,UAAW;AAEhB,YAAM,aAA+B,CAAC;AACtC,YAAM,YAAuC,CAAC;AAE9C,UAAI,MAAM,QAAQ,SAAS,YAAY,CAAC,GAAG;AACzC,mBAAW,SAAS,SAAS,YAAY,GAAG;AAC1C,cAAI,SAAS,OAAO,UAAU,UAAU;AACtC,uBAAW,KAAK;AAAA,cACd,MAAM,OAAO,MAAM,MAAM,KAAK,EAAE;AAAA,cAChC,IAAI,MAAM,IAAI,KAAK;AAAA,cACnB,UAAU,QAAQ,MAAM,UAAU,CAAC;AAAA,cACnC,QAAQ,MAAM,QAAQ,KAAK,CAAC;AAAA,YAC9B,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAEA,UAAI,MAAM,QAAQ,UAAU,YAAY,CAAC,GAAG;AAC1C,mBAAW,SAAS,UAAU,YAAY,GAAG;AAC3C,cAAI,SAAS,OAAO,UAAU,UAAU;AACtC,uBAAW,KAAK;AAAA,cACd,MAAM,OAAO,MAAM,MAAM,KAAK,EAAE;AAAA,cAChC,IAAI,MAAM,IAAI,KAAK;AAAA,cACnB,UAAU,QAAQ,MAAM,UAAU,CAAC;AAAA,cACnC,QAAQ,MAAM,QAAQ,KAAK,CAAC;AAAA,YAC9B,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAEA,UAAI;AACJ,UAAI,UAAU,aAAa,GAAG;AAC5B,cAAM,KAAK,UAAU,aAAa;AAClC,YAAI,MAAM,OAAO,OAAO,UAAU;AAChC,gBAAM,UAAU,GAAG,SAAS;AAC5B,cAAI,WAAW,OAAO,YAAY,UAAU;AAC1C,kBAAM,cAAc,QAAQ,kBAAkB;AAC9C,gBAAI,eAAe,OAAO,gBAAgB,UAAU;AAClD,4BAAc,YAAY,QAAQ,KAAK,CAAC;AAAA,YAC1C;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAEA,UAAI,UAAU,WAAW,KAAK,OAAO,UAAU,WAAW,MAAM,UAAU;AACxE,mBAAW,CAAC,YAAY,QAAQ,KAAK,OAAO;AAAA,UAC1C,UAAU,WAAW;AAAA,QACvB,GAAG;AACD,cAAI,YAAY,OAAO,aAAa,UAAU;AAC5C,kBAAM,iBAAiB;AACvB,kBAAM,UAAU,eAAe,SAAS;AACxC,gBAAI,WAAW,OAAO,YAAY,UAAU;AAC1C,oBAAM,cAAc,QAAQ,kBAAkB;AAC9C,kBAAI,eAAe,OAAO,gBAAgB,UAAU;AAClD,sBAAM,SAAS,YAAY,QAAQ;AACnC,oBAAI,QAAQ;AACV,4BAAU,UAAU,IAAI;AAAA,gBAC1B;AAAA,cACF;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAEA,aAAO,KAAK;AAAA,QACV;AAAA,QACA,QAAQ,kBAAkB,MAAM;AAAA,QAChC;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,yBACd,OACkB;AAClB,QAAM,aAAa,MAAM,WAAW,OAAO,CAAC,MAAM,EAAE,OAAO,MAAM;AACjE,QAAM,cAAc,MAAM,WAAW,OAAO,CAAC,MAAM,EAAE,OAAO,OAAO;AACnE,QAAM,eAAe,MAAM,WAAW,OAAO,CAAC,MAAM,EAAE,OAAO,QAAQ;AACrE,QAAM,kBAAkB,OAAO,KAAK,MAAM,SAAS,EAAE;AAAA,IAAO,CAAC,MAC3D,EAAE,WAAW,GAAG;AAAA,EAClB;AAEA,QAAM,SAA2B;AAAA,IAC/B,oBAAoB,gBAAgB,SAAS,IACzC;AAAA,MACE,MAAM;AAAA,MACN,MAAM;AAAA,MACN;AAAA,IACF,IACA;AAAA,EACN;AAEA,MAAI,WAAW,SAAS,GAAG;AACzB,WAAO,mBAAmB;AAAA,MACxB,MAAM;AAAA,MACN,MAAM;AAAA,MACN;AAAA,IACF;AAAA,EACF;AAEA,MAAI,YAAY,SAAS,GAAG;AAC1B,WAAO,kBAAkB;AAAA,MACvB,MAAM;AAAA,MACN,MAAM;AAAA,MACN;AAAA,IACF;AAAA,EACF;AAEA,MAAI,aAAa,SAAS,GAAG;AAC3B,WAAO,oBAAoB;AAAA,MACzB,MAAM;AAAA,MACN,MAAM;AAAA,MACN;AAAA,IACF;AAAA,EACF;AAEA,MAAI,MAAM,aAAa;AACrB,WAAO,iBAAiB;AAAA,MACtB,MAAM;AAAA,MACN,MAAM;AAAA,MACN;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;;;AC5NA,IAAMC,wBAAuB;AAE7B,SAASC,mBAAkB,MAAsB;AAC/C,SAAOD,sBAAqB,KAAK,IAAI,IAAI,OAAO,IAAI,IAAI;AAC1D;AAEA,SAASE,yBACP,MACA,QACA,QACQ;AACR,QAAM,YAAY,KACf,MAAM,GAAG,EACT,OAAO,CAAC,MAAM,CAAC,EACf,IAAI,CAAC,MAAM;AACV,QAAI,EAAE,WAAW,GAAG,KAAK,EAAE,SAAS,GAAG,GAAG;AACxC,aAAO,EAAE,MAAM,GAAG,EAAE;AAAA,IACtB;AACA,WAAO;AAAA,EACT,CAAC,EACA,IAAI,CAAC,SAAS;AAEb,WAAO,KACJ,MAAM,MAAM,EACZ,IAAI,CAAC,YAAY,QAAQ,OAAO,CAAC,EAAE,YAAY,IAAI,QAAQ,MAAM,CAAC,EAAE,YAAY,CAAC,EACjF,KAAK,EAAE;AAAA,EACZ,CAAC;AACH,QAAM,eAAe,OAAO,OAAO,CAAC,IAAI,OAAO,MAAM,CAAC,EAAE,YAAY;AACpE,QAAM,QAAQ,CAAC,cAAc,GAAG,WAAW,MAAM;AACjD,SAAO,MAAM,KAAK,EAAE;AACtB;AAEA,SAAS,qBACP,QACA,eACU;AACV,QAAM,QAAkB,CAAC;AACzB,QAAM,cAAc,oBAAI,IAAY;AAEpC,aAAW,SAAS,QAAQ;AAC1B,UAAM,QAAQ,yBAAyB,KAAK;AAC5C,UAAM,aAAa,MAAM,WAAW,OAAO,CAAC,MAAM,EAAE,OAAO,MAAM;AACjE,UAAM,cAAc,MAAM,WAAW,OAAO,CAAC,MAAM,EAAE,OAAO,OAAO;AACnE,UAAM,eAAe,MAAM,WAAW,OAAO,CAAC,MAAM,EAAE,OAAO,QAAQ;AAErE,QAAI,MAAM,oBAAoB,WAAW,SAAS,GAAG;AACnD,UAAI,CAAC,YAAY,IAAI,MAAM,gBAAgB,GAAG;AAC5C,oBAAY,IAAI,MAAM,gBAAgB;AACtC,cAAM,aAAuB,CAAC;AAC9B,cAAM,WAAqB,CAAC;AAC5B,mBAAW,SAAS,YAAY;AAC9B,gBAAM,UAAU,cAAc,MAAM,MAAM;AAC1C,qBAAW,KAAK,GAAGD,mBAAkB,MAAM,IAAI,CAAC,KAAK,OAAO,EAAE;AAC9D,cAAI,MAAM,UAAU;AAClB,qBAAS,KAAK,MAAM,IAAI;AAAA,UAC1B;AAAA,QACF;AACA,cAAM;AAAA,UACJ,gBAAgB,MAAM,gBAAgB,iBAAiB,WAAW,KAAK,IAAI,CAAC;AAAA,QAC9E;AAAA,MACF;AAAA,IACF;AAEA,QAAI,MAAM,mBAAmB,YAAY,SAAS,GAAG;AACnD,UAAI,CAAC,YAAY,IAAI,MAAM,eAAe,GAAG;AAC3C,oBAAY,IAAI,MAAM,eAAe;AACrC,cAAM,aAAuB,CAAC;AAC9B,mBAAW,SAAS,aAAa;AAC/B,cAAI,UAAU,cAAc,MAAM,MAAM;AACxC,cAAI,CAAC,MAAM,UAAU;AACnB,uBAAW;AAAA,UACb;AACA,qBAAW,KAAK,GAAGA,mBAAkB,MAAM,IAAI,CAAC,KAAK,OAAO,EAAE;AAAA,QAChE;AACA,cAAM;AAAA,UACJ,gBAAgB,MAAM,eAAe,iBAAiB,WAAW,KAAK,IAAI,CAAC;AAAA,QAC7E;AAAA,MACF;AAAA,IACF;AAEA,QAAI,MAAM,qBAAqB,aAAa,SAAS,GAAG;AACtD,UAAI,CAAC,YAAY,IAAI,MAAM,iBAAiB,GAAG;AAC7C,oBAAY,IAAI,MAAM,iBAAiB;AACvC,cAAM,aAAuB,CAAC;AAC9B,mBAAW,SAAS,cAAc;AAChC,cAAI,UAAU,cAAc,MAAM,MAAM;AACxC,cAAI,CAAC,MAAM,UAAU;AACnB,uBAAW;AAAA,UACb;AACA,qBAAW,KAAK,GAAGA,mBAAkB,MAAM,IAAI,CAAC,KAAK,OAAO,EAAE;AAAA,QAChE;AACA,cAAM;AAAA,UACJ,gBAAgB,MAAM,iBAAiB,iBAAiB,WAAW,KAAK,IAAI,CAAC;AAAA,QAC/E;AAAA,MACF;AAAA,IACF;AAEA,QAAI,MAAM,kBAAkB,MAAM,aAAa;AAC7C,UAAI,CAAC,YAAY,IAAI,MAAM,cAAc,GAAG;AAC1C,oBAAY,IAAI,MAAM,cAAc;AACpC,cAAM,UAAU,cAAc,MAAM,WAAW;AAC/C,cAAM,KAAK,gBAAgB,MAAM,cAAc,MAAM,OAAO,GAAG;AAAA,MACjE;AAAA,IACF;AAGA,eAAW,CAAC,YAAY,cAAc,KAAK,OAAO;AAAA,MAChD,MAAM;AAAA,IACR,GAAG;AACD,UAAI,CAAC,eAAgB;AAErB,YAAM,YAAY,WAAW,WAAW,GAAG;AAC3C,YAAM,SAAS,YACX,GAAG,UAAU,aACb,GAAG,UAAU;AACjB,YAAM,qBAAqBC;AAAA,QACzB,MAAM;AAAA,QACN,MAAM;AAAA,QACN;AAAA,MACF;AAEA,UAAI,CAAC,YAAY,IAAI,kBAAkB,GAAG;AACxC,oBAAY,IAAI,kBAAkB;AAClC,cAAM,UAAU,cAAc,cAAc;AAC5C,cAAM,KAAK,gBAAgB,kBAAkB,MAAM,OAAO,GAAG;AAAA,MAC/D;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,+BAA+B,QAA+B;AACrE,QAAM,QAAkB,CAAC;AACzB,QAAM,eAAyD,CAAC;AAChE,QAAM,gBAGF,CAAC;AAEL,aAAW,SAAS,QAAQ;AAC1B,UAAM,QAAQ,yBAAyB,KAAK;AAC5C,UAAM,aAAa,MAAM,WAAW,OAAO,CAAC,MAAM,EAAE,OAAO,MAAM;AACjE,UAAM,cAAc,MAAM,WAAW,OAAO,CAAC,MAAM,EAAE,OAAO,OAAO;AACnE,UAAM,eAAe,MAAM,WAAW,OAAO,CAAC,MAAM,EAAE,OAAO,QAAQ;AAErE,QAAI,CAAC,aAAa,MAAM,IAAI,GAAG;AAC7B,mBAAa,MAAM,IAAI,IAAI,CAAC;AAAA,IAC9B;AACA,UAAM,mBAAmB,aAAa,MAAM,IAAI;AAChD,QAAI,CAAC,iBAAiB,MAAM,MAAM,GAAG;AACnC,uBAAiB,MAAM,MAAM,IAAI,CAAC;AAAA,IACpC;AAEA,UAAM,eAAyB,CAAC;AAChC,QAAI,MAAM,oBAAoB,WAAW,SAAS,GAAG;AACnD,mBAAa,KAAK,WAAW,MAAM,gBAAgB,EAAE;AAAA,IACvD;AACA,QAAI,MAAM,mBAAmB,YAAY,SAAS,GAAG;AACnD,mBAAa,KAAK,UAAU,MAAM,eAAe,EAAE;AAAA,IACrD;AACA,QAAI,MAAM,qBAAqB,aAAa,SAAS,GAAG;AACtD,mBAAa,KAAK,YAAY,MAAM,iBAAiB,EAAE;AAAA,IACzD;AACA,QAAI,MAAM,kBAAkB,MAAM,aAAa;AAC7C,mBAAa,KAAK,SAAS,MAAM,cAAc,EAAE;AAAA,IACnD;AAEA,QAAI,aAAa,SAAS,GAAG;AAC3B,uBAAiB,MAAM,MAAM,IAAI;AAAA,IACnC;AAGA,QAAI,CAAC,cAAc,MAAM,IAAI,GAAG;AAC9B,oBAAc,MAAM,IAAI,IAAI,CAAC;AAAA,IAC/B;AACA,UAAM,oBAAoB,cAAc,MAAM,IAAI;AAClD,QAAI,CAAC,kBAAkB,MAAM,MAAM,GAAG;AACpC,wBAAkB,MAAM,MAAM,IAAI,CAAC;AAAA,IACrC;AAEA,eAAW,CAAC,YAAY,cAAc,KAAK,OAAO;AAAA,MAChD,MAAM;AAAA,IACR,GAAG;AACD,UAAI,CAAC,eAAgB;AAErB,YAAM,YAAY,WAAW,WAAW,GAAG;AAC3C,YAAM,SAAS,YACX,GAAG,UAAU,aACb,GAAG,UAAU;AACjB,YAAM,qBAAqBA;AAAA,QACzB,MAAM;AAAA,QACN,MAAM;AAAA,QACN;AAAA,MACF;AACA,wBAAkB,MAAM,MAAM,EAAG,UAAU,IAAI;AAAA,IACjD;AAAA,EACF;AAEA,QAAM,KAAK,0BAA0B;AACrC,aAAW,CAAC,MAAM,OAAO,KAAK,OAAO,QAAQ,YAAY,GAAG;AAC1D,UAAM,gBAAgB,OAAO,QAAQ,OAAO,EAAE;AAAA,MAC5C,CAAC,CAAC,EAAE,KAAK,MAAM,MAAM,SAAS;AAAA,IAChC;AACA,QAAI,cAAc,SAAS,GAAG;AAC5B,YAAM,KAAK,MAAM,IAAI,MAAM;AAC3B,iBAAW,CAAC,QAAQ,KAAK,KAAK,eAAe;AAC3C,cAAM,KAAK,OAAO,MAAM,KAAK;AAC7B,mBAAW,QAAQ,OAAO;AACxB,gBAAM,KAAK,SAAS,IAAI,GAAG;AAAA,QAC7B;AACA,cAAM,KAAK,QAAQ;AAAA,MACrB;AACA,YAAM,KAAK,MAAM;AAAA,IACnB;AAAA,EACF;AACA,QAAM,KAAK,aAAa;AACxB,QAAM,KAAK,EAAE;AAEb,QAAM,KAAK,2BAA2B;AACtC,aAAW,CAAC,MAAM,OAAO,KAAK,OAAO,QAAQ,aAAa,GAAG;AAC3D,UAAM,gBAAgB,OAAO,QAAQ,OAAO;AAC5C,QAAI,cAAc,SAAS,GAAG;AAC5B,YAAM,KAAK,MAAM,IAAI,MAAM;AAC3B,iBAAW,CAAC,QAAQ,WAAW,KAAK,eAAe;AACjD,cAAM,KAAK,OAAO,MAAM,KAAK;AAC7B,mBAAW,CAAC,YAAY,UAAU,KAAK,OAAO,QAAQ,WAAW,GAAG;AAClE,gBAAM,KAAK,UAAU,UAAU,MAAM,UAAU,GAAG;AAAA,QACpD;AACA,cAAM,KAAK,QAAQ;AAAA,MACrB;AACA,YAAM,KAAK,MAAM;AAAA,IACnB;AAAA,EACF;AACA,QAAM,KAAK,aAAa;AAExB,SAAO;AACT;AAEO,IAAM,qBAAqB,CAChC,SACA,mBACA,YACW;AACX,QAAM,aAAc,QAAsB,YAAY;AAGtD,QAAM,UACH,aAAa,SAAS,KAAmC,CAAC;AAE7D,QAAM,QAAkB,CAAC;AACzB,QAAM,KAAK,KAAK;AAChB,QAAM,KAAK,8DAA8D;AACzE,QAAM,KAAK,mCAAmC;AAC9C,QAAM,KAAK,KAAK;AAChB,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,0BAA0B;AACrC,QAAM,KAAK,GAAI,qBAAqB,CAAC,CAAE;AACvC,QAAM,KAAK,EAAE;AAEb,QAAM,oBAAoB,uBAAuB,OAAO;AAExD,aAAW,QAAQ,mBAAmB;AACpC,UAAM,SAAS,QAAQ,IAAI;AAC3B,QAAI,QAAQ;AACV,YAAM,UAAU,yBAAyB,MAAM;AAC/C,YAAM,aAAa,GAAG,IAAI;AAC1B,YAAM,WAAW;AACjB,YAAM,KAAK,gBAAgB,UAAU,MAAM,OAAO,GAAG;AACrD,YAAM,KAAK,eAAe,QAAQ,qBAAqB,UAAU,IAAI;AACrE,YAAM,KAAK,EAAE;AAAA,IACf;AAAA,EACF;AAEA,MAAI,SAAS,eAAe;AAC1B,UAAM,SAAS,kBAAkB,OAAO;AACxC,QAAI,OAAO,SAAS,GAAG;AACrB,YAAM,eAAe;AAAA,QACnB;AAAA,QACA;AAAA,MACF;AACA,UAAI,aAAa,SAAS,GAAG;AAC3B,cAAM,KAAK,GAAG,YAAY;AAC1B,cAAM,KAAK,EAAE;AACb,cAAM,sBAAsB,+BAA+B,MAAM;AACjE,cAAM,KAAK,GAAG,mBAAmB;AAAA,MACnC;AAAA,IACF;AAAA,EACF;AAEA,SAAO,MAAM,KAAK,IAAI;AACxB;","names":["result","validIdentifierRegex","quotePropertyName","generateRouteSchemaName"]}
|
|
1
|
+
{"version":3,"sources":["../src/dependencies.ts","../src/schema-dedup.ts","../src/types/boolean.ts","../src/types/number.ts","../src/registry.ts","../src/types/string.ts","../src/types/array.ts","../src/types/object.ts","../src/types/union.ts","../src/types/intersection.ts","../src/to-zod.ts","../src/routes.ts","../src/to-typescript.ts"],"sourcesContent":["import type { AnySchema } from \"./types/types\";\n\n/**\n * Extracts all schema references ($ref) from an OpenAPI schema by recursively\n * traversing its structure.\n *\n * This function is used during the OpenAPI-to-Zod conversion process to identify\n * which schemas a given schema depends on. It traverses all OpenAPI schema\n * structures including objects, arrays, unions (oneOf), intersections (allOf),\n * conditionals (if/then/else), and discriminator mappings to find all $ref\n * references that point to other schemas in the components/schemas section.\n *\n * The extracted dependency names are used by `topologicalSortSchemas` to build\n * a dependency graph and determine the correct order for generating Zod schemas,\n * ensuring that referenced schemas are defined before they are used in the\n * generated TypeScript code.\n *\n * @param schema - The OpenAPI schema to extract dependencies from\n * @returns An array of schema names that this schema references (via $ref)\n */\nexport function extractSchemaDependencies(schema: AnySchema): string[] {\n const dependencies: Set<string> = new Set();\n const visited = new WeakSet();\n\n function traverse(obj: any): void {\n if (!obj || typeof obj !== \"object\") return;\n\n if (visited.has(obj)) return;\n visited.add(obj);\n\n if (obj[\"$ref\"] && typeof obj[\"$ref\"] === \"string\") {\n const match = (obj[\"$ref\"] as string).match(\n /#\\/components\\/schemas\\/(.+)/,\n );\n if (match && match[1]) {\n dependencies.add(decodeURIComponent(match[1]));\n }\n return;\n }\n\n if (Array.isArray(obj)) {\n obj.forEach(traverse);\n return;\n }\n\n if (obj.properties && typeof obj.properties === \"object\") {\n for (const propValue of Object.values(obj.properties)) {\n traverse(propValue);\n }\n }\n\n const schemaKeys = [\n \"items\",\n \"oneOf\",\n \"allOf\",\n \"anyOf\",\n \"not\",\n \"if\",\n \"then\",\n \"else\",\n \"prefixItems\",\n \"contains\",\n \"propertyNames\",\n \"dependentSchemas\",\n ];\n\n for (const key of schemaKeys) {\n if (obj[key]) {\n traverse(obj[key]);\n }\n }\n\n if (\n obj.additionalProperties &&\n typeof obj.additionalProperties === \"object\"\n ) {\n traverse(obj.additionalProperties);\n }\n\n if (obj.discriminator?.mapping) {\n Object.values(obj.discriminator.mapping).forEach(traverse);\n }\n }\n\n traverse(schema);\n return Array.from(dependencies);\n}\n\n/**\n * Sorts OpenAPI schemas topologically based on their dependencies to ensure\n * correct generation order.\n *\n * When converting OpenAPI schemas to Zod schemas and generating TypeScript code,\n * schemas must be defined before they are referenced. For example, if `UserSchema`\n * references `ProfileSchema` (via $ref), then `ProfileSchema` must be generated\n * before `UserSchema` to avoid \"undefined variable\" errors in the generated code.\n *\n * This function uses Kahn's algorithm for topological sorting to order schemas\n * such that all dependencies come before their dependents. It:\n * 1. Extracts dependencies for each schema using `extractSchemaDependencies`\n * 2. Builds a dependency graph and computes in-degrees\n * 3. Sorts schemas starting with those that have no dependencies (in-degree 0)\n * 4. Handles circular dependencies gracefully by appending any remaining schemas\n * that couldn't be sorted (though this indicates a problematic schema structure)\n *\n * This function is called by `openApiToZodTsCode` to determine the order in which\n * schemas should be converted and emitted in the generated TypeScript file.\n *\n * @param schemas - A record mapping schema names to their OpenAPI schema definitions\n * @returns An array of schema names sorted in topological order (dependencies before dependents)\n */\nexport function topologicalSortSchemas(\n schemas: Record<string, AnySchema>,\n): string[] {\n const schemaNames = Object.keys(schemas);\n const dependencies: Map<string, string[]> = new Map();\n const inDegree: Map<string, number> = new Map();\n const sorted: string[] = [];\n const queue: string[] = [];\n const dependents: Map<string, string[]> = new Map();\n\n for (const name of schemaNames) {\n dependencies.set(name, []);\n dependents.set(name, []);\n inDegree.set(name, 0);\n }\n\n for (const name of schemaNames) {\n const schemaValue = schemas[name];\n if (schemaValue) {\n const deps = extractSchemaDependencies(schemaValue);\n const validDeps = deps.filter((dep) => schemaNames.includes(dep));\n dependencies.set(name, validDeps);\n\n for (const dep of validDeps) {\n const currentDependents = dependents.get(dep) || [];\n currentDependents.push(name);\n dependents.set(dep, currentDependents);\n }\n }\n }\n\n for (const [name, deps] of dependencies.entries()) {\n inDegree.set(name, deps.length);\n }\n\n for (const [name, degree] of inDegree.entries()) {\n if (degree === 0) {\n queue.push(name);\n }\n }\n\n while (queue.length > 0) {\n const current = queue.shift()!;\n sorted.push(current);\n\n const currentDependents = dependents.get(current) || [];\n for (const dependent of currentDependents) {\n const newDegree = (inDegree.get(dependent) || 0) - 1;\n inDegree.set(dependent, newDegree);\n if (newDegree === 0) {\n queue.push(dependent);\n }\n }\n }\n\n if (sorted.length !== schemaNames.length) {\n for (const name of schemaNames) {\n if (!sorted.includes(name)) {\n sorted.push(name);\n }\n }\n }\n\n return sorted;\n}\n","import type { AnySchema } from \"./types/types\";\n\n/**\n * Schema deduplication utilities for optimizing generated TypeScript types.\n *\n * This module provides fingerprinting and registry functionality to detect\n * structurally identical schemas and generate them only once, reducing\n * memory usage in consuming TypeScript projects.\n */\n\n/**\n * Recursively sorts an object's keys to create a stable representation.\n * This ensures that {a: 1, b: 2} and {b: 2, a: 1} produce the same fingerprint.\n */\nfunction sortObjectDeep(obj: unknown): unknown {\n if (obj === null || typeof obj !== \"object\") return obj;\n if (Array.isArray(obj)) return obj.map(sortObjectDeep);\n\n const sorted: Record<string, unknown> = {};\n const keys = Object.keys(obj as Record<string, unknown>).sort();\n for (const key of keys) {\n sorted[key] = sortObjectDeep((obj as Record<string, unknown>)[key]);\n }\n return sorted;\n}\n\n/**\n * Generates a canonical fingerprint for an OpenAPI schema.\n * Identical schemas will produce identical fingerprints.\n */\nexport function getSchemaFingerprint(schema: AnySchema): string {\n return JSON.stringify(sortObjectDeep(schema));\n}\n\n/**\n * Registry for tracking unique schemas and their canonical names.\n */\nexport interface SchemaRegistry {\n /** Map from fingerprint to the first schema name that used it */\n fingerprintToName: Map<string, string>;\n /** Map from schema name to its fingerprint (for reverse lookup) */\n nameToFingerprint: Map<string, string>;\n}\n\n/**\n * Creates a new empty schema registry.\n */\nexport function createSchemaRegistry(): SchemaRegistry {\n return {\n fingerprintToName: new Map(),\n nameToFingerprint: new Map(),\n };\n}\n\n/**\n * Result of registering a schema.\n */\nexport interface RegisterSchemaResult {\n /** Whether this is a new unique schema */\n isNew: boolean;\n /** The canonical name for this schema (may be different from input name if duplicate) */\n canonicalName: string;\n}\n\n/**\n * Registers a schema in the registry. If an identical schema already exists,\n * returns the existing canonical name instead.\n */\nexport function registerSchema(\n registry: SchemaRegistry,\n name: string,\n schema: AnySchema,\n): RegisterSchemaResult {\n const fingerprint = getSchemaFingerprint(schema);\n\n const existing = registry.fingerprintToName.get(fingerprint);\n if (existing) {\n return { isNew: false, canonicalName: existing };\n }\n\n registry.fingerprintToName.set(fingerprint, name);\n registry.nameToFingerprint.set(name, fingerprint);\n return { isNew: true, canonicalName: name };\n}\n\n/**\n * Pre-registers a schema with a specific fingerprint.\n * Used for common schemas that should take priority.\n */\nexport function preRegisterSchema(\n registry: SchemaRegistry,\n name: string,\n fingerprint: string,\n): void {\n registry.fingerprintToName.set(fingerprint, name);\n registry.nameToFingerprint.set(name, fingerprint);\n}\n\n/**\n * Extracts the error code from an OpenAPI error schema.\n * Looks for patterns like: { error: { code: enum(['UNAUTHORIZED']) } }\n */\nexport function extractErrorCode(schema: AnySchema): string | null {\n const properties = schema?.[\"properties\"] as Record<string, AnySchema> | undefined;\n const errorObj = properties?.[\"error\"] as AnySchema | undefined;\n const errorProps = errorObj?.[\"properties\"] as Record<string, AnySchema> | undefined;\n const codeSchema = errorProps?.[\"code\"] as AnySchema | undefined;\n const codeEnum = codeSchema?.[\"enum\"] as string[] | undefined;\n\n if (Array.isArray(codeEnum) && codeEnum.length === 1) {\n return codeEnum[0]!;\n }\n return null;\n}\n\n/**\n * Converts an error code like UNAUTHORIZED or NOT_FOUND to PascalCase.\n * UNAUTHORIZED -> Unauthorized\n * NOT_FOUND -> NotFound\n */\nexport function errorCodeToPascalCase(code: string): string {\n return code\n .split(\"_\")\n .map((part) => part.charAt(0) + part.slice(1).toLowerCase())\n .join(\"\");\n}\n\n/**\n * Generates a common error schema name from an error code.\n * UNAUTHORIZED -> UnauthorizedErrorSchema\n */\nexport function generateCommonErrorSchemaName(errorCode: string): string {\n return `${errorCodeToPascalCase(errorCode)}ErrorSchema`;\n}\n\n/**\n * Represents a common schema that appears multiple times.\n */\nexport interface CommonSchema {\n /** The canonical name for this schema */\n name: string;\n /** The schema definition */\n schema: AnySchema;\n /** The fingerprint for deduplication */\n fingerprint: string;\n /** Number of times this schema appears */\n count: number;\n}\n\n/**\n * Scans schemas and identifies those that appear multiple times.\n * Returns common schemas sorted by count (most common first).\n */\nexport function findCommonSchemas(\n schemas: Array<{ name: string; schema: AnySchema }>,\n minCount: number = 2,\n): CommonSchema[] {\n const fingerprints = new Map<\n string,\n { schema: AnySchema; names: string[]; errorCode: string | null }\n >();\n\n // Count occurrences of each unique schema\n for (const { name, schema } of schemas) {\n const fingerprint = getSchemaFingerprint(schema);\n const existing = fingerprints.get(fingerprint);\n\n if (existing) {\n existing.names.push(name);\n } else {\n fingerprints.set(fingerprint, {\n schema,\n names: [name],\n errorCode: extractErrorCode(schema),\n });\n }\n }\n\n // Filter to schemas appearing minCount+ times\n const commonSchemas: CommonSchema[] = [];\n for (const [fingerprint, data] of fingerprints) {\n if (data.names.length >= minCount) {\n // Generate a semantic name if it's an error schema, otherwise use first occurrence\n const name = data.errorCode\n ? generateCommonErrorSchemaName(data.errorCode)\n : data.names[0]!;\n\n commonSchemas.push({\n name,\n schema: data.schema,\n fingerprint,\n count: data.names.length,\n });\n }\n }\n\n // Sort by count descending (most common first)\n return commonSchemas.sort((a, b) => b.count - a.count);\n}\n","/**\n * Convert an OpenAPI v3 boolean schema to a Zod schema string\n */\nexport function convertOpenAPIBooleanToZod(_: { type: \"boolean\" }): string {\n return \"z.boolean()\";\n}\n","/**\n * Convert an OpenAPI v3 number/integer schema to a Zod schema string\n */\nexport function convertOpenAPINumberToZod(schema: {\n type: \"number\" | \"integer\";\n minimum?: number;\n maximum?: number;\n}): string {\n let result = \"z.number()\";\n if (schema.type === \"integer\") {\n result += \".int()\";\n }\n if (typeof schema.minimum === \"number\") {\n result += `.min(${schema.minimum})`;\n }\n if (typeof schema.maximum === \"number\") {\n result += `.max(${schema.maximum})`;\n }\n return result;\n}\n","import { z } from \"zod\";\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst SUPPORTED_STRING_FORMATS_MAP = {\n \"color-hex\": 1,\n date: 1,\n \"date-time\": 1,\n email: 1,\n \"iso-date\": 1,\n \"iso-date-time\": 1,\n objectid: 1,\n uri: 1,\n url: 1,\n uuid: 1,\n} as const;\n\nexport const SUPPORTED_STRING_FORMATS = Object.keys(\n SUPPORTED_STRING_FORMATS_MAP,\n) as unknown as keyof typeof SUPPORTED_STRING_FORMATS_MAP;\n\ntype SupportedStringFormat = typeof SUPPORTED_STRING_FORMATS;\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type ZodOpenApiRegistrationString<\n F extends SupportedStringFormat = SupportedStringFormat,\n> = {\n /** The name of the schema variable, IMPORTANT: must be named the same as the variable name */\n schemaExportedVariableName: string;\n type: \"string\";\n description?: string;\n format: F;\n};\n\nexport type ZodOpenApiRegistrationStrings<\n Fs extends\n readonly SupportedStringFormat[] = readonly SupportedStringFormat[],\n> = {\n /** The name of the schema variable, IMPORTANT: must be named the same as the variable name */\n schemaExportedVariableName: string;\n type: \"string\";\n description?: string;\n formats: Fs;\n};\n\nexport type ZodOpenApiRegistrationPrimitive = {\n /** The name of the schema variable, IMPORTANT: must be named the same as the variable name */\n schemaExportedVariableName: string;\n description?: string;\n type: \"number\" | \"integer\" | \"boolean\";\n};\n\nexport type ZodOpenApiRegistration =\n | ZodOpenApiRegistrationString\n | ZodOpenApiRegistrationStrings\n | ZodOpenApiRegistrationPrimitive;\n\n// ============================================================================\n// Type Guards\n// ============================================================================\n\nfunction isStringRegistration(\n reg: ZodOpenApiRegistration,\n): reg is ZodOpenApiRegistrationString {\n return reg.type === \"string\" && \"format\" in reg;\n}\n\nfunction isStringsRegistration(\n reg: ZodOpenApiRegistration,\n): reg is ZodOpenApiRegistrationStrings {\n return reg.type === \"string\" && \"formats\" in reg;\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\ntype TypeFormatPair = { type: string; format: string | undefined };\n\nfunction getTypeFormatPairs(reg: ZodOpenApiRegistration): TypeFormatPair[] {\n if (isStringRegistration(reg)) {\n return [{ type: \"string\", format: reg.format }];\n }\n\n if (isStringsRegistration(reg)) {\n return reg.formats.map((f) => ({ type: \"string\", format: f }));\n }\n\n return [];\n}\n\n// ============================================================================\n// Registry Class\n// ============================================================================\n\n/**\n * Global registry for mapping Zod schemas to OpenAPI schema representations\n */\nclass ZodSchemaRegistry {\n private readonly map = new Map<z.ZodTypeAny, ZodOpenApiRegistration>();\n\n /**\n * Register a Zod schema with its OpenAPI representation\n */\n register<F extends SupportedStringFormat>(\n schema: z.ZodTypeAny,\n registration: ZodOpenApiRegistrationString<F>,\n ): void;\n register<Fs extends readonly SupportedStringFormat[]>(\n schema: z.ZodTypeAny,\n registration: ZodOpenApiRegistrationStrings<Fs>,\n ): void;\n register(\n schema: z.ZodTypeAny,\n registration: ZodOpenApiRegistrationPrimitive,\n ): void;\n register(schema: z.ZodTypeAny, registration: ZodOpenApiRegistration): void {\n const newPairs = getTypeFormatPairs(registration);\n\n if (newPairs.length > 0) {\n for (const [existingSchema, existingRegistration] of this.map.entries()) {\n if (existingSchema === schema) continue;\n\n const existingPairs = getTypeFormatPairs(existingRegistration);\n for (const { type, format } of newPairs) {\n if (\n existingPairs.some((p) => p.type === type && p.format === format)\n ) {\n throw new Error(\n `duplicate Zod OpenAPI registration for (type, format)=('${type}', '${format as string}')`,\n );\n }\n }\n }\n }\n\n this.map.set(schema, registration);\n }\n\n /**\n * Get the OpenAPI schema for a given Zod schema\n */\n getOpenApiSchema(schema: z.ZodTypeAny): ZodOpenApiRegistration | undefined {\n return this.map.get(schema);\n }\n\n /**\n * Check if a Zod schema is registered\n */\n isRegistered(schema: z.ZodTypeAny): boolean {\n return this.map.has(schema);\n }\n\n /**\n * Clear all registered schemas\n */\n clear(): void {\n this.map.clear();\n }\n\n /**\n * Reverse-lookup helper: given a string format, return the registered schema's exported variable name\n */\n getSchemaExportedVariableNameForStringFormat(\n format: SupportedStringFormat,\n ): string | undefined {\n for (const registration of this.map.values()) {\n if (registration.type !== \"string\") continue;\n\n if (\n isStringRegistration(registration) &&\n registration.format === format\n ) {\n return registration.schemaExportedVariableName;\n }\n\n if (\n isStringsRegistration(registration) &&\n registration.formats.includes(format)\n ) {\n return registration.schemaExportedVariableName;\n }\n }\n return undefined;\n }\n}\n\n// ============================================================================\n// Global Registry Instance\n// ============================================================================\n\nexport const schemaRegistry = new ZodSchemaRegistry();\n\n// ============================================================================\n// Public API\n// ============================================================================\n\n/**\n * Helper function to register a Zod schema with its OpenAPI representation\n */\nexport function registerZodSchemaToOpenApiSchema(\n schema: z.ZodTypeAny,\n openApiSchema: ZodOpenApiRegistration,\n): void {\n schemaRegistry.register(schema, openApiSchema as any);\n}\n\n/**\n * Convenience helper to get an exported schema variable name for a given string format\n */\nexport function getSchemaExportedVariableNameForStringFormat(\n format: SupportedStringFormat,\n): string | undefined {\n return schemaRegistry.getSchemaExportedVariableNameForStringFormat(format);\n}\n\n/**\n * Clear all registered schemas in the global registry\n */\nexport function clearZodSchemaToOpenApiSchemaRegistry(): void {\n schemaRegistry.clear();\n}\n","import {\n getSchemaExportedVariableNameForStringFormat,\n SUPPORTED_STRING_FORMATS,\n} from \"../registry\";\n\n/**\n * Convert an OpenAPI v3 string schema to a Zod schema string\n */\nexport function convertOpenAPIStringToZod(schema: {\n type: \"string\";\n format?: typeof SUPPORTED_STRING_FORMATS;\n minLength?: number;\n maxLength?: number;\n pattern?: string;\n enum?: string[];\n}): string {\n // Handle enum values\n if (schema.enum) {\n return `z.enum([${schema.enum.map((value) => `'${value}'`).join(\", \")}])`;\n }\n\n // Check for custom registered format schemas\n if (schema.format && SUPPORTED_STRING_FORMATS.includes(schema.format)) {\n const customSchemaName = getSchemaExportedVariableNameForStringFormat(\n schema.format,\n );\n\n // Use custom schema if registered (ignores other constraints)\n if (customSchemaName) {\n return customSchemaName;\n }\n }\n\n // Build string schema with format modifiers\n let zodSchema = \"z.string()\";\n\n if (schema.format) {\n zodSchema += getFormatModifier(schema.format);\n }\n\n // Apply length constraints\n if (typeof schema.minLength === \"number\") {\n zodSchema += `.min(${schema.minLength})`;\n }\n\n if (typeof schema.maxLength === \"number\") {\n zodSchema += `.max(${schema.maxLength})`;\n }\n\n // Apply pattern constraint\n if (typeof schema.pattern === \"string\") {\n zodSchema += `.regex(/${schema.pattern}/)`;\n }\n\n return zodSchema;\n}\n\n/**\n * Get the Zod modifier for built-in string formats\n */\nfunction getFormatModifier(format: string): string {\n switch (format) {\n case \"email\":\n return \".email()\";\n case \"url\":\n case \"uri\":\n return \".url()\";\n case \"uuid\":\n return \".uuid()\";\n case \"color-hex\":\n return \".regex(/^[a-fA-F0-9]{6}$/)\";\n default:\n return \"\";\n }\n}\n","import type { AnySchema } from \"./types\";\n\nexport function convertOpenAPIArrayToZod(\n schema: {\n type: \"array\";\n items?: any;\n minItems?: number;\n maxItems?: number;\n },\n convertSchema: (schema: AnySchema) => string,\n): string {\n const item = schema.items;\n\n let itemZodString = \"z.unknown()\";\n if (item && typeof item === \"object\") {\n itemZodString = convertSchema(item);\n }\n\n let result = `z.array(${itemZodString})`;\n\n if (typeof schema.minItems === \"number\") {\n result += `.min(${schema.minItems})`;\n }\n if (typeof schema.maxItems === \"number\") {\n result += `.max(${schema.maxItems})`;\n }\n\n return result;\n}\n","import { AnySchema, OpenAPIObjectSchema } from \"./types\";\n\nconst validIdentifierRegex = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;\n\nfunction quotePropertyName(name: string): string {\n return validIdentifierRegex.test(name) ? name : `'${name}'`;\n}\n\nexport function convertOpenAPIObjectToZod(\n schema: OpenAPIObjectSchema,\n convertSchema: (schema: AnySchema) => string,\n): string {\n const properties = schema.properties || {};\n const propertyNames = Object.keys(properties);\n\n if (propertyNames.length === 0) {\n if (schema.additionalProperties === false) {\n return \"z.object({}).strict()\";\n }\n return \"z.record(z.string(), z.unknown())\";\n }\n\n const requiredSet = new Set(schema.required || []);\n\n const entries: string[] = [];\n for (const [propName, propSchema] of Object.entries(properties)) {\n let zodProp = \"z.unknown()\";\n\n if (propSchema && typeof propSchema === \"object\") {\n zodProp = convertSchema(propSchema);\n }\n\n if (!requiredSet.has(propName)) {\n zodProp += \".optional()\";\n }\n\n entries.push(`${quotePropertyName(propName)}: ${zodProp}`);\n }\n\n let result = `z.object({ ${entries.join(\", \")} })`;\n\n if (schema.additionalProperties === false) {\n result += \".strict()\";\n }\n\n return result;\n}\n","import type { AnySchema } from \"./types\";\n\nexport function convertOpenAPIUnionToZod(\n schema: { oneOf: AnySchema[] },\n convertSchema: (schema: AnySchema) => string,\n): string {\n const items = schema.oneOf.map((item) => convertSchema(item));\n return `z.union([${items.join(\", \")}])`;\n}\n\n","import type { AnySchema } from \"./types\";\n\nexport function convertOpenAPIIntersectionToZod(\n schema: { allOf: AnySchema[] },\n convertSchema: (schema: AnySchema) => string,\n): string {\n const items = schema.allOf.map((item) => convertSchema(item));\n\n if (schema.allOf.length === 0) return \"z.unknown()\";\n if (schema.allOf.length === 1) return convertSchema(schema.allOf[0]!);\n\n return `z.intersection(${items.join(\", \")})`;\n}\n\n","import { convertOpenAPIBooleanToZod } from \"./types/boolean\";\nimport { convertOpenAPINumberToZod } from \"./types/number\";\nimport { convertOpenAPIStringToZod } from \"./types/string\";\nimport { convertOpenAPIArrayToZod } from \"./types/array\";\nimport { convertOpenAPIObjectToZod } from \"./types/object\";\nimport { convertOpenAPIUnionToZod } from \"./types/union\";\nimport { convertOpenAPIIntersectionToZod } from \"./types/intersection\";\nimport type { AnySchema } from \"./types/types\";\n\nexport function convertSchemaToZodString(schema: AnySchema): string {\n if (!schema || typeof schema !== \"object\") return \"z.unknown()\";\n\n if (schema[\"$ref\"] && typeof schema[\"$ref\"] === \"string\") {\n const match = (schema[\"$ref\"] as string).match(\n /#\\/components\\/schemas\\/(.+)/,\n );\n let result = \"z.unknown()\";\n if (match && match[1]) {\n result = `${match[1]}Schema`;\n }\n if (schema[\"nullable\"] === true) {\n result = `z.union([${result}, z.null()])`;\n }\n return result;\n }\n let result: string = \"z.unknown()\";\n\n if (\"oneOf\" in schema && Array.isArray(schema[\"oneOf\"])) {\n result = convertOpenAPIUnionToZod(\n schema as { oneOf: AnySchema[] },\n convertSchemaToZodString,\n );\n } else if (\"allOf\" in schema && Array.isArray(schema[\"allOf\"])) {\n result = convertOpenAPIIntersectionToZod(\n schema as { allOf: AnySchema[] },\n convertSchemaToZodString,\n );\n } else {\n switch (schema[\"type\"]) {\n case \"string\":\n result = convertOpenAPIStringToZod({\n enum: schema[\"enum\"],\n format: schema[\"format\"],\n maxLength: schema[\"maxLength\"],\n minLength: schema[\"minLength\"],\n pattern: schema[\"pattern\"],\n type: \"string\",\n });\n break;\n case \"number\":\n result = convertOpenAPINumberToZod({\n maximum: schema[\"maximum\"],\n minimum: schema[\"minimum\"],\n type: \"number\",\n });\n break;\n case \"integer\":\n result = convertOpenAPINumberToZod({\n maximum: schema[\"maximum\"],\n minimum: schema[\"minimum\"],\n type: \"integer\",\n });\n break;\n case \"boolean\":\n result = convertOpenAPIBooleanToZod({ type: \"boolean\" });\n break;\n case \"array\":\n result = convertOpenAPIArrayToZod(\n {\n items: schema[\"items\"],\n maxItems: schema[\"maxItems\"],\n minItems: schema[\"minItems\"],\n type: \"array\",\n },\n convertSchemaToZodString,\n );\n break;\n case \"object\":\n result = convertOpenAPIObjectToZod(\n {\n additionalProperties: schema[\"additionalProperties\"],\n properties: schema[\"properties\"],\n required: schema[\"required\"],\n type: \"object\",\n },\n convertSchemaToZodString,\n );\n break;\n default:\n if (schema[\"properties\"]) {\n result = convertOpenAPIObjectToZod(\n {\n additionalProperties: schema[\"additionalProperties\"],\n properties: schema[\"properties\"],\n required: schema[\"required\"],\n type: \"object\",\n },\n convertSchemaToZodString,\n );\n } else {\n result = \"z.unknown()\";\n }\n break;\n }\n }\n\n if (schema[\"nullable\"] === true) {\n result = `z.union([${result}, z.null()])`;\n }\n\n return result;\n}\n","import type { AnySchema } from \"./types/types\";\n\nexport type HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\" | \"HEAD\" | \"OPTIONS\";\n\nexport interface RouteParameter {\n name: string;\n in: \"path\" | \"query\" | \"header\" | \"cookie\";\n required: boolean;\n schema: AnySchema;\n}\n\nexport interface RouteInfo {\n path: string;\n method: HttpMethod;\n parameters: RouteParameter[];\n requestBody?: AnySchema;\n responses: Record<string, AnySchema>;\n}\n\nexport interface RouteSchemaNames {\n paramsSchemaName?: string;\n querySchemaName?: string;\n headersSchemaName?: string;\n bodySchemaName?: string;\n responseSchemaName?: string;\n}\n\nfunction toUpperCaseMethod(method: string): HttpMethod {\n const upper = method.toUpperCase();\n if (\n upper === \"GET\" ||\n upper === \"POST\" ||\n upper === \"PUT\" ||\n upper === \"PATCH\" ||\n upper === \"DELETE\" ||\n upper === \"HEAD\" ||\n upper === \"OPTIONS\"\n ) {\n return upper as HttpMethod;\n }\n return \"GET\";\n}\n\nfunction toPascalCase(str: string): string {\n return str\n .replace(/[^a-zA-Z0-9]/g, \" \")\n .split(\" \")\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n .join(\"\");\n}\n\nfunction generateRouteSchemaName(\n path: string,\n method: HttpMethod,\n suffix: string,\n): string {\n const pathParts = path\n .split(\"/\")\n .filter((p) => p)\n .map((p) => {\n if (p.startsWith(\"{\") && p.endsWith(\"}\")) {\n return p.slice(1, -1);\n }\n return p;\n })\n .map(toPascalCase);\n const methodPrefix = method.charAt(0) + method.slice(1).toLowerCase();\n const parts = [methodPrefix, ...pathParts, suffix];\n return parts.join(\"\");\n}\n\nexport function parseOpenApiPaths(\n openapi: Record<string, unknown>,\n): RouteInfo[] {\n const paths = (openapi as AnySchema)[\"paths\"] as\n | Record<string, AnySchema>\n | undefined;\n if (!paths) {\n return [];\n }\n\n const routes: RouteInfo[] = [];\n\n for (const [path, pathItem] of Object.entries(paths)) {\n if (!pathItem || typeof pathItem !== \"object\") continue;\n\n const methods = [\n \"get\",\n \"post\",\n \"put\",\n \"patch\",\n \"delete\",\n \"head\",\n \"options\",\n ] as const;\n\n for (const method of methods) {\n const operation = pathItem[method] as AnySchema | undefined;\n if (!operation) continue;\n\n const parameters: RouteParameter[] = [];\n const responses: Record<string, AnySchema> = {};\n\n if (Array.isArray(pathItem[\"parameters\"])) {\n for (const param of pathItem[\"parameters\"]) {\n if (param && typeof param === \"object\") {\n parameters.push({\n name: String(param[\"name\"] || \"\"),\n in: param[\"in\"] || \"query\",\n required: Boolean(param[\"required\"]),\n schema: param[\"schema\"] || {},\n });\n }\n }\n }\n\n if (Array.isArray(operation[\"parameters\"])) {\n for (const param of operation[\"parameters\"]) {\n if (param && typeof param === \"object\") {\n parameters.push({\n name: String(param[\"name\"] || \"\"),\n in: param[\"in\"] || \"query\",\n required: Boolean(param[\"required\"]),\n schema: param[\"schema\"] || {},\n });\n }\n }\n }\n\n let requestBody: AnySchema | undefined;\n if (operation[\"requestBody\"]) {\n const rb = operation[\"requestBody\"];\n if (rb && typeof rb === \"object\") {\n const content = rb[\"content\"];\n if (content && typeof content === \"object\") {\n const jsonContent = content[\"application/json\"];\n if (jsonContent && typeof jsonContent === \"object\") {\n requestBody = jsonContent[\"schema\"] || {};\n }\n }\n }\n }\n\n if (operation[\"responses\"] && typeof operation[\"responses\"] === \"object\") {\n for (const [statusCode, response] of Object.entries(\n operation[\"responses\"],\n )) {\n if (response && typeof response === \"object\") {\n const responseSchema = response as AnySchema;\n const content = responseSchema[\"content\"];\n if (content && typeof content === \"object\") {\n const jsonContent = content[\"application/json\"];\n if (jsonContent && typeof jsonContent === \"object\") {\n const schema = jsonContent[\"schema\"];\n if (schema) {\n responses[statusCode] = schema;\n }\n }\n }\n }\n }\n }\n\n routes.push({\n path,\n method: toUpperCaseMethod(method),\n parameters,\n requestBody,\n responses,\n });\n }\n }\n\n return routes;\n}\n\nexport function generateRouteSchemaNames(\n route: RouteInfo,\n): RouteSchemaNames {\n const pathParams = route.parameters.filter((p) => p.in === \"path\");\n const queryParams = route.parameters.filter((p) => p.in === \"query\");\n const headerParams = route.parameters.filter((p) => p.in === \"header\");\n const successStatuses = Object.keys(route.responses).filter((s) =>\n s.startsWith(\"2\"),\n );\n\n const result: RouteSchemaNames = {\n responseSchemaName: successStatuses.length > 0\n ? generateRouteSchemaName(\n route.path,\n route.method,\n \"Response\",\n )\n : undefined,\n };\n\n if (pathParams.length > 0) {\n result.paramsSchemaName = generateRouteSchemaName(\n route.path,\n route.method,\n \"Params\",\n );\n }\n\n if (queryParams.length > 0) {\n result.querySchemaName = generateRouteSchemaName(\n route.path,\n route.method,\n \"Query\",\n );\n }\n\n if (headerParams.length > 0) {\n result.headersSchemaName = generateRouteSchemaName(\n route.path,\n route.method,\n \"Headers\",\n );\n }\n\n if (route.requestBody) {\n result.bodySchemaName = generateRouteSchemaName(\n route.path,\n route.method,\n \"Body\",\n );\n }\n\n return result;\n}\n\n","import { topologicalSortSchemas } from \"./dependencies\";\nimport {\n createSchemaRegistry,\n findCommonSchemas,\n getSchemaFingerprint,\n preRegisterSchema,\n registerSchema,\n type SchemaRegistry,\n} from \"./schema-dedup\";\nimport { convertSchemaToZodString } from \"./to-zod\";\nimport type { AnySchema } from \"./types/types\";\nimport {\n parseOpenApiPaths,\n generateRouteSchemaNames,\n type RouteInfo,\n} from \"./routes\";\n\nconst validIdentifierRegex = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;\n\nfunction quotePropertyName(name: string): string {\n return validIdentifierRegex.test(name) ? name : `'${name}'`;\n}\n\nfunction generateRouteSchemaName(\n path: string,\n method: string,\n suffix: string,\n): string {\n const pathParts = path\n .split(\"/\")\n .filter((p) => p)\n .map((p) => {\n if (p.startsWith(\"{\") && p.endsWith(\"}\")) {\n return p.slice(1, -1);\n }\n return p;\n })\n .map((word) => {\n // Convert hyphenated words to PascalCase (e.g., \"timer-drafts\" -> \"TimerDrafts\")\n return word\n .split(/[-_]/)\n .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1).toLowerCase())\n .join(\"\");\n });\n const methodPrefix = method.charAt(0) + method.slice(1).toLowerCase();\n const parts = [methodPrefix, ...pathParts, suffix];\n return parts.join(\"\");\n}\n\n/**\n * Result of route schema generation including declarations and name mappings.\n */\ninterface RouteSchemaResult {\n /** Schema declarations to be emitted */\n declarations: string[];\n /** Maps route-specific schema name to its canonical name (for deduplication) */\n schemaNameToCanonical: Map<string, string>;\n}\n\nfunction generateRouteSchemas(\n routes: RouteInfo[],\n convertSchema: (schema: AnySchema) => string,\n registry: SchemaRegistry,\n): RouteSchemaResult {\n const declarations: string[] = [];\n const schemaNameToCanonical = new Map<string, string>();\n const generatedNames = new Set<string>();\n\n for (const route of routes) {\n const names = generateRouteSchemaNames(route);\n const pathParams = route.parameters.filter((p) => p.in === \"path\");\n const queryParams = route.parameters.filter((p) => p.in === \"query\");\n const headerParams = route.parameters.filter((p) => p.in === \"header\");\n\n // Generate params schema with deduplication\n if (names.paramsSchemaName && pathParams.length > 0) {\n const paramsSchema: AnySchema = {\n type: \"object\",\n properties: Object.fromEntries(\n pathParams.map((p) => [p.name, p.schema]),\n ),\n required: pathParams.filter((p) => p.required).map((p) => p.name),\n };\n\n const { isNew, canonicalName } = registerSchema(\n registry,\n names.paramsSchemaName,\n paramsSchema,\n );\n schemaNameToCanonical.set(names.paramsSchemaName, canonicalName);\n\n if (isNew && !generatedNames.has(names.paramsSchemaName)) {\n generatedNames.add(names.paramsSchemaName);\n const properties: string[] = [];\n for (const param of pathParams) {\n const zodExpr = convertSchema(param.schema);\n properties.push(`${quotePropertyName(param.name)}: ${zodExpr}`);\n }\n declarations.push(\n `export const ${names.paramsSchemaName} = z.object({ ${properties.join(\", \")} });`,\n );\n } else if (!isNew && names.paramsSchemaName !== canonicalName) {\n if (!generatedNames.has(names.paramsSchemaName)) {\n generatedNames.add(names.paramsSchemaName);\n declarations.push(\n `export const ${names.paramsSchemaName} = ${canonicalName};`,\n );\n }\n }\n }\n\n // Generate query schema with deduplication\n if (names.querySchemaName && queryParams.length > 0) {\n const querySchema: AnySchema = {\n type: \"object\",\n properties: Object.fromEntries(\n queryParams.map((p) => [p.name, p.schema]),\n ),\n required: queryParams.filter((p) => p.required).map((p) => p.name),\n };\n\n const { isNew, canonicalName } = registerSchema(\n registry,\n names.querySchemaName,\n querySchema,\n );\n schemaNameToCanonical.set(names.querySchemaName, canonicalName);\n\n if (isNew && !generatedNames.has(names.querySchemaName)) {\n generatedNames.add(names.querySchemaName);\n const properties: string[] = [];\n for (const param of queryParams) {\n let zodExpr = convertSchema(param.schema);\n if (!param.required) {\n zodExpr += \".optional()\";\n }\n properties.push(`${quotePropertyName(param.name)}: ${zodExpr}`);\n }\n declarations.push(\n `export const ${names.querySchemaName} = z.object({ ${properties.join(\", \")} });`,\n );\n } else if (!isNew && names.querySchemaName !== canonicalName) {\n if (!generatedNames.has(names.querySchemaName)) {\n generatedNames.add(names.querySchemaName);\n declarations.push(\n `export const ${names.querySchemaName} = ${canonicalName};`,\n );\n }\n }\n }\n\n // Generate headers schema with deduplication\n if (names.headersSchemaName && headerParams.length > 0) {\n const headersSchema: AnySchema = {\n type: \"object\",\n properties: Object.fromEntries(\n headerParams.map((p) => [p.name, p.schema]),\n ),\n required: headerParams.filter((p) => p.required).map((p) => p.name),\n };\n\n const { isNew, canonicalName } = registerSchema(\n registry,\n names.headersSchemaName,\n headersSchema,\n );\n schemaNameToCanonical.set(names.headersSchemaName, canonicalName);\n\n if (isNew && !generatedNames.has(names.headersSchemaName)) {\n generatedNames.add(names.headersSchemaName);\n const properties: string[] = [];\n for (const param of headerParams) {\n let zodExpr = convertSchema(param.schema);\n if (!param.required) {\n zodExpr += \".optional()\";\n }\n properties.push(`${quotePropertyName(param.name)}: ${zodExpr}`);\n }\n declarations.push(\n `export const ${names.headersSchemaName} = z.object({ ${properties.join(\", \")} });`,\n );\n } else if (!isNew && names.headersSchemaName !== canonicalName) {\n if (!generatedNames.has(names.headersSchemaName)) {\n generatedNames.add(names.headersSchemaName);\n declarations.push(\n `export const ${names.headersSchemaName} = ${canonicalName};`,\n );\n }\n }\n }\n\n // Generate body schema with deduplication\n if (names.bodySchemaName && route.requestBody) {\n const { isNew, canonicalName } = registerSchema(\n registry,\n names.bodySchemaName,\n route.requestBody,\n );\n schemaNameToCanonical.set(names.bodySchemaName, canonicalName);\n\n if (isNew && !generatedNames.has(names.bodySchemaName)) {\n generatedNames.add(names.bodySchemaName);\n const zodExpr = convertSchema(route.requestBody);\n declarations.push(`export const ${names.bodySchemaName} = ${zodExpr};`);\n } else if (!isNew && names.bodySchemaName !== canonicalName) {\n if (!generatedNames.has(names.bodySchemaName)) {\n generatedNames.add(names.bodySchemaName);\n declarations.push(\n `export const ${names.bodySchemaName} = ${canonicalName};`,\n );\n }\n }\n }\n\n // Generate schemas for ALL status codes with deduplication\n for (const [statusCode, responseSchema] of Object.entries(\n route.responses,\n )) {\n if (!responseSchema) continue;\n\n const isSuccess = statusCode.startsWith(\"2\");\n const suffix = isSuccess\n ? `${statusCode}Response`\n : `${statusCode}ErrorResponse`;\n const responseSchemaName = generateRouteSchemaName(\n route.path,\n route.method,\n suffix,\n );\n\n const { isNew, canonicalName } = registerSchema(\n registry,\n responseSchemaName,\n responseSchema,\n );\n schemaNameToCanonical.set(responseSchemaName, canonicalName);\n\n if (isNew && !generatedNames.has(responseSchemaName)) {\n generatedNames.add(responseSchemaName);\n const zodExpr = convertSchema(responseSchema);\n declarations.push(`export const ${responseSchemaName} = ${zodExpr};`);\n } else if (!isNew && responseSchemaName !== canonicalName) {\n if (!generatedNames.has(responseSchemaName)) {\n generatedNames.add(responseSchemaName);\n declarations.push(\n `export const ${responseSchemaName} = ${canonicalName};`,\n );\n }\n }\n }\n }\n\n return { declarations, schemaNameToCanonical };\n}\n\nfunction generateRequestResponseObjects(\n routes: RouteInfo[],\n schemaNameToCanonical: Map<string, string>,\n): string[] {\n const lines: string[] = [];\n const requestPaths: Record<string, Record<string, string[]>> = {};\n const responsePaths: Record<\n string,\n Record<string, Record<string, string>>\n > = {};\n\n /**\n * Resolves a schema name to its canonical name if it exists,\n * otherwise returns the original name.\n */\n const resolveSchemaName = (name: string): string => {\n return schemaNameToCanonical.get(name) ?? name;\n };\n\n for (const route of routes) {\n const names = generateRouteSchemaNames(route);\n const pathParams = route.parameters.filter((p) => p.in === \"path\");\n const queryParams = route.parameters.filter((p) => p.in === \"query\");\n const headerParams = route.parameters.filter((p) => p.in === \"header\");\n\n if (!requestPaths[route.path]) {\n requestPaths[route.path] = {};\n }\n const requestMethodObj = requestPaths[route.path]!;\n if (!requestMethodObj[route.method]) {\n requestMethodObj[route.method] = [];\n }\n\n const requestParts: string[] = [];\n if (names.paramsSchemaName && pathParams.length > 0) {\n requestParts.push(\n `params: ${resolveSchemaName(names.paramsSchemaName)}`,\n );\n }\n if (names.querySchemaName && queryParams.length > 0) {\n requestParts.push(`query: ${resolveSchemaName(names.querySchemaName)}`);\n }\n if (names.headersSchemaName && headerParams.length > 0) {\n requestParts.push(\n `headers: ${resolveSchemaName(names.headersSchemaName)}`,\n );\n }\n if (names.bodySchemaName && route.requestBody) {\n requestParts.push(`body: ${resolveSchemaName(names.bodySchemaName)}`);\n }\n\n if (requestParts.length > 0) {\n requestMethodObj[route.method] = requestParts;\n }\n\n // Store all status codes in nested structure\n if (!responsePaths[route.path]) {\n responsePaths[route.path] = {};\n }\n const responseMethodObj = responsePaths[route.path]!;\n if (!responseMethodObj[route.method]) {\n responseMethodObj[route.method] = {};\n }\n\n for (const [statusCode, responseSchema] of Object.entries(\n route.responses,\n )) {\n if (!responseSchema) continue;\n\n const isSuccess = statusCode.startsWith(\"2\");\n const suffix = isSuccess\n ? `${statusCode}Response`\n : `${statusCode}ErrorResponse`;\n const responseSchemaName = generateRouteSchemaName(\n route.path,\n route.method,\n suffix,\n );\n // Use canonical name for the Response object\n responseMethodObj[route.method]![statusCode] =\n resolveSchemaName(responseSchemaName);\n }\n }\n\n lines.push(\"export const Request = {\");\n for (const [path, methods] of Object.entries(requestPaths)) {\n const methodEntries = Object.entries(methods).filter(\n ([, parts]) => parts.length > 0,\n );\n if (methodEntries.length > 0) {\n lines.push(` '${path}': {`);\n for (const [method, parts] of methodEntries) {\n lines.push(` ${method}: {`);\n for (const part of parts) {\n lines.push(` ${part},`);\n }\n lines.push(` },`);\n }\n lines.push(` },`);\n }\n }\n lines.push(\"} as const;\");\n lines.push(\"\");\n\n lines.push(\"export const Response = {\");\n for (const [path, methods] of Object.entries(responsePaths)) {\n const methodEntries = Object.entries(methods);\n if (methodEntries.length > 0) {\n lines.push(` '${path}': {`);\n for (const [method, statusCodes] of methodEntries) {\n lines.push(` ${method}: {`);\n for (const [statusCode, schemaName] of Object.entries(statusCodes)) {\n lines.push(` '${statusCode}': ${schemaName},`);\n }\n lines.push(` },`);\n }\n lines.push(` },`);\n }\n }\n lines.push(\"} as const;\");\n\n return lines;\n}\n\n/**\n * Collects all response schemas from routes for common schema detection.\n */\nfunction collectRouteSchemas(\n routes: RouteInfo[],\n): Array<{ name: string; schema: AnySchema }> {\n const collected: Array<{ name: string; schema: AnySchema }> = [];\n\n for (const route of routes) {\n for (const [statusCode, responseSchema] of Object.entries(\n route.responses,\n )) {\n if (!responseSchema) continue;\n\n const isSuccess = statusCode.startsWith(\"2\");\n const suffix = isSuccess\n ? `${statusCode}Response`\n : `${statusCode}ErrorResponse`;\n const responseSchemaName = generateRouteSchemaName(\n route.path,\n route.method,\n suffix,\n );\n\n collected.push({ name: responseSchemaName, schema: responseSchema });\n }\n }\n\n return collected;\n}\n\nexport const openApiToZodTsCode = (\n openapi: Record<string, unknown>,\n customImportLines?: string[],\n options?: { includeRoutes?: boolean },\n): string => {\n const components = (openapi as AnySchema)[\"components\"] as\n | AnySchema\n | undefined;\n const schemas: Record<string, AnySchema> =\n (components?.[\"schemas\"] as Record<string, AnySchema>) ?? {};\n\n const lines: string[] = [];\n lines.push(\"/**\");\n lines.push(\" * This file was automatically generated from OpenAPI schema\");\n lines.push(\" * Do not manually edit this file\");\n lines.push(\" */\");\n lines.push(\"\");\n lines.push(\"import { z } from 'zod';\");\n lines.push(...(customImportLines ?? []));\n lines.push(\"\");\n\n // Create registry for schema deduplication\n const registry = createSchemaRegistry();\n\n const sortedSchemaNames = topologicalSortSchemas(schemas);\n\n for (const name of sortedSchemaNames) {\n const schema = schemas[name];\n if (schema) {\n const zodExpr = convertSchemaToZodString(schema);\n const schemaName = `${name}Schema`;\n const typeName = name;\n lines.push(`export const ${schemaName} = ${zodExpr};`);\n lines.push(`export type ${typeName} = z.infer<typeof ${schemaName}>;`);\n lines.push(\"\");\n\n // Register component schemas so they can be referenced by route schemas\n const fingerprint = getSchemaFingerprint(schema);\n preRegisterSchema(registry, schemaName, fingerprint);\n }\n }\n\n if (options?.includeRoutes) {\n const routes = parseOpenApiPaths(openapi);\n if (routes.length > 0) {\n // Find common schemas that appear multiple times (for error responses, etc.)\n const routeSchemaList = collectRouteSchemas(routes);\n const commonSchemas = findCommonSchemas(routeSchemaList, 2);\n\n // Generate common schemas first (e.g., UnauthorizedErrorSchema, NotFoundErrorSchema)\n if (commonSchemas.length > 0) {\n lines.push(\"// Common Error Schemas (deduplicated)\");\n for (const common of commonSchemas) {\n const zodExpr = convertSchemaToZodString(common.schema);\n lines.push(`export const ${common.name} = ${zodExpr};`);\n // Pre-register so route schemas reference this instead of duplicating\n preRegisterSchema(registry, common.name, common.fingerprint);\n }\n lines.push(\"\");\n }\n\n // Generate route schemas with deduplication\n const { declarations, schemaNameToCanonical } = generateRouteSchemas(\n routes,\n convertSchemaToZodString,\n registry,\n );\n\n if (declarations.length > 0) {\n lines.push(\"// Route Schemas\");\n lines.push(...declarations);\n lines.push(\"\");\n\n // Generate Request/Response objects using canonical names\n const requestResponseObjs = generateRequestResponseObjects(\n routes,\n schemaNameToCanonical,\n );\n lines.push(...requestResponseObjs);\n }\n }\n }\n\n return lines.join(\"\\n\");\n};\n"],"mappings":"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","names":["result","validIdentifierRegex","quotePropertyName","generateRouteSchemaName"]}
|
package/package.json
CHANGED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import type { AnySchema } from "./types/types";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Schema deduplication utilities for optimizing generated TypeScript types.
|
|
5
|
+
*
|
|
6
|
+
* This module provides fingerprinting and registry functionality to detect
|
|
7
|
+
* structurally identical schemas and generate them only once, reducing
|
|
8
|
+
* memory usage in consuming TypeScript projects.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Recursively sorts an object's keys to create a stable representation.
|
|
13
|
+
* This ensures that {a: 1, b: 2} and {b: 2, a: 1} produce the same fingerprint.
|
|
14
|
+
*/
|
|
15
|
+
function sortObjectDeep(obj: unknown): unknown {
|
|
16
|
+
if (obj === null || typeof obj !== "object") return obj;
|
|
17
|
+
if (Array.isArray(obj)) return obj.map(sortObjectDeep);
|
|
18
|
+
|
|
19
|
+
const sorted: Record<string, unknown> = {};
|
|
20
|
+
const keys = Object.keys(obj as Record<string, unknown>).sort();
|
|
21
|
+
for (const key of keys) {
|
|
22
|
+
sorted[key] = sortObjectDeep((obj as Record<string, unknown>)[key]);
|
|
23
|
+
}
|
|
24
|
+
return sorted;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Generates a canonical fingerprint for an OpenAPI schema.
|
|
29
|
+
* Identical schemas will produce identical fingerprints.
|
|
30
|
+
*/
|
|
31
|
+
export function getSchemaFingerprint(schema: AnySchema): string {
|
|
32
|
+
return JSON.stringify(sortObjectDeep(schema));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Registry for tracking unique schemas and their canonical names.
|
|
37
|
+
*/
|
|
38
|
+
export interface SchemaRegistry {
|
|
39
|
+
/** Map from fingerprint to the first schema name that used it */
|
|
40
|
+
fingerprintToName: Map<string, string>;
|
|
41
|
+
/** Map from schema name to its fingerprint (for reverse lookup) */
|
|
42
|
+
nameToFingerprint: Map<string, string>;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Creates a new empty schema registry.
|
|
47
|
+
*/
|
|
48
|
+
export function createSchemaRegistry(): SchemaRegistry {
|
|
49
|
+
return {
|
|
50
|
+
fingerprintToName: new Map(),
|
|
51
|
+
nameToFingerprint: new Map(),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Result of registering a schema.
|
|
57
|
+
*/
|
|
58
|
+
export interface RegisterSchemaResult {
|
|
59
|
+
/** Whether this is a new unique schema */
|
|
60
|
+
isNew: boolean;
|
|
61
|
+
/** The canonical name for this schema (may be different from input name if duplicate) */
|
|
62
|
+
canonicalName: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Registers a schema in the registry. If an identical schema already exists,
|
|
67
|
+
* returns the existing canonical name instead.
|
|
68
|
+
*/
|
|
69
|
+
export function registerSchema(
|
|
70
|
+
registry: SchemaRegistry,
|
|
71
|
+
name: string,
|
|
72
|
+
schema: AnySchema,
|
|
73
|
+
): RegisterSchemaResult {
|
|
74
|
+
const fingerprint = getSchemaFingerprint(schema);
|
|
75
|
+
|
|
76
|
+
const existing = registry.fingerprintToName.get(fingerprint);
|
|
77
|
+
if (existing) {
|
|
78
|
+
return { isNew: false, canonicalName: existing };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
registry.fingerprintToName.set(fingerprint, name);
|
|
82
|
+
registry.nameToFingerprint.set(name, fingerprint);
|
|
83
|
+
return { isNew: true, canonicalName: name };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Pre-registers a schema with a specific fingerprint.
|
|
88
|
+
* Used for common schemas that should take priority.
|
|
89
|
+
*/
|
|
90
|
+
export function preRegisterSchema(
|
|
91
|
+
registry: SchemaRegistry,
|
|
92
|
+
name: string,
|
|
93
|
+
fingerprint: string,
|
|
94
|
+
): void {
|
|
95
|
+
registry.fingerprintToName.set(fingerprint, name);
|
|
96
|
+
registry.nameToFingerprint.set(name, fingerprint);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Extracts the error code from an OpenAPI error schema.
|
|
101
|
+
* Looks for patterns like: { error: { code: enum(['UNAUTHORIZED']) } }
|
|
102
|
+
*/
|
|
103
|
+
export function extractErrorCode(schema: AnySchema): string | null {
|
|
104
|
+
const properties = schema?.["properties"] as Record<string, AnySchema> | undefined;
|
|
105
|
+
const errorObj = properties?.["error"] as AnySchema | undefined;
|
|
106
|
+
const errorProps = errorObj?.["properties"] as Record<string, AnySchema> | undefined;
|
|
107
|
+
const codeSchema = errorProps?.["code"] as AnySchema | undefined;
|
|
108
|
+
const codeEnum = codeSchema?.["enum"] as string[] | undefined;
|
|
109
|
+
|
|
110
|
+
if (Array.isArray(codeEnum) && codeEnum.length === 1) {
|
|
111
|
+
return codeEnum[0]!;
|
|
112
|
+
}
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Converts an error code like UNAUTHORIZED or NOT_FOUND to PascalCase.
|
|
118
|
+
* UNAUTHORIZED -> Unauthorized
|
|
119
|
+
* NOT_FOUND -> NotFound
|
|
120
|
+
*/
|
|
121
|
+
export function errorCodeToPascalCase(code: string): string {
|
|
122
|
+
return code
|
|
123
|
+
.split("_")
|
|
124
|
+
.map((part) => part.charAt(0) + part.slice(1).toLowerCase())
|
|
125
|
+
.join("");
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Generates a common error schema name from an error code.
|
|
130
|
+
* UNAUTHORIZED -> UnauthorizedErrorSchema
|
|
131
|
+
*/
|
|
132
|
+
export function generateCommonErrorSchemaName(errorCode: string): string {
|
|
133
|
+
return `${errorCodeToPascalCase(errorCode)}ErrorSchema`;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Represents a common schema that appears multiple times.
|
|
138
|
+
*/
|
|
139
|
+
export interface CommonSchema {
|
|
140
|
+
/** The canonical name for this schema */
|
|
141
|
+
name: string;
|
|
142
|
+
/** The schema definition */
|
|
143
|
+
schema: AnySchema;
|
|
144
|
+
/** The fingerprint for deduplication */
|
|
145
|
+
fingerprint: string;
|
|
146
|
+
/** Number of times this schema appears */
|
|
147
|
+
count: number;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Scans schemas and identifies those that appear multiple times.
|
|
152
|
+
* Returns common schemas sorted by count (most common first).
|
|
153
|
+
*/
|
|
154
|
+
export function findCommonSchemas(
|
|
155
|
+
schemas: Array<{ name: string; schema: AnySchema }>,
|
|
156
|
+
minCount: number = 2,
|
|
157
|
+
): CommonSchema[] {
|
|
158
|
+
const fingerprints = new Map<
|
|
159
|
+
string,
|
|
160
|
+
{ schema: AnySchema; names: string[]; errorCode: string | null }
|
|
161
|
+
>();
|
|
162
|
+
|
|
163
|
+
// Count occurrences of each unique schema
|
|
164
|
+
for (const { name, schema } of schemas) {
|
|
165
|
+
const fingerprint = getSchemaFingerprint(schema);
|
|
166
|
+
const existing = fingerprints.get(fingerprint);
|
|
167
|
+
|
|
168
|
+
if (existing) {
|
|
169
|
+
existing.names.push(name);
|
|
170
|
+
} else {
|
|
171
|
+
fingerprints.set(fingerprint, {
|
|
172
|
+
schema,
|
|
173
|
+
names: [name],
|
|
174
|
+
errorCode: extractErrorCode(schema),
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Filter to schemas appearing minCount+ times
|
|
180
|
+
const commonSchemas: CommonSchema[] = [];
|
|
181
|
+
for (const [fingerprint, data] of fingerprints) {
|
|
182
|
+
if (data.names.length >= minCount) {
|
|
183
|
+
// Generate a semantic name if it's an error schema, otherwise use first occurrence
|
|
184
|
+
const name = data.errorCode
|
|
185
|
+
? generateCommonErrorSchemaName(data.errorCode)
|
|
186
|
+
: data.names[0]!;
|
|
187
|
+
|
|
188
|
+
commonSchemas.push({
|
|
189
|
+
name,
|
|
190
|
+
schema: data.schema,
|
|
191
|
+
fingerprint,
|
|
192
|
+
count: data.names.length,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Sort by count descending (most common first)
|
|
198
|
+
return commonSchemas.sort((a, b) => b.count - a.count);
|
|
199
|
+
}
|