@kubb/ast
Advanced tools
Sorry, the diff of this file is too big to display
| import "./chunk-C0LytTxp.js"; | ||
| //#region src/constants.ts | ||
| const visitorDepths = { | ||
| shallow: "shallow", | ||
| deep: "deep" | ||
| }; | ||
| /** | ||
| * Schema type discriminators used by all AST schema nodes. | ||
| * | ||
| * These values serve as stable discriminators across the AST (e.g., `schema.type === schemaTypes.object`). | ||
| * Grouped by category: primitives (`string`, `number`, `boolean`), structural types (`object`, `array`, `union`), | ||
| * and format-specific types (`date`, `uuid`, `email`). Use `isScalarPrimitive()` to check for scalar types. | ||
| */ | ||
| const schemaTypes = { | ||
| /** | ||
| * Text value. | ||
| */ | ||
| string: "string", | ||
| /** | ||
| * Floating-point number (`float`, `double`). | ||
| */ | ||
| number: "number", | ||
| /** | ||
| * Whole number (`int32`). Use `bigint` for `int64`. | ||
| */ | ||
| integer: "integer", | ||
| /** | ||
| * 64-bit integer (`int64`). Only used when `integerType` is set to `'bigint'`. | ||
| */ | ||
| bigint: "bigint", | ||
| /** | ||
| * Boolean value | ||
| */ | ||
| boolean: "boolean", | ||
| /** | ||
| * Explicit null value. | ||
| */ | ||
| null: "null", | ||
| /** | ||
| * Any value (no type restriction). | ||
| */ | ||
| any: "any", | ||
| /** | ||
| * Unknown value (must be narrowed before usage). | ||
| */ | ||
| unknown: "unknown", | ||
| /** | ||
| * No return value (`void`). | ||
| */ | ||
| void: "void", | ||
| /** | ||
| * Object with named properties. | ||
| */ | ||
| object: "object", | ||
| /** | ||
| * Sequential list of items. | ||
| */ | ||
| array: "array", | ||
| /** | ||
| * Fixed-length list with position-specific items. | ||
| */ | ||
| tuple: "tuple", | ||
| /** | ||
| * "One of" multiple schema members. | ||
| */ | ||
| union: "union", | ||
| /** | ||
| * "All of" multiple schema members. | ||
| */ | ||
| intersection: "intersection", | ||
| /** | ||
| * Enum schema. | ||
| */ | ||
| enum: "enum", | ||
| /** | ||
| * Reference to another schema. | ||
| */ | ||
| ref: "ref", | ||
| /** | ||
| * Calendar date (for example `2026-03-24`). | ||
| */ | ||
| date: "date", | ||
| /** | ||
| * Date-time value (for example `2026-03-24T09:00:00Z`). | ||
| */ | ||
| datetime: "datetime", | ||
| /** | ||
| * Time-only value (for example `09:00:00`). | ||
| */ | ||
| time: "time", | ||
| /** | ||
| * UUID value. | ||
| */ | ||
| uuid: "uuid", | ||
| /** | ||
| * Email address value. | ||
| */ | ||
| email: "email", | ||
| /** | ||
| * URL value. | ||
| */ | ||
| url: "url", | ||
| /** | ||
| * IPv4 address value. | ||
| */ | ||
| ipv4: "ipv4", | ||
| /** | ||
| * IPv6 address value. | ||
| */ | ||
| ipv6: "ipv6", | ||
| /** | ||
| * Binary/blob value. | ||
| */ | ||
| blob: "blob", | ||
| /** | ||
| * Impossible value (`never`). | ||
| */ | ||
| never: "never" | ||
| }; | ||
| /** | ||
| * Scalar primitive schema types used for union simplification and type narrowing. | ||
| * | ||
| * Use `isScalarPrimitive()` to safely check whether a type is a scalar primitive. | ||
| */ | ||
| const SCALAR_PRIMITIVE_TYPES = new Set([ | ||
| "string", | ||
| "number", | ||
| "integer", | ||
| "bigint", | ||
| "boolean" | ||
| ]); | ||
| /** | ||
| * Type guard that returns `true` when `type` is a scalar primitive schema type. | ||
| * | ||
| * Use this to check if a schema type can be directly assigned without wrapping (e.g., `string | number | boolean`). | ||
| */ | ||
| function isScalarPrimitive(type) { | ||
| return SCALAR_PRIMITIVE_TYPES.has(type); | ||
| } | ||
| /** | ||
| * HTTP method identifiers used by operation nodes. | ||
| * | ||
| * Includes all standard HTTP methods (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, TRACE). | ||
| */ | ||
| const httpMethods = { | ||
| get: "GET", | ||
| post: "POST", | ||
| put: "PUT", | ||
| patch: "PATCH", | ||
| delete: "DELETE", | ||
| head: "HEAD", | ||
| options: "OPTIONS", | ||
| trace: "TRACE" | ||
| }; | ||
| /** | ||
| * One indentation level, derived from {@link INDENT_SIZE}. | ||
| */ | ||
| const INDENT = Array.from({ length: 2 }, () => " ").join(""); | ||
| //#endregion | ||
| //#region ../../internals/utils/src/casing.ts | ||
| /** | ||
| * Shared implementation for camelCase and PascalCase conversion. | ||
| * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons) | ||
| * and capitalizes each word according to `pascal`. | ||
| * | ||
| * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are. | ||
| */ | ||
| function toCamelOrPascal(text, pascal) { | ||
| return text.trim().replace(/([a-z\d])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/(\d)([a-z])/g, "$1 $2").split(/[\s\-_./\\:]+/).filter(Boolean).map((word, i) => { | ||
| if (word.length > 1 && word === word.toUpperCase()) return word; | ||
| return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1); | ||
| }).join("").replace(/[^a-zA-Z0-9]/g, ""); | ||
| } | ||
| /** | ||
| * Converts `text` to camelCase. | ||
| * | ||
| * @example Word boundaries | ||
| * `camelCase('hello-world') // 'helloWorld'` | ||
| * | ||
| * @example With a prefix | ||
| * `camelCase('tag', { prefix: 'create' }) // 'createTag'` | ||
| */ | ||
| function camelCase(text, { prefix = "", suffix = "" } = {}) { | ||
| return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false); | ||
| } | ||
| /** | ||
| * Converts `text` to PascalCase. | ||
| * | ||
| * @example Word boundaries | ||
| * `pascalCase('hello-world') // 'HelloWorld'` | ||
| * | ||
| * @example With a suffix | ||
| * `pascalCase('tag', { suffix: 'schema' }) // 'TagSchema'` | ||
| */ | ||
| function pascalCase(text, { prefix = "", suffix = "" } = {}) { | ||
| return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true); | ||
| } | ||
| //#endregion | ||
| //#region ../../internals/utils/src/reserved.ts | ||
| /** | ||
| * JavaScript and Java reserved words. | ||
| * @link https://github.com/jonschlinkert/reserved/blob/master/index.js | ||
| */ | ||
| const reservedWords = new Set([ | ||
| "abstract", | ||
| "arguments", | ||
| "boolean", | ||
| "break", | ||
| "byte", | ||
| "case", | ||
| "catch", | ||
| "char", | ||
| "class", | ||
| "const", | ||
| "continue", | ||
| "debugger", | ||
| "default", | ||
| "delete", | ||
| "do", | ||
| "double", | ||
| "else", | ||
| "enum", | ||
| "eval", | ||
| "export", | ||
| "extends", | ||
| "false", | ||
| "final", | ||
| "finally", | ||
| "float", | ||
| "for", | ||
| "function", | ||
| "goto", | ||
| "if", | ||
| "implements", | ||
| "import", | ||
| "in", | ||
| "instanceof", | ||
| "int", | ||
| "interface", | ||
| "let", | ||
| "long", | ||
| "native", | ||
| "new", | ||
| "null", | ||
| "package", | ||
| "private", | ||
| "protected", | ||
| "public", | ||
| "return", | ||
| "short", | ||
| "static", | ||
| "super", | ||
| "switch", | ||
| "synchronized", | ||
| "this", | ||
| "throw", | ||
| "throws", | ||
| "transient", | ||
| "true", | ||
| "try", | ||
| "typeof", | ||
| "var", | ||
| "void", | ||
| "volatile", | ||
| "while", | ||
| "with", | ||
| "yield", | ||
| "Array", | ||
| "Date", | ||
| "hasOwnProperty", | ||
| "Infinity", | ||
| "isFinite", | ||
| "isNaN", | ||
| "isPrototypeOf", | ||
| "length", | ||
| "Math", | ||
| "name", | ||
| "NaN", | ||
| "Number", | ||
| "Object", | ||
| "prototype", | ||
| "String", | ||
| "toString", | ||
| "undefined", | ||
| "valueOf" | ||
| ]); | ||
| /** | ||
| * Returns `true` when `name` is a syntactically valid JavaScript variable name. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * isValidVarName('status') // true | ||
| * isValidVarName('class') // false (reserved word) | ||
| * isValidVarName('42foo') // false (starts with digit) | ||
| * ``` | ||
| */ | ||
| function isValidVarName(name) { | ||
| if (!name || reservedWords.has(name)) return false; | ||
| return isIdentifier(name); | ||
| } | ||
| /** | ||
| * Returns `true` when `name` is syntactically a valid identifier, ignoring reserved words. | ||
| * | ||
| * Reserved words and globals (`class`, `name`, `Date`, …) are valid as bare object-literal keys | ||
| * even though they are not valid variable names, so use this (not {@link isValidVarName}) when | ||
| * deciding whether an object key needs quoting. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * isIdentifier('name') // true | ||
| * isIdentifier('x-total')// false | ||
| * ``` | ||
| */ | ||
| function isIdentifier(name) { | ||
| return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name); | ||
| } | ||
| //#endregion | ||
| //#region ../../internals/utils/src/string.ts | ||
| /** | ||
| * Wraps a value in single quotes for emitting a single-quoted JavaScript string literal, escaping | ||
| * any backslash or single quote in the content. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * singleQuote('foo') // "'foo'" | ||
| * singleQuote("o'clock") // "'o\\'clock'" | ||
| * ``` | ||
| */ | ||
| function singleQuote(value) { | ||
| if (value === void 0 || value === null) return "''"; | ||
| return `'${String(value).replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`; | ||
| } | ||
| //#endregion | ||
| //#region src/utils/index.ts | ||
| /** | ||
| * Strips a single matching pair of `"..."`, `'...'`, or `` `...` `` from both ends of `text`. | ||
| * Returns the string unchanged when no balanced quote pair is found. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * trimQuotes('"hello"') // 'hello' | ||
| * trimQuotes('hello') // 'hello' | ||
| * ``` | ||
| */ | ||
| function trimQuotes(text) { | ||
| if (text.length >= 2) { | ||
| const first = text[0]; | ||
| const last = text[text.length - 1]; | ||
| if (first === "\"" && last === "\"" || first === "'" && last === "'" || first === "`" && last === "`") return text.slice(1, -1); | ||
| } | ||
| return text; | ||
| } | ||
| /** | ||
| * Serializes a primitive value to a single-quoted string literal, stripping any surrounding quote | ||
| * characters first. Escaping comes from `JSON.stringify`, then the quote style switches to single | ||
| * quotes so generated code matches the repo style without a formatter. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * stringify('hello') // "'hello'" | ||
| * stringify('"hello"') // "'hello'" | ||
| * ``` | ||
| */ | ||
| function stringify(value) { | ||
| if (value === void 0 || value === null) return "''"; | ||
| return `'${JSON.stringify(trimQuotes(value.toString())).slice(1, -1).replace(/\\"/g, "\"").replace(/'/g, "\\'")}'`; | ||
| } | ||
| /** | ||
| * Escapes characters that are not allowed inside JS string literals, covering quotes, backslashes, | ||
| * and the Unicode line terminators U+2028 and U+2029. | ||
| * | ||
| * @see http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.4 | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * jsStringEscape('say "hi"\nbye') // 'say \\"hi\\"\\nbye' | ||
| * ``` | ||
| */ | ||
| function jsStringEscape(input) { | ||
| return `${input}`.replace(/["'\\\n\r\u2028\u2029]/g, (character) => { | ||
| switch (character) { | ||
| case "\"": | ||
| case "'": | ||
| case "\\": return `\\${character}`; | ||
| case "\n": return "\\n"; | ||
| case "\r": return "\\r"; | ||
| case "\u2028": return "\\u2028"; | ||
| case "\u2029": return "\\u2029"; | ||
| default: return ""; | ||
| } | ||
| }); | ||
| } | ||
| /** | ||
| * Converts a pattern string into a `new RegExp(...)` constructor call or a regex literal string. | ||
| * Inline flags expressed as a `^(?im)` prefix are extracted and applied to the resulting expression. | ||
| * Pass `null` as the second argument to emit a `/pattern/flags` literal instead. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * toRegExpString('^(?im)foo') // 'new RegExp("^foo", "im")' | ||
| * toRegExpString('^(?im)foo', null) // '/^foo/im' | ||
| * ``` | ||
| */ | ||
| function toRegExpString(text, func = "RegExp") { | ||
| const raw = trimQuotes(text); | ||
| const match = raw.match(/^\^(\(\?([igmsuy]+)\))/i); | ||
| const replacementTarget = match?.[1] ?? ""; | ||
| const matchedFlags = match?.[2]; | ||
| const cleaned = raw.replace(/^\\?\//, "").replace(/\\?\/$/, "").replace(replacementTarget, ""); | ||
| const { source, flags } = new RegExp(cleaned, matchedFlags); | ||
| if (func === null) return `/${source}/${flags}`; | ||
| return `new ${func}(${JSON.stringify(source)}${flags ? `, ${JSON.stringify(flags)}` : ""})`; | ||
| } | ||
| /** | ||
| * Renders a plain object as multi-line `key: value` source for embedding in generated code. Nested | ||
| * objects recurse with fixed indentation, so the result drops straight into an object literal | ||
| * without re-parsing. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * stringifyObject({ foo: 'bar', nested: { a: 1 } }) | ||
| * // 'foo: bar,\nnested: {\n a: 1\n }' | ||
| * ``` | ||
| */ | ||
| function stringifyObject(value) { | ||
| return Object.entries(value).map(([key, val]) => { | ||
| if (val !== null && typeof val === "object") return `${key}: {\n ${stringifyObject(val)}\n }`; | ||
| return `${key}: ${val}`; | ||
| }).filter(Boolean).join(",\n"); | ||
| } | ||
| /** | ||
| * Renders a dotted path or string array as an optional-chaining accessor expression rooted at | ||
| * `accessor`. Returns `null` for an empty path. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * getNestedAccessor('pagination.next.id', 'lastPage') | ||
| * // "lastPage?.['pagination']?.['next']?.['id']" | ||
| * ``` | ||
| */ | ||
| function getNestedAccessor(param, accessor) { | ||
| const parts = Array.isArray(param) ? param : param.split("."); | ||
| if (parts.length === 0 || parts.length === 1 && parts[0] === "") return null; | ||
| return `${accessor}?.['${`${parts.join("']?.['")}']`}`; | ||
| } | ||
| /** | ||
| * Builds a JSDoc comment block from an array of lines, returning `fallback` when there are no | ||
| * comments so callers always get a usable string. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * buildJSDoc(['@type string', '@example hello']) | ||
| * // '/**\n * @type string\n * @example hello\n *\/\n ' | ||
| * ``` | ||
| */ | ||
| function buildJSDoc(comments, options = {}) { | ||
| const { indent = " * ", suffix = "\n ", fallback = " " } = options; | ||
| if (comments.length === 0) return fallback; | ||
| return `/**\n${comments.map((c) => `${indent}${c}`).join("\n")}\n */${suffix}`; | ||
| } | ||
| /** | ||
| * Indents every non-empty line of `text` by one indent level, leaving blank lines empty. | ||
| */ | ||
| function indentLines(text) { | ||
| if (!text) return ""; | ||
| return text.split("\n").map((line) => line.trim() ? `${INDENT}${line}` : "").join("\n"); | ||
| } | ||
| /** | ||
| * Renders an object key, quoting it with single quotes only when it is not a valid identifier. | ||
| * Reserved words and globals (`name`, `class`, …) are valid bare keys and stay unquoted. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * objectKey('name') // 'name' | ||
| * objectKey('x-total') // "'x-total'" | ||
| * ``` | ||
| */ | ||
| function objectKey(name) { | ||
| return isIdentifier(name) ? name : singleQuote(name); | ||
| } | ||
| /** | ||
| * Assembles a multi-line object literal from already-rendered `entries`, indenting each entry one | ||
| * level and closing the brace at column zero. Nested objects built the same way indent cumulatively, | ||
| * so callers never re-parse the generated code. A trailing comma is added per entry to match the | ||
| * formatter's multi-line style. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * buildObject(['id: z.number()', 'name: z.string()']) | ||
| * // '{\n id: z.number(),\n name: z.string(),\n}' | ||
| * ``` | ||
| */ | ||
| function buildObject(entries) { | ||
| if (entries.length === 0) return "{}"; | ||
| return `{\n${entries.map((entry) => `${indentLines(entry)},`).join("\n")}\n}`; | ||
| } | ||
| /** | ||
| * Assembles a bracketed list (array by default) from already-rendered `items`. Keeps everything on | ||
| * one line when no item spans multiple lines, and otherwise puts each item on its own line, indented | ||
| * one level with a trailing comma and the closing bracket at column zero. Use it for `z.union([…])`, | ||
| * `z.array([…])`, and similar member lists so objects inside them nest correctly. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * buildList(['z.string()', 'z.number()']) | ||
| * // '[z.string(), z.number()]' | ||
| * ``` | ||
| */ | ||
| function buildList(items, brackets = ["[", "]"]) { | ||
| const [open, close] = brackets; | ||
| if (items.length === 0) return `${open}${close}`; | ||
| if (!items.some((item) => item.includes("\n"))) return `${open}${items.join(", ")}${close}`; | ||
| return `${open}\n${items.map((item) => `${indentLines(item)},`).join("\n")}\n${close}`; | ||
| } | ||
| /** | ||
| * Returns the last path segment of a reference string. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * extractRefName('#/components/schemas/Pet') // 'Pet' | ||
| * ``` | ||
| */ | ||
| function extractRefName(ref) { | ||
| return ref.split("/").at(-1) ?? ref; | ||
| } | ||
| /** | ||
| * Builds a PascalCase child schema name by joining a parent name and property name. | ||
| * Returns `null` when there is no parent to nest under. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * childName('Order', 'shipping_address') // 'OrderShippingAddress' | ||
| * childName(undefined, 'params') // null | ||
| * ``` | ||
| */ | ||
| function childName(parentName, propName) { | ||
| return parentName ? pascalCase([parentName, propName].join(" ")) : null; | ||
| } | ||
| /** | ||
| * Builds a PascalCase enum name from the parent name, property name, and a suffix, skipping any | ||
| * empty parts. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * enumPropName('Order', 'status', 'enum') // 'OrderStatusEnum' | ||
| * ``` | ||
| */ | ||
| function enumPropName(parentName, propName, enumSuffix) { | ||
| return pascalCase([ | ||
| parentName, | ||
| propName, | ||
| enumSuffix | ||
| ].filter(Boolean).join(" ")); | ||
| } | ||
| /** | ||
| * Returns the discriminator key whose mapping value matches `ref`, or `null` when there is no match. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * findDiscriminator({ dog: '#/components/schemas/Dog' }, '#/components/schemas/Dog') // 'dog' | ||
| * ``` | ||
| */ | ||
| function findDiscriminator(mapping, ref) { | ||
| if (!mapping || !ref) return null; | ||
| return Object.entries(mapping).find(([, value]) => value === ref)?.[0] ?? null; | ||
| } | ||
| //#endregion | ||
| export { httpMethods as _, enumPropName as a, visitorDepths as b, getNestedAccessor as c, stringify as d, stringifyObject as f, camelCase as g, isValidVarName as h, childName as i, jsStringEscape as l, trimQuotes as m, buildList as n, extractRefName as o, toRegExpString as p, buildObject as r, findDiscriminator as s, buildJSDoc as t, objectKey as u, isScalarPrimitive as v, schemaTypes as y }; | ||
| //# sourceMappingURL=utils-0p8ZO287.js.map |
| {"version":3,"file":"utils-0p8ZO287.js","names":[],"sources":["../src/constants.ts","../../../internals/utils/src/casing.ts","../../../internals/utils/src/reserved.ts","../../../internals/utils/src/string.ts","../src/utils/index.ts"],"sourcesContent":["import type { HttpMethod } from './nodes/operation.ts'\nimport type { SchemaType } from './nodes/schema.ts'\n\n/**\n * Traversal depth for AST visitor utilities.\n *\n * - `'shallow'` visits only the immediate node, skipping children.\n * - `'deep'` recursively visits all descendant nodes.\n */\nexport type VisitorDepth = 'shallow' | 'deep'\n\nexport const visitorDepths = {\n shallow: 'shallow',\n deep: 'deep',\n} as const satisfies Record<VisitorDepth, VisitorDepth>\n\n/**\n * Schema type discriminators used by all AST schema nodes.\n *\n * These values serve as stable discriminators across the AST (e.g., `schema.type === schemaTypes.object`).\n * Grouped by category: primitives (`string`, `number`, `boolean`), structural types (`object`, `array`, `union`),\n * and format-specific types (`date`, `uuid`, `email`). Use `isScalarPrimitive()` to check for scalar types.\n */\nexport const schemaTypes = {\n /**\n * Text value.\n */\n string: 'string',\n /**\n * Floating-point number (`float`, `double`).\n */\n number: 'number',\n /**\n * Whole number (`int32`). Use `bigint` for `int64`.\n */\n integer: 'integer',\n /**\n * 64-bit integer (`int64`). Only used when `integerType` is set to `'bigint'`.\n */\n bigint: 'bigint',\n /**\n * Boolean value\n */\n boolean: 'boolean',\n /**\n * Explicit null value.\n */\n null: 'null',\n /**\n * Any value (no type restriction).\n */\n any: 'any',\n /**\n * Unknown value (must be narrowed before usage).\n */\n unknown: 'unknown',\n /**\n * No return value (`void`).\n */\n void: 'void',\n /**\n * Object with named properties.\n */\n object: 'object',\n /**\n * Sequential list of items.\n */\n array: 'array',\n /**\n * Fixed-length list with position-specific items.\n */\n tuple: 'tuple',\n /**\n * \"One of\" multiple schema members.\n */\n union: 'union',\n /**\n * \"All of\" multiple schema members.\n */\n intersection: 'intersection',\n /**\n * Enum schema.\n */\n enum: 'enum',\n /**\n * Reference to another schema.\n */\n ref: 'ref',\n /**\n * Calendar date (for example `2026-03-24`).\n */\n date: 'date',\n /**\n * Date-time value (for example `2026-03-24T09:00:00Z`).\n */\n datetime: 'datetime',\n /**\n * Time-only value (for example `09:00:00`).\n */\n time: 'time',\n /**\n * UUID value.\n */\n uuid: 'uuid',\n /**\n * Email address value.\n */\n email: 'email',\n /**\n * URL value.\n */\n url: 'url',\n /**\n * IPv4 address value.\n */\n ipv4: 'ipv4',\n /**\n * IPv6 address value.\n */\n ipv6: 'ipv6',\n /**\n * Binary/blob value.\n */\n blob: 'blob',\n /**\n * Impossible value (`never`).\n */\n never: 'never',\n} as const satisfies Record<SchemaType, SchemaType>\n\nexport type ScalarPrimitive = 'string' | 'number' | 'integer' | 'bigint' | 'boolean'\n\n/**\n * Scalar primitive schema types used for union simplification and type narrowing.\n *\n * Use `isScalarPrimitive()` to safely check whether a type is a scalar primitive.\n */\nconst SCALAR_PRIMITIVE_TYPES = new Set<ScalarPrimitive>(['string', 'number', 'integer', 'bigint', 'boolean'])\n\n/**\n * Type guard that returns `true` when `type` is a scalar primitive schema type.\n *\n * Use this to check if a schema type can be directly assigned without wrapping (e.g., `string | number | boolean`).\n */\nexport function isScalarPrimitive(type: string): type is ScalarPrimitive {\n return SCALAR_PRIMITIVE_TYPES.has(type as ScalarPrimitive)\n}\n\n/**\n * HTTP method identifiers used by operation nodes.\n *\n * Includes all standard HTTP methods (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, TRACE).\n */\nexport const httpMethods = {\n get: 'GET',\n post: 'POST',\n put: 'PUT',\n patch: 'PATCH',\n delete: 'DELETE',\n head: 'HEAD',\n options: 'OPTIONS',\n trace: 'TRACE',\n} as const satisfies Record<Lowercase<HttpMethod>, HttpMethod>\n\n/**\n * Default concurrency limit for `walk()` traversal utility.\n *\n * Set to 30 to balance I/O-bound resolver parallelism against event loop pressure and memory usage during large spec traversals.\n * Use `WALK_CONCURRENCY` when calling `walk()` or override for different hardware constraints.\n *\n * @example\n * ```ts\n * import { walk, WALK_CONCURRENCY } from '@kubb/ast'\n *\n * walk(root, { concurrency: WALK_CONCURRENCY, root: () => {} })\n * ```\n */\nexport const WALK_CONCURRENCY = 30\n\n/**\n * Number of spaces in one indentation level when assembling multi-line code as strings.\n * Set to 2, 3, … to change the indent width used by `buildObject`/`buildList`.\n */\nconst INDENT_SIZE = 2\n\n/**\n * One indentation level, derived from {@link INDENT_SIZE}.\n */\nexport const INDENT = Array.from({ length: INDENT_SIZE }, () => ' ').join('')\n","type Options = {\n /**\n * Text prepended before casing is applied.\n */\n prefix?: string\n /**\n * Text appended before casing is applied.\n */\n suffix?: string\n}\n\n/**\n * Shared implementation for camelCase and PascalCase conversion.\n * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)\n * and capitalizes each word according to `pascal`.\n *\n * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.\n */\nfunction toCamelOrPascal(text: string, pascal: boolean): string {\n return text\n .trim()\n .replace(/([a-z\\d])([A-Z])/g, '$1 $2')\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')\n .replace(/(\\d)([a-z])/g, '$1 $2')\n .split(/[\\s\\-_./\\\\:]+/)\n .filter(Boolean)\n .map((word, i) => {\n if (word.length > 1 && word === word.toUpperCase()) return word\n const head = i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()\n return head + word.slice(1)\n })\n .join('')\n .replace(/[^a-zA-Z0-9]/g, '')\n}\n\n/**\n * Converts `text` to camelCase.\n *\n * @example Word boundaries\n * `camelCase('hello-world') // 'helloWorld'`\n *\n * @example With a prefix\n * `camelCase('tag', { prefix: 'create' }) // 'createTag'`\n */\nexport function camelCase(text: string, { prefix = '', suffix = '' }: Options = {}): string {\n return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false)\n}\n\n/**\n * Converts `text` to PascalCase.\n *\n * @example Word boundaries\n * `pascalCase('hello-world') // 'HelloWorld'`\n *\n * @example With a suffix\n * `pascalCase('tag', { suffix: 'schema' }) // 'TagSchema'`\n */\nexport function pascalCase(text: string, { prefix = '', suffix = '' }: Options = {}): string {\n return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true)\n}\n","/**\n * JavaScript and Java reserved words.\n * @link https://github.com/jonschlinkert/reserved/blob/master/index.js\n */\nconst reservedWords = new Set([\n 'abstract',\n 'arguments',\n 'boolean',\n 'break',\n 'byte',\n 'case',\n 'catch',\n 'char',\n 'class',\n 'const',\n 'continue',\n 'debugger',\n 'default',\n 'delete',\n 'do',\n 'double',\n 'else',\n 'enum',\n 'eval',\n 'export',\n 'extends',\n 'false',\n 'final',\n 'finally',\n 'float',\n 'for',\n 'function',\n 'goto',\n 'if',\n 'implements',\n 'import',\n 'in',\n 'instanceof',\n 'int',\n 'interface',\n 'let',\n 'long',\n 'native',\n 'new',\n 'null',\n 'package',\n 'private',\n 'protected',\n 'public',\n 'return',\n 'short',\n 'static',\n 'super',\n 'switch',\n 'synchronized',\n 'this',\n 'throw',\n 'throws',\n 'transient',\n 'true',\n 'try',\n 'typeof',\n 'var',\n 'void',\n 'volatile',\n 'while',\n 'with',\n 'yield',\n 'Array',\n 'Date',\n 'hasOwnProperty',\n 'Infinity',\n 'isFinite',\n 'isNaN',\n 'isPrototypeOf',\n 'length',\n 'Math',\n 'name',\n 'NaN',\n 'Number',\n 'Object',\n 'prototype',\n 'String',\n 'toString',\n 'undefined',\n 'valueOf',\n] as const)\n\n/**\n * Prefixes `word` with `_` when it is a reserved JavaScript/Java identifier or starts with a digit.\n *\n * @example\n * ```ts\n * transformReservedWord('class') // '_class'\n * transformReservedWord('42foo') // '_42foo'\n * transformReservedWord('status') // 'status'\n * ```\n */\nexport function transformReservedWord(word: string): string {\n const firstChar = word.charCodeAt(0)\n if (word && (reservedWords.has(word as 'valueOf') || (firstChar >= 48 && firstChar <= 57))) {\n return `_${word}`\n }\n return word\n}\n\n/**\n * Returns `true` when `name` is a syntactically valid JavaScript variable name.\n *\n * @example\n * ```ts\n * isValidVarName('status') // true\n * isValidVarName('class') // false (reserved word)\n * isValidVarName('42foo') // false (starts with digit)\n * ```\n */\nexport function isValidVarName(name: string): boolean {\n if (!name || reservedWords.has(name as 'valueOf')) {\n return false\n }\n return isIdentifier(name)\n}\n\n/**\n * Returns `true` when `name` is syntactically a valid identifier, ignoring reserved words.\n *\n * Reserved words and globals (`class`, `name`, `Date`, …) are valid as bare object-literal keys\n * even though they are not valid variable names, so use this (not {@link isValidVarName}) when\n * deciding whether an object key needs quoting.\n *\n * @example\n * ```ts\n * isIdentifier('name') // true\n * isIdentifier('x-total')// false\n * ```\n */\nexport function isIdentifier(name: string): boolean {\n return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name)\n}\n","/**\n * Wraps a value in single quotes for emitting a single-quoted JavaScript string literal, escaping\n * any backslash or single quote in the content.\n *\n * @example\n * ```ts\n * singleQuote('foo') // \"'foo'\"\n * singleQuote(\"o'clock\") // \"'o\\\\'clock'\"\n * ```\n */\nexport function singleQuote(value: string | number | boolean | undefined | null): string {\n if (value === undefined || value === null) return \"''\"\n const escaped = String(value).replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\")\n\n return `'${escaped}'`\n}\n","import { isIdentifier, pascalCase, singleQuote } from '@internals/utils'\nimport { INDENT } from '../constants.ts'\n\nexport { isValidVarName } from '@internals/utils'\n\n/**\n * Strips a single matching pair of `\"...\"`, `'...'`, or `` `...` `` from both ends of `text`.\n * Returns the string unchanged when no balanced quote pair is found.\n *\n * @example\n * ```ts\n * trimQuotes('\"hello\"') // 'hello'\n * trimQuotes('hello') // 'hello'\n * ```\n */\nexport function trimQuotes(text: string): string {\n if (text.length >= 2) {\n const first = text[0]\n const last = text[text.length - 1]\n if ((first === '\"' && last === '\"') || (first === \"'\" && last === \"'\") || (first === '`' && last === '`')) {\n return text.slice(1, -1)\n }\n }\n return text\n}\n\n/**\n * Serializes a primitive value to a single-quoted string literal, stripping any surrounding quote\n * characters first. Escaping comes from `JSON.stringify`, then the quote style switches to single\n * quotes so generated code matches the repo style without a formatter.\n *\n * @example\n * ```ts\n * stringify('hello') // \"'hello'\"\n * stringify('\"hello\"') // \"'hello'\"\n * ```\n */\nexport function stringify(value: string | number | boolean | undefined): string {\n if (value === undefined || value === null) return \"''\"\n const json = JSON.stringify(trimQuotes(value.toString()))\n const inner = json.slice(1, -1).replace(/\\\\\"/g, '\"').replace(/'/g, \"\\\\'\")\n return `'${inner}'`\n}\n\n/**\n * Escapes characters that are not allowed inside JS string literals, covering quotes, backslashes,\n * and the Unicode line terminators U+2028 and U+2029.\n *\n * @see http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.4\n *\n * @example\n * ```ts\n * jsStringEscape('say \"hi\"\\nbye') // 'say \\\\\"hi\\\\\"\\\\nbye'\n * ```\n */\nexport function jsStringEscape(input: unknown): string {\n return `${input}`.replace(/[\"'\\\\\\n\\r\\u2028\\u2029]/g, (character) => {\n switch (character) {\n case '\"':\n case \"'\":\n case '\\\\':\n return `\\\\${character}`\n case '\\n':\n return '\\\\n'\n case '\\r':\n return '\\\\r'\n case '\\u2028':\n return '\\\\u2028'\n case '\\u2029':\n return '\\\\u2029'\n default:\n return ''\n }\n })\n}\n\n/**\n * Converts a pattern string into a `new RegExp(...)` constructor call or a regex literal string.\n * Inline flags expressed as a `^(?im)` prefix are extracted and applied to the resulting expression.\n * Pass `null` as the second argument to emit a `/pattern/flags` literal instead.\n *\n * @example\n * ```ts\n * toRegExpString('^(?im)foo') // 'new RegExp(\"^foo\", \"im\")'\n * toRegExpString('^(?im)foo', null) // '/^foo/im'\n * ```\n */\nexport function toRegExpString(text: string, func: string | null = 'RegExp'): string {\n const raw = trimQuotes(text)\n\n const match = raw.match(/^\\^(\\(\\?([igmsuy]+)\\))/i)\n const replacementTarget = match?.[1] ?? ''\n const matchedFlags = match?.[2]\n const cleaned = raw\n .replace(/^\\\\?\\//, '')\n .replace(/\\\\?\\/$/, '')\n .replace(replacementTarget, '')\n\n const { source, flags } = new RegExp(cleaned, matchedFlags)\n\n if (func === null) return `/${source}/${flags}`\n\n return `new ${func}(${JSON.stringify(source)}${flags ? `, ${JSON.stringify(flags)}` : ''})`\n}\n\n/**\n * Renders a plain object as multi-line `key: value` source for embedding in generated code. Nested\n * objects recurse with fixed indentation, so the result drops straight into an object literal\n * without re-parsing.\n *\n * @example\n * ```ts\n * stringifyObject({ foo: 'bar', nested: { a: 1 } })\n * // 'foo: bar,\\nnested: {\\n a: 1\\n }'\n * ```\n */\nexport function stringifyObject(value: Record<string, unknown>): string {\n const items = Object.entries(value)\n .map(([key, val]) => {\n if (val !== null && typeof val === 'object') {\n return `${key}: {\\n ${stringifyObject(val as Record<string, unknown>)}\\n }`\n }\n return `${key}: ${val}`\n })\n .filter(Boolean)\n return items.join(',\\n')\n}\n\n/**\n * Renders a dotted path or string array as an optional-chaining accessor expression rooted at\n * `accessor`. Returns `null` for an empty path.\n *\n * @example\n * ```ts\n * getNestedAccessor('pagination.next.id', 'lastPage')\n * // \"lastPage?.['pagination']?.['next']?.['id']\"\n * ```\n */\nexport function getNestedAccessor(param: string | Array<string>, accessor: string): string | null {\n const parts = Array.isArray(param) ? param : param.split('.')\n if (parts.length === 0 || (parts.length === 1 && parts[0] === '')) return null\n return `${accessor}?.['${`${parts.join(\"']?.['\")}']`}`\n}\n\n/**\n * Builds a JSDoc comment block from an array of lines, returning `fallback` when there are no\n * comments so callers always get a usable string.\n *\n * @example\n * ```ts\n * buildJSDoc(['@type string', '@example hello'])\n * // '/**\\n * @type string\\n * @example hello\\n *\\/\\n '\n * ```\n */\nexport function buildJSDoc(\n comments: Array<string>,\n options: {\n /**\n * String used to indent each comment line.\n * @default ' * '\n */\n indent?: string\n /**\n * String appended after the closing tag.\n * @default '\\n '\n */\n suffix?: string\n /**\n * Returned as-is when `comments` is empty.\n * @default ' '\n */\n fallback?: string\n } = {},\n): string {\n const { indent = ' * ', suffix = '\\n ', fallback = ' ' } = options\n\n if (comments.length === 0) return fallback\n\n return `/**\\n${comments.map((c) => `${indent}${c}`).join('\\n')}\\n */${suffix}`\n}\n\n/**\n * Indents every non-empty line of `text` by one indent level, leaving blank lines empty.\n */\nfunction indentLines(text: string): string {\n if (!text) return ''\n return text\n .split('\\n')\n .map((line) => (line.trim() ? `${INDENT}${line}` : ''))\n .join('\\n')\n}\n\n/**\n * Renders an object key, quoting it with single quotes only when it is not a valid identifier.\n * Reserved words and globals (`name`, `class`, …) are valid bare keys and stay unquoted.\n *\n * @example\n * ```ts\n * objectKey('name') // 'name'\n * objectKey('x-total') // \"'x-total'\"\n * ```\n */\nexport function objectKey(name: string): string {\n return isIdentifier(name) ? name : singleQuote(name)\n}\n\n/**\n * Assembles a multi-line object literal from already-rendered `entries`, indenting each entry one\n * level and closing the brace at column zero. Nested objects built the same way indent cumulatively,\n * so callers never re-parse the generated code. A trailing comma is added per entry to match the\n * formatter's multi-line style.\n *\n * @example\n * ```ts\n * buildObject(['id: z.number()', 'name: z.string()'])\n * // '{\\n id: z.number(),\\n name: z.string(),\\n}'\n * ```\n */\nexport function buildObject(entries: Array<string>): string {\n if (entries.length === 0) return '{}'\n const body = entries.map((entry) => `${indentLines(entry)},`).join('\\n')\n\n return `{\\n${body}\\n}`\n}\n\n/**\n * Assembles a bracketed list (array by default) from already-rendered `items`. Keeps everything on\n * one line when no item spans multiple lines, and otherwise puts each item on its own line, indented\n * one level with a trailing comma and the closing bracket at column zero. Use it for `z.union([…])`,\n * `z.array([…])`, and similar member lists so objects inside them nest correctly.\n *\n * @example\n * ```ts\n * buildList(['z.string()', 'z.number()'])\n * // '[z.string(), z.number()]'\n * ```\n */\nexport function buildList(items: Array<string>, brackets: [open: string, close: string] = ['[', ']']): string {\n const [open, close] = brackets\n if (items.length === 0) return `${open}${close}`\n if (!items.some((item) => item.includes('\\n'))) return `${open}${items.join(', ')}${close}`\n const body = items.map((item) => `${indentLines(item)},`).join('\\n')\n\n return `${open}\\n${body}\\n${close}`\n}\n\n/**\n * Returns the last path segment of a reference string.\n *\n * @example\n * ```ts\n * extractRefName('#/components/schemas/Pet') // 'Pet'\n * ```\n */\nexport function extractRefName(ref: string): string {\n return ref.split('/').at(-1) ?? ref\n}\n\n/**\n * Builds a PascalCase child schema name by joining a parent name and property name.\n * Returns `null` when there is no parent to nest under.\n *\n * @example\n * ```ts\n * childName('Order', 'shipping_address') // 'OrderShippingAddress'\n * childName(undefined, 'params') // null\n * ```\n */\nexport function childName(parentName: string | null | undefined, propName: string): string | null {\n return parentName ? pascalCase([parentName, propName].join(' ')) : null\n}\n\n/**\n * Builds a PascalCase enum name from the parent name, property name, and a suffix, skipping any\n * empty parts.\n *\n * @example\n * ```ts\n * enumPropName('Order', 'status', 'enum') // 'OrderStatusEnum'\n * ```\n */\nexport function enumPropName(parentName: string | null | undefined, propName: string, enumSuffix: string): string {\n return pascalCase([parentName, propName, enumSuffix].filter(Boolean).join(' '))\n}\n\n/**\n * Returns the discriminator key whose mapping value matches `ref`, or `null` when there is no match.\n *\n * @example\n * ```ts\n * findDiscriminator({ dog: '#/components/schemas/Dog' }, '#/components/schemas/Dog') // 'dog'\n * ```\n */\nexport function findDiscriminator(mapping: Record<string, string> | undefined, ref: string | undefined): string | null {\n if (!mapping || !ref) return null\n return Object.entries(mapping).find(([, value]) => value === ref)?.[0] ?? null\n}\n"],"mappings":"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"} |
| //#region \0rolldown/runtime.js | ||
| var __create = Object.create; | ||
| var __defProp = Object.defineProperty; | ||
| var __name = (target, value) => __defProp(target, "name", { | ||
| value, | ||
| configurable: true | ||
| }); | ||
| var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
| var __getOwnPropNames = Object.getOwnPropertyNames; | ||
| var __getProtoOf = Object.getPrototypeOf; | ||
| var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
| var __copyProps = (to, from, except, desc) => { | ||
| if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) { | ||
| key = keys[i]; | ||
| if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { | ||
| get: ((k) => from[k]).bind(null, key), | ||
| enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable | ||
| }); | ||
| } | ||
| return to; | ||
| }; | ||
| var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { | ||
| value: mod, | ||
| enumerable: true | ||
| }) : target, mod)); | ||
| //#endregion | ||
| //#region src/constants.ts | ||
| const visitorDepths = { | ||
| shallow: "shallow", | ||
| deep: "deep" | ||
| }; | ||
| /** | ||
| * Schema type discriminators used by all AST schema nodes. | ||
| * | ||
| * These values serve as stable discriminators across the AST (e.g., `schema.type === schemaTypes.object`). | ||
| * Grouped by category: primitives (`string`, `number`, `boolean`), structural types (`object`, `array`, `union`), | ||
| * and format-specific types (`date`, `uuid`, `email`). Use `isScalarPrimitive()` to check for scalar types. | ||
| */ | ||
| const schemaTypes = { | ||
| /** | ||
| * Text value. | ||
| */ | ||
| string: "string", | ||
| /** | ||
| * Floating-point number (`float`, `double`). | ||
| */ | ||
| number: "number", | ||
| /** | ||
| * Whole number (`int32`). Use `bigint` for `int64`. | ||
| */ | ||
| integer: "integer", | ||
| /** | ||
| * 64-bit integer (`int64`). Only used when `integerType` is set to `'bigint'`. | ||
| */ | ||
| bigint: "bigint", | ||
| /** | ||
| * Boolean value | ||
| */ | ||
| boolean: "boolean", | ||
| /** | ||
| * Explicit null value. | ||
| */ | ||
| null: "null", | ||
| /** | ||
| * Any value (no type restriction). | ||
| */ | ||
| any: "any", | ||
| /** | ||
| * Unknown value (must be narrowed before usage). | ||
| */ | ||
| unknown: "unknown", | ||
| /** | ||
| * No return value (`void`). | ||
| */ | ||
| void: "void", | ||
| /** | ||
| * Object with named properties. | ||
| */ | ||
| object: "object", | ||
| /** | ||
| * Sequential list of items. | ||
| */ | ||
| array: "array", | ||
| /** | ||
| * Fixed-length list with position-specific items. | ||
| */ | ||
| tuple: "tuple", | ||
| /** | ||
| * "One of" multiple schema members. | ||
| */ | ||
| union: "union", | ||
| /** | ||
| * "All of" multiple schema members. | ||
| */ | ||
| intersection: "intersection", | ||
| /** | ||
| * Enum schema. | ||
| */ | ||
| enum: "enum", | ||
| /** | ||
| * Reference to another schema. | ||
| */ | ||
| ref: "ref", | ||
| /** | ||
| * Calendar date (for example `2026-03-24`). | ||
| */ | ||
| date: "date", | ||
| /** | ||
| * Date-time value (for example `2026-03-24T09:00:00Z`). | ||
| */ | ||
| datetime: "datetime", | ||
| /** | ||
| * Time-only value (for example `09:00:00`). | ||
| */ | ||
| time: "time", | ||
| /** | ||
| * UUID value. | ||
| */ | ||
| uuid: "uuid", | ||
| /** | ||
| * Email address value. | ||
| */ | ||
| email: "email", | ||
| /** | ||
| * URL value. | ||
| */ | ||
| url: "url", | ||
| /** | ||
| * IPv4 address value. | ||
| */ | ||
| ipv4: "ipv4", | ||
| /** | ||
| * IPv6 address value. | ||
| */ | ||
| ipv6: "ipv6", | ||
| /** | ||
| * Binary/blob value. | ||
| */ | ||
| blob: "blob", | ||
| /** | ||
| * Impossible value (`never`). | ||
| */ | ||
| never: "never" | ||
| }; | ||
| /** | ||
| * Scalar primitive schema types used for union simplification and type narrowing. | ||
| * | ||
| * Use `isScalarPrimitive()` to safely check whether a type is a scalar primitive. | ||
| */ | ||
| const SCALAR_PRIMITIVE_TYPES = new Set([ | ||
| "string", | ||
| "number", | ||
| "integer", | ||
| "bigint", | ||
| "boolean" | ||
| ]); | ||
| /** | ||
| * Type guard that returns `true` when `type` is a scalar primitive schema type. | ||
| * | ||
| * Use this to check if a schema type can be directly assigned without wrapping (e.g., `string | number | boolean`). | ||
| */ | ||
| function isScalarPrimitive(type) { | ||
| return SCALAR_PRIMITIVE_TYPES.has(type); | ||
| } | ||
| /** | ||
| * HTTP method identifiers used by operation nodes. | ||
| * | ||
| * Includes all standard HTTP methods (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, TRACE). | ||
| */ | ||
| const httpMethods = { | ||
| get: "GET", | ||
| post: "POST", | ||
| put: "PUT", | ||
| patch: "PATCH", | ||
| delete: "DELETE", | ||
| head: "HEAD", | ||
| options: "OPTIONS", | ||
| trace: "TRACE" | ||
| }; | ||
| /** | ||
| * One indentation level, derived from {@link INDENT_SIZE}. | ||
| */ | ||
| const INDENT = Array.from({ length: 2 }, () => " ").join(""); | ||
| //#endregion | ||
| //#region ../../internals/utils/src/casing.ts | ||
| /** | ||
| * Shared implementation for camelCase and PascalCase conversion. | ||
| * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons) | ||
| * and capitalizes each word according to `pascal`. | ||
| * | ||
| * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are. | ||
| */ | ||
| function toCamelOrPascal(text, pascal) { | ||
| return text.trim().replace(/([a-z\d])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/(\d)([a-z])/g, "$1 $2").split(/[\s\-_./\\:]+/).filter(Boolean).map((word, i) => { | ||
| if (word.length > 1 && word === word.toUpperCase()) return word; | ||
| return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1); | ||
| }).join("").replace(/[^a-zA-Z0-9]/g, ""); | ||
| } | ||
| /** | ||
| * Converts `text` to camelCase. | ||
| * | ||
| * @example Word boundaries | ||
| * `camelCase('hello-world') // 'helloWorld'` | ||
| * | ||
| * @example With a prefix | ||
| * `camelCase('tag', { prefix: 'create' }) // 'createTag'` | ||
| */ | ||
| function camelCase(text, { prefix = "", suffix = "" } = {}) { | ||
| return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false); | ||
| } | ||
| /** | ||
| * Converts `text` to PascalCase. | ||
| * | ||
| * @example Word boundaries | ||
| * `pascalCase('hello-world') // 'HelloWorld'` | ||
| * | ||
| * @example With a suffix | ||
| * `pascalCase('tag', { suffix: 'schema' }) // 'TagSchema'` | ||
| */ | ||
| function pascalCase(text, { prefix = "", suffix = "" } = {}) { | ||
| return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true); | ||
| } | ||
| //#endregion | ||
| //#region ../../internals/utils/src/reserved.ts | ||
| /** | ||
| * JavaScript and Java reserved words. | ||
| * @link https://github.com/jonschlinkert/reserved/blob/master/index.js | ||
| */ | ||
| const reservedWords = new Set([ | ||
| "abstract", | ||
| "arguments", | ||
| "boolean", | ||
| "break", | ||
| "byte", | ||
| "case", | ||
| "catch", | ||
| "char", | ||
| "class", | ||
| "const", | ||
| "continue", | ||
| "debugger", | ||
| "default", | ||
| "delete", | ||
| "do", | ||
| "double", | ||
| "else", | ||
| "enum", | ||
| "eval", | ||
| "export", | ||
| "extends", | ||
| "false", | ||
| "final", | ||
| "finally", | ||
| "float", | ||
| "for", | ||
| "function", | ||
| "goto", | ||
| "if", | ||
| "implements", | ||
| "import", | ||
| "in", | ||
| "instanceof", | ||
| "int", | ||
| "interface", | ||
| "let", | ||
| "long", | ||
| "native", | ||
| "new", | ||
| "null", | ||
| "package", | ||
| "private", | ||
| "protected", | ||
| "public", | ||
| "return", | ||
| "short", | ||
| "static", | ||
| "super", | ||
| "switch", | ||
| "synchronized", | ||
| "this", | ||
| "throw", | ||
| "throws", | ||
| "transient", | ||
| "true", | ||
| "try", | ||
| "typeof", | ||
| "var", | ||
| "void", | ||
| "volatile", | ||
| "while", | ||
| "with", | ||
| "yield", | ||
| "Array", | ||
| "Date", | ||
| "hasOwnProperty", | ||
| "Infinity", | ||
| "isFinite", | ||
| "isNaN", | ||
| "isPrototypeOf", | ||
| "length", | ||
| "Math", | ||
| "name", | ||
| "NaN", | ||
| "Number", | ||
| "Object", | ||
| "prototype", | ||
| "String", | ||
| "toString", | ||
| "undefined", | ||
| "valueOf" | ||
| ]); | ||
| /** | ||
| * Returns `true` when `name` is a syntactically valid JavaScript variable name. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * isValidVarName('status') // true | ||
| * isValidVarName('class') // false (reserved word) | ||
| * isValidVarName('42foo') // false (starts with digit) | ||
| * ``` | ||
| */ | ||
| function isValidVarName(name) { | ||
| if (!name || reservedWords.has(name)) return false; | ||
| return isIdentifier(name); | ||
| } | ||
| /** | ||
| * Returns `true` when `name` is syntactically a valid identifier, ignoring reserved words. | ||
| * | ||
| * Reserved words and globals (`class`, `name`, `Date`, …) are valid as bare object-literal keys | ||
| * even though they are not valid variable names, so use this (not {@link isValidVarName}) when | ||
| * deciding whether an object key needs quoting. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * isIdentifier('name') // true | ||
| * isIdentifier('x-total')// false | ||
| * ``` | ||
| */ | ||
| function isIdentifier(name) { | ||
| return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name); | ||
| } | ||
| //#endregion | ||
| //#region ../../internals/utils/src/string.ts | ||
| /** | ||
| * Wraps a value in single quotes for emitting a single-quoted JavaScript string literal, escaping | ||
| * any backslash or single quote in the content. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * singleQuote('foo') // "'foo'" | ||
| * singleQuote("o'clock") // "'o\\'clock'" | ||
| * ``` | ||
| */ | ||
| function singleQuote(value) { | ||
| if (value === void 0 || value === null) return "''"; | ||
| return `'${String(value).replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`; | ||
| } | ||
| //#endregion | ||
| //#region src/utils/index.ts | ||
| /** | ||
| * Strips a single matching pair of `"..."`, `'...'`, or `` `...` `` from both ends of `text`. | ||
| * Returns the string unchanged when no balanced quote pair is found. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * trimQuotes('"hello"') // 'hello' | ||
| * trimQuotes('hello') // 'hello' | ||
| * ``` | ||
| */ | ||
| function trimQuotes(text) { | ||
| if (text.length >= 2) { | ||
| const first = text[0]; | ||
| const last = text[text.length - 1]; | ||
| if (first === "\"" && last === "\"" || first === "'" && last === "'" || first === "`" && last === "`") return text.slice(1, -1); | ||
| } | ||
| return text; | ||
| } | ||
| /** | ||
| * Serializes a primitive value to a single-quoted string literal, stripping any surrounding quote | ||
| * characters first. Escaping comes from `JSON.stringify`, then the quote style switches to single | ||
| * quotes so generated code matches the repo style without a formatter. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * stringify('hello') // "'hello'" | ||
| * stringify('"hello"') // "'hello'" | ||
| * ``` | ||
| */ | ||
| function stringify(value) { | ||
| if (value === void 0 || value === null) return "''"; | ||
| return `'${JSON.stringify(trimQuotes(value.toString())).slice(1, -1).replace(/\\"/g, "\"").replace(/'/g, "\\'")}'`; | ||
| } | ||
| /** | ||
| * Escapes characters that are not allowed inside JS string literals, covering quotes, backslashes, | ||
| * and the Unicode line terminators U+2028 and U+2029. | ||
| * | ||
| * @see http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.4 | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * jsStringEscape('say "hi"\nbye') // 'say \\"hi\\"\\nbye' | ||
| * ``` | ||
| */ | ||
| function jsStringEscape(input) { | ||
| return `${input}`.replace(/["'\\\n\r\u2028\u2029]/g, (character) => { | ||
| switch (character) { | ||
| case "\"": | ||
| case "'": | ||
| case "\\": return `\\${character}`; | ||
| case "\n": return "\\n"; | ||
| case "\r": return "\\r"; | ||
| case "\u2028": return "\\u2028"; | ||
| case "\u2029": return "\\u2029"; | ||
| default: return ""; | ||
| } | ||
| }); | ||
| } | ||
| /** | ||
| * Converts a pattern string into a `new RegExp(...)` constructor call or a regex literal string. | ||
| * Inline flags expressed as a `^(?im)` prefix are extracted and applied to the resulting expression. | ||
| * Pass `null` as the second argument to emit a `/pattern/flags` literal instead. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * toRegExpString('^(?im)foo') // 'new RegExp("^foo", "im")' | ||
| * toRegExpString('^(?im)foo', null) // '/^foo/im' | ||
| * ``` | ||
| */ | ||
| function toRegExpString(text, func = "RegExp") { | ||
| const raw = trimQuotes(text); | ||
| const match = raw.match(/^\^(\(\?([igmsuy]+)\))/i); | ||
| const replacementTarget = match?.[1] ?? ""; | ||
| const matchedFlags = match?.[2]; | ||
| const cleaned = raw.replace(/^\\?\//, "").replace(/\\?\/$/, "").replace(replacementTarget, ""); | ||
| const { source, flags } = new RegExp(cleaned, matchedFlags); | ||
| if (func === null) return `/${source}/${flags}`; | ||
| return `new ${func}(${JSON.stringify(source)}${flags ? `, ${JSON.stringify(flags)}` : ""})`; | ||
| } | ||
| /** | ||
| * Renders a plain object as multi-line `key: value` source for embedding in generated code. Nested | ||
| * objects recurse with fixed indentation, so the result drops straight into an object literal | ||
| * without re-parsing. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * stringifyObject({ foo: 'bar', nested: { a: 1 } }) | ||
| * // 'foo: bar,\nnested: {\n a: 1\n }' | ||
| * ``` | ||
| */ | ||
| function stringifyObject(value) { | ||
| return Object.entries(value).map(([key, val]) => { | ||
| if (val !== null && typeof val === "object") return `${key}: {\n ${stringifyObject(val)}\n }`; | ||
| return `${key}: ${val}`; | ||
| }).filter(Boolean).join(",\n"); | ||
| } | ||
| /** | ||
| * Renders a dotted path or string array as an optional-chaining accessor expression rooted at | ||
| * `accessor`. Returns `null` for an empty path. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * getNestedAccessor('pagination.next.id', 'lastPage') | ||
| * // "lastPage?.['pagination']?.['next']?.['id']" | ||
| * ``` | ||
| */ | ||
| function getNestedAccessor(param, accessor) { | ||
| const parts = Array.isArray(param) ? param : param.split("."); | ||
| if (parts.length === 0 || parts.length === 1 && parts[0] === "") return null; | ||
| return `${accessor}?.['${`${parts.join("']?.['")}']`}`; | ||
| } | ||
| /** | ||
| * Builds a JSDoc comment block from an array of lines, returning `fallback` when there are no | ||
| * comments so callers always get a usable string. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * buildJSDoc(['@type string', '@example hello']) | ||
| * // '/**\n * @type string\n * @example hello\n *\/\n ' | ||
| * ``` | ||
| */ | ||
| function buildJSDoc(comments, options = {}) { | ||
| const { indent = " * ", suffix = "\n ", fallback = " " } = options; | ||
| if (comments.length === 0) return fallback; | ||
| return `/**\n${comments.map((c) => `${indent}${c}`).join("\n")}\n */${suffix}`; | ||
| } | ||
| /** | ||
| * Indents every non-empty line of `text` by one indent level, leaving blank lines empty. | ||
| */ | ||
| function indentLines(text) { | ||
| if (!text) return ""; | ||
| return text.split("\n").map((line) => line.trim() ? `${INDENT}${line}` : "").join("\n"); | ||
| } | ||
| /** | ||
| * Renders an object key, quoting it with single quotes only when it is not a valid identifier. | ||
| * Reserved words and globals (`name`, `class`, …) are valid bare keys and stay unquoted. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * objectKey('name') // 'name' | ||
| * objectKey('x-total') // "'x-total'" | ||
| * ``` | ||
| */ | ||
| function objectKey(name) { | ||
| return isIdentifier(name) ? name : singleQuote(name); | ||
| } | ||
| /** | ||
| * Assembles a multi-line object literal from already-rendered `entries`, indenting each entry one | ||
| * level and closing the brace at column zero. Nested objects built the same way indent cumulatively, | ||
| * so callers never re-parse the generated code. A trailing comma is added per entry to match the | ||
| * formatter's multi-line style. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * buildObject(['id: z.number()', 'name: z.string()']) | ||
| * // '{\n id: z.number(),\n name: z.string(),\n}' | ||
| * ``` | ||
| */ | ||
| function buildObject(entries) { | ||
| if (entries.length === 0) return "{}"; | ||
| return `{\n${entries.map((entry) => `${indentLines(entry)},`).join("\n")}\n}`; | ||
| } | ||
| /** | ||
| * Assembles a bracketed list (array by default) from already-rendered `items`. Keeps everything on | ||
| * one line when no item spans multiple lines, and otherwise puts each item on its own line, indented | ||
| * one level with a trailing comma and the closing bracket at column zero. Use it for `z.union([…])`, | ||
| * `z.array([…])`, and similar member lists so objects inside them nest correctly. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * buildList(['z.string()', 'z.number()']) | ||
| * // '[z.string(), z.number()]' | ||
| * ``` | ||
| */ | ||
| function buildList(items, brackets = ["[", "]"]) { | ||
| const [open, close] = brackets; | ||
| if (items.length === 0) return `${open}${close}`; | ||
| if (!items.some((item) => item.includes("\n"))) return `${open}${items.join(", ")}${close}`; | ||
| return `${open}\n${items.map((item) => `${indentLines(item)},`).join("\n")}\n${close}`; | ||
| } | ||
| /** | ||
| * Returns the last path segment of a reference string. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * extractRefName('#/components/schemas/Pet') // 'Pet' | ||
| * ``` | ||
| */ | ||
| function extractRefName(ref) { | ||
| return ref.split("/").at(-1) ?? ref; | ||
| } | ||
| /** | ||
| * Builds a PascalCase child schema name by joining a parent name and property name. | ||
| * Returns `null` when there is no parent to nest under. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * childName('Order', 'shipping_address') // 'OrderShippingAddress' | ||
| * childName(undefined, 'params') // null | ||
| * ``` | ||
| */ | ||
| function childName(parentName, propName) { | ||
| return parentName ? pascalCase([parentName, propName].join(" ")) : null; | ||
| } | ||
| /** | ||
| * Builds a PascalCase enum name from the parent name, property name, and a suffix, skipping any | ||
| * empty parts. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * enumPropName('Order', 'status', 'enum') // 'OrderStatusEnum' | ||
| * ``` | ||
| */ | ||
| function enumPropName(parentName, propName, enumSuffix) { | ||
| return pascalCase([ | ||
| parentName, | ||
| propName, | ||
| enumSuffix | ||
| ].filter(Boolean).join(" ")); | ||
| } | ||
| /** | ||
| * Returns the discriminator key whose mapping value matches `ref`, or `null` when there is no match. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * findDiscriminator({ dog: '#/components/schemas/Dog' }, '#/components/schemas/Dog') // 'dog' | ||
| * ``` | ||
| */ | ||
| function findDiscriminator(mapping, ref) { | ||
| if (!mapping || !ref) return null; | ||
| return Object.entries(mapping).find(([, value]) => value === ref)?.[0] ?? null; | ||
| } | ||
| //#endregion | ||
| Object.defineProperty(exports, "__name", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return __name; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "__toESM", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return __toESM; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "buildJSDoc", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return buildJSDoc; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "buildList", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return buildList; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "buildObject", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return buildObject; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "camelCase", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return camelCase; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "childName", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return childName; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "enumPropName", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return enumPropName; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "extractRefName", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return extractRefName; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "findDiscriminator", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return findDiscriminator; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "getNestedAccessor", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return getNestedAccessor; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "httpMethods", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return httpMethods; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "isScalarPrimitive", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return isScalarPrimitive; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "isValidVarName", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return isValidVarName; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "jsStringEscape", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return jsStringEscape; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "objectKey", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return objectKey; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "schemaTypes", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return schemaTypes; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "stringify", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return stringify; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "stringifyObject", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return stringifyObject; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "toRegExpString", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return toRegExpString; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "trimQuotes", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return trimQuotes; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "visitorDepths", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return visitorDepths; | ||
| } | ||
| }); | ||
| //# sourceMappingURL=utils-cdQ6Pzyi.cjs.map |
| {"version":3,"file":"utils-cdQ6Pzyi.cjs","names":[],"sources":["../src/constants.ts","../../../internals/utils/src/casing.ts","../../../internals/utils/src/reserved.ts","../../../internals/utils/src/string.ts","../src/utils/index.ts"],"sourcesContent":["import type { HttpMethod } from './nodes/operation.ts'\nimport type { SchemaType } from './nodes/schema.ts'\n\n/**\n * Traversal depth for AST visitor utilities.\n *\n * - `'shallow'` visits only the immediate node, skipping children.\n * - `'deep'` recursively visits all descendant nodes.\n */\nexport type VisitorDepth = 'shallow' | 'deep'\n\nexport const visitorDepths = {\n shallow: 'shallow',\n deep: 'deep',\n} as const satisfies Record<VisitorDepth, VisitorDepth>\n\n/**\n * Schema type discriminators used by all AST schema nodes.\n *\n * These values serve as stable discriminators across the AST (e.g., `schema.type === schemaTypes.object`).\n * Grouped by category: primitives (`string`, `number`, `boolean`), structural types (`object`, `array`, `union`),\n * and format-specific types (`date`, `uuid`, `email`). Use `isScalarPrimitive()` to check for scalar types.\n */\nexport const schemaTypes = {\n /**\n * Text value.\n */\n string: 'string',\n /**\n * Floating-point number (`float`, `double`).\n */\n number: 'number',\n /**\n * Whole number (`int32`). Use `bigint` for `int64`.\n */\n integer: 'integer',\n /**\n * 64-bit integer (`int64`). Only used when `integerType` is set to `'bigint'`.\n */\n bigint: 'bigint',\n /**\n * Boolean value\n */\n boolean: 'boolean',\n /**\n * Explicit null value.\n */\n null: 'null',\n /**\n * Any value (no type restriction).\n */\n any: 'any',\n /**\n * Unknown value (must be narrowed before usage).\n */\n unknown: 'unknown',\n /**\n * No return value (`void`).\n */\n void: 'void',\n /**\n * Object with named properties.\n */\n object: 'object',\n /**\n * Sequential list of items.\n */\n array: 'array',\n /**\n * Fixed-length list with position-specific items.\n */\n tuple: 'tuple',\n /**\n * \"One of\" multiple schema members.\n */\n union: 'union',\n /**\n * \"All of\" multiple schema members.\n */\n intersection: 'intersection',\n /**\n * Enum schema.\n */\n enum: 'enum',\n /**\n * Reference to another schema.\n */\n ref: 'ref',\n /**\n * Calendar date (for example `2026-03-24`).\n */\n date: 'date',\n /**\n * Date-time value (for example `2026-03-24T09:00:00Z`).\n */\n datetime: 'datetime',\n /**\n * Time-only value (for example `09:00:00`).\n */\n time: 'time',\n /**\n * UUID value.\n */\n uuid: 'uuid',\n /**\n * Email address value.\n */\n email: 'email',\n /**\n * URL value.\n */\n url: 'url',\n /**\n * IPv4 address value.\n */\n ipv4: 'ipv4',\n /**\n * IPv6 address value.\n */\n ipv6: 'ipv6',\n /**\n * Binary/blob value.\n */\n blob: 'blob',\n /**\n * Impossible value (`never`).\n */\n never: 'never',\n} as const satisfies Record<SchemaType, SchemaType>\n\nexport type ScalarPrimitive = 'string' | 'number' | 'integer' | 'bigint' | 'boolean'\n\n/**\n * Scalar primitive schema types used for union simplification and type narrowing.\n *\n * Use `isScalarPrimitive()` to safely check whether a type is a scalar primitive.\n */\nconst SCALAR_PRIMITIVE_TYPES = new Set<ScalarPrimitive>(['string', 'number', 'integer', 'bigint', 'boolean'])\n\n/**\n * Type guard that returns `true` when `type` is a scalar primitive schema type.\n *\n * Use this to check if a schema type can be directly assigned without wrapping (e.g., `string | number | boolean`).\n */\nexport function isScalarPrimitive(type: string): type is ScalarPrimitive {\n return SCALAR_PRIMITIVE_TYPES.has(type as ScalarPrimitive)\n}\n\n/**\n * HTTP method identifiers used by operation nodes.\n *\n * Includes all standard HTTP methods (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, TRACE).\n */\nexport const httpMethods = {\n get: 'GET',\n post: 'POST',\n put: 'PUT',\n patch: 'PATCH',\n delete: 'DELETE',\n head: 'HEAD',\n options: 'OPTIONS',\n trace: 'TRACE',\n} as const satisfies Record<Lowercase<HttpMethod>, HttpMethod>\n\n/**\n * Default concurrency limit for `walk()` traversal utility.\n *\n * Set to 30 to balance I/O-bound resolver parallelism against event loop pressure and memory usage during large spec traversals.\n * Use `WALK_CONCURRENCY` when calling `walk()` or override for different hardware constraints.\n *\n * @example\n * ```ts\n * import { walk, WALK_CONCURRENCY } from '@kubb/ast'\n *\n * walk(root, { concurrency: WALK_CONCURRENCY, root: () => {} })\n * ```\n */\nexport const WALK_CONCURRENCY = 30\n\n/**\n * Number of spaces in one indentation level when assembling multi-line code as strings.\n * Set to 2, 3, … to change the indent width used by `buildObject`/`buildList`.\n */\nconst INDENT_SIZE = 2\n\n/**\n * One indentation level, derived from {@link INDENT_SIZE}.\n */\nexport const INDENT = Array.from({ length: INDENT_SIZE }, () => ' ').join('')\n","type Options = {\n /**\n * Text prepended before casing is applied.\n */\n prefix?: string\n /**\n * Text appended before casing is applied.\n */\n suffix?: string\n}\n\n/**\n * Shared implementation for camelCase and PascalCase conversion.\n * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)\n * and capitalizes each word according to `pascal`.\n *\n * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.\n */\nfunction toCamelOrPascal(text: string, pascal: boolean): string {\n return text\n .trim()\n .replace(/([a-z\\d])([A-Z])/g, '$1 $2')\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')\n .replace(/(\\d)([a-z])/g, '$1 $2')\n .split(/[\\s\\-_./\\\\:]+/)\n .filter(Boolean)\n .map((word, i) => {\n if (word.length > 1 && word === word.toUpperCase()) return word\n const head = i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()\n return head + word.slice(1)\n })\n .join('')\n .replace(/[^a-zA-Z0-9]/g, '')\n}\n\n/**\n * Converts `text` to camelCase.\n *\n * @example Word boundaries\n * `camelCase('hello-world') // 'helloWorld'`\n *\n * @example With a prefix\n * `camelCase('tag', { prefix: 'create' }) // 'createTag'`\n */\nexport function camelCase(text: string, { prefix = '', suffix = '' }: Options = {}): string {\n return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false)\n}\n\n/**\n * Converts `text` to PascalCase.\n *\n * @example Word boundaries\n * `pascalCase('hello-world') // 'HelloWorld'`\n *\n * @example With a suffix\n * `pascalCase('tag', { suffix: 'schema' }) // 'TagSchema'`\n */\nexport function pascalCase(text: string, { prefix = '', suffix = '' }: Options = {}): string {\n return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true)\n}\n","/**\n * JavaScript and Java reserved words.\n * @link https://github.com/jonschlinkert/reserved/blob/master/index.js\n */\nconst reservedWords = new Set([\n 'abstract',\n 'arguments',\n 'boolean',\n 'break',\n 'byte',\n 'case',\n 'catch',\n 'char',\n 'class',\n 'const',\n 'continue',\n 'debugger',\n 'default',\n 'delete',\n 'do',\n 'double',\n 'else',\n 'enum',\n 'eval',\n 'export',\n 'extends',\n 'false',\n 'final',\n 'finally',\n 'float',\n 'for',\n 'function',\n 'goto',\n 'if',\n 'implements',\n 'import',\n 'in',\n 'instanceof',\n 'int',\n 'interface',\n 'let',\n 'long',\n 'native',\n 'new',\n 'null',\n 'package',\n 'private',\n 'protected',\n 'public',\n 'return',\n 'short',\n 'static',\n 'super',\n 'switch',\n 'synchronized',\n 'this',\n 'throw',\n 'throws',\n 'transient',\n 'true',\n 'try',\n 'typeof',\n 'var',\n 'void',\n 'volatile',\n 'while',\n 'with',\n 'yield',\n 'Array',\n 'Date',\n 'hasOwnProperty',\n 'Infinity',\n 'isFinite',\n 'isNaN',\n 'isPrototypeOf',\n 'length',\n 'Math',\n 'name',\n 'NaN',\n 'Number',\n 'Object',\n 'prototype',\n 'String',\n 'toString',\n 'undefined',\n 'valueOf',\n] as const)\n\n/**\n * Prefixes `word` with `_` when it is a reserved JavaScript/Java identifier or starts with a digit.\n *\n * @example\n * ```ts\n * transformReservedWord('class') // '_class'\n * transformReservedWord('42foo') // '_42foo'\n * transformReservedWord('status') // 'status'\n * ```\n */\nexport function transformReservedWord(word: string): string {\n const firstChar = word.charCodeAt(0)\n if (word && (reservedWords.has(word as 'valueOf') || (firstChar >= 48 && firstChar <= 57))) {\n return `_${word}`\n }\n return word\n}\n\n/**\n * Returns `true` when `name` is a syntactically valid JavaScript variable name.\n *\n * @example\n * ```ts\n * isValidVarName('status') // true\n * isValidVarName('class') // false (reserved word)\n * isValidVarName('42foo') // false (starts with digit)\n * ```\n */\nexport function isValidVarName(name: string): boolean {\n if (!name || reservedWords.has(name as 'valueOf')) {\n return false\n }\n return isIdentifier(name)\n}\n\n/**\n * Returns `true` when `name` is syntactically a valid identifier, ignoring reserved words.\n *\n * Reserved words and globals (`class`, `name`, `Date`, …) are valid as bare object-literal keys\n * even though they are not valid variable names, so use this (not {@link isValidVarName}) when\n * deciding whether an object key needs quoting.\n *\n * @example\n * ```ts\n * isIdentifier('name') // true\n * isIdentifier('x-total')// false\n * ```\n */\nexport function isIdentifier(name: string): boolean {\n return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name)\n}\n","/**\n * Wraps a value in single quotes for emitting a single-quoted JavaScript string literal, escaping\n * any backslash or single quote in the content.\n *\n * @example\n * ```ts\n * singleQuote('foo') // \"'foo'\"\n * singleQuote(\"o'clock\") // \"'o\\\\'clock'\"\n * ```\n */\nexport function singleQuote(value: string | number | boolean | undefined | null): string {\n if (value === undefined || value === null) return \"''\"\n const escaped = String(value).replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\")\n\n return `'${escaped}'`\n}\n","import { isIdentifier, pascalCase, singleQuote } from '@internals/utils'\nimport { INDENT } from '../constants.ts'\n\nexport { isValidVarName } from '@internals/utils'\n\n/**\n * Strips a single matching pair of `\"...\"`, `'...'`, or `` `...` `` from both ends of `text`.\n * Returns the string unchanged when no balanced quote pair is found.\n *\n * @example\n * ```ts\n * trimQuotes('\"hello\"') // 'hello'\n * trimQuotes('hello') // 'hello'\n * ```\n */\nexport function trimQuotes(text: string): string {\n if (text.length >= 2) {\n const first = text[0]\n const last = text[text.length - 1]\n if ((first === '\"' && last === '\"') || (first === \"'\" && last === \"'\") || (first === '`' && last === '`')) {\n return text.slice(1, -1)\n }\n }\n return text\n}\n\n/**\n * Serializes a primitive value to a single-quoted string literal, stripping any surrounding quote\n * characters first. Escaping comes from `JSON.stringify`, then the quote style switches to single\n * quotes so generated code matches the repo style without a formatter.\n *\n * @example\n * ```ts\n * stringify('hello') // \"'hello'\"\n * stringify('\"hello\"') // \"'hello'\"\n * ```\n */\nexport function stringify(value: string | number | boolean | undefined): string {\n if (value === undefined || value === null) return \"''\"\n const json = JSON.stringify(trimQuotes(value.toString()))\n const inner = json.slice(1, -1).replace(/\\\\\"/g, '\"').replace(/'/g, \"\\\\'\")\n return `'${inner}'`\n}\n\n/**\n * Escapes characters that are not allowed inside JS string literals, covering quotes, backslashes,\n * and the Unicode line terminators U+2028 and U+2029.\n *\n * @see http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.4\n *\n * @example\n * ```ts\n * jsStringEscape('say \"hi\"\\nbye') // 'say \\\\\"hi\\\\\"\\\\nbye'\n * ```\n */\nexport function jsStringEscape(input: unknown): string {\n return `${input}`.replace(/[\"'\\\\\\n\\r\\u2028\\u2029]/g, (character) => {\n switch (character) {\n case '\"':\n case \"'\":\n case '\\\\':\n return `\\\\${character}`\n case '\\n':\n return '\\\\n'\n case '\\r':\n return '\\\\r'\n case '\\u2028':\n return '\\\\u2028'\n case '\\u2029':\n return '\\\\u2029'\n default:\n return ''\n }\n })\n}\n\n/**\n * Converts a pattern string into a `new RegExp(...)` constructor call or a regex literal string.\n * Inline flags expressed as a `^(?im)` prefix are extracted and applied to the resulting expression.\n * Pass `null` as the second argument to emit a `/pattern/flags` literal instead.\n *\n * @example\n * ```ts\n * toRegExpString('^(?im)foo') // 'new RegExp(\"^foo\", \"im\")'\n * toRegExpString('^(?im)foo', null) // '/^foo/im'\n * ```\n */\nexport function toRegExpString(text: string, func: string | null = 'RegExp'): string {\n const raw = trimQuotes(text)\n\n const match = raw.match(/^\\^(\\(\\?([igmsuy]+)\\))/i)\n const replacementTarget = match?.[1] ?? ''\n const matchedFlags = match?.[2]\n const cleaned = raw\n .replace(/^\\\\?\\//, '')\n .replace(/\\\\?\\/$/, '')\n .replace(replacementTarget, '')\n\n const { source, flags } = new RegExp(cleaned, matchedFlags)\n\n if (func === null) return `/${source}/${flags}`\n\n return `new ${func}(${JSON.stringify(source)}${flags ? `, ${JSON.stringify(flags)}` : ''})`\n}\n\n/**\n * Renders a plain object as multi-line `key: value` source for embedding in generated code. Nested\n * objects recurse with fixed indentation, so the result drops straight into an object literal\n * without re-parsing.\n *\n * @example\n * ```ts\n * stringifyObject({ foo: 'bar', nested: { a: 1 } })\n * // 'foo: bar,\\nnested: {\\n a: 1\\n }'\n * ```\n */\nexport function stringifyObject(value: Record<string, unknown>): string {\n const items = Object.entries(value)\n .map(([key, val]) => {\n if (val !== null && typeof val === 'object') {\n return `${key}: {\\n ${stringifyObject(val as Record<string, unknown>)}\\n }`\n }\n return `${key}: ${val}`\n })\n .filter(Boolean)\n return items.join(',\\n')\n}\n\n/**\n * Renders a dotted path or string array as an optional-chaining accessor expression rooted at\n * `accessor`. Returns `null` for an empty path.\n *\n * @example\n * ```ts\n * getNestedAccessor('pagination.next.id', 'lastPage')\n * // \"lastPage?.['pagination']?.['next']?.['id']\"\n * ```\n */\nexport function getNestedAccessor(param: string | Array<string>, accessor: string): string | null {\n const parts = Array.isArray(param) ? param : param.split('.')\n if (parts.length === 0 || (parts.length === 1 && parts[0] === '')) return null\n return `${accessor}?.['${`${parts.join(\"']?.['\")}']`}`\n}\n\n/**\n * Builds a JSDoc comment block from an array of lines, returning `fallback` when there are no\n * comments so callers always get a usable string.\n *\n * @example\n * ```ts\n * buildJSDoc(['@type string', '@example hello'])\n * // '/**\\n * @type string\\n * @example hello\\n *\\/\\n '\n * ```\n */\nexport function buildJSDoc(\n comments: Array<string>,\n options: {\n /**\n * String used to indent each comment line.\n * @default ' * '\n */\n indent?: string\n /**\n * String appended after the closing tag.\n * @default '\\n '\n */\n suffix?: string\n /**\n * Returned as-is when `comments` is empty.\n * @default ' '\n */\n fallback?: string\n } = {},\n): string {\n const { indent = ' * ', suffix = '\\n ', fallback = ' ' } = options\n\n if (comments.length === 0) return fallback\n\n return `/**\\n${comments.map((c) => `${indent}${c}`).join('\\n')}\\n */${suffix}`\n}\n\n/**\n * Indents every non-empty line of `text` by one indent level, leaving blank lines empty.\n */\nfunction indentLines(text: string): string {\n if (!text) return ''\n return text\n .split('\\n')\n .map((line) => (line.trim() ? `${INDENT}${line}` : ''))\n .join('\\n')\n}\n\n/**\n * Renders an object key, quoting it with single quotes only when it is not a valid identifier.\n * Reserved words and globals (`name`, `class`, …) are valid bare keys and stay unquoted.\n *\n * @example\n * ```ts\n * objectKey('name') // 'name'\n * objectKey('x-total') // \"'x-total'\"\n * ```\n */\nexport function objectKey(name: string): string {\n return isIdentifier(name) ? name : singleQuote(name)\n}\n\n/**\n * Assembles a multi-line object literal from already-rendered `entries`, indenting each entry one\n * level and closing the brace at column zero. Nested objects built the same way indent cumulatively,\n * so callers never re-parse the generated code. A trailing comma is added per entry to match the\n * formatter's multi-line style.\n *\n * @example\n * ```ts\n * buildObject(['id: z.number()', 'name: z.string()'])\n * // '{\\n id: z.number(),\\n name: z.string(),\\n}'\n * ```\n */\nexport function buildObject(entries: Array<string>): string {\n if (entries.length === 0) return '{}'\n const body = entries.map((entry) => `${indentLines(entry)},`).join('\\n')\n\n return `{\\n${body}\\n}`\n}\n\n/**\n * Assembles a bracketed list (array by default) from already-rendered `items`. Keeps everything on\n * one line when no item spans multiple lines, and otherwise puts each item on its own line, indented\n * one level with a trailing comma and the closing bracket at column zero. Use it for `z.union([…])`,\n * `z.array([…])`, and similar member lists so objects inside them nest correctly.\n *\n * @example\n * ```ts\n * buildList(['z.string()', 'z.number()'])\n * // '[z.string(), z.number()]'\n * ```\n */\nexport function buildList(items: Array<string>, brackets: [open: string, close: string] = ['[', ']']): string {\n const [open, close] = brackets\n if (items.length === 0) return `${open}${close}`\n if (!items.some((item) => item.includes('\\n'))) return `${open}${items.join(', ')}${close}`\n const body = items.map((item) => `${indentLines(item)},`).join('\\n')\n\n return `${open}\\n${body}\\n${close}`\n}\n\n/**\n * Returns the last path segment of a reference string.\n *\n * @example\n * ```ts\n * extractRefName('#/components/schemas/Pet') // 'Pet'\n * ```\n */\nexport function extractRefName(ref: string): string {\n return ref.split('/').at(-1) ?? ref\n}\n\n/**\n * Builds a PascalCase child schema name by joining a parent name and property name.\n * Returns `null` when there is no parent to nest under.\n *\n * @example\n * ```ts\n * childName('Order', 'shipping_address') // 'OrderShippingAddress'\n * childName(undefined, 'params') // null\n * ```\n */\nexport function childName(parentName: string | null | undefined, propName: string): string | null {\n return parentName ? pascalCase([parentName, propName].join(' ')) : null\n}\n\n/**\n * Builds a PascalCase enum name from the parent name, property name, and a suffix, skipping any\n * empty parts.\n *\n * @example\n * ```ts\n * enumPropName('Order', 'status', 'enum') // 'OrderStatusEnum'\n * ```\n */\nexport function enumPropName(parentName: string | null | undefined, propName: string, enumSuffix: string): string {\n return pascalCase([parentName, propName, enumSuffix].filter(Boolean).join(' '))\n}\n\n/**\n * Returns the discriminator key whose mapping value matches `ref`, or `null` when there is no match.\n *\n * @example\n * ```ts\n * findDiscriminator({ dog: '#/components/schemas/Dog' }, '#/components/schemas/Dog') // 'dog'\n * ```\n */\nexport function findDiscriminator(mapping: Record<string, string> | undefined, ref: string | undefined): string | null {\n if (!mapping || !ref) return null\n return Object.entries(mapping).find(([, value]) => value === ref)?.[0] ?? null\n}\n"],"mappings":"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"} |
| import type { Streamable } from '@internals/utils' | ||
| import type { BaseNode } from './base.ts' | ||
| import type { OperationNode } from './operation.ts' | ||
| import type { SchemaNode } from './schema.ts' | ||
| /** | ||
| * Metadata for an API document, populated by the adapter and available to every generator. | ||
| * | ||
| * All fields are plain JSON-serializable values, no `Set`, no `Map`, no class instances. | ||
| * Computed fields (`circularNames`, `enumNames`) are pre-calculated once during the adapter | ||
| * pre-scan so generators never need to iterate the full schema list themselves. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const meta: InputMeta = { title: 'Pet Store', version: '1.0.0', baseURL: 'https://petstore.swagger.io/v2', circularNames: [], enumNames: [] } | ||
| * ``` | ||
| */ | ||
| export type InputMeta = { | ||
| /** | ||
| * API title from `info.title` in the source document. | ||
| */ | ||
| title?: string | ||
| /** | ||
| * API description from `info.description` in the source document. | ||
| */ | ||
| description?: string | ||
| /** | ||
| * API version string from `info.version` in the source document. | ||
| */ | ||
| version?: string | ||
| /** | ||
| * Resolved base URL from the first matching server entry in the source document. | ||
| */ | ||
| baseURL?: string | null | ||
| /** | ||
| * Names of schemas that participate in a circular reference chain. | ||
| * Computed once during the adapter pre-scan, use this instead of calling | ||
| * `findCircularSchemas` per generator call. | ||
| * | ||
| * Convert to a `Set` once at the start of a generator, not per-schema, | ||
| * to keep lookup O(1) without repeated allocations. | ||
| * | ||
| * @example Wrap a circular schema in z.lazy() | ||
| * ```ts | ||
| * const circular = new Set(meta.circularNames) | ||
| * if (circular.has(schema.name)) { ... } | ||
| * ``` | ||
| */ | ||
| circularNames: ReadonlyArray<string> | ||
| /** | ||
| * Names of schemas whose type is `enum`. | ||
| * Computed once during the adapter pre-scan, use this instead of filtering | ||
| * schemas per generator call. | ||
| * | ||
| * Convert to a `Set` once at the start of a generator when you need repeated | ||
| * membership checks, rather than calling `.includes()` per schema. | ||
| * | ||
| * @example Check if a referenced schema is an enum | ||
| * `const enums = new Set(meta.enumNames)` | ||
| * `const isEnum = enums.has(schemaName)` | ||
| */ | ||
| enumNames: ReadonlyArray<string> | ||
| } | ||
| /** | ||
| * Input AST node that contains all schemas and operations for one API document. | ||
| * Produced by the adapter and consumed by all Kubb plugins. | ||
| * | ||
| * `Stream` switches `schemas` and `operations` between eager `Array`s (the default) and lazy | ||
| * `AsyncIterable`s. The streaming variant `InputNode<true>` yields nodes one at a time and makes | ||
| * `meta` optional, since the adapter can emit metadata before the first node is parsed. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const input: InputNode = { | ||
| * kind: 'Input', | ||
| * schemas: [], | ||
| * operations: [], | ||
| * meta: { circularNames: [], enumNames: [] }, | ||
| * } | ||
| * ``` | ||
| * | ||
| * @example Streaming variant for large specs | ||
| * ```ts | ||
| * for await (const schema of inputNode.schemas) { | ||
| * // only this one SchemaNode is live here. Previous ones are GC-eligible | ||
| * } | ||
| * ``` | ||
| */ | ||
| export type InputNode<Stream extends boolean = false> = BaseNode & { | ||
| /** | ||
| * Node kind. | ||
| */ | ||
| kind: 'Input' | ||
| /** | ||
| * All schema nodes in the document. | ||
| */ | ||
| schemas: Streamable<SchemaNode, Stream> | ||
| /** | ||
| * All operation nodes in the document. | ||
| */ | ||
| operations: Streamable<OperationNode, Stream> | ||
| } & (Stream extends true ? { meta?: InputMeta } : { meta: InputMeta }) |
| import type { BaseNode } from './base.ts' | ||
| import type { ContentNode } from './content.ts' | ||
| /** | ||
| * AST node representing an operation request body. | ||
| * | ||
| * Body schemas live exclusively inside the `content` array (one entry per content type), | ||
| * mirroring {@link ResponseNode}. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const requestBody: RequestBodyNode = { | ||
| * kind: 'RequestBody', | ||
| * required: true, | ||
| * content: [{ kind: 'Content', contentType: 'application/json', schema: createSchema({ type: 'string' }) }], | ||
| * } | ||
| * ``` | ||
| */ | ||
| export type RequestBodyNode = BaseNode & { | ||
| /** | ||
| * Node kind. | ||
| */ | ||
| kind: 'RequestBody' | ||
| /** | ||
| * Human-readable request body description. | ||
| */ | ||
| description?: string | ||
| /** | ||
| * Whether the request body is required (`requestBody.required: true` in the spec). | ||
| * When `false` or absent, the generated `data` parameter should be optional. | ||
| */ | ||
| required?: boolean | ||
| /** | ||
| * All available content type entries for this request body. | ||
| * | ||
| * When the adapter `contentType` option is set, this array contains exactly one entry for | ||
| * that content type. Otherwise it contains one entry per content type declared in the spec, | ||
| * so that plugins can generate code for every variant (e.g. separate hooks for | ||
| * `application/json` and `multipart/form-data`). | ||
| */ | ||
| content?: Array<ContentNode> | ||
| } |
+10
-26
| import { t as __name } from "./chunk-C0LytTxp.js"; | ||
| import { $ as SchemaDialect, $t as TypeNode, A as createFunctionParameter, At as DatetimeSchemaNode, B as createProperty, Bt as SchemaType, C as UserFileNode, Ct as ParamsTypeNode, D as createExport, Dt as SourceNode, E as createConst, Et as ImportNode, F as createOperation, Ft as PrimitiveSchemaType, G as createText, Gt as PropertyNode, H as createSchema, Ht as TimeSchemaNode, I as createOutput, It as RefSchemaNode, J as update, Jt as ConstNode, K as createType, Kt as ArrowFunctionNode, L as createParameter, Lt as ScalarSchemaType, M as createImport, Mt as IntersectionSchemaNode, N as createInput, Nt as NumberSchemaNode, O as createFile, Ot as ArraySchemaNode, P as createJsx, Pt as ObjectSchemaNode, Q as dispatch, Qt as TextNode, R as createParameterGroup, Rt as SchemaNode, S as DistributiveOmit, St as ParameterGroupNode, T as createBreak, Tt as FileNode, U as createSource, Ut as UnionSchemaNode, V as createResponse, Vt as StringSchemaNode, W as createStreamInput, Wt as UrlSchemaNode, X as ParserOptions, Xt as JSDocNode, Y as InferSchemaNode, Yt as FunctionNode, Z as DispatchRule, Zt as JsxNode, _ as Printer, _t as ParameterNode, a as createDiscriminantNode, at as buildDedupePlan, b as createPrinterFactory, bt as FunctionParameterNode, c as findCircularSchemas, ct as InputNode, d as ParentOf, dt as HttpMethod, en as NodeKind, et as defineSchemaDialect, f as Visitor, ft as HttpOperationNode, g as walk, gt as ParameterLocation, h as transform, ht as StatusCode, i as containsCircularRef, it as applyDedupe, j as createFunctionParameters, jt as EnumSchemaNode, k as createFunction, kt as DateSchemaNode, l as isStringType, lt as InputStreamNode, m as collect, mt as ResponseNode, n as caseParams, nn as schemaTypes, nt as DedupeLookups, o as createOperationParams, ot as Node, p as VisitorContext, pt as OperationNode, q as syncOptionality, qt as CodeNode, r as collectUsedSchemaNames, rt as DedupePlan, s as extractStringsFromNodes, st as InputMeta, t as OperationParamsResolver, tn as httpMethods, tt as DedupeCanonical, u as syncSchemaRef, ut as OutputNode, v as PrinterFactoryOptions, vt as FunctionNodeType, w as createArrowFunction, wt as ExportNode, x as definePrinter, xt as FunctionParametersNode, y as PrinterPartial, yt as FunctionParamNode, z as createParamsType, zt as SchemaNodeByType } from "./types-BYujEIxF.js"; | ||
| import { $ as DedupeCanonical, $t as schemaTypes, A as createFunctionParameter, At as NumberSchemaNode, B as createProperty, Bt as UnionSchemaNode, C as UserFileNode, Ct as ImportNode, D as createExport, Dt as DatetimeSchemaNode, E as createConst, Et as DateSchemaNode, F as createOperation, Ft as SchemaNode, G as createText, Gt as ConstNode, H as createSchema, Ht as PropertyNode, I as createOutput, It as SchemaNodeByType, J as update, Jt as JsxNode, K as createType, Kt as FunctionNode, L as createParameter, Lt as SchemaType, M as createImport, Mt as PrimitiveSchemaType, N as createInput, Nt as RefSchemaNode, O as createFile, Ot as EnumSchemaNode, P as createJsx, Pt as ScalarSchemaType, Q as defineSchemaDialect, Qt as httpMethods, R as createParameterGroup, Rt as StringSchemaNode, S as DistributiveOmit, St as FileNode, T as createBreak, Tt as ArraySchemaNode, U as createSource, Ut as ArrowFunctionNode, V as createResponse, Vt as UrlSchemaNode, W as createStreamInput, Wt as CodeNode, X as ParserOptions, Xt as TypeNode, Y as InferSchemaNode, Yt as TextNode, Z as SchemaDialect, Zt as NodeKind, _ as Printer, _t as FunctionParameterNode, a as createDiscriminantNode, at as OutputNode, b as createPrinterFactory, bt as ParamsTypeNode, c as findCircularSchemas, ct as HttpMethod, d as ParentOf, dt as ResponseNode, et as DedupeLookups, f as Visitor, ft as StatusCode, g as walk, gt as FunctionParamNode, h as transform, ht as FunctionNodeType, i as containsCircularRef, it as Node, j as createFunctionParameters, jt as ObjectSchemaNode, k as createFunction, kt as IntersectionSchemaNode, l as isStringType, lt as HttpOperationNode, m as collect, mt as ParameterNode, n as caseParams, nt as applyDedupe, o as createOperationParams, ot as InputMeta, p as VisitorContext, pt as ParameterLocation, q as syncOptionality, qt as JSDocNode, r as collectUsedSchemaNames, rt as buildDedupePlan, s as extractStringsFromNodes, st as InputNode, t as OperationParamsResolver, tt as DedupePlan, u as syncSchemaRef, ut as OperationNode, v as PrinterFactoryOptions, vt as FunctionParametersNode, w as createArrowFunction, wt as SourceNode, x as definePrinter, xt as ExportNode, y as PrinterPartial, yt as ParameterGroupNode, z as createParamsType, zt as TimeSchemaNode } from "./types-BL7RpQAE.js"; | ||
@@ -71,33 +71,17 @@ //#region src/guards.d.ts | ||
| //#endregion | ||
| //#region src/resolvers.d.ts | ||
| /** | ||
| * Collects import entries for all `ref` schema nodes in `node`. | ||
| */ | ||
| declare function collectImports<TImport>({ | ||
| node, | ||
| nameMapping, | ||
| resolve | ||
| }: { | ||
| node: SchemaNode; | ||
| nameMapping: Map<string, string>; | ||
| resolve: (schemaName: string) => TImport | null; | ||
| }): Array<TImport>; | ||
| //#endregion | ||
| //#region src/signature.d.ts | ||
| /** | ||
| * Computes a deterministic, shape-only signature (a fixed-length content hash) for a schema node. | ||
| * Computes a deterministic, shape-only signature (a content hash) for a schema node. Two schemas | ||
| * share a signature when they are structurally identical, ignoring documentation (`name`, `title`, | ||
| * `description`, `example`, `default`, `deprecated`) and usage-slot flags (`optional`, `nullish`, | ||
| * `readOnly`, `writeOnly`). `nullable` is kept because it changes the produced type, and `ref` | ||
| * nodes compare by target name, which also terminates on circular shapes. | ||
| * | ||
| * Two schemas share a signature when they are structurally identical, ignoring | ||
| * documentation (`name`, `title`, `description`, `example`, `default`, `deprecated`) | ||
| * and usage-slot flags (`optional`, `nullish`, `readOnly`, `writeOnly`). `nullable` | ||
| * is kept because it changes the produced type. `ref` nodes compare by target name, | ||
| * which also keeps the algorithm terminating on circular shapes. | ||
| * | ||
| * @example Two enums with different descriptions share a signature | ||
| * ```ts | ||
| * schemaSignature(createSchema({ type: 'enum', primitive: 'string', enumValues: ['a', 'b'], description: 'x' })) === | ||
| * schemaSignature(createSchema({ type: 'enum', primitive: 'string', enumValues: ['a', 'b'] })) | ||
| * signatureOf(createSchema({ type: 'enum', primitive: 'string', enumValues: ['a', 'b'], description: 'x' })) === | ||
| * signatureOf(createSchema({ type: 'enum', primitive: 'string', enumValues: ['a', 'b'] })) | ||
| * ``` | ||
| */ | ||
| declare function schemaSignature(node: SchemaNode): string; | ||
| declare function signatureOf(node: SchemaNode): string; | ||
| //#endregion | ||
@@ -158,3 +142,3 @@ //#region src/transformers.d.ts | ||
| //#endregion | ||
| export { type ArraySchemaNode, type ArrowFunctionNode, type CodeNode, type ConstNode, type DateSchemaNode, type DatetimeSchemaNode, type DedupeCanonical, type DedupeLookups, type DedupePlan, type DispatchRule, type DistributiveOmit, type EnumSchemaNode, type ExportNode, type FileNode, type FunctionNode, type FunctionNodeType, type FunctionParamNode, type FunctionParameterNode, type FunctionParametersNode, type HttpMethod, type HttpOperationNode, type ImportNode, type InferSchemaNode, type InputMeta, type InputNode, type InputStreamNode, type IntersectionSchemaNode, type JSDocNode, type JsxNode, type Node, type NodeKind, type NumberSchemaNode, type ObjectSchemaNode, type OperationNode, type OperationParamsResolver, type OutputNode, type ParameterGroupNode, type ParameterLocation, type ParameterNode, type ParamsTypeNode, type ParentOf, type ParserOptions, type PrimitiveSchemaType, type Printer, type PrinterFactoryOptions, type PrinterPartial, type PropertyNode, type RefSchemaNode, type ResponseNode, type ScalarSchemaType, type SchemaDialect, type SchemaNode, type SchemaNodeByType, type SchemaType, type SourceNode, type StatusCode, type StringSchemaNode, type TextNode, type TimeSchemaNode, type TypeNode, type UnionSchemaNode, type UrlSchemaNode, type UserFileNode, type Visitor, type VisitorContext, applyDedupe, buildDedupePlan, caseParams, collect, collectImports, collectUsedSchemaNames, containsCircularRef, createArrowFunction, createBreak, createConst, createDiscriminantNode, createExport, createFile, createFunction, createFunctionParameter, createFunctionParameters, createImport, createInput, createJsx, createOperation, createOperationParams, createOutput, createParameter, createParameterGroup, createParamsType, createPrinterFactory, createProperty, createResponse, createSchema, createSource, createStreamInput, createText, createType, definePrinter, defineSchemaDialect, dispatch, extractStringsFromNodes, findCircularSchemas, httpMethods, isHttpOperationNode, isInputNode, isOperationNode, isOutputNode, isSchemaNode, isStringType, mergeAdjacentObjectsLazy, narrowSchema, schemaSignature, schemaTypes, setDiscriminatorEnum, setEnumName, simplifyUnion, syncOptionality, syncSchemaRef, transform, update, walk }; | ||
| export { type ArraySchemaNode, type ArrowFunctionNode, type CodeNode, type ConstNode, type DateSchemaNode, type DatetimeSchemaNode, type DedupeCanonical, type DedupeLookups, type DedupePlan, type DistributiveOmit, type EnumSchemaNode, type ExportNode, type FileNode, type FunctionNode, type FunctionNodeType, type FunctionParamNode, type FunctionParameterNode, type FunctionParametersNode, type HttpMethod, type HttpOperationNode, type ImportNode, type InferSchemaNode, type InputMeta, type InputNode, type IntersectionSchemaNode, type JSDocNode, type JsxNode, type Node, type NodeKind, type NumberSchemaNode, type ObjectSchemaNode, type OperationNode, type OperationParamsResolver, type OutputNode, type ParameterGroupNode, type ParameterLocation, type ParameterNode, type ParamsTypeNode, type ParentOf, type ParserOptions, type PrimitiveSchemaType, type Printer, type PrinterFactoryOptions, type PrinterPartial, type PropertyNode, type RefSchemaNode, type ResponseNode, type ScalarSchemaType, type SchemaDialect, type SchemaNode, type SchemaNodeByType, type SchemaType, type SourceNode, type StatusCode, type StringSchemaNode, type TextNode, type TimeSchemaNode, type TypeNode, type UnionSchemaNode, type UrlSchemaNode, type UserFileNode, type Visitor, type VisitorContext, applyDedupe, buildDedupePlan, caseParams, collect, collectUsedSchemaNames, containsCircularRef, createArrowFunction, createBreak, createConst, createDiscriminantNode, createExport, createFile, createFunction, createFunctionParameter, createFunctionParameters, createImport, createInput, createJsx, createOperation, createOperationParams, createOutput, createParameter, createParameterGroup, createParamsType, createPrinterFactory, createProperty, createResponse, createSchema, createSource, createStreamInput, createText, createType, definePrinter, defineSchemaDialect, extractStringsFromNodes, findCircularSchemas, httpMethods, isHttpOperationNode, isInputNode, isOperationNode, isOutputNode, isSchemaNode, isStringType, mergeAdjacentObjectsLazy, narrowSchema, schemaTypes, setDiscriminatorEnum, setEnumName, signatureOf, simplifyUnion, syncOptionality, syncSchemaRef, transform, update, walk }; | ||
| //# sourceMappingURL=index.d.ts.map |
+2
-2
@@ -1,2 +0,2 @@ | ||
| import { $ as SchemaDialect, $t as TypeNode, At as DatetimeSchemaNode, Bt as SchemaType, C as UserFileNode, Ct as ParamsTypeNode, Dt as SourceNode, Et as ImportNode, Ft as PrimitiveSchemaType, Gt as PropertyNode, Ht as TimeSchemaNode, It as RefSchemaNode, Jt as ConstNode, Kt as ArrowFunctionNode, Lt as ScalarSchemaType, Mt as IntersectionSchemaNode, Nt as NumberSchemaNode, Ot as ArraySchemaNode, Pt as ObjectSchemaNode, Qt as TextNode, Rt as SchemaNode, S as DistributiveOmit, St as ParameterGroupNode, Tt as FileNode, Ut as UnionSchemaNode, Vt as StringSchemaNode, Wt as UrlSchemaNode, X as ParserOptions, Xt as JSDocNode, Y as InferSchemaNode, Yt as FunctionNode, Z as DispatchRule, Zt as JsxNode, _ as Printer, _t as ParameterNode, bt as FunctionParameterNode, ct as InputNode, d as ParentOf, dt as HttpMethod, en as NodeKind, f as Visitor, ft as HttpOperationNode, gt as ParameterLocation, ht as StatusCode, jt as EnumSchemaNode, kt as DateSchemaNode, lt as InputStreamNode, mt as ResponseNode, nt as DedupeLookups, ot as Node, p as VisitorContext, pt as OperationNode, qt as CodeNode, rt as DedupePlan, st as InputMeta, t as OperationParamsResolver, tt as DedupeCanonical, ut as OutputNode, v as PrinterFactoryOptions, vt as FunctionNodeType, wt as ExportNode, xt as FunctionParametersNode, y as PrinterPartial, yt as FunctionParamNode, zt as SchemaNodeByType } from "./types-BYujEIxF.js"; | ||
| export type { ArraySchemaNode, ArrowFunctionNode, CodeNode, ConstNode, DateSchemaNode, DatetimeSchemaNode, DedupeCanonical, DedupeLookups, DedupePlan, DispatchRule, DistributiveOmit, EnumSchemaNode, ExportNode, FileNode, FunctionNode, FunctionNodeType, FunctionParamNode, FunctionParameterNode, FunctionParametersNode, HttpMethod, HttpOperationNode, ImportNode, InferSchemaNode, InputMeta, InputNode, InputStreamNode, IntersectionSchemaNode, JSDocNode, JsxNode, Node, NodeKind, NumberSchemaNode, ObjectSchemaNode, OperationNode, OperationParamsResolver, OutputNode, ParameterGroupNode, ParameterLocation, ParameterNode, ParamsTypeNode, ParentOf, ParserOptions, PrimitiveSchemaType, Printer, PrinterFactoryOptions, PrinterPartial, PropertyNode, RefSchemaNode, ResponseNode, ScalarSchemaType, SchemaDialect, SchemaNode, SchemaNodeByType, SchemaType, SourceNode, StatusCode, StringSchemaNode, TextNode, TimeSchemaNode, TypeNode, UnionSchemaNode, UrlSchemaNode, UserFileNode, Visitor, VisitorContext }; | ||
| import { $ as DedupeCanonical, At as NumberSchemaNode, Bt as UnionSchemaNode, C as UserFileNode, Ct as ImportNode, Dt as DatetimeSchemaNode, Et as DateSchemaNode, Ft as SchemaNode, Gt as ConstNode, Ht as PropertyNode, It as SchemaNodeByType, Jt as JsxNode, Kt as FunctionNode, Lt as SchemaType, Mt as PrimitiveSchemaType, Nt as RefSchemaNode, Ot as EnumSchemaNode, Pt as ScalarSchemaType, Rt as StringSchemaNode, S as DistributiveOmit, St as FileNode, Tt as ArraySchemaNode, Ut as ArrowFunctionNode, Vt as UrlSchemaNode, Wt as CodeNode, X as ParserOptions, Xt as TypeNode, Y as InferSchemaNode, Yt as TextNode, Z as SchemaDialect, Zt as NodeKind, _ as Printer, _t as FunctionParameterNode, at as OutputNode, bt as ParamsTypeNode, ct as HttpMethod, d as ParentOf, dt as ResponseNode, et as DedupeLookups, f as Visitor, ft as StatusCode, gt as FunctionParamNode, ht as FunctionNodeType, it as Node, jt as ObjectSchemaNode, kt as IntersectionSchemaNode, lt as HttpOperationNode, mt as ParameterNode, ot as InputMeta, p as VisitorContext, pt as ParameterLocation, qt as JSDocNode, st as InputNode, t as OperationParamsResolver, tt as DedupePlan, ut as OperationNode, v as PrinterFactoryOptions, vt as FunctionParametersNode, wt as SourceNode, xt as ExportNode, y as PrinterPartial, yt as ParameterGroupNode, zt as TimeSchemaNode } from "./types-BL7RpQAE.js"; | ||
| export type { ArraySchemaNode, ArrowFunctionNode, CodeNode, ConstNode, DateSchemaNode, DatetimeSchemaNode, DedupeCanonical, DedupeLookups, DedupePlan, DistributiveOmit, EnumSchemaNode, ExportNode, FileNode, FunctionNode, FunctionNodeType, FunctionParamNode, FunctionParameterNode, FunctionParametersNode, HttpMethod, HttpOperationNode, ImportNode, InferSchemaNode, InputMeta, InputNode, IntersectionSchemaNode, JSDocNode, JsxNode, Node, NodeKind, NumberSchemaNode, ObjectSchemaNode, OperationNode, OperationParamsResolver, OutputNode, ParameterGroupNode, ParameterLocation, ParameterNode, ParamsTypeNode, ParentOf, ParserOptions, PrimitiveSchemaType, Printer, PrinterFactoryOptions, PrinterPartial, PropertyNode, RefSchemaNode, ResponseNode, ScalarSchemaType, SchemaDialect, SchemaNode, SchemaNodeByType, SchemaType, SourceNode, StatusCode, StringSchemaNode, TextNode, TimeSchemaNode, TypeNode, UnionSchemaNode, UrlSchemaNode, UserFileNode, Visitor, VisitorContext }; |
+1
-2
| Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); | ||
| const require_utils = require("./utils-CMRZrT-w.cjs"); | ||
| const require_utils = require("./utils-cdQ6Pzyi.cjs"); | ||
| exports.buildJSDoc = require_utils.buildJSDoc; | ||
@@ -7,3 +7,2 @@ exports.buildList = require_utils.buildList; | ||
| exports.childName = require_utils.childName; | ||
| exports.ensureValidVarName = require_utils.ensureValidVarName; | ||
| exports.enumPropName = require_utils.enumPropName; | ||
@@ -10,0 +9,0 @@ exports.extractRefName = require_utils.extractRefName; |
+1
-14
@@ -15,15 +15,2 @@ import { t as __name } from "./chunk-C0LytTxp.js"; | ||
| declare function isValidVarName(name: string): boolean; | ||
| /** | ||
| * Returns `name` when it is already a valid JavaScript variable name, otherwise prefixes it with `_` | ||
| * so the result can be used as an identifier. Useful for sanitizing schema names or operation IDs | ||
| * that start with a digit (`409`, `504AccountCancel`) or collide with a reserved word. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * ensureValidVarName('409') // '_409' | ||
| * ensureValidVarName('Pet') // 'Pet' | ||
| * ensureValidVarName('class') // '_class' | ||
| * ``` | ||
| */ | ||
| declare function ensureValidVarName(name: string): string; | ||
| //#endregion | ||
@@ -205,3 +192,3 @@ //#region src/utils/index.d.ts | ||
| //#endregion | ||
| export { buildJSDoc, buildList, buildObject, childName, ensureValidVarName, enumPropName, extractRefName, findDiscriminator, getNestedAccessor, isValidVarName, jsStringEscape, objectKey, stringify, stringifyObject, toRegExpString, trimQuotes }; | ||
| export { buildJSDoc, buildList, buildObject, childName, enumPropName, extractRefName, findDiscriminator, getNestedAccessor, isValidVarName, jsStringEscape, objectKey, stringify, stringifyObject, toRegExpString, trimQuotes }; | ||
| //# sourceMappingURL=utils.d.ts.map |
+2
-2
@@ -1,2 +0,2 @@ | ||
| import { _ as isValidVarName, a as enumPropName, c as getNestedAccessor, d as stringify, f as stringifyObject, g as ensureValidVarName, i as childName, l as jsStringEscape, m as trimQuotes, n as buildList, o as extractRefName, p as toRegExpString, r as buildObject, s as findDiscriminator, t as buildJSDoc, u as objectKey } from "./utils-BIcKgbbc.js"; | ||
| export { buildJSDoc, buildList, buildObject, childName, ensureValidVarName, enumPropName, extractRefName, findDiscriminator, getNestedAccessor, isValidVarName, jsStringEscape, objectKey, stringify, stringifyObject, toRegExpString, trimQuotes }; | ||
| import { a as enumPropName, c as getNestedAccessor, d as stringify, f as stringifyObject, h as isValidVarName, i as childName, l as jsStringEscape, m as trimQuotes, n as buildList, o as extractRefName, p as toRegExpString, r as buildObject, s as findDiscriminator, t as buildJSDoc, u as objectKey } from "./utils-0p8ZO287.js"; | ||
| export { buildJSDoc, buildList, buildObject, childName, enumPropName, extractRefName, findDiscriminator, getNestedAccessor, isValidVarName, jsStringEscape, objectKey, stringify, stringifyObject, toRegExpString, trimQuotes }; |
+1
-1
| { | ||
| "name": "@kubb/ast", | ||
| "version": "5.0.0-beta.54", | ||
| "version": "5.0.0-beta.55", | ||
| "description": "Spec-agnostic AST layer for Kubb. Defines the node tree, visitor pattern, factory functions, and type guards used across all code generation plugins.", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
+23
-28
| /** | ||
| * The spec-specific decisions a schema parser makes when converting a source document's schemas | ||
| * into Kubb AST nodes. Everything else in an adapter's schema pipeline is generic JSON Schema, | ||
| * shared across specs, so the dialect is the one seam where specs differ, like a database driver | ||
| * targeting Postgres vs MySQL. Pair it with {@link dispatch}: the rule table picks which converter | ||
| * runs, the dialect answers the spec-specific questions inside it. | ||
| * | ||
| * The guards (`isReference`, `isDiscriminator`) are type predicates, so converters narrow the | ||
| * schema after a check and the type parameters carry the narrowed types through. | ||
| * | ||
| * This is the seam for the JSON Schema family: OpenAPI, AsyncAPI, and plain JSON Schema share | ||
| * `$ref`, `allOf`/`oneOf`, `enum`, and `format` and differ only in these few decisions. A spec on | ||
| * a different type system (GraphQL, with non-null wrappers and named-type references instead of | ||
| * `$ref`) skips `SchemaDialect` and reuses the universal layer directly: the `Adapter` port, the | ||
| * AST factories, and {@link dispatch} with its own rule table. | ||
| * | ||
| * @typeParam TSchema - The adapter's schema object type (e.g. an OpenAPI `SchemaObject`). | ||
| * @typeParam TRef - The narrowed `$ref` pointer type `isReference` proves. | ||
| * @typeParam TDiscriminated - The narrowed discriminated-schema type `isDiscriminator` proves. | ||
| * @typeParam TDocument - The source document `resolveRef` resolves against. | ||
| * The spec-specific questions a schema parser answers while turning a source document into Kubb | ||
| * AST nodes. The rest of the pipeline is generic JSON Schema, so this is the one seam where | ||
| * OpenAPI, AsyncAPI, and plain JSON Schema differ. | ||
| */ | ||
| export type SchemaDialect<TSchema = unknown, TRef = TSchema, TDiscriminated = TSchema, TDocument = unknown> = { | ||
| /** Identifies the dialect in logs and while debugging dispatch. */ | ||
| /** | ||
| * Identifies the dialect in logs and diagnostics. | ||
| */ | ||
| name: string | ||
| /** Whether a schema should be treated as nullable. */ | ||
| /** | ||
| * Whether the schema is nullable. | ||
| */ | ||
| isNullable: (schema?: TSchema) => boolean | ||
| /** Whether a value is a `$ref` pointer object. */ | ||
| /** | ||
| * Whether the value is a `$ref` pointer. | ||
| */ | ||
| isReference: (value?: unknown) => value is TRef | ||
| /** Whether a schema carries a structured discriminator (polymorphism). */ | ||
| /** | ||
| * Whether the schema carries a discriminator for polymorphism. | ||
| */ | ||
| isDiscriminator: (value?: unknown) => value is TDiscriminated | ||
| /** Whether a schema represents binary data (converted to a `blob` node). */ | ||
| /** | ||
| * Whether the schema is binary data, converted to a `blob` node. | ||
| */ | ||
| isBinary: (schema: TSchema) => boolean | ||
| /** Resolves a local `$ref` pointer against the document, or nullish when it cannot. */ | ||
| /** | ||
| * Resolves a local `$ref` against the document, or nullish when it cannot. | ||
| */ | ||
| resolveRef: <TResolved>(document: TDocument, ref: string) => TResolved | null | undefined | ||
@@ -38,5 +34,4 @@ } | ||
| /** | ||
| * Identity helper that types a {@link SchemaDialect} for an adapter. Like | ||
| * `defineParser`, it adds no runtime behavior, it pins the dialect's type for | ||
| * inference and gives adapter authors a discoverable anchor. | ||
| * Types a {@link SchemaDialect} for an adapter. Adds no runtime behavior and only pins the | ||
| * dialect's type for inference. | ||
| * | ||
@@ -43,0 +38,0 @@ * @example |
+2
-3
@@ -20,3 +20,2 @@ import { hash } from 'node:crypto' | ||
| InputNode, | ||
| InputStreamNode, | ||
| JsxNode, | ||
@@ -131,3 +130,3 @@ Node, | ||
| /** | ||
| * Creates an `InputStreamNode` from pre-built `AsyncIterable` sources. | ||
| * Creates a streaming `InputNode<true>` from pre-built `AsyncIterable` sources. | ||
| * | ||
@@ -139,3 +138,3 @@ * @example | ||
| */ | ||
| export function createStreamInput(schemas: AsyncIterable<SchemaNode>, operations: AsyncIterable<OperationNode>, meta?: InputMeta): InputStreamNode { | ||
| export function createStreamInput(schemas: AsyncIterable<SchemaNode>, operations: AsyncIterable<OperationNode>, meta?: InputMeta): InputNode<true> { | ||
| return { kind: 'Input', schemas, operations, meta } | ||
@@ -142,0 +141,0 @@ } |
+1
-3
| export { httpMethods, schemaTypes } from './constants.ts' | ||
| export { applyDedupe, buildDedupePlan } from './dedupe.ts' | ||
| export { defineSchemaDialect } from './dialect.ts' | ||
| export { dispatch } from './dispatch.ts' | ||
| export { | ||
@@ -34,4 +33,3 @@ createArrowFunction, | ||
| export { createPrinterFactory, definePrinter } from './printer.ts' | ||
| export { collectImports } from './resolvers.ts' | ||
| export { schemaSignature } from './signature.ts' | ||
| export { signatureOf } from './signature.ts' | ||
| export { mergeAdjacentObjectsLazy, setDiscriminatorEnum, setEnumName, simplifyUnion } from './transformers.ts' | ||
@@ -38,0 +36,0 @@ export type * from './types.ts' |
+1
-1
| import { createInput, createOperation, createParameter, createProperty, createResponse, createSchema } from './factory.ts' | ||
| import type { InputNode } from './nodes/root.ts' | ||
| import type { InputNode } from './nodes/input.ts' | ||
@@ -4,0 +4,0 @@ /** |
@@ -5,8 +5,9 @@ import type { ArrowFunctionNode, ConstNode, FunctionNode, TypeNode } from './code.ts' | ||
| import type { FunctionParamNode, ParamsTypeNode } from './function.ts' | ||
| import type { OperationNode, RequestBodyNode } from './operation.ts' | ||
| import type { InputNode } from './input.ts' | ||
| import type { OperationNode } from './operation.ts' | ||
| import type { OutputNode } from './output.ts' | ||
| import type { ParameterNode } from './parameter.ts' | ||
| import type { PropertyNode } from './property.ts' | ||
| import type { RequestBodyNode } from './requestBody.ts' | ||
| import type { ResponseNode } from './response.ts' | ||
| import type { InputNode } from './root.ts' | ||
| import type { SchemaNode } from './schema.ts' | ||
@@ -20,8 +21,9 @@ | ||
| export type { StatusCode } from './http.ts' | ||
| export type { GenericOperationNode, HttpMethod, HttpOperationNode, OperationNode, RequestBodyNode } from './operation.ts' | ||
| export type { InputMeta, InputNode } from './input.ts' | ||
| export type { GenericOperationNode, HttpMethod, HttpOperationNode, OperationNode } from './operation.ts' | ||
| export type { OutputNode } from './output.ts' | ||
| export type { ParameterLocation, ParameterNode } from './parameter.ts' | ||
| export type { PropertyNode } from './property.ts' | ||
| export type { RequestBodyNode } from './requestBody.ts' | ||
| export type { ResponseNode } from './response.ts' | ||
| export type { InputMeta, InputNode, InputStreamNode } from './root.ts' | ||
| export type { | ||
@@ -28,0 +30,0 @@ ArraySchemaNode, |
| import type { BaseNode } from './base.ts' | ||
| import type { ContentNode } from './content.ts' | ||
| import type { ParameterNode } from './parameter.ts' | ||
| import type { RequestBodyNode } from './requestBody.ts' | ||
| import type { ResponseNode } from './response.ts' | ||
@@ -14,42 +14,2 @@ | ||
| /** | ||
| * AST node representing an operation request body. | ||
| * | ||
| * Body schemas live exclusively inside the `content` array (one entry per content type), | ||
| * mirroring {@link ResponseNode}. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const requestBody: RequestBodyNode = { | ||
| * kind: 'RequestBody', | ||
| * required: true, | ||
| * content: [{ kind: 'Content', contentType: 'application/json', schema: createSchema({ type: 'string' }) }], | ||
| * } | ||
| * ``` | ||
| */ | ||
| export type RequestBodyNode = BaseNode & { | ||
| /** | ||
| * Node kind. | ||
| */ | ||
| kind: 'RequestBody' | ||
| /** | ||
| * Human-readable request body description. | ||
| */ | ||
| description?: string | ||
| /** | ||
| * Whether the request body is required (`requestBody.required: true` in the spec). | ||
| * When `false` or absent, the generated `data` parameter should be optional. | ||
| */ | ||
| required?: boolean | ||
| /** | ||
| * All available content type entries for this request body. | ||
| * | ||
| * When the adapter `contentType` option is set, this array contains exactly one entry for | ||
| * that content type. Otherwise it contains one entry per content type declared in the spec, | ||
| * so that plugins can generate code for every variant (e.g. separate hooks for | ||
| * `application/json` and `multipart/form-data`). | ||
| */ | ||
| content?: Array<ContentNode> | ||
| } | ||
| /** | ||
| * Fields shared by every operation, regardless of transport. | ||
@@ -56,0 +16,0 @@ */ |
+23
-48
@@ -6,5 +6,3 @@ import { hash } from 'node:crypto' | ||
| /** | ||
| * The shape-affecting flags shared by every node kind: base primitive, format, and `nullable`. | ||
| * Documentation and usage-slot flags (`optional`/`nullish`/`readOnly`/`writeOnly`) are | ||
| * intentionally excluded, they describe the property slot, not the type. | ||
| * The flags shared by every node kind that affect its type: `primitive`, `format`, `nullable`. | ||
| */ | ||
@@ -63,5 +61,4 @@ function flagsDescriptor(node: SchemaNode): string { | ||
| /** | ||
| * Maps each schema node `type` to the ordered list of shape-contributing fields. | ||
| * Node types absent from this map (scalar types like boolean, null, any, etc.) fall | ||
| * back to `${type}|${flags}` with no additional fields. | ||
| * Maps each node `type` to its ordered shape-contributing fields. Types absent from the map | ||
| * (boolean, null, any, and other scalars) fall back to `${type}|${flags}`. | ||
| */ | ||
@@ -161,5 +158,4 @@ const SHAPE_KEYS: Partial<Record<SchemaNode['type'], ReadonlyArray<ShapeField>>> = { | ||
| /** | ||
| * Builds the local, shape-only descriptor for a node: its kind, flags, constraints, and its | ||
| * children's signatures. {@link signatureOf} hashes this string. Children contribute their | ||
| * fixed-length signature rather than their own full descriptor, which keeps the result bounded. | ||
| * Builds the local shape descriptor that {@link signatureOf} hashes: the node's kind, flags, | ||
| * constraints, and its children's signatures. | ||
| */ | ||
@@ -180,9 +176,5 @@ function describeShape(node: SchemaNode): string { | ||
| /** | ||
| * Persistent hash-consing cache: `SchemaNode` → signature digest, keyed by node identity. | ||
| * | ||
| * A `WeakMap` so entries are released once the node is garbage-collected, and so a node hashed | ||
| * during dedupe planning is not re-hashed when the same tree is rewritten during streaming | ||
| * (where `schemaSignature` and `applyDedupe` would otherwise each walk it from scratch). Reuse | ||
| * across calls is sound because a signature depends only on a node's content, and schema nodes | ||
| * are immutable once created, transforms allocate new objects rather than mutating in place. | ||
| * Node → digest cache, keyed by identity. A `WeakMap` so entries die with the node, and so a tree | ||
| * hashed during dedupe planning is not walked again when it is rewritten during streaming. Reuse | ||
| * is safe because a signature depends only on content, and nodes are immutable once created. | ||
| */ | ||
@@ -192,8 +184,13 @@ const signatureCache = new WeakMap<SchemaNode, string>() | ||
| /** | ||
| * Hash-consing: each node's signature is a fixed-length digest of its local shape plus its | ||
| * children's digests (a Merkle hash). Children contribute their 64-char hash instead of their | ||
| * full nested descriptor, so a signature stays bounded regardless of subtree depth, and the | ||
| * digest is identical across calls because it depends only on content, never on traversal | ||
| * order. This keeps the keys built during planning consistent with the ones recomputed later | ||
| * during streaming. {@link signatureCache} memoizes node → digest across every computation. | ||
| * Computes a deterministic, shape-only signature (a content hash) for a schema node. Two schemas | ||
| * share a signature when they are structurally identical, ignoring documentation (`name`, `title`, | ||
| * `description`, `example`, `default`, `deprecated`) and usage-slot flags (`optional`, `nullish`, | ||
| * `readOnly`, `writeOnly`). `nullable` is kept because it changes the produced type, and `ref` | ||
| * nodes compare by target name, which also terminates on circular shapes. | ||
| * | ||
| * @example Two enums with different descriptions share a signature | ||
| * ```ts | ||
| * signatureOf(createSchema({ type: 'enum', primitive: 'string', enumValues: ['a', 'b'], description: 'x' })) === | ||
| * signatureOf(createSchema({ type: 'enum', primitive: 'string', enumValues: ['a', 'b'] })) | ||
| * ``` | ||
| */ | ||
@@ -205,2 +202,3 @@ export function signatureOf(node: SchemaNode): string { | ||
| signatureCache.set(node, signature) | ||
| return signature | ||
@@ -210,30 +208,7 @@ } | ||
| /** | ||
| * Computes a deterministic, shape-only signature (a fixed-length content hash) for a schema node. | ||
| * | ||
| * Two schemas share a signature when they are structurally identical, ignoring | ||
| * documentation (`name`, `title`, `description`, `example`, `default`, `deprecated`) | ||
| * and usage-slot flags (`optional`, `nullish`, `readOnly`, `writeOnly`). `nullable` | ||
| * is kept because it changes the produced type. `ref` nodes compare by target name, | ||
| * which also keeps the algorithm terminating on circular shapes. | ||
| * | ||
| * @example Two enums with different descriptions share a signature | ||
| * ```ts | ||
| * schemaSignature(createSchema({ type: 'enum', primitive: 'string', enumValues: ['a', 'b'], description: 'x' })) === | ||
| * schemaSignature(createSchema({ type: 'enum', primitive: 'string', enumValues: ['a', 'b'] })) | ||
| * ``` | ||
| * Returns `true` when two schema nodes are structurally identical under shape-only equality, | ||
| * meaning they produce the same TypeScript type. | ||
| */ | ||
| export function schemaSignature(node: SchemaNode): string { | ||
| return signatureOf(node) | ||
| } | ||
| /** | ||
| * Returns `true` when two schema nodes are structurally identical under shape-only equality. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * isSchemaEqual(a, b) // a and b produce the same TypeScript type | ||
| * ``` | ||
| */ | ||
| export function isSchemaEqual(a: SchemaNode, b: SchemaNode): boolean { | ||
| return schemaSignature(a) === schemaSignature(b) | ||
| return signatureOf(a) === signatureOf(b) | ||
| } |
+0
-2
| export type { DedupeCanonical, DedupeLookups, DedupePlan } from './dedupe.ts' | ||
| export type { SchemaDialect } from './dialect.ts' | ||
| export type { DispatchRule } from './dispatch.ts' | ||
| export type { DistributiveOmit } from './factory.ts' | ||
@@ -26,3 +25,2 @@ export type { InferSchemaNode, ParserOptions } from './infer.ts' | ||
| InputNode, | ||
| InputStreamNode, | ||
| IntersectionSchemaNode, | ||
@@ -29,0 +27,0 @@ JSDocNode, |
| import { isIdentifier, pascalCase, singleQuote } from '@internals/utils' | ||
| import { INDENT } from '../constants.ts' | ||
| export { ensureValidVarName, isValidVarName } from '@internals/utils' | ||
| export { isValidVarName } from '@internals/utils' | ||
@@ -222,2 +222,3 @@ /** | ||
| const body = entries.map((entry) => `${indentLines(entry)},`).join('\n') | ||
| return `{\n${body}\n}` | ||
@@ -243,2 +244,3 @@ } | ||
| const body = items.map((item) => `${indentLines(item)},`).join('\n') | ||
| return `${open}\n${body}\n${close}` | ||
@@ -245,0 +247,0 @@ } |
Sorry, the diff of this file is too big to display
| import "./chunk-C0LytTxp.js"; | ||
| //#region src/constants.ts | ||
| const visitorDepths = { | ||
| shallow: "shallow", | ||
| deep: "deep" | ||
| }; | ||
| /** | ||
| * Schema type discriminators used by all AST schema nodes. | ||
| * | ||
| * These values serve as stable discriminators across the AST (e.g., `schema.type === schemaTypes.object`). | ||
| * Grouped by category: primitives (`string`, `number`, `boolean`), structural types (`object`, `array`, `union`), | ||
| * and format-specific types (`date`, `uuid`, `email`). Use `isScalarPrimitive()` to check for scalar types. | ||
| */ | ||
| const schemaTypes = { | ||
| /** | ||
| * Text value. | ||
| */ | ||
| string: "string", | ||
| /** | ||
| * Floating-point number (`float`, `double`). | ||
| */ | ||
| number: "number", | ||
| /** | ||
| * Whole number (`int32`). Use `bigint` for `int64`. | ||
| */ | ||
| integer: "integer", | ||
| /** | ||
| * 64-bit integer (`int64`). Only used when `integerType` is set to `'bigint'`. | ||
| */ | ||
| bigint: "bigint", | ||
| /** | ||
| * Boolean value | ||
| */ | ||
| boolean: "boolean", | ||
| /** | ||
| * Explicit null value. | ||
| */ | ||
| null: "null", | ||
| /** | ||
| * Any value (no type restriction). | ||
| */ | ||
| any: "any", | ||
| /** | ||
| * Unknown value (must be narrowed before usage). | ||
| */ | ||
| unknown: "unknown", | ||
| /** | ||
| * No return value (`void`). | ||
| */ | ||
| void: "void", | ||
| /** | ||
| * Object with named properties. | ||
| */ | ||
| object: "object", | ||
| /** | ||
| * Sequential list of items. | ||
| */ | ||
| array: "array", | ||
| /** | ||
| * Fixed-length list with position-specific items. | ||
| */ | ||
| tuple: "tuple", | ||
| /** | ||
| * "One of" multiple schema members. | ||
| */ | ||
| union: "union", | ||
| /** | ||
| * "All of" multiple schema members. | ||
| */ | ||
| intersection: "intersection", | ||
| /** | ||
| * Enum schema. | ||
| */ | ||
| enum: "enum", | ||
| /** | ||
| * Reference to another schema. | ||
| */ | ||
| ref: "ref", | ||
| /** | ||
| * Calendar date (for example `2026-03-24`). | ||
| */ | ||
| date: "date", | ||
| /** | ||
| * Date-time value (for example `2026-03-24T09:00:00Z`). | ||
| */ | ||
| datetime: "datetime", | ||
| /** | ||
| * Time-only value (for example `09:00:00`). | ||
| */ | ||
| time: "time", | ||
| /** | ||
| * UUID value. | ||
| */ | ||
| uuid: "uuid", | ||
| /** | ||
| * Email address value. | ||
| */ | ||
| email: "email", | ||
| /** | ||
| * URL value. | ||
| */ | ||
| url: "url", | ||
| /** | ||
| * IPv4 address value. | ||
| */ | ||
| ipv4: "ipv4", | ||
| /** | ||
| * IPv6 address value. | ||
| */ | ||
| ipv6: "ipv6", | ||
| /** | ||
| * Binary/blob value. | ||
| */ | ||
| blob: "blob", | ||
| /** | ||
| * Impossible value (`never`). | ||
| */ | ||
| never: "never" | ||
| }; | ||
| /** | ||
| * Scalar primitive schema types used for union simplification and type narrowing. | ||
| * | ||
| * Use `isScalarPrimitive()` to safely check whether a type is a scalar primitive. | ||
| */ | ||
| const SCALAR_PRIMITIVE_TYPES = new Set([ | ||
| "string", | ||
| "number", | ||
| "integer", | ||
| "bigint", | ||
| "boolean" | ||
| ]); | ||
| /** | ||
| * Type guard that returns `true` when `type` is a scalar primitive schema type. | ||
| * | ||
| * Use this to check if a schema type can be directly assigned without wrapping (e.g., `string | number | boolean`). | ||
| */ | ||
| function isScalarPrimitive(type) { | ||
| return SCALAR_PRIMITIVE_TYPES.has(type); | ||
| } | ||
| /** | ||
| * HTTP method identifiers used by operation nodes. | ||
| * | ||
| * Includes all standard HTTP methods (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, TRACE). | ||
| */ | ||
| const httpMethods = { | ||
| get: "GET", | ||
| post: "POST", | ||
| put: "PUT", | ||
| patch: "PATCH", | ||
| delete: "DELETE", | ||
| head: "HEAD", | ||
| options: "OPTIONS", | ||
| trace: "TRACE" | ||
| }; | ||
| /** | ||
| * One indentation level, derived from {@link INDENT_SIZE}. | ||
| */ | ||
| const INDENT = Array.from({ length: 2 }, () => " ").join(""); | ||
| //#endregion | ||
| //#region ../../internals/utils/src/casing.ts | ||
| /** | ||
| * Shared implementation for camelCase and PascalCase conversion. | ||
| * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons) | ||
| * and capitalizes each word according to `pascal`. | ||
| * | ||
| * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are. | ||
| */ | ||
| function toCamelOrPascal(text, pascal) { | ||
| return text.trim().replace(/([a-z\d])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/(\d)([a-z])/g, "$1 $2").split(/[\s\-_./\\:]+/).filter(Boolean).map((word, i) => { | ||
| if (word.length > 1 && word === word.toUpperCase()) return word; | ||
| if (i === 0 && !pascal) return word.charAt(0).toLowerCase() + word.slice(1); | ||
| return word.charAt(0).toUpperCase() + word.slice(1); | ||
| }).join("").replace(/[^a-zA-Z0-9]/g, ""); | ||
| } | ||
| /** | ||
| * Splits `text` on `.` and applies `transformPart` to each segment. | ||
| * The last segment receives `isLast = true`, all earlier segments receive `false`. | ||
| * Segments are joined with `/` to form a file path. | ||
| * | ||
| * Only splits on dots followed by a letter so that version numbers | ||
| * embedded in operationIds (e.g. `v2025.0`) are kept intact. | ||
| * | ||
| * Empty segments are filtered before joining. They arise when the text starts with | ||
| * a dot followed immediately by a letter (e.g. `..Schema` splits into `['..', 'Schema']` | ||
| * and `'..'` transforms to an empty string). Without this filter the join would produce | ||
| * a leading `/`, which `path.resolve` would interpret as an absolute path, allowing | ||
| * generated files to escape the configured output directory. | ||
| */ | ||
| function applyToFileParts(text, transformPart) { | ||
| const parts = text.split(/\.(?=[a-zA-Z])/); | ||
| return parts.map((part, i) => transformPart(part, i === parts.length - 1)).filter(Boolean).join("/"); | ||
| } | ||
| /** | ||
| * Converts `text` to camelCase. | ||
| * When `isFile` is `true`, dot-separated segments are each cased independently and joined with `/`. | ||
| * | ||
| * @example | ||
| * camelCase('hello-world') // 'helloWorld' | ||
| * camelCase('pet.petId', { isFile: true }) // 'pet/petId' | ||
| */ | ||
| function camelCase(text, { isFile, prefix = "", suffix = "" } = {}) { | ||
| if (isFile) return applyToFileParts(text, (part, isLast) => camelCase(part, isLast ? { | ||
| prefix, | ||
| suffix | ||
| } : {})); | ||
| return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false); | ||
| } | ||
| /** | ||
| * Converts `text` to PascalCase. | ||
| * When `isFile` is `true`, the last dot-separated segment is PascalCased and earlier segments are camelCased. | ||
| * | ||
| * @example | ||
| * pascalCase('hello-world') // 'HelloWorld' | ||
| * pascalCase('pet.petId', { isFile: true }) // 'pet/PetId' | ||
| */ | ||
| function pascalCase(text, { isFile, prefix = "", suffix = "" } = {}) { | ||
| if (isFile) return applyToFileParts(text, (part, isLast) => isLast ? pascalCase(part, { | ||
| prefix, | ||
| suffix | ||
| }) : camelCase(part)); | ||
| return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true); | ||
| } | ||
| //#endregion | ||
| //#region ../../internals/utils/src/reserved.ts | ||
| /** | ||
| * JavaScript and Java reserved words. | ||
| * @link https://github.com/jonschlinkert/reserved/blob/master/index.js | ||
| */ | ||
| const reservedWords = new Set([ | ||
| "abstract", | ||
| "arguments", | ||
| "boolean", | ||
| "break", | ||
| "byte", | ||
| "case", | ||
| "catch", | ||
| "char", | ||
| "class", | ||
| "const", | ||
| "continue", | ||
| "debugger", | ||
| "default", | ||
| "delete", | ||
| "do", | ||
| "double", | ||
| "else", | ||
| "enum", | ||
| "eval", | ||
| "export", | ||
| "extends", | ||
| "false", | ||
| "final", | ||
| "finally", | ||
| "float", | ||
| "for", | ||
| "function", | ||
| "goto", | ||
| "if", | ||
| "implements", | ||
| "import", | ||
| "in", | ||
| "instanceof", | ||
| "int", | ||
| "interface", | ||
| "let", | ||
| "long", | ||
| "native", | ||
| "new", | ||
| "null", | ||
| "package", | ||
| "private", | ||
| "protected", | ||
| "public", | ||
| "return", | ||
| "short", | ||
| "static", | ||
| "super", | ||
| "switch", | ||
| "synchronized", | ||
| "this", | ||
| "throw", | ||
| "throws", | ||
| "transient", | ||
| "true", | ||
| "try", | ||
| "typeof", | ||
| "var", | ||
| "void", | ||
| "volatile", | ||
| "while", | ||
| "with", | ||
| "yield", | ||
| "Array", | ||
| "Date", | ||
| "hasOwnProperty", | ||
| "Infinity", | ||
| "isFinite", | ||
| "isNaN", | ||
| "isPrototypeOf", | ||
| "length", | ||
| "Math", | ||
| "name", | ||
| "NaN", | ||
| "Number", | ||
| "Object", | ||
| "prototype", | ||
| "String", | ||
| "toString", | ||
| "undefined", | ||
| "valueOf" | ||
| ]); | ||
| /** | ||
| * Returns `true` when `name` is a syntactically valid JavaScript variable name. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * isValidVarName('status') // true | ||
| * isValidVarName('class') // false (reserved word) | ||
| * isValidVarName('42foo') // false (starts with digit) | ||
| * ``` | ||
| */ | ||
| function isValidVarName(name) { | ||
| if (!name || reservedWords.has(name)) return false; | ||
| return isIdentifier(name); | ||
| } | ||
| /** | ||
| * Returns `name` when it is already a valid JavaScript variable name, otherwise prefixes it with `_` | ||
| * so the result can be used as an identifier. Useful for sanitizing schema names or operation IDs | ||
| * that start with a digit (`409`, `504AccountCancel`) or collide with a reserved word. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * ensureValidVarName('409') // '_409' | ||
| * ensureValidVarName('Pet') // 'Pet' | ||
| * ensureValidVarName('class') // '_class' | ||
| * ``` | ||
| */ | ||
| function ensureValidVarName(name) { | ||
| if (!name || isValidVarName(name)) return name; | ||
| return `_${name}`; | ||
| } | ||
| /** | ||
| * Returns `true` when `name` is syntactically a valid identifier, ignoring reserved words. | ||
| * | ||
| * Reserved words and globals (`class`, `name`, `Date`, …) are valid as bare object-literal keys | ||
| * even though they are not valid variable names, so use this (not {@link isValidVarName}) when | ||
| * deciding whether an object key needs quoting. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * isIdentifier('name') // true | ||
| * isIdentifier('x-total')// false | ||
| * ``` | ||
| */ | ||
| function isIdentifier(name) { | ||
| return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name); | ||
| } | ||
| //#endregion | ||
| //#region ../../internals/utils/src/string.ts | ||
| /** | ||
| * Wraps a value in single quotes for emitting a single-quoted JavaScript string literal, escaping | ||
| * any backslash or single quote in the content. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * singleQuote('foo') // "'foo'" | ||
| * singleQuote("o'clock") // "'o\\'clock'" | ||
| * ``` | ||
| */ | ||
| function singleQuote(value) { | ||
| if (value === void 0 || value === null) return "''"; | ||
| return `'${String(value).replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`; | ||
| } | ||
| /** | ||
| * Strips the file extension from a path or file name. | ||
| * Only removes the last `.ext` segment when the dot is not part of a directory name. | ||
| * | ||
| * @example | ||
| * trimExtName('petStore.ts') // 'petStore' | ||
| * trimExtName('/src/models/pet.ts') // '/src/models/pet' | ||
| * trimExtName('/project.v2/gen/pet.ts') // '/project.v2/gen/pet' | ||
| * trimExtName('noExtension') // 'noExtension' | ||
| */ | ||
| function trimExtName(text) { | ||
| const dotIndex = text.lastIndexOf("."); | ||
| if (dotIndex > 0 && !text.includes("/", dotIndex)) return text.slice(0, dotIndex); | ||
| return text; | ||
| } | ||
| //#endregion | ||
| //#region src/utils/index.ts | ||
| /** | ||
| * Strips a single matching pair of `"..."`, `'...'`, or `` `...` `` from both ends of `text`. | ||
| * Returns the string unchanged when no balanced quote pair is found. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * trimQuotes('"hello"') // 'hello' | ||
| * trimQuotes('hello') // 'hello' | ||
| * ``` | ||
| */ | ||
| function trimQuotes(text) { | ||
| if (text.length >= 2) { | ||
| const first = text[0]; | ||
| const last = text[text.length - 1]; | ||
| if (first === "\"" && last === "\"" || first === "'" && last === "'" || first === "`" && last === "`") return text.slice(1, -1); | ||
| } | ||
| return text; | ||
| } | ||
| /** | ||
| * Serializes a primitive value to a single-quoted string literal, stripping any surrounding quote | ||
| * characters first. Escaping comes from `JSON.stringify`, then the quote style switches to single | ||
| * quotes so generated code matches the repo style without a formatter. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * stringify('hello') // "'hello'" | ||
| * stringify('"hello"') // "'hello'" | ||
| * ``` | ||
| */ | ||
| function stringify(value) { | ||
| if (value === void 0 || value === null) return "''"; | ||
| return `'${JSON.stringify(trimQuotes(value.toString())).slice(1, -1).replace(/\\"/g, "\"").replace(/'/g, "\\'")}'`; | ||
| } | ||
| /** | ||
| * Escapes characters that are not allowed inside JS string literals, covering quotes, backslashes, | ||
| * and the Unicode line terminators U+2028 and U+2029. | ||
| * | ||
| * @see http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.4 | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * jsStringEscape('say "hi"\nbye') // 'say \\"hi\\"\\nbye' | ||
| * ``` | ||
| */ | ||
| function jsStringEscape(input) { | ||
| return `${input}`.replace(/["'\\\n\r\u2028\u2029]/g, (character) => { | ||
| switch (character) { | ||
| case "\"": | ||
| case "'": | ||
| case "\\": return `\\${character}`; | ||
| case "\n": return "\\n"; | ||
| case "\r": return "\\r"; | ||
| case "\u2028": return "\\u2028"; | ||
| case "\u2029": return "\\u2029"; | ||
| default: return ""; | ||
| } | ||
| }); | ||
| } | ||
| /** | ||
| * Converts a pattern string into a `new RegExp(...)` constructor call or a regex literal string. | ||
| * Inline flags expressed as a `^(?im)` prefix are extracted and applied to the resulting expression. | ||
| * Pass `null` as the second argument to emit a `/pattern/flags` literal instead. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * toRegExpString('^(?im)foo') // 'new RegExp("^foo", "im")' | ||
| * toRegExpString('^(?im)foo', null) // '/^foo/im' | ||
| * ``` | ||
| */ | ||
| function toRegExpString(text, func = "RegExp") { | ||
| const raw = trimQuotes(text); | ||
| const match = raw.match(/^\^(\(\?([igmsuy]+)\))/i); | ||
| const replacementTarget = match?.[1] ?? ""; | ||
| const matchedFlags = match?.[2]; | ||
| const cleaned = raw.replace(/^\\?\//, "").replace(/\\?\/$/, "").replace(replacementTarget, ""); | ||
| const { source, flags } = new RegExp(cleaned, matchedFlags); | ||
| if (func === null) return `/${source}/${flags}`; | ||
| return `new ${func}(${JSON.stringify(source)}${flags ? `, ${JSON.stringify(flags)}` : ""})`; | ||
| } | ||
| /** | ||
| * Renders a plain object as multi-line `key: value` source for embedding in generated code. Nested | ||
| * objects recurse with fixed indentation, so the result drops straight into an object literal | ||
| * without re-parsing. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * stringifyObject({ foo: 'bar', nested: { a: 1 } }) | ||
| * // 'foo: bar,\nnested: {\n a: 1\n }' | ||
| * ``` | ||
| */ | ||
| function stringifyObject(value) { | ||
| return Object.entries(value).map(([key, val]) => { | ||
| if (val !== null && typeof val === "object") return `${key}: {\n ${stringifyObject(val)}\n }`; | ||
| return `${key}: ${val}`; | ||
| }).filter(Boolean).join(",\n"); | ||
| } | ||
| /** | ||
| * Renders a dotted path or string array as an optional-chaining accessor expression rooted at | ||
| * `accessor`. Returns `null` for an empty path. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * getNestedAccessor('pagination.next.id', 'lastPage') | ||
| * // "lastPage?.['pagination']?.['next']?.['id']" | ||
| * ``` | ||
| */ | ||
| function getNestedAccessor(param, accessor) { | ||
| const parts = Array.isArray(param) ? param : param.split("."); | ||
| if (parts.length === 0 || parts.length === 1 && parts[0] === "") return null; | ||
| return `${accessor}?.['${`${parts.join("']?.['")}']`}`; | ||
| } | ||
| /** | ||
| * Builds a JSDoc comment block from an array of lines, returning `fallback` when there are no | ||
| * comments so callers always get a usable string. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * buildJSDoc(['@type string', '@example hello']) | ||
| * // '/**\n * @type string\n * @example hello\n *\/\n ' | ||
| * ``` | ||
| */ | ||
| function buildJSDoc(comments, options = {}) { | ||
| const { indent = " * ", suffix = "\n ", fallback = " " } = options; | ||
| if (comments.length === 0) return fallback; | ||
| return `/**\n${comments.map((c) => `${indent}${c}`).join("\n")}\n */${suffix}`; | ||
| } | ||
| /** | ||
| * Indents every non-empty line of `text` by one indent level, leaving blank lines empty. | ||
| */ | ||
| function indentLines(text) { | ||
| if (!text) return ""; | ||
| return text.split("\n").map((line) => line.trim() ? `${INDENT}${line}` : "").join("\n"); | ||
| } | ||
| /** | ||
| * Renders an object key, quoting it with single quotes only when it is not a valid identifier. | ||
| * Reserved words and globals (`name`, `class`, …) are valid bare keys and stay unquoted. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * objectKey('name') // 'name' | ||
| * objectKey('x-total') // "'x-total'" | ||
| * ``` | ||
| */ | ||
| function objectKey(name) { | ||
| return isIdentifier(name) ? name : singleQuote(name); | ||
| } | ||
| /** | ||
| * Assembles a multi-line object literal from already-rendered `entries`, indenting each entry one | ||
| * level and closing the brace at column zero. Nested objects built the same way indent cumulatively, | ||
| * so callers never re-parse the generated code. A trailing comma is added per entry to match the | ||
| * formatter's multi-line style. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * buildObject(['id: z.number()', 'name: z.string()']) | ||
| * // '{\n id: z.number(),\n name: z.string(),\n}' | ||
| * ``` | ||
| */ | ||
| function buildObject(entries) { | ||
| if (entries.length === 0) return "{}"; | ||
| return `{\n${entries.map((entry) => `${indentLines(entry)},`).join("\n")}\n}`; | ||
| } | ||
| /** | ||
| * Assembles a bracketed list (array by default) from already-rendered `items`. Keeps everything on | ||
| * one line when no item spans multiple lines, and otherwise puts each item on its own line, indented | ||
| * one level with a trailing comma and the closing bracket at column zero. Use it for `z.union([…])`, | ||
| * `z.array([…])`, and similar member lists so objects inside them nest correctly. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * buildList(['z.string()', 'z.number()']) | ||
| * // '[z.string(), z.number()]' | ||
| * ``` | ||
| */ | ||
| function buildList(items, brackets = ["[", "]"]) { | ||
| const [open, close] = brackets; | ||
| if (items.length === 0) return `${open}${close}`; | ||
| if (!items.some((item) => item.includes("\n"))) return `${open}${items.join(", ")}${close}`; | ||
| return `${open}\n${items.map((item) => `${indentLines(item)},`).join("\n")}\n${close}`; | ||
| } | ||
| /** | ||
| * Returns the last path segment of a reference string. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * extractRefName('#/components/schemas/Pet') // 'Pet' | ||
| * ``` | ||
| */ | ||
| function extractRefName(ref) { | ||
| return ref.split("/").at(-1) ?? ref; | ||
| } | ||
| /** | ||
| * Builds a PascalCase child schema name by joining a parent name and property name. | ||
| * Returns `null` when there is no parent to nest under. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * childName('Order', 'shipping_address') // 'OrderShippingAddress' | ||
| * childName(undefined, 'params') // null | ||
| * ``` | ||
| */ | ||
| function childName(parentName, propName) { | ||
| return parentName ? pascalCase([parentName, propName].join(" ")) : null; | ||
| } | ||
| /** | ||
| * Builds a PascalCase enum name from the parent name, property name, and a suffix, skipping any | ||
| * empty parts. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * enumPropName('Order', 'status', 'enum') // 'OrderStatusEnum' | ||
| * ``` | ||
| */ | ||
| function enumPropName(parentName, propName, enumSuffix) { | ||
| return pascalCase([ | ||
| parentName, | ||
| propName, | ||
| enumSuffix | ||
| ].filter(Boolean).join(" ")); | ||
| } | ||
| /** | ||
| * Returns the discriminator key whose mapping value matches `ref`, or `null` when there is no match. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * findDiscriminator({ dog: '#/components/schemas/Dog' }, '#/components/schemas/Dog') // 'dog' | ||
| * ``` | ||
| */ | ||
| function findDiscriminator(mapping, ref) { | ||
| if (!mapping || !ref) return null; | ||
| return Object.entries(mapping).find(([, value]) => value === ref)?.[0] ?? null; | ||
| } | ||
| //#endregion | ||
| export { visitorDepths as S, isValidVarName as _, enumPropName as a, isScalarPrimitive as b, getNestedAccessor as c, stringify as d, stringifyObject as f, ensureValidVarName as g, trimExtName as h, childName as i, jsStringEscape as l, trimQuotes as m, buildList as n, extractRefName as o, toRegExpString as p, buildObject as r, findDiscriminator as s, buildJSDoc as t, objectKey as u, camelCase as v, schemaTypes as x, httpMethods as y }; | ||
| //# sourceMappingURL=utils-BIcKgbbc.js.map |
| {"version":3,"file":"utils-BIcKgbbc.js","names":[],"sources":["../src/constants.ts","../../../internals/utils/src/casing.ts","../../../internals/utils/src/reserved.ts","../../../internals/utils/src/string.ts","../src/utils/index.ts"],"sourcesContent":["import type { HttpMethod } from './nodes/operation.ts'\nimport type { SchemaType } from './nodes/schema.ts'\n\n/**\n * Traversal depth for AST visitor utilities.\n *\n * - `'shallow'` visits only the immediate node, skipping children.\n * - `'deep'` recursively visits all descendant nodes.\n */\nexport type VisitorDepth = 'shallow' | 'deep'\n\nexport const visitorDepths = {\n shallow: 'shallow',\n deep: 'deep',\n} as const satisfies Record<VisitorDepth, VisitorDepth>\n\n/**\n * Schema type discriminators used by all AST schema nodes.\n *\n * These values serve as stable discriminators across the AST (e.g., `schema.type === schemaTypes.object`).\n * Grouped by category: primitives (`string`, `number`, `boolean`), structural types (`object`, `array`, `union`),\n * and format-specific types (`date`, `uuid`, `email`). Use `isScalarPrimitive()` to check for scalar types.\n */\nexport const schemaTypes = {\n /**\n * Text value.\n */\n string: 'string',\n /**\n * Floating-point number (`float`, `double`).\n */\n number: 'number',\n /**\n * Whole number (`int32`). Use `bigint` for `int64`.\n */\n integer: 'integer',\n /**\n * 64-bit integer (`int64`). Only used when `integerType` is set to `'bigint'`.\n */\n bigint: 'bigint',\n /**\n * Boolean value\n */\n boolean: 'boolean',\n /**\n * Explicit null value.\n */\n null: 'null',\n /**\n * Any value (no type restriction).\n */\n any: 'any',\n /**\n * Unknown value (must be narrowed before usage).\n */\n unknown: 'unknown',\n /**\n * No return value (`void`).\n */\n void: 'void',\n /**\n * Object with named properties.\n */\n object: 'object',\n /**\n * Sequential list of items.\n */\n array: 'array',\n /**\n * Fixed-length list with position-specific items.\n */\n tuple: 'tuple',\n /**\n * \"One of\" multiple schema members.\n */\n union: 'union',\n /**\n * \"All of\" multiple schema members.\n */\n intersection: 'intersection',\n /**\n * Enum schema.\n */\n enum: 'enum',\n /**\n * Reference to another schema.\n */\n ref: 'ref',\n /**\n * Calendar date (for example `2026-03-24`).\n */\n date: 'date',\n /**\n * Date-time value (for example `2026-03-24T09:00:00Z`).\n */\n datetime: 'datetime',\n /**\n * Time-only value (for example `09:00:00`).\n */\n time: 'time',\n /**\n * UUID value.\n */\n uuid: 'uuid',\n /**\n * Email address value.\n */\n email: 'email',\n /**\n * URL value.\n */\n url: 'url',\n /**\n * IPv4 address value.\n */\n ipv4: 'ipv4',\n /**\n * IPv6 address value.\n */\n ipv6: 'ipv6',\n /**\n * Binary/blob value.\n */\n blob: 'blob',\n /**\n * Impossible value (`never`).\n */\n never: 'never',\n} as const satisfies Record<SchemaType, SchemaType>\n\nexport type ScalarPrimitive = 'string' | 'number' | 'integer' | 'bigint' | 'boolean'\n\n/**\n * Scalar primitive schema types used for union simplification and type narrowing.\n *\n * Use `isScalarPrimitive()` to safely check whether a type is a scalar primitive.\n */\nconst SCALAR_PRIMITIVE_TYPES = new Set<ScalarPrimitive>(['string', 'number', 'integer', 'bigint', 'boolean'])\n\n/**\n * Type guard that returns `true` when `type` is a scalar primitive schema type.\n *\n * Use this to check if a schema type can be directly assigned without wrapping (e.g., `string | number | boolean`).\n */\nexport function isScalarPrimitive(type: string): type is ScalarPrimitive {\n return SCALAR_PRIMITIVE_TYPES.has(type as ScalarPrimitive)\n}\n\n/**\n * HTTP method identifiers used by operation nodes.\n *\n * Includes all standard HTTP methods (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, TRACE).\n */\nexport const httpMethods = {\n get: 'GET',\n post: 'POST',\n put: 'PUT',\n patch: 'PATCH',\n delete: 'DELETE',\n head: 'HEAD',\n options: 'OPTIONS',\n trace: 'TRACE',\n} as const satisfies Record<Lowercase<HttpMethod>, HttpMethod>\n\n/**\n * Default concurrency limit for `walk()` traversal utility.\n *\n * Set to 30 to balance I/O-bound resolver parallelism against event loop pressure and memory usage during large spec traversals.\n * Use `WALK_CONCURRENCY` when calling `walk()` or override for different hardware constraints.\n *\n * @example\n * ```ts\n * import { walk, WALK_CONCURRENCY } from '@kubb/ast'\n *\n * walk(root, { concurrency: WALK_CONCURRENCY, root: () => {} })\n * ```\n */\nexport const WALK_CONCURRENCY = 30\n\n/**\n * Number of spaces in one indentation level when assembling multi-line code as strings.\n * Set to 2, 3, … to change the indent width used by `buildObject`/`buildList`.\n */\nconst INDENT_SIZE = 2\n\n/**\n * One indentation level, derived from {@link INDENT_SIZE}.\n */\nexport const INDENT = Array.from({ length: INDENT_SIZE }, () => ' ').join('')\n","type Options = {\n /**\n * When `true`, dot-separated segments are split on `.` and joined with `/` after casing.\n */\n isFile?: boolean\n /**\n * Text prepended before casing is applied.\n */\n prefix?: string\n /**\n * Text appended before casing is applied.\n */\n suffix?: string\n}\n\n/**\n * Shared implementation for camelCase and PascalCase conversion.\n * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)\n * and capitalizes each word according to `pascal`.\n *\n * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.\n */\nfunction toCamelOrPascal(text: string, pascal: boolean): string {\n const normalized = text\n .trim()\n .replace(/([a-z\\d])([A-Z])/g, '$1 $2')\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')\n .replace(/(\\d)([a-z])/g, '$1 $2')\n\n const words = normalized.split(/[\\s\\-_./\\\\:]+/).filter(Boolean)\n\n return words\n .map((word, i) => {\n const allUpper = word.length > 1 && word === word.toUpperCase()\n if (allUpper) return word\n if (i === 0 && !pascal) return word.charAt(0).toLowerCase() + word.slice(1)\n return word.charAt(0).toUpperCase() + word.slice(1)\n })\n .join('')\n .replace(/[^a-zA-Z0-9]/g, '')\n}\n\n/**\n * Splits `text` on `.` and applies `transformPart` to each segment.\n * The last segment receives `isLast = true`, all earlier segments receive `false`.\n * Segments are joined with `/` to form a file path.\n *\n * Only splits on dots followed by a letter so that version numbers\n * embedded in operationIds (e.g. `v2025.0`) are kept intact.\n *\n * Empty segments are filtered before joining. They arise when the text starts with\n * a dot followed immediately by a letter (e.g. `..Schema` splits into `['..', 'Schema']`\n * and `'..'` transforms to an empty string). Without this filter the join would produce\n * a leading `/`, which `path.resolve` would interpret as an absolute path, allowing\n * generated files to escape the configured output directory.\n */\nfunction applyToFileParts(text: string, transformPart: (part: string, isLast: boolean) => string): string {\n const parts = text.split(/\\.(?=[a-zA-Z])/)\n return parts\n .map((part, i) => transformPart(part, i === parts.length - 1))\n .filter(Boolean)\n .join('/')\n}\n\n/**\n * Converts `text` to camelCase.\n * When `isFile` is `true`, dot-separated segments are each cased independently and joined with `/`.\n *\n * @example\n * camelCase('hello-world') // 'helloWorld'\n * camelCase('pet.petId', { isFile: true }) // 'pet/petId'\n */\nexport function camelCase(text: string, { isFile, prefix = '', suffix = '' }: Options = {}): string {\n if (isFile) {\n return applyToFileParts(text, (part, isLast) => camelCase(part, isLast ? { prefix, suffix } : {}))\n }\n\n return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false)\n}\n\n/**\n * Converts `text` to PascalCase.\n * When `isFile` is `true`, the last dot-separated segment is PascalCased and earlier segments are camelCased.\n *\n * @example\n * pascalCase('hello-world') // 'HelloWorld'\n * pascalCase('pet.petId', { isFile: true }) // 'pet/PetId'\n */\nexport function pascalCase(text: string, { isFile, prefix = '', suffix = '' }: Options = {}): string {\n if (isFile) {\n return applyToFileParts(text, (part, isLast) => (isLast ? pascalCase(part, { prefix, suffix }) : camelCase(part)))\n }\n\n return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true)\n}\n","/**\n * JavaScript and Java reserved words.\n * @link https://github.com/jonschlinkert/reserved/blob/master/index.js\n */\nconst reservedWords = new Set([\n 'abstract',\n 'arguments',\n 'boolean',\n 'break',\n 'byte',\n 'case',\n 'catch',\n 'char',\n 'class',\n 'const',\n 'continue',\n 'debugger',\n 'default',\n 'delete',\n 'do',\n 'double',\n 'else',\n 'enum',\n 'eval',\n 'export',\n 'extends',\n 'false',\n 'final',\n 'finally',\n 'float',\n 'for',\n 'function',\n 'goto',\n 'if',\n 'implements',\n 'import',\n 'in',\n 'instanceof',\n 'int',\n 'interface',\n 'let',\n 'long',\n 'native',\n 'new',\n 'null',\n 'package',\n 'private',\n 'protected',\n 'public',\n 'return',\n 'short',\n 'static',\n 'super',\n 'switch',\n 'synchronized',\n 'this',\n 'throw',\n 'throws',\n 'transient',\n 'true',\n 'try',\n 'typeof',\n 'var',\n 'void',\n 'volatile',\n 'while',\n 'with',\n 'yield',\n 'Array',\n 'Date',\n 'hasOwnProperty',\n 'Infinity',\n 'isFinite',\n 'isNaN',\n 'isPrototypeOf',\n 'length',\n 'Math',\n 'name',\n 'NaN',\n 'Number',\n 'Object',\n 'prototype',\n 'String',\n 'toString',\n 'undefined',\n 'valueOf',\n] as const)\n\n/**\n * Prefixes `word` with `_` when it is a reserved JavaScript/Java identifier or starts with a digit.\n *\n * @example\n * ```ts\n * transformReservedWord('class') // '_class'\n * transformReservedWord('42foo') // '_42foo'\n * transformReservedWord('status') // 'status'\n * ```\n */\nexport function transformReservedWord(word: string): string {\n const firstChar = word.charCodeAt(0)\n if (word && (reservedWords.has(word as 'valueOf') || (firstChar >= 48 && firstChar <= 57))) {\n return `_${word}`\n }\n return word\n}\n\n/**\n * Returns `true` when `name` is a syntactically valid JavaScript variable name.\n *\n * @example\n * ```ts\n * isValidVarName('status') // true\n * isValidVarName('class') // false (reserved word)\n * isValidVarName('42foo') // false (starts with digit)\n * ```\n */\nexport function isValidVarName(name: string): boolean {\n if (!name || reservedWords.has(name as 'valueOf')) {\n return false\n }\n return isIdentifier(name)\n}\n\n/**\n * Returns `name` when it is already a valid JavaScript variable name, otherwise prefixes it with `_`\n * so the result can be used as an identifier. Useful for sanitizing schema names or operation IDs\n * that start with a digit (`409`, `504AccountCancel`) or collide with a reserved word.\n *\n * @example\n * ```ts\n * ensureValidVarName('409') // '_409'\n * ensureValidVarName('Pet') // 'Pet'\n * ensureValidVarName('class') // '_class'\n * ```\n */\nexport function ensureValidVarName(name: string): string {\n if (!name || isValidVarName(name)) {\n return name\n }\n return `_${name}`\n}\n\n/**\n * Returns `true` when `name` is syntactically a valid identifier, ignoring reserved words.\n *\n * Reserved words and globals (`class`, `name`, `Date`, …) are valid as bare object-literal keys\n * even though they are not valid variable names, so use this (not {@link isValidVarName}) when\n * deciding whether an object key needs quoting.\n *\n * @example\n * ```ts\n * isIdentifier('name') // true\n * isIdentifier('x-total')// false\n * ```\n */\nexport function isIdentifier(name: string): boolean {\n return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name)\n}\n","/**\n * Returns a masked version of a string, showing only the first and last few characters.\n * Useful for logging sensitive values (tokens, keys) without exposing the full value.\n *\n * @example\n * maskString('KUBB_STUDIO-abc123-xyz789') // 'KUBB_STUDIO-…789'\n */\nexport function maskString(value: string, start = 8, end = 4): string {\n if (value.length <= start + end) return value\n return `${value.slice(0, start)}…${value.slice(-end)}`\n}\n\n/**\n * Wraps a value in single quotes for emitting a single-quoted JavaScript string literal, escaping\n * any backslash or single quote in the content.\n *\n * @example\n * ```ts\n * singleQuote('foo') // \"'foo'\"\n * singleQuote(\"o'clock\") // \"'o\\\\'clock'\"\n * ```\n */\nexport function singleQuote(value: string | number | boolean | undefined | null): string {\n if (value === undefined || value === null) return \"''\"\n const escaped = String(value).replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\")\n return `'${escaped}'`\n}\n\n/**\n * Strips the file extension from a path or file name.\n * Only removes the last `.ext` segment when the dot is not part of a directory name.\n *\n * @example\n * trimExtName('petStore.ts') // 'petStore'\n * trimExtName('/src/models/pet.ts') // '/src/models/pet'\n * trimExtName('/project.v2/gen/pet.ts') // '/project.v2/gen/pet'\n * trimExtName('noExtension') // 'noExtension'\n */\nexport function trimExtName(text: string): string {\n const dotIndex = text.lastIndexOf('.')\n if (dotIndex > 0 && !text.includes('/', dotIndex)) {\n return text.slice(0, dotIndex)\n }\n return text\n}\n","import { isIdentifier, pascalCase, singleQuote } from '@internals/utils'\nimport { INDENT } from '../constants.ts'\n\nexport { ensureValidVarName, isValidVarName } from '@internals/utils'\n\n/**\n * Strips a single matching pair of `\"...\"`, `'...'`, or `` `...` `` from both ends of `text`.\n * Returns the string unchanged when no balanced quote pair is found.\n *\n * @example\n * ```ts\n * trimQuotes('\"hello\"') // 'hello'\n * trimQuotes('hello') // 'hello'\n * ```\n */\nexport function trimQuotes(text: string): string {\n if (text.length >= 2) {\n const first = text[0]\n const last = text[text.length - 1]\n if ((first === '\"' && last === '\"') || (first === \"'\" && last === \"'\") || (first === '`' && last === '`')) {\n return text.slice(1, -1)\n }\n }\n return text\n}\n\n/**\n * Serializes a primitive value to a single-quoted string literal, stripping any surrounding quote\n * characters first. Escaping comes from `JSON.stringify`, then the quote style switches to single\n * quotes so generated code matches the repo style without a formatter.\n *\n * @example\n * ```ts\n * stringify('hello') // \"'hello'\"\n * stringify('\"hello\"') // \"'hello'\"\n * ```\n */\nexport function stringify(value: string | number | boolean | undefined): string {\n if (value === undefined || value === null) return \"''\"\n const json = JSON.stringify(trimQuotes(value.toString()))\n const inner = json.slice(1, -1).replace(/\\\\\"/g, '\"').replace(/'/g, \"\\\\'\")\n return `'${inner}'`\n}\n\n/**\n * Escapes characters that are not allowed inside JS string literals, covering quotes, backslashes,\n * and the Unicode line terminators U+2028 and U+2029.\n *\n * @see http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.4\n *\n * @example\n * ```ts\n * jsStringEscape('say \"hi\"\\nbye') // 'say \\\\\"hi\\\\\"\\\\nbye'\n * ```\n */\nexport function jsStringEscape(input: unknown): string {\n return `${input}`.replace(/[\"'\\\\\\n\\r\\u2028\\u2029]/g, (character) => {\n switch (character) {\n case '\"':\n case \"'\":\n case '\\\\':\n return `\\\\${character}`\n case '\\n':\n return '\\\\n'\n case '\\r':\n return '\\\\r'\n case '\\u2028':\n return '\\\\u2028'\n case '\\u2029':\n return '\\\\u2029'\n default:\n return ''\n }\n })\n}\n\n/**\n * Converts a pattern string into a `new RegExp(...)` constructor call or a regex literal string.\n * Inline flags expressed as a `^(?im)` prefix are extracted and applied to the resulting expression.\n * Pass `null` as the second argument to emit a `/pattern/flags` literal instead.\n *\n * @example\n * ```ts\n * toRegExpString('^(?im)foo') // 'new RegExp(\"^foo\", \"im\")'\n * toRegExpString('^(?im)foo', null) // '/^foo/im'\n * ```\n */\nexport function toRegExpString(text: string, func: string | null = 'RegExp'): string {\n const raw = trimQuotes(text)\n\n const match = raw.match(/^\\^(\\(\\?([igmsuy]+)\\))/i)\n const replacementTarget = match?.[1] ?? ''\n const matchedFlags = match?.[2]\n const cleaned = raw\n .replace(/^\\\\?\\//, '')\n .replace(/\\\\?\\/$/, '')\n .replace(replacementTarget, '')\n\n const { source, flags } = new RegExp(cleaned, matchedFlags)\n\n if (func === null) return `/${source}/${flags}`\n\n return `new ${func}(${JSON.stringify(source)}${flags ? `, ${JSON.stringify(flags)}` : ''})`\n}\n\n/**\n * Renders a plain object as multi-line `key: value` source for embedding in generated code. Nested\n * objects recurse with fixed indentation, so the result drops straight into an object literal\n * without re-parsing.\n *\n * @example\n * ```ts\n * stringifyObject({ foo: 'bar', nested: { a: 1 } })\n * // 'foo: bar,\\nnested: {\\n a: 1\\n }'\n * ```\n */\nexport function stringifyObject(value: Record<string, unknown>): string {\n const items = Object.entries(value)\n .map(([key, val]) => {\n if (val !== null && typeof val === 'object') {\n return `${key}: {\\n ${stringifyObject(val as Record<string, unknown>)}\\n }`\n }\n return `${key}: ${val}`\n })\n .filter(Boolean)\n return items.join(',\\n')\n}\n\n/**\n * Renders a dotted path or string array as an optional-chaining accessor expression rooted at\n * `accessor`. Returns `null` for an empty path.\n *\n * @example\n * ```ts\n * getNestedAccessor('pagination.next.id', 'lastPage')\n * // \"lastPage?.['pagination']?.['next']?.['id']\"\n * ```\n */\nexport function getNestedAccessor(param: string | Array<string>, accessor: string): string | null {\n const parts = Array.isArray(param) ? param : param.split('.')\n if (parts.length === 0 || (parts.length === 1 && parts[0] === '')) return null\n return `${accessor}?.['${`${parts.join(\"']?.['\")}']`}`\n}\n\n/**\n * Builds a JSDoc comment block from an array of lines, returning `fallback` when there are no\n * comments so callers always get a usable string.\n *\n * @example\n * ```ts\n * buildJSDoc(['@type string', '@example hello'])\n * // '/**\\n * @type string\\n * @example hello\\n *\\/\\n '\n * ```\n */\nexport function buildJSDoc(\n comments: Array<string>,\n options: {\n /**\n * String used to indent each comment line.\n * @default ' * '\n */\n indent?: string\n /**\n * String appended after the closing tag.\n * @default '\\n '\n */\n suffix?: string\n /**\n * Returned as-is when `comments` is empty.\n * @default ' '\n */\n fallback?: string\n } = {},\n): string {\n const { indent = ' * ', suffix = '\\n ', fallback = ' ' } = options\n\n if (comments.length === 0) return fallback\n\n return `/**\\n${comments.map((c) => `${indent}${c}`).join('\\n')}\\n */${suffix}`\n}\n\n/**\n * Indents every non-empty line of `text` by one indent level, leaving blank lines empty.\n */\nfunction indentLines(text: string): string {\n if (!text) return ''\n return text\n .split('\\n')\n .map((line) => (line.trim() ? `${INDENT}${line}` : ''))\n .join('\\n')\n}\n\n/**\n * Renders an object key, quoting it with single quotes only when it is not a valid identifier.\n * Reserved words and globals (`name`, `class`, …) are valid bare keys and stay unquoted.\n *\n * @example\n * ```ts\n * objectKey('name') // 'name'\n * objectKey('x-total') // \"'x-total'\"\n * ```\n */\nexport function objectKey(name: string): string {\n return isIdentifier(name) ? name : singleQuote(name)\n}\n\n/**\n * Assembles a multi-line object literal from already-rendered `entries`, indenting each entry one\n * level and closing the brace at column zero. Nested objects built the same way indent cumulatively,\n * so callers never re-parse the generated code. A trailing comma is added per entry to match the\n * formatter's multi-line style.\n *\n * @example\n * ```ts\n * buildObject(['id: z.number()', 'name: z.string()'])\n * // '{\\n id: z.number(),\\n name: z.string(),\\n}'\n * ```\n */\nexport function buildObject(entries: Array<string>): string {\n if (entries.length === 0) return '{}'\n const body = entries.map((entry) => `${indentLines(entry)},`).join('\\n')\n return `{\\n${body}\\n}`\n}\n\n/**\n * Assembles a bracketed list (array by default) from already-rendered `items`. Keeps everything on\n * one line when no item spans multiple lines, and otherwise puts each item on its own line, indented\n * one level with a trailing comma and the closing bracket at column zero. Use it for `z.union([…])`,\n * `z.array([…])`, and similar member lists so objects inside them nest correctly.\n *\n * @example\n * ```ts\n * buildList(['z.string()', 'z.number()'])\n * // '[z.string(), z.number()]'\n * ```\n */\nexport function buildList(items: Array<string>, brackets: [open: string, close: string] = ['[', ']']): string {\n const [open, close] = brackets\n if (items.length === 0) return `${open}${close}`\n if (!items.some((item) => item.includes('\\n'))) return `${open}${items.join(', ')}${close}`\n const body = items.map((item) => `${indentLines(item)},`).join('\\n')\n return `${open}\\n${body}\\n${close}`\n}\n\n/**\n * Returns the last path segment of a reference string.\n *\n * @example\n * ```ts\n * extractRefName('#/components/schemas/Pet') // 'Pet'\n * ```\n */\nexport function extractRefName(ref: string): string {\n return ref.split('/').at(-1) ?? ref\n}\n\n/**\n * Builds a PascalCase child schema name by joining a parent name and property name.\n * Returns `null` when there is no parent to nest under.\n *\n * @example\n * ```ts\n * childName('Order', 'shipping_address') // 'OrderShippingAddress'\n * childName(undefined, 'params') // null\n * ```\n */\nexport function childName(parentName: string | null | undefined, propName: string): string | null {\n return parentName ? pascalCase([parentName, propName].join(' ')) : null\n}\n\n/**\n * Builds a PascalCase enum name from the parent name, property name, and a suffix, skipping any\n * empty parts.\n *\n * @example\n * ```ts\n * enumPropName('Order', 'status', 'enum') // 'OrderStatusEnum'\n * ```\n */\nexport function enumPropName(parentName: string | null | undefined, propName: string, enumSuffix: string): string {\n return pascalCase([parentName, propName, enumSuffix].filter(Boolean).join(' '))\n}\n\n/**\n * Returns the discriminator key whose mapping value matches `ref`, or `null` when there is no match.\n *\n * @example\n * ```ts\n * findDiscriminator({ dog: '#/components/schemas/Dog' }, '#/components/schemas/Dog') // 'dog'\n * ```\n */\nexport function findDiscriminator(mapping: Record<string, string> | undefined, ref: string | undefined): string | null {\n if (!mapping || !ref) return null\n return Object.entries(mapping).find(([, value]) => value === ref)?.[0] ?? null\n}\n"],"mappings":"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"} |
| //#region \0rolldown/runtime.js | ||
| var __create = Object.create; | ||
| var __defProp = Object.defineProperty; | ||
| var __name = (target, value) => __defProp(target, "name", { | ||
| value, | ||
| configurable: true | ||
| }); | ||
| var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
| var __getOwnPropNames = Object.getOwnPropertyNames; | ||
| var __getProtoOf = Object.getPrototypeOf; | ||
| var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
| var __copyProps = (to, from, except, desc) => { | ||
| if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) { | ||
| key = keys[i]; | ||
| if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { | ||
| get: ((k) => from[k]).bind(null, key), | ||
| enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable | ||
| }); | ||
| } | ||
| return to; | ||
| }; | ||
| var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { | ||
| value: mod, | ||
| enumerable: true | ||
| }) : target, mod)); | ||
| //#endregion | ||
| //#region src/constants.ts | ||
| const visitorDepths = { | ||
| shallow: "shallow", | ||
| deep: "deep" | ||
| }; | ||
| /** | ||
| * Schema type discriminators used by all AST schema nodes. | ||
| * | ||
| * These values serve as stable discriminators across the AST (e.g., `schema.type === schemaTypes.object`). | ||
| * Grouped by category: primitives (`string`, `number`, `boolean`), structural types (`object`, `array`, `union`), | ||
| * and format-specific types (`date`, `uuid`, `email`). Use `isScalarPrimitive()` to check for scalar types. | ||
| */ | ||
| const schemaTypes = { | ||
| /** | ||
| * Text value. | ||
| */ | ||
| string: "string", | ||
| /** | ||
| * Floating-point number (`float`, `double`). | ||
| */ | ||
| number: "number", | ||
| /** | ||
| * Whole number (`int32`). Use `bigint` for `int64`. | ||
| */ | ||
| integer: "integer", | ||
| /** | ||
| * 64-bit integer (`int64`). Only used when `integerType` is set to `'bigint'`. | ||
| */ | ||
| bigint: "bigint", | ||
| /** | ||
| * Boolean value | ||
| */ | ||
| boolean: "boolean", | ||
| /** | ||
| * Explicit null value. | ||
| */ | ||
| null: "null", | ||
| /** | ||
| * Any value (no type restriction). | ||
| */ | ||
| any: "any", | ||
| /** | ||
| * Unknown value (must be narrowed before usage). | ||
| */ | ||
| unknown: "unknown", | ||
| /** | ||
| * No return value (`void`). | ||
| */ | ||
| void: "void", | ||
| /** | ||
| * Object with named properties. | ||
| */ | ||
| object: "object", | ||
| /** | ||
| * Sequential list of items. | ||
| */ | ||
| array: "array", | ||
| /** | ||
| * Fixed-length list with position-specific items. | ||
| */ | ||
| tuple: "tuple", | ||
| /** | ||
| * "One of" multiple schema members. | ||
| */ | ||
| union: "union", | ||
| /** | ||
| * "All of" multiple schema members. | ||
| */ | ||
| intersection: "intersection", | ||
| /** | ||
| * Enum schema. | ||
| */ | ||
| enum: "enum", | ||
| /** | ||
| * Reference to another schema. | ||
| */ | ||
| ref: "ref", | ||
| /** | ||
| * Calendar date (for example `2026-03-24`). | ||
| */ | ||
| date: "date", | ||
| /** | ||
| * Date-time value (for example `2026-03-24T09:00:00Z`). | ||
| */ | ||
| datetime: "datetime", | ||
| /** | ||
| * Time-only value (for example `09:00:00`). | ||
| */ | ||
| time: "time", | ||
| /** | ||
| * UUID value. | ||
| */ | ||
| uuid: "uuid", | ||
| /** | ||
| * Email address value. | ||
| */ | ||
| email: "email", | ||
| /** | ||
| * URL value. | ||
| */ | ||
| url: "url", | ||
| /** | ||
| * IPv4 address value. | ||
| */ | ||
| ipv4: "ipv4", | ||
| /** | ||
| * IPv6 address value. | ||
| */ | ||
| ipv6: "ipv6", | ||
| /** | ||
| * Binary/blob value. | ||
| */ | ||
| blob: "blob", | ||
| /** | ||
| * Impossible value (`never`). | ||
| */ | ||
| never: "never" | ||
| }; | ||
| /** | ||
| * Scalar primitive schema types used for union simplification and type narrowing. | ||
| * | ||
| * Use `isScalarPrimitive()` to safely check whether a type is a scalar primitive. | ||
| */ | ||
| const SCALAR_PRIMITIVE_TYPES = new Set([ | ||
| "string", | ||
| "number", | ||
| "integer", | ||
| "bigint", | ||
| "boolean" | ||
| ]); | ||
| /** | ||
| * Type guard that returns `true` when `type` is a scalar primitive schema type. | ||
| * | ||
| * Use this to check if a schema type can be directly assigned without wrapping (e.g., `string | number | boolean`). | ||
| */ | ||
| function isScalarPrimitive(type) { | ||
| return SCALAR_PRIMITIVE_TYPES.has(type); | ||
| } | ||
| /** | ||
| * HTTP method identifiers used by operation nodes. | ||
| * | ||
| * Includes all standard HTTP methods (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, TRACE). | ||
| */ | ||
| const httpMethods = { | ||
| get: "GET", | ||
| post: "POST", | ||
| put: "PUT", | ||
| patch: "PATCH", | ||
| delete: "DELETE", | ||
| head: "HEAD", | ||
| options: "OPTIONS", | ||
| trace: "TRACE" | ||
| }; | ||
| /** | ||
| * One indentation level, derived from {@link INDENT_SIZE}. | ||
| */ | ||
| const INDENT = Array.from({ length: 2 }, () => " ").join(""); | ||
| //#endregion | ||
| //#region ../../internals/utils/src/casing.ts | ||
| /** | ||
| * Shared implementation for camelCase and PascalCase conversion. | ||
| * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons) | ||
| * and capitalizes each word according to `pascal`. | ||
| * | ||
| * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are. | ||
| */ | ||
| function toCamelOrPascal(text, pascal) { | ||
| return text.trim().replace(/([a-z\d])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/(\d)([a-z])/g, "$1 $2").split(/[\s\-_./\\:]+/).filter(Boolean).map((word, i) => { | ||
| if (word.length > 1 && word === word.toUpperCase()) return word; | ||
| if (i === 0 && !pascal) return word.charAt(0).toLowerCase() + word.slice(1); | ||
| return word.charAt(0).toUpperCase() + word.slice(1); | ||
| }).join("").replace(/[^a-zA-Z0-9]/g, ""); | ||
| } | ||
| /** | ||
| * Splits `text` on `.` and applies `transformPart` to each segment. | ||
| * The last segment receives `isLast = true`, all earlier segments receive `false`. | ||
| * Segments are joined with `/` to form a file path. | ||
| * | ||
| * Only splits on dots followed by a letter so that version numbers | ||
| * embedded in operationIds (e.g. `v2025.0`) are kept intact. | ||
| * | ||
| * Empty segments are filtered before joining. They arise when the text starts with | ||
| * a dot followed immediately by a letter (e.g. `..Schema` splits into `['..', 'Schema']` | ||
| * and `'..'` transforms to an empty string). Without this filter the join would produce | ||
| * a leading `/`, which `path.resolve` would interpret as an absolute path, allowing | ||
| * generated files to escape the configured output directory. | ||
| */ | ||
| function applyToFileParts(text, transformPart) { | ||
| const parts = text.split(/\.(?=[a-zA-Z])/); | ||
| return parts.map((part, i) => transformPart(part, i === parts.length - 1)).filter(Boolean).join("/"); | ||
| } | ||
| /** | ||
| * Converts `text` to camelCase. | ||
| * When `isFile` is `true`, dot-separated segments are each cased independently and joined with `/`. | ||
| * | ||
| * @example | ||
| * camelCase('hello-world') // 'helloWorld' | ||
| * camelCase('pet.petId', { isFile: true }) // 'pet/petId' | ||
| */ | ||
| function camelCase(text, { isFile, prefix = "", suffix = "" } = {}) { | ||
| if (isFile) return applyToFileParts(text, (part, isLast) => camelCase(part, isLast ? { | ||
| prefix, | ||
| suffix | ||
| } : {})); | ||
| return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false); | ||
| } | ||
| /** | ||
| * Converts `text` to PascalCase. | ||
| * When `isFile` is `true`, the last dot-separated segment is PascalCased and earlier segments are camelCased. | ||
| * | ||
| * @example | ||
| * pascalCase('hello-world') // 'HelloWorld' | ||
| * pascalCase('pet.petId', { isFile: true }) // 'pet/PetId' | ||
| */ | ||
| function pascalCase(text, { isFile, prefix = "", suffix = "" } = {}) { | ||
| if (isFile) return applyToFileParts(text, (part, isLast) => isLast ? pascalCase(part, { | ||
| prefix, | ||
| suffix | ||
| }) : camelCase(part)); | ||
| return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true); | ||
| } | ||
| //#endregion | ||
| //#region ../../internals/utils/src/reserved.ts | ||
| /** | ||
| * JavaScript and Java reserved words. | ||
| * @link https://github.com/jonschlinkert/reserved/blob/master/index.js | ||
| */ | ||
| const reservedWords = new Set([ | ||
| "abstract", | ||
| "arguments", | ||
| "boolean", | ||
| "break", | ||
| "byte", | ||
| "case", | ||
| "catch", | ||
| "char", | ||
| "class", | ||
| "const", | ||
| "continue", | ||
| "debugger", | ||
| "default", | ||
| "delete", | ||
| "do", | ||
| "double", | ||
| "else", | ||
| "enum", | ||
| "eval", | ||
| "export", | ||
| "extends", | ||
| "false", | ||
| "final", | ||
| "finally", | ||
| "float", | ||
| "for", | ||
| "function", | ||
| "goto", | ||
| "if", | ||
| "implements", | ||
| "import", | ||
| "in", | ||
| "instanceof", | ||
| "int", | ||
| "interface", | ||
| "let", | ||
| "long", | ||
| "native", | ||
| "new", | ||
| "null", | ||
| "package", | ||
| "private", | ||
| "protected", | ||
| "public", | ||
| "return", | ||
| "short", | ||
| "static", | ||
| "super", | ||
| "switch", | ||
| "synchronized", | ||
| "this", | ||
| "throw", | ||
| "throws", | ||
| "transient", | ||
| "true", | ||
| "try", | ||
| "typeof", | ||
| "var", | ||
| "void", | ||
| "volatile", | ||
| "while", | ||
| "with", | ||
| "yield", | ||
| "Array", | ||
| "Date", | ||
| "hasOwnProperty", | ||
| "Infinity", | ||
| "isFinite", | ||
| "isNaN", | ||
| "isPrototypeOf", | ||
| "length", | ||
| "Math", | ||
| "name", | ||
| "NaN", | ||
| "Number", | ||
| "Object", | ||
| "prototype", | ||
| "String", | ||
| "toString", | ||
| "undefined", | ||
| "valueOf" | ||
| ]); | ||
| /** | ||
| * Returns `true` when `name` is a syntactically valid JavaScript variable name. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * isValidVarName('status') // true | ||
| * isValidVarName('class') // false (reserved word) | ||
| * isValidVarName('42foo') // false (starts with digit) | ||
| * ``` | ||
| */ | ||
| function isValidVarName(name) { | ||
| if (!name || reservedWords.has(name)) return false; | ||
| return isIdentifier(name); | ||
| } | ||
| /** | ||
| * Returns `name` when it is already a valid JavaScript variable name, otherwise prefixes it with `_` | ||
| * so the result can be used as an identifier. Useful for sanitizing schema names or operation IDs | ||
| * that start with a digit (`409`, `504AccountCancel`) or collide with a reserved word. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * ensureValidVarName('409') // '_409' | ||
| * ensureValidVarName('Pet') // 'Pet' | ||
| * ensureValidVarName('class') // '_class' | ||
| * ``` | ||
| */ | ||
| function ensureValidVarName(name) { | ||
| if (!name || isValidVarName(name)) return name; | ||
| return `_${name}`; | ||
| } | ||
| /** | ||
| * Returns `true` when `name` is syntactically a valid identifier, ignoring reserved words. | ||
| * | ||
| * Reserved words and globals (`class`, `name`, `Date`, …) are valid as bare object-literal keys | ||
| * even though they are not valid variable names, so use this (not {@link isValidVarName}) when | ||
| * deciding whether an object key needs quoting. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * isIdentifier('name') // true | ||
| * isIdentifier('x-total')// false | ||
| * ``` | ||
| */ | ||
| function isIdentifier(name) { | ||
| return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name); | ||
| } | ||
| //#endregion | ||
| //#region ../../internals/utils/src/string.ts | ||
| /** | ||
| * Wraps a value in single quotes for emitting a single-quoted JavaScript string literal, escaping | ||
| * any backslash or single quote in the content. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * singleQuote('foo') // "'foo'" | ||
| * singleQuote("o'clock") // "'o\\'clock'" | ||
| * ``` | ||
| */ | ||
| function singleQuote(value) { | ||
| if (value === void 0 || value === null) return "''"; | ||
| return `'${String(value).replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`; | ||
| } | ||
| /** | ||
| * Strips the file extension from a path or file name. | ||
| * Only removes the last `.ext` segment when the dot is not part of a directory name. | ||
| * | ||
| * @example | ||
| * trimExtName('petStore.ts') // 'petStore' | ||
| * trimExtName('/src/models/pet.ts') // '/src/models/pet' | ||
| * trimExtName('/project.v2/gen/pet.ts') // '/project.v2/gen/pet' | ||
| * trimExtName('noExtension') // 'noExtension' | ||
| */ | ||
| function trimExtName(text) { | ||
| const dotIndex = text.lastIndexOf("."); | ||
| if (dotIndex > 0 && !text.includes("/", dotIndex)) return text.slice(0, dotIndex); | ||
| return text; | ||
| } | ||
| //#endregion | ||
| //#region src/utils/index.ts | ||
| /** | ||
| * Strips a single matching pair of `"..."`, `'...'`, or `` `...` `` from both ends of `text`. | ||
| * Returns the string unchanged when no balanced quote pair is found. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * trimQuotes('"hello"') // 'hello' | ||
| * trimQuotes('hello') // 'hello' | ||
| * ``` | ||
| */ | ||
| function trimQuotes(text) { | ||
| if (text.length >= 2) { | ||
| const first = text[0]; | ||
| const last = text[text.length - 1]; | ||
| if (first === "\"" && last === "\"" || first === "'" && last === "'" || first === "`" && last === "`") return text.slice(1, -1); | ||
| } | ||
| return text; | ||
| } | ||
| /** | ||
| * Serializes a primitive value to a single-quoted string literal, stripping any surrounding quote | ||
| * characters first. Escaping comes from `JSON.stringify`, then the quote style switches to single | ||
| * quotes so generated code matches the repo style without a formatter. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * stringify('hello') // "'hello'" | ||
| * stringify('"hello"') // "'hello'" | ||
| * ``` | ||
| */ | ||
| function stringify(value) { | ||
| if (value === void 0 || value === null) return "''"; | ||
| return `'${JSON.stringify(trimQuotes(value.toString())).slice(1, -1).replace(/\\"/g, "\"").replace(/'/g, "\\'")}'`; | ||
| } | ||
| /** | ||
| * Escapes characters that are not allowed inside JS string literals, covering quotes, backslashes, | ||
| * and the Unicode line terminators U+2028 and U+2029. | ||
| * | ||
| * @see http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.4 | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * jsStringEscape('say "hi"\nbye') // 'say \\"hi\\"\\nbye' | ||
| * ``` | ||
| */ | ||
| function jsStringEscape(input) { | ||
| return `${input}`.replace(/["'\\\n\r\u2028\u2029]/g, (character) => { | ||
| switch (character) { | ||
| case "\"": | ||
| case "'": | ||
| case "\\": return `\\${character}`; | ||
| case "\n": return "\\n"; | ||
| case "\r": return "\\r"; | ||
| case "\u2028": return "\\u2028"; | ||
| case "\u2029": return "\\u2029"; | ||
| default: return ""; | ||
| } | ||
| }); | ||
| } | ||
| /** | ||
| * Converts a pattern string into a `new RegExp(...)` constructor call or a regex literal string. | ||
| * Inline flags expressed as a `^(?im)` prefix are extracted and applied to the resulting expression. | ||
| * Pass `null` as the second argument to emit a `/pattern/flags` literal instead. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * toRegExpString('^(?im)foo') // 'new RegExp("^foo", "im")' | ||
| * toRegExpString('^(?im)foo', null) // '/^foo/im' | ||
| * ``` | ||
| */ | ||
| function toRegExpString(text, func = "RegExp") { | ||
| const raw = trimQuotes(text); | ||
| const match = raw.match(/^\^(\(\?([igmsuy]+)\))/i); | ||
| const replacementTarget = match?.[1] ?? ""; | ||
| const matchedFlags = match?.[2]; | ||
| const cleaned = raw.replace(/^\\?\//, "").replace(/\\?\/$/, "").replace(replacementTarget, ""); | ||
| const { source, flags } = new RegExp(cleaned, matchedFlags); | ||
| if (func === null) return `/${source}/${flags}`; | ||
| return `new ${func}(${JSON.stringify(source)}${flags ? `, ${JSON.stringify(flags)}` : ""})`; | ||
| } | ||
| /** | ||
| * Renders a plain object as multi-line `key: value` source for embedding in generated code. Nested | ||
| * objects recurse with fixed indentation, so the result drops straight into an object literal | ||
| * without re-parsing. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * stringifyObject({ foo: 'bar', nested: { a: 1 } }) | ||
| * // 'foo: bar,\nnested: {\n a: 1\n }' | ||
| * ``` | ||
| */ | ||
| function stringifyObject(value) { | ||
| return Object.entries(value).map(([key, val]) => { | ||
| if (val !== null && typeof val === "object") return `${key}: {\n ${stringifyObject(val)}\n }`; | ||
| return `${key}: ${val}`; | ||
| }).filter(Boolean).join(",\n"); | ||
| } | ||
| /** | ||
| * Renders a dotted path or string array as an optional-chaining accessor expression rooted at | ||
| * `accessor`. Returns `null` for an empty path. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * getNestedAccessor('pagination.next.id', 'lastPage') | ||
| * // "lastPage?.['pagination']?.['next']?.['id']" | ||
| * ``` | ||
| */ | ||
| function getNestedAccessor(param, accessor) { | ||
| const parts = Array.isArray(param) ? param : param.split("."); | ||
| if (parts.length === 0 || parts.length === 1 && parts[0] === "") return null; | ||
| return `${accessor}?.['${`${parts.join("']?.['")}']`}`; | ||
| } | ||
| /** | ||
| * Builds a JSDoc comment block from an array of lines, returning `fallback` when there are no | ||
| * comments so callers always get a usable string. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * buildJSDoc(['@type string', '@example hello']) | ||
| * // '/**\n * @type string\n * @example hello\n *\/\n ' | ||
| * ``` | ||
| */ | ||
| function buildJSDoc(comments, options = {}) { | ||
| const { indent = " * ", suffix = "\n ", fallback = " " } = options; | ||
| if (comments.length === 0) return fallback; | ||
| return `/**\n${comments.map((c) => `${indent}${c}`).join("\n")}\n */${suffix}`; | ||
| } | ||
| /** | ||
| * Indents every non-empty line of `text` by one indent level, leaving blank lines empty. | ||
| */ | ||
| function indentLines(text) { | ||
| if (!text) return ""; | ||
| return text.split("\n").map((line) => line.trim() ? `${INDENT}${line}` : "").join("\n"); | ||
| } | ||
| /** | ||
| * Renders an object key, quoting it with single quotes only when it is not a valid identifier. | ||
| * Reserved words and globals (`name`, `class`, …) are valid bare keys and stay unquoted. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * objectKey('name') // 'name' | ||
| * objectKey('x-total') // "'x-total'" | ||
| * ``` | ||
| */ | ||
| function objectKey(name) { | ||
| return isIdentifier(name) ? name : singleQuote(name); | ||
| } | ||
| /** | ||
| * Assembles a multi-line object literal from already-rendered `entries`, indenting each entry one | ||
| * level and closing the brace at column zero. Nested objects built the same way indent cumulatively, | ||
| * so callers never re-parse the generated code. A trailing comma is added per entry to match the | ||
| * formatter's multi-line style. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * buildObject(['id: z.number()', 'name: z.string()']) | ||
| * // '{\n id: z.number(),\n name: z.string(),\n}' | ||
| * ``` | ||
| */ | ||
| function buildObject(entries) { | ||
| if (entries.length === 0) return "{}"; | ||
| return `{\n${entries.map((entry) => `${indentLines(entry)},`).join("\n")}\n}`; | ||
| } | ||
| /** | ||
| * Assembles a bracketed list (array by default) from already-rendered `items`. Keeps everything on | ||
| * one line when no item spans multiple lines, and otherwise puts each item on its own line, indented | ||
| * one level with a trailing comma and the closing bracket at column zero. Use it for `z.union([…])`, | ||
| * `z.array([…])`, and similar member lists so objects inside them nest correctly. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * buildList(['z.string()', 'z.number()']) | ||
| * // '[z.string(), z.number()]' | ||
| * ``` | ||
| */ | ||
| function buildList(items, brackets = ["[", "]"]) { | ||
| const [open, close] = brackets; | ||
| if (items.length === 0) return `${open}${close}`; | ||
| if (!items.some((item) => item.includes("\n"))) return `${open}${items.join(", ")}${close}`; | ||
| return `${open}\n${items.map((item) => `${indentLines(item)},`).join("\n")}\n${close}`; | ||
| } | ||
| /** | ||
| * Returns the last path segment of a reference string. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * extractRefName('#/components/schemas/Pet') // 'Pet' | ||
| * ``` | ||
| */ | ||
| function extractRefName(ref) { | ||
| return ref.split("/").at(-1) ?? ref; | ||
| } | ||
| /** | ||
| * Builds a PascalCase child schema name by joining a parent name and property name. | ||
| * Returns `null` when there is no parent to nest under. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * childName('Order', 'shipping_address') // 'OrderShippingAddress' | ||
| * childName(undefined, 'params') // null | ||
| * ``` | ||
| */ | ||
| function childName(parentName, propName) { | ||
| return parentName ? pascalCase([parentName, propName].join(" ")) : null; | ||
| } | ||
| /** | ||
| * Builds a PascalCase enum name from the parent name, property name, and a suffix, skipping any | ||
| * empty parts. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * enumPropName('Order', 'status', 'enum') // 'OrderStatusEnum' | ||
| * ``` | ||
| */ | ||
| function enumPropName(parentName, propName, enumSuffix) { | ||
| return pascalCase([ | ||
| parentName, | ||
| propName, | ||
| enumSuffix | ||
| ].filter(Boolean).join(" ")); | ||
| } | ||
| /** | ||
| * Returns the discriminator key whose mapping value matches `ref`, or `null` when there is no match. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * findDiscriminator({ dog: '#/components/schemas/Dog' }, '#/components/schemas/Dog') // 'dog' | ||
| * ``` | ||
| */ | ||
| function findDiscriminator(mapping, ref) { | ||
| if (!mapping || !ref) return null; | ||
| return Object.entries(mapping).find(([, value]) => value === ref)?.[0] ?? null; | ||
| } | ||
| //#endregion | ||
| Object.defineProperty(exports, "__name", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return __name; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "__toESM", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return __toESM; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "buildJSDoc", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return buildJSDoc; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "buildList", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return buildList; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "buildObject", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return buildObject; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "camelCase", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return camelCase; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "childName", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return childName; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "ensureValidVarName", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return ensureValidVarName; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "enumPropName", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return enumPropName; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "extractRefName", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return extractRefName; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "findDiscriminator", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return findDiscriminator; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "getNestedAccessor", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return getNestedAccessor; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "httpMethods", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return httpMethods; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "isScalarPrimitive", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return isScalarPrimitive; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "isValidVarName", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return isValidVarName; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "jsStringEscape", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return jsStringEscape; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "objectKey", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return objectKey; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "schemaTypes", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return schemaTypes; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "stringify", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return stringify; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "stringifyObject", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return stringifyObject; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "toRegExpString", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return toRegExpString; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "trimExtName", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return trimExtName; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "trimQuotes", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return trimQuotes; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, "visitorDepths", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return visitorDepths; | ||
| } | ||
| }); | ||
| //# sourceMappingURL=utils-CMRZrT-w.cjs.map |
| {"version":3,"file":"utils-CMRZrT-w.cjs","names":[],"sources":["../src/constants.ts","../../../internals/utils/src/casing.ts","../../../internals/utils/src/reserved.ts","../../../internals/utils/src/string.ts","../src/utils/index.ts"],"sourcesContent":["import type { HttpMethod } from './nodes/operation.ts'\nimport type { SchemaType } from './nodes/schema.ts'\n\n/**\n * Traversal depth for AST visitor utilities.\n *\n * - `'shallow'` visits only the immediate node, skipping children.\n * - `'deep'` recursively visits all descendant nodes.\n */\nexport type VisitorDepth = 'shallow' | 'deep'\n\nexport const visitorDepths = {\n shallow: 'shallow',\n deep: 'deep',\n} as const satisfies Record<VisitorDepth, VisitorDepth>\n\n/**\n * Schema type discriminators used by all AST schema nodes.\n *\n * These values serve as stable discriminators across the AST (e.g., `schema.type === schemaTypes.object`).\n * Grouped by category: primitives (`string`, `number`, `boolean`), structural types (`object`, `array`, `union`),\n * and format-specific types (`date`, `uuid`, `email`). Use `isScalarPrimitive()` to check for scalar types.\n */\nexport const schemaTypes = {\n /**\n * Text value.\n */\n string: 'string',\n /**\n * Floating-point number (`float`, `double`).\n */\n number: 'number',\n /**\n * Whole number (`int32`). Use `bigint` for `int64`.\n */\n integer: 'integer',\n /**\n * 64-bit integer (`int64`). Only used when `integerType` is set to `'bigint'`.\n */\n bigint: 'bigint',\n /**\n * Boolean value\n */\n boolean: 'boolean',\n /**\n * Explicit null value.\n */\n null: 'null',\n /**\n * Any value (no type restriction).\n */\n any: 'any',\n /**\n * Unknown value (must be narrowed before usage).\n */\n unknown: 'unknown',\n /**\n * No return value (`void`).\n */\n void: 'void',\n /**\n * Object with named properties.\n */\n object: 'object',\n /**\n * Sequential list of items.\n */\n array: 'array',\n /**\n * Fixed-length list with position-specific items.\n */\n tuple: 'tuple',\n /**\n * \"One of\" multiple schema members.\n */\n union: 'union',\n /**\n * \"All of\" multiple schema members.\n */\n intersection: 'intersection',\n /**\n * Enum schema.\n */\n enum: 'enum',\n /**\n * Reference to another schema.\n */\n ref: 'ref',\n /**\n * Calendar date (for example `2026-03-24`).\n */\n date: 'date',\n /**\n * Date-time value (for example `2026-03-24T09:00:00Z`).\n */\n datetime: 'datetime',\n /**\n * Time-only value (for example `09:00:00`).\n */\n time: 'time',\n /**\n * UUID value.\n */\n uuid: 'uuid',\n /**\n * Email address value.\n */\n email: 'email',\n /**\n * URL value.\n */\n url: 'url',\n /**\n * IPv4 address value.\n */\n ipv4: 'ipv4',\n /**\n * IPv6 address value.\n */\n ipv6: 'ipv6',\n /**\n * Binary/blob value.\n */\n blob: 'blob',\n /**\n * Impossible value (`never`).\n */\n never: 'never',\n} as const satisfies Record<SchemaType, SchemaType>\n\nexport type ScalarPrimitive = 'string' | 'number' | 'integer' | 'bigint' | 'boolean'\n\n/**\n * Scalar primitive schema types used for union simplification and type narrowing.\n *\n * Use `isScalarPrimitive()` to safely check whether a type is a scalar primitive.\n */\nconst SCALAR_PRIMITIVE_TYPES = new Set<ScalarPrimitive>(['string', 'number', 'integer', 'bigint', 'boolean'])\n\n/**\n * Type guard that returns `true` when `type` is a scalar primitive schema type.\n *\n * Use this to check if a schema type can be directly assigned without wrapping (e.g., `string | number | boolean`).\n */\nexport function isScalarPrimitive(type: string): type is ScalarPrimitive {\n return SCALAR_PRIMITIVE_TYPES.has(type as ScalarPrimitive)\n}\n\n/**\n * HTTP method identifiers used by operation nodes.\n *\n * Includes all standard HTTP methods (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, TRACE).\n */\nexport const httpMethods = {\n get: 'GET',\n post: 'POST',\n put: 'PUT',\n patch: 'PATCH',\n delete: 'DELETE',\n head: 'HEAD',\n options: 'OPTIONS',\n trace: 'TRACE',\n} as const satisfies Record<Lowercase<HttpMethod>, HttpMethod>\n\n/**\n * Default concurrency limit for `walk()` traversal utility.\n *\n * Set to 30 to balance I/O-bound resolver parallelism against event loop pressure and memory usage during large spec traversals.\n * Use `WALK_CONCURRENCY` when calling `walk()` or override for different hardware constraints.\n *\n * @example\n * ```ts\n * import { walk, WALK_CONCURRENCY } from '@kubb/ast'\n *\n * walk(root, { concurrency: WALK_CONCURRENCY, root: () => {} })\n * ```\n */\nexport const WALK_CONCURRENCY = 30\n\n/**\n * Number of spaces in one indentation level when assembling multi-line code as strings.\n * Set to 2, 3, … to change the indent width used by `buildObject`/`buildList`.\n */\nconst INDENT_SIZE = 2\n\n/**\n * One indentation level, derived from {@link INDENT_SIZE}.\n */\nexport const INDENT = Array.from({ length: INDENT_SIZE }, () => ' ').join('')\n","type Options = {\n /**\n * When `true`, dot-separated segments are split on `.` and joined with `/` after casing.\n */\n isFile?: boolean\n /**\n * Text prepended before casing is applied.\n */\n prefix?: string\n /**\n * Text appended before casing is applied.\n */\n suffix?: string\n}\n\n/**\n * Shared implementation for camelCase and PascalCase conversion.\n * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)\n * and capitalizes each word according to `pascal`.\n *\n * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.\n */\nfunction toCamelOrPascal(text: string, pascal: boolean): string {\n const normalized = text\n .trim()\n .replace(/([a-z\\d])([A-Z])/g, '$1 $2')\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')\n .replace(/(\\d)([a-z])/g, '$1 $2')\n\n const words = normalized.split(/[\\s\\-_./\\\\:]+/).filter(Boolean)\n\n return words\n .map((word, i) => {\n const allUpper = word.length > 1 && word === word.toUpperCase()\n if (allUpper) return word\n if (i === 0 && !pascal) return word.charAt(0).toLowerCase() + word.slice(1)\n return word.charAt(0).toUpperCase() + word.slice(1)\n })\n .join('')\n .replace(/[^a-zA-Z0-9]/g, '')\n}\n\n/**\n * Splits `text` on `.` and applies `transformPart` to each segment.\n * The last segment receives `isLast = true`, all earlier segments receive `false`.\n * Segments are joined with `/` to form a file path.\n *\n * Only splits on dots followed by a letter so that version numbers\n * embedded in operationIds (e.g. `v2025.0`) are kept intact.\n *\n * Empty segments are filtered before joining. They arise when the text starts with\n * a dot followed immediately by a letter (e.g. `..Schema` splits into `['..', 'Schema']`\n * and `'..'` transforms to an empty string). Without this filter the join would produce\n * a leading `/`, which `path.resolve` would interpret as an absolute path, allowing\n * generated files to escape the configured output directory.\n */\nfunction applyToFileParts(text: string, transformPart: (part: string, isLast: boolean) => string): string {\n const parts = text.split(/\\.(?=[a-zA-Z])/)\n return parts\n .map((part, i) => transformPart(part, i === parts.length - 1))\n .filter(Boolean)\n .join('/')\n}\n\n/**\n * Converts `text` to camelCase.\n * When `isFile` is `true`, dot-separated segments are each cased independently and joined with `/`.\n *\n * @example\n * camelCase('hello-world') // 'helloWorld'\n * camelCase('pet.petId', { isFile: true }) // 'pet/petId'\n */\nexport function camelCase(text: string, { isFile, prefix = '', suffix = '' }: Options = {}): string {\n if (isFile) {\n return applyToFileParts(text, (part, isLast) => camelCase(part, isLast ? { prefix, suffix } : {}))\n }\n\n return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false)\n}\n\n/**\n * Converts `text` to PascalCase.\n * When `isFile` is `true`, the last dot-separated segment is PascalCased and earlier segments are camelCased.\n *\n * @example\n * pascalCase('hello-world') // 'HelloWorld'\n * pascalCase('pet.petId', { isFile: true }) // 'pet/PetId'\n */\nexport function pascalCase(text: string, { isFile, prefix = '', suffix = '' }: Options = {}): string {\n if (isFile) {\n return applyToFileParts(text, (part, isLast) => (isLast ? pascalCase(part, { prefix, suffix }) : camelCase(part)))\n }\n\n return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true)\n}\n","/**\n * JavaScript and Java reserved words.\n * @link https://github.com/jonschlinkert/reserved/blob/master/index.js\n */\nconst reservedWords = new Set([\n 'abstract',\n 'arguments',\n 'boolean',\n 'break',\n 'byte',\n 'case',\n 'catch',\n 'char',\n 'class',\n 'const',\n 'continue',\n 'debugger',\n 'default',\n 'delete',\n 'do',\n 'double',\n 'else',\n 'enum',\n 'eval',\n 'export',\n 'extends',\n 'false',\n 'final',\n 'finally',\n 'float',\n 'for',\n 'function',\n 'goto',\n 'if',\n 'implements',\n 'import',\n 'in',\n 'instanceof',\n 'int',\n 'interface',\n 'let',\n 'long',\n 'native',\n 'new',\n 'null',\n 'package',\n 'private',\n 'protected',\n 'public',\n 'return',\n 'short',\n 'static',\n 'super',\n 'switch',\n 'synchronized',\n 'this',\n 'throw',\n 'throws',\n 'transient',\n 'true',\n 'try',\n 'typeof',\n 'var',\n 'void',\n 'volatile',\n 'while',\n 'with',\n 'yield',\n 'Array',\n 'Date',\n 'hasOwnProperty',\n 'Infinity',\n 'isFinite',\n 'isNaN',\n 'isPrototypeOf',\n 'length',\n 'Math',\n 'name',\n 'NaN',\n 'Number',\n 'Object',\n 'prototype',\n 'String',\n 'toString',\n 'undefined',\n 'valueOf',\n] as const)\n\n/**\n * Prefixes `word` with `_` when it is a reserved JavaScript/Java identifier or starts with a digit.\n *\n * @example\n * ```ts\n * transformReservedWord('class') // '_class'\n * transformReservedWord('42foo') // '_42foo'\n * transformReservedWord('status') // 'status'\n * ```\n */\nexport function transformReservedWord(word: string): string {\n const firstChar = word.charCodeAt(0)\n if (word && (reservedWords.has(word as 'valueOf') || (firstChar >= 48 && firstChar <= 57))) {\n return `_${word}`\n }\n return word\n}\n\n/**\n * Returns `true` when `name` is a syntactically valid JavaScript variable name.\n *\n * @example\n * ```ts\n * isValidVarName('status') // true\n * isValidVarName('class') // false (reserved word)\n * isValidVarName('42foo') // false (starts with digit)\n * ```\n */\nexport function isValidVarName(name: string): boolean {\n if (!name || reservedWords.has(name as 'valueOf')) {\n return false\n }\n return isIdentifier(name)\n}\n\n/**\n * Returns `name` when it is already a valid JavaScript variable name, otherwise prefixes it with `_`\n * so the result can be used as an identifier. Useful for sanitizing schema names or operation IDs\n * that start with a digit (`409`, `504AccountCancel`) or collide with a reserved word.\n *\n * @example\n * ```ts\n * ensureValidVarName('409') // '_409'\n * ensureValidVarName('Pet') // 'Pet'\n * ensureValidVarName('class') // '_class'\n * ```\n */\nexport function ensureValidVarName(name: string): string {\n if (!name || isValidVarName(name)) {\n return name\n }\n return `_${name}`\n}\n\n/**\n * Returns `true` when `name` is syntactically a valid identifier, ignoring reserved words.\n *\n * Reserved words and globals (`class`, `name`, `Date`, …) are valid as bare object-literal keys\n * even though they are not valid variable names, so use this (not {@link isValidVarName}) when\n * deciding whether an object key needs quoting.\n *\n * @example\n * ```ts\n * isIdentifier('name') // true\n * isIdentifier('x-total')// false\n * ```\n */\nexport function isIdentifier(name: string): boolean {\n return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name)\n}\n","/**\n * Returns a masked version of a string, showing only the first and last few characters.\n * Useful for logging sensitive values (tokens, keys) without exposing the full value.\n *\n * @example\n * maskString('KUBB_STUDIO-abc123-xyz789') // 'KUBB_STUDIO-…789'\n */\nexport function maskString(value: string, start = 8, end = 4): string {\n if (value.length <= start + end) return value\n return `${value.slice(0, start)}…${value.slice(-end)}`\n}\n\n/**\n * Wraps a value in single quotes for emitting a single-quoted JavaScript string literal, escaping\n * any backslash or single quote in the content.\n *\n * @example\n * ```ts\n * singleQuote('foo') // \"'foo'\"\n * singleQuote(\"o'clock\") // \"'o\\\\'clock'\"\n * ```\n */\nexport function singleQuote(value: string | number | boolean | undefined | null): string {\n if (value === undefined || value === null) return \"''\"\n const escaped = String(value).replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\")\n return `'${escaped}'`\n}\n\n/**\n * Strips the file extension from a path or file name.\n * Only removes the last `.ext` segment when the dot is not part of a directory name.\n *\n * @example\n * trimExtName('petStore.ts') // 'petStore'\n * trimExtName('/src/models/pet.ts') // '/src/models/pet'\n * trimExtName('/project.v2/gen/pet.ts') // '/project.v2/gen/pet'\n * trimExtName('noExtension') // 'noExtension'\n */\nexport function trimExtName(text: string): string {\n const dotIndex = text.lastIndexOf('.')\n if (dotIndex > 0 && !text.includes('/', dotIndex)) {\n return text.slice(0, dotIndex)\n }\n return text\n}\n","import { isIdentifier, pascalCase, singleQuote } from '@internals/utils'\nimport { INDENT } from '../constants.ts'\n\nexport { ensureValidVarName, isValidVarName } from '@internals/utils'\n\n/**\n * Strips a single matching pair of `\"...\"`, `'...'`, or `` `...` `` from both ends of `text`.\n * Returns the string unchanged when no balanced quote pair is found.\n *\n * @example\n * ```ts\n * trimQuotes('\"hello\"') // 'hello'\n * trimQuotes('hello') // 'hello'\n * ```\n */\nexport function trimQuotes(text: string): string {\n if (text.length >= 2) {\n const first = text[0]\n const last = text[text.length - 1]\n if ((first === '\"' && last === '\"') || (first === \"'\" && last === \"'\") || (first === '`' && last === '`')) {\n return text.slice(1, -1)\n }\n }\n return text\n}\n\n/**\n * Serializes a primitive value to a single-quoted string literal, stripping any surrounding quote\n * characters first. Escaping comes from `JSON.stringify`, then the quote style switches to single\n * quotes so generated code matches the repo style without a formatter.\n *\n * @example\n * ```ts\n * stringify('hello') // \"'hello'\"\n * stringify('\"hello\"') // \"'hello'\"\n * ```\n */\nexport function stringify(value: string | number | boolean | undefined): string {\n if (value === undefined || value === null) return \"''\"\n const json = JSON.stringify(trimQuotes(value.toString()))\n const inner = json.slice(1, -1).replace(/\\\\\"/g, '\"').replace(/'/g, \"\\\\'\")\n return `'${inner}'`\n}\n\n/**\n * Escapes characters that are not allowed inside JS string literals, covering quotes, backslashes,\n * and the Unicode line terminators U+2028 and U+2029.\n *\n * @see http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.4\n *\n * @example\n * ```ts\n * jsStringEscape('say \"hi\"\\nbye') // 'say \\\\\"hi\\\\\"\\\\nbye'\n * ```\n */\nexport function jsStringEscape(input: unknown): string {\n return `${input}`.replace(/[\"'\\\\\\n\\r\\u2028\\u2029]/g, (character) => {\n switch (character) {\n case '\"':\n case \"'\":\n case '\\\\':\n return `\\\\${character}`\n case '\\n':\n return '\\\\n'\n case '\\r':\n return '\\\\r'\n case '\\u2028':\n return '\\\\u2028'\n case '\\u2029':\n return '\\\\u2029'\n default:\n return ''\n }\n })\n}\n\n/**\n * Converts a pattern string into a `new RegExp(...)` constructor call or a regex literal string.\n * Inline flags expressed as a `^(?im)` prefix are extracted and applied to the resulting expression.\n * Pass `null` as the second argument to emit a `/pattern/flags` literal instead.\n *\n * @example\n * ```ts\n * toRegExpString('^(?im)foo') // 'new RegExp(\"^foo\", \"im\")'\n * toRegExpString('^(?im)foo', null) // '/^foo/im'\n * ```\n */\nexport function toRegExpString(text: string, func: string | null = 'RegExp'): string {\n const raw = trimQuotes(text)\n\n const match = raw.match(/^\\^(\\(\\?([igmsuy]+)\\))/i)\n const replacementTarget = match?.[1] ?? ''\n const matchedFlags = match?.[2]\n const cleaned = raw\n .replace(/^\\\\?\\//, '')\n .replace(/\\\\?\\/$/, '')\n .replace(replacementTarget, '')\n\n const { source, flags } = new RegExp(cleaned, matchedFlags)\n\n if (func === null) return `/${source}/${flags}`\n\n return `new ${func}(${JSON.stringify(source)}${flags ? `, ${JSON.stringify(flags)}` : ''})`\n}\n\n/**\n * Renders a plain object as multi-line `key: value` source for embedding in generated code. Nested\n * objects recurse with fixed indentation, so the result drops straight into an object literal\n * without re-parsing.\n *\n * @example\n * ```ts\n * stringifyObject({ foo: 'bar', nested: { a: 1 } })\n * // 'foo: bar,\\nnested: {\\n a: 1\\n }'\n * ```\n */\nexport function stringifyObject(value: Record<string, unknown>): string {\n const items = Object.entries(value)\n .map(([key, val]) => {\n if (val !== null && typeof val === 'object') {\n return `${key}: {\\n ${stringifyObject(val as Record<string, unknown>)}\\n }`\n }\n return `${key}: ${val}`\n })\n .filter(Boolean)\n return items.join(',\\n')\n}\n\n/**\n * Renders a dotted path or string array as an optional-chaining accessor expression rooted at\n * `accessor`. Returns `null` for an empty path.\n *\n * @example\n * ```ts\n * getNestedAccessor('pagination.next.id', 'lastPage')\n * // \"lastPage?.['pagination']?.['next']?.['id']\"\n * ```\n */\nexport function getNestedAccessor(param: string | Array<string>, accessor: string): string | null {\n const parts = Array.isArray(param) ? param : param.split('.')\n if (parts.length === 0 || (parts.length === 1 && parts[0] === '')) return null\n return `${accessor}?.['${`${parts.join(\"']?.['\")}']`}`\n}\n\n/**\n * Builds a JSDoc comment block from an array of lines, returning `fallback` when there are no\n * comments so callers always get a usable string.\n *\n * @example\n * ```ts\n * buildJSDoc(['@type string', '@example hello'])\n * // '/**\\n * @type string\\n * @example hello\\n *\\/\\n '\n * ```\n */\nexport function buildJSDoc(\n comments: Array<string>,\n options: {\n /**\n * String used to indent each comment line.\n * @default ' * '\n */\n indent?: string\n /**\n * String appended after the closing tag.\n * @default '\\n '\n */\n suffix?: string\n /**\n * Returned as-is when `comments` is empty.\n * @default ' '\n */\n fallback?: string\n } = {},\n): string {\n const { indent = ' * ', suffix = '\\n ', fallback = ' ' } = options\n\n if (comments.length === 0) return fallback\n\n return `/**\\n${comments.map((c) => `${indent}${c}`).join('\\n')}\\n */${suffix}`\n}\n\n/**\n * Indents every non-empty line of `text` by one indent level, leaving blank lines empty.\n */\nfunction indentLines(text: string): string {\n if (!text) return ''\n return text\n .split('\\n')\n .map((line) => (line.trim() ? `${INDENT}${line}` : ''))\n .join('\\n')\n}\n\n/**\n * Renders an object key, quoting it with single quotes only when it is not a valid identifier.\n * Reserved words and globals (`name`, `class`, …) are valid bare keys and stay unquoted.\n *\n * @example\n * ```ts\n * objectKey('name') // 'name'\n * objectKey('x-total') // \"'x-total'\"\n * ```\n */\nexport function objectKey(name: string): string {\n return isIdentifier(name) ? name : singleQuote(name)\n}\n\n/**\n * Assembles a multi-line object literal from already-rendered `entries`, indenting each entry one\n * level and closing the brace at column zero. Nested objects built the same way indent cumulatively,\n * so callers never re-parse the generated code. A trailing comma is added per entry to match the\n * formatter's multi-line style.\n *\n * @example\n * ```ts\n * buildObject(['id: z.number()', 'name: z.string()'])\n * // '{\\n id: z.number(),\\n name: z.string(),\\n}'\n * ```\n */\nexport function buildObject(entries: Array<string>): string {\n if (entries.length === 0) return '{}'\n const body = entries.map((entry) => `${indentLines(entry)},`).join('\\n')\n return `{\\n${body}\\n}`\n}\n\n/**\n * Assembles a bracketed list (array by default) from already-rendered `items`. Keeps everything on\n * one line when no item spans multiple lines, and otherwise puts each item on its own line, indented\n * one level with a trailing comma and the closing bracket at column zero. Use it for `z.union([…])`,\n * `z.array([…])`, and similar member lists so objects inside them nest correctly.\n *\n * @example\n * ```ts\n * buildList(['z.string()', 'z.number()'])\n * // '[z.string(), z.number()]'\n * ```\n */\nexport function buildList(items: Array<string>, brackets: [open: string, close: string] = ['[', ']']): string {\n const [open, close] = brackets\n if (items.length === 0) return `${open}${close}`\n if (!items.some((item) => item.includes('\\n'))) return `${open}${items.join(', ')}${close}`\n const body = items.map((item) => `${indentLines(item)},`).join('\\n')\n return `${open}\\n${body}\\n${close}`\n}\n\n/**\n * Returns the last path segment of a reference string.\n *\n * @example\n * ```ts\n * extractRefName('#/components/schemas/Pet') // 'Pet'\n * ```\n */\nexport function extractRefName(ref: string): string {\n return ref.split('/').at(-1) ?? ref\n}\n\n/**\n * Builds a PascalCase child schema name by joining a parent name and property name.\n * Returns `null` when there is no parent to nest under.\n *\n * @example\n * ```ts\n * childName('Order', 'shipping_address') // 'OrderShippingAddress'\n * childName(undefined, 'params') // null\n * ```\n */\nexport function childName(parentName: string | null | undefined, propName: string): string | null {\n return parentName ? pascalCase([parentName, propName].join(' ')) : null\n}\n\n/**\n * Builds a PascalCase enum name from the parent name, property name, and a suffix, skipping any\n * empty parts.\n *\n * @example\n * ```ts\n * enumPropName('Order', 'status', 'enum') // 'OrderStatusEnum'\n * ```\n */\nexport function enumPropName(parentName: string | null | undefined, propName: string, enumSuffix: string): string {\n return pascalCase([parentName, propName, enumSuffix].filter(Boolean).join(' '))\n}\n\n/**\n * Returns the discriminator key whose mapping value matches `ref`, or `null` when there is no match.\n *\n * @example\n * ```ts\n * findDiscriminator({ dog: '#/components/schemas/Dog' }, '#/components/schemas/Dog') // 'dog'\n * ```\n */\nexport function findDiscriminator(mapping: Record<string, string> | undefined, ref: string | undefined): string | null {\n if (!mapping || !ref) return null\n return Object.entries(mapping).find(([, value]) => value === ref)?.[0] ?? null\n}\n"],"mappings":"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"} |
| /** | ||
| * One entry in an ordered dispatch table: a predicate paired with a converter. | ||
| * | ||
| * @typeParam TContext - Per-input context handed to every rule. A spec adapter typically | ||
| * pre-computes this once per node (the source spec node plus derived fields like a | ||
| * normalized type or resolved options) so individual rules stay cheap predicates. | ||
| * @typeParam TNode - The node a rule produces, e.g. a Kubb AST `SchemaNode`. | ||
| */ | ||
| export type DispatchRule<TContext, TNode> = { | ||
| /** Identifies the rule when reading the table or debugging which branch ran. */ | ||
| name: string | ||
| /** Returns `true` when this rule is responsible for the given context. */ | ||
| match: (context: TContext) => boolean | ||
| /** | ||
| * Produces a node for the context, or `null` to fall through to the next rule. | ||
| * | ||
| * Returning `null` lets a broad `match` defer: e.g. "has a `format`" matches many schemas, | ||
| * but only some formats are convertible, the rest fall through to plain `type` handling. | ||
| */ | ||
| convert: (context: TContext) => TNode | null | ||
| } | ||
| /** | ||
| * Walks an ordered list of {@link DispatchRule}s and returns the first node produced. | ||
| * | ||
| * This is the shared backbone for spec adapters (OpenAPI today, AsyncAPI and others later). | ||
| * The contract an adapter follows is intentionally minimal: | ||
| * | ||
| * context → [rule.match → rule.convert] → node | ||
| * | ||
| * An adapter derives a context from a source spec node, then declares an ordered table of | ||
| * rules mapping spec shapes onto Kubb AST nodes. To add support for a new spec, write a new | ||
| * context type and a new rules table, the traversal here is reused unchanged. | ||
| * | ||
| * Order is significant: earlier rules win, so list higher-precedence or more specific shapes | ||
| * first (e.g. composition keywords before plain `type`). A rule whose `match` returns `true` | ||
| * may still `convert` to `null` to defer to later rules. When no rule produces a node this | ||
| * returns `null`, leaving the caller to apply its own fallback. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const node = dispatch(schemaRules, schemaContext) ?? createSchema({ type: fallbackType }) | ||
| * ``` | ||
| */ | ||
| export function dispatch<TContext, TNode>(rules: ReadonlyArray<DispatchRule<TContext, TNode>>, context: TContext): TNode | null { | ||
| for (const rule of rules) { | ||
| if (!rule.match(context)) continue | ||
| const node = rule.convert(context) | ||
| if (node !== null && node !== undefined) return node | ||
| } | ||
| return null | ||
| } |
| import type { BaseNode } from './base.ts' | ||
| import type { OperationNode } from './operation.ts' | ||
| import type { SchemaNode } from './schema.ts' | ||
| /** | ||
| * Metadata for an API document, populated by the adapter and available to every generator. | ||
| * | ||
| * All fields are plain JSON-serializable values, no `Set`, no `Map`, no class instances. | ||
| * Computed fields (`circularNames`, `enumNames`) are pre-calculated once during the adapter | ||
| * pre-scan so generators never need to iterate the full schema list themselves. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const meta: InputMeta = { title: 'Pet Store', version: '1.0.0', baseURL: 'https://petstore.swagger.io/v2', circularNames: [], enumNames: [] } | ||
| * ``` | ||
| */ | ||
| export type InputMeta = { | ||
| /** | ||
| * API title from `info.title` in the source document. | ||
| */ | ||
| title?: string | ||
| /** | ||
| * API description from `info.description` in the source document. | ||
| */ | ||
| description?: string | ||
| /** | ||
| * API version string from `info.version` in the source document. | ||
| */ | ||
| version?: string | ||
| /** | ||
| * Resolved base URL from the first matching server entry in the source document. | ||
| */ | ||
| baseURL?: string | null | ||
| /** | ||
| * Names of schemas that participate in a circular reference chain. | ||
| * Computed once during the adapter pre-scan, use this instead of calling | ||
| * `findCircularSchemas` per generator call. | ||
| * | ||
| * Convert to a `Set` once at the start of a generator, not per-schema, | ||
| * to keep lookup O(1) without repeated allocations. | ||
| * | ||
| * @example Wrap a circular schema in z.lazy() | ||
| * ```ts | ||
| * const circular = new Set(meta.circularNames) | ||
| * if (circular.has(schema.name)) { ... } | ||
| * ``` | ||
| */ | ||
| circularNames: ReadonlyArray<string> | ||
| /** | ||
| * Names of schemas whose type is `enum`. | ||
| * Computed once during the adapter pre-scan, use this instead of filtering | ||
| * schemas per generator call. | ||
| * | ||
| * Convert to a `Set` once at the start of a generator when you need repeated | ||
| * membership checks, rather than calling `.includes()` per schema. | ||
| * | ||
| * @example Check if a referenced schema is an enum | ||
| * `const enums = new Set(meta.enumNames)` | ||
| * `const isEnum = enums.has(schemaName)` | ||
| */ | ||
| enumNames: ReadonlyArray<string> | ||
| } | ||
| /** | ||
| * Input AST node that contains all schemas and operations for one API document. | ||
| * Produced by the adapter and consumed by all Kubb plugins. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const input: InputNode = { | ||
| * kind: 'Input', | ||
| * schemas: [], | ||
| * operations: [], | ||
| * } | ||
| * ``` | ||
| */ | ||
| export type InputNode = BaseNode & { | ||
| /** | ||
| * Node kind. | ||
| */ | ||
| kind: 'Input' | ||
| /** | ||
| * All schema nodes in the document. | ||
| */ | ||
| schemas: Array<SchemaNode> | ||
| /** | ||
| * All operation nodes in the document. | ||
| */ | ||
| operations: Array<OperationNode> | ||
| /** | ||
| * Document metadata populated by the adapter. | ||
| */ | ||
| meta: InputMeta | ||
| } | ||
| /** | ||
| * Streaming variant of `InputNode` for memory-efficient processing of large API specs. | ||
| * | ||
| * `schemas` and `operations` are `AsyncIterable` rather than arrays, each `for await` | ||
| * loop creates a fresh parse pass from the cached in-memory document, so multiple | ||
| * consumers (plugins) can iterate independently without keeping all nodes in memory. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * for await (const schema of inputStreamNode.schemas) { | ||
| * // only this one SchemaNode is live here. Previous ones are GC-eligible | ||
| * } | ||
| * ``` | ||
| */ | ||
| export type InputStreamNode = { | ||
| kind: 'Input' | ||
| /** | ||
| * Lazily parsed schema nodes. Each `for await` creates a fresh parse pass, so | ||
| * multiple plugins can iterate independently without sharing state. | ||
| */ | ||
| schemas: AsyncIterable<SchemaNode> | ||
| /** | ||
| * Lazily parsed operation nodes. Each `for await` creates a fresh parse pass, so | ||
| * multiple plugins can iterate independently without sharing state. | ||
| */ | ||
| operations: AsyncIterable<OperationNode> | ||
| /** | ||
| * Document metadata available immediately, before the first yielded node. | ||
| */ | ||
| meta?: InputMeta | ||
| } |
| import { narrowSchema } from './guards.ts' | ||
| import type { SchemaNode } from './nodes/schema.ts' | ||
| import { collect } from './visitor.ts' | ||
| import { extractRefName } from './utils/index.ts' | ||
| /** | ||
| * Collects import entries for all `ref` schema nodes in `node`. | ||
| */ | ||
| export function collectImports<TImport>({ | ||
| node, | ||
| nameMapping, | ||
| resolve, | ||
| }: { | ||
| node: SchemaNode | ||
| nameMapping: Map<string, string> | ||
| resolve: (schemaName: string) => TImport | null | ||
| }): Array<TImport> { | ||
| return collect<TImport>(node, { | ||
| schema(schemaNode): TImport | null { | ||
| const schemaRef = narrowSchema(schemaNode, 'ref') | ||
| if (!schemaRef?.ref) return null | ||
| const rawName = extractRefName(schemaRef.ref) | ||
| const schemaName = nameMapping.get(rawName) ?? rawName | ||
| const result = resolve(schemaName) | ||
| if (!result) return null | ||
| return result | ||
| }, | ||
| }) | ||
| } |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
845335
-3.06%50
-1.96%15705
-2.71%