@kubb/plugin-ts 5.0.0-alpha.22 → 5.0.0-alpha.23

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 (66) hide show
  1. package/dist/index.cjs +1668 -49
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.ts +466 -4
  4. package/dist/index.js +1641 -52
  5. package/dist/index.js.map +1 -1
  6. package/package.json +3 -42
  7. package/src/components/Enum.tsx +1 -1
  8. package/src/components/Type.tsx +3 -5
  9. package/src/generators/typeGenerator.tsx +10 -22
  10. package/src/generators/typeGeneratorLegacy.tsx +28 -38
  11. package/src/index.ts +13 -1
  12. package/src/plugin.ts +42 -23
  13. package/src/presets.ts +16 -34
  14. package/src/printers/functionPrinter.ts +194 -0
  15. package/src/printers/printerTs.ts +6 -6
  16. package/src/resolvers/resolverTs.ts +10 -47
  17. package/src/resolvers/resolverTsLegacy.ts +4 -31
  18. package/src/types.ts +85 -225
  19. package/src/utils.ts +103 -0
  20. package/dist/Type-Bf8raoQX.cjs +0 -124
  21. package/dist/Type-Bf8raoQX.cjs.map +0 -1
  22. package/dist/Type-BpXxT4l_.js +0 -113
  23. package/dist/Type-BpXxT4l_.js.map +0 -1
  24. package/dist/builderTs-COUg3xtQ.cjs +0 -135
  25. package/dist/builderTs-COUg3xtQ.cjs.map +0 -1
  26. package/dist/builderTs-DPpkJKd1.js +0 -131
  27. package/dist/builderTs-DPpkJKd1.js.map +0 -1
  28. package/dist/builders.cjs +0 -3
  29. package/dist/builders.d.ts +0 -23
  30. package/dist/builders.js +0 -2
  31. package/dist/casing-BJHFg-zZ.js +0 -84
  32. package/dist/casing-BJHFg-zZ.js.map +0 -1
  33. package/dist/casing-DHfdqpLi.cjs +0 -107
  34. package/dist/casing-DHfdqpLi.cjs.map +0 -1
  35. package/dist/chunk-ByKO4r7w.cjs +0 -38
  36. package/dist/components.cjs +0 -4
  37. package/dist/components.d.ts +0 -71
  38. package/dist/components.js +0 -2
  39. package/dist/generators-DFDut8o-.js +0 -555
  40. package/dist/generators-DFDut8o-.js.map +0 -1
  41. package/dist/generators-DKd7MYbx.cjs +0 -567
  42. package/dist/generators-DKd7MYbx.cjs.map +0 -1
  43. package/dist/generators.cjs +0 -4
  44. package/dist/generators.d.ts +0 -12
  45. package/dist/generators.js +0 -2
  46. package/dist/printerTs-BcHudagv.cjs +0 -594
  47. package/dist/printerTs-BcHudagv.cjs.map +0 -1
  48. package/dist/printerTs-CMBCOuqd.js +0 -558
  49. package/dist/printerTs-CMBCOuqd.js.map +0 -1
  50. package/dist/printers.cjs +0 -3
  51. package/dist/printers.d.ts +0 -81
  52. package/dist/printers.js +0 -2
  53. package/dist/resolverTsLegacy-CPiqqsO6.js +0 -185
  54. package/dist/resolverTsLegacy-CPiqqsO6.js.map +0 -1
  55. package/dist/resolverTsLegacy-CuR9XbKk.cjs +0 -196
  56. package/dist/resolverTsLegacy-CuR9XbKk.cjs.map +0 -1
  57. package/dist/resolvers.cjs +0 -4
  58. package/dist/resolvers.d.ts +0 -52
  59. package/dist/resolvers.js +0 -2
  60. package/dist/types-CRtcZOCz.d.ts +0 -374
  61. package/src/builders/builderTs.ts +0 -107
  62. package/src/builders/index.ts +0 -1
  63. package/src/components/index.ts +0 -2
  64. package/src/generators/index.ts +0 -2
  65. package/src/printers/index.ts +0 -1
  66. package/src/resolvers/index.ts +0 -2
package/dist/index.js CHANGED
@@ -1,47 +1,1515 @@
1
- import { t as __name } from "./chunk--u3MIqq1.js";
2
- import { n as typeGenerator, t as typeGeneratorLegacy } from "./generators-DFDut8o-.js";
3
- import { n as resolverTs, t as resolverTsLegacy } from "./resolverTsLegacy-CPiqqsO6.js";
1
+ import "./chunk--u3MIqq1.js";
4
2
  import path from "node:path";
5
- import { walk } from "@kubb/ast";
6
- import { createPlugin, definePreset, definePresets, getBarrelFiles, getPreset, renderOperation, renderSchema } from "@kubb/core";
7
- //#region src/presets.ts
3
+ import { safePrint } from "@kubb/fabric-core/parsers/typescript";
4
+ import { File } from "@kubb/react-fabric";
5
+ import { isNumber } from "remeda";
6
+ import ts from "typescript";
7
+ import { Fragment, jsx, jsxs } from "@kubb/react-fabric/jsx-runtime";
8
+ import { caseParams, collect, composeTransformers, createPrinterFactory, createProperty, createSchema, isStringType, narrowSchema, schemaTypes, transform, walk } from "@kubb/ast";
9
+ import { createPlugin, defineGenerator, definePresets, definePrinter, defineResolver, getBarrelFiles, getMode, getPreset, renderOperation, renderSchema } from "@kubb/core";
10
+ //#region ../../internals/utils/src/casing.ts
8
11
  /**
9
- * Built-in preset registry for `@kubb/plugin-ts`.
12
+ * Shared implementation for camelCase and PascalCase conversion.
13
+ * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)
14
+ * and capitalizes each word according to `pascal`.
10
15
  *
11
- * - `default` uses `resolverTs` and `typeGenerator` (current naming conventions).
12
- * - `kubbV4` — uses `resolverTsLegacy` and `typeGeneratorLegacy` (Kubb v4 naming conventions).
16
+ * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
13
17
  */
