@kubb/plugin-ts 5.0.0-beta.4 → 5.0.0-beta.56

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -5,6 +5,10 @@ Object.defineProperties(exports, {
5
5
  //#region \0rolldown/runtime.js
6
6
  var __create = Object.create;
7
7
  var __defProp = Object.defineProperty;
8
+ var __name = (target, value) => __defProp(target, "name", {
9
+ value,
10
+ configurable: true
11
+ });
8
12
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
9
13
  var __getOwnPropNames = Object.getOwnPropertyNames;
10
14
  var __getProtoOf = Object.getPrototypeOf;
@@ -24,10 +28,10 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
24
28
  enumerable: true
25
29
  }) : target, mod));
26
30
  //#endregion
31
+ let _kubb_ast_utils = require("@kubb/ast/utils");
27
32
  let _kubb_parser_ts = require("@kubb/parser-ts");
28
33
  let _kubb_renderer_jsx = require("@kubb/renderer-jsx");
29
34
  let _kubb_core = require("@kubb/core");
30
- let remeda = require("remeda");
31
35
  let typescript = require("typescript");
32
36
  typescript = __toESM(typescript, 1);
33
37
  let _kubb_renderer_jsx_jsx_runtime = require("@kubb/renderer-jsx/jsx-runtime");
@@ -42,58 +46,41 @@ let _kubb_renderer_jsx_jsx_runtime = require("@kubb/renderer-jsx/jsx-runtime");
42
46
  function toCamelOrPascal(text, pascal) {
43
47
  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) => {
44
48
  if (word.length > 1 && word === word.toUpperCase()) return word;
45
- if (i === 0 && !pascal) return word.charAt(0).toLowerCase() + word.slice(1);
46
- return word.charAt(0).toUpperCase() + word.slice(1);
49
+ return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
47
50
  }).join("").replace(/[^a-zA-Z0-9]/g, "");
48
51
  }
49
52
  /**
50
- * Splits `text` on `.` and applies `transformPart` to each segment.
51
- * The last segment receives `isLast = true`, all earlier segments receive `false`.
52
- * Segments are joined with `/` to form a file path.
53
- *
54
- * Only splits on dots followed by a letter so that version numbers
55
- * embedded in operationIds (e.g. `v2025.0`) are kept intact.
56
- */
57
- function applyToFileParts(text, transformPart) {
58
- const parts = text.split(/\.(?=[a-zA-Z])/);
59
- return parts.map((part, i) => transformPart(part, i === parts.length - 1)).join("/");
60
- }
61
- /**
62
53
  * Converts `text` to camelCase.
63
- * When `isFile` is `true`, dot-separated segments are each cased independently and joined with `/`.
64
54
  *
65
- * @example
66
- * camelCase('hello-world') // 'helloWorld'
67
- * camelCase('pet.petId', { isFile: true }) // 'pet/petId'
55
+ * @example Word boundaries
56
+ * `camelCase('hello-world') // 'helloWorld'`
57
+ *
58
+ * @example With a prefix
59
+ * `camelCase('tag', { prefix: 'create' }) // 'createTag'`
68
60
  */
