@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/README.md +39 -22
- package/dist/index.cjs +513 -266
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +168 -144
- package/dist/index.js +506 -263
- package/dist/index.js.map +1 -1
- package/package.json +13 -22
- package/src/components/Enum.tsx +33 -29
- package/src/components/Type.tsx +6 -11
- package/src/constants.ts +7 -7
- package/src/factory.ts +58 -62
- package/src/generators/typeGenerator.tsx +118 -77
- package/src/plugin.ts +30 -28
- package/src/printers/functionPrinter.ts +2 -2
- package/src/printers/printerTs.ts +44 -54
- package/src/resolvers/resolverTs.ts +28 -25
- package/src/types.ts +113 -86
- package/src/utils.ts +24 -14
- package/extension.yaml +0 -632
- /package/dist/{chunk--u3MIqq1.js → chunk-C0LytTxp.js} +0 -0
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
|
-
|
|
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')
|
|
67
|
-
*
|
|
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, {
|
|
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')
|
|
82
|
-
*
|
|
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, {
|
|
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')
|
|
96
|
-
*
|
|
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/
|
|
101
|
+
//#region ../../internals/utils/src/fs.ts
|
|
115
102
|
/**
|
|
116
|
-
*
|
|
117
|
-
*
|
|
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
|
-
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
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
|
-
*
|
|
133
|
-
*
|
|
134
|
-
|
|
135
|
-
|
|
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
|
-
*
|
|
219
|
+
* isValidVarName('status') // true
|
|
220
|
+
* isValidVarName('class') // false (reserved word)
|
|
221
|
+
* isValidVarName('42foo') // false (starts with digit)
|
|
140
222
|
* ```
|
|
141
223
|
*/
|
|
142
|
-
function
|
|
143
|
-
|
|
144
|
-
|
|
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
|
-
*
|
|
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
|
-
*
|
|
163
|
-
*
|
|
237
|
+
* ```ts
|
|
238
|
+
* ensureValidVarName('409') // '_409'
|
|
239
|
+
* ensureValidVarName('504AccountCancel') // '_504AccountCancel'
|
|
240
|
+
* ensureValidVarName('Pet') // 'Pet'
|
|
241
|
+
* ensureValidVarName('class') // '_class'
|
|
242
|
+
* ```
|
|
164
243
|
*/
|
|
165
|
-
function
|
|
166
|
-
if (
|
|
167
|
-
return
|
|
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
|
-
* `
|
|
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"
|
|
261
|
+
const ENUM_TYPES_WITH_KEY_SUFFIX = new Set(["asConst"]);
|
|
183
262
|
/**
|
|
184
|
-
* `
|
|
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
|
-
* `
|
|
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
|
-
|
|
235
|
-
|
|
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(
|
|
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 (
|
|
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(
|
|
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(
|
|
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 &&
|
|
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 (
|
|
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(
|
|
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 (
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
620
|
-
*
|
|
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,
|
|
710
|
+
function getEnumNames({ node, enum: enumOptions, resolver }) {
|
|
623
711
|
const resolved = resolver.default(node.name, "type");
|
|
624
712
|
return {
|
|
625
|
-
enumName:
|
|
626
|
-
typeName: ENUM_TYPES_WITH_KEY_SUFFIX.has(
|
|
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 `
|
|
633
|
-
* - A runtime object (`asConst`
|
|
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,
|
|
728
|
+
function Enum({ node, enum: enumOptions, resolver }) {
|
|
641
729
|
const { enumName, typeName } = getEnumNames({
|
|
642
730
|
node,
|
|
643
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
663
|
-
isExportable: ENUM_TYPES_WITH_RUNTIME_VALUE.has(
|
|
664
|
-
isTypeOnly: ENUM_TYPES_WITH_TYPE_ONLY.has(
|
|
665
|
-
children:
|
|
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,
|
|
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
|
-
|
|
683
|
-
enumTypeSuffix,
|
|
770
|
+
enum: enumOptions,
|
|
684
771
|
resolver
|
|
685
772
|
})
|
|
686
773
|
};
|
|
687
774
|
});
|
|
688
|
-
const shouldExportEnums =
|
|
689
|
-
const shouldExportType =
|
|
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
|
-
|
|
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
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
!isArray && meta && "
|
|
721
|
-
meta && "
|
|
722
|
-
meta && "
|
|
723
|
-
meta && "
|
|
724
|
-
meta && "
|
|
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
|
|
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',
|
|
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',
|
|
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 ?
|
|
891
|
-
return createTypeReferenceNode(node.ref && ENUM_TYPES_WITH_KEY_SUFFIX.has(this.options.
|
|
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.
|
|
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(
|
|
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.
|
|
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(
|
|
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
|
-
}) ??
|
|
1105
|
+
}) ?? null;
|
|
927
1106
|
},
|
|
928
1107
|
array(node) {
|
|
929
1108
|
return createArrayDeclaration({
|
|
930
|
-
nodes: (node.items ?? []).map((item) => this.transform(item)).filter(
|
|
1109
|
+
nodes: (node.items ?? []).map((item) => this.transform(item)).filter(isNonNullable),
|
|
931
1110
|
arrayType: this.options.arrayType
|
|
932
|
-
}) ??
|
|
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
|
-
|
|
963
|
-
if (!
|
|
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
|
-
|
|
967
|
-
|
|
968
|
-
return
|
|
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
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
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:
|
|
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 {
|
|
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
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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: [
|
|
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
|
-
|
|
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 {
|
|
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(
|
|
1278
|
+
const enumSchemaNames = new Set(ctx.meta.enumNames);
|
|
1089
1279
|
function resolveImportName(schemaName) {
|
|
1090
|
-
if (ENUM_TYPES_WITH_KEY_SUFFIX.has(
|
|
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
|
-
|
|
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: [
|
|
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
|
-
|
|
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
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
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
|
-
|
|
1167
|
-
|
|
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(
|
|
1170
|
-
if (new Set(responsesWithSchema.flatMap((res) => res.schema ? adapter.getImports(
|
|
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(
|
|
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(
|
|
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
|
-
*
|
|
1209
|
-
*
|
|
1210
|
-
*
|
|
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
|
|
1213
|
-
*
|
|
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 {
|
|
1455
|
+
* import { resolverTs } from '@kubb/plugin-ts'
|
|
1218
1456
|
*
|
|
1219
|
-
*
|
|
1220
|
-
*
|
|
1221
|
-
*
|
|
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)((
|
|
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
|
-
|
|
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
|
-
|
|
1474
|
+
if (type === "file") return toFilePath(name, pascalCase);
|
|
1475
|
+
return ensureValidVarName(pascalCase(name));
|
|
1236
1476
|
},
|
|
1237
1477
|
resolveParamName(node, param) {
|
|
1238
|
-
return
|
|
1478
|
+
return this.resolveTypeName(`${node.operationId} ${param.in} ${param.name}`);
|
|
1239
1479
|
},
|
|
1240
1480
|
resolveResponseStatusName(node, statusCode) {
|
|
1241
|
-
return
|
|
1481
|
+
return this.resolveTypeName(`${node.operationId} Status ${statusCode}`);
|
|
1242
1482
|
},
|
|
1243
1483
|
resolveDataName(node) {
|
|
1244
|
-
return
|
|
1484
|
+
return this.resolveTypeName(`${node.operationId} Data`);
|
|
1245
1485
|
},
|
|
1246
1486
|
resolveRequestConfigName(node) {
|
|
1247
|
-
return
|
|
1487
|
+
return this.resolveTypeName(`${node.operationId} RequestConfig`);
|
|
1248
1488
|
},
|
|
1249
1489
|
resolveResponsesName(node) {
|
|
1250
|
-
return
|
|
1490
|
+
return this.resolveTypeName(`${node.operationId} Responses`);
|
|
1251
1491
|
},
|
|
1252
1492
|
resolveResponseName(node) {
|
|
1253
|
-
return
|
|
1493
|
+
return this.resolveTypeName(`${node.operationId} Response`);
|
|
1254
1494
|
},
|
|
1255
1495
|
resolveEnumKeyName(node, enumTypeSuffix = "key") {
|
|
1256
|
-
return `${
|
|
1496
|
+
return `${this.resolveTypeName(node.name ?? "")}${enumTypeSuffix}`;
|
|
1257
1497
|
},
|
|
1258
1498
|
resolvePathParamsName(node, param) {
|
|
1259
|
-
return
|
|
1499
|
+
return this.resolveParamName(node, param);
|
|
1260
1500
|
},
|
|
1261
1501
|
resolveQueryParamsName(node, param) {
|
|
1262
|
-
return
|
|
1502
|
+
return this.resolveParamName(node, param);
|
|
1263
1503
|
},
|
|
1264
1504
|
resolveHeaderParamsName(node, param) {
|
|
1265
|
-
return
|
|
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
|
|
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
|
-
*
|
|
1277
|
-
*
|
|
1278
|
-
*
|
|
1279
|
-
*
|
|
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
|
|
1524
|
+
* import { defineConfig } from 'kubb'
|
|
1525
|
+
* import { pluginTs } from '@kubb/plugin-ts'
|
|
1285
1526
|
*
|
|
1286
1527
|
* export default defineConfig({
|
|
1287
|
-
*
|
|
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
|
-
|
|
1295
|
-
}, group, exclude = [], include, override = [],
|
|
1296
|
-
const groupConfig = group
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
}
|
|
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
|
-
|
|
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
|
|
1604
|
+
return params.toSorted((a, b) => rank(a) - rank(b));
|
|
1358
1605
|
}
|
|
1359
1606
|
function sortChildParams(params) {
|
|
1360
|
-
return
|
|
1607
|
+
return params.toSorted((a, b) => rank(a) - rank(b));
|
|
1361
1608
|
}
|
|
1362
1609
|
/**
|
|
1363
1610
|
* Default function-signature printer.
|