@trpc/openapi
Version:
1 lines • 90.1 kB
Source Map (JSON)
{"version":3,"file":"index.mjs","names":["value: unknown","schema: $ZodType","wrapperDefTypes: ReadonlySet<$ZodTypeDef['type']>","def: $ZodTypeDef","current: $ZodType","schema: unknown","map: DescriptionMap","prefix: string","ctx: {\n registry: $ZodRegistry<GlobalMeta>;\n map: DescriptionMap;\n seenLazy: Set<$ZodType>;\n }","path","mod: Record<string, unknown>","exportName: string","resolvedPath: string","routerOrRecord: AnyTRPCRouter | TRPCRouterRecord","result: Map<string, RuntimeDescriptions>","record: TRPCRouterRecord","inputDescs: DescriptionMap | null","outputDescs: DescriptionMap | null","value: AnyTRPCProcedure | TRPCRouterRecord","schema: SchemaObject","descs: DescriptionMap","schemas?: Record<string, SchemaObject>","propertyName: string","description: string","type: ts.Type","flag: ts.TypeFlags","sym: ts.Symbol","prop: ts.Symbol","schema: SchemaObject | null","schemas: Record<string, SchemaObject>","name: string","existing: Record<string, unknown>","schema: SchemaObject","s: SchemaObject","ctx: SchemaCtx","schema","flags: ts.TypeFlags","checker: ts.TypeChecker","type: ts.UnionType","depth: number","schemas: SchemaObject[]","nonNull: ts.Type[]","hasNull: boolean","type: ts.IntersectionType","properties: Record<string, SchemaObject>","required: string[]","additionalProperties: SchemaObject | boolean | undefined","result: SchemaObject","autoRegName: string | null","defType: ts.Type","inputType: ts.Type | null","type: ProcedureInfo['type']","path: string","def: ProcedureDef","initializer: ts.Expression | null","recovered: ts.Type | null","expr: ts.Expression","ctx: WalkCtx","inputSchema: SchemaObject | null","outputSchema: SchemaObject | null","filePath: string","opts: WalkTypeOpts","recordType: ts.Type","prefix: string","startDir: string","options: ts.CompilerOptions","routerType: ts.Type","schemaCtx: SchemaCtx","keys: string[]","DEFAULT_ERROR_SCHEMA: SchemaObject","resultSchema: SchemaObject","proc: ProcedureInfo","method: 'get' | 'post'","operation: OperationObject","procedures: ProcedureInfo[]","options: GenerateOptions","meta: RouterMeta","paths: PathsObject","pathItem: PathItemObject","routerFilePath: string","walkCtx: WalkCtx"],"sources":["../src/schemaExtraction.ts","../src/generate.ts","../src/types.ts"],"sourcesContent":["import { pathToFileURL } from 'node:url';\nimport type {\n AnyTRPCProcedure,\n AnyTRPCRouter,\n TRPCRouterRecord,\n} from '@trpc/server';\nimport type {\n $ZodArrayDef,\n $ZodObjectDef,\n $ZodRegistry,\n $ZodShape,\n $ZodType,\n $ZodTypeDef,\n GlobalMeta,\n} from 'zod/v4/core';\nimport type { SchemaObject } from './types';\n\n/** Description strings extracted from Zod `.describe()` calls, keyed by dot-delimited property path. */\nexport interface DescriptionMap {\n /** Top-level description on the schema itself (empty-string key). */\n self?: string;\n /** Property-path → description, e.g. `\"name\"` or `\"address.street\"`. */\n properties: Map<string, string>;\n}\n\nexport interface RuntimeDescriptions {\n input: DescriptionMap | null;\n output: DescriptionMap | null;\n}\n\n// ---------------------------------------------------------------------------\n// Zod shape walking — extract .describe() strings\n// ---------------------------------------------------------------------------\n\n/**\n * Zod v4 stores `.describe()` strings in `globalThis.__zod_globalRegistry`,\n * a WeakMap-backed `$ZodRegistry<GlobalMeta>`. We access it via globalThis\n * because zod is an optional peer dependency.\n */\nfunction getZodGlobalRegistry(): $ZodRegistry<GlobalMeta> | null {\n const reg = (\n globalThis as { __zod_globalRegistry?: $ZodRegistry<GlobalMeta> }\n ).__zod_globalRegistry;\n return reg && typeof reg.get === 'function' ? reg : null;\n}\n\n/** Runtime check: does this value look like a `$ZodType` (has `_zod.def`)? */\nfunction isZodSchema(value: unknown): value is $ZodType {\n if (value == null || typeof value !== 'object') return false;\n const zod = (value as { _zod?: unknown })._zod;\n return zod != null && typeof zod === 'object' && 'def' in zod;\n}\n\n/** Get the object shape from a Zod object schema, if applicable. */\nfunction zodObjectShape(schema: $ZodType): $ZodShape | null {\n const def = schema._zod.def;\n if (def.type === 'object' && 'shape' in def) {\n return (def as $ZodObjectDef).shape;\n }\n return null;\n}\n\n/** Get the element schema from a Zod array schema, if applicable. */\nfunction zodArrayElement(schema: $ZodType): $ZodType | null {\n const def = schema._zod.def;\n if (def.type === 'array' && 'element' in def) {\n return (def as $ZodArrayDef).element;\n }\n return null;\n}\n\n/** Wrapper def types whose inner schema is accessible via `innerType` or `in`. */\nconst wrapperDefTypes: ReadonlySet<$ZodTypeDef['type']> = new Set([\n 'optional',\n 'nullable',\n 'nonoptional',\n 'default',\n 'prefault',\n 'catch',\n 'readonly',\n 'pipe',\n 'transform',\n 'promise',\n]);\n\n/**\n * Extract the wrapped inner schema from a wrapper def.\n * Most wrappers use `innerType`; `pipe` uses `in`.\n */\nfunction getWrappedInner(def: $ZodTypeDef): $ZodType | null {\n if ('innerType' in def) return (def as { innerType: $ZodType }).innerType;\n if ('in' in def) return (def as { in: $ZodType }).in;\n return null;\n}\n\n/** Unwrap wrapper types (optional, nullable, default, readonly, etc.) to get the inner schema. */\nfunction unwrapZodSchema(schema: $ZodType): $ZodType {\n let current: $ZodType = schema;\n const seen = new Set<$ZodType>();\n while (!seen.has(current)) {\n seen.add(current);\n const def = current._zod.def;\n if (!wrapperDefTypes.has(def.type)) break;\n const inner = getWrappedInner(def);\n if (!inner) break;\n current = inner;\n }\n return current;\n}\n\n/**\n * Walk a Zod schema and collect description strings at each property path.\n * Returns `null` if the value is not a Zod schema or has no descriptions.\n */\nexport function extractZodDescriptions(schema: unknown): DescriptionMap | null {\n if (!isZodSchema(schema)) return null;\n const registry = getZodGlobalRegistry();\n if (!registry) return null;\n\n const map: DescriptionMap = { properties: new Map() };\n let hasAny = false;\n\n // Check top-level description\n const topMeta = registry.get(schema);\n if (topMeta?.description) {\n map.self = topMeta.description;\n hasAny = true;\n }\n\n // Walk object shape\n walkZodShape(schema, '', { registry, map, seenLazy: new Set() });\n if (map.properties.size > 0) hasAny = true;\n\n return hasAny ? map : null;\n}\n\nfunction walkZodShape(\n schema: $ZodType,\n prefix: string,\n ctx: {\n registry: $ZodRegistry<GlobalMeta>;\n map: DescriptionMap;\n seenLazy: Set<$ZodType>;\n },\n): void {\n const unwrapped = unwrapZodSchema(schema);\n const def = unwrapped._zod.def;\n\n if (def.type === 'lazy' && 'getter' in def) {\n if (ctx.seenLazy.has(unwrapped)) {\n return;\n }\n ctx.seenLazy.add(unwrapped);\n const inner = (def as { getter: () => unknown }).getter();\n if (isZodSchema(inner)) {\n walkZodShape(inner, prefix, ctx);\n }\n return;\n }\n\n // If this is an array, check for a description on the element schema itself\n // (stored as `[]` in the path) and recurse into the element's shape.\n const element = zodArrayElement(unwrapped);\n if (element) {\n const unwrappedElement = unwrapZodSchema(element);\n const elemMeta = ctx.registry.get(element);\n const innerElemMeta =\n unwrappedElement !== element\n ? ctx.registry.get(unwrappedElement)\n : undefined;\n const elemDesc = elemMeta?.description ?? innerElemMeta?.description;\n if (elemDesc) {\n const itemsPath = prefix ? `${prefix}.[]` : '[]';\n ctx.map.properties.set(itemsPath, elemDesc);\n }\n walkZodShape(element, prefix, ctx);\n return;\n }\n\n const shape = zodObjectShape(unwrapped);\n if (!shape) return;\n\n for (const [key, fieldSchema] of Object.entries(shape)) {\n const path = prefix ? `${prefix}.${key}` : key;\n\n // Check for description on the field — may be on the wrapper or inner schema\n const meta = ctx.registry.get(fieldSchema);\n const unwrappedField = unwrapZodSchema(fieldSchema);\n const innerMeta =\n unwrappedField !== fieldSchema\n ? ctx.registry.get(unwrappedField)\n : undefined;\n const description = meta?.description ?? innerMeta?.description;\n if (description) {\n ctx.map.properties.set(path, description);\n }\n\n // Recurse into nested objects and arrays\n walkZodShape(unwrappedField, path, ctx);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Router detection & dynamic import\n// ---------------------------------------------------------------------------\n\n/** Check whether a value looks like a tRPC router instance at runtime. */\nfunction isRouterInstance(value: unknown): value is AnyTRPCRouter {\n if (value == null) return false;\n const obj = value as Record<string, unknown>;\n const def = obj['_def'];\n return (\n typeof obj === 'object' &&\n def != null &&\n typeof def === 'object' &&\n (def as Record<string, unknown>)['record'] != null &&\n typeof (def as Record<string, unknown>)['record'] === 'object'\n );\n}\n\n/**\n * Search a module's exports for a tRPC router instance.\n *\n * Tries (in order):\n * 1. Exact `exportName` match\n * 2. lcfirst variant (`AppRouter` → `appRouter`)\n * 3. First export that looks like a router\n */\nexport function findRouterExport(\n mod: Record<string, unknown>,\n exportName: string,\n): AnyTRPCRouter | null {\n // 1. Exact match\n if (isRouterInstance(mod[exportName])) {\n return mod[exportName];\n }\n\n // 2. lcfirst variant (e.g. AppRouter → appRouter)\n const lcFirst = exportName.charAt(0).toLowerCase() + exportName.slice(1);\n if (lcFirst !== exportName && isRouterInstance(mod[lcFirst])) {\n return mod[lcFirst];\n }\n\n // 3. Any export that looks like a router\n for (const value of Object.values(mod)) {\n if (isRouterInstance(value)) {\n return value;\n }\n }\n\n return null;\n}\n\n/**\n * Try to dynamically import the router file and extract a tRPC router\n * instance. Returns `null` if the import fails (e.g. no TS loader) or\n * no router export is found.\n */\nexport async function tryImportRouter(\n resolvedPath: string,\n exportName: string,\n): Promise<AnyTRPCRouter | null> {\n try {\n const mod = await import(pathToFileURL(resolvedPath).href);\n return findRouterExport(mod as Record<string, unknown>, exportName);\n } catch {\n // Dynamic import not available (no TS loader registered) — that's fine,\n // we fall back to type-checker-only schemas.\n return null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Router walker — collect descriptions per procedure\n// ---------------------------------------------------------------------------\n\n/**\n * Walk a runtime tRPC router/record and collect Zod `.describe()` strings\n * keyed by procedure path.\n */\nexport function collectRuntimeDescriptions(\n routerOrRecord: AnyTRPCRouter | TRPCRouterRecord,\n prefix: string,\n result: Map<string, RuntimeDescriptions>,\n): void {\n // Unwrap router to its record; plain RouterRecords are used as-is.\n const record: TRPCRouterRecord = isRouterInstance(routerOrRecord)\n ? routerOrRecord._def.record\n : routerOrRecord;\n\n for (const [key, value] of Object.entries(record)) {\n const fullPath = prefix ? `${prefix}.${key}` : key;\n\n if (isProcedure(value)) {\n // Procedure — extract descriptions from input and output Zod schemas\n const def = value._def;\n let inputDescs: DescriptionMap | null = null;\n for (const input of def.inputs) {\n const descs = extractZodDescriptions(input);\n if (descs) {\n // Merge multiple .input() descriptions (last wins for conflicts)\n inputDescs ??= { properties: new Map() };\n inputDescs.self = descs.self ?? inputDescs.self;\n for (const [p, d] of descs.properties) {\n inputDescs.properties.set(p, d);\n }\n }\n }\n\n let outputDescs: DescriptionMap | null = null;\n // `output` exists at runtime on the procedure def (from the builder)\n // but is not part of the public Procedure type.\n const outputParser = (def as Record<string, unknown>)['output'];\n if (outputParser) {\n outputDescs = extractZodDescriptions(outputParser);\n }\n\n if (inputDescs || outputDescs) {\n result.set(fullPath, { input: inputDescs, output: outputDescs });\n }\n } else {\n // Sub-router or nested RouterRecord — recurse\n collectRuntimeDescriptions(value, fullPath, result);\n }\n }\n}\n\n/** Type guard: check if a RouterRecord value is a procedure (callable). */\nfunction isProcedure(\n value: AnyTRPCProcedure | TRPCRouterRecord,\n): value is AnyTRPCProcedure {\n return typeof value === 'function';\n}\n\n// ---------------------------------------------------------------------------\n// Apply descriptions to JSON schemas\n// ---------------------------------------------------------------------------\n\n/**\n * Overlay description strings from a `DescriptionMap` onto an existing\n * JSON schema produced by the TypeScript type checker. Mutates in place.\n */\nexport function applyDescriptions(\n schema: SchemaObject,\n descs: DescriptionMap,\n schemas?: Record<string, SchemaObject>,\n): void {\n if (descs.self) {\n schema.description = descs.self;\n }\n\n for (const [propPath, description] of descs.properties) {\n setNestedDescription({\n schema,\n pathParts: propPath.split('.'),\n description,\n schemas,\n });\n }\n}\n\nfunction resolveSchemaRef(\n schema: SchemaObject,\n schemas?: Record<string, SchemaObject>,\n): SchemaObject | null {\n const ref = schema.$ref;\n if (!ref) {\n return schema;\n }\n if (!schemas || !ref.startsWith('#/components/schemas/')) {\n return null;\n }\n\n const refName = ref.slice('#/components/schemas/'.length);\n return refName ? (schemas[refName] ?? null) : null;\n}\n\nfunction getArrayItemsSchema(schema: SchemaObject): SchemaObject | null {\n const items = schema.items;\n if (schema.type !== 'array' || items == null || items === false) {\n return null;\n }\n return items;\n}\n\nfunction getPropertySchema(\n schema: SchemaObject,\n propertyName: string,\n): SchemaObject | null {\n return schema.properties?.[propertyName] ?? null;\n}\n\nfunction setLeafDescription(schema: SchemaObject, description: string): void {\n if (schema.$ref) {\n const ref = schema.$ref;\n delete schema.$ref;\n schema.allOf = [{ $ref: ref }, ...(schema.allOf ?? [])];\n }\n schema.description = description;\n}\n\nfunction setNestedDescription({\n schema,\n pathParts,\n description,\n schemas,\n}: {\n schema: SchemaObject;\n pathParts: string[];\n description: string;\n schemas?: Record<string, SchemaObject>;\n}): void {\n if (pathParts.length === 0) return;\n\n const [head, ...rest] = pathParts;\n if (!head) return;\n\n // `[]` means \"array items\" — navigate to the `items` sub-schema\n if (head === '[]') {\n const items = getArrayItemsSchema(schema);\n if (!items) return;\n if (rest.length === 0) {\n setLeafDescription(items, description);\n } else {\n const target = resolveSchemaRef(items, schemas) ?? items;\n setNestedDescription({\n schema: target,\n pathParts: rest,\n description,\n schemas,\n });\n }\n return;\n }\n\n const propSchema = getPropertySchema(schema, head);\n if (!propSchema) return;\n\n if (rest.length === 0) {\n // Leaf — Zod .describe() takes priority over JSDoc\n setLeafDescription(propSchema, description);\n } else {\n // For arrays, step through `items` transparently\n const target = getArrayItemsSchema(propSchema) ?? propSchema;\n const resolvedTarget = resolveSchemaRef(target, schemas) ?? target;\n setNestedDescription({\n schema: resolvedTarget,\n pathParts: rest,\n description,\n schemas,\n });\n }\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport * as ts from 'typescript';\nimport {\n applyDescriptions,\n collectRuntimeDescriptions,\n tryImportRouter,\n type RuntimeDescriptions,\n} from './schemaExtraction';\nimport type {\n Document,\n OperationObject,\n PathItemObject,\n PathsObject,\n SchemaObject,\n ServerObject,\n} from './types';\n\ninterface ProcedureInfo {\n path: string;\n type: 'query' | 'mutation' | 'subscription';\n inputSchema: SchemaObject | null;\n outputSchema: SchemaObject | null;\n description?: string;\n}\n\n/** State extracted from the router's root config. */\ninterface RouterMeta {\n errorSchema: SchemaObject | null;\n schemas?: Record<string, SchemaObject>;\n}\n\nexport interface GenerateOptions {\n /**\n * The name of the exported router symbol.\n * @default 'AppRouter'\n */\n exportName?: string;\n /** Title for the generated OpenAPI `info` object. */\n title?: string;\n /** Version string for the generated OpenAPI `info` object. */\n version?: string;\n /**\n * OpenAPI `servers` array, passed through to the generated document. Each\n * `url` should include any tRPC mount prefix, since the generated paths\n * (`/user.create`, …) are relative to it — e.g.\n * `https://api.example.com/trpc`. When omitted, no `servers` entry is added.\n */\n servers?: ServerObject[];\n}\n\n// ---------------------------------------------------------------------------\n// Flag helpers\n// ---------------------------------------------------------------------------\n\nconst PRIMITIVE_FLAGS =\n ts.TypeFlags.String |\n ts.TypeFlags.Number |\n ts.TypeFlags.Boolean |\n ts.TypeFlags.StringLiteral |\n ts.TypeFlags.NumberLiteral |\n ts.TypeFlags.BooleanLiteral;\n\nfunction hasFlag(type: ts.Type, flag: ts.TypeFlags): boolean {\n return (type.getFlags() & flag) !== 0;\n}\n\nfunction isPrimitive(type: ts.Type): boolean {\n return hasFlag(type, PRIMITIVE_FLAGS);\n}\n\nfunction isObjectType(type: ts.Type): boolean {\n return hasFlag(type, ts.TypeFlags.Object);\n}\n\nfunction isOptionalSymbol(sym: ts.Symbol): boolean {\n return (sym.flags & ts.SymbolFlags.Optional) !== 0;\n}\n\n// ---------------------------------------------------------------------------\n// JSON Schema conversion — shared state\n// ---------------------------------------------------------------------------\n\n/** Shared state threaded through the type-to-schema recursion. */\ninterface SchemaCtx {\n checker: ts.TypeChecker;\n visited: Set<ts.Type>;\n /** Collected named schemas for components/schemas. */\n schemas: Record<string, SchemaObject>;\n /** Map from TS type identity to its registered schema name. */\n typeToRef: Map<ts.Type, string>;\n}\n\n// ---------------------------------------------------------------------------\n// Brand unwrapping\n// ---------------------------------------------------------------------------\n\n/**\n * If `type` is a branded intersection (primitive & object), return just the\n * primitive part. Otherwise return the type as-is.\n */\nfunction unwrapBrand(type: ts.Type): ts.Type {\n if (!type.isIntersection()) {\n return type;\n }\n const primitives = type.types.filter(isPrimitive);\n const hasObject = type.types.some(isObjectType);\n const [first] = primitives;\n if (first && hasObject) {\n return first;\n }\n return type;\n}\n\n// ---------------------------------------------------------------------------\n// Schema naming helpers\n// ---------------------------------------------------------------------------\n\nconst ANONYMOUS_NAMES = new Set(['__type', '__object', 'Object', '']);\nconst INTERNAL_COMPUTED_PROPERTY_SYMBOL = /^__@.*@\\d+$/;\n\n/** Try to determine a meaningful name for a TS type (type alias or interface). */\nfunction getTypeName(type: ts.Type): string | null {\n const aliasName = type.aliasSymbol?.getName();\n if (aliasName && !ANONYMOUS_NAMES.has(aliasName)) {\n return aliasName;\n }\n const symName = type.getSymbol()?.getName();\n if (symName && !ANONYMOUS_NAMES.has(symName) && !symName.startsWith('__')) {\n return symName;\n }\n return null;\n}\n\n// Skips asyncGenerator and branded symbols etc when creating types\n// Symbols can't be serialised\nfunction shouldSkipPropertySymbol(prop: ts.Symbol): boolean {\n return (\n prop.declarations?.some((declaration) => {\n const declarationName = ts.getNameOfDeclaration(declaration);\n if (!declarationName || !ts.isComputedPropertyName(declarationName)) {\n return false;\n }\n\n return INTERNAL_COMPUTED_PROPERTY_SYMBOL.test(prop.getName());\n }) ?? false\n );\n}\n\nfunction getReferencedSchema(\n schema: SchemaObject | null,\n schemas: Record<string, SchemaObject>,\n): SchemaObject | null {\n const ref = schema?.$ref;\n if (!ref?.startsWith('#/components/schemas/')) {\n return schema;\n }\n\n const refName = ref.slice('#/components/schemas/'.length);\n return refName ? (schemas[refName] ?? null) : schema;\n}\n\nfunction ensureUniqueName(\n name: string,\n existing: Record<string, unknown>,\n): string {\n if (!(name in existing)) {\n return name;\n }\n let i = 2;\n while (`${name}${i}` in existing) {\n i++;\n }\n return `${name}${i}`;\n}\n\nfunction schemaRef(name: string): SchemaObject {\n return { $ref: `#/components/schemas/${name}` };\n}\n\nfunction isSelfSchemaRef(schema: SchemaObject, name: string): boolean {\n return schema.$ref === schemaRef(name).$ref;\n}\n\nfunction isNonEmptySchema(s: SchemaObject): boolean {\n for (const _ in s) return true;\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// Type → JSON Schema (with component extraction)\n// ---------------------------------------------------------------------------\n\n/**\n * Convert a TS type to a JSON Schema. If the type has been pre-registered\n * (or has a meaningful TS name), it is stored in `ctx.schemas` and a `$ref`\n * is returned instead of an inline schema.\n *\n * Named types (type aliases, interfaces) are auto-registered before conversion\n * so that recursive references (including through unions and intersections)\n * resolve to a `$ref` instead of causing infinite recursion.\n */\nfunction typeToJsonSchema(\n type: ts.Type,\n ctx: SchemaCtx,\n depth = 0,\n): SchemaObject {\n // If this type is already registered as a named schema, return a $ref.\n const existingRef = ctx.typeToRef.get(type);\n if (existingRef) {\n const storedSchema = ctx.schemas[existingRef];\n if (\n storedSchema &&\n (isNonEmptySchema(storedSchema) || ctx.visited.has(type))\n ) {\n return schemaRef(existingRef);\n }\n\n // First encounter for a pre-registered placeholder: convert once, but keep\n // returning $ref for recursive edges while the type is actively visiting.\n ctx.schemas[existingRef] = storedSchema ?? {};\n const schema = convertTypeToSchema(type, ctx, depth);\n if (!isSelfSchemaRef(schema, existingRef)) {\n ctx.schemas[existingRef] = schema;\n }\n return schemaRef(existingRef);\n }\n\n const schema = convertTypeToSchema(type, ctx, depth);\n\n // If a recursive reference was detected during conversion (via handleCyclicRef\n // or convertPlainObject's auto-registration), the type is now registered in\n // typeToRef. If the stored schema is still the empty placeholder, fill it in\n // with the actual converted schema. Either way, return a $ref.\n const postConvertRef = ctx.typeToRef.get(type);\n if (postConvertRef) {\n const stored = ctx.schemas[postConvertRef];\n if (\n stored &&\n !isNonEmptySchema(stored) &&\n !isSelfSchemaRef(schema, postConvertRef)\n ) {\n ctx.schemas[postConvertRef] = schema;\n }\n return schemaRef(postConvertRef);\n }\n\n // Extract JSDoc from type alias symbol (e.g. `/** desc */ type Foo = string`)\n if (!schema.description && !schema.$ref && type.aliasSymbol) {\n const aliasJsDoc = getJsDocComment(type.aliasSymbol, ctx.checker);\n if (aliasJsDoc) {\n schema.description = aliasJsDoc;\n }\n }\n\n return schema;\n}\n\n// ---------------------------------------------------------------------------\n// Cyclic reference handling\n// ---------------------------------------------------------------------------\n\n/**\n * When we encounter a type we're already visiting, it's recursive.\n * Register it as a named schema and return a $ref.\n */\nfunction handleCyclicRef(type: ts.Type, ctx: SchemaCtx): SchemaObject {\n let refName = ctx.typeToRef.get(type);\n if (!refName) {\n const name = getTypeName(type) ?? 'RecursiveType';\n refName = ensureUniqueName(name, ctx.schemas);\n ctx.typeToRef.set(type, refName);\n ctx.schemas[refName] = {}; // placeholder — filled by the outer call\n }\n return schemaRef(refName);\n}\n\n// ---------------------------------------------------------------------------\n// Primitive & literal type conversion\n// ---------------------------------------------------------------------------\n\nfunction convertPrimitiveOrLiteral(\n type: ts.Type,\n flags: ts.TypeFlags,\n checker: ts.TypeChecker,\n): SchemaObject | null {\n if (flags & ts.TypeFlags.String) {\n return { type: 'string' };\n }\n if (flags & ts.TypeFlags.Number) {\n return { type: 'number' };\n }\n if (flags & ts.TypeFlags.Boolean) {\n return { type: 'boolean' };\n }\n if (flags & ts.TypeFlags.Null) {\n return { type: 'null' };\n }\n if (flags & ts.TypeFlags.Undefined) {\n return {};\n }\n if (flags & ts.TypeFlags.Void) {\n return {};\n }\n if (flags & ts.TypeFlags.Any || flags & ts.TypeFlags.Unknown) {\n return {};\n }\n if (flags & ts.TypeFlags.Never) {\n return { not: {} };\n }\n if (flags & ts.TypeFlags.BigInt || flags & ts.TypeFlags.BigIntLiteral) {\n return { type: 'integer', format: 'bigint' };\n }\n\n if (flags & ts.TypeFlags.StringLiteral) {\n return { type: 'string', const: (type as ts.StringLiteralType).value };\n }\n if (flags & ts.TypeFlags.NumberLiteral) {\n return { type: 'number', const: (type as ts.NumberLiteralType).value };\n }\n if (flags & ts.TypeFlags.BooleanLiteral) {\n const isTrue = checker.typeToString(type) === 'true';\n return { type: 'boolean', const: isTrue };\n }\n\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Union type conversion\n// ---------------------------------------------------------------------------\n\nfunction convertUnionType(\n type: ts.UnionType,\n ctx: SchemaCtx,\n depth: number,\n): SchemaObject {\n const members = type.types;\n\n // Strip undefined / void members (they make the field optional, not typed)\n const defined = members.filter(\n (m) => !hasFlag(m, ts.TypeFlags.Undefined | ts.TypeFlags.Void),\n );\n if (defined.length === 0) {\n return {};\n }\n\n const hasNull = defined.some((m) => hasFlag(m, ts.TypeFlags.Null));\n const nonNull = defined.filter((m) => !hasFlag(m, ts.TypeFlags.Null));\n\n // TypeScript represents `boolean` as `true | false`. Collapse boolean\n // literal pairs back into a single boolean, even when mixed with other types.\n // e.g. `string | true | false` → treat as `string | boolean`\n const boolLiterals = nonNull.filter((m) =>\n hasFlag(unwrapBrand(m), ts.TypeFlags.BooleanLiteral),\n );\n const hasBoolPair =\n boolLiterals.length === 2 &&\n boolLiterals.some(\n (m) => ctx.checker.typeToString(unwrapBrand(m)) === 'true',\n ) &&\n boolLiterals.some(\n (m) => ctx.checker.typeToString(unwrapBrand(m)) === 'false',\n );\n\n // Build the effective non-null members, collapsing boolean literal pairs\n const effective = hasBoolPair\n ? nonNull.filter(\n (m) => !hasFlag(unwrapBrand(m), ts.TypeFlags.BooleanLiteral),\n )\n : nonNull;\n\n // Pure boolean (or boolean | null) — no other types\n if (hasBoolPair && effective.length === 0) {\n return hasNull ? { type: ['boolean', 'null'] } : { type: 'boolean' };\n }\n\n // Collapse unions of same-type literals into a single `enum` array.\n // e.g. \"FOO\" | \"BAR\" → { type: \"string\", enum: [\"FOO\", \"BAR\"] }\n const collapsedEnum = tryCollapseLiteralUnion(effective, hasNull);\n if (collapsedEnum) {\n return collapsedEnum;\n }\n\n const schemas = effective\n .map((m) => typeToJsonSchema(m, ctx, depth + 1))\n .filter(isNonEmptySchema);\n\n // Re-inject the collapsed boolean\n if (hasBoolPair) {\n schemas.push({ type: 'boolean' });\n }\n\n if (hasNull) {\n schemas.push({ type: 'null' });\n }\n\n if (schemas.length === 0) {\n return {};\n }\n\n const [firstSchema] = schemas;\n if (schemas.length === 1 && firstSchema !== undefined) {\n return firstSchema;\n }\n\n // When all schemas are simple type-only schemas (no other properties),\n // collapse into a single `type` array. e.g. string | null → type: [\"string\", \"null\"]\n if (schemas.every(isSimpleTypeSchema)) {\n return { type: schemas.map((s) => s.type as string) };\n }\n\n // Detect discriminated unions: all oneOf members are objects sharing a common\n // required property whose value is a `const`. If found, add a `discriminator`.\n const discriminatorProp = detectDiscriminatorProperty(schemas);\n if (discriminatorProp) {\n return {\n oneOf: schemas,\n discriminator: { propertyName: discriminatorProp },\n };\n }\n\n return { oneOf: schemas };\n}\n\n/**\n * If every schema in a oneOf is an object with a common required property\n * whose value is a `const`, return that property name. Otherwise return null.\n */\nfunction detectDiscriminatorProperty(schemas: SchemaObject[]): string | null {\n if (schemas.length < 2) {\n return null;\n }\n\n // All schemas must be object types with properties\n if (!schemas.every((s) => s.type === 'object' && s.properties)) {\n return null;\n }\n\n // Find properties that exist in every schema, are required, and have a `const` value\n const first = schemas[0];\n if (!first?.properties) {\n return null;\n }\n const firstProps = Object.keys(first.properties);\n for (const prop of firstProps) {\n const allHaveConst = schemas.every((s) => {\n const propSchema = s.properties?.[prop];\n return (\n propSchema !== undefined &&\n propSchema.const !== undefined &&\n s.required?.includes(prop)\n );\n });\n if (allHaveConst) {\n return prop;\n }\n }\n\n return null;\n}\n\n/** A schema that is just `{ type: \"somePrimitive\" }` with no other keys. */\nfunction isSimpleTypeSchema(s: SchemaObject): boolean {\n const keys = Object.keys(s);\n return keys.length === 1 && keys[0] === 'type' && typeof s.type === 'string';\n}\n\n/**\n * If every non-null member is a string or number literal of the same kind,\n * collapse them into a single `{ type, enum }` schema.\n */\nfunction tryCollapseLiteralUnion(\n nonNull: ts.Type[],\n hasNull: boolean,\n): SchemaObject | null {\n if (nonNull.length <= 1) {\n return null;\n }\n\n const allLiterals = nonNull.every((m) =>\n hasFlag(m, ts.TypeFlags.StringLiteral | ts.TypeFlags.NumberLiteral),\n );\n if (!allLiterals) {\n return null;\n }\n\n const [first] = nonNull;\n if (!first) {\n return null;\n }\n\n const isString = hasFlag(first, ts.TypeFlags.StringLiteral);\n const targetFlag = isString\n ? ts.TypeFlags.StringLiteral\n : ts.TypeFlags.NumberLiteral;\n const allSameKind = nonNull.every((m) => hasFlag(m, targetFlag));\n if (!allSameKind) {\n return null;\n }\n\n const values = nonNull.map((m) =>\n isString\n ? (m as ts.StringLiteralType).value\n : (m as ts.NumberLiteralType).value,\n );\n const baseType = isString ? 'string' : 'number';\n return {\n type: hasNull ? [baseType, 'null'] : baseType,\n enum: values,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Intersection type conversion\n// ---------------------------------------------------------------------------\n\nfunction convertIntersectionType(\n type: ts.IntersectionType,\n ctx: SchemaCtx,\n depth: number,\n): SchemaObject {\n // Branded types (e.g. z.string().brand<'X'>()) appear as an intersection of\n // a primitive with a phantom object. Strip the object members — they are\n // always brand metadata.\n const hasPrimitiveMember = type.types.some(isPrimitive);\n const nonBrand = hasPrimitiveMember\n ? type.types.filter((m) => !isObjectType(m))\n : type.types;\n\n const schemas = nonBrand\n .map((m) => typeToJsonSchema(m, ctx, depth + 1))\n .filter(isNonEmptySchema);\n\n if (schemas.length === 0) {\n return {};\n }\n const [onlySchema] = schemas;\n if (schemas.length === 1 && onlySchema !== undefined) {\n return onlySchema;\n }\n\n // When all members are plain inline object schemas (no $ref), merge them\n // into a single object instead of wrapping in allOf.\n if (schemas.every(isInlineObjectSchema)) {\n return mergeObjectSchemas(schemas);\n }\n\n return { allOf: schemas };\n}\n\n/** True when the schema is an inline `{ type: \"object\", ... }` (not a $ref). */\nfunction isInlineObjectSchema(s: SchemaObject): boolean {\n return s.type === 'object' && !s.$ref;\n}\n\n/**\n * Merge multiple `{ type: \"object\" }` schemas into one.\n * Falls back to `allOf` if any property names conflict across schemas.\n */\nfunction mergeObjectSchemas(schemas: SchemaObject[]): SchemaObject {\n // Check for property name conflicts before merging.\n const seen = new Set<string>();\n for (const s of schemas) {\n if (s.properties) {\n for (const prop of Object.keys(s.properties)) {\n if (seen.has(prop)) {\n // Conflicting property — fall back to allOf to preserve both definitions.\n return { allOf: schemas };\n }\n seen.add(prop);\n }\n }\n }\n\n const properties: Record<string, SchemaObject> = {};\n const required: string[] = [];\n let additionalProperties: SchemaObject | boolean | undefined;\n\n for (const s of schemas) {\n if (s.properties) {\n Object.assign(properties, s.properties);\n }\n if (s.required) {\n required.push(...s.required);\n }\n if (s.additionalProperties !== undefined) {\n additionalProperties = s.additionalProperties;\n }\n }\n\n const result: SchemaObject = { type: 'object' };\n if (Object.keys(properties).length > 0) {\n result.properties = properties;\n }\n if (required.length > 0) {\n result.required = required;\n }\n if (additionalProperties !== undefined) {\n result.additionalProperties = additionalProperties;\n }\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Object type conversion\n// ---------------------------------------------------------------------------\n\nfunction convertWellKnownType(\n type: ts.Type,\n ctx: SchemaCtx,\n depth: number,\n): SchemaObject | null {\n const symName = type.getSymbol()?.getName();\n if (symName === 'Date') {\n return { type: 'string', format: 'date-time' };\n }\n if (symName === 'Uint8Array' || symName === 'Buffer') {\n return { type: 'string', format: 'binary' };\n }\n\n // Unwrap Promise<T>\n if (symName === 'Promise') {\n const [inner] = ctx.checker.getTypeArguments(type as ts.TypeReference);\n return inner ? typeToJsonSchema(inner, ctx, depth + 1) : {};\n }\n\n return null;\n}\n\nfunction convertArrayType(\n type: ts.Type,\n ctx: SchemaCtx,\n depth: number,\n): SchemaObject {\n const [elem] = ctx.checker.getTypeArguments(type as ts.TypeReference);\n const schema: SchemaObject = { type: 'array' };\n if (elem) {\n schema.items = typeToJsonSchema(elem, ctx, depth + 1);\n }\n return schema;\n}\n\nfunction convertTupleType(\n type: ts.Type,\n ctx: SchemaCtx,\n depth: number,\n): SchemaObject {\n const args = ctx.checker.getTypeArguments(type as ts.TypeReference);\n const schemas = args.map((a) => typeToJsonSchema(a, ctx, depth + 1));\n return {\n type: 'array',\n prefixItems: schemas,\n items: false,\n minItems: args.length,\n maxItems: args.length,\n };\n}\n\nfunction convertPlainObject(\n type: ts.Type,\n ctx: SchemaCtx,\n depth: number,\n): SchemaObject {\n const { checker } = ctx;\n const stringIndexType = type.getStringIndexType();\n const typeProps = type.getProperties();\n\n // Pure index-signature Record type (no named props)\n if (typeProps.length === 0 && stringIndexType) {\n return {\n type: 'object',\n additionalProperties: typeToJsonSchema(stringIndexType, ctx, depth + 1),\n };\n }\n\n // Auto-register types with a meaningful TS name BEFORE converting\n // properties, so that circular or shared refs discovered during recursion\n // resolve to a $ref via the `typeToJsonSchema` wrapper.\n let autoRegName: string | null = null;\n const tsName = getTypeName(type);\n const isNamedUnregisteredType =\n tsName !== null && typeProps.length > 0 && !ctx.typeToRef.has(type);\n if (isNamedUnregisteredType) {\n autoRegName = ensureUniqueName(tsName, ctx.schemas);\n ctx.typeToRef.set(type, autoRegName);\n ctx.schemas[autoRegName] = {}; // placeholder for circular ref guard\n }\n\n ctx.visited.add(type);\n const properties: Record<string, SchemaObject> = {};\n const required: string[] = [];\n\n for (const prop of typeProps) {\n if (shouldSkipPropertySymbol(prop)) {\n continue;\n }\n\n const propType = checker.getTypeOfSymbol(prop);\n const propSchema = typeToJsonSchema(propType, ctx, depth + 1);\n\n // Extract JSDoc comment from the property symbol as a description\n const jsDoc = getJsDocComment(prop, checker);\n if (jsDoc && !propSchema.description && !propSchema.$ref) {\n propSchema.description = jsDoc;\n }\n\n properties[prop.name] = propSchema;\n if (!isOptionalSymbol(prop)) {\n required.push(prop.name);\n }\n }\n\n ctx.visited.delete(type);\n\n const result: SchemaObject = { type: 'object' };\n if (Object.keys(properties).length > 0) {\n result.properties = properties;\n }\n if (required.length > 0) {\n result.required = required;\n }\n if (stringIndexType) {\n result.additionalProperties = typeToJsonSchema(\n stringIndexType,\n ctx,\n depth + 1,\n );\n } else if (Object.keys(properties).length > 0) {\n result.additionalProperties = false;\n }\n\n // autoRegName covers named types (early-registered). For anonymous\n // recursive types, a recursive call may have registered this type during\n // property conversion — check typeToRef as a fallback.\n const registeredName = autoRegName ?? ctx.typeToRef.get(type);\n if (registeredName) {\n ctx.schemas[registeredName] = result;\n return schemaRef(registeredName);\n }\n\n return result;\n}\n\nfunction convertObjectType(\n type: ts.Type,\n ctx: SchemaCtx,\n depth: number,\n): SchemaObject {\n const wellKnown = convertWellKnownType(type, ctx, depth);\n if (wellKnown) {\n return wellKnown;\n }\n\n if (ctx.checker.isArrayType(type)) {\n return convertArrayType(type, ctx, depth);\n }\n if (ctx.checker.isTupleType(type)) {\n return convertTupleType(type, ctx, depth);\n }\n\n return convertPlainObject(type, ctx, depth);\n}\n\n// ---------------------------------------------------------------------------\n// Core dispatcher\n// ---------------------------------------------------------------------------\n\n/** Core type-to-schema conversion (no ref handling). */\nfunction convertTypeToSchema(\n type: ts.Type,\n ctx: SchemaCtx,\n depth: number,\n): SchemaObject {\n if (ctx.visited.has(type)) {\n return handleCyclicRef(type, ctx);\n }\n\n const flags = type.getFlags();\n\n const primitive = convertPrimitiveOrLiteral(type, flags, ctx.checker);\n if (primitive) {\n return primitive;\n }\n\n if (type.isUnion()) {\n ctx.visited.add(type);\n const result = convertUnionType(type, ctx, depth);\n ctx.visited.delete(type);\n return result;\n }\n if (type.isIntersection()) {\n ctx.visited.add(type);\n const result = convertIntersectionType(type, ctx, depth);\n ctx.visited.delete(type);\n return result;\n }\n if (isObjectType(type)) {\n return convertObjectType(type, ctx, depth);\n }\n\n return {};\n}\n\n// ---------------------------------------------------------------------------\n// Router / procedure type walker\n// ---------------------------------------------------------------------------\n\n/** State shared across the router-walk recursion. */\ninterface WalkCtx {\n procedures: ProcedureInfo[];\n seen: Set<ts.Type>;\n schemaCtx: SchemaCtx;\n /** Runtime descriptions keyed by procedure path (when a router instance is available). */\n runtimeDescriptions: Map<string, RuntimeDescriptions>;\n}\n\n/**\n * Inspect `_def.type` and return the procedure type string, or null if this is\n * not a procedure (e.g. a nested router).\n */\nfunction getProcedureTypeName(\n defType: ts.Type,\n checker: ts.TypeChecker,\n): ProcedureInfo['type'] | null {\n const typeSym = defType.getProperty('type');\n if (!typeSym) {\n return null;\n }\n const typeType = checker.getTypeOfSymbol(typeSym);\n const raw = checker.typeToString(typeType).replace(/['\"]/g, '');\n if (raw === 'query' || raw === 'mutation' || raw === 'subscription') {\n return raw;\n }\n return null;\n}\n\nfunction isVoidLikeInput(inputType: ts.Type | null): boolean {\n if (!inputType) {\n return true;\n }\n\n const isVoidOrUndefinedOrNever = hasFlag(\n inputType,\n ts.TypeFlags.Void | ts.TypeFlags.Undefined | ts.TypeFlags.Never,\n );\n if (isVoidOrUndefinedOrNever) {\n return true;\n }\n\n const isUnionOfVoids =\n inputType.isUnion() &&\n inputType.types.every((t) =>\n hasFlag(t, ts.TypeFlags.Void | ts.TypeFlags.Undefined),\n );\n return isUnionOfVoids;\n}\n\ninterface ProcedureDef {\n defType: ts.Type;\n typeName: string;\n path: string;\n description?: string;\n symbol: ts.Symbol;\n}\n\nfunction shouldIncludeProcedureInOpenAPI(type: ProcedureInfo['type']): boolean {\n return type !== 'subscription';\n}\n\nfunction getProcedureInputTypeName(type: ts.Type, path: string): string {\n const directName = getTypeName(type);\n if (directName) {\n return directName;\n }\n\n for (const sym of [type.aliasSymbol, type.getSymbol()].filter(\n (candidate): candidate is ts.Symbol => !!candidate,\n )) {\n for (const declaration of sym.declarations ?? []) {\n const declarationName = ts.getNameOfDeclaration(declaration)?.getText();\n if (\n declarationName &&\n !ANONYMOUS_NAMES.has(declarationName) &&\n !declarationName.startsWith('__')\n ) {\n return declarationName;\n }\n }\n }\n\n const fallbackName = path\n .split('.')\n .filter(Boolean)\n .map((segment) =>\n segment\n .split(/[^A-Za-z0-9]+/)\n .filter(Boolean)\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join(''),\n )\n .join('');\n\n return `${fallbackName || 'Procedure'}Input`;\n}\n\nfunction isUnknownLikeType(type: ts.Type): boolean {\n return hasFlag(type, ts.TypeFlags.Unknown | ts.TypeFlags.Any);\n}\n\nfunction isCollapsedProcedureInputType(type: ts.Type): boolean {\n return (\n isUnknownLikeType(type) ||\n (isObjectType(type) &&\n type.getProperties().length === 0 &&\n !type.getStringIndexType())\n );\n}\n\nfunction recoverProcedureInputType(\n def: ProcedureDef,\n checker: ts.TypeChecker,\n): ts.Type | null {\n let initializer: ts.Expression | null = null;\n for (const declaration of def.symbol.declarations ?? []) {\n if (ts.isPropertyAssignment(declaration)) {\n initializer = declaration.initializer;\n break;\n }\n if (ts.isVariableDeclaration(declaration) && declaration.initializer) {\n initializer = declaration.initializer;\n break;\n }\n }\n if (!initializer) {\n return null;\n }\n\n let recovered: ts.Type | null = null;\n // Walk the builder chain and keep the last `.input(...)` parser output type.\n const visit = (expr: ts.Expression): void => {\n if (!ts.isCallExpression(expr)) {\n return;\n }\n\n const callee = expr.expression;\n if (!ts.isPropertyAccessExpression(callee)) {\n return;\n }\n\n visit(callee.expression);\n if (callee.name.text !== 'input') {\n return;\n }\n\n const [parserExpr] = expr.arguments;\n if (!parserExpr) {\n return;\n }\n\n const parserType = checker.getTypeAtLocation(parserExpr);\n const standardSym = parserType.getProperty('~standard');\n if (!standardSym) {\n return;\n }\n\n const standardType = checker.getTypeOfSymbolAtLocation(\n standardSym,\n parserExpr,\n );\n const typesSym = standardType.getProperty('types');\n if (!typesSym) {\n return;\n }\n\n const typesType = checker.getNonNullableType(\n checker.getTypeOfSymbolAtLocation(typesSym, parserExpr),\n );\n const outputSym = typesType.getProperty('output');\n if (!outputSym) {\n return;\n }\n\n const outputType = checker.getTypeOfSymbolAtLocation(outputSym, parserExpr);\n if (!isUnknownLikeType(outputType)) {\n recovered = outputType;\n }\n };\n visit(initializer);\n\n return recovered;\n}\n\nfunction extractProcedure(def: ProcedureDef, ctx: WalkCtx): void {\n const { schemaCtx } = ctx;\n const { checker } = schemaCtx;\n\n const $typesSym = def.defType.getProperty('$types');\n if (!$typesSym) {\n return;\n }\n const $typesType = checker.getTypeOfSymbol($typesSym);\n\n const inputSym = $typesType.getProperty('input');\n const outputSym = $typesType.getProperty('output');\n\n const inputType = inputSym ? checker.getTypeOfSymbol(inputSym) : null;\n const outputType = outputSym ? checker.getTypeOfSymbol(outputSym) : null;\n const resolvedInputType =\n inputType && isCollapsedProcedureInputType(inputType)\n ? (recoverProcedureInputType(def, checker) ?? inputType)\n : inputType;\n\n let inputSchema: SchemaObject | null = null;\n if (!resolvedInputType || isVoidLikeInput(resolvedInputType)) {\n // null is fine\n } else {\n // Pre-register recovered parser output types so recursive edges resolve to a\n // stable component ref instead of collapsing into `{}`.\n const ensureRecoveredInputRegistration = (type: ts.Type): void => {\n if (schemaCtx.typeToRef.has(type)) {\n return;\n }\n\n const refName = ensureUniqueName(\n getProcedureInputTypeName(type, def.path),\n schemaCtx.schemas,\n );\n schemaCtx.typeToRef.set(type, refName);\n schemaCtx.schemas[refName] = {};\n };\n\n if (resolvedInputType !== inputType) {\n ensureRecoveredInputRegistration(resolvedInputType);\n }\n\n const initialSchema = typeToJsonSchema(resolvedInputType, schemaCtx);\n if (\n !isNonEmptySchema(initialSchema) &&\n !schemaCtx.typeToRef.has(resolvedInputType)\n ) {\n ensureRecoveredInputRegistration(resolvedInputType);\n inputSchema = typeToJsonSchema(resolvedInputType, schemaCtx);\n } else {\n inputSchema = initialSchema;\n }\n }\n\n const outputSchema: SchemaObject | null = outputType\n ? typeToJsonSchema(outputType, schemaCtx)\n : null;\n\n // Overlay extracted schema descriptions onto the type-checker-generated schemas.\n const runtimeDescs = ctx.runtimeDescriptions.get(def.path);\n if (runtimeDescs) {\n const resolvedInputSchema = getReferencedSchema(\n inputSchema,\n schemaCtx.schemas,\n );\n const resolvedOutputSchema = getReferencedSchema(\n outputSchema,\n schemaCtx.schemas,\n );\n\n if (resolvedInputSchema && runtimeDescs.input) {\n applyDescriptions(\n resolvedInputSchema,\n runtimeDescs.input,\n schemaCtx.schemas,\n );\n }\n if (resolvedOutputSchema && runtimeDescs.output) {\n applyDescriptions(\n resolvedOutputSchema,\n runtimeDescs.output,\n schemaCtx.schemas,\n );\n }\n }\n\n ctx.procedures.push({\n path: def.path,\n type: def.typeName as 'query' | 'mutation' | 'subscription',\n inputSchema,\n outputSchema,\n description: def.description,\n });\n}\n\n/** Extract the JSDoc comment text from a symbol, if any. */\nfunction getJsDocComment(\n sym: ts.Symbol,\n checker: ts.TypeChecker,\n): string | undefined {\n const normalize = (filePath: string): string => filePath.replace(/\\\\/g, '/');\n\n const declarations = sym.declarations ?? [];\n const isExternalNodeModulesDeclaration =\n declarations.length > 0 &&\n declarations.every((declaration) => {\n const sourceFile = declaration.getSourceFile();\n if (!sourceFile.isDeclarationFile) {\n return false;\n }\n\n const declarationPath = normalize(sourceFile.fileName);\n if (!declarationPath.includes('/node_modules/')) {\n return false;\n }\n\n try {\n const realPath = normalize(fs.realpathSync.native(sourceFile.fileName));\n // Keep JSDoc for workspace packages linked into node_modules\n // (e.g. monorepos using pnpm/yarn workspaces). The resolved target\n // may sit outside the current cwd, so avoid cwd-based checks here.\n if (!realPath.includes('/node_modules/')) {\n return false;\n }\n } catch {\n // Fall back to treating the declaration as external.\n }\n\n return true;\n });\n if (isExternalNodeModulesDeclaration) {\n return undefined;\n }\n\n const parts = sym.getDocumentationComment(checker);\n if (parts.length === 0) {\n return undefined;\n }\n const text = parts.map((p) => p.text).join('');\n return text || undefined;\n}\n\ninterface WalkTypeOpts {\n type: ts.Type;\n ctx: WalkCtx;\n currentPath: string;\n description?: string;\n symbol?: ts.Symbol;\n}\n\nfunction walkType(opts: WalkTypeOpts): void {\n const { type, ctx, currentPath, description, symbol } = opts;\n if (ctx.seen.has(type)) {\n return;\n }\n\n const defSym = type.getProperty('_def');\n\n if (!defSym) {\n // No `_def` — this is a plain RouterRecord or an unrecognised type.\n // Walk its own properties so nested procedures are found.\n if (isObjectType(type)) {\n ctx.seen.add(type);\n walkRecord(type, ctx, currentPath);\n ctx.seen.delete(type);\n }\n return;\n }\n\n const { checker } = ctx.schemaCtx;\n const defType = checker.getTypeOfSymbol(defSym);\n\n const procedureTypeName = getProcedureTypeName(defType, checker);\n if (procedureTypeName) {\n if (!shouldIncludeProcedureInOpenAPI(procedureTypeName)) {\n return;\n }\n\n extractProcedure(\n {\n defType,\n typeName: procedureTypeName,\n path: currentPath,\n description,\n symbol: symbol ?? type.getSymbol() ?? defSym,\n },\n ctx,\n );\n return;\n }\n\n // Router? (_def.router === true)\n const routerSym = defType.getProperty('router');\n if (!routerSym) {\n return;\n }\n\n const isRouter =\n checker.typeToString(checker.getTypeOfSymbol(routerSym)) === 'true';\n if (!isRouter) {\n return;\n }\n\n const recordSym = defType.getProperty('record');\n if (!recordSym) {\n return;\n }\n\n ctx.seen.add(type);\n const recordType = checker.getTypeOfSymbol(recordSym);\n walkRecord(recordType, ctx, currentPath);\n ctx.seen.delete(type);\n}\n\nfunction walkRecord(recordType: ts.Type, ctx: WalkCtx, prefix: string): void {\n for (const prop of recordType.getProperties()) {\n const propType = ctx.schemaCtx.checker.getTypeOfSymbol(prop);\n const fullPath = prefix ? `${prefix}.${prop.name}` : prop.name;\n const description = getJsDocComment(prop, ctx.schemaCtx.checker);\n walkType({\n type: propType,\n ctx,\n currentPath: fullPath,\n description,\n symbol: prop,\n });\n }\n}\n\n// ---------------------------------------------------------------------------\n// TypeScript program helpers\n// ---------------------------------------------------------------------------\n\nfunction loadCompilerOptions(startDir: string): ts.CompilerOptions {\n const configPath = ts.findConfigFile(\n startDir,\n (f) => ts.sys.fileExists(f),\n 'tsconfig.json',\n );\n if (!configPath) {\n return {\n target: ts.ScriptTarget.ES2020,\n moduleResolution: ts.ModuleResolutionKind.Bundler,\n skipLibCheck: true,\n noEmit: true,\n };\n }\n\n const configFile = ts.readConfigFile(configPath, (f) => ts.sys.readFile(f));\n const parsed = ts.parseJsonConfigFileContent(\n configFile.config,\n ts.sys,\n path.dirname(configPath),\n );\n const options: ts.CompilerOptions = { ...parsed.options, noEmit: true };\n\n // `parseJsonConfigFileContent` only returns explicitly-set values. TypeScript\n // itself infers moduleResolution from `module` at compile time, but we have to\n // do it manually here for the compiler host to resolve imports correctly.\n if (options.moduleResolution === undefined) {\n const mod = options.module;\n if (mod === ts.ModuleKind.Node16 || mod === ts.ModuleKind.NodeNext) {\n options.moduleResolution = ts.ModuleResolutionKind.NodeNext;\n } else if (\n mod === ts.ModuleKind.Preserve ||\n mod === ts.ModuleKind.ES2022 ||\n mod === ts.ModuleKind.ESNext\n ) {\n options.moduleResolution = ts.ModuleResolutionKind.Bundler;\n } else {\n options.moduleResolution = ts.ModuleResolutionKind.Node10;\n }\n }\n\n return options;\n}\n\n// ---------------------------------------------------------------------------\n// Error shape extraction\n// ---------------------------------------------------------------------------\n\n/**\n * Walk `_def._config.$types.errorShape` on the router type and convert\n * it to a JSON Schema. Returns `null` when the path cannot be resolved\n * (e.g. older tRPC versions or missing type info).\n */\nfunction extractErrorSchema(\n routerType: ts.Type,\n checker: ts.TypeChecker,\n schemaCtx: SchemaCtx,\n): SchemaObject | null {\n const walk = (type: ts.Type, keys: string[]): ts.Type | null => {\n const [head, ...rest] = keys;\n if (!head) {\n return type;\n }\n const sym = type.getProperty(head);\n if (!sym) {\n return null;\n }\n return walk(checker.getTypeOfSymbol(sym), rest);\n };\n\n const errorShapeType = walk(routerType, [\n '_def',\n '_config',\n '$types',\n 'errorShape',\n ]);\n if (!errorShapeType) {\n return null;\n }\n\n if (hasFlag(errorShapeType, ts.TypeFlags.Any)) {\n return null;\n }\n\n return typeToJsonSchema(errorShapeType, schemaCtx);\n}\n\n// ---------------------------------------------------------------------------\n// OpenAPI document builder\n// ---------------------------------------------------------------------------\n\n/** Fallback error schema when the router type doesn't expose an error shape. */\nconst DEFAULT_ERROR_SCHEMA: SchemaObject = {\n type: 'object',\n properties: {\n message: { type: 'string' },\n code: { type: 'string' },\n data: { type: 'object' },\n },\n required: ['message', 'code'],\n};\n\n/**\n * Wrap a procedure's output schema in the tRPC success envelope.\n *\n * tRPC HTTP responses are always serialised as:\n * `{ result: { data: T } }`\n *\n * When the procedure has no output the envelope is still present but\n * the `data` property is omitted.\n */\nfunction wrapInSuccessEnvelope(\n outputSchema: SchemaObject | null,\n): SchemaObject {\n const hasOutput = outputSchema !== null && isNonEmptySchema(outputSchema);\n const resultSchema: SchemaObject = {\n type: 'object',\n properties: {\n ...(hasOutput ? { data: outputSchema } : {}),\n },\n ...(hasOutput ? { required: ['data'] } : {}),\n };\n return {\n type: 'object',\n properties: {\n result: resultSchema,\n },\n required: ['result'],\n };\n}\n\nfunction buildProcedureOperation(\n proc: ProcedureInfo,\n method: 'get' | 'post',\n): OperationObject {\n const [tag = proc.path] = proc.path.split('.');\n const operation: OperationObject = {\n operationId: proc.path,\n ...(proc.description ? { description: proc.description } : {}),\n tags: [tag],\n responses: {\n '200': {\n description: 'Successful response',\n content: {\n 'application/json': {\n schema: wrapInSuccessEnvelope(proc.outputSchema),\n },\n },\n },\n default: { $ref: '#/components/responses/Error' },\n },\n };\n\n if (proc.inputSchema === null) {\n return operation;\n }\n\n if (method === 'get') {\n operation.parameters = [\n {\n name: 'input',\n in: 'query',\n required: true,\n // FIXME: OAS 3.1.1 says a parameter MUST use either schema+style OR content, not both.\n // style should be removed here, but hey-api requires it to generate a correct query serializer.\n style: 'deepObject',\n content: { 'application/json': { schema: proc.inputSchema } },\n },\n ];\n } else {\n operation.requestBody = {\n required: true,\n content: { 'application/json': { schema: proc.inputSchema } },\n };\n }\n\n return operation;\n}\n\nfunction buildOpenAPIDocument(\n procedures: ProcedureInfo[],\n options: GenerateOptions,\n meta: RouterMeta = { errorSchema: null },\n): Document {\n const paths: PathsObject = {};\n\n for (const proc of procedures) {\n if (!shouldIncludeProcedureInOpenAPI(proc.type)) {\n continue;\n }\n\n const opPath = `/${proc.path}`;\n const method = proc.type === 'query' ? 'get' : 'post';\n\n const pathItem: PathItemObject = paths[opPath] ?? {};\n paths[opPath] = pathItem;\n pathItem[method] = buildProcedureOperation(\n proc,\n method,\n ) as PathItemObject[typeof method];\n }\n\n const hasNamedSchemas =\n meta.schemas !== undefined && Object.keys(meta.schemas).length > 0;\n\n return {\n openapi: '3.1.1',\n jsonSchemaDialect: 'https://spec.openapis.org/oas/3.1/dialect/base',\n info: {\n title: options.title ?? 'tRPC API',\n version: options.version ?? '0.0.0',\n },\n ...(options.servers?.length ? { servers: options.servers } : {}),\n paths,\n components: {\n ...(hasNamedSchemas && meta.schemas ? { schemas: meta.schemas } : {}),\n responses: {\n Error: {\n description: 'Error response',\n content: {\n 'application/json': {\n schema: {\n type: 'object',\n properties: {\n error: meta.errorSchema ?? DEFAULT_ERROR_SCHEMA,\n },\n required: ['error'],\n },\n },\n },\n },\n },\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Analyse the given TypeScript router file using the TypeScript compiler and\n * return an OpenAPI 3.1 document describing all query and mutation procedures.\n *\n * @param routerFilePath - Absolute or relative path to the file that exports\n * the AppRouter.\n * @param options - Optional generation settings (export name, title, version).\n */\nexport async function generateOpenAPIDocument(\n routerFilePath: string,\n options: GenerateOptions = {},\n): Promise<Document> {\n const resolvedPath = path.resolve(routerFilePath);\n const exportName = options.exportName ?? 'AppRouter';\n\n const compilerOptions = loadCompilerOptions(path.dirname(resolvedPath));\n const program = ts.createProgram([resolvedPath], compilerOptions);\n const checker = program.getTypeChecker();\n const sourceFile = program.getSourceFile(resolvedPath);\n\n if (!sourceFile) {\n throw new Error(`Could not load TypeScript file: ${resolvedPath}`);\n }\n\n const moduleSymbol = checker.getSymbolAtLocation(sourceFile);\n if (!moduleSymbol) {\n throw new Error(`No module exports found in: ${resolvedPath}`);\n }\n\n const tsExports = checker.getExportsOfModule(moduleSymbol);\n const routerSymbol = tsExports.find((sym) => sym.getName() === exportName);\n\n if (!routerSymbol) {\n const available = tsExports.map((e) => e.getName()).join(', ');\n throw new Error(\n `No export named '${exportName}' found in: ${resolvedPath}\\n` +\n `Available exports: ${available || '(none)'}`,\n );\n }\n\n // Prefer the value declaration for value exports; fall back to the declared\n // type for `export type AppRouter = …` aliases.\n let routerType: ts.Type;\n if (routerSymbol.valueDeclaration) {\n routerType = checker.getTypeOfSymbolAtLocation(\n routerSymbol,\n routerSymbol.valueDeclaration,\n );\n } else {\n routerType = checker.getDeclaredTypeOfSymbol(routerSymbol);\n }\n\n const schemaCtx: SchemaCtx = {\n checker,\n visited: new Set(),\n schemas: {},\n typeToRef: new Map(),\n };\n\n // Try to dynamically import the router to extract schema descriptions\n const runtimeDescriptions = new Map<string, RuntimeDescriptions>();\n const router = await tryImportRouter(resolvedPath, exportName);\n if (router) {\n collectRuntimeDescriptions(router, '', runtimeDescriptions);\n }\n\n const walkCtx: WalkCtx = {\n procedures: [],\n seen: new Set(),\n schemaCtx,\n runtimeDescriptions,\n };\n walkType({ type: routerType, ctx: walkCtx, currentPath: '' });\n\n const errorSchema = extractErrorSchema(routerType, checker, schemaCtx);\n return buildOpenAPIDocument(walkCtx.procedures, options, {\n errorSchema,\n schemas: schemaCtx.schemas,\n });\n}\n","import type { OpenAPIV3_1 as BaseOpenAPIV3_1 } from 'openapi-types';\n\nexport type Replace<TTarget, TReplaceWith> = Omit<TTarget, keyof TReplaceWith> &\n TReplaceWith;\n\nexport type SchemaType =\n | 'array'\n | 'boolean'\n | 'integer'\n | 'null'\n | 'number'\n | 'object'\n | 'string';\n\nexport type PrimitiveSchemaType = SchemaType;\n\nexport type HttpMethods = BaseOpenAPIV3_1.HttpMethods;\nexport type ReferenceObject = BaseOpenAPIV3_1.ReferenceObject;\nexport type ExampleObject = BaseOpenAPIV3_1.ExampleObject;\nexport type DiscriminatorObject = BaseOpenAPIV3_1.DiscriminatorObject;\nexport type ExternalDocumentationObject =\n BaseOpenAPIV3_1.ExternalDocumentationObject;\nexport type XMLObject = BaseOpenAPIV3_1.XMLObject;\nexport type LinkObject = BaseOpenAPIV3_1.LinkObject;\nexport type SecuritySchemeObject = BaseOpenAPIV3_1.SecuritySchemeObject;\nexport type ServerObject = BaseOpenAPIV3_1.ServerObject;\n\nexport type SchemaObject = Replace<\n BaseOpenAPIV3_1.BaseSchemaObject,\n {\n $ref?: string;\n $defs?: Record<string, SchemaObject>;\n $schema?: string;\n type?: string | string[];\n properties?: Record<string, SchemaObject>;\n required?: string[];\n items?: SchemaObject | false;\n prefixItems?: SchemaObject[];\n const?: string | number | boolean | null;\n enum?: (string | number | boolean | null)[];\n oneOf?: SchemaObject[];\n anyOf?: SchemaObject[];\n allOf?: SchemaObject[];\n not?: SchemaObject;\n additionalProperties?: boolean | SchemaObject;\n discriminator?: DiscriminatorObject;\n externalDocs?: ExternalDocumentationObject;\n xml?: XMLObject;\n contentMediaType?: string;\n exclusiveMinimum?: boolean | number;\n exclusiveMaximum?: boolean | number;\n }\n>;\n\nexport type SchemaLike = SchemaObject;\n\nexport interface ArraySchemaObject extends SchemaObject {\n type: 'array';\n items: SchemaObject | false;\n}\n\nexport type MediaTypeObject = Replace<\n BaseOpenAPIV3_1.MediaTypeObject,\n {\n schema?: SchemaObject | ReferenceObject;\n examples?: Record<string, ReferenceObject | ExampleObject>;\n }\n>;\n\nexport interface ParameterBaseObject\n extends Replace<\n BaseOpenAPIV3_1.ParameterBaseObject,\n {\n schema?: SchemaObject | ReferenceObject;\n examples?: Record<string, ReferenceObject | ExampleObject>;\n content?: Record<string, MediaTypeObject>;\n }\n > {}\n\nexport interface ParameterObject extends ParameterBaseObject {\n name: string;\n in: string;\n}\n\nexport type HeaderObject = ParameterBaseObject;\n\nexport type RequestBodyObject = Replace<\n BaseOpenAPIV3_1.RequestBodyObject,\n {\n content: Record<string, MediaTypeObject>;\n }\n>;\n\nexport type ResponseObject = Replace<\n BaseOpenAPIV3_1.ResponseObject,\n {\n headers?: Record<string, ReferenceObject | HeaderObject>;\n content?: Record<string, MediaTypeObject>;\n links?: Record<string, ReferenceObject | LinkObject>;\n }\n>;\n\nexport type ResponsesObject = Record<string, ReferenceObject | ResponseObject>;\n\nexport type OperationObject<T extends {} = {}> = Replace<\n BaseOpenAPIV3_1.OperationObject<T>,\n {\n parameters?: (ReferenceObject | ParameterObject)[];\n requestBody?: ReferenceObject | RequestBodyObject;\n responses?: ResponsesObject;\n callbacks?: Record<string, ReferenceObject | CallbackObject>;\n }\n> &\n T;\n\nexport type PathItemObject<T extends {} = {}> = Replace<\n BaseOpenAPIV3_1.PathItemObject<T>,\n {\n parameters?: (ReferenceObject | ParameterObject)[];\n }\n> & {\n [method in HttpMethods]?: OperationObject<T>;\n};\n\nexport type PathsObject<T extends {} = {}, TPath extends {} = {}> = Record<\n string,\n (PathItemObject<T> & TPath) | undefined\n>;\n\nexport type CallbackObject = Record<string, PathItemObject | ReferenceObject>;\n\nexport type ComponentsObject = Replace<\n BaseOpenAPIV3_1.ComponentsObject,\n {\n schemas?: Record<string, SchemaObject>;\n responses?: Record<string, ReferenceObject | ResponseObject>;\n parameters?: Record<string, ReferenceObject | ParameterObject>;\n requestBodies?: Record<string, ReferenceObject | RequestBodyObject>;\n headers?: Record<string, ReferenceObject | HeaderObject>;\n links?: Record<string, ReferenceObject | LinkObject>;\n callbacks?: Record<string, ReferenceObject | CallbackObject>;\n pathItems?: Record<string, ReferenceObject | PathItemObject>;\n }\n>;\n\nexport type Document<T extends {} = {}> = Replace<\n BaseOpenAPIV3_1.Document<T>,\n {\n paths?: PathsObject<T>;\n components?: ComponentsObject;\n }\n>;\n"],"mappings":"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"}