@kubb/plugin-ts 5.0.0-beta.4 → 5.0.0-beta.42
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 +432 -126
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +84 -62
- package/dist/index.js +427 -125
- package/dist/index.js.map +1 -1
- package/extension.yaml +713 -265
- package/package.json +10 -12
- package/src/components/Enum.tsx +3 -3
- package/src/factory.ts +54 -25
- package/src/generators/typeGenerator.tsx +100 -39
- package/src/plugin.ts +20 -21
- package/src/printers/functionPrinter.ts +2 -2
- package/src/printers/printerTs.ts +31 -30
- package/src/resolvers/resolverTs.ts +28 -25
- package/src/types.ts +44 -37
- package/src/utils.ts +23 -13
- /package/dist/{chunk--u3MIqq1.js → chunk-C0LytTxp.js} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import "./chunk
|
|
2
|
-
import {
|
|
3
|
-
import { File,
|
|
1
|
+
import { t as __name } from "./chunk-C0LytTxp.js";
|
|
2
|
+
import { parserTs } from "@kubb/parser-ts";
|
|
3
|
+
import { File, jsxRendererSync } from "@kubb/renderer-jsx";
|
|
4
4
|
import { ast, defineGenerator, definePlugin, defineResolver } from "@kubb/core";
|
|
5
|
-
import { isNumber } from "remeda";
|
|
6
5
|
import ts from "typescript";
|
|
7
6
|
import { Fragment, jsx, jsxs } from "@kubb/renderer-jsx/jsx-runtime";
|
|
8
7
|
//#region ../../internals/utils/src/casing.ts
|
|
@@ -141,6 +140,129 @@ function stringify(value) {
|
|
|
141
140
|
return JSON.stringify(trimQuotes(value.toString()));
|
|
142
141
|
}
|
|
143
142
|
//#endregion
|
|
143
|
+
//#region ../../internals/utils/src/reserved.ts
|
|
144
|
+
/**
|
|
145
|
+
* JavaScript and Java reserved words.
|
|
146
|
+
* @link https://github.com/jonschlinkert/reserved/blob/master/index.js
|
|
147
|
+
*/
|
|
148
|
+
const reservedWords = new Set([
|
|
149
|
+
"abstract",
|
|
150
|
+
"arguments",
|
|
151
|
+
"boolean",
|
|
152
|
+
"break",
|
|
153
|
+
"byte",
|
|
154
|
+
"case",
|
|
155
|
+
"catch",
|
|
156
|
+
"char",
|
|
157
|
+
"class",
|
|
158
|
+
"const",
|
|
159
|
+
"continue",
|
|
160
|
+
"debugger",
|
|
161
|
+
"default",
|
|
162
|
+
"delete",
|
|
163
|
+
"do",
|
|
164
|
+
"double",
|
|
165
|
+
"else",
|
|
166
|
+
"enum",
|
|
167
|
+
"eval",
|
|
168
|
+
"export",
|
|
169
|
+
"extends",
|
|
170
|
+
"false",
|
|
171
|
+
"final",
|
|
172
|
+
"finally",
|
|
173
|
+
"float",
|
|
174
|
+
"for",
|
|
175
|
+
"function",
|
|
176
|
+
"goto",
|
|
177
|
+
"if",
|
|
178
|
+
"implements",
|
|
179
|
+
"import",
|
|
180
|
+
"in",
|
|
181
|
+
"instanceof",
|
|
182
|
+
"int",
|
|
183
|
+
"interface",
|
|
184
|
+
"let",
|
|
185
|
+
"long",
|
|
186
|
+
"native",
|
|
187
|
+
"new",
|
|
188
|
+
"null",
|
|
189
|
+
"package",
|
|
190
|
+
"private",
|
|
191
|
+
"protected",
|
|
192
|
+
"public",
|
|
193
|
+
"return",
|
|
194
|
+
"short",
|
|
195
|
+
"static",
|
|
196
|
+
"super",
|
|
197
|
+
"switch",
|
|
198
|
+
"synchronized",
|
|
199
|
+
"this",
|
|
200
|
+
"throw",
|
|
201
|
+
"throws",
|
|
202
|
+
"transient",
|
|
203
|
+
"true",
|
|
204
|
+
"try",
|
|
205
|
+
"typeof",
|
|
206
|
+
"var",
|
|
207
|
+
"void",
|
|
208
|
+
"volatile",
|
|
209
|
+
"while",
|
|
210
|
+
"with",
|
|
211
|
+
"yield",
|
|
212
|
+
"Array",
|
|
213
|
+
"Date",
|
|
214
|
+
"hasOwnProperty",
|
|
215
|
+
"Infinity",
|
|
216
|
+
"isFinite",
|
|
217
|
+
"isNaN",
|
|
218
|
+
"isPrototypeOf",
|
|
219
|
+
"length",
|
|
220
|
+
"Math",
|
|
221
|
+
"name",
|
|
222
|
+
"NaN",
|
|
223
|
+
"Number",
|
|
224
|
+
"Object",
|
|
225
|
+
"prototype",
|
|
226
|
+
"String",
|
|
227
|
+
"toString",
|
|
228
|
+
"undefined",
|
|
229
|
+
"valueOf"
|
|
230
|
+
]);
|
|
231
|
+
/**
|
|
232
|
+
* Returns `true` when `name` is a syntactically valid JavaScript variable name.
|
|
233
|
+
*
|
|
234
|
+
* @example
|
|
235
|
+
* ```ts
|
|
236
|
+
* isValidVarName('status') // true
|
|
237
|
+
* isValidVarName('class') // false (reserved word)
|
|
238
|
+
* isValidVarName('42foo') // false (starts with digit)
|
|
239
|
+
* ```
|
|
240
|
+
*/
|
|
241
|
+
function isValidVarName(name) {
|
|
242
|
+
if (!name || reservedWords.has(name)) return false;
|
|
243
|
+
return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Returns `name` when it's a syntactically valid JavaScript variable name,
|
|
247
|
+
* otherwise prefixes it with `_` so the result is a valid identifier.
|
|
248
|
+
*
|
|
249
|
+
* Useful for sanitizing OpenAPI schema names or operation IDs that start with
|
|
250
|
+
* a digit (e.g. `409`, `504AccountCancel`) before using them as exported
|
|
251
|
+
* variable, type, or function names.
|
|
252
|
+
*
|
|
253
|
+
* @example
|
|
254
|
+
* ```ts
|
|
255
|
+
* ensureValidVarName('409') // '_409'
|
|
256
|
+
* ensureValidVarName('504AccountCancel') // '_504AccountCancel'
|
|
257
|
+
* ensureValidVarName('Pet') // 'Pet'
|
|
258
|
+
* ensureValidVarName('class') // '_class'
|
|
259
|
+
* ```
|
|
260
|
+
*/
|
|
261
|
+
function ensureValidVarName(name) {
|
|
262
|
+
if (!name || isValidVarName(name)) return name;
|
|
263
|
+
return `_${name}`;
|
|
264
|
+
}
|
|
265
|
+
//#endregion
|
|
144
266
|
//#region src/constants.ts
|
|
145
267
|
/**
|
|
146
268
|
* `optionalType` values that cause a property's type to include `| undefined`.
|
|
@@ -186,6 +308,9 @@ const PARAM_RANK = {
|
|
|
186
308
|
//#endregion
|
|
187
309
|
//#region src/factory.ts
|
|
188
310
|
const { SyntaxKind, factory } = ts;
|
|
311
|
+
function isNumber(value) {
|
|
312
|
+
return typeof value === "number" && !Number.isNaN(value);
|
|
313
|
+
}
|
|
189
314
|
/**
|
|
190
315
|
* TypeScript AST modifiers for common keywords (async, export, const, static).
|
|
191
316
|
*/
|
|
@@ -203,10 +328,19 @@ const syntaxKind = {
|
|
|
203
328
|
literalType: SyntaxKind.LiteralType,
|
|
204
329
|
stringLiteral: SyntaxKind.StringLiteral
|
|
205
330
|
};
|
|
331
|
+
function isNonNullable$1(value) {
|
|
332
|
+
return value !== null && value !== void 0;
|
|
333
|
+
}
|
|
334
|
+
__name(isNonNullable$1, "isNonNullable");
|
|
206
335
|
function isValidIdentifier(str) {
|
|
207
336
|
if (!str.length || str.trim() !== str) return false;
|
|
208
|
-
|
|
209
|
-
|
|
337
|
+
let ch = str.codePointAt(0);
|
|
338
|
+
if (!ts.isIdentifierStart(ch, ts.ScriptTarget.Latest)) return false;
|
|
339
|
+
for (let i = ch > 65535 ? 2 : 1; i < str.length; i += ch > 65535 ? 2 : 1) {
|
|
340
|
+
ch = str.codePointAt(i);
|
|
341
|
+
if (!ts.isIdentifierPart(ch, ts.ScriptTarget.Latest)) return false;
|
|
342
|
+
}
|
|
343
|
+
return true;
|
|
210
344
|
}
|
|
211
345
|
function propertyName(name) {
|
|
212
346
|
if (typeof name === "string") return isValidIdentifier(name) ? factory.createIdentifier(name) : factory.createStringLiteral(name);
|
|
@@ -272,7 +406,7 @@ function createUnionDeclaration({ nodes, withParentheses }) {
|
|
|
272
406
|
* Supports optional markers, readonly modifiers, and type annotations.
|
|
273
407
|
*/
|
|
274
408
|
function createPropertySignature({ readOnly, modifiers = [], name, questionToken, type }) {
|
|
275
|
-
return factory.createPropertySignature([...modifiers, readOnly ? factory.createToken(ts.SyntaxKind.ReadonlyKeyword) : void 0].filter(
|
|
409
|
+
return factory.createPropertySignature([...modifiers, readOnly ? factory.createToken(ts.SyntaxKind.ReadonlyKeyword) : void 0].filter((modifier) => modifier !== void 0), propertyName(name), createQuestionToken(questionToken), type);
|
|
276
410
|
}
|
|
277
411
|
/**
|
|
278
412
|
* Creates a function parameter declaration with optional markers, rest parameters, and type annotations.
|
|
@@ -370,8 +504,8 @@ function createEnumDeclaration({ type = "enum", name, typeName, enums, enumKeyCa
|
|
|
370
504
|
}
|
|
371
505
|
if (typeof value === "boolean") return factory.createLiteralTypeNode(value ? factory.createTrue() : factory.createFalse());
|
|
372
506
|
if (value) return factory.createLiteralTypeNode(factory.createStringLiteral(value.toString()));
|
|
373
|
-
}).filter(
|
|
374
|
-
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(
|
|
507
|
+
}).filter((node) => node !== void 0)))];
|
|
508
|
+
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((modifier) => modifier !== void 0), factory.createIdentifier(typeName), enums.map(([key, value]) => {
|
|
375
509
|
let initializer = factory.createStringLiteral(value?.toString());
|
|
376
510
|
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)));
|
|
377
511
|
else initializer = factory.createNumericLiteral(value);
|
|
@@ -384,7 +518,7 @@ function createEnumDeclaration({ type = "enum", name, typeName, enums, enumKeyCa
|
|
|
384
518
|
const casingKey = applyEnumKeyCasing(key.toString(), enumKeyCasing);
|
|
385
519
|
return factory.createEnumMember(propertyName(casingKey), initializer);
|
|
386
520
|
}
|
|
387
|
-
}).filter(
|
|
521
|
+
}).filter((member) => member !== void 0))];
|
|
388
522
|
const identifierName = name;
|
|
389
523
|
if (enums.length === 0) return [void 0, factory.createTypeAliasDeclaration([factory.createToken(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier(typeName), void 0, factory.createKeywordTypeNode(ts.SyntaxKind.NeverKeyword))];
|
|
390
524
|
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]) => {
|
|
@@ -396,7 +530,7 @@ function createEnumDeclaration({ type = "enum", name, typeName, enums, enumKeyCa
|
|
|
396
530
|
const casingKey = applyEnumKeyCasing(key.toString(), enumKeyCasing);
|
|
397
531
|
return factory.createPropertyAssignment(propertyName(casingKey), initializer);
|
|
398
532
|
}
|
|
399
|
-
}).filter(
|
|
533
|
+
}).filter((property) => property !== void 0), 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))))];
|
|
400
534
|
}
|
|
401
535
|
/**
|
|
402
536
|
* Creates a TypeScript `Omit<T, Keys>` type reference node.
|
|
@@ -536,14 +670,14 @@ function dateOrStringNode(node) {
|
|
|
536
670
|
* Maps an array of `SchemaNode`s through the printer, filtering out `null` and `undefined` results.
|
|
537
671
|
*/
|
|
538
672
|
function buildMemberNodes(members, print) {
|
|
539
|
-
return (members ?? []).map(print).filter(
|
|
673
|
+
return (members ?? []).map(print).filter(isNonNullable$1);
|
|
540
674
|
}
|
|
541
675
|
/**
|
|
542
676
|
* Builds a TypeScript tuple type node from an array schema's `items`,
|
|
543
677
|
* applying min/max slice and optional/rest element rules.
|
|
544
678
|
*/
|
|
545
679
|
function buildTupleNode(node, print) {
|
|
546
|
-
let items = (node.items ?? []).map(print).filter(
|
|
680
|
+
let items = (node.items ?? []).map(print).filter(isNonNullable$1);
|
|
547
681
|
const restNode = node.rest ? print(node.rest) ?? void 0 : void 0;
|
|
548
682
|
const { min, max } = node;
|
|
549
683
|
if (max !== void 0) {
|
|
@@ -630,13 +764,13 @@ function Enum({ node, enumType, enumTypeSuffix, enumKeyCasing, resolver }) {
|
|
|
630
764
|
isExportable: true,
|
|
631
765
|
isIndexable: true,
|
|
632
766
|
isTypeOnly: false,
|
|
633
|
-
children:
|
|
767
|
+
children: parserTs.print(nameNode)
|
|
634
768
|
}), /* @__PURE__ */ jsx(File.Source, {
|
|
635
769
|
name: typeName,
|
|
636
770
|
isIndexable: true,
|
|
637
771
|
isExportable: ENUM_TYPES_WITH_RUNTIME_VALUE.has(enumType),
|
|
638
772
|
isTypeOnly: ENUM_TYPES_WITH_TYPE_ONLY.has(enumType),
|
|
639
|
-
children:
|
|
773
|
+
children: parserTs.print(typeNode)
|
|
640
774
|
})] });
|
|
641
775
|
}
|
|
642
776
|
//#endregion
|
|
@@ -676,6 +810,98 @@ function Type({ name, node, printer, enumType, enumTypeSuffix, enumKeyCasing, re
|
|
|
676
810
|
})] });
|
|
677
811
|
}
|
|
678
812
|
//#endregion
|
|
813
|
+
//#region ../../internals/shared/src/operation.ts
|
|
814
|
+
/**
|
|
815
|
+
* Maps a content type to the PascalCase suffix used to name per-content-type variants
|
|
816
|
+
* (e.g. `application/json` → `Json`, `application/xml` → `Xml`, `multipart/form-data` → `FormData`).
|
|
817
|
+
*/
|
|
818
|
+
function getContentTypeSuffix(contentType) {
|
|
819
|
+
const baseType = contentType.split(";")[0].trim();
|
|
820
|
+
if (baseType === "application/json") return "Json";
|
|
821
|
+
if (baseType === "multipart/form-data") return "FormData";
|
|
822
|
+
if (baseType === "application/x-www-form-urlencoded") return "FormUrlEncoded";
|
|
823
|
+
const parts = (baseType.split("/").pop() ?? baseType).split(/[^a-zA-Z0-9]+/).filter(Boolean);
|
|
824
|
+
if (parts.length === 0) return "Unknown";
|
|
825
|
+
return parts.map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
826
|
+
}
|
|
827
|
+
/**
|
|
828
|
+
* Appends a content-type suffix to a base name, keeping a trailing `Data` segment last
|
|
829
|
+
* (e.g. `AddPetData` + `Json` → `AddPetJsonData`, `AddPetStatus200` + `Xml` → `AddPetStatus200Xml`).
|
|
830
|
+
*/
|
|
831
|
+
function getPerContentTypeName(baseName, suffix) {
|
|
832
|
+
if (baseName.endsWith("Data")) return suffix.endsWith("Data") ? baseName.slice(0, -4) + suffix : `${baseName.slice(0, -4)}${suffix}Data`;
|
|
833
|
+
return baseName + suffix;
|
|
834
|
+
}
|
|
835
|
+
/**
|
|
836
|
+
* Resolves per-content-type variant names for a set of content entries, deduplicating suffix
|
|
837
|
+
* collisions with a numeric counter. Entries without a schema are skipped. The returned `suffix` is
|
|
838
|
+
* the final (possibly counter-augmented) value, so callers can derive parallel names in another
|
|
839
|
+
* namespace (e.g. plugin-faker deriving the matching plugin-ts type name).
|
|
840
|
+
*/
|
|
841
|
+
function resolveContentTypeVariants(entries, baseName) {
|
|
842
|
+
const usedNames = /* @__PURE__ */ new Set();
|
|
843
|
+
return entries.filter((entry) => entry.schema).map((entry) => {
|
|
844
|
+
const baseSuffix = getContentTypeSuffix(entry.contentType);
|
|
845
|
+
let suffix = baseSuffix;
|
|
846
|
+
let name = getPerContentTypeName(baseName, suffix);
|
|
847
|
+
let counter = 2;
|
|
848
|
+
while (usedNames.has(name)) {
|
|
849
|
+
suffix = `${baseSuffix}${counter++}`;
|
|
850
|
+
name = getPerContentTypeName(baseName, suffix);
|
|
851
|
+
}
|
|
852
|
+
usedNames.add(name);
|
|
853
|
+
return {
|
|
854
|
+
name,
|
|
855
|
+
suffix,
|
|
856
|
+
schema: entry.schema,
|
|
857
|
+
keysToOmit: entry.keysToOmit,
|
|
858
|
+
contentType: entry.contentType
|
|
859
|
+
};
|
|
860
|
+
});
|
|
861
|
+
}
|
|
862
|
+
function getOperationParameters(node, options = {}) {
|
|
863
|
+
const params = ast.caseParams(node.parameters, options.paramsCasing);
|
|
864
|
+
return {
|
|
865
|
+
path: params.filter((param) => param.in === "path"),
|
|
866
|
+
query: params.filter((param) => param.in === "query"),
|
|
867
|
+
header: params.filter((param) => param.in === "header"),
|
|
868
|
+
cookie: params.filter((param) => param.in === "cookie")
|
|
869
|
+
};
|
|
870
|
+
}
|
|
871
|
+
//#endregion
|
|
872
|
+
//#region ../../internals/shared/src/group.ts
|
|
873
|
+
/**
|
|
874
|
+
* Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the
|
|
875
|
+
* shared default naming so every plugin groups output consistently:
|
|
876
|
+
*
|
|
877
|
+
* - `path` groups use the second path segment (`/pet/findByStatus` → `pet`).
|
|
878
|
+
* - other groups use `${camelCase(group)}${suffix}` (e.g. `petController`).
|
|
879
|
+
*
|
|
880
|
+
* A user-provided `group.name` always wins over the default namer, so callers stay in
|
|
881
|
+
* control of their output folders. Returns `null` when grouping is disabled, matching the
|
|
882
|
+
* per-plugin convention.
|
|
883
|
+
*
|
|
884
|
+
* @param group - The user-supplied group option, or `undefined` to disable grouping.
|
|
885
|
+
* @param options.suffix - Appended to non-`path` group names, e.g. `'Controller'` or `'Requests'`.
|
|
886
|
+
*
|
|
887
|
+
* @example
|
|
888
|
+
* ```ts
|
|
889
|
+
* createGroupConfig(group, { suffix: 'Controller' }) // plugin-ts, plugin-client, …
|
|
890
|
+
* createGroupConfig(group, { suffix: 'Requests' }) // plugin-cypress, plugin-mcp
|
|
891
|
+
* ```
|
|
892
|
+
*/
|
|
893
|
+
function createGroupConfig(group, options) {
|
|
894
|
+
if (!group) return null;
|
|
895
|
+
const defaultName = (ctx) => {
|
|
896
|
+
if (group.type === "path") return `${ctx.group.split("/")[1]}`;
|
|
897
|
+
return `${camelCase(ctx.group)}${options.suffix}`;
|
|
898
|
+
};
|
|
899
|
+
return {
|
|
900
|
+
...group,
|
|
901
|
+
name: group.name ? group.name : defaultName
|
|
902
|
+
};
|
|
903
|
+
}
|
|
904
|
+
//#endregion
|
|
679
905
|
//#region src/utils.ts
|
|
680
906
|
/**
|
|
681
907
|
* Collects JSDoc annotation strings for a schema node.
|
|
@@ -687,15 +913,18 @@ function Type({ name, node, printer, enumType, enumTypeSuffix, enumKeyCasing, re
|
|
|
687
913
|
function buildPropertyJSDocComments(schema) {
|
|
688
914
|
const meta = ast.syncSchemaRef(schema);
|
|
689
915
|
const isArray = meta?.primitive === "array";
|
|
916
|
+
const hasDescription = meta && "description" in meta && meta.description;
|
|
917
|
+
const formatComment = meta && "format" in meta && meta.format ? hasDescription ? [" ", `Format: \`${meta.format}\``] : ["@description", `Format: \`${meta.format}\``] : [];
|
|
690
918
|
return [
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
!isArray && meta && "
|
|
695
|
-
meta && "
|
|
696
|
-
meta && "
|
|
697
|
-
meta && "
|
|
698
|
-
meta && "
|
|
919
|
+
hasDescription ? `@description ${jsStringEscape(meta.description)}` : null,
|
|
920
|
+
...formatComment,
|
|
921
|
+
meta && "deprecated" in meta && meta.deprecated ? "@deprecated" : null,
|
|
922
|
+
!isArray && meta && "min" in meta && meta.min !== void 0 ? `@minLength ${meta.min}` : null,
|
|
923
|
+
!isArray && meta && "max" in meta && meta.max !== void 0 ? `@maxLength ${meta.max}` : null,
|
|
924
|
+
meta && "pattern" in meta && meta.pattern ? `@pattern ${meta.pattern}` : null,
|
|
925
|
+
meta && "default" in meta && meta.default !== void 0 ? `@default ${"primitive" in meta && meta.primitive === "string" ? stringify(meta.default) : meta.default}` : null,
|
|
926
|
+
meta && "example" in meta && meta.example !== void 0 ? `@example ${meta.example}` : null,
|
|
927
|
+
meta && "primitive" in meta && meta.primitive ? [`@type ${meta.primitive}`, "optional" in schema && schema.optional ? " | undefined" : null].filter(Boolean).join("") : null
|
|
699
928
|
].filter(Boolean);
|
|
700
929
|
}
|
|
701
930
|
function buildParams(node, { params, resolver }) {
|
|
@@ -712,9 +941,7 @@ function buildParams(node, { params, resolver }) {
|
|
|
712
941
|
});
|
|
713
942
|
}
|
|
714
943
|
function buildData(node, { resolver }) {
|
|
715
|
-
const pathParams
|
|
716
|
-
const queryParams = node.parameters.filter((p) => p.in === "query");
|
|
717
|
-
const headerParams = node.parameters.filter((p) => p.in === "header");
|
|
944
|
+
const { path: pathParams, query: queryParams, header: headerParams } = getOperationParameters(node);
|
|
718
945
|
return ast.createSchema({
|
|
719
946
|
type: "object",
|
|
720
947
|
deprecated: node.deprecated,
|
|
@@ -796,7 +1023,7 @@ function buildResponses(node, { resolver }) {
|
|
|
796
1023
|
});
|
|
797
1024
|
}
|
|
798
1025
|
function buildResponseUnion(node, { resolver }) {
|
|
799
|
-
const responsesWithSchema = node.responses.filter((res) => res.schema);
|
|
1026
|
+
const responsesWithSchema = node.responses.filter((res) => res.content?.some((entry) => entry.schema));
|
|
800
1027
|
if (responsesWithSchema.length === 0) return null;
|
|
801
1028
|
return ast.createSchema({
|
|
802
1029
|
type: "union",
|
|
@@ -808,6 +1035,9 @@ function buildResponseUnion(node, { resolver }) {
|
|
|
808
1035
|
}
|
|
809
1036
|
//#endregion
|
|
810
1037
|
//#region src/printers/printerTs.ts
|
|
1038
|
+
function isNonNullable(value) {
|
|
1039
|
+
return value !== null && value !== void 0;
|
|
1040
|
+
}
|
|
811
1041
|
/**
|
|
812
1042
|
* TypeScript type printer built with `definePrinter`.
|
|
813
1043
|
*
|
|
@@ -860,7 +1090,7 @@ const printerTs = ast.definePrinter((options) => {
|
|
|
860
1090
|
date: dateOrStringNode,
|
|
861
1091
|
time: dateOrStringNode,
|
|
862
1092
|
ref(node) {
|
|
863
|
-
if (!node.name) return;
|
|
1093
|
+
if (!node.name) return null;
|
|
864
1094
|
const refName = node.ref ? ast.extractRefName(node.ref) ?? node.name : node.name;
|
|
865
1095
|
return createTypeReferenceNode(node.ref && ENUM_TYPES_WITH_KEY_SUFFIX.has(this.options.enumType) && this.options.enumTypeSuffix && this.options.enumSchemaNames?.has(refName) ? this.options.resolver.resolveEnumKeyName({ name: refName }, this.options.enumTypeSuffix) : node.ref ? this.options.resolver.default(refName, "type") : refName, void 0);
|
|
866
1096
|
},
|
|
@@ -868,7 +1098,7 @@ const printerTs = ast.definePrinter((options) => {
|
|
|
868
1098
|
const values = node.namedEnumValues?.map((v) => v.value) ?? node.enumValues ?? [];
|
|
869
1099
|
if (this.options.enumType === "inlineLiteral" || !node.name) return createUnionDeclaration({
|
|
870
1100
|
withParentheses: true,
|
|
871
|
-
nodes: values.filter((v) => v !== null && v !== void 0).map((value) => constToTypeNode(value, typeof value)).filter(
|
|
1101
|
+
nodes: values.filter((v) => v !== null && v !== void 0).map((value) => constToTypeNode(value, typeof value)).filter(isNonNullable)
|
|
872
1102
|
}) ?? void 0;
|
|
873
1103
|
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);
|
|
874
1104
|
},
|
|
@@ -886,7 +1116,7 @@ const printerTs = ast.definePrinter((options) => {
|
|
|
886
1116
|
withParentheses: true
|
|
887
1117
|
});
|
|
888
1118
|
return this.transform(m);
|
|
889
|
-
}).filter(
|
|
1119
|
+
}).filter(isNonNullable)
|
|
890
1120
|
}) ?? void 0;
|
|
891
1121
|
return createUnionDeclaration({
|
|
892
1122
|
withParentheses: true,
|
|
@@ -897,16 +1127,16 @@ const printerTs = ast.definePrinter((options) => {
|
|
|
897
1127
|
return createIntersectionDeclaration({
|
|
898
1128
|
withParentheses: true,
|
|
899
1129
|
nodes: buildMemberNodes(node.members, this.transform)
|
|
900
|
-
}) ??
|
|
1130
|
+
}) ?? null;
|
|
901
1131
|
},
|
|
902
1132
|
array(node) {
|
|
903
1133
|
return createArrayDeclaration({
|
|
904
|
-
nodes: (node.items ?? []).map((item) => this.transform(item)).filter(
|
|
1134
|
+
nodes: (node.items ?? []).map((item) => this.transform(item)).filter(isNonNullable),
|
|
905
1135
|
arrayType: this.options.arrayType
|
|
906
|
-
}) ??
|
|
1136
|
+
}) ?? null;
|
|
907
1137
|
},
|
|
908
1138
|
tuple(node) {
|
|
909
|
-
return buildTupleNode(node, this.transform);
|
|
1139
|
+
return buildTupleNode(node, this.transform) ?? null;
|
|
910
1140
|
},
|
|
911
1141
|
object(node) {
|
|
912
1142
|
const { transform, options } = this;
|
|
@@ -933,46 +1163,54 @@ const printerTs = ast.definePrinter((options) => {
|
|
|
933
1163
|
},
|
|
934
1164
|
print(node) {
|
|
935
1165
|
const { name, syntaxType = "type", description, keysToOmit } = this.options;
|
|
936
|
-
|
|
937
|
-
if (!
|
|
1166
|
+
const transformed = this.transform(node);
|
|
1167
|
+
if (!transformed) return null;
|
|
938
1168
|
const meta = ast.syncSchemaRef(node);
|
|
939
1169
|
if (!name) {
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
return
|
|
1170
|
+
const withNullable = meta.nullable ? createUnionDeclaration({ nodes: [transformed, keywordTypeNodes.null] }) : transformed;
|
|
1171
|
+
const result = (meta.nullish || meta.optional) && addsUndefined ? createUnionDeclaration({ nodes: [withNullable, keywordTypeNodes.undefined] }) : withNullable;
|
|
1172
|
+
return parserTs.print(result);
|
|
943
1173
|
}
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
1174
|
+
const inner = (() => {
|
|
1175
|
+
const omitted = keysToOmit?.length ? createOmitDeclaration({
|
|
1176
|
+
keys: keysToOmit,
|
|
1177
|
+
type: transformed,
|
|
1178
|
+
nonNullable: true
|
|
1179
|
+
}) : transformed;
|
|
1180
|
+
const withNullable = meta.nullable ? createUnionDeclaration({ nodes: [omitted, keywordTypeNodes.null] }) : omitted;
|
|
1181
|
+
return meta.nullish || meta.optional ? createUnionDeclaration({ nodes: [withNullable, keywordTypeNodes.undefined] }) : withNullable;
|
|
1182
|
+
})();
|
|
1183
|
+
const typeNode = createTypeDeclaration({
|
|
953
1184
|
name,
|
|
954
1185
|
isExportable: true,
|
|
955
1186
|
type: inner,
|
|
956
|
-
syntax:
|
|
1187
|
+
syntax: syntaxType === "type" || inner.kind === syntaxKind.union || !!keysToOmit?.length ? "type" : "interface",
|
|
957
1188
|
comments: buildPropertyJSDocComments({
|
|
958
1189
|
...meta,
|
|
959
1190
|
description
|
|
960
1191
|
})
|
|
961
|
-
})
|
|
1192
|
+
});
|
|
1193
|
+
return parserTs.print(typeNode);
|
|
962
1194
|
}
|
|
963
1195
|
};
|
|
964
1196
|
});
|
|
965
1197
|
//#endregion
|
|
966
1198
|
//#region src/generators/typeGenerator.tsx
|
|
1199
|
+
/**
|
|
1200
|
+
* Built-in generator for `@kubb/plugin-ts`. Emits one TypeScript file per
|
|
1201
|
+
* schema in the spec plus per-operation request, response, and parameter
|
|
1202
|
+
* types. Drop-replace with a custom `Generator<PluginTs>` to change how
|
|
1203
|
+
* TypeScript output is produced.
|
|
1204
|
+
*/
|
|
967
1205
|
const typeGenerator = defineGenerator({
|
|
968
1206
|
name: "typescript",
|
|
969
|
-
renderer:
|
|
1207
|
+
renderer: jsxRendererSync,
|
|
970
1208
|
schema(node, ctx) {
|
|
971
1209
|
const { enumType, enumTypeSuffix, enumKeyCasing, syntaxType, optionalType, arrayType, output, group, printer } = ctx.options;
|
|
972
1210
|
const { adapter, config, resolver, root } = ctx;
|
|
973
1211
|
if (!node.name) return;
|
|
974
1212
|
const mode = ctx.getMode(output);
|
|
975
|
-
const enumSchemaNames = new Set(
|
|
1213
|
+
const enumSchemaNames = new Set(ctx.meta.enumNames);
|
|
976
1214
|
function resolveImportName(schemaName) {
|
|
977
1215
|
if (ENUM_TYPES_WITH_KEY_SUFFIX.has(enumType) && enumTypeSuffix && enumSchemaNames.has(schemaName)) return resolver.resolveEnumKeyName({ name: schemaName }, enumTypeSuffix);
|
|
978
1216
|
return resolver.resolveTypeName(schemaName);
|
|
@@ -985,7 +1223,7 @@ const typeGenerator = defineGenerator({
|
|
|
985
1223
|
}, {
|
|
986
1224
|
root,
|
|
987
1225
|
output,
|
|
988
|
-
group
|
|
1226
|
+
group: group ?? void 0
|
|
989
1227
|
}).path
|
|
990
1228
|
}));
|
|
991
1229
|
const isEnumSchema = !!ast.narrowSchema(node, ast.schemaTypes.enum);
|
|
@@ -997,7 +1235,7 @@ const typeGenerator = defineGenerator({
|
|
|
997
1235
|
}, {
|
|
998
1236
|
root,
|
|
999
1237
|
output,
|
|
1000
|
-
group
|
|
1238
|
+
group: group ?? void 0
|
|
1001
1239
|
})
|
|
1002
1240
|
};
|
|
1003
1241
|
const schemaPrinter = printerTs({
|
|
@@ -1016,13 +1254,21 @@ const typeGenerator = defineGenerator({
|
|
|
1016
1254
|
baseName: meta.file.baseName,
|
|
1017
1255
|
path: meta.file.path,
|
|
1018
1256
|
meta: meta.file.meta,
|
|
1019
|
-
banner: resolver.resolveBanner(
|
|
1257
|
+
banner: resolver.resolveBanner(ctx.meta, {
|
|
1020
1258
|
output,
|
|
1021
|
-
config
|
|
1259
|
+
config,
|
|
1260
|
+
file: {
|
|
1261
|
+
path: meta.file.path,
|
|
1262
|
+
baseName: meta.file.baseName
|
|
1263
|
+
}
|
|
1022
1264
|
}),
|
|
1023
|
-
footer: resolver.resolveFooter(
|
|
1265
|
+
footer: resolver.resolveFooter(ctx.meta, {
|
|
1024
1266
|
output,
|
|
1025
|
-
config
|
|
1267
|
+
config,
|
|
1268
|
+
file: {
|
|
1269
|
+
path: meta.file.path,
|
|
1270
|
+
baseName: meta.file.baseName
|
|
1271
|
+
}
|
|
1026
1272
|
}),
|
|
1027
1273
|
children: [mode === "split" && imports.map((imp) => /* @__PURE__ */ jsx(File.Import, {
|
|
1028
1274
|
root: meta.file.path,
|
|
@@ -1057,9 +1303,9 @@ const typeGenerator = defineGenerator({
|
|
|
1057
1303
|
}, {
|
|
1058
1304
|
root,
|
|
1059
1305
|
output,
|
|
1060
|
-
group
|
|
1306
|
+
group: group ?? void 0
|
|
1061
1307
|
}) };
|
|
1062
|
-
const enumSchemaNames = new Set(
|
|
1308
|
+
const enumSchemaNames = new Set(ctx.meta.enumNames);
|
|
1063
1309
|
function resolveImportName(schemaName) {
|
|
1064
1310
|
if (ENUM_TYPES_WITH_KEY_SUFFIX.has(enumType) && enumTypeSuffix && enumSchemaNames.has(schemaName)) return resolver.resolveEnumKeyName({ name: schemaName }, enumTypeSuffix);
|
|
1065
1311
|
return resolver.resolveTypeName(schemaName);
|
|
@@ -1074,7 +1320,7 @@ const typeGenerator = defineGenerator({
|
|
|
1074
1320
|
}, {
|
|
1075
1321
|
root,
|
|
1076
1322
|
output,
|
|
1077
|
-
group
|
|
1323
|
+
group: group ?? void 0
|
|
1078
1324
|
}).path
|
|
1079
1325
|
}));
|
|
1080
1326
|
const schemaPrinter = printerTs({
|
|
@@ -1109,23 +1355,63 @@ const typeGenerator = defineGenerator({
|
|
|
1109
1355
|
printer: schemaPrinter
|
|
1110
1356
|
})] });
|
|
1111
1357
|
}
|
|
1358
|
+
/**
|
|
1359
|
+
* Emits an individual type per content type plus a union alias under `baseName`.
|
|
1360
|
+
* Shared by the request body and multi-content-type responses.
|
|
1361
|
+
*/
|
|
1362
|
+
function buildContentTypeVariants(entries, baseName, decorate) {
|
|
1363
|
+
const variants = resolveContentTypeVariants(entries, baseName);
|
|
1364
|
+
const unionSchema = ast.createSchema({
|
|
1365
|
+
type: "union",
|
|
1366
|
+
members: variants.map((variant) => ast.createSchema({
|
|
1367
|
+
type: "ref",
|
|
1368
|
+
name: variant.name
|
|
1369
|
+
}))
|
|
1370
|
+
});
|
|
1371
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [variants.map((variant) => renderSchemaType({
|
|
1372
|
+
schema: decorate ? decorate(variant.schema) : variant.schema,
|
|
1373
|
+
name: variant.name,
|
|
1374
|
+
keysToOmit: variant.keysToOmit
|
|
1375
|
+
})), renderSchemaType({
|
|
1376
|
+
schema: unionSchema,
|
|
1377
|
+
name: baseName
|
|
1378
|
+
})] });
|
|
1379
|
+
}
|
|
1112
1380
|
const paramTypes = params.map((param) => renderSchemaType({
|
|
1113
1381
|
schema: param.schema,
|
|
1114
1382
|
name: resolver.resolveParamName(node, param)
|
|
1115
1383
|
}));
|
|
1116
|
-
const
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1384
|
+
const requestBodyContent = node.requestBody?.content ?? [];
|
|
1385
|
+
function buildRequestType() {
|
|
1386
|
+
if (requestBodyContent.length === 0) return null;
|
|
1387
|
+
if (requestBodyContent.length === 1) {
|
|
1388
|
+
const entry = requestBodyContent[0];
|
|
1389
|
+
if (!entry.schema) return null;
|
|
1390
|
+
return renderSchemaType({
|
|
1391
|
+
schema: {
|
|
1392
|
+
...entry.schema,
|
|
1393
|
+
description: node.requestBody.description ?? entry.schema.description
|
|
1394
|
+
},
|
|
1395
|
+
name: resolver.resolveDataName(node),
|
|
1396
|
+
keysToOmit: entry.keysToOmit
|
|
1397
|
+
});
|
|
1398
|
+
}
|
|
1399
|
+
return buildContentTypeVariants(requestBodyContent, resolver.resolveDataName(node), (schema) => ({
|
|
1400
|
+
...schema,
|
|
1401
|
+
description: node.requestBody.description ?? schema.description
|
|
1402
|
+
}));
|
|
1403
|
+
}
|
|
1404
|
+
const requestType = buildRequestType();
|
|
1405
|
+
const responseTypes = node.responses.map((res) => {
|
|
1406
|
+
const variants = (res.content ?? []).filter((entry) => entry.schema);
|
|
1407
|
+
if (variants.length > 1) return buildContentTypeVariants(variants, resolver.resolveResponseStatusName(node, res.statusCode));
|
|
1408
|
+
const primary = variants[0] ?? res.content?.[0];
|
|
1409
|
+
return renderSchemaType({
|
|
1410
|
+
schema: primary?.schema ?? null,
|
|
1411
|
+
name: resolver.resolveResponseStatusName(node, res.statusCode),
|
|
1412
|
+
keysToOmit: primary?.keysToOmit
|
|
1413
|
+
});
|
|
1414
|
+
});
|
|
1129
1415
|
const dataType = renderSchemaType({
|
|
1130
1416
|
schema: buildData({
|
|
1131
1417
|
...node,
|
|
@@ -1137,14 +1423,15 @@ const typeGenerator = defineGenerator({
|
|
|
1137
1423
|
schema: buildResponses(node, { resolver }),
|
|
1138
1424
|
name: resolver.resolveResponsesName(node)
|
|
1139
1425
|
});
|
|
1140
|
-
|
|
1141
|
-
|
|
1426
|
+
function buildResponseType() {
|
|
1427
|
+
const hasSchema = (res) => (res.content ?? []).some((entry) => entry.schema);
|
|
1428
|
+
if (!node.responses.some(hasSchema)) return null;
|
|
1142
1429
|
const responseName = resolver.resolveResponseName(node);
|
|
1143
|
-
const responsesWithSchema = node.responses.filter(
|
|
1144
|
-
if (new Set(responsesWithSchema.flatMap((res) => res.schema ? adapter.getImports(
|
|
1430
|
+
const responsesWithSchema = node.responses.filter(hasSchema);
|
|
1431
|
+
if (new Set(responsesWithSchema.flatMap((res) => (res.content ?? []).flatMap((entry) => entry.schema ? adapter.getImports(entry.schema, (schemaName) => ({
|
|
1145
1432
|
name: resolveImportName(schemaName),
|
|
1146
1433
|
path: ""
|
|
1147
|
-
})).flatMap((imp) => Array.isArray(imp.name) ? imp.name : [imp.name]) : [])).has(responseName)) return null;
|
|
1434
|
+
})).flatMap((imp) => Array.isArray(imp.name) ? imp.name : [imp.name]) : []))).has(responseName)) return null;
|
|
1148
1435
|
return renderSchemaType({
|
|
1149
1436
|
schema: {
|
|
1150
1437
|
...buildResponseUnion(node, { resolver }),
|
|
@@ -1152,18 +1439,27 @@ const typeGenerator = defineGenerator({
|
|
|
1152
1439
|
},
|
|
1153
1440
|
name: responseName
|
|
1154
1441
|
});
|
|
1155
|
-
}
|
|
1442
|
+
}
|
|
1443
|
+
const responseType = buildResponseType();
|
|
1156
1444
|
return /* @__PURE__ */ jsxs(File, {
|
|
1157
1445
|
baseName: meta.file.baseName,
|
|
1158
1446
|
path: meta.file.path,
|
|
1159
1447
|
meta: meta.file.meta,
|
|
1160
|
-
banner: resolver.resolveBanner(
|
|
1448
|
+
banner: resolver.resolveBanner(ctx.meta, {
|
|
1161
1449
|
output,
|
|
1162
|
-
config
|
|
1450
|
+
config,
|
|
1451
|
+
file: {
|
|
1452
|
+
path: meta.file.path,
|
|
1453
|
+
baseName: meta.file.baseName
|
|
1454
|
+
}
|
|
1163
1455
|
}),
|
|
1164
|
-
footer: resolver.resolveFooter(
|
|
1456
|
+
footer: resolver.resolveFooter(ctx.meta, {
|
|
1165
1457
|
output,
|
|
1166
|
-
config
|
|
1458
|
+
config,
|
|
1459
|
+
file: {
|
|
1460
|
+
path: meta.file.path,
|
|
1461
|
+
baseName: meta.file.baseName
|
|
1462
|
+
}
|
|
1167
1463
|
}),
|
|
1168
1464
|
children: [
|
|
1169
1465
|
paramTypes,
|
|
@@ -1179,86 +1475,98 @@ const typeGenerator = defineGenerator({
|
|
|
1179
1475
|
//#endregion
|
|
1180
1476
|
//#region src/resolvers/resolverTs.ts
|
|
1181
1477
|
/**
|
|
1182
|
-
*
|
|
1183
|
-
*
|
|
1184
|
-
*
|
|
1478
|
+
* Default resolver used by `@kubb/plugin-ts`. Decides the names and file paths
|
|
1479
|
+
* for every generated TypeScript type. Import this in other plugins that need
|
|
1480
|
+
* to reference the exact names `plugin-ts` produces without duplicating the
|
|
1481
|
+
* casing/file-layout rules.
|
|
1185
1482
|
*
|
|
1186
|
-
* The `default` method is
|
|
1187
|
-
*
|
|
1483
|
+
* The `default` method is supplied by `defineResolver`. It uses PascalCase for
|
|
1484
|
+
* type names and PascalCase-with-isFile for files.
|
|
1188
1485
|
*
|
|
1189
|
-
* @example
|
|
1486
|
+
* @example Resolve a type and file name
|
|
1190
1487
|
* ```ts
|
|
1191
|
-
* import {
|
|
1488
|
+
* import { resolverTs } from '@kubb/plugin-ts'
|
|
1192
1489
|
*
|
|
1193
|
-
*
|
|
1194
|
-
*
|
|
1195
|
-
*
|
|
1490
|
+
* resolverTs.default('list pets', 'type') // 'ListPets'
|
|
1491
|
+
* resolverTs.resolvePathName('list pets', 'file') // 'ListPets'
|
|
1492
|
+
* resolverTs.resolveResponseStatusName(node, 200) // 'ListPetsStatus200'
|
|
1196
1493
|
* ```
|
|
1197
1494
|
*/
|
|
1198
|
-
const resolverTs = defineResolver((
|
|
1495
|
+
const resolverTs = defineResolver(() => {
|
|
1199
1496
|
return {
|
|
1200
1497
|
name: "default",
|
|
1201
1498
|
pluginName: "plugin-ts",
|
|
1202
1499
|
default(name, type) {
|
|
1203
|
-
|
|
1500
|
+
const resolved = pascalCase(name, { isFile: type === "file" });
|
|
1501
|
+
return type === "file" ? resolved : ensureValidVarName(resolved);
|
|
1204
1502
|
},
|
|
1205
1503
|
resolveTypeName(name) {
|
|
1206
|
-
return pascalCase(name);
|
|
1504
|
+
return ensureValidVarName(pascalCase(name));
|
|
1207
1505
|
},
|
|
1208
1506
|
resolvePathName(name, type) {
|
|
1209
|
-
|
|
1507
|
+
const resolved = pascalCase(name, { isFile: type === "file" });
|
|
1508
|
+
return type === "file" ? resolved : ensureValidVarName(resolved);
|
|
1210
1509
|
},
|
|
1211
1510
|
resolveParamName(node, param) {
|
|
1212
|
-
return
|
|
1511
|
+
return this.resolveTypeName(`${node.operationId} ${param.in} ${param.name}`);
|
|
1213
1512
|
},
|
|
1214
1513
|
resolveResponseStatusName(node, statusCode) {
|
|
1215
|
-
return
|
|
1514
|
+
return this.resolveTypeName(`${node.operationId} Status ${statusCode}`);
|
|
1216
1515
|
},
|
|
1217
1516
|
resolveDataName(node) {
|
|
1218
|
-
return
|
|
1517
|
+
return this.resolveTypeName(`${node.operationId} Data`);
|
|
1219
1518
|
},
|
|
1220
1519
|
resolveRequestConfigName(node) {
|
|
1221
|
-
return
|
|
1520
|
+
return this.resolveTypeName(`${node.operationId} RequestConfig`);
|
|
1222
1521
|
},
|
|
1223
1522
|
resolveResponsesName(node) {
|
|
1224
|
-
return
|
|
1523
|
+
return this.resolveTypeName(`${node.operationId} Responses`);
|
|
1225
1524
|
},
|
|
1226
1525
|
resolveResponseName(node) {
|
|
1227
|
-
return
|
|
1526
|
+
return this.resolveTypeName(`${node.operationId} Response`);
|
|
1228
1527
|
},
|
|
1229
1528
|
resolveEnumKeyName(node, enumTypeSuffix = "key") {
|
|
1230
|
-
return `${
|
|
1529
|
+
return `${this.resolveTypeName(node.name ?? "")}${enumTypeSuffix}`;
|
|
1231
1530
|
},
|
|
1232
1531
|
resolvePathParamsName(node, param) {
|
|
1233
|
-
return
|
|
1532
|
+
return this.resolveParamName(node, param);
|
|
1234
1533
|
},
|
|
1235
1534
|
resolveQueryParamsName(node, param) {
|
|
1236
|
-
return
|
|
1535
|
+
return this.resolveParamName(node, param);
|
|
1237
1536
|
},
|
|
1238
1537
|
resolveHeaderParamsName(node, param) {
|
|
1239
|
-
return
|
|
1538
|
+
return this.resolveParamName(node, param);
|
|
1240
1539
|
}
|
|
1241
1540
|
};
|
|
1242
1541
|
});
|
|
1243
1542
|
//#endregion
|
|
1244
1543
|
//#region src/plugin.ts
|
|
1245
1544
|
/**
|
|
1246
|
-
* Canonical plugin name for `@kubb/plugin-ts
|
|
1545
|
+
* Canonical plugin name for `@kubb/plugin-ts`. Used for driver lookups and
|
|
1546
|
+
* cross-plugin dependency references.
|
|
1247
1547
|
*/
|
|
1248
1548
|
const pluginTsName = "plugin-ts";
|
|
1249
1549
|
/**
|
|
1250
|
-
*
|
|
1251
|
-
*
|
|
1252
|
-
*
|
|
1253
|
-
*
|
|
1254
|
-
* and writes barrel files based on `output.barrelType`.
|
|
1550
|
+
* Generates TypeScript `type` aliases and `interface` declarations from an
|
|
1551
|
+
* OpenAPI spec. The foundation that every other Kubb plugin builds on:
|
|
1552
|
+
* clients, query hooks, mocks, and validators all reference the names this
|
|
1553
|
+
* plugin produces.
|
|
1255
1554
|
*
|
|
1256
1555
|
* @example
|
|
1257
1556
|
* ```ts
|
|
1258
|
-
* import
|
|
1557
|
+
* import { defineConfig } from 'kubb'
|
|
1558
|
+
* import { pluginTs } from '@kubb/plugin-ts'
|
|
1259
1559
|
*
|
|
1260
1560
|
* export default defineConfig({
|
|
1261
|
-
*
|
|
1561
|
+
* input: { path: './petStore.yaml' },
|
|
1562
|
+
* output: { path: './src/gen' },
|
|
1563
|
+
* plugins: [
|
|
1564
|
+
* pluginTs({
|
|
1565
|
+
* output: { path: './types' },
|
|
1566
|
+
* enumType: 'asConst',
|
|
1567
|
+
* optionalType: 'questionTokenAndUndefined',
|
|
1568
|
+
* }),
|
|
1569
|
+
* ],
|
|
1262
1570
|
* })
|
|
1263
1571
|
* ```
|
|
1264
1572
|
*/
|
|
@@ -1267,13 +1575,7 @@ const pluginTs = definePlugin((options) => {
|
|
|
1267
1575
|
path: "types",
|
|
1268
1576
|
barrelType: "named"
|
|
1269
1577
|
}, group, exclude = [], include, override = [], enumType = "asConst", enumTypeSuffix = "Key", enumKeyCasing = "none", optionalType = "questionToken", arrayType = "array", syntaxType = "type", paramsCasing, printer, resolver: userResolver, transformer: userTransformer, generators: userGenerators = [] } = options;
|
|
1270
|
-
const groupConfig = group
|
|
1271
|
-
...group,
|
|
1272
|
-
name: (ctx) => {
|
|
1273
|
-
if (group.type === "path") return `${ctx.group.split("/")[1]}`;
|
|
1274
|
-
return `${camelCase(ctx.group)}Controller`;
|
|
1275
|
-
}
|
|
1276
|
-
} : void 0;
|
|
1578
|
+
const groupConfig = createGroupConfig(group, { suffix: "Controller" });
|
|
1277
1579
|
return {
|
|
1278
1580
|
name: pluginTsName,
|
|
1279
1581
|
options,
|
|
@@ -1328,10 +1630,10 @@ function rank(param) {
|
|
|
1328
1630
|
return param.optional ? PARAM_RANK.optional : PARAM_RANK.required;
|
|
1329
1631
|
}
|
|
1330
1632
|
function sortParams(params) {
|
|
1331
|
-
return
|
|
1633
|
+
return params.toSorted((a, b) => rank(a) - rank(b));
|
|
1332
1634
|
}
|
|
1333
1635
|
function sortChildParams(params) {
|
|
1334
|
-
return
|
|
1636
|
+
return params.toSorted((a, b) => rank(a) - rank(b));
|
|
1335
1637
|
}
|
|
1336
1638
|
/**
|
|
1337
1639
|
* Default function-signature printer.
|