69
- function camelCase(text, { isFile, prefix = "", suffix = "" } = {}) {
70
- if (isFile) return applyToFileParts(text, (part, isLast) => camelCase(part, isLast ? {
71
- prefix,
72
- suffix
73
- } : {}));
61
+ function camelCase(text, { prefix = "", suffix = "" } = {}) {
74
62
  return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
75
63
  }
76
64
  /**
77
65
  * Converts `text` to PascalCase.
78
- * When `isFile` is `true`, the last dot-separated segment is PascalCased and earlier segments are camelCased.
79
66
  *
80
- * @example
81
- * pascalCase('hello-world') // 'HelloWorld'
82
- * pascalCase('pet.petId', { isFile: true }) // 'pet/PetId'
67
+ * @example Word boundaries
68
+ * `pascalCase('hello-world') // 'HelloWorld'`
69
+ *
70
+ * @example With a suffix
71
+ * `pascalCase('tag', { suffix: 'schema' }) // 'TagSchema'`
83
72
  */
84
- function pascalCase(text, { isFile, prefix = "", suffix = "" } = {}) {
85
- if (isFile) return applyToFileParts(text, (part, isLast) => isLast ? pascalCase(part, {
86
- prefix,
87
- suffix
88
- }) : camelCase(part));
73
+ function pascalCase(text, { prefix = "", suffix = "" } = {}) {
89
74
  return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true);
90
75
  }
91
76
  /**
92
77
  * Converts `text` to snake_case.
93
78
  *
94
- * @example
95
- * snakeCase('helloWorld') // 'hello_world'
96
- * snakeCase('Hello-World') // 'hello_world'
79
+ * @example From camelCase
80
+ * `snakeCase('helloWorld') // 'hello_world'`
81
+ *
82
+ * @example From mixed separators
83
+ * `snakeCase('Hello-World') // 'hello_world'`
97
84
  */
98
85
  function snakeCase(text, { prefix = "", suffix = "" } = {}) {
99
86
  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("_");
@@ -101,8 +88,8 @@ function snakeCase(text, { prefix = "", suffix = "" } = {}) {
101
88
  /**
102
89
  * Converts `text` to SCREAMING_SNAKE_CASE.
103
90
  *
104
- * @example
105
- * screamingSnakeCase('helloWorld') // 'HELLO_WORLD'
91
+ * @example From camelCase
92
+ * `screamingSnakeCase('helloWorld') // 'HELLO_WORLD'`
106
93
  */
107
94
  function screamingSnakeCase(text, { prefix = "", suffix = "" } = {}) {
108
95
  return snakeCase(text, {
@@ -111,60 +98,152 @@ function screamingSnakeCase(text, { prefix = "", suffix = "" } = {}) {
111
98
  }).toUpperCase();
112
99
  }
113
100
  //#endregion
114
- //#region ../../internals/utils/src/string.ts
101
+ //#region ../../internals/utils/src/fs.ts
115
102
  /**
116
- * Strips a single matching pair of `"..."`, `'...'`, or `` `...` `` from both ends of `text`.
117
- * Returns the string unchanged when no balanced quote pair is found.
103
+ * Builds a nested file path from a dotted name. Splits on dots that precede a letter
104
+ * (so version numbers embedded in operationIds like `v2025.0` stay intact), camelCases
105
+ * every earlier segment, applies `caseLast` to the final segment, and joins with `/`.
118
106
  *
119
- * @example
120
- * trimQuotes('"hello"') // 'hello'
121
- * trimQuotes('hello') // 'hello'
122
- */
123
- function trimQuotes(text) {
124
- if (text.length >= 2) {
125
- const first = text[0];
126
- const last = text[text.length - 1];
127
- if (first === "\"" && last === "\"" || first === "'" && last === "'" || first === "`" && last === "`") return text.slice(1, -1);
128
- }
129
- return text;
107
+ * Empty segments are dropped before joining. They arise when the name starts with a dot
108
+ * followed by a letter (e.g. `..Schema` splits into `['..', 'Schema']` and `'..'` cases to
109
+ * an empty string). Without this a leading `/` would form, which `path.resolve` reads as an
110
+ * absolute path, letting generated files escape the configured output directory.
111
+ *
112
+ * @example Nested path from a dotted name
113
+ * `toFilePath('pet.petId') // 'pet/petId'`
114
+ *
115
+ * @example PascalCase the final segment
116
+ * `toFilePath('pet.Pet', pascalCase) // 'pet/Pet'`
117
+ *
118
+ * @example Suffix applied to the final segment only
119
+ * `toFilePath('tag.tag', (part) => camelCase(part, { suffix: 'schema' })) // 'tag/tagSchema'`
120
+ */
121
+ function toFilePath(name, caseLast = camelCase) {
122
+ const parts = name.split(/\.(?=[a-zA-Z])/);
123
+ return parts.map((part, i) => i === parts.length - 1 ? caseLast(part) : camelCase(part)).filter(Boolean).join("/");
130
124
  }
125
+ //#endregion
126
+ //#region ../../internals/utils/src/reserved.ts
131
127
  /**
132
- * Escapes characters that are not allowed inside JS string literals.
133
- * Handles quotes, backslashes, and Unicode line terminators (U+2028 / U+2029).
134
- *
135
- * @see http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.4
128
+ * JavaScript and Java reserved words.
129
+ * @link https://github.com/jonschlinkert/reserved/blob/master/index.js
130
+ */
131
+ const reservedWords = new Set([
132
+ "abstract",
133
+ "arguments",
134
+ "boolean",
135
+ "break",
136
+ "byte",
137
+ "case",
138
+ "catch",
139
+ "char",
140
+ "class",
141
+ "const",
142
+ "continue",
143
+ "debugger",
144
+ "default",
145
+ "delete",
146
+ "do",
147
+ "double",
148
+ "else",
149
+ "enum",
150
+ "eval",
151
+ "export",
152
+ "extends",
153
+ "false",
154
+ "final",
155
+ "finally",
156
+ "float",
157
+ "for",
158
+ "function",
159
+ "goto",
160
+ "if",
161
+ "implements",
162
+ "import",
163
+ "in",
164
+ "instanceof",
165
+ "int",
166
+ "interface",
167
+ "let",
168
+ "long",
169
+ "native",
170
+ "new",
171
+ "null",
172
+ "package",
173
+ "private",
174
+ "protected",
175
+ "public",
176
+ "return",
177
+ "short",
178
+ "static",
179
+ "super",
180
+ "switch",
181
+ "synchronized",
182
+ "this",
183
+ "throw",
184
+ "throws",
185
+ "transient",
186
+ "true",
187
+ "try",
188
+ "typeof",
189
+ "var",
190
+ "void",
191
+ "volatile",
192
+ "while",
193
+ "with",
194
+ "yield",
195
+ "Array",
196
+ "Date",
197
+ "hasOwnProperty",
198
+ "Infinity",
199
+ "isFinite",
200
+ "isNaN",
201
+ "isPrototypeOf",
202
+ "length",
203
+ "Math",
204
+ "name",
205
+ "NaN",
206
+ "Number",
207
+ "Object",
208
+ "prototype",
209
+ "String",
210
+ "toString",
211
+ "undefined",
212
+ "valueOf"
213
+ ]);
214
+ /**
215
+ * Returns `true` when `name` is a syntactically valid JavaScript variable name.
136
216
  *
137
217
  * @example
138
218
  * ```ts
139
- * jsStringEscape('say "hi"\nbye') // 'say \\"hi\\"\\nbye'
219
+ * isValidVarName('status') // true
220
+ * isValidVarName('class') // false (reserved word)
221
+ * isValidVarName('42foo') // false (starts with digit)
140
222
  * ```
141
223
  */
142
- function jsStringEscape(input) {
143
- return `${input}`.replace(/["'\\\n\r\u2028\u2029]/g, (character) => {
144
- switch (character) {
145
- case "\"":
146
- case "'":
147
- case "\\": return `\\${character}`;
148
- case "\n": return "\\n";
149
- case "\r": return "\\r";
150
- case "\u2028": return "\\u2028";
151
- case "\u2029": return "\\u2029";
152
- default: return "";
153
- }
154
- });
224
+ function isValidVarName(name) {
225
+ if (!name || reservedWords.has(name)) return false;
226
+ return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
155
227
  }
156
- //#endregion
157
- //#region ../../internals/utils/src/object.ts
158
228
  /**
159
- * Serializes a primitive value to a JSON string literal, stripping any surrounding quote characters first.
229
+ * Returns `name` when it's a syntactically valid JavaScript variable name,
230
+ * otherwise prefixes it with `_` so the result is a valid identifier.
231
+ *
232
+ * Useful for sanitizing OpenAPI schema names or operation IDs that start with
233
+ * a digit (e.g. `409`, `504AccountCancel`) before using them as exported
234
+ * variable, type, or function names.
160
235
  *
161
236
  * @example
162
- * stringify('hello') // '"hello"'
163
- * stringify('"hello"') // '"hello"'
237
+ * ```ts
238
+ * ensureValidVarName('409') // '_409'
239
+ * ensureValidVarName('504AccountCancel') // '_504AccountCancel'
240
+ * ensureValidVarName('Pet') // 'Pet'
241
+ * ensureValidVarName('class') // '_class'
242
+ * ```
164
243
  */
165
- function stringify(value) {
166
- if (value === void 0 || value === null) return "\"\"";
167
- return JSON.stringify(trimQuotes(value.toString()));
244
+ function ensureValidVarName(name) {
245
+ if (!name || isValidVarName(name)) return name;
246
+ return `_${name}`;
168
247
  }
169
248
  //#endregion
170
249
  //#region src/constants.ts
@@ -177,26 +256,24 @@ const OPTIONAL_ADDS_UNDEFINED = new Set(["undefined", "questionTokenAndUndefined
177
256
  */
178
257
  const OPTIONAL_ADDS_QUESTION_TOKEN = new Set(["questionToken", "questionTokenAndUndefined"]);
179
258
  /**
180
- * `enumType` values that append a `Key` suffix to the generated enum type alias.
259
+ * `enum.type` values that append a `typeSuffix` to the generated enum type alias.
181
260
  */
182
- const ENUM_TYPES_WITH_KEY_SUFFIX = new Set(["asConst", "asPascalConst"]);
261
+ const ENUM_TYPES_WITH_KEY_SUFFIX = new Set(["asConst"]);
183
262
  /**
184
- * `enumType` values that require a runtime value declaration (object, enum, or literal).
263
+ * `enum.type` values that require a runtime value declaration (object, enum, or literal).
185
264
  */
186
265
  const ENUM_TYPES_WITH_RUNTIME_VALUE = new Set([
187
266
  "enum",
188
267
  "asConst",
189
- "asPascalConst",
190
268
  "constEnum",
191
269
  "literal",
192
270
  void 0
193
271
  ]);
194
272
  /**
195
- * `enumType` values whose type declaration is type-only (no runtime value emitted for the type alias).
273
+ * `enum.type` values whose type declaration is type-only (no runtime value emitted for the type alias).
196
274
  */
197
275
  const ENUM_TYPES_WITH_TYPE_ONLY = new Set([
198
276
  "asConst",
199
- "asPascalConst",
200
277
  "literal",
201
278
  void 0
202
279
  ]);
@@ -212,6 +289,9 @@ const PARAM_RANK = {
212
289
  //#endregion
213
290
  //#region src/factory.ts
214
291
  const { SyntaxKind, factory } = typescript.default;
292
+ function isNumber(value) {
293
+ return typeof value === "number" && !Number.isNaN(value);
294
+ }
215
295
  /**
216
296
  * TypeScript AST modifiers for common keywords (async, export, const, static).
217
297
  */
@@ -229,10 +309,19 @@ const syntaxKind = {
229
309
  literalType: SyntaxKind.LiteralType,
230
310
  stringLiteral: SyntaxKind.StringLiteral
231
311
  };
312
+ function isNonNullable$1(value) {
313
+ return value !== null && value !== void 0;
314
+ }
315
+ __name(isNonNullable$1, "isNonNullable");
232
316
  function isValidIdentifier(str) {
233
317
  if (!str.length || str.trim() !== str) return false;
234
- const node = typescript.default.parseIsolatedEntityName(str, typescript.default.ScriptTarget.Latest);
235
- return !!node && node.kind === typescript.default.SyntaxKind.Identifier && typescript.default.identifierToKeywordKind(node.kind) === void 0;
318
+ let ch = str.codePointAt(0);
319
+ if (!typescript.default.isIdentifierStart(ch, typescript.default.ScriptTarget.Latest)) return false;
320
+ for (let i = ch > 65535 ? 2 : 1; i < str.length; i += ch > 65535 ? 2 : 1) {
321
+ ch = str.codePointAt(i);
322
+ if (!typescript.default.isIdentifierPart(ch, typescript.default.ScriptTarget.Latest)) return false;
323
+ }
324
+ return true;
236
325
  }
237
326
  function propertyName(name) {
238
327
  if (typeof name === "string") return isValidIdentifier(name) ? factory.createIdentifier(name) : factory.createStringLiteral(name);
@@ -298,7 +387,7 @@ function createUnionDeclaration({ nodes, withParentheses }) {
298
387
  * Supports optional markers, readonly modifiers, and type annotations.
299
388
  */
300
389
  function createPropertySignature({ readOnly, modifiers = [], name, questionToken, type }) {
301
- return factory.createPropertySignature([...modifiers, readOnly ? factory.createToken(typescript.default.SyntaxKind.ReadonlyKeyword) : void 0].filter(Boolean), propertyName(name), createQuestionToken(questionToken), type);
390
+ return factory.createPropertySignature([...modifiers, readOnly ? factory.createToken(typescript.default.SyntaxKind.ReadonlyKeyword) : void 0].filter((modifier) => modifier !== void 0), propertyName(name), createQuestionToken(questionToken), type);
302
391
  }
303
392
  /**
304
393
  * Creates a function parameter declaration with optional markers, rest parameters, and type annotations.
@@ -390,19 +479,19 @@ function applyEnumKeyCasing(key, casing = "none") {
390
479
  */
391
480
  function createEnumDeclaration({ type = "enum", name, typeName, enums, enumKeyCasing = "none" }) {
392
481
  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]) => {
393
- if ((0, remeda.isNumber)(value)) {
482
+ if (isNumber(value)) {
394
483
  if (value < 0) return factory.createLiteralTypeNode(factory.createPrefixUnaryExpression(typescript.default.SyntaxKind.MinusToken, factory.createNumericLiteral(Math.abs(value))));
395
484
  return factory.createLiteralTypeNode(factory.createNumericLiteral(value?.toString()));
396
485
  }
397
486
  if (typeof value === "boolean") return factory.createLiteralTypeNode(value ? factory.createTrue() : factory.createFalse());
398
487
  if (value) return factory.createLiteralTypeNode(factory.createStringLiteral(value.toString()));
399
- }).filter(Boolean)))];
400
- 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(Boolean), factory.createIdentifier(typeName), enums.map(([key, value]) => {
488
+ }).filter((node) => node !== void 0)))];
489
+ 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]) => {
401
490
  let initializer = factory.createStringLiteral(value?.toString());
402
- if (Number.parseInt(value.toString(), 10) === value && (0, remeda.isNumber)(Number.parseInt(value.toString(), 10))) if (value < 0) initializer = factory.createPrefixUnaryExpression(typescript.default.SyntaxKind.MinusToken, factory.createNumericLiteral(Math.abs(value)));
491
+ if (Number.parseInt(value.toString(), 10) === value && isNumber(Number.parseInt(value.toString(), 10))) if (value < 0) initializer = factory.createPrefixUnaryExpression(typescript.default.SyntaxKind.MinusToken, factory.createNumericLiteral(Math.abs(value)));
403
492
  else initializer = factory.createNumericLiteral(value);
404
493
  if (typeof value === "boolean") initializer = value ? factory.createTrue() : factory.createFalse();
405
- if ((0, remeda.isNumber)(Number.parseInt(key.toString(), 10))) {
494
+ if (isNumber(Number.parseInt(key.toString(), 10))) {
406
495
  const casingKey = applyEnumKeyCasing(`${typeName}_${key}`, enumKeyCasing);
407
496
  return factory.createEnumMember(propertyName(casingKey), initializer);
408
497
  }
@@ -410,19 +499,19 @@ function createEnumDeclaration({ type = "enum", name, typeName, enums, enumKeyCa
410
499
  const casingKey = applyEnumKeyCasing(key.toString(), enumKeyCasing);
411
500
  return factory.createEnumMember(propertyName(casingKey), initializer);
412
501
  }
413
- }).filter(Boolean))];
502
+ }).filter((member) => member !== void 0))];
414
503
  const identifierName = name;
