@kubb/plugin-ts 5.0.0-alpha.9 → 5.0.0-beta.100

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/LICENSE +17 -10
  2. package/README.md +38 -23
  3. package/dist/index.cjs +2376 -5
  4. package/dist/index.cjs.map +1 -0
  5. package/dist/index.d.ts +941 -40
  6. package/dist/index.js +2321 -2
  7. package/dist/index.js.map +1 -0
  8. package/dist/rolldown-runtime-CNktS9qV.js +17 -0
  9. package/package.json +38 -74
  10. package/dist/chunk--u3MIqq1.js +0 -8
  11. package/dist/components-CRu8IKY3.js +0 -729
  12. package/dist/components-CRu8IKY3.js.map +0 -1
  13. package/dist/components-DeNDKlzf.cjs +0 -982
  14. package/dist/components-DeNDKlzf.cjs.map +0 -1
  15. package/dist/components.cjs +0 -3
  16. package/dist/components.d.ts +0 -36
  17. package/dist/components.js +0 -2
  18. package/dist/generators.cjs +0 -4
  19. package/dist/generators.d.ts +0 -509
  20. package/dist/generators.js +0 -2
  21. package/dist/plugin-BZkBwnEA.js +0 -1269
  22. package/dist/plugin-BZkBwnEA.js.map +0 -1
  23. package/dist/plugin-Bunz1oGa.cjs +0 -1322
  24. package/dist/plugin-Bunz1oGa.cjs.map +0 -1
  25. package/dist/types-mSXmB8WU.d.ts +0 -298
  26. package/src/components/Type.tsx +0 -190
  27. package/src/components/index.ts +0 -1
  28. package/src/components/v2/Enum.tsx +0 -67
  29. package/src/components/v2/Type.tsx +0 -59
  30. package/src/constants.ts +0 -29
  31. package/src/factory.ts +0 -726
  32. package/src/generators/index.ts +0 -2
  33. package/src/generators/typeGenerator.tsx +0 -468
  34. package/src/generators/v2/typeGenerator.tsx +0 -167
  35. package/src/generators/v2/utils.ts +0 -140
  36. package/src/index.ts +0 -3
  37. package/src/parser.ts +0 -389
  38. package/src/plugin.ts +0 -232
  39. package/src/printer.ts +0 -368
  40. package/src/resolverTs.ts +0 -77
  41. package/src/types.ts +0 -296