14
- const presets = definePresets({
15
- default: definePreset("default", {
16
- resolvers: [resolverTs],
17
- generators: [typeGenerator]
18
- }),
19
- kubbV4: definePreset("kubbV4", {
20
- resolvers: [resolverTsLegacy],
21
- generators: [typeGeneratorLegacy]
22
- })
18
+ function toCamelOrPascal(text, pascal) {
19
+ 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) => {
20
+ if (word.length > 1 && word === word.toUpperCase()) return word;
21
+ if (i === 0 && !pascal) return word.charAt(0).toLowerCase() + word.slice(1);
22
+ return word.charAt(0).toUpperCase() + word.slice(1);
23
+ }).join("").replace(/[^a-zA-Z0-9]/g, "");
24
+ }
25
+ /**
26
+ * Splits `text` on `.` and applies `transformPart` to each segment.
27
+ * The last segment receives `isLast = true`, all earlier segments receive `false`.
28
+ * Segments are joined with `/` to form a file path.
29
+ *
30
+ * Only splits on dots followed by a letter so that version numbers
31
+ * embedded in operationIds (e.g. `v2025.0`) are kept intact.
32
+ */
33
+ function applyToFileParts(text, transformPart) {
34
+ const parts = text.split(/\.(?=[a-zA-Z])/);
35
+ return parts.map((part, i) => transformPart(part, i === parts.length - 1)).join("/");
36
+ }
37
+ /**
38
+ * Converts `text` to camelCase.
39
+ * When `isFile` is `true`, dot-separated segments are each cased independently and joined with `/`.
40
+ *
41
+ * @example
42
+ * camelCase('hello-world') // 'helloWorld'
43
+ * camelCase('pet.petId', { isFile: true }) // 'pet/petId'
44
+ */
45
+ function camelCase(text, { isFile, prefix = "", suffix = "" } = {}) {
46
+ if (isFile) return applyToFileParts(text, (part, isLast) => camelCase(part, isLast ? {
47
+ prefix,
48
+ suffix
49
+ } : {}));
50
+ return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
51
+ }
52
+ /**
53
+ * Converts `text` to PascalCase.
54
+ * When `isFile` is `true`, the last dot-separated segment is PascalCased and earlier segments are camelCased.
55
+ *
56
+ * @example
57
+ * pascalCase('hello-world') // 'HelloWorld'
58
+ * pascalCase('pet.petId', { isFile: true }) // 'pet/PetId'
59
+ */
60
+ function pascalCase(text, { isFile, prefix = "", suffix = "" } = {}) {
61
+ if (isFile) return applyToFileParts(text, (part, isLast) => isLast ? pascalCase(part, {
62
+ prefix,
63
+ suffix
64
+ }) : camelCase(part));
65
+ return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true);
66
+ }
67
+ /**
68
+ * Converts `text` to snake_case.
69
+ *
70
+ * @example
71
+ * snakeCase('helloWorld') // 'hello_world'
72
+ * snakeCase('Hello-World') // 'hello_world'
73
+ */
74
+ function snakeCase(text, { prefix = "", suffix = "" } = {}) {
75
+ 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("_");
76
+ }
77
+ /**
78
+ * Converts `text` to SCREAMING_SNAKE_CASE.
79
+ *
80
+ * @example
81
+ * screamingSnakeCase('helloWorld') // 'HELLO_WORLD'
82
+ */
83
+ function screamingSnakeCase(text, { prefix = "", suffix = "" } = {}) {
84
+ return snakeCase(text, {
85
+ prefix,
86
+ suffix
87
+ }).toUpperCase();
88
+ }
89
+ //#endregion
90
+ //#region ../../internals/utils/src/string.ts
91
+ /**
92
+ * Strips a single matching pair of `"..."`, `'...'`, or `` `...` `` from both ends of `text`.
93
+ * Returns the string unchanged when no balanced quote pair is found.
94
+ *
95
+ * @example
96
+ * trimQuotes('"hello"') // 'hello'
97
+ * trimQuotes('hello') // 'hello'
98
+ */
99
+ function trimQuotes(text) {
100
+ if (text.length >= 2) {
101
+ const first = text[0];
102
+ const last = text[text.length - 1];
103
+ if (first === "\"" && last === "\"" || first === "'" && last === "'" || first === "`" && last === "`") return text.slice(1, -1);
104
+ }
105
+ return text;
106
+ }
107
+ /**
108
+ * Escapes characters that are not allowed inside JS string literals.
109
+ * Handles quotes, backslashes, and Unicode line terminators (U+2028 / U+2029).
110
+ *
111
+ * @see http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.4
112
+ *
113
+ * @example
114
+ * ```ts
115
+ * jsStringEscape('say "hi"\nbye') // 'say \\"hi\\"\\nbye'
116
+ * ```
117
+ */
118
+ function jsStringEscape(input) {
119
+ return `${input}`.replace(/["'\\\n\r\u2028\u2029]/g, (character) => {
120
+ switch (character) {
121
+ case "\"":
122
+ case "'":
123
+ case "\\": return `\\${character}`;
124
+ case "\n": return "\\n";
125
+ case "\r": return "\\r";
126
+ case "\u2028": return "\\u2028";
127
+ case "\u2029": return "\\u2029";
128
+ default: return "";
129
+ }
130
+ });
131
+ }
132
+ //#endregion
133
+ //#region ../../internals/utils/src/object.ts
134
+ /**
135
+ * Serializes a primitive value to a JSON string literal, stripping any surrounding quote characters first.
136
+ *
137
+ * @example
138
+ * stringify('hello') // '"hello"'
139
+ * stringify('"hello"') // '"hello"'
140
+ */
141
+ function stringify(value) {
142
+ if (value === void 0 || value === null) return "\"\"";
143
+ return JSON.stringify(trimQuotes(value.toString()));
144
+ }
145
+ //#endregion
146
+ //#region src/constants.ts
147
+ /**
148
+ * `optionalType` values that cause a property's type to include `| undefined`.
149
+ */
150
+ const OPTIONAL_ADDS_UNDEFINED = new Set(["undefined", "questionTokenAndUndefined"]);
151
+ /**
152
+ * `optionalType` values that render the property key with a `?` token.
153
+ */
154
+ const OPTIONAL_ADDS_QUESTION_TOKEN = new Set(["questionToken", "questionTokenAndUndefined"]);
155
+ /**
156
+ * `enumType` values that append a `Key` suffix to the generated enum type alias.
157
+ */
158
+ const ENUM_TYPES_WITH_KEY_SUFFIX = new Set(["asConst", "asPascalConst"]);
159
+ /**
160
+ * `enumType` values that require a runtime value declaration (object, enum, or literal).
161
+ */
162
+ const ENUM_TYPES_WITH_RUNTIME_VALUE = new Set([
163
+ "enum",
164
+ "asConst",
165
+ "asPascalConst",
166
+ "constEnum",
167
+ "literal",
168
+ void 0
169
+ ]);
170
+ /**
171
+ * `enumType` values whose type declaration is type-only (no runtime value emitted for the type alias).
172
+ */
173
+ const ENUM_TYPES_WITH_TYPE_ONLY = new Set([
174
+ "asConst",
175
+ "asPascalConst",
176
+ "literal",
177
+ void 0
178
+ ]);
179
+ //#endregion
180
+ //#region src/factory.ts
181
+ const { SyntaxKind, factory } = ts;
182
+ const modifiers = {
183
+ async: factory.createModifier(ts.SyntaxKind.AsyncKeyword),
184
+ export: factory.createModifier(ts.SyntaxKind.ExportKeyword),
185
+ const: factory.createModifier(ts.SyntaxKind.ConstKeyword),
186
+ static: factory.createModifier(ts.SyntaxKind.StaticKeyword)
187
+ };
188
+ const syntaxKind = {
189
+ union: SyntaxKind.UnionType,
190
+ literalType: SyntaxKind.LiteralType,
191
+ stringLiteral: SyntaxKind.StringLiteral
192
+ };
193
+ function isValidIdentifier(str) {
194
+ if (!str.length || str.trim() !== str) return false;
195
+ const node = ts.parseIsolatedEntityName(str, ts.ScriptTarget.Latest);
196
+ return !!node && node.kind === ts.SyntaxKind.Identifier && ts.identifierToKeywordKind(node.kind) === void 0;
197
+ }
198
+ function propertyName(name) {
199
+ if (typeof name === "string") return isValidIdentifier(name) ? factory.createIdentifier(name) : factory.createStringLiteral(name);
200
+ return name;
201
+ }
202
+ const questionToken = factory.createToken(ts.SyntaxKind.QuestionToken);
203
+ function createQuestionToken(token) {
204
+ if (!token) return;
205
+ if (token === true) return questionToken;
206
+ return token;
207
+ }
208
+ function createIntersectionDeclaration({ nodes, withParentheses }) {
209
+ if (!nodes.length) return null;
210
+ if (nodes.length === 1) return nodes[0] || null;
211
+ const node = factory.createIntersectionTypeNode(nodes);
212
+ if (withParentheses) return factory.createParenthesizedType(node);
213
+ return node;
214
+ }
215
+ function createArrayDeclaration({ nodes, arrayType = "array" }) {
216
+ if (!nodes.length) return factory.createTupleTypeNode([]);
217
+ if (nodes.length === 1) {
218
+ const node = nodes[0];
219
+ if (!node) return null;
220
+ if (arrayType === "generic") return factory.createTypeReferenceNode(factory.createIdentifier("Array"), [node]);
221
+ return factory.createArrayTypeNode(node);
222
+ }
223
+ const unionType = factory.createUnionTypeNode(nodes);
224
+ if (arrayType === "generic") return factory.createTypeReferenceNode(factory.createIdentifier("Array"), [unionType]);
225
+ return factory.createArrayTypeNode(factory.createParenthesizedType(unionType));
226
+ }
227
+ /**
228
+ * Minimum nodes length of 2
229
+ * @example `string | number`
230
+ */
231
+ function createUnionDeclaration({ nodes, withParentheses }) {
232
+ if (!nodes.length) return keywordTypeNodes.any;
233
+ if (nodes.length === 1) return nodes[0];
234
+ const node = factory.createUnionTypeNode(nodes);
235
+ if (withParentheses) return factory.createParenthesizedType(node);
236
+ return node;
237
+ }
238
+ function createPropertySignature({ readOnly, modifiers = [], name, questionToken, type }) {
239
+ return factory.createPropertySignature([...modifiers, readOnly ? factory.createToken(ts.SyntaxKind.ReadonlyKeyword) : void 0].filter(Boolean), propertyName(name), createQuestionToken(questionToken), type);
240
+ }
241
+ function createParameterSignature(name, { modifiers, dotDotDotToken, questionToken, type, initializer }) {
242
+ return factory.createParameterDeclaration(modifiers, dotDotDotToken, name, createQuestionToken(questionToken), type, initializer);
243
+ }
244
+ /**
245
+ * @link https://github.com/microsoft/TypeScript/issues/44151
246
+ */
247
+ function appendJSDocToNode({ node, comments }) {
248
+ const filteredComments = comments.filter(Boolean);
249
+ if (!filteredComments.length) return node;
250
+ const text = filteredComments.reduce((acc = "", comment = "") => {
251
+ return `${acc}\n * ${comment.replaceAll("*/", "*\\/")}`;
252
+ }, "*");
253
+ return ts.addSyntheticLeadingComment(node, ts.SyntaxKind.MultiLineCommentTrivia, `${text || "*"}\n`, true);
254
+ }
255
+ function createIndexSignature(type, { modifiers, indexName = "key", indexType = factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword) } = {}) {
256
+ return factory.createIndexSignature(modifiers, [createParameterSignature(indexName, { type: indexType })], type);
257
+ }
258
+ function createTypeAliasDeclaration({ modifiers, name, typeParameters, type }) {
259
+ return factory.createTypeAliasDeclaration(modifiers, name, typeParameters, type);
260
+ }
261
+ function createInterfaceDeclaration({ modifiers, name, typeParameters, members }) {
262
+ return factory.createInterfaceDeclaration(modifiers, name, typeParameters, void 0, members);
263
+ }
264
+ function createTypeDeclaration({ syntax, isExportable, comments, name, type }) {
265
+ if (syntax === "interface" && "members" in type) return appendJSDocToNode({
266
+ node: createInterfaceDeclaration({
267
+ members: type.members,
268
+ modifiers: isExportable ? [modifiers.export] : [],
269
+ name,
270
+ typeParameters: void 0
271
+ }),
272
+ comments
273
+ });
274
+ return appendJSDocToNode({
275
+ node: createTypeAliasDeclaration({
276
+ type,
277
+ modifiers: isExportable ? [modifiers.export] : [],
278
+ name,
279
+ typeParameters: void 0
280
+ }),
281
+ comments
282
+ });
283
+ }
284
+ /**
285
+ * Apply casing transformation to enum keys
286
+ */
287
+ function applyEnumKeyCasing(key, casing = "none") {
288
+ if (casing === "none") return key;
289
+ if (casing === "screamingSnakeCase") return screamingSnakeCase(key);
290
+ if (casing === "snakeCase") return snakeCase(key);
291
+ if (casing === "pascalCase") return pascalCase(key);
292
+ if (casing === "camelCase") return camelCase(key);
293
+ return key;
294
+ }
295
+ function createEnumDeclaration({ type = "enum", name, typeName, enums, enumKeyCasing = "none" }) {
296
+ if (type === "literal" || type === "inlineLiteral") return [void 0, factory.createTypeAliasDeclaration([factory.createToken(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier(typeName), void 0, factory.createUnionTypeNode(enums.map(([_key, value]) => {
297
+ if (isNumber(value)) {
298
+ if (value < 0) return factory.createLiteralTypeNode(factory.createPrefixUnaryExpression(ts.SyntaxKind.MinusToken, factory.createNumericLiteral(Math.abs(value))));
299
+ return factory.createLiteralTypeNode(factory.createNumericLiteral(value?.toString()));
300
+ }
301
+ if (typeof value === "boolean") return factory.createLiteralTypeNode(value ? factory.createTrue() : factory.createFalse());
302
+ if (value) return factory.createLiteralTypeNode(factory.createStringLiteral(value.toString()));
303
+ }).filter(Boolean)))];
304
+ if (type === "enum" || type === "constEnum") return [void 0, factory.createEnumDeclaration([factory.createToken(ts.SyntaxKind.ExportKeyword), type === "constEnum" ? factory.createToken(ts.SyntaxKind.ConstKeyword) : void 0].filter(Boolean), factory.createIdentifier(typeName), enums.map(([key, value]) => {
305
+ let initializer = factory.createStringLiteral(value?.toString());
306
+ if (Number.parseInt(value.toString(), 10) === value && isNumber(Number.parseInt(value.toString(), 10))) if (value < 0) initializer = factory.createPrefixUnaryExpression(ts.SyntaxKind.MinusToken, factory.createNumericLiteral(Math.abs(value)));
307
+ else initializer = factory.createNumericLiteral(value);
308
+ if (typeof value === "boolean") initializer = value ? factory.createTrue() : factory.createFalse();
309
+ if (isNumber(Number.parseInt(key.toString(), 10))) {
310
+ const casingKey = applyEnumKeyCasing(`${typeName}_${key}`, enumKeyCasing);
311
+ return factory.createEnumMember(propertyName(casingKey), initializer);
312
+ }
313
+ if (key) {
314
+ const casingKey = applyEnumKeyCasing(key.toString(), enumKeyCasing);
315
+ return factory.createEnumMember(propertyName(casingKey), initializer);
316
+ }
317
+ }).filter(Boolean))];
318
+ const identifierName = name;
319
+ if (enums.length === 0) return [void 0, factory.createTypeAliasDeclaration([factory.createToken(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier(typeName), void 0, factory.createKeywordTypeNode(ts.SyntaxKind.NeverKeyword))];
320
+ return [factory.createVariableStatement([factory.createToken(ts.SyntaxKind.ExportKeyword)], factory.createVariableDeclarationList([factory.createVariableDeclaration(factory.createIdentifier(identifierName), void 0, void 0, factory.createAsExpression(factory.createObjectLiteralExpression(enums.map(([key, value]) => {
321
+ let initializer = factory.createStringLiteral(value?.toString());
322
+ if (isNumber(value)) if (value < 0) initializer = factory.createPrefixUnaryExpression(ts.SyntaxKind.MinusToken, factory.createNumericLiteral(Math.abs(value)));
323
+ else initializer = factory.createNumericLiteral(value);
324
+ if (typeof value === "boolean") initializer = value ? factory.createTrue() : factory.createFalse();
325
+ if (key) {
326
+ const casingKey = applyEnumKeyCasing(key.toString(), enumKeyCasing);
327
+ return factory.createPropertyAssignment(propertyName(casingKey), initializer);
328
+ }
329
+ }).filter(Boolean), true), factory.createTypeReferenceNode(factory.createIdentifier("const"), void 0)))], ts.NodeFlags.Const)), factory.createTypeAliasDeclaration([factory.createToken(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier(typeName), void 0, factory.createIndexedAccessTypeNode(factory.createParenthesizedType(factory.createTypeQueryNode(factory.createIdentifier(identifierName), void 0)), factory.createTypeOperatorNode(ts.SyntaxKind.KeyOfKeyword, factory.createTypeQueryNode(factory.createIdentifier(identifierName), void 0))))];
330
+ }
331
+ function createOmitDeclaration({ keys, type, nonNullable }) {
332
+ const node = nonNullable ? factory.createTypeReferenceNode(factory.createIdentifier("NonNullable"), [type]) : type;
333
+ if (Array.isArray(keys)) return factory.createTypeReferenceNode(factory.createIdentifier("Omit"), [node, factory.createUnionTypeNode(keys.map((key) => {
334
+ return factory.createLiteralTypeNode(factory.createStringLiteral(key));
335
+ }))]);
336
+ return factory.createTypeReferenceNode(factory.createIdentifier("Omit"), [node, factory.createLiteralTypeNode(factory.createStringLiteral(keys))]);
337
+ }
338
+ const keywordTypeNodes = {
339
+ any: factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword),
340
+ unknown: factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword),
341
+ void: factory.createKeywordTypeNode(ts.SyntaxKind.VoidKeyword),
342
+ number: factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword),
343
+ integer: factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword),
344
+ bigint: factory.createKeywordTypeNode(ts.SyntaxKind.BigIntKeyword),
345
+ object: factory.createKeywordTypeNode(ts.SyntaxKind.ObjectKeyword),
346
+ string: factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
347
+ boolean: factory.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword),
348
+ undefined: factory.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword),
349
+ null: factory.createLiteralTypeNode(factory.createToken(ts.SyntaxKind.NullKeyword)),
350
+ never: factory.createKeywordTypeNode(ts.SyntaxKind.NeverKeyword)
351
+ };
352
+ /**
353
+ * Converts a path like '/pet/{petId}/uploadImage' to a template literal type
354
+ * like `/pet/${string}/uploadImage`
355
+ */
356
+ /**
357
+ * Converts an OAS-style path (e.g. `/pets/{petId}`) or an Express-style path
358
+ * (e.g. `/pets/:petId`) to a TypeScript template literal type
359
+ * like `` `/pets/${string}` ``.
360
+ */
361
+ function createUrlTemplateType(path) {
362
+ const normalized = path.replace(/:([^/]+)/g, "{$1}");
363
+ if (!normalized.includes("{")) return factory.createLiteralTypeNode(factory.createStringLiteral(normalized));
364
+ const segments = normalized.split(/(\{[^}]+\})/);
365
+ const parts = [];
366
+ const parameterIndices = [];
367
+ segments.forEach((segment) => {
368
+ if (segment.startsWith("{") && segment.endsWith("}")) {
369
+ parameterIndices.push(parts.length);
370
+ parts.push(segment);
371
+ } else if (segment) parts.push(segment);
372
+ });
373
+ const head = ts.factory.createTemplateHead(parts[0] || "");
374
+ const templateSpans = [];
375
+ parameterIndices.forEach((paramIndex, i) => {
376
+ const isLast = i === parameterIndices.length - 1;
377
+ const nextPart = parts[paramIndex + 1] || "";
378
+ const literal = isLast ? ts.factory.createTemplateTail(nextPart) : ts.factory.createTemplateMiddle(nextPart);
379
+ templateSpans.push(ts.factory.createTemplateLiteralTypeSpan(keywordTypeNodes.string, literal));
380
+ });
381
+ return ts.factory.createTemplateLiteralType(head, templateSpans);
382
+ }
383
+ const createTypeLiteralNode = factory.createTypeLiteralNode;
384
+ const createTypeReferenceNode = factory.createTypeReferenceNode;
385
+ const createNumericLiteral = factory.createNumericLiteral;
386
+ const createStringLiteral = factory.createStringLiteral;
387
+ const createArrayTypeNode = factory.createArrayTypeNode;
388
+ factory.createParenthesizedType;
389
+ const createLiteralTypeNode = factory.createLiteralTypeNode;
390
+ factory.createNull;
391
+ const createIdentifier = factory.createIdentifier;
392
+ const createOptionalTypeNode = factory.createOptionalTypeNode;
393
+ const createTupleTypeNode = factory.createTupleTypeNode;
394
+ const createRestTypeNode = factory.createRestTypeNode;
395
+ const createTrue = factory.createTrue;
396
+ const createFalse = factory.createFalse;
397
+ factory.createIndexedAccessTypeNode;
398
+ factory.createTypeOperatorNode;
399
+ const createPrefixUnaryExpression = factory.createPrefixUnaryExpression;
400
+ //#endregion
401
+ //#region src/components/Enum.tsx
402
+ /**
403
+ * Resolves the runtime identifier name and the TypeScript type name for an enum schema node.
404
+ *
405
+ * The raw `node.name` may be a YAML key such as `"enumNames.Type"` which is not a
406
+ * valid TypeScript identifier. The resolver normalizes it; for inline enum
407
+ * properties the adapter already emits a PascalCase+suffix name so resolution is typically a no-op.
408
+ */
409
+ function getEnumNames({ node, enumType, enumTypeSuffix, resolver }) {
410
+ const resolved = resolver.default(node.name, "type");
411
+ return {
412
+ enumName: enumType === "asPascalConst" ? resolved : camelCase(node.name),
413
+ typeName: ENUM_TYPES_WITH_KEY_SUFFIX.has(enumType) ? resolver.resolveEnumKeyName(node, enumTypeSuffix) : resolved,
414
+ refName: resolved
415
+ };
416
+ }
417
+ /**
418
+ * Renders the enum declaration(s) for a single named `EnumSchemaNode`.
419
+ *
420
+ * Depending on `enumType` this may emit:
421
+ * - A runtime object (`asConst` / `asPascalConst`) plus a `typeof` type alias
422
+ * - A `const enum` or plain `enum` declaration (`constEnum` / `enum`)
423
+ * - A union literal type alias (`literal`)
424
+ *
425
+ * The emitted `File.Source` nodes carry the resolved names so that the barrel
426
+ * index picks up the correct export identifiers.
427
+ */
428
+ function Enum({ node, enumType, enumTypeSuffix, enumKeyCasing, resolver }) {
429
+ const { enumName, typeName } = getEnumNames({
430
+ node,
431
+ enumType,
432
+ enumTypeSuffix,
433
+ resolver
434
+ });
435
+ const [nameNode, typeNode] = createEnumDeclaration({
436
+ name: enumName,
437
+ typeName,
438
+ 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]) ?? [],
439
+ type: enumType,
440
+ enumKeyCasing
441
+ });
442
+ return /* @__PURE__ */ jsxs(Fragment, { children: [nameNode && /* @__PURE__ */ jsx(File.Source, {
443
+ name: enumName,
444
+ isExportable: true,
445
+ isIndexable: true,
446
+ isTypeOnly: false,
447
+ children: safePrint(nameNode)
448
+ }), /* @__PURE__ */ jsx(File.Source, {
449
+ name: typeName,
450
+ isIndexable: true,
451
+ isExportable: ENUM_TYPES_WITH_RUNTIME_VALUE.has(enumType),
452
+ isTypeOnly: ENUM_TYPES_WITH_TYPE_ONLY.has(enumType),
453
+ children: safePrint(typeNode)
454
+ })] });
455
+ }
456
+ //#endregion
457
+ //#region src/printers/printerTs.ts
458
+ /**
459
+ * Converts a primitive const value to a TypeScript literal type node.
460
+ * Handles negative numbers via a prefix unary expression.
461
+ */
462
+ function constToTypeNode(value, format) {
463
+ if (format === "boolean") return createLiteralTypeNode(value === true ? createTrue() : createFalse());
464
+ if (format === "number" && typeof value === "number") {
465
+ if (value < 0) return createLiteralTypeNode(createPrefixUnaryExpression(SyntaxKind.MinusToken, createNumericLiteral(Math.abs(value))));
466
+ return createLiteralTypeNode(createNumericLiteral(value));
467
+ }
468
+ return createLiteralTypeNode(createStringLiteral(String(value)));
469
+ }
470
+ /**
471
+ * Returns a `Date` reference type node when `representation` is `'date'`, otherwise falls back to `string`.
472
+ */
473
+ function dateOrStringNode(node) {
474
+ return node.representation === "date" ? createTypeReferenceNode(createIdentifier("Date")) : keywordTypeNodes.string;
475
+ }
476
+ /**
477
+ * Maps an array of `SchemaNode`s through the printer, filtering out `null` and `undefined` results.
478
+ */
479
+ function buildMemberNodes(members, print) {
480
+ return (members ?? []).map(print).filter(Boolean);
481
+ }
482
+ /**
483
+ * Builds a TypeScript tuple type node from an array schema's `items`,
484
+ * applying min/max slice and optional/rest element rules.
485
+ */
486
+ function buildTupleNode(node, print) {
487
+ let items = (node.items ?? []).map(print).filter(Boolean);
488
+ const restNode = node.rest ? print(node.rest) ?? void 0 : void 0;
489
+ const { min, max } = node;
490
+ if (max !== void 0) {
491
+ items = items.slice(0, max);
492
+ if (items.length < max && restNode) items = [...items, ...Array(max - items.length).fill(restNode)];
493
+ }
494
+ if (min !== void 0) items = items.map((item, i) => i >= min ? createOptionalTypeNode(item) : item);
495
+ if (max === void 0 && restNode) items.push(createRestTypeNode(createArrayTypeNode(restNode)));
496
+ return createTupleTypeNode(items);
497
+ }
498
+ /**
499
+ * Applies `nullable` and optional/nullish `| undefined` union modifiers to a property's resolved base type.
500
+ */
501
+ function buildPropertyType(schema, baseType, optionalType) {
502
+ const addsUndefined = OPTIONAL_ADDS_UNDEFINED.has(optionalType);
503
+ let type = baseType;
504
+ if (schema.nullable) type = createUnionDeclaration({ nodes: [type, keywordTypeNodes.null] });
505
+ if ((schema.nullish || schema.optional) && addsUndefined) type = createUnionDeclaration({ nodes: [type, keywordTypeNodes.undefined] });
506
+ return type;
507
+ }
508
+ /**
509
+ * Collects JSDoc annotation strings (description, deprecated, min/max, pattern, default, example, type) for a schema node.
510
+ */
511
+ function buildPropertyJSDocComments(schema) {
512
+ const isArray = schema.type === "array";
513
+ return [
514
+ "description" in schema && schema.description ? `@description ${jsStringEscape(schema.description)}` : void 0,
515
+ "deprecated" in schema && schema.deprecated ? "@deprecated" : void 0,
516
+ !isArray && "min" in schema && schema.min !== void 0 ? `@minLength ${schema.min}` : void 0,
517
+ !isArray && "max" in schema && schema.max !== void 0 ? `@maxLength ${schema.max}` : void 0,
518
+ "pattern" in schema && schema.pattern ? `@pattern ${schema.pattern}` : void 0,
519
+ "default" in schema && schema.default !== void 0 ? `@default ${"primitive" in schema && schema.primitive === "string" ? stringify(schema.default) : schema.default}` : void 0,
520
+ "example" in schema && schema.example !== void 0 ? `@example ${schema.example}` : void 0,
521
+ "primitive" in schema && schema.primitive ? [`@type ${schema.primitive || "unknown"}`, "optional" in schema && schema.optional ? " | undefined" : void 0].filter(Boolean).join("") : void 0
522
+ ];
523
+ }
524
+ /**
525
+ * Creates TypeScript index signatures for `additionalProperties` and `patternProperties` on an object schema node.
526
+ */
527
+ function buildIndexSignatures(node, propertyCount, print) {
528
+ const elements = [];
529
+ if (node.additionalProperties && node.additionalProperties !== true) {
530
+ const additionalType = print(node.additionalProperties) ?? keywordTypeNodes.unknown;
531
+ elements.push(createIndexSignature(propertyCount > 0 ? keywordTypeNodes.unknown : additionalType));
532
+ } else if (node.additionalProperties === true) elements.push(createIndexSignature(keywordTypeNodes.unknown));
533
+ if (node.patternProperties) {
534
+ const first = Object.values(node.patternProperties)[0];
535
+ if (first) {
536
+ let patternType = print(first) ?? keywordTypeNodes.unknown;
537
+ if (first.nullable) patternType = createUnionDeclaration({ nodes: [patternType, keywordTypeNodes.null] });
538
+ elements.push(createIndexSignature(patternType));
539
+ }
540
+ }
541
+ return elements;
542
+ }
543
+ /**
544
+ * TypeScript type printer built with `definePrinter`.
545
+ *
546
+ * Converts a `SchemaNode` AST node into a TypeScript AST node:
547
+ * - **`printer.print(node)`** — when `options.typeName` is set, returns a full
548
+ * `type Name = …` or `interface Name { … }` declaration (`ts.Node`).
549
+ * Without `typeName`, returns the raw `ts.TypeNode` for the schema.
550
+ *
551
+ * Dispatches on `node.type` to the appropriate handler in `nodes`. Options are closed
552
+ * over per printer instance, so each call to `printerTs(options)` produces an independent printer.
553
+ *
554
+ * @example Raw type node (no `typeName`)
555
+ * ```ts
556
+ * const printer = printerTs({ optionalType: 'questionToken', arrayType: 'array', enumType: 'inlineLiteral' })
557
+ * const typeNode = printer.print(schemaNode) // ts.TypeNode
558
+ * ```
559
+ *
560
+ * @example Full declaration (with `typeName`)
561
+ * ```ts
562
+ * const printer = printerTs({ optionalType: 'questionToken', arrayType: 'array', enumType: 'inlineLiteral', typeName: 'MyType' })
563
+ * const declaration = printer.print(schemaNode) // ts.TypeAliasDeclaration | ts.InterfaceDeclaration
564
+ * ```
565
+ */
566
+ const printerTs = definePrinter((options) => {
567
+ const addsUndefined = OPTIONAL_ADDS_UNDEFINED.has(options.optionalType);
568
+ return {
569
+ name: "typescript",
570
+ options,
571
+ nodes: {
572
+ any: () => keywordTypeNodes.any,
573
+ unknown: () => keywordTypeNodes.unknown,
574
+ void: () => keywordTypeNodes.void,
575
+ never: () => keywordTypeNodes.never,
576
+ boolean: () => keywordTypeNodes.boolean,
577
+ null: () => keywordTypeNodes.null,
578
+ blob: () => createTypeReferenceNode("Blob", []),
579
+ string: () => keywordTypeNodes.string,
580
+ uuid: () => keywordTypeNodes.string,
581
+ email: () => keywordTypeNodes.string,
582
+ url: (node) => {
583
+ if (node.path) return createUrlTemplateType(node.path);
584
+ return keywordTypeNodes.string;
585
+ },
586
+ datetime: () => keywordTypeNodes.string,
587
+ number: () => keywordTypeNodes.number,
588
+ integer: () => keywordTypeNodes.number,
589
+ bigint: () => keywordTypeNodes.bigint,
590
+ date: dateOrStringNode,
591
+ time: dateOrStringNode,
592
+ ref(node) {
593
+ if (!node.name) return;
594
+ const refName = node.ref ? node.ref.split("/").at(-1) ?? node.name : node.name;
595
+ return createTypeReferenceNode(node.ref ? this.options.resolver.default(refName, "type") : refName, void 0);
596
+ },
597
+ enum(node) {
598
+ const values = node.namedEnumValues?.map((v) => v.value) ?? node.enumValues ?? [];
599
+ if (this.options.enumType === "inlineLiteral" || !node.name) return createUnionDeclaration({
600
+ withParentheses: true,
601
+ nodes: values.filter((v) => v !== null).map((value) => constToTypeNode(value, typeof value)).filter(Boolean)
602
+ }) ?? void 0;
603
+ 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);
604
+ },
605
+ union(node) {
606
+ const members = node.members ?? [];
607
+ const hasStringLiteral = members.some((m) => {
608
+ return narrowSchema(m, schemaTypes.enum)?.primitive === "string";
609
+ });
610
+ const hasPlainString = members.some((m) => isStringType(m));
611
+ if (hasStringLiteral && hasPlainString) return createUnionDeclaration({
612
+ withParentheses: true,
613
+ nodes: members.map((m) => {
614
+ if (isStringType(m)) return createIntersectionDeclaration({
615
+ nodes: [keywordTypeNodes.string, createTypeLiteralNode([])],
616
+ withParentheses: true
617
+ });
618
+ return this.transform(m);
619
+ }).filter(Boolean)
620
+ }) ?? void 0;
621
+ return createUnionDeclaration({
622
+ withParentheses: true,
623
+ nodes: buildMemberNodes(members, this.transform)
624
+ }) ?? void 0;
625
+ },
626
+ intersection(node) {
627
+ return createIntersectionDeclaration({
628
+ withParentheses: true,
629
+ nodes: buildMemberNodes(node.members, this.transform)
630
+ }) ?? void 0;
631
+ },
632
+ array(node) {
633
+ return createArrayDeclaration({
634
+ nodes: (node.items ?? []).map((item) => this.transform(item)).filter(Boolean),
635
+ arrayType: this.options.arrayType
636
+ }) ?? void 0;
637
+ },
638
+ tuple(node) {
639
+ return buildTupleNode(node, this.transform);
640
+ },
641
+ object(node) {
642
+ const { transform, options } = this;
643
+ const addsQuestionToken = OPTIONAL_ADDS_QUESTION_TOKEN.has(options.optionalType);
644
+ const propertyNodes = node.properties.map((prop) => {
645
+ const baseType = transform(prop.schema) ?? keywordTypeNodes.unknown;
646
+ const type = buildPropertyType(prop.schema, baseType, options.optionalType);
647
+ return appendJSDocToNode({
648
+ node: createPropertySignature({
649
+ questionToken: prop.schema.optional || prop.schema.nullish ? addsQuestionToken : false,
650
+ name: prop.name,
651
+ type,
652
+ readOnly: prop.schema.readOnly
653
+ }),
654
+ comments: buildPropertyJSDocComments(prop.schema)
655
+ });
656
+ });
657
+ const allElements = [...propertyNodes, ...buildIndexSignatures(node, propertyNodes.length, transform)];
658
+ if (!allElements.length) return keywordTypeNodes.object;
659
+ return createTypeLiteralNode(allElements);
660
+ }
661
+ },
662
+ print(node) {
663
+ let type = this.transform(node);
664
+ if (!type) return null;
665
+ if (node.nullable) type = createUnionDeclaration({ nodes: [type, keywordTypeNodes.null] });
666
+ if ((node.nullish || node.optional) && addsUndefined) type = createUnionDeclaration({ nodes: [type, keywordTypeNodes.undefined] });
667
+ const { name, syntaxType = "type", description, keysToOmit } = this.options;
668
+ if (!name) return safePrint(type);
669
+ const useTypeGeneration = syntaxType === "type" || type.kind === syntaxKind.union || !!keysToOmit?.length;
670
+ return safePrint(createTypeDeclaration({
671
+ name,
672
+ isExportable: true,
673
+ type: keysToOmit?.length ? createOmitDeclaration({
674
+ keys: keysToOmit,
675
+ type,
676
+ nonNullable: true
677
+ }) : type,
678
+ syntax: useTypeGeneration ? "type" : "interface",
679
+ comments: [
680
+ node?.title ? jsStringEscape(node.title) : void 0,
681
+ description ? `@description ${jsStringEscape(description)}` : void 0,
682
+ node?.deprecated ? "@deprecated" : void 0,
683
+ node && "min" in node && node.min !== void 0 ? `@minLength ${node.min}` : void 0,
684
+ node && "max" in node && node.max !== void 0 ? `@maxLength ${node.max}` : void 0,
685
+ node && "pattern" in node && node.pattern ? `@pattern ${node.pattern}` : void 0,
686
+ node?.default ? `@default ${node.default}` : void 0,
687
+ node?.example ? `@example ${node.example}` : void 0
688
+ ]
689
+ }));
690
+ }
691
+ };
692
+ });
693
+ //#endregion
694
+ //#region src/components/Type.tsx
695
+ function Type({ name, node, keysToOmit, optionalType, arrayType, syntaxType, enumType, enumTypeSuffix, enumKeyCasing, description, resolver }) {
696
+ const resolvedDescription = description || node?.description;
697
+ const enumSchemaNodes = collect(node, { schema(n) {
698
+ const enumNode = narrowSchema(n, schemaTypes.enum);
699
+ if (enumNode?.name) return enumNode;
700
+ } });
701
+ const output = printerTs({
702
+ optionalType,
703
+ arrayType,
704
+ enumType,
705
+ enumTypeSuffix,
706
+ name,
707
+ syntaxType,
708
+ description: resolvedDescription,
709
+ keysToOmit,
710
+ resolver
711
+ }).print(node);
712
+ if (!output) return;
713
+ const enums = [...new Map(enumSchemaNodes.map((n) => [n.name, n])).values()].map((node) => {
714
+ return {
715
+ node,
716
+ ...getEnumNames({
717
+ node,
718
+ enumType,
719
+ enumTypeSuffix,
720
+ resolver
721
+ })
722
+ };
723
+ });
724
+ const shouldExportEnums = enumType !== "inlineLiteral";
725
+ const shouldExportType = enumType === "inlineLiteral" || enums.every((item) => item.typeName !== name);
726
+ return /* @__PURE__ */ jsxs(Fragment, { children: [shouldExportEnums && enums.map(({ node }) => /* @__PURE__ */ jsx(Enum, {
727
+ node,
728
+ enumType,
729
+ enumTypeSuffix,
730
+ enumKeyCasing,
731
+ resolver
732
+ })), shouldExportType && /* @__PURE__ */ jsx(File.Source, {
733
+ name,
734
+ isTypeOnly: true,
735
+ isExportable: true,
736
+ isIndexable: true,
737
+ children: output
738
+ })] });
739
+ }
740
+ //#endregion
741
+ //#region src/utils.ts
742
+ function buildParams({ params, node, resolver }) {
743
+ return createSchema({
744
+ type: "object",
745
+ properties: params.map((param) => createProperty({
746
+ name: param.name,
747
+ required: param.required,
748
+ schema: createSchema({
749
+ type: "ref",
750
+ name: resolver.resolveParamName(node, param)
751
+ })
752
+ }))
753
+ });
754
+ }
755
+ function buildData({ node, resolver }) {
756
+ const pathParams = node.parameters.filter((p) => p.in === "path");
757
+ const queryParams = node.parameters.filter((p) => p.in === "query");
758
+ const headerParams = node.parameters.filter((p) => p.in === "header");
759
+ return createSchema({
760
+ type: "object",
761
+ deprecated: node.deprecated,
762
+ properties: [
763
+ createProperty({
764
+ name: "data",
765
+ schema: node.requestBody?.schema ? createSchema({
766
+ type: "ref",
767
+ name: resolver.resolveDataName(node),
768
+ optional: true
769
+ }) : createSchema({
770
+ type: "never",
771
+ optional: true
772
+ })
773
+ }),
774
+ createProperty({
775
+ name: "pathParams",
776
+ required: pathParams.length > 0,
777
+ schema: pathParams.length > 0 ? buildParams({
778
+ params: pathParams,
779
+ node,
780
+ resolver
781
+ }) : createSchema({ type: "never" })
782
+ }),
783
+ createProperty({
784
+ name: "queryParams",
785
+ schema: queryParams.length > 0 ? createSchema({
786
+ ...buildParams({
787
+ params: queryParams,
788
+ node,
789
+ resolver
790
+ }),
791
+ optional: true
792
+ }) : createSchema({
793
+ type: "never",
794
+ optional: true
795
+ })
796
+ }),
797
+ createProperty({
798
+ name: "headerParams",
799
+ schema: headerParams.length > 0 ? createSchema({
800
+ ...buildParams({
801
+ params: headerParams,
802
+ node,
803
+ resolver
804
+ }),
805
+ optional: true
806
+ }) : createSchema({
807
+ type: "never",
808
+ optional: true
809
+ })
810
+ }),
811
+ createProperty({
812
+ name: "url",
813
+ required: true,
814
+ schema: createSchema({
815
+ type: "url",
816
+ path: node.path
817
+ })
818
+ })
819
+ ]
820
+ });
821
+ }
822
+ function buildResponses({ node, resolver }) {
823
+ if (node.responses.length === 0) return null;
824
+ return createSchema({
825
+ type: "object",
826
+ properties: node.responses.map((res) => createProperty({
827
+ name: String(res.statusCode),
828
+ required: true,
829
+ schema: createSchema({
830
+ type: "ref",
831
+ name: resolver.resolveResponseStatusName(node, res.statusCode)
832
+ })
833
+ }))
834
+ });
835
+ }
836
+ function buildResponseUnion({ node, resolver }) {
837
+ const responsesWithSchema = node.responses.filter((res) => res.schema);
838
+ if (responsesWithSchema.length === 0) return null;
839
+ return createSchema({
840
+ type: "union",
841
+ members: responsesWithSchema.map((res) => createSchema({
842
+ type: "ref",
843
+ name: resolver.resolveResponseStatusName(node, res.statusCode)
844
+ }))
845
+ });
846
+ }
847
+ //#endregion
848
+ //#region src/generators/typeGenerator.tsx
849
+ const typeGenerator = defineGenerator({
850
+ name: "typescript",
851
+ type: "react",
852
+ Operation({ node, adapter, options, config, resolver }) {
853
+ const { enumType, enumTypeSuffix, enumKeyCasing, optionalType, arrayType, syntaxType, paramsCasing, group, output, transformers = [] } = options;
854
+ const root = path.resolve(config.root, config.output.path);
855
+ const mode = getMode(path.resolve(root, output.path));
856
+ const file = resolver.resolveFile({
857
+ name: node.operationId,
858
+ extname: ".ts",
859
+ tag: node.tags[0] ?? "default",
860
+ path: node.path
861
+ }, {
862
+ root,
863
+ output,
864
+ group
865
+ });
866
+ const params = caseParams(node.parameters, paramsCasing);
867
+ function renderSchemaType({ node: schemaNode, name, description, keysToOmit }) {
868
+ if (!schemaNode) return null;
869
+ const transformedNode = transform(schemaNode, composeTransformers(...transformers));
870
+ const imports = adapter.getImports(transformedNode, (schemaName) => ({
871
+ name: resolver.default(schemaName, "type"),
872
+ path: resolver.resolveFile({
873
+ name: schemaName,
874
+ extname: ".ts"
875
+ }, {
876
+ root,
877
+ output,
878
+ group
879
+ }).path
880
+ }));
881
+ return /* @__PURE__ */ jsxs(Fragment, { children: [mode === "split" && imports.map((imp) => /* @__PURE__ */ jsx(File.Import, {
882
+ root: file.path,
883
+ path: imp.path,
884
+ name: imp.name,
885
+ isTypeOnly: true
886
+ }, [
887
+ name,
888
+ imp.path,
889
+ imp.isTypeOnly
890
+ ].join("-"))), /* @__PURE__ */ jsx(Type, {
891
+ name,
892
+ node: transformedNode,
893
+ description,
894
+ enumType,
895
+ enumTypeSuffix,
896
+ enumKeyCasing,
897
+ optionalType,
898
+ arrayType,
899
+ syntaxType,
900
+ resolver,
901
+ keysToOmit
902
+ })] });
903
+ }
904
+ const paramTypes = params.map((param) => renderSchemaType({
905
+ node: param.schema,
906
+ name: resolver.resolveParamName(node, param)
907
+ }));
908
+ const requestType = node.requestBody?.schema ? renderSchemaType({
909
+ node: node.requestBody.schema,
910
+ name: resolver.resolveDataName(node),
911
+ description: node.requestBody.description ?? node.requestBody.schema.description,
912
+ keysToOmit: node.requestBody.keysToOmit
913
+ }) : null;
914
+ const responseTypes = node.responses.map((res) => renderSchemaType({
915
+ node: res.schema,
916
+ name: resolver.resolveResponseStatusName(node, res.statusCode),
917
+ description: res.description,
918
+ keysToOmit: res.keysToOmit
919
+ }));
920
+ const dataType = renderSchemaType({
921
+ node: buildData({
922
+ node: {
923
+ ...node,
924
+ parameters: params
925
+ },
926
+ resolver
927
+ }),
928
+ name: resolver.resolveRequestConfigName(node)
929
+ });
930
+ const responsesType = renderSchemaType({
931
+ node: buildResponses({
932
+ node,
933
+ resolver
934
+ }),
935
+ name: resolver.resolveResponsesName(node)
936
+ });
937
+ const responseType = renderSchemaType({
938
+ node: buildResponseUnion({
939
+ node,
940
+ resolver
941
+ }),
942
+ name: resolver.resolveResponseName(node),
943
+ description: "Union of all possible responses"
944
+ });
945
+ return /* @__PURE__ */ jsxs(File, {
946
+ baseName: file.baseName,
947
+ path: file.path,
948
+ meta: file.meta,
949
+ banner: resolver.resolveBanner(adapter.rootNode, {
950
+ output,
951
+ config
952
+ }),
953
+ footer: resolver.resolveFooter(adapter.rootNode, {
954
+ output,
955
+ config
956
+ }),
957
+ children: [
958
+ paramTypes,
959
+ responseTypes,
960
+ requestType,
961
+ dataType,
962
+ responsesType,
963
+ responseType
964
+ ]
965
+ });
966
+ },
967
+ Schema({ node, adapter, options, config, resolver }) {
968
+ const { enumType, enumTypeSuffix, enumKeyCasing, syntaxType, optionalType, arrayType, output, group, transformers = [] } = options;
969
+ const root = path.resolve(config.root, config.output.path);
970
+ const mode = getMode(path.resolve(root, output.path));
971
+ if (!node.name) return;
972
+ const transformedNode = transform(node, composeTransformers(...transformers));
973
+ const imports = adapter.getImports(transformedNode, (schemaName) => ({
974
+ name: resolver.default(schemaName, "type"),
975
+ path: resolver.resolveFile({
976
+ name: schemaName,
977
+ extname: ".ts"
978
+ }, {
979
+ root,
980
+ output,
981
+ group
982
+ }).path
983
+ }));
984
+ const isEnumSchema = !!narrowSchema(node, schemaTypes.enum);
985
+ const type = {
986
+ name: ENUM_TYPES_WITH_KEY_SUFFIX.has(enumType) && isEnumSchema ? resolver.resolveEnumKeyName(node, enumTypeSuffix) : resolver.resolveName(node.name),
987
+ file: resolver.resolveFile({
988
+ name: node.name,
989
+ extname: ".ts"
990
+ }, {
991
+ root,
992
+ output,
993
+ group
994
+ })
995
+ };
996
+ return /* @__PURE__ */ jsxs(File, {
997
+ baseName: type.file.baseName,
998
+ path: type.file.path,
999
+ meta: type.file.meta,
1000
+ banner: resolver.resolveBanner(adapter.rootNode, {
1001
+ output,
1002
+ config
1003
+ }),
1004
+ footer: resolver.resolveFooter(adapter.rootNode, {
1005
+ output,
1006
+ config
1007
+ }),
1008
+ children: [mode === "split" && imports.map((imp) => /* @__PURE__ */ jsx(File.Import, {
1009
+ root: type.file.path,
1010
+ path: imp.path,
1011
+ name: imp.name,
1012
+ isTypeOnly: true
1013
+ }, [
1014
+ node.name,
1015
+ imp.path,
1016
+ imp.isTypeOnly
1017
+ ].join("-"))), /* @__PURE__ */ jsx(Type, {
1018
+ name: type.name,
1019
+ node: transformedNode,
1020
+ enumType,
1021
+ enumTypeSuffix,
1022
+ enumKeyCasing,
1023
+ optionalType,
1024
+ arrayType,
1025
+ syntaxType,
1026
+ resolver
1027
+ })]
1028
+ });
1029
+ }
1030
+ });
1031
+ //#endregion
1032
+ //#region src/resolvers/resolverTs.ts
1033
+ function resolveName(name, type) {
1034
+ return pascalCase(name, { isFile: type === "file" });
1035
+ }
1036
+ /**
1037
+ * Resolver for `@kubb/plugin-ts` that provides the default naming and path-resolution
1038
+ * helpers used by the plugin. Import this in other plugins to resolve the exact names and
1039
+ * paths that `plugin-ts` generates without hardcoding the conventions.
1040
+ *
1041
+ * The `default` method is automatically injected by `defineResolver` — it uses `camelCase`
1042
+ * for identifiers/files and `pascalCase` for type names.
1043
+ *
1044
+ * @example
1045
+ * ```ts
1046
+ * import { resolver } from '@kubb/plugin-ts'
1047
+ *
1048
+ * resolver.default('list pets', 'type') // → 'ListPets'
1049
+ * resolver.resolveName('list pets status 200') // → 'ListPetsStatus200'
1050
+ * resolver.resolvePathName('list pets', 'file') // → 'listPets'
1051
+ * ```
1052
+ */
1053
+ const resolverTs = defineResolver(() => {
1054
+ return {
1055
+ name: "default",
1056
+ pluginName: "plugin-ts",
1057
+ default(name, type) {
1058
+ return resolveName(name, type);
1059
+ },
1060
+ resolveName(name) {
1061
+ return this.default(name, "function");
1062
+ },
1063
+ resolvePathName(name, type) {
1064
+ return this.default(name, type);
1065
+ },
1066
+ resolveParamName(node, param) {
1067
+ return this.resolveName(`${node.operationId} ${param.in} ${param.name}`);
1068
+ },
1069
+ resolveResponseStatusName(node, statusCode) {
1070
+ return this.resolveName(`${node.operationId} Status ${statusCode}`);
1071
+ },
1072
+ resolveDataName(node) {
1073
+ return this.resolveName(`${node.operationId} Data`);
1074
+ },
1075
+ resolveRequestConfigName(node) {
1076
+ return this.resolveName(`${node.operationId} RequestConfig`);
1077
+ },
1078
+ resolveResponsesName(node) {
1079
+ return this.resolveName(`${node.operationId} Responses`);
1080
+ },
1081
+ resolveResponseName(node) {
1082
+ return this.resolveName(`${node.operationId} Response`);
1083
+ },
1084
+ resolveEnumKeyName(node, enumTypeSuffix = "key") {
1085
+ return `${this.resolveName(node.name ?? "")}${enumTypeSuffix}`;
1086
+ },
1087
+ resolvePathParamsName(node, param) {
1088
+ return this.resolveParamName(node, param);
1089
+ },
1090
+ resolveQueryParamsName(node, param) {
1091
+ return this.resolveParamName(node, param);
1092
+ },
1093
+ resolveHeaderParamsName(node, param) {
1094
+ return this.resolveParamName(node, param);
1095
+ }
1096
+ };
23
1097
  });