415
504
  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))];
416
505
  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]) => {
417
506
  let initializer = factory.createStringLiteral(value?.toString());
418
- if ((0, remeda.isNumber)(value)) if (value < 0) initializer = factory.createPrefixUnaryExpression(typescript.default.SyntaxKind.MinusToken, factory.createNumericLiteral(Math.abs(value)));
507
+ if (isNumber(value)) if (value < 0) initializer = factory.createPrefixUnaryExpression(typescript.default.SyntaxKind.MinusToken, factory.createNumericLiteral(Math.abs(value)));
419
508
  else initializer = factory.createNumericLiteral(value);
420
509
  if (typeof value === "boolean") initializer = value ? factory.createTrue() : factory.createFalse();
421
510
  if (key) {
422
511
  const casingKey = applyEnumKeyCasing(key.toString(), enumKeyCasing);
423
512
  return factory.createPropertyAssignment(propertyName(casingKey), initializer);
424
513
  }
425
- }).filter(Boolean), 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))))];
514
+ }).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))))];
426
515
  }
427
516
  /**
428
517
  * Creates a TypeScript `Omit<T, Keys>` type reference node.
@@ -504,12 +593,10 @@ const createStringLiteral = factory.createStringLiteral;
504
593
  * Creates an array type node (e.g., `T[]`).
505
594
  */
506
595
  const createArrayTypeNode = factory.createArrayTypeNode;
507
- factory.createParenthesizedType;
508
596
  /**
509
597
  * Creates a literal type node (e.g., `'hello'`, `42`, `true`).
510
598
  */
511
599
  const createLiteralTypeNode = factory.createLiteralTypeNode;
512
- factory.createNull;
513
600
  /**
514
601
  * Creates an identifier node.
515
602
  */
@@ -534,8 +621,6 @@ const createTrue = factory.createTrue;
534
621
  * Creates a boolean false literal type node.
535
622
  */
536
623
  const createFalse = factory.createFalse;
537
- factory.createIndexedAccessTypeNode;
538
- factory.createTypeOperatorNode;
539
624
  /**
540
625
  * Creates a prefix unary expression (e.g., negative numbers, logical not).
541
626
  */
@@ -562,14 +647,14 @@ function dateOrStringNode(node) {
562
647
  * Maps an array of `SchemaNode`s through the printer, filtering out `null` and `undefined` results.
563
648
  */
564
649
  function buildMemberNodes(members, print) {
565
- return (members ?? []).map(print).filter(Boolean);
650
+ return (members ?? []).map(print).filter(isNonNullable$1);
566
651
  }
567
652
  /**
568
653
  * Builds a TypeScript tuple type node from an array schema's `items`,
569
654
  * applying min/max slice and optional/rest element rules.
570
655
  */
571
656
  function buildTupleNode(node, print) {
572
- let items = (node.items ?? []).map(print).filter(Boolean);
657
+ let items = (node.items ?? []).map(print).filter(isNonNullable$1);
573
658
  const restNode = node.rest ? print(node.rest) ?? void 0 : void 0;
574
659
  const { min, max } = node;
575
660
  if (max !== void 0) {
@@ -616,58 +701,61 @@ function buildIndexSignatures(node, propertyCount, print) {
616
701
  * Resolves the runtime identifier name and the TypeScript type name for an enum schema node.
617
702
  *
618
703
  * The raw `node.name` may be a YAML key such as `"enumNames.Type"` which is not a
619
- * valid TypeScript identifier. The resolver normalizes it; for inline enum
620
- * properties the adapter already emits a PascalCase+suffix name so resolution is typically a no-op.
704
+ * valid TypeScript identifier. The resolver normalizes it. For inline enum properties the adapter
705
+ * already emits a PascalCase+suffix name, so resolution is typically a no-op.
706
+ *
707
+ * When `constCasing` is `'pascalCase'` and `typeSuffix` is empty, the const and the type
708
+ * resolve to the same name, which TypeScript merges into a single value+type declaration.
621
709
  */
622
- function getEnumNames({ node, enumType, enumTypeSuffix, resolver }) {
710
+ function getEnumNames({ node, enum: enumOptions, resolver }) {
623
711
  const resolved = resolver.default(node.name, "type");
624
712
  return {
625
- enumName: enumType === "asPascalConst" ? resolved : camelCase(node.name),
626
- typeName: ENUM_TYPES_WITH_KEY_SUFFIX.has(enumType) ? resolver.resolveEnumKeyName(node, enumTypeSuffix) : resolved
713
+ enumName: enumOptions.constCasing === "pascalCase" ? resolved : camelCase(node.name),
714
+ typeName: ENUM_TYPES_WITH_KEY_SUFFIX.has(enumOptions.type) ? resolver.resolveEnumKeyName(node, enumOptions.typeSuffix) : resolved
627
715
  };
628
716
  }
629
717
  /**
630
718
  * Renders the enum declaration(s) for a single named `EnumSchemaNode`.
631
719
  *
632
- * Depending on `enumType` this may emit:
633
- * - A runtime object (`asConst` / `asPascalConst`) plus a `typeof` type alias
720
+ * Depending on `enum.type` this may emit:
721
+ * - A runtime object (`asConst`) plus a `typeof` type alias
634
722
  * - A `const enum` or plain `enum` declaration (`constEnum` / `enum`)
635
723
  * - A union literal type alias (`literal`)
636
724
  *
637
725
  * The emitted `File.Source` nodes carry the resolved names so that the barrel
638
726
  * index picks up the correct export identifiers.
639
727
  */
640
- function Enum({ node, enumType, enumTypeSuffix, enumKeyCasing, resolver }) {
728
+ function Enum({ node, enum: enumOptions, resolver }) {
641
729
  const { enumName, typeName } = getEnumNames({
642
730
  node,
643
- enumType,
644
- enumTypeSuffix,
731
+ enum: enumOptions,
645
732
  resolver
646
733
  });
647
734
  const [nameNode, typeNode] = createEnumDeclaration({
648
735
  name: enumName,
649
736
  typeName,
650
- enums: node.namedEnumValues?.map((v) => [trimQuotes(v.name.toString()), v.value]) ?? node.enumValues?.filter((v) => v !== null && v !== void 0).map((v) => [trimQuotes(v.toString()), v]) ?? [],
651
- type: enumType,
652
- enumKeyCasing
737
+ enums: node.namedEnumValues?.map((v) => [(0, _kubb_ast_utils.trimQuotes)(v.name.toString()), v.value]) ?? node.enumValues?.filter((v) => v !== null && v !== void 0).map((v) => [(0, _kubb_ast_utils.trimQuotes)(v.toString()), v]) ?? [],
738
+ type: enumOptions.type,
739
+ enumKeyCasing: enumOptions.keyCasing
653
740
  });
741
+ const namesMerge = !!nameNode && enumName === typeName;
654
742
  return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [nameNode && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
655
743
  name: enumName,
656
744
  isExportable: true,
657
745
  isIndexable: true,
658
746
  isTypeOnly: false,
659
- children: (0, _kubb_parser_ts.safePrint)(nameNode)
747
+ children: _kubb_parser_ts.parserTs.print(nameNode)
660
748
  }), /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
661
749
  name: typeName,
662
- isIndexable: true,
663
- isExportable: ENUM_TYPES_WITH_RUNTIME_VALUE.has(enumType),
664
- isTypeOnly: ENUM_TYPES_WITH_TYPE_ONLY.has(enumType),
665
- children: (0, _kubb_parser_ts.safePrint)(typeNode)
750
+ isIndexable: !namesMerge,
751
+ isExportable: !namesMerge && ENUM_TYPES_WITH_RUNTIME_VALUE.has(enumOptions.type),
752
+ isTypeOnly: ENUM_TYPES_WITH_TYPE_ONLY.has(enumOptions.type),
753
+ children: _kubb_parser_ts.parserTs.print(typeNode)
666
754
  })] });
667
755
  }