package/dist/index.cjs CHANGED
@@ -1,5 +1,2376 @@
1
- Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_plugin = require("./plugin-Bunz1oGa.cjs");
3
- exports.pluginTs = require_plugin.pluginTs;
4
- exports.pluginTsName = require_plugin.pluginTsName;
5
- exports.resolverTs = require_plugin.resolverTs;
1
+ Object.defineProperties(exports, {
2
+ __esModule: { value: true },
3
+ [Symbol.toStringTag]: { value: "Module" }
4
+ });
5
+ //#region \0rolldown/runtime.js
6
+ var __create = Object.create;
7
+ var __defProp = Object.defineProperty;
8
+ var __name = (target, value) => __defProp(target, "name", {
9
+ value,
10
+ configurable: true
11
+ });
12
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
13
+ var __getOwnPropNames = Object.getOwnPropertyNames;
14
+ var __getProtoOf = Object.getPrototypeOf;
15
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
16
+ var __exportAll = (all, no_symbols) => {
17
+ let target = {};
18
+ for (var name in all) __defProp(target, name, {
19
+ get: all[name],
20
+ enumerable: true
21
+ });
22
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
23
+ return target;
24
+ };
25
+ var __copyProps = (to, from, except, desc) => {
26
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
27
+ key = keys[i];
28
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
29
+ get: ((k) => from[k]).bind(null, key),
30
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
31
+ });
32
+ }
33
+ return to;
34
+ };
35
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
36
+ value: mod,
37
+ enumerable: true
38
+ }) : target, mod));
39
+ //#endregion
40
+ let _kubb_parser_ts = require("@kubb/parser-ts");
41
+ let kubb_jsx = require("kubb/jsx");
42
+ let kubb_kit = require("kubb/kit");
43
+ let typescript = require("typescript");
44
+ typescript = __toESM(typescript, 1);
45
+ let kubb_jsx_jsx_runtime = require("kubb/jsx/jsx-runtime");
46
+ //#region ../../internals/utils/src/casing.ts
47
+ /**
48
+ * Shared implementation for camelCase and PascalCase conversion.
49
+ * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)
50
+ * and capitalizes each word according to `pascal`.
51
+ *
52
+ * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
53
+ */
54
+ function toCamelOrPascal(text, pascal) {
55
+ 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) => {
56
+ if (word.length > 1 && word === word.toUpperCase()) return word;
57
+ return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
58
+ }).join("").replace(/[^a-zA-Z0-9]/g, "");
59
+ }
60
+ /**
61
+ * Converts `text` to camelCase.
62
+ *
63
+ * @example Word boundaries
64
+ * `camelCase('hello-world') // 'helloWorld'`
65
+ *
66
+ * @example With a prefix
67
+ * `camelCase('tag', { prefix: 'create' }) // 'createTag'`
68
+ */
69
+ function camelCase(text, { prefix = "", suffix = "" } = {}) {
70
+ return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
71
+ }
72
+ /**
73
+ * Converts `text` to PascalCase.
74
+ *
75
+ * @example Word boundaries
76
+ * `pascalCase('hello-world') // 'HelloWorld'`
77
+ *
78
+ * @example With a suffix
79
+ * `pascalCase('tag', { suffix: 'schema' }) // 'TagSchema'`
80
+ */
81
+ function pascalCase(text, { prefix = "", suffix = "" } = {}) {
82
+ return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true);
83
+ }
84
+ /**
85
+ * Converts `text` to snake_case.
86
+ *
87
+ * @example From camelCase
88
+ * `snakeCase('helloWorld') // 'hello_world'`
89
+ *
90
+ * @example From mixed separators
91
+ * `snakeCase('Hello-World') // 'hello_world'`
92
+ */
93
+ function snakeCase(text, { prefix = "", suffix = "" } = {}) {
94
+ return `${prefix} ${text} ${suffix}`.trim().replace(/([a-z])([A-Z])/g, "$1_$2").replace(/[\s\-.]+/g, "_").replace(/[^a-zA-Z0-9_]/g, "").toLowerCase().split("_").filter(Boolean).join("_");
95
+ }
96
+ /**
97
+ * Converts `text` to SCREAMING_SNAKE_CASE.
98
+ *
99
+ * @example From camelCase
100
+ * `screamingSnakeCase('helloWorld') // 'HELLO_WORLD'`
101
+ */
102
+ function screamingSnakeCase(text, { prefix = "", suffix = "" } = {}) {
103
+ return snakeCase(text, {
104
+ prefix,
105
+ suffix
106
+ }).toUpperCase();
107
+ }
108
+ //#endregion
109
+ //#region ../../internals/utils/src/reserved.ts
110
+ /**
111
+ * JavaScript and Java reserved words.
112
+ * @link https://github.com/jonschlinkert/reserved/blob/master/index.js
113
+ */
114
+ const reservedWords = /* @__PURE__ */ new Set([
115
+ "abstract",
116
+ "arguments",
117
+ "boolean",
118
+ "break",
119
+ "byte",
120
+ "case",
121
+ "catch",
122
+ "char",
123
+ "class",
124
+ "const",
125
+ "continue",
126
+ "debugger",
127
+ "default",
128
+ "delete",
129
+ "do",
130
+ "double",
131
+ "else",
132
+ "enum",
133
+ "eval",
134
+ "export",
135
+ "extends",
136
+ "false",
137
+ "final",
138
+ "finally",
139
+ "float",
140
+ "for",
141
+ "function",
142
+ "goto",
143
+ "if",
144
+ "implements",
145
+ "import",
146
+ "in",
147
+ "instanceof",
148
+ "int",
149
+ "interface",
150
+ "let",
151
+ "long",
152
+ "native",
153
+ "new",
154
+ "null",
155
+ "package",
156
+ "private",
157
+ "protected",
158
+ "public",
159
+ "return",
160
+ "short",
161
+ "static",
162
+ "super",
163
+ "switch",
164
+ "synchronized",
165
+ "this",
166
+ "throw",
167
+ "throws",
168
+ "transient",
169
+ "true",
170
+ "try",
171
+ "typeof",
172
+ "var",
173
+ "void",
174
+ "volatile",
175
+ "while",
176
+ "with",
177
+ "yield",
178
+ "Array",
179
+ "Date",
180
+ "hasOwnProperty",
181
+ "Infinity",
182
+ "isFinite",
183
+ "isNaN",
184
+ "isPrototypeOf",
185
+ "length",
186
+ "Math",
187
+ "name",
188
+ "NaN",
189
+ "Number",
190
+ "Object",
191
+ "prototype",
192
+ "String",
193
+ "toString",
194
+ "undefined",
195
+ "valueOf"
196
+ ]);
197
+ /**
198
+ * Returns `true` when `name` is a syntactically valid JavaScript variable name.
199
+ *
200
+ * @example
201
+ * ```ts
202
+ * isValidVarName('status') // true
203
+ * isValidVarName('class') // false (reserved word)
204
+ * isValidVarName('42foo') // false (starts with digit)
205
+ * ```
206
+ */
207
+ function isValidVarName(name) {
208
+ if (!name || reservedWords.has(name)) return false;
209
+ return isIdentifier(name);
210
+ }
211
+ /**
212
+ * Returns `name` when it's a syntactically valid JavaScript variable name,
213
+ * otherwise prefixes it with `_` so the result is a valid identifier.
214
+ *
215
+ * Useful for sanitizing OpenAPI schema names or operation IDs that start with
216
+ * a digit (e.g. `409`, `504AccountCancel`) before using them as exported
217
+ * variable, type, or function names.
218
+ *
219
+ * @example
220
+ * ```ts
221
+ * ensureValidVarName('409') // '_409'
222
+ * ensureValidVarName('504AccountCancel') // '_504AccountCancel'
223
+ * ensureValidVarName('Pet') // 'Pet'
224
+ * ensureValidVarName('class') // '_class'
225
+ * ```
226
+ */
227
+ function ensureValidVarName(name) {
228
+ if (!name || isValidVarName(name)) return name;
229
+ return `_${name}`;
230
+ }
231
+ /**
232
+ * Returns `true` when `name` is syntactically a valid identifier, ignoring reserved words.
233
+ *
234
+ * Reserved words and globals (`class`, `name`, `Date`, …) are valid as bare object-literal keys
235
+ * even though they are not valid variable names, so use this (not {@link isValidVarName}) when
236
+ * deciding whether an object key needs quoting.
237
+ *
238
+ * @example
239
+ * ```ts
240
+ * isIdentifier('name') // true
241
+ * isIdentifier('x-total')// false
242
+ * ```
243
+ */
244
+ function isIdentifier(name) {
245
+ return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
246
+ }
247
+ //#endregion
248
+ //#region ../../internals/utils/src/strings.ts
249
+ /**
250
+ * Strips a single matching pair of `"..."`, `'...'`, or `` `...` `` from both ends of `text`.
251
+ * Returns the string unchanged when no balanced quote pair is found.
252
+ *
253
+ * @example
254
+ * ```ts
255
+ * trimQuotes('"hello"') // 'hello'
256
+ * trimQuotes('hello') // 'hello'
257
+ * ```
258
+ */
259
+ function trimQuotes(text) {
260
+ if (text.length >= 2) {
261
+ const first = text[0];
262
+ const last = text[text.length - 1];
263
+ if (first === "\"" && last === "\"" || first === "'" && last === "'" || first === "`" && last === "`") return text.slice(1, -1);
264
+ }
265
+ return text;
266
+ }
267
+ /**
268
+ * Serializes a primitive to a single-quoted string literal, stripping any surrounding quotes first.
269
+ *
270
+ * Escaping runs through `JSON.stringify`, then the result switches to single quotes so the generated
271
+ * code matches the repo style without a formatter.
272
+ *
273
+ * @example
274
+ * ```ts
275
+ * stringify('hello') // "'hello'"
276
+ * stringify('"hello"') // "'hello'"
277
+ * ```
278
+ */
279
+ function stringify(value) {
280
+ if (value === void 0 || value === null) return "''";
281
+ return `'${JSON.stringify(trimQuotes(value.toString())).slice(1, -1).replace(/\\"/g, "\"").replace(/'/g, "\\'")}'`;
282
+ }
283
+ /**
284
+ * Escapes characters that are not allowed inside JS string literals, covering quotes, backslashes,
285
+ * and the Unicode line terminators U+2028 and U+2029.
286
+ *
287
+ * @see http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.4
288
+ *
289
+ * @example
290
+ * ```ts
291
+ * jsStringEscape('say "hi"\nbye') // 'say \\"hi\\"\\nbye'
292
+ * ```
293
+ */
294
+ function jsStringEscape(input) {
295
+ return `${input}`.replace(/["'\\\n\r\u2028\u2029]/g, (character) => {
296
+ switch (character) {
297
+ case "\"":
298
+ case "'":
299
+ case "\\": return `\\${character}`;
300
+ case "\n": return "\\n";
301
+ case "\r": return "\\r";
302
+ case "\u2028": return "\\u2028";
303
+ case "\u2029": return "\\u2029";
304
+ default: return "";
305
+ }
306
+ });
307
+ }
308
+ //#endregion
309
+ //#region ../../internals/utils/src/fs.ts
310
+ /**
311
+ * Builds a nested file path from a dotted name. Splits on dots that precede a letter
312
+ * (so version numbers embedded in operationIds like `v2025.0` stay intact), camelCases
313
+ * every earlier segment, applies `caseLast` to the final segment, and joins with `/`.
314
+ *
315
+ * Empty segments are dropped before joining. They arise when the name starts with a dot
316
+ * followed by a letter (e.g. `..Schema` splits into `['..', 'Schema']` and `'..'` cases to
317
+ * an empty string). Without this a leading `/` would form, which `path.resolve` reads as an
318
+ * absolute path, letting generated files escape the configured output directory.
319
+ *
320
+ * @example Nested path from a dotted name
321
+ * `toFilePath('pet.petId') // 'pet/petId'`
322
+ *
323
+ * @example PascalCase the final segment
324
+ * `toFilePath('pet.Pet', pascalCase) // 'pet/Pet'`
325
+ *
326
+ * @example Suffix applied to the final segment only
327
+ * `toFilePath('tag.tag', (part) => camelCase(part, { suffix: 'schema' })) // 'tag/tagSchema'`
328
+ */
329
+ function toFilePath(name, caseLast = camelCase) {
330
+ const parts = name.split(/\.(?=[a-zA-Z])/);
331
+ return parts.map((part, i) => i === parts.length - 1 ? caseLast(part) : camelCase(part)).filter(Boolean).join("/");
332
+ }
333
+ //#endregion
334
+ //#region src/constants.ts
335
+ /**
336
+ * `optionalType` values that cause a property's type to include `| undefined`.
337
+ */
338
+ const OPTIONAL_ADDS_UNDEFINED = /* @__PURE__ */ new Set(["undefined", "questionTokenAndUndefined"]);
339
+ /**
340
+ * `optionalType` values that render the property key with a `?` token.
341
+ */
342
+ const OPTIONAL_ADDS_QUESTION_TOKEN = /* @__PURE__ */ new Set(["questionToken", "questionTokenAndUndefined"]);
343
+ /**
344
+ * `enum.type` values that append a `typeSuffix` to the generated enum type alias.
345
+ */
346
+ const ENUM_TYPES_WITH_KEY_SUFFIX = /* @__PURE__ */ new Set(["asConst"]);
347
+ /**
348
+ * `enum.type` values that require a runtime value declaration (object, enum, or literal).
349
+ */
350
+ const ENUM_TYPES_WITH_RUNTIME_VALUE = /* @__PURE__ */ new Set([
351
+ "enum",
352
+ "asConst",
353
+ "constEnum",
354
+ "literal",
355
+ void 0
356
+ ]);
357
+ /**
358
+ * `enum.type` values whose type declaration is type-only (no runtime value emitted for the type alias).
359
+ */
360
+ const ENUM_TYPES_WITH_TYPE_ONLY = /* @__PURE__ */ new Set([
361
+ "asConst",
362
+ "literal",
363
+ void 0
364
+ ]);
365
+ /**
366
+ * Ordering priority for function parameters: lower = sorted earlier.
367
+ */
368
+ const PARAM_RANK = {
369
+ required: 0,
370
+ optional: 1,
371
+ withDefault: 2,
372
+ rest: 3
373
+ };
374
+ //#endregion
375
+ //#region src/factory.ts
376
+ var factory_exports = /* @__PURE__ */ __exportAll({
377
+ appendJSDocToNode: () => appendJSDocToNode,
378
+ buildIndexSignatures: () => buildIndexSignatures,
379
+ buildMemberNodes: () => buildMemberNodes,
380
+ buildPropertyType: () => buildPropertyType,
381
+ buildTupleNode: () => buildTupleNode,
382
+ constToTypeNode: () => constToTypeNode,
383
+ createArrayDeclaration: () => createArrayDeclaration,
384
+ createEnumDeclaration: () => createEnumDeclaration,
385
+ createExportDeclaration: () => createExportDeclaration,
386
+ createImportDeclaration: () => createImportDeclaration,
387
+ createIntersectionDeclaration: () => createIntersectionDeclaration,
388
+ createJSDoc: () => createJSDoc,
389
+ createOmitDeclaration: () => createOmitDeclaration,
390
+ createParameterSignature: () => createParameterSignature,
391
+ createPropertySignature: () => createPropertySignature,
392
+ createQuestionToken: () => createQuestionToken,
393
+ createTypeDeclaration: () => createTypeDeclaration,
394
+ createTypeLiteralNode: () => createTypeLiteralNode,
395
+ createTypeReferenceNode: () => createTypeReferenceNode,
396
+ createUnionDeclaration: () => createUnionDeclaration,
397
+ createUrlTemplateType: () => createUrlTemplateType,
398
+ dateOrStringNode: () => dateOrStringNode,
399
+ isNonNullable: () => isNonNullable$1,
400
+ keywordTypeNodes: () => keywordTypeNodes,
401
+ modifiers: () => modifiers,
402
+ syntaxKind: () => syntaxKind
403
+ });
404
+ const { SyntaxKind, factory } = typescript.default;
405
+ /**
406
+ * Compares two strings by UTF-16 code unit, keeping sorted output identical across platforms
407
+ * regardless of locale.
408
+ */
409
+ function compareStrings(a, b) {
410
+ if (a < b) return -1;
411
+ if (a > b) return 1;
412
+ return 0;
413
+ }
414
+ function isNumber(value) {
415
+ return typeof value === "number" && !Number.isNaN(value);
416
+ }
417
+ /**
418
+ * TypeScript AST modifiers for common keywords (async, export, const, static).
419
+ */
420
+ const modifiers = {
421
+ async: factory.createModifier(typescript.default.SyntaxKind.AsyncKeyword),
422
+ export: factory.createModifier(typescript.default.SyntaxKind.ExportKeyword),
423
+ const: factory.createModifier(typescript.default.SyntaxKind.ConstKeyword),
424
+ static: factory.createModifier(typescript.default.SyntaxKind.StaticKeyword)
425
+ };
426
+ /**
427
+ * TypeScript syntax kind constants for union, literal, and string types.
428
+ */
429
+ const syntaxKind = {
430
+ union: SyntaxKind.UnionType,
431
+ literalType: SyntaxKind.LiteralType,
432
+ stringLiteral: SyntaxKind.StringLiteral
433
+ };
434
+ function isNonNullable$1(value) {
435
+ return value !== null && value !== void 0;
436
+ }
437
+ __name(isNonNullable$1, "isNonNullable");
438
+ function isValidIdentifier(str) {
439
+ if (!str.length || str.trim() !== str) return false;
440
+ let ch = str.codePointAt(0);
441
+ if (!typescript.default.isIdentifierStart(ch, typescript.default.ScriptTarget.Latest)) return false;
442
+ for (let i = ch > 65535 ? 2 : 1; i < str.length; i += ch > 65535 ? 2 : 1) {
443
+ ch = str.codePointAt(i);
444
+ if (!typescript.default.isIdentifierPart(ch, typescript.default.ScriptTarget.Latest)) return false;
445
+ }
446
+ return true;
447
+ }
448
+ function propertyName(name) {
449
+ if (typeof name === "string") return isValidIdentifier(name) ? factory.createIdentifier(name) : factory.createStringLiteral(name);
450
+ return name;
451
+ }
452
+ const questionToken = factory.createToken(typescript.default.SyntaxKind.QuestionToken);
453
+ /**
454
+ * Creates a question token for optional type annotations.
455
+ * Pass `true` to use the cached token, or provide a pre-created token.
456
+ */
457
+ function createQuestionToken(token) {
458
+ if (!token) return;
459
+ if (token === true) return questionToken;
460
+ return token;
461
+ }
462
+ /**
463
+ * Creates a TypeScript intersection type node from multiple type nodes.
464
+ * Returns the single node if only one is provided, or wraps in parentheses if requested.
465
+ */
466
+ function createIntersectionDeclaration({ nodes, withParentheses }) {
467
+ if (!nodes.length) return null;
468
+ if (nodes.length === 1) return nodes[0] || null;
469
+ const node = factory.createIntersectionTypeNode(nodes);
470
+ if (withParentheses) return factory.createParenthesizedType(node);
471
+ return node;
472
+ }
473
+ /**
474
+ * Creates a TypeScript array type node.
475
+ * Use `arrayType: 'array'` for bracket syntax (`T[]`), or `'generic'` for `Array<T>`.
476
+ *
477
+ * @example Array bracket syntax
478
+ * `createArrayDeclaration({ nodes: [stringType], arrayType: 'array' }) // → string[]`
479
+ *
480
+ * @example Generic Array syntax
481
+ * `createArrayDeclaration({ nodes: [stringType], arrayType: 'generic' }) // → Array<string>`
482
+ */
483
+ function createArrayDeclaration({ nodes, arrayType = "array" }) {
484
+ if (!nodes.length) return factory.createTupleTypeNode([]);
485
+ if (nodes.length === 1) {
486
+ const node = nodes[0];
487
+ if (!node) return null;
488
+ if (arrayType === "generic") return factory.createTypeReferenceNode(factory.createIdentifier("Array"), [node]);
489
+ return factory.createArrayTypeNode(node);
490
+ }
491
+ const unionType = factory.createUnionTypeNode(nodes);
492
+ if (arrayType === "generic") return factory.createTypeReferenceNode(factory.createIdentifier("Array"), [unionType]);
493
+ return factory.createArrayTypeNode(factory.createParenthesizedType(unionType));
494
+ }
495
+ /**
496
+ * Minimum nodes length of 2
497
+ * @example Union type example
498
+ * `string | number`
499
+ */
500
+ function createUnionDeclaration({ nodes, withParentheses }) {
501
+ if (!nodes.length) return keywordTypeNodes.any;
502
+ if (nodes.length === 1) return nodes[0];
503
+ const node = factory.createUnionTypeNode(nodes);
504
+ if (withParentheses) return factory.createParenthesizedType(node);
505
+ return node;
506
+ }
507
+ /**
508
+ * Creates a TypeScript property signature for object/interface members.
509
+ * Supports optional markers, readonly modifiers, and type annotations.
510
+ */
511
+ function createPropertySignature({ readOnly, modifiers = [], name, questionToken, type }) {
512
+ return factory.createPropertySignature([...modifiers, readOnly ? factory.createToken(typescript.default.SyntaxKind.ReadonlyKeyword) : void 0].filter((modifier) => modifier !== void 0), propertyName(name), createQuestionToken(questionToken), type);
513
+ }
514
+ /**
515
+ * Creates a function parameter declaration with optional markers, rest parameters, and type annotations.
516
+ */
517
+ function createParameterSignature(name, { modifiers, dotDotDotToken, questionToken, type, initializer }) {
518
+ return factory.createParameterDeclaration(modifiers, dotDotDotToken, name, createQuestionToken(questionToken), type, initializer);
519
+ }
520
+ /**
521
+ * Creates a JSDoc comment node from an array of comment strings.
522
+ * Returns null if no comments are provided.
523
+ */
524
+ function createJSDoc({ comments }) {
525
+ if (!comments.length) return null;
526
+ return factory.createJSDocComment(factory.createNodeArray(comments.map((comment, i) => {
527
+ if (i === comments.length - 1) return factory.createJSDocText(comment);
528
+ return factory.createJSDocText(`${comment}\n`);
529
+ })));
530
+ }
531
+ /**
532
+ * Attaches JSDoc comments to an AST node as synthetic leading comments.
533
+ * Filters out undefined comments before attaching.
534
+ *
535
+ * @see https://github.com/microsoft/TypeScript/issues/44151
536
+ */
537
+ function appendJSDocToNode({ node, comments }) {
538
+ const filteredComments = comments.filter(Boolean);
539
+ if (!filteredComments.length) return node;
540
+ const text = filteredComments.reduce((acc = "", comment = "") => {
541
+ return `${acc}\n * ${comment.replaceAll("*/", "*\\/")}`;
542
+ }, "*");
543
+ return typescript.default.addSyntheticLeadingComment(node, typescript.default.SyntaxKind.MultiLineCommentTrivia, `${text || "*"}\n`, true);
544
+ }
545
+ /**
546
+ * Creates a TypeScript index signature for dynamic property access.
547
+ * Defines the key type (default: `string`) and value type on an object.
548
+ */
549
+ function createIndexSignature(type, { modifiers, indexName = "key", indexType = factory.createKeywordTypeNode(typescript.default.SyntaxKind.StringKeyword) } = {}) {
550
+ return factory.createIndexSignature(modifiers, [createParameterSignature(indexName, { type: indexType })], type);
551
+ }
552
+ /**
553
+ * Creates a TypeScript type alias declaration with optional modifiers and type parameters.
554
+ */
555
+ function createTypeAliasDeclaration({ modifiers, name, typeParameters, type }) {
556
+ return factory.createTypeAliasDeclaration(modifiers, name, typeParameters, type);
557
+ }
558
+ /**
559
+ * Creates a TypeScript interface declaration with optional modifiers, type parameters, and members.
560
+ */
561
+ function createInterfaceDeclaration({ modifiers, name, typeParameters, members }) {
562
+ return factory.createInterfaceDeclaration(modifiers, name, typeParameters, void 0, members);
563
+ }
564
+ /**
565
+ * Creates a TypeScript type declaration as either a type alias or interface.
566
+ * Intelligently selects the syntax based on the type structure and attaches JSDoc comments.
567
+ */
568
+ function createTypeDeclaration({ syntax, isExportable, comments, name, type }) {
569
+ if (syntax === "interface" && typescript.default.isTypeLiteralNode(type)) return appendJSDocToNode({
570
+ node: createInterfaceDeclaration({
571
+ members: [...type.members],
572
+ modifiers: isExportable ? [modifiers.export] : [],
573
+ name,
574
+ typeParameters: void 0
575
+ }),
576
+ comments
577
+ });
578
+ return appendJSDocToNode({
579
+ node: createTypeAliasDeclaration({
580
+ type,
581
+ modifiers: isExportable ? [modifiers.export] : [],
582
+ name,
583
+ typeParameters: void 0
584
+ }),
585
+ comments
586
+ });
587
+ }
588
+ /**
589
+ * Creates an import declaration with support for default imports, named imports, namespace imports, and type-only imports.
590
+ * Optionally rename imported members with `propertyName` and `name` pairs.
591
+ *
592
+ * @example Default import
593
+ * `import Pet from './Pet'`
594
+ *
595
+ * @example Named imports with rename
596
+ * `import { Pet as Cat } from './Pet'`
597
+ *
598
+ * @example Namespace import
599
+ * `import * as Pet from './Pet'`
600
+ */
601
+ function createImportDeclaration({ name, path, isTypeOnly = false, isNameSpace = false }) {
602
+ if (!Array.isArray(name)) {
603
+ const importPropertyName = isNameSpace ? void 0 : factory.createIdentifier(name);
604
+ const importName = isNameSpace ? factory.createNamespaceImport(factory.createIdentifier(name)) : void 0;
605
+ return factory.createImportDeclaration(void 0, factory.createImportClause(isTypeOnly, importPropertyName, importName), factory.createStringLiteral(path), void 0);
606
+ }
607
+ const sortedName = name.toSorted((a, b) => compareStrings(typeof a === "object" ? a.propertyName : a, typeof b === "object" ? b.propertyName : b));
608
+ return factory.createImportDeclaration(void 0, factory.createImportClause(isTypeOnly, void 0, factory.createNamedImports(sortedName.map((item) => {
609
+ if (typeof item === "object") {
610
+ const obj = item;
611
+ if (obj.name) return factory.createImportSpecifier(false, factory.createIdentifier(obj.propertyName), factory.createIdentifier(obj.name));
612
+ return factory.createImportSpecifier(false, void 0, factory.createIdentifier(obj.propertyName));
613
+ }
614
+ return factory.createImportSpecifier(false, void 0, factory.createIdentifier(item));
615
+ }))), factory.createStringLiteral(path), void 0);
616
+ }
617
+ /**
618
+ * Creates an export declaration with support for named exports, namespace exports, and type-only exports.
619
+ * Sorts export names alphabetically for consistent output across platforms.
620
+ */
621
+ function createExportDeclaration({ path, asAlias, isTypeOnly = false, name }) {
622
+ if (name && !Array.isArray(name) && !asAlias) console.warn(`When using name as string, asAlias should be true ${name}`);
623
+ if (!Array.isArray(name)) {
624
+ const parsedName = name?.match(/^\d/) ? `_${name?.slice(1)}` : name;
625
+ return factory.createExportDeclaration(void 0, isTypeOnly, asAlias && parsedName ? factory.createNamespaceExport(factory.createIdentifier(parsedName)) : void 0, factory.createStringLiteral(path), void 0);
626
+ }
627
+ const sortedName = name.toSorted((a, b) => compareStrings(typeof a === "string" ? a : a.text, typeof b === "string" ? b : b.text));
628
+ return factory.createExportDeclaration(void 0, isTypeOnly, factory.createNamedExports(sortedName.map((propertyName) => {
629
+ return factory.createExportSpecifier(false, void 0, typeof propertyName === "string" ? factory.createIdentifier(propertyName) : propertyName);
630
+ })), factory.createStringLiteral(path), void 0);
631
+ }
632
+ /**
633
+ * Apply casing transformation to enum keys
634
+ */
635
+ function applyEnumKeyCasing(key, casing = "none") {
636
+ if (casing === "none") return key;
637
+ if (casing === "screamingSnakeCase") return screamingSnakeCase(key);
638
+ if (casing === "snakeCase") return snakeCase(key);
639
+ if (casing === "pascalCase") return pascalCase(key);
640
+ if (casing === "camelCase") return camelCase(key);
641
+ return key;
642
+ }
643
+ /**
644
+ * Creates a TypeScript enum declaration or equivalent construct in various formats.
645
+ * Returns a tuple of [name node, type node] - name node may be undefined for certain types.
646
+ *
647
+ * @example
648
+ * ```ts
649
+ * const [name, type] = createEnumDeclaration({
650
+ * type: 'enum',
651
+ * name: 'petType',
652
+ * typeName: 'PetType',
653
+ * enums: [['cat', 'cat', 'A cat'], ['dog', 'dog']],
654
+ * })
655
+ * ```
656
+ */
657
+ function createEnumDeclaration({ type = "enum", name, typeName, enums, enumKeyCasing = "none" }) {
658
+ if (type === "literal" || type === "inlineLiteral") return [void 0, factory.createTypeAliasDeclaration([factory.createToken(typescript.default.SyntaxKind.ExportKeyword)], factory.createIdentifier(typeName), void 0, factory.createUnionTypeNode(enums.map(([_key, value]) => {
659
+ if (isNumber(value)) {
660
+ if (value < 0) return factory.createLiteralTypeNode(factory.createPrefixUnaryExpression(typescript.default.SyntaxKind.MinusToken, factory.createNumericLiteral(Math.abs(value))));
661
+ return factory.createLiteralTypeNode(factory.createNumericLiteral(value?.toString()));
662
+ }
663
+ if (typeof value === "boolean") return factory.createLiteralTypeNode(value ? factory.createTrue() : factory.createFalse());
664
+ if (value !== null && value !== void 0) return factory.createLiteralTypeNode(factory.createStringLiteral(value.toString()));
665
+ }).filter((node) => node !== void 0)))];
666
+ if (type === "enum" || type === "constEnum") return [void 0, factory.createEnumDeclaration([factory.createToken(typescript.default.SyntaxKind.ExportKeyword), type === "constEnum" ? factory.createToken(typescript.default.SyntaxKind.ConstKeyword) : void 0].filter((modifier) => modifier !== void 0), factory.createIdentifier(typeName), enums.map(([key, value, description]) => {
667
+ let initializer = factory.createStringLiteral(value?.toString());
668
+ if (Number.parseInt(value.toString(), 10) === value && isNumber(value)) if (value < 0) initializer = factory.createPrefixUnaryExpression(typescript.default.SyntaxKind.MinusToken, factory.createNumericLiteral(Math.abs(value)));
669
+ else initializer = factory.createNumericLiteral(value);
670
+ if (typeof value === "boolean") initializer = value ? factory.createTrue() : factory.createFalse();
671
+ if (isNumber(Number.parseInt(key.toString(), 10))) {
672
+ const casingKey = applyEnumKeyCasing(`${typeName}_${key}`, enumKeyCasing);
673
+ return appendJSDocToNode({
674
+ node: factory.createEnumMember(propertyName(casingKey), initializer),
675
+ comments: [description]
676
+ });
677
+ }
678
+ if (key !== null && key !== void 0) {
679
+ const casingKey = applyEnumKeyCasing(key.toString(), enumKeyCasing);
680
+ return appendJSDocToNode({
681
+ node: factory.createEnumMember(propertyName(casingKey), initializer),
682
+ comments: [description]
683
+ });
684
+ }
685
+ }).filter((member) => member !== void 0))];
686
+ const identifierName = name;
687
+ if (enums.length === 0) return [void 0, factory.createTypeAliasDeclaration([factory.createToken(typescript.default.SyntaxKind.ExportKeyword)], factory.createIdentifier(typeName), void 0, factory.createKeywordTypeNode(typescript.default.SyntaxKind.NeverKeyword))];
688
+ return [factory.createVariableStatement([factory.createToken(typescript.default.SyntaxKind.ExportKeyword)], factory.createVariableDeclarationList([factory.createVariableDeclaration(factory.createIdentifier(identifierName), void 0, void 0, factory.createAsExpression(factory.createObjectLiteralExpression(enums.map(([key, value, description]) => {
689
+ let initializer = factory.createStringLiteral(value?.toString());
690
+ if (isNumber(value)) if (value < 0) initializer = factory.createPrefixUnaryExpression(typescript.default.SyntaxKind.MinusToken, factory.createNumericLiteral(Math.abs(value)));
691
+ else initializer = factory.createNumericLiteral(value);
692
+ if (typeof value === "boolean") initializer = value ? factory.createTrue() : factory.createFalse();
693
+ if (key !== null && key !== void 0) {
694
+ const casingKey = applyEnumKeyCasing(key.toString(), enumKeyCasing);
695
+ return appendJSDocToNode({
696
+ node: factory.createPropertyAssignment(propertyName(casingKey), initializer),
697
+ comments: [description]
698
+ });
699
+ }
700
+ }).filter((property) => property !== void 0), true), factory.createTypeReferenceNode(factory.createIdentifier("const"), void 0)))], typescript.default.NodeFlags.Const)), factory.createTypeAliasDeclaration([factory.createToken(typescript.default.SyntaxKind.ExportKeyword)], factory.createIdentifier(typeName), void 0, factory.createIndexedAccessTypeNode(factory.createParenthesizedType(factory.createTypeQueryNode(factory.createIdentifier(identifierName), void 0)), factory.createTypeOperatorNode(typescript.default.SyntaxKind.KeyOfKeyword, factory.createTypeQueryNode(factory.createIdentifier(identifierName), void 0))))];
701
+ }
702
+ /**
703
+ * Creates a TypeScript `Omit<T, Keys>` type reference node.
704
+ * Optionally wraps the type in `NonNullable<T>` if `nonNullable` is true.
705
+ */
706
+ function createOmitDeclaration({ keys, type, nonNullable }) {
707
+ const node = nonNullable ? factory.createTypeReferenceNode(factory.createIdentifier("NonNullable"), [type]) : type;
708
+ if (Array.isArray(keys)) return factory.createTypeReferenceNode(factory.createIdentifier("Omit"), [node, factory.createUnionTypeNode(keys.map((key) => {
709
+ return factory.createLiteralTypeNode(factory.createStringLiteral(key));
710
+ }))]);
711
+ return factory.createTypeReferenceNode(factory.createIdentifier("Omit"), [node, factory.createLiteralTypeNode(factory.createStringLiteral(keys))]);
712
+ }
713
+ /**
714
+ * Pre-built TypeScript keyword type nodes for common primitive types.
715
+ * Use these to avoid repeatedly creating the same type nodes.
716
+ */
717
+ const keywordTypeNodes = {
718
+ any: factory.createKeywordTypeNode(typescript.default.SyntaxKind.AnyKeyword),
719
+ unknown: factory.createKeywordTypeNode(typescript.default.SyntaxKind.UnknownKeyword),
720
+ void: factory.createKeywordTypeNode(typescript.default.SyntaxKind.VoidKeyword),
721
+ number: factory.createKeywordTypeNode(typescript.default.SyntaxKind.NumberKeyword),
722
+ integer: factory.createKeywordTypeNode(typescript.default.SyntaxKind.NumberKeyword),
723
+ bigint: factory.createKeywordTypeNode(typescript.default.SyntaxKind.BigIntKeyword),
724
+ object: factory.createKeywordTypeNode(typescript.default.SyntaxKind.ObjectKeyword),
725
+ string: factory.createKeywordTypeNode(typescript.default.SyntaxKind.StringKeyword),
726
+ boolean: factory.createKeywordTypeNode(typescript.default.SyntaxKind.BooleanKeyword),
727
+ undefined: factory.createKeywordTypeNode(typescript.default.SyntaxKind.UndefinedKeyword),
728
+ null: factory.createLiteralTypeNode(factory.createToken(typescript.default.SyntaxKind.NullKeyword)),
729
+ never: factory.createKeywordTypeNode(typescript.default.SyntaxKind.NeverKeyword)
730
+ };
731
+ /**
732
+ * Converts a path like '/pet/{petId}/uploadImage' to a template literal type
733
+ * like `/pet/${string}/uploadImage`
734
+ */
735
+ /**
736
+ * Converts an OAS-style path (e.g. `/pets/{petId}`) or an Express-style path
737
+ * (e.g. `/pets/:petId`) to a TypeScript template literal type
738
+ * like `` `/pets/${string}` ``.
739
+ */
740
+ function createUrlTemplateType(path) {
741
+ const normalized = path.replace(/:([^/]+)/g, "{$1}");
742
+ if (!normalized.includes("{")) return factory.createLiteralTypeNode(factory.createStringLiteral(normalized));
743
+ const segments = normalized.split(/(\{[^}]+\})/);
744
+ const parts = [];
745
+ const parameterIndices = [];
746
+ segments.forEach((segment) => {
747
+ if (segment.startsWith("{") && segment.endsWith("}")) {
748
+ parameterIndices.push(parts.length);
749
+ parts.push(segment);
750
+ } else if (segment) parts.push(segment);
751
+ });
752
+ const head = typescript.default.factory.createTemplateHead(parts[0] || "");
753
+ const templateSpans = [];
754
+ parameterIndices.forEach((paramIndex, i) => {
755
+ const isLast = i === parameterIndices.length - 1;
756
+ const nextPart = parts[paramIndex + 1] || "";
757
+ const literal = isLast ? typescript.default.factory.createTemplateTail(nextPart) : typescript.default.factory.createTemplateMiddle(nextPart);
758
+ templateSpans.push(typescript.default.factory.createTemplateLiteralTypeSpan(keywordTypeNodes.string, literal));
759
+ });
760
+ return typescript.default.factory.createTemplateLiteralType(head, templateSpans);
761
+ }
762
+ /**
763
+ * Creates a TypeScript type literal node (anonymous object type).
764
+ */
765
+ const createTypeLiteralNode = factory.createTypeLiteralNode;
766
+ /**
767
+ * Creates a TypeScript type reference node (e.g., `Array<string>`, `Record<K, V>`).
768
+ */
769
+ const createTypeReferenceNode = factory.createTypeReferenceNode;
770
+ /**
771
+ * Creates a numeric literal type node.
772
+ */
773
+ const createNumericLiteral = factory.createNumericLiteral;
774
+ /**
775
+ * Creates a string literal type node.
776
+ */
777
+ const createStringLiteral = factory.createStringLiteral;
778
+ /**
779
+ * Creates an array type node (e.g., `T[]`).
780
+ */
781
+ const createArrayTypeNode = factory.createArrayTypeNode;
782
+ /**
783
+ * Creates a literal type node (e.g., `'hello'`, `42`, `true`).
784
+ */
785
+ const createLiteralTypeNode = factory.createLiteralTypeNode;
786
+ /**
787
+ * Creates an identifier node.
788
+ */
789
+ const createIdentifier = factory.createIdentifier;
790
+ /**
791
+ * Creates an optional type node (e.g., `T | undefined`).
792
+ */
793
+ const createOptionalTypeNode = factory.createOptionalTypeNode;
794
+ /**
795
+ * Creates a tuple type node (e.g., `[string, number]`).
796
+ */
797
+ const createTupleTypeNode = factory.createTupleTypeNode;
798
+ /**
799
+ * Creates a rest type node for variadic tuple elements (e.g., `...T[]`).
800
+ */
801
+ const createRestTypeNode = factory.createRestTypeNode;
802
+ /**
803
+ * Creates a boolean true literal type node.
804
+ */
805
+ const createTrue = factory.createTrue;
806
+ /**
807
+ * Creates a boolean false literal type node.
808
+ */
809
+ const createFalse = factory.createFalse;
810
+ /**
811
+ * Creates a prefix unary expression (e.g., negative numbers, logical not).
812
+ */
813
+ const createPrefixUnaryExpression = factory.createPrefixUnaryExpression;
814
+ /**
815
+ * Converts a primitive const value to a TypeScript literal type node.
816
+ * Handles negative numbers via a prefix unary expression.
817
+ */
818
+ function constToTypeNode(value, format) {
819
+ if (format === "boolean") return createLiteralTypeNode(value === true ? createTrue() : createFalse());
820
+ if (format === "number" && typeof value === "number") {
821
+ if (value < 0) return createLiteralTypeNode(createPrefixUnaryExpression(SyntaxKind.MinusToken, createNumericLiteral(Math.abs(value))));
822
+ return createLiteralTypeNode(createNumericLiteral(value));
823
+ }
824
+ return createLiteralTypeNode(createStringLiteral(String(value)));
825
+ }
826
+ /**
827
+ * Returns a `Date` reference type node when `representation` is `'date'`, otherwise falls back to `string`.
828
+ */
829
+ function dateOrStringNode(node) {
830
+ return node.representation === "date" ? createTypeReferenceNode(createIdentifier("Date")) : keywordTypeNodes.string;
831
+ }
832
+ /**
833
+ * Maps an array of `SchemaNode`s through the printer, filtering out `null` and `undefined` results.
834
+ */
835
+ function buildMemberNodes(members, print) {
836
+ return (members ?? []).map(print).filter(isNonNullable$1);
837
+ }
838
+ /**
839
+ * Builds a TypeScript tuple type node from an array schema's `items`,
840
+ * applying min/max slice and optional/rest element rules.
841
+ */
842
+ function buildTupleNode(node, print) {
843
+ let items = (node.items ?? []).map(print).filter(isNonNullable$1);
844
+ const restNode = node.rest ? print(node.rest) ?? void 0 : void 0;
845
+ const { min, max } = node;
846
+ if (max !== void 0) {
847
+ items = items.slice(0, max);
848
+ if (items.length < max && restNode) items = [...items, ...Array(max - items.length).fill(restNode)];
849
+ }
850
+ if (min !== void 0) items = items.map((item, i) => i >= min ? createOptionalTypeNode(item) : item);
851
+ if (max === void 0 && restNode) items.push(createRestTypeNode(createArrayTypeNode(restNode)));
852
+ return createTupleTypeNode(items);
853
+ }
854
+ /**
855
+ * Applies `nullable` and optional/nullish `| undefined` union modifiers to a property's resolved base type.
856
+ */
857
+ function buildPropertyType(schema, baseType, optionalType, optional) {
858
+ const addsUndefined = OPTIONAL_ADDS_UNDEFINED.has(optionalType);
859
+ const meta = (0, kubb_kit.syncSchemaRef)(schema);
860
+ let type = baseType;
861
+ if (meta.nullable) type = createUnionDeclaration({ nodes: [type, keywordTypeNodes.null] });
862
+ if ((optional || meta.nullish || meta.optional) && addsUndefined) type = createUnionDeclaration({ nodes: [type, keywordTypeNodes.undefined] });
863
+ return type;
864
+ }
865
+ const indexSignaturePrinter = typescript.default.createPrinter();
866
+ const indexSignatureSource = typescript.default.createSourceFile("", "", typescript.default.ScriptTarget.Latest);
867
+ /**
868
+ * Creates a TypeScript index signature for `additionalProperties` and `patternProperties` on an
869
+ * object schema node. TypeScript allows only one string index signature and its value must be
870
+ * assignable from every named property, so both keywords collapse into a single signature: the
871
+ * union of all value types (deduplicated), or `unknown` when the object also has fixed properties.
872
+ * The key regex of `patternProperties` cannot be expressed by an index signature and is dropped.
873
+ */
874
+ function buildIndexSignatures(node, propertyCount, print) {
875
+ const valueTypes = [];
876
+ if (node.additionalProperties && node.additionalProperties !== true) valueTypes.push(print(node.additionalProperties) ?? keywordTypeNodes.unknown);
877
+ else if (node.additionalProperties === true) valueTypes.push(keywordTypeNodes.unknown);
878
+ for (const schema of Object.values(node.patternProperties ?? {})) {
879
+ const patternType = print(schema) ?? keywordTypeNodes.unknown;
880
+ valueTypes.push(schema.nullable ? createUnionDeclaration({ nodes: [patternType, keywordTypeNodes.null] }) : patternType);
881
+ }
882
+ if (valueTypes.length === 0) return [];
883
+ const seen = /* @__PURE__ */ new Set();
884
+ const distinct = valueTypes.filter((type) => {
885
+ const key = indexSignaturePrinter.printNode(typescript.default.EmitHint.Unspecified, type, indexSignatureSource);
886
+ return seen.has(key) ? false : (seen.add(key), true);
887
+ });
888
+ return [createIndexSignature(propertyCount > 0 ? keywordTypeNodes.unknown : createUnionDeclaration({ nodes: distinct }))];
889
+ }
890
+ //#endregion
891
+ //#region src/components/Enum.tsx
892
+ /**
893
+ * Resolves the runtime identifier name and the TypeScript type name for an enum schema node.
894
+ *
895
+ * The raw `node.name` may be a YAML key such as `"enumNames.Type"` which is not a
896
+ * valid TypeScript identifier. The resolver normalizes it. For inline enum properties the adapter
897
+ * already emits a PascalCase+suffix name, so resolution is typically a no-op.
898
+ *
899
+ * When `constCasing` is `'pascalCase'` and `typeSuffix` is empty, the const and the type
900
+ * resolve to the same name, which TypeScript merges into a single value+type declaration.
901
+ */
902
+ function getEnumNames({ node, enum: enumOptions, resolver }) {
903
+ const resolved = resolver.name(node.name);
904
+ return {
905
+ enumName: enumOptions.constCasing === "pascalCase" ? resolved : camelCase(node.name),
906
+ typeName: ENUM_TYPES_WITH_KEY_SUFFIX.has(enumOptions.type) ? resolver.enum.keyName(node, enumOptions.typeSuffix) : resolved
907
+ };
908
+ }
909
+ /**
910
+ * Renders the enum declaration(s) for a single named `EnumSchemaNode`.
911
+ *
912
+ * Depending on `enum.type` this may emit:
913
+ * - A runtime object (`asConst`) plus a `typeof` type alias
914
+ * - A `const enum` or plain `enum` declaration (`constEnum` / `enum`)
915
+ * - A union literal type alias (`literal`)
916
+ *
917
+ * The emitted `File.Source` nodes carry the resolved names so that the barrel
918
+ * index picks up the correct export identifiers.
919
+ */
920
+ function Enum({ node, enum: enumOptions, resolver }) {
921
+ const { enumName, typeName } = getEnumNames({
922
+ node,
923
+ enum: enumOptions,
924
+ resolver
925
+ });
926
+ const [nameNode, typeNode] = createEnumDeclaration({
927
+ name: enumName,
928
+ typeName,
929
+ enums: node.namedEnumValues?.map((v) => [
930
+ trimQuotes(v.name.toString()),
931
+ v.value,
932
+ v.description
933
+ ]) ?? node.enumValues?.filter((v) => v !== null && v !== void 0).map((v) => [trimQuotes(v.toString()), v]) ?? [],
934
+ type: enumOptions.type,
935
+ enumKeyCasing: enumOptions.keyCasing
936
+ });
937
+ const namesMerge = !!nameNode && enumName === typeName;
938
+ return /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsxs)(kubb_jsx_jsx_runtime.Fragment, { children: [nameNode && /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Source, {
939
+ name: enumName,
940
+ isExportable: true,
941
+ isIndexable: true,
942
+ isTypeOnly: false,
943
+ children: (0, _kubb_parser_ts.parserTs)().print(nameNode)
944
+ }), /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Source, {
945
+ name: typeName,
946
+ isIndexable: !namesMerge,
947
+ isExportable: !namesMerge && ENUM_TYPES_WITH_RUNTIME_VALUE.has(enumOptions.type),
948
+ isTypeOnly: ENUM_TYPES_WITH_TYPE_ONLY.has(enumOptions.type),
949
+ children: (0, _kubb_parser_ts.parserTs)().print(typeNode)
950
+ })] });
951
+ }
952
+ //#endregion
953
+ //#region ../../internals/shared/src/params.ts
954
+ /**
955
+ * Drops parameters that share the same name, keeping the first.
956
+ *
957
+ * A malformed spec can declare the same parameter name twice within one `in` location. Both would
958
+ * resolve to the same output property, so emitting both would yield an object type with a duplicate
959
+ * member, which TypeScript rejects. This is a defensive guard against that case, not a casing guard:
960
+ * parameter names flow through unchanged, so no two distinct names ever collide here anymore.
961
+ */
962
+ function dedupeParams(params) {
963
+ const seen = /* @__PURE__ */ new Set();
964
+ return params.filter((param) => {
965
+ if (seen.has(param.name)) return false;
966
+ seen.add(param.name);
967
+ return true;
968
+ });
969
+ }
970
+ //#endregion
971
+ //#region ../../internals/shared/src/operation.ts
972
+ /**
973
+ * Maps a content type to the PascalCase suffix used to name per-content-type variants
974
+ * (e.g. `application/json` → `Json`, `application/xml` → `Xml`, `multipart/form-data` → `FormData`).
975
+ */
976
+ function getContentTypeSuffix(contentType) {
977
+ const baseType = contentType.split(";")[0].trim();
978
+ if (baseType === "application/json") return "Json";
979
+ if (baseType === "multipart/form-data") return "FormData";
980
+ if (baseType === "application/x-www-form-urlencoded") return "FormUrlEncoded";
981
+ const parts = (baseType.split("/").pop() ?? baseType).split(/[^a-zA-Z0-9]+/).filter(Boolean);
982
+ if (parts.length === 0) return "Unknown";
983
+ return parts.map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
984
+ }
985
+ /**
986
+ * Appends a content-type suffix to a base name, keeping a trailing `Data` segment last
987
+ * (e.g. `AddPetData` + `Json` → `AddPetJsonData`, `AddPetStatus200` + `Xml` → `AddPetStatus200Xml`).
988
+ */
989
+ function getPerContentTypeName(baseName, suffix) {
990
+ if (baseName.endsWith("Data")) return suffix.endsWith("Data") ? baseName.slice(0, -4) + suffix : `${baseName.slice(0, -4)}${suffix}Data`;
991
+ return baseName + suffix;
992
+ }
993
+ /**
994
+ * Resolves per-content-type variant names for a set of content entries, deduplicating suffix
995
+ * collisions with a numeric counter. Entries without a schema are skipped. The returned `suffix` is
996
+ * the final (possibly counter-augmented) value, so callers can derive parallel names in another
997
+ * namespace (e.g. plugin-faker deriving the matching plugin-ts type name).
998
+ */
999
+ function resolveContentTypeVariants(entries, baseName) {
1000
+ const usedNames = /* @__PURE__ */ new Set();
1001
+ return entries.filter((entry) => entry.schema).map((entry) => {
1002
+ const baseSuffix = getContentTypeSuffix(entry.contentType);
1003
+ let suffix = baseSuffix;
1004
+ let name = getPerContentTypeName(baseName, suffix);
1005
+ let counter = 2;
1006
+ while (usedNames.has(name)) {
1007
+ suffix = `${baseSuffix}${counter++}`;
1008
+ name = getPerContentTypeName(baseName, suffix);
1009
+ }
1010
+ usedNames.add(name);
1011
+ return {
1012
+ name,
1013
+ suffix,
1014
+ schema: entry.schema,
1015
+ keysToOmit: entry.keysToOmit,
1016
+ contentType: entry.contentType
1017
+ };
1018
+ });
1019
+ }
1020
+ function getOperationParameters(node) {
1021
+ return {
1022
+ path: dedupeParams(node.parameters.filter((param) => param.in === "path")),
1023
+ query: dedupeParams(node.parameters.filter((param) => param.in === "query")),
1024
+ header: dedupeParams(node.parameters.filter((param) => param.in === "header")),
1025
+ cookie: dedupeParams(node.parameters.filter((param) => param.in === "cookie"))
1026
+ };
1027
+ }
1028
+ /**
1029
+ * Builds the combined `{ body, path, query, headers }` options object schema for an operation,
1030
+ * referencing the already-resolved body and grouped param names. Shared by `@kubb/plugin-ts`'s
1031
+ * `Options` type and `@kubb/plugin-zod`'s inferred options schema, so both printers emit the same
1032
+ * shape from the same inputs. `primitive: 'object'` is a no-op for the TS printer and tells the Zod
1033
+ * printer to emit `z.object(…)` rather than a record.
1034
+ */
1035
+ function buildOptionsSchema(node, resolver) {
1036
+ const { path, query, header } = getOperationParameters(node);
1037
+ const hasBody = Boolean(node.requestBody?.content?.[0]?.schema);
1038
+ const createNever = () => kubb_kit.ast.factory.createSchema({
1039
+ type: "never",
1040
+ primitive: void 0,
1041
+ optional: true
1042
+ });
1043
+ const groups = [
1044
+ {
1045
+ name: "path",
1046
+ params: path,
1047
+ resolve: resolver.param.path
1048
+ },
1049
+ {
1050
+ name: "query",
1051
+ params: query,
1052
+ resolve: resolver.param.query
1053
+ },
1054
+ {
1055
+ name: "headers",
1056
+ params: header,
1057
+ resolve: resolver.param.headers
1058
+ }
1059
+ ];
1060
+ return kubb_kit.ast.factory.createSchema({
1061
+ type: "object",
1062
+ primitive: "object",
1063
+ deprecated: node.deprecated,
1064
+ properties: [kubb_kit.ast.factory.createProperty({
1065
+ name: "body",
1066
+ required: hasBody,
1067
+ schema: hasBody ? kubb_kit.ast.factory.createSchema({
1068
+ type: "ref",
1069
+ name: resolver.response.body(node)
1070
+ }) : createNever()
1071
+ }), ...groups.map(({ name, params, resolve }) => {
1072
+ const required = params.some((param) => param.required);
1073
+ return kubb_kit.ast.factory.createProperty({
1074
+ name,
1075
+ required,
1076
+ schema: params.length > 0 ? kubb_kit.ast.factory.createSchema({
1077
+ type: "ref",
1078
+ name: resolve.call(resolver.param, node, params[0]),
1079
+ optional: !required
1080
+ }) : createNever()
1081
+ });
1082
+ })]
1083
+ });
1084
+ }
1085
+ //#endregion
1086
+ //#region ../../internals/shared/src/resolver.ts
1087
+ /**
1088
+ * Resolves a single operation parameter name with the
1089
+ * `<operationId> <in> <name>` template.
1090
+ *
1091
+ * @example
1092
+ * `operationParamName.call(resolver, node, param) // → 'DeletePetPathPetId'`
1093
+ */
1094
+ function operationParamName(node, param) {
1095
+ return this.name(`${node.operationId} ${param.in} ${param.name}`);
1096
+ }
1097
+ /**
1098
+ * Builds the shared `param` namespace. Spread the result into `createResolver`
1099
+ * and override individual methods next to it when a plugin deviates.
1100
+ *
1101
+ * @example
1102
+ * ```ts
1103
+ * createResolver<PluginTs>({ param: createOperationParamResolver(), ... })
1104
+ * ```
1105
+ */
1106
+ function createOperationParamResolver() {
1107
+ return {
1108
+ name: operationParamName,
1109
+ path(node) {
1110
+ return this.name(`${node.operationId} Path`);
1111
+ },
1112
+ query(node) {
1113
+ return this.name(`${node.operationId} Query`);
1114
+ },
1115
+ headers(node) {
1116
+ return this.name(`${node.operationId} Headers`);
1117
+ }
1118
+ };
1119
+ }
1120
+ /**
1121
+ * Builds the shared `response` namespace. Spread the result into
1122
+ * `createResolver` and add plugin-specific methods (`options`, `error`) next
1123
+ * to it.
1124
+ *
1125
+ * @example
1126
+ * ```ts
1127
+ * createResolver<PluginTs>({ response: { ...createOperationResponseResolver(), options(node) {...} }, ... })
1128
+ * ```
1129
+ */
1130
+ function createOperationResponseResolver() {
1131
+ return {
1132
+ status(node, statusCode) {
1133
+ return this.name(`${node.operationId} Status ${statusCode}`);
1134
+ },
1135
+ body(node) {
1136
+ return this.name(`${node.operationId} Body`);
1137
+ },
1138
+ responses(node) {
1139
+ return this.name(`${node.operationId} Responses`);
1140
+ },
1141
+ response(node) {
1142
+ return this.name(`${node.operationId} Response`);
1143
+ }
1144
+ };
1145
+ }
1146
+ /**
1147
+ * Builds a resolver `file` override whose base name runs every path segment
1148
+ * through `toFilePath`, casing the final segment with `caseLast`.
1149
+ *
1150
+ * @example
1151
+ * ```ts
1152
+ * createResolver<PluginTs>({ file: createCasedFile(pascalCase), ... })
1153
+ * ```
1154
+ */
1155
+ function createCasedFile(caseLast) {
1156
+ return { baseName({ name, extname }) {
1157
+ return `${toFilePath(name, caseLast)}${extname}`;
1158
+ } };
1159
+ }
1160
+ //#endregion
1161
+ //#region ../../internals/shared/src/refs.ts
1162
+ /**
1163
+ * Collects the resolved target name of every pointer-carrying ref in a schema tree, in
1164
+ * first-occurrence order. Use this for name-only checks (e.g. redeclaration detection) where
1165
+ * `resolver.imports` would resolve file paths that are then discarded.
1166
+ */
1167
+ function collectRefNames(schema) {
1168
+ return kubb_kit.ast.collectSync(schema, { schema: (node) => {
1169
+ const refNode = kubb_kit.ast.narrowSchema(node, "ref");
1170
+ if (!refNode?.ref) return null;
1171
+ return kubb_kit.ast.resolveRefName(refNode);
1172
+ } });
1173
+ }
1174
+ //#endregion
1175
+ //#region ../../internals/shared/src/group.ts
1176
+ /**
1177
+ * Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the
1178
+ * shared default naming so every plugin groups output consistently:
1179
+ *
1180
+ * - `path` groups use the second path segment (`/pet/findByStatus` → `pet`).
1181
+ * - other groups use the camelCased group (`pet store` → `petStore`).
1182
+ *
1183
+ * A user-provided `group.name` always wins over the default namer, so callers stay in
1184
+ * control of their output folders. Returns `null` when grouping is disabled, matching the
1185
+ * per-plugin convention.
1186
+ *
1187
+ * @param group - The user-supplied group option, or `undefined` to disable grouping.
1188
+ *
1189
+ * @example
1190
+ * ```ts
1191
+ * createGroupConfig(group) // shared across every plugin
1192
+ * ```
1193
+ */
1194
+ function createGroupConfig(group) {
1195
+ if (!group) return null;
1196
+ const defaultName = (ctx) => {
1197
+ if (group.type === "path") return `${ctx.group.split("/")[1]}`;
1198
+ return camelCase(ctx.group);
1199
+ };
1200
+ return {
1201
+ ...group,
1202
+ name: group.name ? group.name : defaultName
1203
+ };
1204
+ }
1205
+ //#endregion
1206
+ //#region ../../internals/shared/src/schemaTraversal.ts
1207
+ /**
1208
+ * Maps each property of an object schema to its transformed output. Pairs every result with the
1209
+ * original property so the printer keeps full control over modifiers, getters, and key syntax.
1210
+ *
1211
+ * @example
1212
+ * ```ts
1213
+ * const entries = mapSchemaProperties(node, (schema) => this.transform(schema))
1214
+ * // entries: [{ name: 'id', property, output: 'z.number()' }, ...]
1215
+ * ```
1216
+ */
1217
+ function mapSchemaProperties(node, transform) {
1218
+ return node.properties.map((property) => ({
1219
+ name: property.name,
1220
+ property,
1221
+ output: transform(property.schema)
1222
+ }));
1223
+ }
1224
+ /**
1225
+ * Maps each item of an array or tuple schema to its transformed output, pairing every result with
1226
+ * the original item.
1227
+ */
1228
+ function mapSchemaItems(node, transform) {
1229
+ return (node.items ?? []).map((schema) => ({
1230
+ schema,
1231
+ output: transform(schema)
1232
+ }));
1233
+ }
1234
+ //#endregion
1235
+ //#region src/utils.ts
1236
+ /**
1237
+ * Tells whether a `const` (single-value enum) should render as a bare literal type (`'active'`)
1238
+ * rather than a named enum reference or a runtime enum declaration.
1239
+ *
1240
+ * The parser folds `const` into a single-value enum node. The adapter decides which schemas are
1241
+ * named enums and lists them in `enumSchemaNames`, and references to those names get suffixed (for
1242
+ * example `StatusKey`). A const renders as a literal only when the adapter has not registered it as
1243
+ * a named enum, which keeps the declaration and its references in sync across adapter versions.
1244
+ */
1245
+ function isInlineConstEnum(node, enumSchemaNames) {
1246
+ return (node.namedEnumValues ?? node.enumValues ?? []).length === 1 && !(node.name && enumSchemaNames?.has(node.name));
1247
+ }
1248
+ /**
1249
+ * Collects JSDoc annotation strings for a schema node.
1250
+ *
1251
+ * Only uses official JSDoc tags from https://jsdoc.app/: `@description`, `@deprecated`, `@default`, `@example`, `@type`.
1252
+ * Constraint metadata (min/max length, pattern, multipleOf, min/maxProperties) is emitted as plain-text lines.
1253
+
1254
+ */
1255
+ function isSchemaOptional(schema) {
1256
+ return Boolean("optional" in schema && schema.optional || "nullish" in schema && schema.nullish);
1257
+ }
1258
+ function formatExample(value) {
1259
+ if (value === null || typeof value !== "object") return String(value);
1260
+ return (JSON.stringify(value) ?? String(value)).replaceAll("*/", "*\\/");
1261
+ }
1262
+ function buildPropertyJSDocComments(schema, optional) {
1263
+ const meta = (0, kubb_kit.syncSchemaRef)(schema);
1264
+ const isArray = meta?.primitive === "array";
1265
+ const hasDescription = meta && "description" in meta && meta.description;
1266
+ const formatComment = meta && "format" in meta && meta.format ? hasDescription ? [" ", `Format: \`${meta.format}\``] : ["@description", `Format: \`${meta.format}\``] : [];
1267
+ const exampleValues = meta?.examples ?? [];
1268
+ const comments = [
1269
+ hasDescription ? `@description ${jsStringEscape(meta.description)}` : null,
1270
+ ...formatComment,
1271
+ meta && "deprecated" in meta && meta.deprecated ? "@deprecated" : null,
1272
+ !isArray && meta && "min" in meta && meta.min !== void 0 ? `@minLength ${meta.min}` : null,
1273
+ !isArray && meta && "max" in meta && meta.max !== void 0 ? `@maxLength ${meta.max}` : null,
1274
+ meta && "pattern" in meta && meta.pattern ? `@pattern ${meta.pattern}` : null,
1275
+ meta && "default" in meta && meta.default !== void 0 ? `@default ${"primitive" in meta && meta.primitive === "string" && typeof meta.default === "string" ? stringify(meta.default) : meta.default}` : null,
1276
+ ...exampleValues.map((example) => `@example ${formatExample(example)}`)
1277
+ ].filter(Boolean);
1278
+ const typeTag = comments.length && meta && "primitive" in meta && meta.primitive ? [`@type ${meta.primitive}`, optional ?? isSchemaOptional(schema) ? " | undefined" : null].filter(Boolean).join("") : null;
1279
+ return [...comments, typeTag].filter(Boolean);
1280
+ }
1281
+ /**
1282
+ * Builds the object schema for a group of parameters sharing one `in` location (path, query, or
1283
+ * header), embedding each param's own schema (and JSDoc) directly rather than referencing a
1284
+ * separate per-param type — the group itself is the only type these params get exported as.
1285
+ */
1286
+ function buildParams({ params }) {
1287
+ return kubb_kit.ast.factory.createSchema({
1288
+ type: "object",
1289
+ properties: params.map((param) => kubb_kit.ast.factory.createProperty({
1290
+ name: param.name,
1291
+ required: param.required,
1292
+ schema: kubb_kit.ast.factory.createSchema({
1293
+ ...param.schema,
1294
+ optional: !param.required
1295
+ })
1296
+ }))
1297
+ });
1298
+ }
1299
+ /**
1300
+ * The schema a status occupies in the `<Name>Responses` record. A status that documents several
1301
+ * content types becomes a `{ contentType; data }` union so the runtime can surface the negotiated type
1302
+ * on `result.parsed`, while the standalone `<Name>StatusNNN` alias stays the plain body union that the
1303
+ * query hooks and `result.data` use.
1304
+ */
1305
+ function buildResponseRecordEntry(node, res, resolver) {
1306
+ const statusName = resolver.response.status(node, res.statusCode);
1307
+ const variants = (res.content ?? []).filter((entry) => entry.schema);
1308
+ if (variants.length <= 1) return kubb_kit.ast.factory.createSchema({
1309
+ type: "ref",
1310
+ name: statusName
1311
+ });
1312
+ return kubb_kit.ast.factory.createSchema({
1313
+ type: "union",
1314
+ members: resolveContentTypeVariants(variants, statusName).map((variant) => kubb_kit.ast.factory.createSchema({
1315
+ type: "object",
1316
+ properties: [kubb_kit.ast.factory.createProperty({
1317
+ name: "contentType",
1318
+ required: true,
1319
+ schema: kubb_kit.ast.factory.createSchema({
1320
+ type: "enum",
1321
+ enumValues: [variant.contentType]
1322
+ })
1323
+ }), kubb_kit.ast.factory.createProperty({
1324
+ name: "data",
1325
+ required: true,
1326
+ schema: kubb_kit.ast.factory.createSchema({
1327
+ type: "ref",
1328
+ name: variant.name
1329
+ })
1330
+ })]
1331
+ }))
1332
+ });
1333
+ }
1334
+ function buildResponses(node, { resolver }) {
1335
+ return kubb_kit.ast.factory.createSchema({
1336
+ type: "object",
1337
+ properties: node.responses.map((res) => kubb_kit.ast.factory.createProperty({
1338
+ name: String(res.statusCode),
1339
+ required: true,
1340
+ schema: buildResponseRecordEntry(node, res, resolver)
1341
+ }))
1342
+ });
1343
+ }
1344
+ function buildResponseUnion(node, { resolver }) {
1345
+ const responsesWithSchema = node.responses.filter((res) => res.content?.some((entry) => entry.schema));
1346
+ if (responsesWithSchema.length === 0) return null;
1347
+ return kubb_kit.ast.factory.createSchema({
1348
+ type: "union",
1349
+ members: responsesWithSchema.map((res) => kubb_kit.ast.factory.createSchema({
1350
+ type: "ref",
1351
+ name: resolver.response.status(node, res.statusCode)
1352
+ }))
1353
+ });
1354
+ }
1355
+ //#endregion
1356
+ //#region src/components/Type.tsx
1357
+ function Type({ name, node, printer, enum: enumOptions, resolver }) {
1358
+ const enumSchemaNodes = kubb_kit.ast.collectSync(node, { schema(n) {
1359
+ const enumNode = kubb_kit.ast.narrowSchema(n, kubb_kit.ast.schemaTypes.enum);
1360
+ if (enumNode?.name && !isInlineConstEnum(enumNode, printer.options.enumSchemaNames)) return enumNode;
1361
+ } });
1362
+ const output = printer.print(node);
1363
+ if (!output) return;
1364
+ const enums = [...new Map(enumSchemaNodes.map((n) => [n.name, n])).values()].map((node) => {
1365
+ return {
1366
+ node,
1367
+ ...getEnumNames({
1368
+ node,
1369
+ enum: enumOptions,
1370
+ resolver
1371
+ })
1372
+ };
1373
+ });
1374
+ const shouldExportEnums = enumOptions.type !== "inlineLiteral";
1375
+ const shouldExportType = enumOptions.type === "inlineLiteral" || enums.every((item) => item.typeName !== name);
1376
+ return /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsxs)(kubb_jsx_jsx_runtime.Fragment, { children: [shouldExportEnums && enums.map(({ node }) => /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(Enum, {
1377
+ node,
1378
+ enum: enumOptions,
1379
+ resolver
1380
+ }, node.name)), shouldExportType && /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Source, {
1381
+ name,
1382
+ isTypeOnly: true,
1383
+ isExportable: true,
1384
+ isIndexable: true,
1385
+ children: output
1386
+ })] });
1387
+ }
1388
+ //#endregion
1389
+ //#region src/printers/printerTs.ts
1390
+ const { isNonNullable } = factory_exports;
1391
+ /**
1392
+ * TypeScript type printer built with `definePrinter`.
1393
+ *
1394
+ * Converts a `SchemaNode` AST node into a TypeScript AST node:
1395
+ * - **`printer.print(node)`** — when `options.typeName` is set, returns a full
1396
+ * `type Name = …` or `interface Name { … }` declaration (`ts.Node`).
1397
+ * Without `typeName`, returns the raw `ts.TypeNode` for the schema.
1398
+ *
1399
+ * Dispatches on `node.type` to the appropriate handler in `nodes`. Options are closed
1400
+ * over per printer instance, so each call to `printerTs(options)` produces an independent printer.
1401
+ *
1402
+ * @example Raw type node (no `typeName`)
1403
+ * ```ts
1404
+ * const printer = printerTs({ optionalType: 'questionToken', arrayType: 'array', enum: { type: 'inlineLiteral' } })
1405
+ * const typeNode = printer.print(schemaNode) // ts.TypeNode
1406
+ * ```
1407
+ *
1408
+ * @example Full declaration (with `typeName`)
1409
+ * ```ts
1410
+ * const printer = printerTs({ optionalType: 'questionToken', arrayType: 'array', enum: { type: 'inlineLiteral' }, typeName: 'MyType' })
1411
+ * const declaration = printer.print(schemaNode) // ts.TypeAliasDeclaration | ts.InterfaceDeclaration
1412
+ * ```
1413
+ */
1414
+ const printerTs = kubb_kit.ast.createPrinter((options) => {
1415
+ const addsUndefined = OPTIONAL_ADDS_UNDEFINED.has(options.optionalType);
1416
+ return {
1417
+ name: "typescript",
1418
+ options,
1419
+ nodes: {
1420
+ any: () => keywordTypeNodes.any,
1421
+ unknown: () => keywordTypeNodes.unknown,
1422
+ void: () => keywordTypeNodes.void,
1423
+ never: () => keywordTypeNodes.never,
1424
+ boolean: () => keywordTypeNodes.boolean,
1425
+ null: () => keywordTypeNodes.null,
1426
+ blob: () => createTypeReferenceNode("Blob", []),
1427
+ string: () => keywordTypeNodes.string,
1428
+ uuid: () => keywordTypeNodes.string,
1429
+ email: () => keywordTypeNodes.string,
1430
+ url: (node) => {
1431
+ if (node.path) return createUrlTemplateType(node.path);
1432
+ return keywordTypeNodes.string;
1433
+ },
1434
+ ipv4: () => keywordTypeNodes.string,
1435
+ ipv6: () => keywordTypeNodes.string,
1436
+ datetime: () => keywordTypeNodes.string,
1437
+ number: () => keywordTypeNodes.number,
1438
+ integer: () => keywordTypeNodes.number,
1439
+ bigint: () => keywordTypeNodes.bigint,
1440
+ date: dateOrStringNode,
1441
+ time: dateOrStringNode,
1442
+ ref(node) {
1443
+ if (!node.name) return null;
1444
+ const refName = kubb_kit.ast.resolveRefName(node);
1445
+ if (!refName) return null;
1446
+ const name = node.ref && ENUM_TYPES_WITH_KEY_SUFFIX.has(this.options.enum.type) && this.options.enum.typeSuffix && this.options.enumSchemaNames?.has(refName) ? this.options.resolver.enum.keyName({ name: refName }, this.options.enum.typeSuffix) : node.ref ? this.options.resolver.name(refName) : refName;
1447
+ return createTypeReferenceNode(name, void 0);
1448
+ },
1449
+ enum(node) {
1450
+ const values = node.namedEnumValues?.map((v) => v.value) ?? node.enumValues ?? [];
1451
+ if (this.options.enum.type === "inlineLiteral" || !node.name || isInlineConstEnum(node, this.options.enumSchemaNames)) return createUnionDeclaration({
1452
+ withParentheses: true,
1453
+ nodes: values.filter((v) => v !== null && v !== void 0).map((value) => constToTypeNode(value, typeof value)).filter(isNonNullable)
1454
+ }) ?? void 0;
1455
+ const resolvedName = ENUM_TYPES_WITH_KEY_SUFFIX.has(this.options.enum.type) && this.options.enum.typeSuffix ? this.options.resolver.enum.keyName(node, this.options.enum.typeSuffix) : this.options.resolver.name(node.name);
1456
+ return createTypeReferenceNode(resolvedName, void 0);
1457
+ },
1458
+ union(node) {
1459
+ const members = node.members ?? [];
1460
+ const hasStringLiteral = members.some((m) => {
1461
+ return kubb_kit.ast.narrowSchema(m, kubb_kit.ast.schemaTypes.enum)?.primitive === "string";
1462
+ });
1463
+ const hasPlainString = members.some((m) => (0, kubb_kit.isStringType)(m));
1464
+ if (hasStringLiteral && hasPlainString) return createUnionDeclaration({
1465
+ withParentheses: true,
1466
+ nodes: members.map((m) => {
1467
+ if ((0, kubb_kit.isStringType)(m)) return createIntersectionDeclaration({
1468
+ nodes: [keywordTypeNodes.string, createTypeLiteralNode([])],
1469
+ withParentheses: true
1470
+ });
1471
+ return this.transform(m);
1472
+ }).filter(isNonNullable)
1473
+ }) ?? void 0;
1474
+ return createUnionDeclaration({
1475
+ withParentheses: true,
1476
+ nodes: buildMemberNodes(members, this.transform)
1477
+ }) ?? void 0;
1478
+ },
1479
+ intersection(node) {
1480
+ return createIntersectionDeclaration({
1481
+ withParentheses: true,
1482
+ nodes: buildMemberNodes(node.members, this.transform)
1483
+ }) ?? null;
1484
+ },
1485
+ array(node) {
1486
+ return createArrayDeclaration({
1487
+ nodes: mapSchemaItems(node, (item) => this.transform(item)).map(({ output }) => output).filter(isNonNullable),
1488
+ arrayType: this.options.arrayType
1489
+ }) ?? null;
1490
+ },
1491
+ tuple(node) {
1492
+ return buildTupleNode(node, this.transform) ?? null;
1493
+ },
1494
+ object(node) {
1495
+ const { transform, options } = this;
1496
+ const addsQuestionToken = OPTIONAL_ADDS_QUESTION_TOKEN.has(options.optionalType);
1497
+ const propertyNodes = mapSchemaProperties(node, (schema) => transform(schema)).map(({ name, property, output }) => {
1498
+ const baseType = output ?? keywordTypeNodes.unknown;
1499
+ const optional = !property.required || !!property.schema.optional || !!property.schema.nullish;
1500
+ const type = buildPropertyType(property.schema, baseType, options.optionalType, optional);
1501
+ const propMeta = (0, kubb_kit.syncSchemaRef)(property.schema);
1502
+ return appendJSDocToNode({
1503
+ node: createPropertySignature({
1504
+ questionToken: optional ? addsQuestionToken : false,
1505
+ name,
1506
+ type,
1507
+ readOnly: propMeta?.readOnly
1508
+ }),
1509
+ comments: buildPropertyJSDocComments(property.schema, optional)
1510
+ });
1511
+ });
1512
+ const allElements = [...propertyNodes, ...buildIndexSignatures(node, propertyNodes.length, transform)];
1513
+ if (!allElements.length) return keywordTypeNodes.object;
1514
+ return createTypeLiteralNode(allElements);
1515
+ },
1516
+ ...options.nodes
1517
+ },
1518
+ print(node) {
1519
+ const { name, syntaxType = "type", description, keysToOmit } = this.options;
1520
+ const transformed = this.transform(node);
1521
+ if (!transformed) return null;
1522
+ const meta = (0, kubb_kit.syncSchemaRef)(node);
1523
+ if (!name) {
1524
+ const withNullable = meta.nullable ? createUnionDeclaration({ nodes: [transformed, keywordTypeNodes.null] }) : transformed;
1525
+ const result = (meta.nullish || meta.optional) && addsUndefined ? createUnionDeclaration({ nodes: [withNullable, keywordTypeNodes.undefined] }) : withNullable;
1526
+ return (0, _kubb_parser_ts.parserTs)().print(result);
1527
+ }
1528
+ const inner = (() => {
1529
+ const omitted = keysToOmit?.length ? createOmitDeclaration({
1530
+ keys: keysToOmit,
1531
+ type: transformed,
1532
+ nonNullable: true
1533
+ }) : transformed;
1534
+ const withNullable = meta.nullable ? createUnionDeclaration({ nodes: [omitted, keywordTypeNodes.null] }) : omitted;
1535
+ return meta.nullish || meta.optional ? createUnionDeclaration({ nodes: [withNullable, keywordTypeNodes.undefined] }) : withNullable;
1536
+ })();
1537
+ const typeNode = createTypeDeclaration({
1538
+ name,
1539
+ isExportable: true,
1540
+ type: inner,
1541
+ syntax: syntaxType === "type" || inner.kind === syntaxKind.union || !!keysToOmit?.length ? "type" : "interface",
1542
+ comments: buildPropertyJSDocComments({
1543
+ ...meta,
1544
+ description
1545
+ })
1546
+ });
1547
+ return (0, _kubb_parser_ts.parserTs)().print(typeNode);
1548
+ }
1549
+ };
1550
+ });
1551
+ //#endregion
1552
+ //#region src/generators/typeGenerator.tsx
1553
+ /**
1554
+ * Resolves the imported type name for a referenced schema. An enum schema emitted
1555
+ * as a `const` object imports its suffixed key alias (e.g. `StatusKey`); every other
1556
+ * schema imports its plain resolved name.
1557
+ */
1558
+ function resolveImportName({ schemaName, enumOptions, enumSchemaNames, resolver }) {
1559
+ if (ENUM_TYPES_WITH_KEY_SUFFIX.has(enumOptions.type) && enumOptions.typeSuffix && enumSchemaNames.has(schemaName)) return resolver.enum.keyName({ name: schemaName }, enumOptions.typeSuffix);
1560
+ return resolver.name(schemaName);
1561
+ }
1562
+ /**
1563
+ * Built-in generator for `@kubb/plugin-ts`. Emits one TypeScript file per
1564
+ * schema in the spec plus per-operation request, response, and parameter
1565
+ * types. Drop-replace with a custom `Generator<PluginTs>` to change how
1566
+ * TypeScript output is produced.
1567
+ */
1568
+ const typeGenerator = (0, kubb_kit.defineGenerator)({
1569
+ name: "typescript",
1570
+ renderer: kubb_jsx.jsxRenderer,
1571
+ schema(node, ctx) {
1572
+ const { enum: enumOptions, syntaxType, optionalType, arrayType, output, group, printer } = ctx.options;
1573
+ const { config, resolver, root } = ctx;
1574
+ if (!node.name) return;
1575
+ const enumSchemaNames = new Set(ctx.meta.enumNames);
1576
+ const importName = (schemaName) => resolveImportName({
1577
+ schemaName,
1578
+ enumOptions,
1579
+ enumSchemaNames,
1580
+ resolver
1581
+ });
1582
+ const imports = resolver.imports({
1583
+ node,
1584
+ root,
1585
+ output,
1586
+ group: group ?? void 0,
1587
+ name: importName
1588
+ });
1589
+ const enumNode = kubb_kit.ast.narrowSchema(node, kubb_kit.ast.schemaTypes.enum);
1590
+ const isEnumSchema = !!enumNode && !isInlineConstEnum(enumNode, enumSchemaNames);
1591
+ const meta = {
1592
+ name: ENUM_TYPES_WITH_KEY_SUFFIX.has(enumOptions.type) && isEnumSchema ? resolver.enum.keyName(node, enumOptions.typeSuffix) : resolver.name(node.name),
1593
+ file: resolver.file({
1594
+ name: node.name,
1595
+ extname: ".ts",
1596
+ root,
1597
+ output,
1598
+ group: group ?? void 0
1599
+ })
1600
+ };
1601
+ const schemaPrinter = printerTs({
1602
+ optionalType,
1603
+ arrayType,
1604
+ enum: enumOptions,
1605
+ name: meta.name,
1606
+ syntaxType,
1607
+ description: node.description,
1608
+ resolver,
1609
+ enumSchemaNames,
1610
+ nodes: printer?.nodes
1611
+ });
1612
+ return /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsxs)(kubb_jsx.File, {
1613
+ baseName: meta.file.baseName,
1614
+ path: meta.file.path,
1615
+ meta: meta.file.meta,
1616
+ banner: resolver.default.banner(ctx.meta, {
1617
+ output,
1618
+ config,
1619
+ file: {
1620
+ path: meta.file.path,
1621
+ baseName: meta.file.baseName
1622
+ }
1623
+ }),
1624
+ footer: resolver.default.footer(ctx.meta, {
1625
+ output,
1626
+ config,
1627
+ file: {
1628
+ path: meta.file.path,
1629
+ baseName: meta.file.baseName
1630
+ }
1631
+ }),
1632
+ children: [imports.map((imp) => /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
1633
+ root: meta.file.path,
1634
+ path: imp.path,
1635
+ name: imp.name,
1636
+ isTypeOnly: true
1637
+ }, [
1638
+ node.name,
1639
+ imp.path,
1640
+ imp.isTypeOnly
1641
+ ].join("-"))), /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(Type, {
1642
+ name: meta.name,
1643
+ node,
1644
+ enum: enumOptions,
1645
+ resolver,
1646
+ printer: schemaPrinter
1647
+ })]
1648
+ });
1649
+ },
1650
+ operation(node, ctx) {
1651
+ const { enum: enumOptions, optionalType, arrayType, syntaxType, group, output, printer } = ctx.options;
1652
+ const { config, resolver, root } = ctx;
1653
+ const meta = { file: resolver.file({
1654
+ name: node.operationId,
1655
+ extname: ".ts",
1656
+ tag: node.tags[0] ?? "default",
1657
+ path: node.path,
1658
+ root,
1659
+ output,
1660
+ group: group ?? void 0
1661
+ }) };
1662
+ const enumSchemaNames = new Set(ctx.meta.enumNames);
1663
+ const importName = (schemaName) => resolveImportName({
1664
+ schemaName,
1665
+ enumOptions,
1666
+ enumSchemaNames,
1667
+ resolver
1668
+ });
1669
+ function renderSchemaType({ schema, name, keysToOmit }) {
1670
+ if (!schema) return null;
1671
+ const imports = resolver.imports({
1672
+ node: schema,
1673
+ root,
1674
+ output,
1675
+ group: group ?? void 0,
1676
+ name: importName
1677
+ });
1678
+ const schemaPrinter = printerTs({
1679
+ optionalType,
1680
+ arrayType,
1681
+ enum: enumOptions,
1682
+ name,
1683
+ syntaxType,
1684
+ description: schema.description,
1685
+ keysToOmit,
1686
+ resolver,
1687
+ enumSchemaNames,
1688
+ nodes: printer?.nodes
1689
+ });
1690
+ return /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsxs)(kubb_jsx_jsx_runtime.Fragment, { children: [imports.map((imp) => /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
1691
+ root: meta.file.path,
1692
+ path: imp.path,
1693
+ name: imp.name,
1694
+ isTypeOnly: true
1695
+ }, [
1696
+ name,
1697
+ imp.path,
1698
+ imp.isTypeOnly
1699
+ ].join("-"))), /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(Type, {
1700
+ name,
1701
+ node: schema,
1702
+ enum: enumOptions,
1703
+ resolver,
1704
+ printer: schemaPrinter
1705
+ })] });
1706
+ }
1707
+ /**
1708
+ * Emits an individual type per content type plus a plain union alias under `baseName`. Shared by
1709
+ * the request body and multi-content-type responses. The response record discriminates these
1710
+ * variants by content type in {@link buildResponses}; the standalone alias stays a plain union so
1711
+ * query hooks and `result.data` keep the bare body.
1712
+ */
1713
+ function buildContentTypeVariants(entries, baseName, decorate) {
1714
+ const variants = resolveContentTypeVariants(entries, baseName);
1715
+ const unionSchema = kubb_kit.ast.factory.createSchema({
1716
+ type: "union",
1717
+ members: variants.map((variant) => kubb_kit.ast.factory.createSchema({
1718
+ type: "ref",
1719
+ name: variant.name
1720
+ }))
1721
+ });
1722
+ return /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsxs)(kubb_jsx_jsx_runtime.Fragment, { children: [variants.map((variant) => renderSchemaType({
1723
+ schema: decorate ? decorate(variant.schema) : variant.schema,
1724
+ name: variant.name,
1725
+ keysToOmit: variant.keysToOmit
1726
+ })), renderSchemaType({
1727
+ schema: unionSchema,
1728
+ name: baseName
1729
+ })] });
1730
+ }
1731
+ const { path: pathParams, query: queryParams, header: headerParams } = getOperationParameters(node);
1732
+ const paramGroupTypes = [
1733
+ pathParams.length > 0 && renderSchemaType({
1734
+ schema: buildParams({ params: pathParams }),
1735
+ name: resolver.param.path(node, pathParams[0])
1736
+ }),
1737
+ queryParams.length > 0 && renderSchemaType({
1738
+ schema: buildParams({ params: queryParams }),
1739
+ name: resolver.param.query(node, queryParams[0])
1740
+ }),
1741
+ headerParams.length > 0 && renderSchemaType({
1742
+ schema: buildParams({ params: headerParams }),
1743
+ name: resolver.param.headers(node, headerParams[0])
1744
+ })
1745
+ ];
1746
+ const requestBodyContent = node.requestBody?.content ?? [];
1747
+ function buildRequestType() {
1748
+ if (requestBodyContent.length === 0) return null;
1749
+ if (requestBodyContent.length === 1) {
1750
+ const entry = requestBodyContent[0];
1751
+ if (!entry.schema) return null;
1752
+ return renderSchemaType({
1753
+ schema: {
1754
+ ...entry.schema,
1755
+ description: node.requestBody.description ?? entry.schema.description
1756
+ },
1757
+ name: resolver.response.body(node),
1758
+ keysToOmit: entry.keysToOmit
1759
+ });
1760
+ }
1761
+ return buildContentTypeVariants(requestBodyContent, resolver.response.body(node), (schema) => ({
1762
+ ...schema,
1763
+ description: node.requestBody.description ?? schema.description
1764
+ }));
1765
+ }
1766
+ const requestType = buildRequestType();
1767
+ const responseTypes = node.responses.map((res) => {
1768
+ const variants = (res.content ?? []).filter((entry) => entry.schema);
1769
+ if (variants.length > 1) return buildContentTypeVariants(variants, resolver.response.status(node, res.statusCode));
1770
+ const primary = variants[0] ?? res.content?.[0];
1771
+ return renderSchemaType({
1772
+ schema: primary?.schema ?? null,
1773
+ name: resolver.response.status(node, res.statusCode),
1774
+ keysToOmit: primary?.keysToOmit
1775
+ });
1776
+ });
1777
+ const optionsType = renderSchemaType({
1778
+ schema: buildOptionsSchema(node, resolver),
1779
+ name: resolver.response.options(node)
1780
+ });
1781
+ const responsesType = renderSchemaType({
1782
+ schema: buildResponses(node, { resolver }),
1783
+ name: resolver.response.responses(node)
1784
+ });
1785
+ function buildResponseType() {
1786
+ const hasSchema = (res) => (res.content ?? []).some((entry) => entry.schema);
1787
+ if (!node.responses.some(hasSchema)) return null;
1788
+ const responseName = resolver.response.response(node);
1789
+ const responsesWithSchema = node.responses.filter(hasSchema);
1790
+ if (new Set(responsesWithSchema.flatMap((res) => (res.content ?? []).flatMap((entry) => entry.schema ? collectRefNames(entry.schema).map(importName) : []))).has(responseName)) return null;
1791
+ return renderSchemaType({
1792
+ schema: {
1793
+ ...buildResponseUnion(node, { resolver }),
1794
+ description: "Union of all possible responses"
1795
+ },
1796
+ name: responseName
1797
+ });
1798
+ }
1799
+ const responseType = buildResponseType();
1800
+ return /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsxs)(kubb_jsx.File, {
1801
+ baseName: meta.file.baseName,
1802
+ path: meta.file.path,
1803
+ meta: meta.file.meta,
1804
+ banner: resolver.default.banner(ctx.meta, {
1805
+ output,
1806
+ config,
1807
+ file: {
1808
+ path: meta.file.path,
1809
+ baseName: meta.file.baseName
1810
+ }
1811
+ }),
1812
+ footer: resolver.default.footer(ctx.meta, {
1813
+ output,
1814
+ config,
1815
+ file: {
1816
+ path: meta.file.path,
1817
+ baseName: meta.file.baseName
1818
+ }
1819
+ }),
1820
+ children: [
1821
+ paramGroupTypes,
1822
+ responseTypes,
1823
+ requestType,
1824
+ optionsType,
1825
+ responsesType,
1826
+ responseType
1827
+ ]
1828
+ });
1829
+ }
1830
+ });
1831
+ //#endregion
1832
+ //#region src/resolvers/resolverTs.ts
1833
+ /**
1834
+ * Default resolver used by `@kubb/plugin-ts`. Decides the names and file paths
1835
+ * for every generated TypeScript type. Import this in other plugins that need
1836
+ * to reference the exact names `plugin-ts` produces without duplicating the
1837
+ * casing/file-layout rules.
1838
+ *
1839
+ * The `default` helpers are supplied by `createResolver`. This plugin overrides the top-level `name`
1840
+ * to use PascalCase for value and type names and `file` to write PascalCase file paths (dotted names
1841
+ * become `/`-joined), and groups the operation-specific naming under the `param`, `response`, and
1842
+ * `enum` namespaces.
1843
+ *
1844
+ * @example Resolve a type and file name
1845
+ * ```ts
1846
+ * import { resolverTs } from '@kubb/plugin-ts'
1847
+ *
1848
+ * resolverTs.name('list pets') // 'ListPets'
1849
+ * resolverTs.response.status(node, 200) // 'ListPetsStatus200'
1850
+ * ```
1851
+ */
1852
+ const resolverTs = (0, kubb_kit.createResolver)({
1853
+ pluginName: "plugin-ts",
1854
+ name(name) {
1855
+ return ensureValidVarName(pascalCase(name));
1856
+ },
1857
+ file: createCasedFile(pascalCase),
1858
+ param: createOperationParamResolver(),
1859
+ response: {
1860
+ ...createOperationResponseResolver(),
1861
+ options(node) {
1862
+ return this.name(`${node.operationId} Options`);
1863
+ }
1864
+ },
1865
+ enum: { keyName(node, enumTypeSuffix = "key") {
1866
+ return `${this.name(node.name ?? "")}${enumTypeSuffix}`;
1867
+ } }
1868
+ });
1869
+ //#endregion
1870
+ //#region src/plugin.ts
1871
+ /**
1872
+ * Canonical plugin name for `@kubb/plugin-ts`. Used for driver lookups and
1873
+ * cross-plugin dependency references.
1874
+ */
1875
+ const pluginTsName = "plugin-ts";
1876
+ /**
1877
+ * Generates TypeScript `type` aliases and `interface` declarations from an
1878
+ * OpenAPI spec. The foundation that every other Kubb plugin builds on:
1879
+ * clients, query hooks, mocks, and validators all reference the names this
1880
+ * plugin produces.
1881
+ *
1882
+ * @example
1883
+ * ```ts
1884
+ * import { defineConfig } from 'kubb/config'
1885
+ * import { pluginTs } from '@kubb/plugin-ts'
1886
+ *
1887
+ * export default defineConfig({
1888
+ * input: './petStore.yaml',
1889
+ * output: { path: './src/gen' },
1890
+ * plugins: [
1891
+ * pluginTs({
1892
+ * output: { path: './types' },
1893
+ * enum: { type: 'asConst' },
1894
+ * optionalType: 'questionTokenAndUndefined',
1895
+ * }),
1896
+ * ],
1897
+ * })
1898
+ * ```
1899
+ */
1900
+ const pluginTs = (0, kubb_kit.definePlugin)((options) => {
1901
+ const { output = {
1902
+ path: "types",
1903
+ barrel: { type: "named" }
1904
+ }, group, exclude = [], include, override = [], enum: enumOptions = {}, optionalType = "questionToken", arrayType = "array", syntaxType = "type", printer, resolver: userResolver, macros: userMacros } = options;
1905
+ const groupConfig = createGroupConfig(group);
1906
+ const resolvedEnum = {
1907
+ type: enumOptions.type ?? "asConst",
1908
+ constCasing: enumOptions.constCasing ?? "camelCase",
1909
+ typeSuffix: enumOptions.typeSuffix ?? "Key",
1910
+ keyCasing: enumOptions.keyCasing ?? "none"
1911
+ };
1912
+ return {
1913
+ name: pluginTsName,
1914
+ options,
1915
+ hooks: { "kubb:plugin:setup"(ctx) {
1916
+ ctx.setOptions({
1917
+ output,
1918
+ exclude,
1919
+ include,
1920
+ override,
1921
+ optionalType,
1922
+ group: groupConfig,
1923
+ arrayType,
1924
+ enum: resolvedEnum,
1925
+ syntaxType,
1926
+ printer
1927
+ });
1928
+ ctx.setResolver(userResolver ? kubb_kit.Resolver.merge(resolverTs, userResolver) : resolverTs);
1929
+ if (userMacros?.length) ctx.setMacros(userMacros);
1930
+ ctx.addGenerator(typeGenerator);
1931
+ } }
1932
+ };
1933
+ });
1934
+ //#endregion
1935
+ //#region src/printers/functionParams.ts
1936
+ /**
1937
+ * Narrows a {@link TypeExpression} to a {@link TypeLiteralNode}.
1938
+ */
1939
+ function isTypeLiteral(type) {
1940
+ return typeof type !== "string" && type.kind === "TypeLiteral";
1941
+ }
1942
+ /**
1943
+ * Narrows a {@link TypeExpression} to an {@link IndexedAccessTypeNode}.
1944
+ */
1945
+ function isIndexedAccessType(type) {
1946
+ return typeof type !== "string" && type.kind === "IndexedAccessType";
1947
+ }
1948
+ /**
1949
+ * Creates a {@link TypeLiteralNode} representing an inline anonymous object type.
1950
+ *
1951
+ * @example
1952
+ * ```ts
1953
+ * createTypeLiteral({ members: [{ name: 'petId', type: 'string', optional: false }] })
1954
+ * // { petId: string }
1955
+ * ```
1956
+ */
1957
+ function createTypeLiteral(props) {
1958
+ return {
1959
+ kind: "TypeLiteral",
1960
+ ...props
1961
+ };
1962
+ }
1963
+ /**
1964
+ * Creates an {@link IndexedAccessTypeNode} representing a single field accessed from a named type.
1965
+ *
1966
+ * @example
1967
+ * ```ts
1968
+ * createIndexedAccessType({ target: 'DeletePetPathParams', key: 'petId' })
1969
+ * // DeletePetPathParams['petId']
1970
+ * ```
1971
+ */
1972
+ function createIndexedAccessType(props) {
1973
+ return {
1974
+ kind: "IndexedAccessType",
1975
+ ...props
1976
+ };
1977
+ }
1978
+ /**
1979
+ * Creates an {@link ObjectBindingPatternNode} for a destructured parameter binding.
1980
+ *
1981
+ * @example
1982
+ * ```ts
1983
+ * createObjectBindingPattern({ elements: [{ name: 'id' }, { name: 'name' }] })
1984
+ * // { id, name }
1985
+ * ```
1986
+ */
1987
+ function createObjectBindingPattern(props) {
1988
+ return {
1989
+ kind: "ObjectBindingPattern",
1990
+ ...props
1991
+ };
1992
+ }
1993
+ /**
1994
+ * Creates a {@link FunctionParameterNode}. `optional` defaults to `false`.
1995
+ * Passing `properties` builds a destructured group: an {@link ObjectBindingPatternNode} name
1996
+ * paired with a {@link TypeLiteralNode} type.
1997
+ *
1998
+ * @example Optional param
1999
+ * ```ts
2000
+ * createFunctionParameter({ name: 'params', type: 'QueryParams', optional: true })
2001
+ * // → params?: QueryParams
2002
+ * ```
2003
+ *
2004
+ * @example Destructured group
2005
+ * ```ts
2006
+ * createFunctionParameter({ properties: [{ name: 'id', type: 'string' }, { name: 'name', type: 'string', optional: true }], default: '{}' })
2007
+ * // → { id, name }: { id: string; name?: string } = {}
2008
+ * ```
2009
+ */
2010
+ function createFunctionParameter(input) {
2011
+ if ("properties" in input) return {
2012
+ kind: "FunctionParameter",
2013
+ name: createObjectBindingPattern({ elements: input.properties.map((p) => ({ name: p.name })) }),
2014
+ type: createTypeLiteral({ members: input.properties.map((p) => ({
2015
+ name: p.name,
2016
+ type: p.type,
2017
+ optional: p.optional ?? false
2018
+ })) }),
2019
+ optional: input.optional ?? false,
2020
+ ...input.default !== void 0 ? { default: input.default } : {}
2021
+ };
2022
+ return {
2023
+ kind: "FunctionParameter",
2024
+ optional: false,
2025
+ ...input
2026
+ };
2027
+ }
2028
+ /**
2029
+ * Creates a {@link FunctionParametersNode} from an ordered list of parameters.
2030
+ *
2031
+ * @example
2032
+ * ```ts
2033
+ * const empty = createFunctionParameters()
2034
+ * // { params: [] }
2035
+ * ```
2036
+ */
2037
+ function createFunctionParameters(props = {}) {
2038
+ return {
2039
+ kind: "FunctionParameters",
2040
+ params: [],
2041
+ ...props
2042
+ };
2043
+ }
2044
+ //#endregion
2045
+ //#region src/printers/functionPrinter.ts
2046
+ /**
2047
+ * Renders a {@link TypeExpression} to its TypeScript source.
2048
+ *
2049
+ * - a `string` is a type reference, returned as-is
2050
+ * - an `IndexedAccessType` becomes `objectType['indexType']`
2051
+ * - a `TypeLiteral` becomes `{ key: Type; key?: Type }`
2052
+ *
2053
+ * `transformType` is applied once to the fully rendered type, matching how the
2054
+ * printer wrapped reference types before the `ts.factory` model.
2055
+ */
2056
+ function renderType(type, transformType) {
2057
+ const rendered = renderTypeExpression(type);
2058
+ return transformType ? transformType(rendered) : rendered;
2059
+ }
2060
+ /**
2061
+ * Renders an object-type key, quoting it as a string literal when it is not a valid
2062
+ * identifier so `{ 'content-type': string }` stays valid TypeScript.
2063
+ */
2064
+ function renderKey(name) {
2065
+ return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name) ? name : JSON.stringify(name);
2066
+ }
2067
+ function renderTypeExpression(type) {
2068
+ if (typeof type === "string") return type;
2069
+ if (isIndexedAccessType(type)) return `${type.target}['${type.key}']`;
2070
+ return `{ ${type.members.map((member) => {
2071
+ const value = renderTypeExpression(member.type);
2072
+ return member.optional ? `${renderKey(member.name)}?: ${value}` : `${renderKey(member.name)}: ${value}`;
2073
+ }).join("; ")} }`;
2074
+ }
2075
+ function groupMembers(param) {
2076
+ if (typeof param.name === "string") return null;
2077
+ return param.type && isTypeLiteral(param.type) ? param.type.members : [];
2078
+ }
2079
+ function rank(param) {
2080
+ if (param.rest) return PARAM_RANK.rest;
2081
+ if (param.default) return PARAM_RANK.withDefault;
2082
+ const members = groupMembers(param);
2083
+ if (members) return members.every((m) => m.optional) ? PARAM_RANK.optional : PARAM_RANK.required;
2084
+ return param.optional ? PARAM_RANK.optional : PARAM_RANK.required;
2085
+ }
2086
+ function sortParams(params) {
2087
+ return params.toSorted((a, b) => rank(a) - rank(b));
2088
+ }
2089
+ function sortedGroupMembers(name, type) {
2090
+ const members = type && isTypeLiteral(type) ? type.members : [];
2091
+ const memberRank = (optional) => optional ? PARAM_RANK.optional : PARAM_RANK.required;
2092
+ return name.elements.map((element, index) => ({
2093
+ name: element.name,
2094
+ propertyName: element.propertyName,
2095
+ type: members[index]?.type,
2096
+ optional: members[index]?.optional
2097
+ })).toSorted((a, b) => memberRank(a.optional) - memberRank(b.optional));
2098
+ }
2099
+ /**
2100
+ * Renders one binding element: the local name, prefixed with its source key when the
2101
+ * binding renames the property, as in `{ petId: id }`.
2102
+ */
2103
+ function renderBindingMember(member, transformName) {
2104
+ const local = transformName ? transformName(member.name) : member.name;
2105
+ return member.propertyName ? `${member.propertyName}: ${local}` : local;
2106
+ }
2107
+ /**
2108
+ * Renders the type annotation of a destructured group. An inline object type is
2109
+ * rendered from the already-sorted members so its key order matches the binding;
2110
+ * a reference type is rendered as-is.
2111
+ */
2112
+ function renderGroupType(type, sorted, transformType) {
2113
+ if (!type) return void 0;
2114
+ if (!isTypeLiteral(type)) return renderType(type);
2115
+ const typed = sorted.filter((member) => member.type !== void 0);
2116
+ if (!typed.length) return void 0;
2117
+ return `{ ${typed.map((member) => {
2118
+ const key = renderKey(member.propertyName ?? member.name);
2119
+ const value = renderType(member.type, transformType);
2120
+ return member.optional ? `${key}?: ${value}` : `${key}: ${value}`;
2121
+ }).join("; ")} }`;
2122
+ }
2123
+ function printParameter(node, options) {
2124
+ const { mode, transformName, transformType } = options;
2125
+ const bindingName = node.name;
2126
+ if (mode === "call") {
2127
+ if (typeof bindingName !== "string") return `{ ${sortedGroupMembers(bindingName, node.type).map((member) => renderBindingMember(member)).join(", ")} }`;
2128
+ const name = transformName ? transformName(bindingName) : bindingName;
2129
+ return node.rest ? `...${name}` : name;
2130
+ }
2131
+ if (typeof bindingName !== "string") {
2132
+ const sorted = sortedGroupMembers(bindingName, node.type);
2133
+ const binding = `{ ${sorted.map((member) => renderBindingMember(member, transformName)).join(", ")} }`;
2134
+ const allOptional = sorted.every((member) => member.optional);
2135
+ const type = renderGroupType(node.type, sorted, transformType);
2136
+ if (type) {
2137
+ if (allOptional) return `${binding}: ${type} = ${node.default ?? "{}"}`;
2138
+ return node.default ? `${binding}: ${type} = ${node.default}` : `${binding}: ${type}`;
2139
+ }
2140
+ return node.default ? `${binding} = ${node.default}` : binding;
2141
+ }
2142
+ const name = transformName ? transformName(bindingName) : bindingName;
2143
+ const type = node.type ? renderType(node.type, transformType) : void 0;
2144
+ if (node.rest) return type ? `...${name}: ${type}` : `...${name}`;
2145
+ if (type) {
2146
+ if (node.optional) return `${name}?: ${type}`;
2147
+ return node.default ? `${name}: ${type} = ${node.default}` : `${name}: ${type}`;
2148
+ }
2149
+ return node.default ? `${name} = ${node.default}` : name;
2150
+ }
2151
+ /**
2152
+ * Default function-signature printer. Renders a parameter list in one of two modes:
2153
+ * `declaration` for the function signature and `call` for the call arguments.
2154
+ *
2155
+ * @example
2156
+ * ```ts
2157
+ * const printer = functionPrinter({ mode: 'declaration' })
2158
+ *
2159
+ * const sig = createFunctionParameters({
2160
+ * params: [
2161
+ * createFunctionParameter({ name: 'petId', type: 'string', optional: false }),
2162
+ * createFunctionParameter({ name: 'config', type: 'Config', optional: false, default: '{}' }),
2163
+ * ],
2164
+ * })
2165
+ *
2166
+ * printer.print(sig) // → "petId: string, config: Config = {}"
2167
+ * ```
2168
+ */
2169
+ function functionPrinter(options) {
2170
+ return {
2171
+ name: "functionParameters",
2172
+ options,
2173
+ print(node) {
2174
+ return sortParams(node.params).map((p) => printParameter(p, options)).filter(Boolean).join(", ");
2175
+ }
2176
+ };
2177
+ }
2178
+ //#endregion
2179
+ //#region src/printers/operationParams.ts
2180
+ /**
2181
+ * Resolves the {@link TypeExpression} for an individual parameter.
2182
+ *
2183
+ * Without a resolver, it falls back to the schema primitive (a plain type-name string). When the
2184
+ * parameter belongs to a named group, it emits an `IndexedAccessType` like `GroupParams['petId']`,
2185
+ * otherwise the resolved individual name.
2186
+ */
2187
+ function resolveParamType({ node, param, resolver }) {
2188
+ if (!resolver) return param.schema.primitive ?? "unknown";
2189
+ const individualName = resolver.param.name(node, param);
2190
+ const groupLocation = param.in === "path" || param.in === "query" || param.in === "header" ? param.in : void 0;
2191
+ const groupResolvers = {
2192
+ path: resolver.param.path,
2193
+ query: resolver.param.query,
2194
+ header: resolver.param.headers
2195
+ };
2196
+ const groupName = groupLocation ? groupResolvers[groupLocation].call(resolver, node, param) : void 0;
2197
+ if (groupName && groupName !== individualName) return createIndexedAccessType({
2198
+ target: groupName,
2199
+ key: param.name
2200
+ });
2201
+ return individualName;
2202
+ }
2203
+ /**
2204
+ * Derives a {@link ParamGroupType} for a query or header group from the resolver.
2205
+ *
2206
+ * Returns `null` when there is no resolver, no params, or the group name equals the
2207
+ * individual param name (so there is no real group to emit).
2208
+ */
2209
+ function resolveGroupType({ node, params, group, resolver }) {
2210
+ if (!resolver || !params.length) return null;
2211
+ const firstParam = params[0];
2212
+ const groupName = (group === "query" ? resolver.param.query : resolver.param.headers).call(resolver, node, firstParam);
2213
+ if (groupName === resolver.param.name(node, firstParam)) return null;
2214
+ return {
2215
+ type: groupName,
2216
+ optional: params.every((p) => !p.required)
2217
+ };
2218
+ }
2219
+ /**
2220
+ * Converts an `OperationNode` into function parameters for code generation.
2221
+ *
2222
+ * Centralizes parameter grouping logic for all plugins. `paramsType` chooses between one
2223
+ * destructured object parameter (`object`) and separate top-level parameters (`inline`), while
2224
+ * `pathParamsType` controls how path params render in inline mode. Provide a `resolver` for type
2225
+ * name resolution and `extraParams` for plugin-specific trailing parameters such as an `options` object.
2226
+ */
2227
+ function createOperationParams(node, options) {
2228
+ const { paramsType, pathParamsType, resolver, pathParamsDefault, extraParams = [], paramNames, typeWrapper } = options;
2229
+ const dataName = paramNames?.data ?? "data";
2230
+ const paramsName = paramNames?.params ?? "params";
2231
+ const headersName = paramNames?.headers ?? "headers";
2232
+ const pathName = paramNames?.path ?? "pathParams";
2233
+ const wrapType = (type) => typeWrapper ? typeWrapper(type) : type;
2234
+ const wrapTypeExpression = (type) => typeof type === "string" ? wrapType(type) : type;
2235
+ const { path: pathParams, query: queryParams, header: headerParams } = getOperationParameters(node);
2236
+ const toProperty = (param) => ({
2237
+ name: param.name,
2238
+ type: wrapTypeExpression(resolveParamType({
2239
+ node,
2240
+ param,
2241
+ resolver
2242
+ })),
2243
+ optional: !param.required
2244
+ });
2245
+ const emptyObjectDefault = (props) => props.every((p) => p.optional) ? "{}" : void 0;
2246
+ const bodyType = node.requestBody?.content?.[0]?.schema ? wrapType(resolver?.response.body(node) ?? "unknown") : void 0;
2247
+ const bodyProperty = bodyType ? [{
2248
+ name: dataName,
2249
+ type: bodyType,
2250
+ optional: !(node.requestBody?.required ?? false)
2251
+ }] : [];
2252
+ const trailingGroups = [{
2253
+ name: paramsName,
2254
+ node,
2255
+ params: queryParams,
2256
+ groupType: resolveGroupType({
2257
+ node,
2258
+ params: queryParams,
2259
+ group: "query",
2260
+ resolver
2261
+ }),
2262
+ resolver,
2263
+ wrapType
2264
+ }, {
2265
+ name: headersName,
2266
+ node,
2267
+ params: headerParams,
2268
+ groupType: resolveGroupType({
2269
+ node,
2270
+ params: headerParams,
2271
+ group: "header",
2272
+ resolver
2273
+ }),
2274
+ resolver,
2275
+ wrapType
2276
+ }];
2277
+ const params = [];
2278
+ if (paramsType === "object") {
2279
+ const children = [
2280
+ ...pathParams.map(toProperty),
2281
+ ...bodyProperty,
2282
+ ...trailingGroups.flatMap(buildGroupProperty)
2283
+ ];
2284
+ if (children.length) params.push(createFunctionParameter({
2285
+ properties: children,
2286
+ default: emptyObjectDefault(children)
2287
+ }));
2288
+ } else {
2289
+ if (pathParamsType === "inlineSpread" && pathParams.length) {
2290
+ const spreadType = resolver?.param.path(node, pathParams[0]);
2291
+ params.push(createFunctionParameter({
2292
+ name: pathName,
2293
+ type: spreadType ? wrapType(spreadType) : void 0,
2294
+ rest: true
2295
+ }));
2296
+ } else if (pathParamsType === "inline") params.push(...pathParams.map((p) => createFunctionParameter(toProperty(p))));
2297
+ else if (pathParams.length) {
2298
+ const pathChildren = pathParams.map(toProperty);
2299
+ params.push(createFunctionParameter({
2300
+ properties: pathChildren,
2301
+ default: pathParamsDefault ?? emptyObjectDefault(pathChildren)
2302
+ }));
2303
+ }
2304
+ params.push(...bodyProperty.map((p) => createFunctionParameter(p)));
2305
+ params.push(...trailingGroups.flatMap(buildGroupParam));
2306
+ }
2307
+ params.push(...extraParams);
2308
+ return createFunctionParameters({ params });
2309
+ }
2310
+ /**
2311
+ * Builds the property descriptor for a query or header group.
2312
+ * Returns an empty array when there are no params to emit.
2313
+ *
2314
+ * A pre-resolved `groupType` emits `name: GroupType`. Otherwise it builds an inline
2315
+ * {@link TypeLiteralNode} from the individual params.
2316
+ */
2317
+ function buildGroupProperty({ name, node, params, groupType, resolver, wrapType }) {
2318
+ if (groupType) return [{
2319
+ name,
2320
+ type: typeof groupType.type === "string" ? wrapType(groupType.type) : groupType.type,
2321
+ optional: groupType.optional
2322
+ }];
2323
+ if (params.length) return [{
2324
+ name,
2325
+ type: buildTypeLiteral({
2326
+ node,
2327
+ params,
2328
+ resolver
2329
+ }),
2330
+ optional: params.every((p) => !p.required)
2331
+ }];
2332
+ return [];
2333
+ }
2334
+ /**
2335
+ * Builds a single {@link FunctionParameterNode} for a query or header group.
2336
+ * Returns an empty array when there are no params to emit.
2337
+ */
2338
+ function buildGroupParam(args) {
2339
+ return buildGroupProperty(args).map((p) => createFunctionParameter(p));
2340
+ }
2341
+ /**
2342
+ * Builds a {@link TypeLiteralNode} for an inline anonymous type grouping named fields.
2343
+ *
2344
+ * Used when query or header parameters have no dedicated group type name.
2345
+ */
2346
+ function buildTypeLiteral({ node, params, resolver }) {
2347
+ return createTypeLiteral({ members: params.map((p) => ({
2348
+ name: p.name,
2349
+ type: resolveParamType({
2350
+ node,
2351
+ param: p,
2352
+ resolver
2353
+ }),
2354
+ optional: !p.required
2355
+ })) });
2356
+ }
2357
+ //#endregion
2358
+ exports.Enum = Enum;
2359
+ exports.Type = Type;
2360
+ exports.buildParams = buildParams;
2361
+ exports.createFunctionParameter = createFunctionParameter;
2362
+ exports.createFunctionParameters = createFunctionParameters;
2363
+ exports.createIndexedAccessType = createIndexedAccessType;
2364
+ exports.createObjectBindingPattern = createObjectBindingPattern;
2365
+ exports.createOperationParams = createOperationParams;
2366
+ exports.createTypeLiteral = createTypeLiteral;
2367
+ exports.default = pluginTs;
2368
+ exports.functionPrinter = functionPrinter;
2369
+ exports.pluginTs = pluginTs;
2370
+ exports.pluginTsName = pluginTsName;
2371
+ exports.printerTs = printerTs;
2372
+ exports.renderType = renderType;
2373
+ exports.resolverTs = resolverTs;
2374
+ exports.typeGenerator = typeGenerator;
2375
+
2376
+ //# sourceMappingURL=index.cjs.map