1098
+ //#endregion
1099
+ //#region src/resolvers/resolverTsLegacy.ts
24
1100
  /**
25
- * Resolves a compatibility preset for `plugin-ts`, merging user-supplied resolvers,
26
- * transformers, and generators on top of the built-in preset defaults.
1101
+ * Legacy resolver for `@kubb/plugin-ts` that reproduces the naming conventions
1102
+ * used before the v2 resolver refactor. Enable via `compatibilityPreset: 'kubbV4'`
1103
+ * (or by composing this resolver manually).
27
1104
  *
28
- * `resolverTs` is always prepended to the resolver list as the baseline.
1105
+ * Key differences from the default resolver:
1106
+ * - Response status types: `<OperationId><StatusCode>` (e.g. `CreatePets201`) instead of `<OperationId>Status201`
1107
+ * - Default/error responses: `<OperationId>Error` instead of `<OperationId>StatusDefault`
1108
+ * - Request body: `<OperationId>MutationRequest` (non-GET) / `<OperationId>QueryRequest` (GET)
1109
+ * - Combined responses type: `<OperationId>Mutation` / `<OperationId>Query`
1110
+ * - Response union: `<OperationId>MutationResponse` / `<OperationId>QueryResponse`
29
1111
  *
30
1112
  * @example
31
1113
  * ```ts
32
- * const preset = getPreset('kubbV4', { resolvers: [], transformers: [], generators: [] })
1114
+ * import { resolverTsLegacy } from '@kubb/plugin-ts'
1115
+ *
1116
+ * resolverTsLegacy.resolveResponseStatusTypedName(node, 201) // → 'CreatePets201'
1117
+ * resolverTsLegacy.resolveResponseStatusTypedName(node, 'default') // → 'CreatePetsError'
1118
+ * resolverTsLegacy.resolveDataTypedName(node) // → 'CreatePetsMutationRequest' (POST)
1119
+ * resolverTsLegacy.resolveResponsesTypedName(node) // → 'CreatePetsMutation' (POST)
1120
+ * resolverTsLegacy.resolveResponseTypedName(node) // → 'CreatePetsMutationResponse' (POST)
33
1121
  * ```
34
1122
  */