668
756
  //#endregion
669
757
  //#region src/components/Type.tsx
670
- function Type({ name, node, printer, enumType, enumTypeSuffix, enumKeyCasing, resolver }) {
758
+ function Type({ name, node, printer, enum: enumOptions, resolver }) {
671
759
  const enumSchemaNodes = _kubb_core.ast.collect(node, { schema(n) {
672
760
  const enumNode = _kubb_core.ast.narrowSchema(n, _kubb_core.ast.schemaTypes.enum);
673
761
  if (enumNode?.name) return enumNode;
@@ -679,19 +767,16 @@ function Type({ name, node, printer, enumType, enumTypeSuffix, enumKeyCasing, re
679
767
  node,
680
768
  ...getEnumNames({
681
769
  node,
682
- enumType,
683
- enumTypeSuffix,
770
+ enum: enumOptions,
684
771
  resolver
685
772
  })
686
773
  };
687
774
  });
688
- const shouldExportEnums = enumType !== "inlineLiteral";
689
- const shouldExportType = enumType === "inlineLiteral" || enums.every((item) => item.typeName !== name);
775
+ const shouldExportEnums = enumOptions.type !== "inlineLiteral";
776
+ const shouldExportType = enumOptions.type === "inlineLiteral" || enums.every((item) => item.typeName !== name);
690
777
  return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [shouldExportEnums && enums.map(({ node }) => /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(Enum, {
691
778
  node,
692
- enumType,
693
- enumTypeSuffix,
694
- enumKeyCasing,
779
+ enum: enumOptions,
695
780
  resolver
696
781
  }, node.name)), shouldExportType && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
697
782
  name,
@@ -702,6 +787,96 @@ function Type({ name, node, printer, enumType, enumTypeSuffix, enumKeyCasing, re
702
787
  })] });
703
788
  }
704
789
  //#endregion
790
+ //#region ../../internals/shared/src/operation.ts
791
+ /**
792
+ * Maps a content type to the PascalCase suffix used to name per-content-type variants
793
+ * (e.g. `application/json` → `Json`, `application/xml` → `Xml`, `multipart/form-data` → `FormData`).
794
+ */
795
+ function getContentTypeSuffix(contentType) {
796
+ const baseType = contentType.split(";")[0].trim();
797
+ if (baseType === "application/json") return "Json";
798
+ if (baseType === "multipart/form-data") return "FormData";
799
+ if (baseType === "application/x-www-form-urlencoded") return "FormUrlEncoded";
800
+ const parts = (baseType.split("/").pop() ?? baseType).split(/[^a-zA-Z0-9]+/).filter(Boolean);
801
+ if (parts.length === 0) return "Unknown";
802
+ return parts.map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
803
+ }
804
+ /**
805
+ * Appends a content-type suffix to a base name, keeping a trailing `Data` segment last
806
+ * (e.g. `AddPetData` + `Json` → `AddPetJsonData`, `AddPetStatus200` + `Xml` → `AddPetStatus200Xml`).
807
+ */
808
+ function getPerContentTypeName(baseName, suffix) {
809
+ if (baseName.endsWith("Data")) return suffix.endsWith("Data") ? baseName.slice(0, -4) + suffix : `${baseName.slice(0, -4)}${suffix}Data`;
810
+ return baseName + suffix;
811
+ }
812
+ /**
813
+ * Resolves per-content-type variant names for a set of content entries, deduplicating suffix
814
+ * collisions with a numeric counter. Entries without a schema are skipped. The returned `suffix` is
815
+ * the final (possibly counter-augmented) value, so callers can derive parallel names in another
816
+ * namespace (e.g. plugin-faker deriving the matching plugin-ts type name).
817
+ */
818
+ function resolveContentTypeVariants(entries, baseName) {
819
+ const usedNames = /* @__PURE__ */ new Set();
820
+ return entries.filter((entry) => entry.schema).map((entry) => {
821
+ const baseSuffix = getContentTypeSuffix(entry.contentType);
822
+ let suffix = baseSuffix;
823
+ let name = getPerContentTypeName(baseName, suffix);
824
+ let counter = 2;
825
+ while (usedNames.has(name)) {
826
+ suffix = `${baseSuffix}${counter++}`;
827
+ name = getPerContentTypeName(baseName, suffix);
828
+ }
829
+ usedNames.add(name);
830
+ return {
831
+ name,
832
+ suffix,
833
+ schema: entry.schema,
834
+ keysToOmit: entry.keysToOmit,
835
+ contentType: entry.contentType
836
+ };
837
+ });
838
+ }
839
+ function getOperationParameters(node, options = {}) {
840
+ const params = _kubb_core.ast.caseParams(node.parameters, options.paramsCasing);
841
+ return {
842
+ path: params.filter((param) => param.in === "path"),
843
+ query: params.filter((param) => param.in === "query"),
844
+ header: params.filter((param) => param.in === "header"),
845
+ cookie: params.filter((param) => param.in === "cookie")
846
+ };
847
+ }
848
+ //#endregion
849
+ //#region ../../internals/shared/src/group.ts
850
+ /**
851
+ * Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the
852
+ * shared default naming so every plugin groups output consistently:
853
+ *
854
+ * - `path` groups use the second path segment (`/pet/findByStatus` → `pet`).
855
+ * - other groups use the camelCased group (`pet store` → `petStore`).
856
+ *
857
+ * A user-provided `group.name` always wins over the default namer, so callers stay in
858
+ * control of their output folders. Returns `null` when grouping is disabled, matching the
859
+ * per-plugin convention.
860
+ *
861
+ * @param group - The user-supplied group option, or `undefined` to disable grouping.
862
+ *
863
+ * @example
864
+ * ```ts
865
+ * createGroupConfig(group) // shared across every plugin
866
+ * ```
867
+ */
868
+ function createGroupConfig(group) {
869
+ if (!group) return null;
870
+ const defaultName = (ctx) => {
871
+ if (group.type === "path") return `${ctx.group.split("/")[1]}`;
872
+ return camelCase(ctx.group);
873
+ };
874
+ return {
875
+ ...group,
876
+ name: group.name ? group.name : defaultName
877
+ };
878
+ }
879
+ //#endregion
705
880
  //#region src/utils.ts
706
881
  /**
707
882
  * Collects JSDoc annotation strings for a schema node.
@@ -713,15 +888,18 @@ function Type({ name, node, printer, enumType, enumTypeSuffix, enumKeyCasing, re
713
888
  function buildPropertyJSDocComments(schema) {
714
889
  const meta = _kubb_core.ast.syncSchemaRef(schema);
715
890
  const isArray = meta?.primitive === "array";
891
+ const hasDescription = meta && "description" in meta && meta.description;
892
+ const formatComment = meta && "format" in meta && meta.format ? hasDescription ? [" ", `Format: \`${meta.format}\``] : ["@description", `Format: \`${meta.format}\``] : [];
716
893
  return [
717
- meta && "description" in meta && meta.description ? `@description ${jsStringEscape(meta.description)}` : void 0,
718
- meta && "deprecated" in meta && meta.deprecated ? "@deprecated" : void 0,
719
- !isArray && meta && "min" in meta && meta.min !== void 0 ? `@minLength ${meta.min}` : void 0,
720
- !isArray && meta && "max" in meta && meta.max !== void 0 ? `@maxLength ${meta.max}` : void 0,
721
- meta && "pattern" in meta && meta.pattern ? `@pattern ${meta.pattern}` : void 0,
722
- meta && "default" in meta && meta.default !== void 0 ? `@default ${"primitive" in meta && meta.primitive === "string" ? stringify(meta.default) : meta.default}` : void 0,
723
- meta && "example" in meta && meta.example !== void 0 ? `@example ${meta.example}` : void 0,
724
- meta && "primitive" in meta && meta.primitive ? [`@type ${meta.primitive}`, "optional" in schema && schema.optional ? " | undefined" : void 0].filter(Boolean).join("") : void 0
894
+ hasDescription ? `@description ${(0, _kubb_ast_utils.jsStringEscape)(meta.description)}` : null,
895
+ ...formatComment,
896
+ meta && "deprecated" in meta && meta.deprecated ? "@deprecated" : null,
897
+ !isArray && meta && "min" in meta && meta.min !== void 0 ? `@minLength ${meta.min}` : null,
898
+ !isArray && meta && "max" in meta && meta.max !== void 0 ? `@maxLength ${meta.max}` : null,
899
+ meta && "pattern" in meta && meta.pattern ? `@pattern ${meta.pattern}` : null,
900
+ meta && "default" in meta && meta.default !== void 0 ? `@default ${"primitive" in meta && meta.primitive === "string" ? (0, _kubb_ast_utils.stringify)(meta.default) : meta.default}` : null,
901
+ meta && "example" in meta && meta.example !== void 0 ? `@example ${meta.example}` : null,
902
+ meta && "primitive" in meta && meta.primitive ? [`@type ${meta.primitive}`, "optional" in schema && schema.optional ? " | undefined" : null].filter(Boolean).join("") : null
725
903
  ].filter(Boolean);
726
904
  }
727
905
  function buildParams(node, { params, resolver }) {
@@ -738,9 +916,7 @@ function buildParams(node, { params, resolver }) {
738
916
  });
739
917
  }
740
918
  function buildData(node, { resolver }) {
741
- const pathParams = node.parameters.filter((p) => p.in === "path");
742
- const queryParams = node.parameters.filter((p) => p.in === "query");
743
- const headerParams = node.parameters.filter((p) => p.in === "header");
919
+ const { path: pathParams, query: queryParams, header: headerParams } = getOperationParameters(node);
744
920
  return _kubb_core.ast.createSchema({
745
921
  type: "object",
746
922
  deprecated: node.deprecated,
@@ -822,7 +998,7 @@ function buildResponses(node, { resolver }) {
822
998
  });
823
999
  }
824
1000
  function buildResponseUnion(node, { resolver }) {
825
- const responsesWithSchema = node.responses.filter((res) => res.schema);
1001
+ const responsesWithSchema = node.responses.filter((res) => res.content?.some((entry) => entry.schema));
826
1002
  if (responsesWithSchema.length === 0) return null;
827
1003
  return _kubb_core.ast.createSchema({
828
1004
  type: "union",
@@ -834,6 +1010,9 @@ function buildResponseUnion(node, { resolver }) {
834
1010
  }
835
1011
  //#endregion
836
1012
  //#region src/printers/printerTs.ts
1013
+ function isNonNullable(value) {
1014
+ return value !== null && value !== void 0;
1015
+ }
837
1016
  /**
838
1017
  * TypeScript type printer built with `definePrinter`.
839
1018
  *
@@ -847,13 +1026,13 @@ function buildResponseUnion(node, { resolver }) {
847
1026
  *
848
1027
  * @example Raw type node (no `typeName`)
849
1028
  * ```ts
850
- * const printer = printerTs({ optionalType: 'questionToken', arrayType: 'array', enumType: 'inlineLiteral' })
1029
+ * const printer = printerTs({ optionalType: 'questionToken', arrayType: 'array', enum: { type: 'inlineLiteral' } })
851
1030
  * const typeNode = printer.print(schemaNode) // ts.TypeNode
852
1031
  * ```
853
1032
  *
854
1033
  * @example Full declaration (with `typeName`)
855
1034
  * ```ts
856
- * const printer = printerTs({ optionalType: 'questionToken', arrayType: 'array', enumType: 'inlineLiteral', typeName: 'MyType' })
1035
+ * const printer = printerTs({ optionalType: 'questionToken', arrayType: 'array', enum: { type: 'inlineLiteral' }, typeName: 'MyType' })
857
1036
  * const declaration = printer.print(schemaNode) // ts.TypeAliasDeclaration | ts.InterfaceDeclaration
858
1037
  * ```
859
1038
  */
@@ -886,17 +1065,17 @@ const printerTs = _kubb_core.ast.definePrinter((options) => {
886
1065
  date: dateOrStringNode,
887
1066
  time: dateOrStringNode,
888
1067
  ref(node) {
889
- if (!node.name) return;
890
- const refName = node.ref ? _kubb_core.ast.extractRefName(node.ref) ?? node.name : node.name;
891
- return createTypeReferenceNode(node.ref && ENUM_TYPES_WITH_KEY_SUFFIX.has(this.options.enumType) && this.options.enumTypeSuffix && this.options.enumSchemaNames?.has(refName) ? this.options.resolver.resolveEnumKeyName({ name: refName }, this.options.enumTypeSuffix) : node.ref ? this.options.resolver.default(refName, "type") : refName, void 0);
1068
+ if (!node.name) return null;
1069
+ const refName = node.ref ? (0, _kubb_ast_utils.extractRefName)(node.ref) ?? node.name : node.name;
1070
+ return createTypeReferenceNode(node.ref && ENUM_TYPES_WITH_KEY_SUFFIX.has(this.options.enum.type) && this.options.enum.typeSuffix && this.options.enumSchemaNames?.has(refName) ? this.options.resolver.resolveEnumKeyName({ name: refName }, this.options.enum.typeSuffix) : node.ref ? this.options.resolver.default(refName, "type") : refName, void 0);
892
1071
  },
893
1072
  enum(node) {
894
1073
  const values = node.namedEnumValues?.map((v) => v.value) ?? node.enumValues ?? [];
895
- if (this.options.enumType === "inlineLiteral" || !node.name) return createUnionDeclaration({
1074
+ if (this.options.enum.type === "inlineLiteral" || !node.name) return createUnionDeclaration({
896
1075
  withParentheses: true,
897
- nodes: values.filter((v) => v !== null && v !== void 0).map((value) => constToTypeNode(value, typeof value)).filter(Boolean)
1076
+ nodes: values.filter((v) => v !== null && v !== void 0).map((value) => constToTypeNode(value, typeof value)).filter(isNonNullable)
898
1077
  }) ?? void 0;
899
- return createTypeReferenceNode(ENUM_TYPES_WITH_KEY_SUFFIX.has(this.options.enumType) && this.options.enumTypeSuffix ? this.options.resolver.resolveEnumKeyName(node, this.options.enumTypeSuffix) : this.options.resolver.default(node.name, "type"), void 0);
1078
+ return createTypeReferenceNode(ENUM_TYPES_WITH_KEY_SUFFIX.has(this.options.enum.type) && this.options.enum.typeSuffix ? this.options.resolver.resolveEnumKeyName(node, this.options.enum.typeSuffix) : this.options.resolver.default(node.name, "type"), void 0);
900
1079
  },
901
1080
  union(node) {
902
1081
  const members = node.members ?? [];
@@ -912,7 +1091,7 @@ const printerTs = _kubb_core.ast.definePrinter((options) => {
912
1091
  withParentheses: true
913
1092
  });
914
1093
  return this.transform(m);
915
- }).filter(Boolean)
1094
+ }).filter(isNonNullable)
916
1095
  }) ?? void 0;
917
1096
  return createUnionDeclaration({
918
1097
  withParentheses: true,
@@ -923,16 +1102,16 @@ const printerTs = _kubb_core.ast.definePrinter((options) => {
923
1102
  return createIntersectionDeclaration({
924
1103
  withParentheses: true,
925
1104
  nodes: buildMemberNodes(node.members, this.transform)
926
- }) ?? void 0;
1105
+ }) ?? null;
927
1106
  },
928
1107
  array(node) {
929
1108
  return createArrayDeclaration({
930
- nodes: (node.items ?? []).map((item) => this.transform(item)).filter(Boolean),
1109
+ nodes: (node.items ?? []).map((item) => this.transform(item)).filter(isNonNullable),
931
1110
  arrayType: this.options.arrayType
932
- }) ?? void 0;
1111
+ }) ?? null;
933
1112
  },
934
1113
  tuple(node) {
935
- return buildTupleNode(node, this.transform);
1114
+ return buildTupleNode(node, this.transform) ?? null;
936
1115
  },
937
1116
  object(node) {
938
1117
  const { transform, options } = this;
@@ -959,48 +1138,55 @@ const printerTs = _kubb_core.ast.definePrinter((options) => {
959
1138
  },
960
1139
  print(node) {
961
1140
  const { name, syntaxType = "type", description, keysToOmit } = this.options;
962
- let base = this.transform(node);
963
- if (!base) return null;
1141
+ const transformed = this.transform(node);
1142
+ if (!transformed) return null;
964
1143
  const meta = _kubb_core.ast.syncSchemaRef(node);
965
1144
  if (!name) {
966
- if (meta.nullable) base = createUnionDeclaration({ nodes: [base, keywordTypeNodes.null] });
967
- if ((meta.nullish || meta.optional) && addsUndefined) base = createUnionDeclaration({ nodes: [base, keywordTypeNodes.undefined] });
968
- return (0, _kubb_parser_ts.safePrint)(base);
1145
+ const withNullable = meta.nullable ? createUnionDeclaration({ nodes: [transformed, keywordTypeNodes.null] }) : transformed;
1146
+ const result = (meta.nullish || meta.optional) && addsUndefined ? createUnionDeclaration({ nodes: [withNullable, keywordTypeNodes.undefined] }) : withNullable;
1147
+ return _kubb_parser_ts.parserTs.print(result);
969
1148
  }
970
- let inner = keysToOmit?.length ? createOmitDeclaration({
971
- keys: keysToOmit,
972
- type: base,
973
- nonNullable: true
974
- }) : base;
975
- if (meta.nullable) inner = createUnionDeclaration({ nodes: [inner, keywordTypeNodes.null] });
976
- if (meta.nullish || meta.optional) inner = createUnionDeclaration({ nodes: [inner, keywordTypeNodes.undefined] });
977
- const useTypeGeneration = syntaxType === "type" || inner.kind === syntaxKind.union || !!keysToOmit?.length;
978
- return (0, _kubb_parser_ts.safePrint)(createTypeDeclaration({
1149
+ const inner = (() => {
1150
+ const omitted = keysToOmit?.length ? createOmitDeclaration({
1151
+ keys: keysToOmit,
1152
+ type: transformed,
1153
+ nonNullable: true
1154
+ }) : transformed;
1155
+ const withNullable = meta.nullable ? createUnionDeclaration({ nodes: [omitted, keywordTypeNodes.null] }) : omitted;
1156
+ return meta.nullish || meta.optional ? createUnionDeclaration({ nodes: [withNullable, keywordTypeNodes.undefined] }) : withNullable;
1157
+ })();
1158
+ const typeNode = createTypeDeclaration({
979
1159
  name,
980
1160
  isExportable: true,
981
1161
  type: inner,
982
- syntax: useTypeGeneration ? "type" : "interface",
1162
+ syntax: syntaxType === "type" || inner.kind === syntaxKind.union || !!keysToOmit?.length ? "type" : "interface",
983
1163
  comments: buildPropertyJSDocComments({
984
1164
  ...meta,
985
1165
  description
986
1166
  })
987
- }));
1167
+ });
1168
+ return _kubb_parser_ts.parserTs.print(typeNode);
988
1169
  }
989
1170
  };
990
1171
  });