35
- function getPreset$1(preset, { resolvers, transformers, generators }) {
36
- return getPreset({
37
- preset,
38
- presets,
39
- resolvers: [resolverTs, ...resolvers ?? []],
40
- transformers,
41
- generators
1123
+ const resolverTsLegacy = defineResolver(() => {
1124
+ return {
1125
+ ...resolverTs,
1126
+ pluginName: "plugin-ts",
1127
+ resolveResponseStatusName(node, statusCode) {
1128
+ if (statusCode === "default") return this.resolveName(`${node.operationId} Error`);
1129
+ return this.resolveName(`${node.operationId} ${statusCode}`);
1130
+ },
1131
+ resolveDataName(node) {
1132
+ const suffix = node.method === "GET" ? "QueryRequest" : "MutationRequest";
1133
+ return this.resolveName(`${node.operationId} ${suffix}`);
1134
+ },
1135
+ resolveResponsesName(node) {
1136
+ const suffix = node.method === "GET" ? "Query" : "Mutation";
1137
+ return this.resolveName(`${node.operationId} ${suffix}`);
1138
+ },
1139
+ resolveResponseName(node) {
1140
+ const suffix = node.method === "GET" ? "QueryResponse" : "MutationResponse";
1141
+ return this.resolveName(`${node.operationId} ${suffix}`);
1142
+ },
1143
+ resolvePathParamsName(node, _param) {
1144
+ return this.resolveName(`${node.operationId} PathParams`);
1145
+ },
1146
+ resolveQueryParamsName(node, _param) {
1147
+ return this.resolveName(`${node.operationId} QueryParams`);
1148
+ },
1149
+ resolveHeaderParamsName(node, _param) {
1150
+ return this.resolveName(`${node.operationId} HeaderParams`);
1151
+ }
1152
+ };
1153
+ });
1154
+ //#endregion
1155
+ //#region src/generators/typeGeneratorLegacy.tsx
1156
+ function buildGroupedParamsSchema({ params, parentName }) {
1157
+ return createSchema({
1158
+ type: "object",
1159
+ properties: params.map((param) => {
1160
+ let schema = param.schema;
1161
+ if (narrowSchema(schema, "enum") && !schema.name && parentName) schema = {
1162
+ ...schema,
1163
+ name: pascalCase([
1164
+ parentName,
1165
+ param.name,
1166
+ "enum"
1167
+ ].join(" "))
1168
+ };
1169
+ return createProperty({
1170
+ name: param.name,
1171
+ required: param.required,
1172
+ schema
1173
+ });
1174
+ })
1175
+ });
1176
+ }
1177
+ function buildLegacyResponsesSchemaNode({ node, resolver }) {
1178
+ const isGet = node.method.toLowerCase() === "get";
1179
+ const successResponses = node.responses.filter((res) => {
1180
+ const code = Number(res.statusCode);
1181
+ return !Number.isNaN(code) && code >= 200 && code < 300;
1182
+ });
1183
+ const errorResponses = node.responses.filter((res) => res.statusCode === "default" || Number(res.statusCode) >= 400);
1184
+ const responseSchema = successResponses.length > 0 ? successResponses.length === 1 ? createSchema({
1185
+ type: "ref",
1186
+ name: resolver.resolveResponseStatusName(node, successResponses[0].statusCode)
1187
+ }) : createSchema({
1188
+ type: "union",
1189
+ members: successResponses.map((res) => createSchema({
1190
+ type: "ref",
1191
+ name: resolver.resolveResponseStatusName(node, res.statusCode)
1192
+ }))
1193
+ }) : createSchema({ type: "any" });
1194
+ const errorsSchema = errorResponses.length > 0 ? errorResponses.length === 1 ? createSchema({
1195
+ type: "ref",
1196
+ name: resolver.resolveResponseStatusName(node, errorResponses[0].statusCode)
1197
+ }) : createSchema({
1198
+ type: "union",
1199
+ members: errorResponses.map((res) => createSchema({
1200
+ type: "ref",
1201
+ name: resolver.resolveResponseStatusName(node, res.statusCode)
1202
+ }))
1203
+ }) : createSchema({ type: "any" });
1204
+ const properties = [createProperty({
1205
+ name: "Response",
1206
+ required: true,
1207
+ schema: responseSchema
1208
+ })];
1209
+ if (!isGet && node.requestBody?.schema) properties.push(createProperty({
1210
+ name: "Request",
1211
+ required: true,
1212
+ schema: createSchema({
1213
+ type: "ref",
1214
+ name: resolver.resolveDataName(node)
1215
+ })
1216
+ }));
1217
+ const queryParam = node.parameters.find((p) => p.in === "query");
1218
+ if (queryParam) properties.push(createProperty({
1219
+ name: "QueryParams",
1220
+ required: true,
1221
+ schema: createSchema({
1222
+ type: "ref",
1223
+ name: resolver.resolveQueryParamsName(node, queryParam)
1224
+ })
1225
+ }));
1226
+ const pathParam = node.parameters.find((p) => p.in === "path");
1227
+ if (pathParam) properties.push(createProperty({
1228
+ name: "PathParams",
1229
+ required: true,
1230
+ schema: createSchema({
1231
+ type: "ref",
1232
+ name: resolver.resolvePathParamsName(node, pathParam)
1233
+ })
1234
+ }));
1235
+ const headerParam = node.parameters.find((p) => p.in === "header");
1236
+ if (headerParam) properties.push(createProperty({
1237
+ name: "HeaderParams",
1238
+ required: true,
1239
+ schema: createSchema({
1240
+ type: "ref",
1241
+ name: resolver.resolveHeaderParamsName(node, headerParam)
1242
+ })
1243
+ }));
1244
+ properties.push(createProperty({
1245
+ name: "Errors",
1246
+ required: true,
1247
+ schema: errorsSchema
1248
+ }));
1249
+ return createSchema({
1250
+ type: "object",
1251
+ properties
1252
+ });
1253
+ }
1254
+ function buildLegacyResponseUnionSchemaNode({ node, resolver }) {
1255
+ const successResponses = node.responses.filter((res) => {
1256
+ const code = Number(res.statusCode);
1257
+ return !Number.isNaN(code) && code >= 200 && code < 300;
1258
+ });
1259
+ if (successResponses.length === 0) return createSchema({ type: "any" });
1260
+ if (successResponses.length === 1) return createSchema({
1261
+ type: "ref",
1262
+ name: resolver.resolveResponseStatusName(node, successResponses[0].statusCode)
1263
+ });
1264
+ return createSchema({
1265
+ type: "union",
1266
+ members: successResponses.map((res) => createSchema({
1267
+ type: "ref",
1268
+ name: resolver.resolveResponseStatusName(node, res.statusCode)
1269
+ }))
42
1270
  });
43
1271
  }
44
- __name(getPreset$1, "getPreset");
1272
+ function nameUnnamedEnums(node, parentName) {
1273
+ return transform(node, {
1274
+ schema(n) {
1275
+ const enumNode = narrowSchema(n, "enum");
1276
+ if (enumNode && !enumNode.name) return {
1277
+ ...enumNode,
1278
+ name: pascalCase([parentName, "enum"].join(" "))
1279
+ };
1280
+ },
1281
+ property(p) {
1282
+ const enumNode = narrowSchema(p.schema, "enum");
1283
+ if (enumNode && !enumNode.name) return {
1284
+ ...p,
1285
+ schema: {
1286
+ ...enumNode,
1287
+ name: pascalCase([
1288
+ parentName,
1289
+ p.name,
1290
+ "enum"
1291
+ ].join(" "))
1292
+ }
1293
+ };
1294
+ }
1295
+ });
1296
+ }
1297
+ const typeGeneratorLegacy = defineGenerator({
1298
+ name: "typescript-legacy",
1299
+ type: "react",
1300
+ Operation({ node, adapter, options, config, resolver }) {
1301
+ const { enumType, enumTypeSuffix, enumKeyCasing, optionalType, arrayType, syntaxType, paramsCasing, group, output, transformers = [] } = options;
1302
+ const root = path.resolve(config.root, config.output.path);
1303
+ const mode = getMode(path.resolve(root, output.path));
1304
+ const file = resolver.resolveFile({
1305
+ name: node.operationId,
1306
+ extname: ".ts",
1307
+ tag: node.tags[0] ?? "default",
1308
+ path: node.path
1309
+ }, {
1310
+ root,
1311
+ output,
1312
+ group
1313
+ });
1314
+ const params = caseParams(node.parameters, paramsCasing);
1315
+ function renderSchemaType({ node: schemaNode, name, description, keysToOmit }) {
1316
+ if (!schemaNode) return null;
1317
+ const transformedNode = transform(schemaNode, composeTransformers(...transformers));
1318
+ const imports = adapter.getImports(transformedNode, (schemaName) => ({
1319
+ name: resolver.default(schemaName, "type"),
1320
+ path: resolver.resolveFile({
1321
+ name: schemaName,
1322
+ extname: ".ts"
1323
+ }, {
1324
+ root,
1325
+ output,
1326
+ group
1327
+ }).path
1328
+ }));
1329
+ return /* @__PURE__ */ jsxs(Fragment, { children: [mode === "split" && imports.map((imp) => /* @__PURE__ */ jsx(File.Import, {
1330
+ root: file.path,
1331
+ path: imp.path,
1332
+ name: imp.name,
1333
+ isTypeOnly: true
1334
+ }, [
1335
+ name,
1336
+ imp.path,
1337
+ imp.isTypeOnly
1338
+ ].join("-"))), /* @__PURE__ */ jsx(Type, {
1339
+ name,
1340
+ node: transformedNode,
1341
+ description,
1342
+ enumType,
1343
+ enumTypeSuffix,
1344
+ enumKeyCasing,
1345
+ optionalType,
1346
+ arrayType,
1347
+ syntaxType,
1348
+ resolver,
1349
+ keysToOmit
1350
+ })] });
1351
+ }
1352
+ const pathParams = params.filter((p) => p.in === "path");
1353
+ const queryParams = params.filter((p) => p.in === "query");
1354
+ const headerParams = params.filter((p) => p.in === "header");
1355
+ const responseTypes = node.responses.map((res) => {
1356
+ const responseName = resolver.resolveResponseStatusName(node, res.statusCode);
1357
+ const baseResponseName = resolverTsLegacy.resolveResponseStatusName(node, res.statusCode);
1358
+ return renderSchemaType({
1359
+ node: res.schema ? nameUnnamedEnums(res.schema, baseResponseName) : res.schema,
1360
+ name: responseName,
1361
+ description: res.description,
1362
+ keysToOmit: res.keysToOmit
1363
+ });
1364
+ });
1365
+ const requestType = node.requestBody?.schema ? renderSchemaType({
1366
+ node: nameUnnamedEnums(node.requestBody.schema, resolverTsLegacy.resolveDataName(node)),
1367
+ name: resolver.resolveDataName(node),
1368
+ description: node.requestBody.description ?? node.requestBody.schema.description,
1369
+ keysToOmit: node.requestBody.keysToOmit
1370
+ }) : null;
1371
+ const legacyParamTypes = [
1372
+ pathParams.length > 0 ? renderSchemaType({
1373
+ node: buildGroupedParamsSchema({
1374
+ params: pathParams,
1375
+ parentName: resolverTsLegacy.resolvePathParamsName(node, pathParams[0])
1376
+ }),
1377
+ name: resolver.resolvePathParamsName(node, pathParams[0])
1378
+ }) : null,
1379
+ queryParams.length > 0 ? renderSchemaType({
1380
+ node: buildGroupedParamsSchema({
1381
+ params: queryParams,
1382
+ parentName: resolverTsLegacy.resolveQueryParamsName(node, queryParams[0])
1383
+ }),
1384
+ name: resolver.resolveQueryParamsName(node, queryParams[0])
1385
+ }) : null,
1386
+ headerParams.length > 0 ? renderSchemaType({
1387
+ node: buildGroupedParamsSchema({
1388
+ params: headerParams,
1389
+ parentName: resolverTsLegacy.resolveHeaderParamsName(node, headerParams[0])
1390
+ }),
1391
+ name: resolver.resolveHeaderParamsName(node, headerParams[0])
1392
+ }) : null
1393
+ ];
1394
+ const legacyResponsesType = renderSchemaType({
1395
+ node: buildLegacyResponsesSchemaNode({
1396
+ node,
1397
+ resolver
1398
+ }),
1399
+ name: resolver.resolveResponsesName(node)
1400
+ });
1401
+ const legacyResponseType = renderSchemaType({
1402
+ node: buildLegacyResponseUnionSchemaNode({
1403
+ node,
1404
+ resolver
1405
+ }),
1406
+ name: resolver.resolveResponseName(node)
1407
+ });
1408
+ return /* @__PURE__ */ jsxs(File, {
1409
+ baseName: file.baseName,
1410
+ path: file.path,
1411
+ meta: file.meta,
1412
+ banner: resolver.resolveBanner(adapter.rootNode, {
1413
+ output,
1414
+ config
1415
+ }),
1416
+ footer: resolver.resolveFooter(adapter.rootNode, {
1417
+ output,
1418
+ config
1419
+ }),
1420
+ children: [
1421
+ legacyParamTypes,
1422
+ responseTypes,
1423
+ requestType,
1424
+ legacyResponseType,
1425
+ legacyResponsesType
1426
+ ]
1427
+ });
1428
+ },
1429
+ Schema({ node, adapter, options, config, resolver }) {
1430
+ const { enumType, enumTypeSuffix, enumKeyCasing, syntaxType, optionalType, arrayType, output, group, transformers = [] } = options;
1431
+ const root = path.resolve(config.root, config.output.path);
1432
+ const mode = getMode(path.resolve(root, output.path));
1433
+ if (!node.name) return;
1434
+ const transformedNode = transform(node, composeTransformers(...transformers));
1435
+ const imports = adapter.getImports(transformedNode, (schemaName) => ({
1436
+ name: resolver.default(schemaName, "type"),
1437
+ path: resolver.resolveFile({
1438
+ name: schemaName,
1439
+ extname: ".ts"
1440
+ }, {
1441
+ root,
1442
+ output,
1443
+ group
1444
+ }).path
1445
+ }));
1446
+ const isEnumSchema = !!narrowSchema(node, schemaTypes.enum);
1447
+ const type = {
1448
+ name: ENUM_TYPES_WITH_KEY_SUFFIX.has(enumType) && isEnumSchema ? resolver.resolveEnumKeyName(node, enumTypeSuffix) : resolver.resolveName(node.name),
1449
+ file: resolver.resolveFile({
1450
+ name: node.name,
1451
+ extname: ".ts"
1452
+ }, {
1453
+ root,
1454
+ output,
1455
+ group
1456
+ })
1457
+ };
1458
+ return /* @__PURE__ */ jsxs(File, {
1459
+ baseName: type.file.baseName,
1460
+ path: type.file.path,
1461
+ meta: type.file.meta,
1462
+ banner: resolver.resolveBanner(adapter.rootNode, {
1463
+ output,
1464
+ config
1465
+ }),
1466
+ footer: resolver.resolveFooter(adapter.rootNode, {
1467
+ output,
1468
+ config
1469
+ }),
1470
+ children: [mode === "split" && imports.map((imp) => /* @__PURE__ */ jsx(File.Import, {
1471
+ root: type.file.path,
1472
+ path: imp.path,
1473
+ name: imp.name,
1474
+ isTypeOnly: true
1475
+ }, [
1476
+ node.name,
1477
+ imp.path,
1478
+ imp.isTypeOnly
1479
+ ].join("-"))), /* @__PURE__ */ jsx(Type, {
1480
+ name: type.name,
1481
+ node: transformedNode,
1482
+ enumType,
1483
+ enumTypeSuffix,
1484
+ enumKeyCasing,
1485
+ optionalType,
1486
+ arrayType,
1487
+ syntaxType,
1488
+ resolver
1489
+ })]
1490
+ });
1491
+ }
1492
+ });
1493
+ //#endregion
1494
+ //#region src/presets.ts
1495
+ /**
1496
+ * Built-in preset registry for `@kubb/plugin-ts`.
1497
+ *
1498
+ * - `default` — uses `resolverTs` and `typeGenerator` (current naming conventions).
1499
+ * - `kubbV4` — uses `resolverTsLegacy` and `typeGeneratorLegacy` (Kubb v4 naming conventions).
1500
+ */
1501
+ const presets = definePresets({
1502
+ default: {
1503
+ name: "default",
1504
+ resolvers: [resolverTs],
1505
+ generators: [typeGenerator]
1506
+ },
1507
+ kubbV4: {
1508
+ name: "kubbV4",
1509
+ resolvers: [resolverTsLegacy],
1510
+ generators: [typeGeneratorLegacy]
1511
+ }
1512
+ });
45
1513
  //#endregion
46
1514
  //#region src/plugin.ts
47
1515
  /**
@@ -69,7 +1537,9 @@ const pluginTs = createPlugin((options) => {
69
1537
  path: "types",
70
1538
  barrelType: "named"
71
1539
  }, group, exclude = [], include, override = [], enumType = "asConst", enumTypeSuffix = "Key", enumKeyCasing = "none", optionalType = "questionToken", arrayType = "array", syntaxType = "type", paramsCasing, compatibilityPreset = "default", resolvers: userResolvers = [], transformers: userTransformers = [], generators: userGenerators = [] } = options;
72
- const { resolver, transformers, generators } = getPreset$1(compatibilityPreset, {
1540
+ const preset = getPreset({
1541
+ preset: compatibilityPreset,
1542
+ presets,
73
1543
  resolvers: userResolvers,
74
1544
  transformers: userTransformers,
75
1545
  generators: userGenerators
@@ -78,25 +1548,35 @@ const pluginTs = createPlugin((options) => {
78
1548
  let resolvePathWarning = false;
79
1549
  return {
80
1550
  name: pluginTsName,
81
- options: {
82
- output,
83
- optionalType,
84
- group,
85
- arrayType,
86
- enumType,
87
- enumTypeSuffix,
88
- enumKeyCasing,
89
- syntaxType,
90
- paramsCasing,
91
- resolver,
92
- transformers
1551
+ get resolver() {
1552
+ return preset.resolver;
1553
+ },
1554
+ get options() {
1555
+ return {
1556
+ output,
1557
+ optionalType,
1558
+ group: group ? {
1559
+ ...options.group,
1560
+ name: (ctx) => {
1561
+ if (options.group?.type === "path") return `${ctx.group.split("/")[1]}`;
1562
+ return `${camelCase(ctx.group)}Controller`;
1563
+ }
1564
+ } : void 0,
1565
+ arrayType,
1566
+ enumType,
1567
+ enumTypeSuffix,
1568
+ enumKeyCasing,
1569
+ syntaxType,
1570
+ paramsCasing,
1571
+ transformers: preset.transformers
1572
+ };
93
1573
  },
94
1574
  resolvePath(baseName, pathMode, options) {
95
1575
  if (!resolvePathWarning) {
96
- this.driver.events.emit("warn", "Do not use resolvePath for pluginTs, use resolverTs.resolvePath instead");
1576
+ this.events.emit("warn", "Do not use resolvePath for pluginTs, use resolverTs.resolvePath instead");
97
1577
  resolvePathWarning = true;
98
1578
  }
99
- return resolver.resolvePath({
1579
+ return this.plugin.resolver.resolvePath({
100
1580
  baseName,
101
1581
  pathMode,
102
1582
  tag: options?.group?.tag,
@@ -104,25 +1584,25 @@ const pluginTs = createPlugin((options) => {
104
1584
  }, {
105
1585
  root: path.resolve(this.config.root, this.config.output.path),
106
1586
  output,
107
- group
1587
+ group: this.plugin.options.group
108
1588
  });
109
1589
  },
110
1590
  resolveName(name, type) {
111
1591
  if (!resolveNameWarning) {
112
- this.driver.events.emit("warn", "Do not use resolveName for pluginTs, use resolverTs.default instead");
1592
+ this.events.emit("warn", "Do not use resolveName for pluginTs, use resolverTs.default instead");
113
1593
  resolveNameWarning = true;
114
1594
  }
115
- return resolver.default(name, type);
1595
+ return this.plugin.resolver.default(name, type);
116
1596
  },
117
1597
  async install() {
118
- const { config, fabric, plugin, adapter, rootNode, driver, openInStudio } = this;
1598
+ const { config, fabric, plugin, adapter, rootNode, driver, openInStudio, resolver } = this;
119
1599
  const root = path.resolve(config.root, config.output.path);
120
1600
  if (!adapter) throw new Error("Plugin cannot work without adapter being set");
121
1601
  await openInStudio({ ast: true });
122
1602
  await walk(rootNode, {
123
1603
  depth: "shallow",
124
1604
  async schema(schemaNode) {
125
- const writeTasks = generators.map(async (generator) => {
1605
+ const writeTasks = preset.generators.map(async (generator) => {
126
1606
  if (generator.type === "react" && generator.version === "2") {
127
1607
  const options = resolver.resolveOptions(schemaNode, {
128
1608
  options: plugin.options,
@@ -133,6 +1613,7 @@ const pluginTs = createPlugin((options) => {
133
1613
  if (options === null) return;
134
1614
  await renderSchema(schemaNode, {
135
1615
  options,
1616
+ resolver,
136
1617
  adapter,
137
1618
  config,
138
1619
  fabric,
@@ -145,7 +1626,7 @@ const pluginTs = createPlugin((options) => {
145
1626
  await Promise.all(writeTasks);
146
1627
  },
147
1628
  async operation(operationNode) {
148
- const writeTasks = generators.map(async (generator) => {
1629
+ const writeTasks = preset.generators.map(async (generator) => {
149
1630
  if (generator.type === "react" && generator.version === "2") {
150
1631
  const options = resolver.resolveOptions(operationNode, {
151
1632
  options: plugin.options,
@@ -156,6 +1637,7 @@ const pluginTs = createPlugin((options) => {
156
1637
  if (options === null) return;
157
1638
  await renderOperation(operationNode, {
158
1639
  options,
1640
+ resolver,
159
1641
  adapter,
160
1642
  config,
161
1643
  fabric,
@@ -179,6 +1661,113 @@ const pluginTs = createPlugin((options) => {
179
1661
  };
180
1662
  });
181
1663
  //#endregion
182
- export { pluginTs, pluginTsName };
1664
+ //#region src/printers/functionPrinter.ts
1665
+ const kindToHandlerKey = {
1666
+ FunctionParameter: "functionParameter",
1667
+ ParameterGroup: "parameterGroup",
1668
+ FunctionParameters: "functionParameters",
1669
+ Type: "type"
1670
+ };
1671
+ /**
1672
+ * Creates a function-parameter printer factory.
1673
+ *
1674
+ * Uses `createPrinterFactory` and dispatches handlers by `node.kind`
1675
+ * (for function nodes) rather than by `node.type` (for schema nodes).
1676
+ */
1677
+ const defineFunctionPrinter = createPrinterFactory((node) => kindToHandlerKey[node.kind]);
1678
+ function rank(param) {
1679
+ if (param.kind === "ParameterGroup") {
1680
+ if (param.default) return 2;
1681
+ return param.optional ?? param.properties.every((p) => p.optional || p.default !== void 0) ? 1 : 0;
1682
+ }
1683
+ if (param.rest) return 3;
1684
+ if (param.default) return 2;
1685
+ return param.optional ? 1 : 0;
1686
+ }
1687
+ function sortParams(params) {
1688
+ return [...params].sort((a, b) => rank(a) - rank(b));
1689
+ }
1690
+ function sortChildParams(params) {
1691
+ return [...params].sort((a, b) => rank(a) - rank(b));
1692
+ }
1693
+ /**
1694
+ * Default function-signature printer.
1695
+ * Covers the four standard output modes used across Kubb plugins.
1696
+ *
1697
+ * @example
1698
+ * ```ts
1699
+ * const printer = functionPrinter({ mode: 'declaration' })
1700
+ *
1701
+ * const sig = createFunctionParameters({
1702
+ * params: [
1703
+ * createFunctionParameter({ name: 'petId', type: 'string', optional: false }),
1704
+ * createFunctionParameter({ name: 'config', type: 'Config', optional: false, default: '{}' }),
1705
+ * ],
1706
+ * })
1707
+ *
1708
+ * printer.print(sig) // → "petId: string, config: Config = {}"
1709
+ * ```
1710
+ */
1711
+ const functionPrinter = defineFunctionPrinter((options) => ({
1712
+ name: "functionParameters",
1713
+ options,
1714
+ nodes: {
1715
+ type(node) {
1716
+ if (node.variant === "member") return `${node.base}['${node.key}']`;
1717
+ if (node.variant === "struct") return `{ ${node.properties.map((p) => {
1718
+ const typeStr = this.transform(p.type);
1719
+ return p.optional ? `${p.name}?: ${typeStr}` : `${p.name}: ${typeStr}`;
1720
+ }).join("; ")} }`;
1721
+ if (node.variant === "reference") return node.name;
1722
+ return null;
1723
+ },
1724
+ functionParameter(node) {
1725
+ const { mode, transformName, transformType } = this.options;
1726
+ const name = transformName ? transformName(node.name) : node.name;
1727
+ const rawType = node.type ? this.transform(node.type) : void 0;
1728
+ const type = rawType != null && transformType ? transformType(rawType) : rawType;
1729
+ if (mode === "keys" || mode === "values") return node.rest ? `...${name}` : name;
1730
+ if (mode === "call") return node.rest ? `...${name}` : name;
1731
+ if (node.rest) return type ? `...${name}: ${type}` : `...${name}`;
1732
+ if (type) {
1733
+ if (node.optional) return `${name}?: ${type}`;
1734
+ return node.default ? `${name}: ${type} = ${node.default}` : `${name}: ${type}`;
1735
+ }
1736
+ return node.default ? `${name} = ${node.default}` : name;
1737
+ },
1738
+ parameterGroup(node) {
1739
+ const { mode, transformName, transformType } = this.options;
1740
+ const sorted = sortChildParams(node.properties);
1741
+ const isOptional = node.optional ?? sorted.every((p) => p.optional || p.default !== void 0);
1742
+ if (node.inline) return sorted.map((p) => this.transform(p)).filter(Boolean).join(", ");
1743
+ if (mode === "keys" || mode === "values") return `{ ${sorted.map((p) => p.name).join(", ")} }`;
1744
+ if (mode === "call") return `{ ${sorted.map((p) => p.name).join(", ")} }`;
1745
+ const names = sorted.map((p) => {
1746
+ return transformName ? transformName(p.name) : p.name;
1747
+ });
1748
+ const nameStr = names.length ? `{ ${names.join(", ")} }` : void 0;
1749
+ if (!nameStr) return null;
1750
+ let typeAnnotation = node.type ? this.transform(node.type) ?? void 0 : void 0;
1751
+ if (!typeAnnotation) {
1752
+ const typeParts = sorted.filter((p) => p.type).map((p) => {
1753
+ const rawT = p.type ? this.transform(p.type) : void 0;
1754
+ const t = rawT != null && transformType ? transformType(rawT) : rawT;
1755
+ return p.optional || p.default !== void 0 ? `${p.name}?: ${t}` : `${p.name}: ${t}`;
1756
+ });
1757
+ typeAnnotation = typeParts.length ? `{ ${typeParts.join("; ")} }` : void 0;
1758
+ }
1759
+ if (typeAnnotation) {
1760
+ if (isOptional) return `${nameStr}: ${typeAnnotation} = ${node.default ?? "{}"}`;
1761
+ return node.default ? `${nameStr}: ${typeAnnotation} = ${node.default}` : `${nameStr}: ${typeAnnotation}`;
1762
+ }
1763
+ return node.default ? `${nameStr} = ${node.default}` : nameStr;
1764
+ },
1765
+ functionParameters(node) {
1766
+ return sortParams(node.params).map((p) => this.transform(p)).filter(Boolean).join(", ");
1767
+ }
1768
+ }
1769
+ }));
1770
+ //#endregion
1771
+ export { Enum, Type, functionPrinter, pluginTs, pluginTsName, printerTs, resolverTs, resolverTsLegacy, typeGenerator };
183
1772
 
184
1773
  //# sourceMappingURL=index.js.map