991
1172
  //#endregion
992
1173
  //#region src/generators/typeGenerator.tsx
1174
+ /**
1175
+ * Built-in generator for `@kubb/plugin-ts`. Emits one TypeScript file per
1176
+ * schema in the spec plus per-operation request, response, and parameter
1177
+ * types. Drop-replace with a custom `Generator<PluginTs>` to change how
1178
+ * TypeScript output is produced.
1179
+ */
993
1180
  const typeGenerator = (0, _kubb_core.defineGenerator)({
994
1181
  name: "typescript",
995
1182
  renderer: _kubb_renderer_jsx.jsxRenderer,
996
1183
  schema(node, ctx) {
997
- const { enumType, enumTypeSuffix, enumKeyCasing, syntaxType, optionalType, arrayType, output, group, printer } = ctx.options;
1184
+ const { enum: enumOptions, syntaxType, optionalType, arrayType, output, group, printer } = ctx.options;
998
1185
  const { adapter, config, resolver, root } = ctx;
999
1186
  if (!node.name) return;
1000
- const mode = ctx.getMode(output);
1001
- const enumSchemaNames = new Set((adapter.inputNode?.schemas ?? []).filter((s) => _kubb_core.ast.narrowSchema(s, _kubb_core.ast.schemaTypes.enum) && s.name).map((s) => s.name));
1187
+ const enumSchemaNames = new Set(ctx.meta.enumNames);
1002
1188
  function resolveImportName(schemaName) {
1003
- if (ENUM_TYPES_WITH_KEY_SUFFIX.has(enumType) && enumTypeSuffix && enumSchemaNames.has(schemaName)) return resolver.resolveEnumKeyName({ name: schemaName }, enumTypeSuffix);
1189
+ if (ENUM_TYPES_WITH_KEY_SUFFIX.has(enumOptions.type) && enumOptions.typeSuffix && enumSchemaNames.has(schemaName)) return resolver.resolveEnumKeyName({ name: schemaName }, enumOptions.typeSuffix);
1004
1190
  return resolver.resolveTypeName(schemaName);
1005
1191
  }
1006
1192
  const imports = adapter.getImports(node, (schemaName) => ({
@@ -1011,26 +1197,25 @@ const typeGenerator = (0, _kubb_core.defineGenerator)({
1011
1197
  }, {
1012
1198
  root,
1013
1199
  output,
1014
- group
1200
+ group: group ?? void 0
1015
1201
  }).path
1016
1202
  }));
1017
1203
  const isEnumSchema = !!_kubb_core.ast.narrowSchema(node, _kubb_core.ast.schemaTypes.enum);
1018
1204
  const meta = {
1019
- name: ENUM_TYPES_WITH_KEY_SUFFIX.has(enumType) && isEnumSchema ? resolver.resolveEnumKeyName(node, enumTypeSuffix) : resolver.resolveTypeName(node.name),
1205
+ name: ENUM_TYPES_WITH_KEY_SUFFIX.has(enumOptions.type) && isEnumSchema ? resolver.resolveEnumKeyName(node, enumOptions.typeSuffix) : resolver.resolveTypeName(node.name),
1020
1206
  file: resolver.resolveFile({
1021
1207
  name: node.name,
1022
1208
  extname: ".ts"
1023
1209
  }, {
1024
1210
  root,
1025
1211
  output,
1026
- group
1212
+ group: group ?? void 0
1027
1213
  })
1028
1214
  };
1029
1215
  const schemaPrinter = printerTs({
1030
1216
  optionalType,
1031
1217
  arrayType,
1032
- enumType,
1033
- enumTypeSuffix,
1218
+ enum: enumOptions,
1034
1219
  name: meta.name,
1035
1220
  syntaxType,
1036
1221
  description: node.description,
@@ -1042,15 +1227,23 @@ const typeGenerator = (0, _kubb_core.defineGenerator)({
1042
1227
  baseName: meta.file.baseName,
1043
1228
  path: meta.file.path,
1044
1229
  meta: meta.file.meta,
1045
- banner: resolver.resolveBanner(adapter.inputNode, {
1230
+ banner: resolver.resolveBanner(ctx.meta, {
1046
1231
  output,
1047
- config
1232
+ config,
1233
+ file: {
1234
+ path: meta.file.path,
1235
+ baseName: meta.file.baseName
1236
+ }
1048
1237
  }),
1049
- footer: resolver.resolveFooter(adapter.inputNode, {
1238
+ footer: resolver.resolveFooter(ctx.meta, {
1050
1239
  output,
1051
- config
1240
+ config,
1241
+ file: {
1242
+ path: meta.file.path,
1243
+ baseName: meta.file.baseName
1244
+ }
1052
1245
  }),
1053
- children: [mode === "split" && imports.map((imp) => /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
1246
+ children: [imports.map((imp) => /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
1054
1247
  root: meta.file.path,
1055
1248
  path: imp.path,
1056
1249
  name: imp.name,
@@ -1062,18 +1255,15 @@ const typeGenerator = (0, _kubb_core.defineGenerator)({
1062
1255
  ].join("-"))), /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(Type, {
1063
1256
  name: meta.name,
1064
1257
  node,
1065
- enumType,
1066
- enumTypeSuffix,
1067
- enumKeyCasing,
1258
+ enum: enumOptions,
1068
1259
  resolver,
1069
1260
  printer: schemaPrinter
1070
1261
  })]
1071
1262
  });
1072
1263
  },
1073
1264
  operation(node, ctx) {
1074
- const { enumType, enumTypeSuffix, enumKeyCasing, optionalType, arrayType, syntaxType, paramsCasing, group, output, printer } = ctx.options;
1265
+ const { enum: enumOptions, optionalType, arrayType, syntaxType, paramsCasing, group, output, printer } = ctx.options;
1075
1266
  const { adapter, config, resolver, root } = ctx;
1076
- const mode = ctx.getMode(output);
1077
1267
  const params = _kubb_core.ast.caseParams(node.parameters, paramsCasing);
1078
1268
  const meta = { file: resolver.resolveFile({
1079
1269
  name: node.operationId,
@@ -1083,11 +1273,11 @@ const typeGenerator = (0, _kubb_core.defineGenerator)({
1083
1273
  }, {
1084
1274
  root,
1085
1275
  output,
1086
- group
1276
+ group: group ?? void 0
1087
1277
  }) };
1088
- const enumSchemaNames = new Set((adapter.inputNode?.schemas ?? []).filter((s) => _kubb_core.ast.narrowSchema(s, _kubb_core.ast.schemaTypes.enum) && s.name).map((s) => s.name));
1278
+ const enumSchemaNames = new Set(ctx.meta.enumNames);
1089
1279
  function resolveImportName(schemaName) {
1090
- if (ENUM_TYPES_WITH_KEY_SUFFIX.has(enumType) && enumTypeSuffix && enumSchemaNames.has(schemaName)) return resolver.resolveEnumKeyName({ name: schemaName }, enumTypeSuffix);
1280
+ if (ENUM_TYPES_WITH_KEY_SUFFIX.has(enumOptions.type) && enumOptions.typeSuffix && enumSchemaNames.has(schemaName)) return resolver.resolveEnumKeyName({ name: schemaName }, enumOptions.typeSuffix);
1091
1281
  return resolver.resolveTypeName(schemaName);
1092
1282
  }
1093
1283
  function renderSchemaType({ schema, name, keysToOmit }) {
@@ -1100,14 +1290,13 @@ const typeGenerator = (0, _kubb_core.defineGenerator)({
1100
1290
  }, {
1101
1291
  root,
1102
1292
  output,
1103
- group
1293
+ group: group ?? void 0
1104
1294
  }).path
1105
1295
  }));
1106
1296
  const schemaPrinter = printerTs({
1107
1297
  optionalType,
1108
1298
  arrayType,
1109
- enumType,
1110
- enumTypeSuffix,
1299
+ enum: enumOptions,
1111
1300
  name,
1112
1301
  syntaxType,
1113
1302
  description: schema.description,
@@ -1116,7 +1305,7 @@ const typeGenerator = (0, _kubb_core.defineGenerator)({
1116
1305
  enumSchemaNames,
1117
1306
  nodes: printer?.nodes
1118
1307
  });
1119
- return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [mode === "split" && imports.map((imp) => /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
1308
+ return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [imports.map((imp) => /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
1120
1309
  root: meta.file.path,
1121
1310
  path: imp.path,
1122
1311
  name: imp.name,
@@ -1128,30 +1317,68 @@ const typeGenerator = (0, _kubb_core.defineGenerator)({
1128
1317
  ].join("-"))), /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(Type, {
1129
1318
  name,
1130
1319
  node: schema,
1131
- enumType,
1132
- enumTypeSuffix,
1133
- enumKeyCasing,
1320
+ enum: enumOptions,
1134
1321
  resolver,
1135
1322
  printer: schemaPrinter
1136
1323
  })] });
1137
1324
  }
1325
+ /**
1326
+ * Emits an individual type per content type plus a union alias under `baseName`.
1327
+ * Shared by the request body and multi-content-type responses.
1328
+ */
1329
+ function buildContentTypeVariants(entries, baseName, decorate) {
1330
+ const variants = resolveContentTypeVariants(entries, baseName);
1331
+ const unionSchema = _kubb_core.ast.createSchema({
1332
+ type: "union",
1333
+ members: variants.map((variant) => _kubb_core.ast.createSchema({
1334
+ type: "ref",
1335
+ name: variant.name
1336
+ }))
1337
+ });
1338
+ return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [variants.map((variant) => renderSchemaType({
1339
+ schema: decorate ? decorate(variant.schema) : variant.schema,
1340
+ name: variant.name,
1341
+ keysToOmit: variant.keysToOmit
1342
+ })), renderSchemaType({
1343
+ schema: unionSchema,
1344
+ name: baseName
1345
+ })] });
1346
+ }
1138
1347
  const paramTypes = params.map((param) => renderSchemaType({
1139
1348
  schema: param.schema,
1140
1349
  name: resolver.resolveParamName(node, param)
1141
1350
  }));
1142
- const requestType = node.requestBody?.content?.[0]?.schema ? renderSchemaType({
1143
- schema: {
1144
- ...node.requestBody.content[0].schema,
1145
- description: node.requestBody.description ?? node.requestBody.content[0].schema.description
1146
- },
1147
- name: resolver.resolveDataName(node),
1148
- keysToOmit: node.requestBody.content[0].keysToOmit
1149
- }) : null;
1150
- const responseTypes = node.responses.map((res) => renderSchemaType({
1151
- schema: res.schema,
1152
- name: resolver.resolveResponseStatusName(node, res.statusCode),
1153
- keysToOmit: res.keysToOmit
1154
- }));
1351
+ const requestBodyContent = node.requestBody?.content ?? [];
1352
+ function buildRequestType() {
1353
+ if (requestBodyContent.length === 0) return null;
1354
+ if (requestBodyContent.length === 1) {
1355
+ const entry = requestBodyContent[0];
1356
+ if (!entry.schema) return null;
1357
+ return renderSchemaType({
1358
+ schema: {
1359
+ ...entry.schema,
1360
+ description: node.requestBody.description ?? entry.schema.description
1361
+ },
1362
+ name: resolver.resolveDataName(node),
1363
+ keysToOmit: entry.keysToOmit
1364
+ });
1365
+ }
1366
+ return buildContentTypeVariants(requestBodyContent, resolver.resolveDataName(node), (schema) => ({
1367
+ ...schema,
1368
+ description: node.requestBody.description ?? schema.description
1369
+ }));
1370
+ }
1371
+ const requestType = buildRequestType();
1372
+ const responseTypes = node.responses.map((res) => {
1373
+ const variants = (res.content ?? []).filter((entry) => entry.schema);
1374
+ if (variants.length > 1) return buildContentTypeVariants(variants, resolver.resolveResponseStatusName(node, res.statusCode));
1375
+ const primary = variants[0] ?? res.content?.[0];
1376
+ return renderSchemaType({
1377
+ schema: primary?.schema ?? null,
1378
+ name: resolver.resolveResponseStatusName(node, res.statusCode),
1379
+ keysToOmit: primary?.keysToOmit
1380
+ });
1381
+ });
1155
1382
  const dataType = renderSchemaType({
1156
1383
  schema: buildData({
1157
1384
  ...node,
@@ -1163,14 +1390,15 @@ const typeGenerator = (0, _kubb_core.defineGenerator)({
1163
1390
  schema: buildResponses(node, { resolver }),
1164
1391
  name: resolver.resolveResponsesName(node)
1165
1392
  });
1166
- const responseType = (() => {
1167
- if (!node.responses.some((res) => res.schema)) return null;
1393
+ function buildResponseType() {
1394
+ const hasSchema = (res) => (res.content ?? []).some((entry) => entry.schema);
1395
+ if (!node.responses.some(hasSchema)) return null;
1168
1396
  const responseName = resolver.resolveResponseName(node);
1169
- const responsesWithSchema = node.responses.filter((res) => res.schema);
1170
- if (new Set(responsesWithSchema.flatMap((res) => res.schema ? adapter.getImports(res.schema, (schemaName) => ({
1397
+ const responsesWithSchema = node.responses.filter(hasSchema);
1398
+ if (new Set(responsesWithSchema.flatMap((res) => (res.content ?? []).flatMap((entry) => entry.schema ? adapter.getImports(entry.schema, (schemaName) => ({
1171
1399
  name: resolveImportName(schemaName),
1172
1400
  path: ""
1173
- })).flatMap((imp) => Array.isArray(imp.name) ? imp.name : [imp.name]) : [])).has(responseName)) return null;
1401
+ })).flatMap((imp) => Array.isArray(imp.name) ? imp.name : [imp.name]) : []))).has(responseName)) return null;
1174
1402
  return renderSchemaType({
1175
1403
  schema: {
1176
1404
  ...buildResponseUnion(node, { resolver }),
@@ -1178,18 +1406,27 @@ const typeGenerator = (0, _kubb_core.defineGenerator)({
1178
1406
  },
1179
1407
  name: responseName
1180
1408
  });
1181
- })();
1409
+ }
1410
+ const responseType = buildResponseType();
1182
1411
  return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.File, {
1183
1412
  baseName: meta.file.baseName,
1184
1413
  path: meta.file.path,
1185
1414
  meta: meta.file.meta,
1186
- banner: resolver.resolveBanner(adapter.inputNode, {
1415
+ banner: resolver.resolveBanner(ctx.meta, {
1187
1416
  output,
1188
- config
1417
+ config,
1418
+ file: {
1419
+ path: meta.file.path,
1420
+ baseName: meta.file.baseName
1421
+ }
1189
1422
  }),
1190
- footer: resolver.resolveFooter(adapter.inputNode, {
1423
+ footer: resolver.resolveFooter(ctx.meta, {
1191
1424
  output,
1192
- config
1425
+ config,
1426
+ file: {
1427
+ path: meta.file.path,
1428
+ baseName: meta.file.baseName
1429
+ }
1193
1430
  }),
1194
1431
  children: [
1195
1432
  paramTypes,
@@ -1205,101 +1442,113 @@ const typeGenerator = (0, _kubb_core.defineGenerator)({
1205
1442
  //#endregion
1206
1443
  //#region src/resolvers/resolverTs.ts
1207
1444
  /**
1208
- * Resolver for `@kubb/plugin-ts` that provides the default naming and path-resolution
1209
- * helpers used by the plugin. Import this in other plugins to resolve the exact names and
1210
- * paths that `plugin-ts` generates without hardcoding the conventions.
1445
+ * Default resolver used by `@kubb/plugin-ts`. Decides the names and file paths
1446
+ * for every generated TypeScript type. Import this in other plugins that need
1447
+ * to reference the exact names `plugin-ts` produces without duplicating the
1448
+ * casing/file-layout rules.
1211
1449
  *
1212
- * The `default` method is automatically injected by `defineResolver` it uses `camelCase`
1213
- * for identifiers/files and `pascalCase` for type names.
1450
+ * The `default` method is supplied by `defineResolver`. It uses PascalCase for
1451
+ * type names and PascalCase file paths (dotted names become `/`-joined) for files.
1214
1452
  *
1215
- * @example
1453
+ * @example Resolve a type and file name
1216
1454
  * ```ts
1217
- * import { resolver } from '@kubb/plugin-ts'
1455
+ * import { resolverTs } from '@kubb/plugin-ts'
1218
1456
  *
1219
- * resolver.default('list pets', 'type') // 'ListPets'
1220
- * resolver.resolveName('list pets status 200') // 'ListPetsStatus200'
1221
- * resolver.resolvePathName('list pets', 'file') // 'listPets'
1457
+ * resolverTs.default('list pets', 'type') // 'ListPets'
1458
+ * resolverTs.resolvePathName('list pets', 'file') // 'ListPets'
1459
+ * resolverTs.resolveResponseStatusName(node, 200) // 'ListPetsStatus200'
1222
1460
  * ```
1223
1461
  */
1224
- const resolverTs = (0, _kubb_core.defineResolver)((ctx) => {
1462
+ const resolverTs = (0, _kubb_core.defineResolver)(() => {
1225
1463
  return {
1226
1464
  name: "default",
1227
1465
  pluginName: "plugin-ts",
1228
1466
  default(name, type) {
1229
- return pascalCase(name, { isFile: type === "file" });
1467
+ if (type === "file") return toFilePath(name, pascalCase);
1468
+ return ensureValidVarName(pascalCase(name));
1230
1469
  },
1231
1470
  resolveTypeName(name) {
1232
- return pascalCase(name);
1471
+ return ensureValidVarName(pascalCase(name));
1233
1472
  },
1234
1473
  resolvePathName(name, type) {
1235
- return pascalCase(name, { isFile: type === "file" });
1474
+ if (type === "file") return toFilePath(name, pascalCase);
1475
+ return ensureValidVarName(pascalCase(name));
1236
1476
  },
1237
1477
  resolveParamName(node, param) {
1238
- return ctx.resolveTypeName(`${node.operationId} ${param.in} ${param.name}`);
1478
+ return this.resolveTypeName(`${node.operationId} ${param.in} ${param.name}`);
1239
1479
  },
1240
1480
  resolveResponseStatusName(node, statusCode) {
1241
- return ctx.resolveTypeName(`${node.operationId} Status ${statusCode}`);
1481
+ return this.resolveTypeName(`${node.operationId} Status ${statusCode}`);
1242
1482
  },
1243
1483
  resolveDataName(node) {
1244
- return ctx.resolveTypeName(`${node.operationId} Data`);
1484
+ return this.resolveTypeName(`${node.operationId} Data`);
1245
1485
  },
1246
1486
  resolveRequestConfigName(node) {
1247
- return ctx.resolveTypeName(`${node.operationId} RequestConfig`);
1487
+ return this.resolveTypeName(`${node.operationId} RequestConfig`);
1248
1488
  },
1249
1489
  resolveResponsesName(node) {
1250
- return ctx.resolveTypeName(`${node.operationId} Responses`);
1490
+ return this.resolveTypeName(`${node.operationId} Responses`);
1251
1491
  },
1252
1492
  resolveResponseName(node) {
1253
- return ctx.resolveTypeName(`${node.operationId} Response`);
1493
+ return this.resolveTypeName(`${node.operationId} Response`);
1254
1494
  },
1255
1495
  resolveEnumKeyName(node, enumTypeSuffix = "key") {
1256
- return `${ctx.resolveTypeName(node.name ?? "")}${enumTypeSuffix}`;
1496
+ return `${this.resolveTypeName(node.name ?? "")}${enumTypeSuffix}`;
1257
1497
  },
1258
1498
  resolvePathParamsName(node, param) {
1259
- return ctx.resolveParamName(node, param);
1499
+ return this.resolveParamName(node, param);
1260
1500
  },
1261
1501
  resolveQueryParamsName(node, param) {
1262
- return ctx.resolveParamName(node, param);
1502
+ return this.resolveParamName(node, param);
1263
1503
  },
1264
1504
  resolveHeaderParamsName(node, param) {
1265
- return ctx.resolveParamName(node, param);
1505
+ return this.resolveParamName(node, param);
1266
1506
  }
1267
1507
  };
1268
1508
  });
1269
1509
  //#endregion
1270
1510
  //#region src/plugin.ts
1271
1511
  /**
1272
- * Canonical plugin name for `@kubb/plugin-ts`, used to identify the plugin in driver lookups and warnings.
1512
+ * Canonical plugin name for `@kubb/plugin-ts`. Used for driver lookups and
1513
+ * cross-plugin dependency references.
1273
1514
  */
1274
1515
  const pluginTsName = "plugin-ts";
1275
1516
  /**
1276
- * The `@kubb/plugin-ts` plugin factory.
1277
- *
1278
- * Generates TypeScript type declarations from an OpenAPI/AST `RootNode`.
1279
- * Walks schemas and operations, delegates rendering to the active generators,
1280
- * and writes barrel files based on `output.barrelType`.
1517
+ * Generates TypeScript `type` aliases and `interface` declarations from an
1518
+ * OpenAPI spec. The foundation that every other Kubb plugin builds on:
1519
+ * clients, query hooks, mocks, and validators all reference the names this
1520
+ * plugin produces.
1281
1521
  *
1282
1522
  * @example
1283
1523
  * ```ts
1284
- * import pluginTs from '@kubb/plugin-ts'
1524
+ * import { defineConfig } from 'kubb'
1525
+ * import { pluginTs } from '@kubb/plugin-ts'
1285
1526
  *
1286
1527
  * export default defineConfig({
1287
- * plugins: [pluginTs({ output: { path: 'types' }, enumType: 'asConst' })],
1528
+ * input: { path: './petStore.yaml' },
1529
+ * output: { path: './src/gen' },
1530
+ * plugins: [
1531
+ * pluginTs({
1532
+ * output: { path: './types' },
1533
+ * enum: { type: 'asConst' },
1534
+ * optionalType: 'questionTokenAndUndefined',
1535
+ * }),
1536
+ * ],
1288
1537
  * })
1289
1538
  * ```
1290
1539
  */
1291
1540
  const pluginTs = (0, _kubb_core.definePlugin)((options) => {
1292
1541
  const { output = {
1293
1542
  path: "types",
1294
- barrelType: "named"
1295
- }, group, exclude = [], include, override = [], enumType = "asConst", enumTypeSuffix = "Key", enumKeyCasing = "none", optionalType = "questionToken", arrayType = "array", syntaxType = "type", paramsCasing, printer, resolver: userResolver, transformer: userTransformer, generators: userGenerators = [] } = options;
1296
- const groupConfig = group ? {
1297
- ...group,
1298
- name: (ctx) => {
1299
- if (group.type === "path") return `${ctx.group.split("/")[1]}`;
1300
- return `${camelCase(ctx.group)}Controller`;
1301
- }
1302
- } : void 0;
1543
+ barrel: { type: "named" }
1544
+ }, group, exclude = [], include, override = [], enum: enumOptions = {}, optionalType = "questionToken", arrayType = "array", syntaxType = "type", paramsCasing, printer, resolver: userResolver, transformer: userTransformer, generators: userGenerators = [] } = options;
1545
+ const groupConfig = createGroupConfig(group);
1546
+ const resolvedEnum = {
1547
+ type: enumOptions.type ?? "asConst",
1548
+ constCasing: enumOptions.constCasing ?? "camelCase",
1549
+ typeSuffix: enumOptions.typeSuffix ?? "Key",
1550
+ keyCasing: enumOptions.keyCasing ?? "none"
1551
+ };
1303
1552
  return {
1304
1553
  name: pluginTsName,
1305
1554
  options,
@@ -1312,9 +1561,7 @@ const pluginTs = (0, _kubb_core.definePlugin)((options) => {
1312
1561
  optionalType,
1313
1562
  group: groupConfig,
1314
1563
  arrayType,
1315
- enumType,
1316
- enumTypeSuffix,
1317
- enumKeyCasing,
1564
+ enum: resolvedEnum,
1318
1565
  syntaxType,
1319
1566
  paramsCasing,
1320
1567
  printer
@@ -1354,10 +1601,10 @@ function rank(param) {
1354
1601
  return param.optional ? PARAM_RANK.optional : PARAM_RANK.required;
1355
1602
  }
1356
1603
  function sortParams(params) {
1357
- return [...params].sort((a, b) => rank(a) - rank(b));
1604
+ return params.toSorted((a, b) => rank(a) - rank(b));
1358
1605
  }
1359
1606
  function sortChildParams(params) {
1360
- return [...params].sort((a, b) => rank(a) - rank(b));
1607
+ return params.toSorted((a, b) => rank(a) - rank(b));
1361
1608
  }
1362
1609
  /**
1363
1610
  * Default function-signature printer.