@kubb/plugin-ts 5.0.0-beta.56 → 5.0.0-beta.73
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 +2 -2
- package/dist/index.cjs +624 -156
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +377 -36
- package/dist/index.js +611 -159
- package/dist/index.js.map +1 -1
- package/dist/rolldown-runtime-CNktS9qV.js +17 -0
- package/package.json +8 -10
- package/dist/chunk-C0LytTxp.js +0 -8
- package/src/components/Enum.tsx +0 -87
- package/src/components/Type.tsx +0 -55
- package/src/constants.ts +0 -39
- package/src/factory.ts +0 -970
- package/src/generators/typeGenerator.tsx +0 -274
- package/src/index.ts +0 -9
- package/src/plugin.ts +0 -95
- package/src/printers/functionPrinter.ts +0 -197
- package/src/printers/printerTs.ts +0 -315
- package/src/resolvers/resolverTs.ts +0 -69
- package/src/types.ts +0 -335
- package/src/utils.ts +0 -140
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { extractRefName, jsStringEscape, stringify, trimQuotes } from "@kubb/ast/utils";
|
|
1
|
+
import { n as __name, t as __exportAll } from "./rolldown-runtime-CNktS9qV.js";
|
|
2
|
+
import { extractRefName, isStringType, jsStringEscape, mapSchemaItems, mapSchemaProperties, stringify, syncSchemaRef, trimQuotes } from "@kubb/ast/utils";
|
|
3
3
|
import { parserTs } from "@kubb/parser-ts";
|
|
4
4
|
import { File, jsxRenderer } from "@kubb/renderer-jsx";
|
|
5
|
-
import { ast, defineGenerator, definePlugin, defineResolver } from "@kubb/core";
|
|
6
5
|
import ts from "typescript";
|
|
7
6
|
import { Fragment, jsx, jsxs } from "@kubb/renderer-jsx/jsx-runtime";
|
|
7
|
+
import { ast, defineGenerator, definePlugin, defineResolver } from "@kubb/core";
|
|
8
8
|
//#region ../../internals/utils/src/casing.ts
|
|
9
9
|
/**
|
|
10
10
|
* Shared implementation for camelCase and PascalCase conversion.
|
|
@@ -258,7 +258,59 @@ const PARAM_RANK = {
|
|
|
258
258
|
};
|
|
259
259
|
//#endregion
|
|
260
260
|
//#region src/factory.ts
|
|
261
|
+
var factory_exports = /* @__PURE__ */ __exportAll({
|
|
262
|
+
SyntaxKind: () => SyntaxKind,
|
|
263
|
+
appendJSDocToNode: () => appendJSDocToNode,
|
|
264
|
+
buildIndexSignatures: () => buildIndexSignatures,
|
|
265
|
+
buildMemberNodes: () => buildMemberNodes,
|
|
266
|
+
buildPropertyType: () => buildPropertyType,
|
|
267
|
+
buildTupleNode: () => buildTupleNode,
|
|
268
|
+
constToTypeNode: () => constToTypeNode,
|
|
269
|
+
createArrayDeclaration: () => createArrayDeclaration,
|
|
270
|
+
createArrayTypeNode: () => createArrayTypeNode,
|
|
271
|
+
createEnumDeclaration: () => createEnumDeclaration,
|
|
272
|
+
createExportDeclaration: () => createExportDeclaration,
|
|
273
|
+
createFalse: () => createFalse,
|
|
274
|
+
createIdentifier: () => createIdentifier,
|
|
275
|
+
createImportDeclaration: () => createImportDeclaration,
|
|
276
|
+
createIndexSignature: () => createIndexSignature,
|
|
277
|
+
createInterfaceDeclaration: () => createInterfaceDeclaration,
|
|
278
|
+
createIntersectionDeclaration: () => createIntersectionDeclaration,
|
|
279
|
+
createJSDoc: () => createJSDoc,
|
|
280
|
+
createLiteralTypeNode: () => createLiteralTypeNode,
|
|
281
|
+
createNumericLiteral: () => createNumericLiteral,
|
|
282
|
+
createOmitDeclaration: () => createOmitDeclaration,
|
|
283
|
+
createOptionalTypeNode: () => createOptionalTypeNode,
|
|
284
|
+
createParameterSignature: () => createParameterSignature,
|
|
285
|
+
createPrefixUnaryExpression: () => createPrefixUnaryExpression,
|
|
286
|
+
createPropertySignature: () => createPropertySignature,
|
|
287
|
+
createQuestionToken: () => createQuestionToken,
|
|
288
|
+
createRestTypeNode: () => createRestTypeNode,
|
|
289
|
+
createStringLiteral: () => createStringLiteral,
|
|
290
|
+
createTrue: () => createTrue,
|
|
291
|
+
createTupleTypeNode: () => createTupleTypeNode,
|
|
292
|
+
createTypeAliasDeclaration: () => createTypeAliasDeclaration,
|
|
293
|
+
createTypeDeclaration: () => createTypeDeclaration,
|
|
294
|
+
createTypeLiteralNode: () => createTypeLiteralNode,
|
|
295
|
+
createTypeReferenceNode: () => createTypeReferenceNode,
|
|
296
|
+
createUnionDeclaration: () => createUnionDeclaration,
|
|
297
|
+
createUrlTemplateType: () => createUrlTemplateType,
|
|
298
|
+
dateOrStringNode: () => dateOrStringNode,
|
|
299
|
+
isNonNullable: () => isNonNullable$1,
|
|
300
|
+
keywordTypeNodes: () => keywordTypeNodes,
|
|
301
|
+
modifiers: () => modifiers,
|
|
302
|
+
syntaxKind: () => syntaxKind
|
|
303
|
+
});
|
|
261
304
|
const { SyntaxKind, factory } = ts;
|
|
305
|
+
/**
|
|
306
|
+
* Compares two strings by UTF-16 code unit, keeping sorted output identical across platforms
|
|
307
|
+
* regardless of locale.
|
|
308
|
+
*/
|
|
309
|
+
function compareStrings(a, b) {
|
|
310
|
+
if (a < b) return -1;
|
|
311
|
+
if (a > b) return 1;
|
|
312
|
+
return 0;
|
|
313
|
+
}
|
|
262
314
|
function isNumber(value) {
|
|
263
315
|
return typeof value === "number" && !Number.isNaN(value);
|
|
264
316
|
}
|
|
@@ -366,6 +418,17 @@ function createParameterSignature(name, { modifiers, dotDotDotToken, questionTok
|
|
|
366
418
|
return factory.createParameterDeclaration(modifiers, dotDotDotToken, name, createQuestionToken(questionToken), type, initializer);
|
|
367
419
|
}
|
|
368
420
|
/**
|
|
421
|
+
* Creates a JSDoc comment node from an array of comment strings.
|
|
422
|
+
* Returns null if no comments are provided.
|
|
423
|
+
*/
|
|
424
|
+
function createJSDoc({ comments }) {
|
|
425
|
+
if (!comments.length) return null;
|
|
426
|
+
return factory.createJSDocComment(factory.createNodeArray(comments.map((comment, i) => {
|
|
427
|
+
if (i === comments.length - 1) return factory.createJSDocText(comment);
|
|
428
|
+
return factory.createJSDocText(`${comment}\n`);
|
|
429
|
+
})));
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
369
432
|
* Attaches JSDoc comments to an AST node as synthetic leading comments.
|
|
370
433
|
* Filters out undefined comments before attaching.
|
|
371
434
|
*
|
|
@@ -423,6 +486,50 @@ function createTypeDeclaration({ syntax, isExportable, comments, name, type }) {
|
|
|
423
486
|
});
|
|
424
487
|
}
|
|
425
488
|
/**
|
|
489
|
+
* Creates an import declaration with support for default imports, named imports, namespace imports, and type-only imports.
|
|
490
|
+
* Optionally rename imported members with `propertyName` and `name` pairs.
|
|
491
|
+
*
|
|
492
|
+
* @example Default import
|
|
493
|
+
* `import Pet from './Pet'`
|
|
494
|
+
*
|
|
495
|
+
* @example Named imports with rename
|
|
496
|
+
* `import { Pet as Cat } from './Pet'`
|
|
497
|
+
*
|
|
498
|
+
* @example Namespace import
|
|
499
|
+
* `import * as Pet from './Pet'`
|
|
500
|
+
*/
|
|
501
|
+
function createImportDeclaration({ name, path, isTypeOnly = false, isNameSpace = false }) {
|
|
502
|
+
if (!Array.isArray(name)) {
|
|
503
|
+
const importPropertyName = isNameSpace ? void 0 : factory.createIdentifier(name);
|
|
504
|
+
const importName = isNameSpace ? factory.createNamespaceImport(factory.createIdentifier(name)) : void 0;
|
|
505
|
+
return factory.createImportDeclaration(void 0, factory.createImportClause(isTypeOnly, importPropertyName, importName), factory.createStringLiteral(path), void 0);
|
|
506
|
+
}
|
|
507
|
+
const sortedName = name.toSorted((a, b) => compareStrings(typeof a === "object" ? a.propertyName : a, typeof b === "object" ? b.propertyName : b));
|
|
508
|
+
return factory.createImportDeclaration(void 0, factory.createImportClause(isTypeOnly, void 0, factory.createNamedImports(sortedName.map((item) => {
|
|
509
|
+
if (typeof item === "object") {
|
|
510
|
+
const obj = item;
|
|
511
|
+
if (obj.name) return factory.createImportSpecifier(false, factory.createIdentifier(obj.propertyName), factory.createIdentifier(obj.name));
|
|
512
|
+
return factory.createImportSpecifier(false, void 0, factory.createIdentifier(obj.propertyName));
|
|
513
|
+
}
|
|
514
|
+
return factory.createImportSpecifier(false, void 0, factory.createIdentifier(item));
|
|
515
|
+
}))), factory.createStringLiteral(path), void 0);
|
|
516
|
+
}
|
|
517
|
+
/**
|
|
518
|
+
* Creates an export declaration with support for named exports, namespace exports, and type-only exports.
|
|
519
|
+
* Sorts export names alphabetically for consistent output across platforms.
|
|
520
|
+
*/
|
|
521
|
+
function createExportDeclaration({ path, asAlias, isTypeOnly = false, name }) {
|
|
522
|
+
if (name && !Array.isArray(name) && !asAlias) console.warn(`When using name as string, asAlias should be true ${name}`);
|
|
523
|
+
if (!Array.isArray(name)) {
|
|
524
|
+
const parsedName = name?.match(/^\d/) ? `_${name?.slice(1)}` : name;
|
|
525
|
+
return factory.createExportDeclaration(void 0, isTypeOnly, asAlias && parsedName ? factory.createNamespaceExport(factory.createIdentifier(parsedName)) : void 0, factory.createStringLiteral(path), void 0);
|
|
526
|
+
}
|
|
527
|
+
const sortedName = name.toSorted((a, b) => compareStrings(typeof a === "string" ? a : a.text, typeof b === "string" ? b : b.text));
|
|
528
|
+
return factory.createExportDeclaration(void 0, isTypeOnly, factory.createNamedExports(sortedName.map((propertyName) => {
|
|
529
|
+
return factory.createExportSpecifier(false, void 0, typeof propertyName === "string" ? factory.createIdentifier(propertyName) : propertyName);
|
|
530
|
+
})), factory.createStringLiteral(path), void 0);
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
426
533
|
* Apply casing transformation to enum keys
|
|
427
534
|
*/
|
|
428
535
|
function applyEnumKeyCasing(key, casing = "none") {
|
|
@@ -454,7 +561,7 @@ function createEnumDeclaration({ type = "enum", name, typeName, enums, enumKeyCa
|
|
|
454
561
|
return factory.createLiteralTypeNode(factory.createNumericLiteral(value?.toString()));
|
|
455
562
|
}
|
|
456
563
|
if (typeof value === "boolean") return factory.createLiteralTypeNode(value ? factory.createTrue() : factory.createFalse());
|
|
457
|
-
if (value) return factory.createLiteralTypeNode(factory.createStringLiteral(value.toString()));
|
|
564
|
+
if (value !== null && value !== void 0) return factory.createLiteralTypeNode(factory.createStringLiteral(value.toString()));
|
|
458
565
|
}).filter((node) => node !== void 0)))];
|
|
459
566
|
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]) => {
|
|
460
567
|
let initializer = factory.createStringLiteral(value?.toString());
|
|
@@ -465,7 +572,7 @@ function createEnumDeclaration({ type = "enum", name, typeName, enums, enumKeyCa
|
|
|
465
572
|
const casingKey = applyEnumKeyCasing(`${typeName}_${key}`, enumKeyCasing);
|
|
466
573
|
return factory.createEnumMember(propertyName(casingKey), initializer);
|
|
467
574
|
}
|
|
468
|
-
if (key) {
|
|
575
|
+
if (key !== null && key !== void 0) {
|
|
469
576
|
const casingKey = applyEnumKeyCasing(key.toString(), enumKeyCasing);
|
|
470
577
|
return factory.createEnumMember(propertyName(casingKey), initializer);
|
|
471
578
|
}
|
|
@@ -477,7 +584,7 @@ function createEnumDeclaration({ type = "enum", name, typeName, enums, enumKeyCa
|
|
|
477
584
|
if (isNumber(value)) if (value < 0) initializer = factory.createPrefixUnaryExpression(ts.SyntaxKind.MinusToken, factory.createNumericLiteral(Math.abs(value)));
|
|
478
585
|
else initializer = factory.createNumericLiteral(value);
|
|
479
586
|
if (typeof value === "boolean") initializer = value ? factory.createTrue() : factory.createFalse();
|
|
480
|
-
if (key) {
|
|
587
|
+
if (key !== null && key !== void 0) {
|
|
481
588
|
const casingKey = applyEnumKeyCasing(key.toString(), enumKeyCasing);
|
|
482
589
|
return factory.createPropertyAssignment(propertyName(casingKey), initializer);
|
|
483
590
|
}
|
|
@@ -638,12 +745,12 @@ function buildTupleNode(node, print) {
|
|
|
638
745
|
/**
|
|
639
746
|
* Applies `nullable` and optional/nullish `| undefined` union modifiers to a property's resolved base type.
|
|
640
747
|
*/
|
|
641
|
-
function buildPropertyType(schema, baseType, optionalType) {
|
|
748
|
+
function buildPropertyType(schema, baseType, optionalType, optional) {
|
|
642
749
|
const addsUndefined = OPTIONAL_ADDS_UNDEFINED.has(optionalType);
|
|
643
|
-
const meta =
|
|
750
|
+
const meta = syncSchemaRef(schema);
|
|
644
751
|
let type = baseType;
|
|
645
752
|
if (meta.nullable) type = createUnionDeclaration({ nodes: [type, keywordTypeNodes.null] });
|
|
646
|
-
if ((meta.nullish || meta.optional) && addsUndefined) type = createUnionDeclaration({ nodes: [type, keywordTypeNodes.undefined] });
|
|
753
|
+
if ((optional || meta.nullish || meta.optional) && addsUndefined) type = createUnionDeclaration({ nodes: [type, keywordTypeNodes.undefined] });
|
|
647
754
|
return type;
|
|
648
755
|
}
|
|
649
756
|
/**
|
|
@@ -757,6 +864,27 @@ function Type({ name, node, printer, enum: enumOptions, resolver }) {
|
|
|
757
864
|
})] });
|
|
758
865
|
}
|
|
759
866
|
//#endregion
|
|
867
|
+
//#region ../../internals/shared/src/params.ts
|
|
868
|
+
const caseParamsCache = /* @__PURE__ */ new WeakMap();
|
|
869
|
+
/**
|
|
870
|
+
* Applies camelCase to parameter names and returns a new array without mutating the input.
|
|
871
|
+
*
|
|
872
|
+
* Run it before handing parameters to schema builders so output property keys get the right casing
|
|
873
|
+
* while `OperationNode.parameters` stays intact for other consumers. When `casing` is unset, the
|
|
874
|
+
* original array is returned unchanged. Results are cached per input array.
|
|
875
|
+
*/
|
|
876
|
+
function caseParams(params, casing) {
|
|
877
|
+
if (!casing) return params;
|
|
878
|
+
const cached = caseParamsCache.get(params);
|
|
879
|
+
if (cached) return cached;
|
|
880
|
+
const result = params.map((param) => ({
|
|
881
|
+
...param,
|
|
882
|
+
name: camelCase(param.name)
|
|
883
|
+
}));
|
|
884
|
+
caseParamsCache.set(params, result);
|
|
885
|
+
return result;
|
|
886
|
+
}
|
|
887
|
+
//#endregion
|
|
760
888
|
//#region ../../internals/shared/src/operation.ts
|
|
761
889
|
/**
|
|
762
890
|
* Maps a content type to the PascalCase suffix used to name per-content-type variants
|
|
@@ -807,7 +935,7 @@ function resolveContentTypeVariants(entries, baseName) {
|
|
|
807
935
|
});
|
|
808
936
|
}
|
|
809
937
|
function getOperationParameters(node, options = {}) {
|
|
810
|
-
const params =
|
|
938
|
+
const params = caseParams(node.parameters, options.paramsCasing === "original" ? void 0 : "camelcase");
|
|
811
939
|
return {
|
|
812
940
|
path: params.filter((param) => param.in === "path"),
|
|
813
941
|
query: params.filter((param) => param.in === "query"),
|
|
@@ -855,11 +983,15 @@ function createGroupConfig(group) {
|
|
|
855
983
|
* Constraint metadata (min/max length, pattern, multipleOf, min/maxProperties) is emitted as plain-text lines.
|
|
856
984
|
|
|
857
985
|
*/
|
|
858
|
-
function
|
|
859
|
-
|
|
986
|
+
function isSchemaOptional(schema) {
|
|
987
|
+
return Boolean("optional" in schema && schema.optional || "nullish" in schema && schema.nullish);
|
|
988
|
+
}
|
|
989
|
+
function buildPropertyJSDocComments(schema, optional) {
|
|
990
|
+
const meta = syncSchemaRef(schema);
|
|
860
991
|
const isArray = meta?.primitive === "array";
|
|
861
992
|
const hasDescription = meta && "description" in meta && meta.description;
|
|
862
993
|
const formatComment = meta && "format" in meta && meta.format ? hasDescription ? [" ", `Format: \`${meta.format}\``] : ["@description", `Format: \`${meta.format}\``] : [];
|
|
994
|
+
const exampleValues = meta?.examples ?? [];
|
|
863
995
|
return [
|
|
864
996
|
hasDescription ? `@description ${jsStringEscape(meta.description)}` : null,
|
|
865
997
|
...formatComment,
|
|
@@ -868,99 +1000,102 @@ function buildPropertyJSDocComments(schema) {
|
|
|
868
1000
|
!isArray && meta && "max" in meta && meta.max !== void 0 ? `@maxLength ${meta.max}` : null,
|
|
869
1001
|
meta && "pattern" in meta && meta.pattern ? `@pattern ${meta.pattern}` : null,
|
|
870
1002
|
meta && "default" in meta && meta.default !== void 0 ? `@default ${"primitive" in meta && meta.primitive === "string" ? stringify(meta.default) : meta.default}` : null,
|
|
871
|
-
|
|
872
|
-
meta && "primitive" in meta && meta.primitive ? [`@type ${meta.primitive}`,
|
|
1003
|
+
...exampleValues.map((example) => `@example ${example}`),
|
|
1004
|
+
meta && "primitive" in meta && meta.primitive ? [`@type ${meta.primitive}`, optional ?? isSchemaOptional(schema) ? " | undefined" : null].filter(Boolean).join("") : null
|
|
873
1005
|
].filter(Boolean);
|
|
874
1006
|
}
|
|
875
1007
|
function buildParams(node, { params, resolver }) {
|
|
876
|
-
return ast.createSchema({
|
|
1008
|
+
return ast.factory.createSchema({
|
|
877
1009
|
type: "object",
|
|
878
|
-
properties: params.map((param) => ast.createProperty({
|
|
1010
|
+
properties: params.map((param) => ast.factory.createProperty({
|
|
879
1011
|
name: param.name,
|
|
880
1012
|
required: param.required,
|
|
881
|
-
schema: ast.createSchema({
|
|
1013
|
+
schema: ast.factory.createSchema({
|
|
882
1014
|
type: "ref",
|
|
883
|
-
name: resolver.resolveParamName(node, param)
|
|
1015
|
+
name: resolver.resolveParamName(node, param),
|
|
1016
|
+
optional: !param.required
|
|
884
1017
|
})
|
|
885
1018
|
}))
|
|
886
1019
|
});
|
|
887
1020
|
}
|
|
888
1021
|
function buildData(node, { resolver }) {
|
|
889
|
-
const { path: pathParams, query: queryParams, header: headerParams } = getOperationParameters(node);
|
|
890
|
-
|
|
1022
|
+
const { path: pathParams, query: queryParams, header: headerParams } = getOperationParameters(node, { paramsCasing: "original" });
|
|
1023
|
+
const hasBody = Boolean(node.requestBody?.content?.[0]?.schema);
|
|
1024
|
+
const hasRequiredPath = pathParams.some((param) => param.required);
|
|
1025
|
+
const hasRequiredQuery = queryParams.some((param) => param.required);
|
|
1026
|
+
const hasRequiredHeader = headerParams.some((param) => param.required);
|
|
1027
|
+
return ast.factory.createSchema({
|
|
891
1028
|
type: "object",
|
|
892
1029
|
deprecated: node.deprecated,
|
|
893
1030
|
properties: [
|
|
894
|
-
ast.createProperty({
|
|
895
|
-
name: "
|
|
896
|
-
|
|
1031
|
+
ast.factory.createProperty({
|
|
1032
|
+
name: "body",
|
|
1033
|
+
required: hasBody,
|
|
1034
|
+
schema: hasBody ? ast.factory.createSchema({
|
|
897
1035
|
type: "ref",
|
|
898
|
-
name: resolver.resolveDataName(node)
|
|
899
|
-
|
|
900
|
-
}) : ast.createSchema({
|
|
1036
|
+
name: resolver.resolveDataName(node)
|
|
1037
|
+
}) : ast.factory.createSchema({
|
|
901
1038
|
type: "never",
|
|
902
1039
|
primitive: void 0,
|
|
903
1040
|
optional: true
|
|
904
1041
|
})
|
|
905
1042
|
}),
|
|
906
|
-
ast.createProperty({
|
|
907
|
-
name: "
|
|
908
|
-
required:
|
|
909
|
-
schema: pathParams.length > 0 ?
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
1043
|
+
ast.factory.createProperty({
|
|
1044
|
+
name: "path",
|
|
1045
|
+
required: hasRequiredPath,
|
|
1046
|
+
schema: pathParams.length > 0 ? ast.factory.createSchema({
|
|
1047
|
+
...buildParams(node, {
|
|
1048
|
+
params: pathParams,
|
|
1049
|
+
resolver
|
|
1050
|
+
}),
|
|
1051
|
+
optional: !hasRequiredPath
|
|
1052
|
+
}) : ast.factory.createSchema({
|
|
913
1053
|
type: "never",
|
|
914
|
-
primitive: void 0
|
|
1054
|
+
primitive: void 0,
|
|
1055
|
+
optional: true
|
|
915
1056
|
})
|
|
916
1057
|
}),
|
|
917
|
-
ast.createProperty({
|
|
918
|
-
name: "
|
|
919
|
-
|
|
1058
|
+
ast.factory.createProperty({
|
|
1059
|
+
name: "query",
|
|
1060
|
+
required: hasRequiredQuery,
|
|
1061
|
+
schema: queryParams.length > 0 ? ast.factory.createSchema({
|
|
920
1062
|
...buildParams(node, {
|
|
921
1063
|
params: queryParams,
|
|
922
1064
|
resolver
|
|
923
1065
|
}),
|
|
924
|
-
optional:
|
|
925
|
-
}) : ast.createSchema({
|
|
1066
|
+
optional: !hasRequiredQuery
|
|
1067
|
+
}) : ast.factory.createSchema({
|
|
926
1068
|
type: "never",
|
|
927
1069
|
primitive: void 0,
|
|
928
1070
|
optional: true
|
|
929
1071
|
})
|
|
930
1072
|
}),
|
|
931
|
-
ast.createProperty({
|
|
932
|
-
name: "
|
|
933
|
-
|
|
1073
|
+
ast.factory.createProperty({
|
|
1074
|
+
name: "headers",
|
|
1075
|
+
required: hasRequiredHeader,
|
|
1076
|
+
schema: headerParams.length > 0 ? ast.factory.createSchema({
|
|
934
1077
|
...buildParams(node, {
|
|
935
1078
|
params: headerParams,
|
|
936
1079
|
resolver
|
|
937
1080
|
}),
|
|
938
|
-
optional:
|
|
939
|
-
}) : ast.createSchema({
|
|
1081
|
+
optional: !hasRequiredHeader
|
|
1082
|
+
}) : ast.factory.createSchema({
|
|
940
1083
|
type: "never",
|
|
941
1084
|
primitive: void 0,
|
|
942
1085
|
optional: true
|
|
943
1086
|
})
|
|
944
|
-
}),
|
|
945
|
-
ast.createProperty({
|
|
946
|
-
name: "url",
|
|
947
|
-
required: true,
|
|
948
|
-
schema: ast.createSchema({
|
|
949
|
-
type: "url",
|
|
950
|
-
path: node.path
|
|
951
|
-
})
|
|
952
1087
|
})
|
|
953
1088
|
]
|
|
954
1089
|
});
|
|
955
1090
|
}
|
|
956
1091
|
function buildResponses(node, { resolver }) {
|
|
957
1092
|
if (node.responses.length === 0) return null;
|
|
958
|
-
return ast.createSchema({
|
|
1093
|
+
return ast.factory.createSchema({
|
|
959
1094
|
type: "object",
|
|
960
|
-
properties: node.responses.map((res) => ast.createProperty({
|
|
1095
|
+
properties: node.responses.map((res) => ast.factory.createProperty({
|
|
961
1096
|
name: String(res.statusCode),
|
|
962
1097
|
required: true,
|
|
963
|
-
schema: ast.createSchema({
|
|
1098
|
+
schema: ast.factory.createSchema({
|
|
964
1099
|
type: "ref",
|
|
965
1100
|
name: resolver.resolveResponseStatusName(node, res.statusCode)
|
|
966
1101
|
})
|
|
@@ -970,9 +1105,9 @@ function buildResponses(node, { resolver }) {
|
|
|
970
1105
|
function buildResponseUnion(node, { resolver }) {
|
|
971
1106
|
const responsesWithSchema = node.responses.filter((res) => res.content?.some((entry) => entry.schema));
|
|
972
1107
|
if (responsesWithSchema.length === 0) return null;
|
|
973
|
-
return ast.createSchema({
|
|
1108
|
+
return ast.factory.createSchema({
|
|
974
1109
|
type: "union",
|
|
975
|
-
members: responsesWithSchema.map((res) => ast.createSchema({
|
|
1110
|
+
members: responsesWithSchema.map((res) => ast.factory.createSchema({
|
|
976
1111
|
type: "ref",
|
|
977
1112
|
name: resolver.resolveResponseStatusName(node, res.statusCode)
|
|
978
1113
|
}))
|
|
@@ -980,9 +1115,7 @@ function buildResponseUnion(node, { resolver }) {
|
|
|
980
1115
|
}
|
|
981
1116
|
//#endregion
|
|
982
1117
|
//#region src/printers/printerTs.ts
|
|
983
|
-
|
|
984
|
-
return value !== null && value !== void 0;
|
|
985
|
-
}
|
|
1118
|
+
const { isNonNullable } = factory_exports;
|
|
986
1119
|
/**
|
|
987
1120
|
* TypeScript type printer built with `definePrinter`.
|
|
988
1121
|
*
|
|
@@ -1006,7 +1139,7 @@ function isNonNullable(value) {
|
|
|
1006
1139
|
* const declaration = printer.print(schemaNode) // ts.TypeAliasDeclaration | ts.InterfaceDeclaration
|
|
1007
1140
|
* ```
|
|
1008
1141
|
*/
|
|
1009
|
-
const printerTs = ast.
|
|
1142
|
+
const printerTs = ast.createPrinter((options) => {
|
|
1010
1143
|
const addsUndefined = OPTIONAL_ADDS_UNDEFINED.has(options.optionalType);
|
|
1011
1144
|
return {
|
|
1012
1145
|
name: "typescript",
|
|
@@ -1052,11 +1185,11 @@ const printerTs = ast.definePrinter((options) => {
|
|
|
1052
1185
|
const hasStringLiteral = members.some((m) => {
|
|
1053
1186
|
return ast.narrowSchema(m, ast.schemaTypes.enum)?.primitive === "string";
|
|
1054
1187
|
});
|
|
1055
|
-
const hasPlainString = members.some((m) =>
|
|
1188
|
+
const hasPlainString = members.some((m) => isStringType(m));
|
|
1056
1189
|
if (hasStringLiteral && hasPlainString) return createUnionDeclaration({
|
|
1057
1190
|
withParentheses: true,
|
|
1058
1191
|
nodes: members.map((m) => {
|
|
1059
|
-
if (
|
|
1192
|
+
if (isStringType(m)) return createIntersectionDeclaration({
|
|
1060
1193
|
nodes: [keywordTypeNodes.string, createTypeLiteralNode([])],
|
|
1061
1194
|
withParentheses: true
|
|
1062
1195
|
});
|
|
@@ -1076,7 +1209,7 @@ const printerTs = ast.definePrinter((options) => {
|
|
|
1076
1209
|
},
|
|
1077
1210
|
array(node) {
|
|
1078
1211
|
return createArrayDeclaration({
|
|
1079
|
-
nodes: (node
|
|
1212
|
+
nodes: mapSchemaItems(node, (item) => this.transform(item)).map(({ output }) => output).filter(isNonNullable),
|
|
1080
1213
|
arrayType: this.options.arrayType
|
|
1081
1214
|
}) ?? null;
|
|
1082
1215
|
},
|
|
@@ -1086,18 +1219,19 @@ const printerTs = ast.definePrinter((options) => {
|
|
|
1086
1219
|
object(node) {
|
|
1087
1220
|
const { transform, options } = this;
|
|
1088
1221
|
const addsQuestionToken = OPTIONAL_ADDS_QUESTION_TOKEN.has(options.optionalType);
|
|
1089
|
-
const propertyNodes = node.
|
|
1090
|
-
const baseType =
|
|
1091
|
-
const
|
|
1092
|
-
const
|
|
1222
|
+
const propertyNodes = mapSchemaProperties(node, (schema) => transform(schema)).map(({ name, property, output }) => {
|
|
1223
|
+
const baseType = output ?? keywordTypeNodes.unknown;
|
|
1224
|
+
const optional = !property.required || !!property.schema.optional || !!property.schema.nullish;
|
|
1225
|
+
const type = buildPropertyType(property.schema, baseType, options.optionalType, optional);
|
|
1226
|
+
const propMeta = syncSchemaRef(property.schema);
|
|
1093
1227
|
return appendJSDocToNode({
|
|
1094
1228
|
node: createPropertySignature({
|
|
1095
|
-
questionToken:
|
|
1096
|
-
name
|
|
1229
|
+
questionToken: optional ? addsQuestionToken : false,
|
|
1230
|
+
name,
|
|
1097
1231
|
type,
|
|
1098
1232
|
readOnly: propMeta?.readOnly
|
|
1099
1233
|
}),
|
|
1100
|
-
comments: buildPropertyJSDocComments(
|
|
1234
|
+
comments: buildPropertyJSDocComments(property.schema, optional)
|
|
1101
1235
|
});
|
|
1102
1236
|
});
|
|
1103
1237
|
const allElements = [...propertyNodes, ...buildIndexSignatures(node, propertyNodes.length, transform)];
|
|
@@ -1110,7 +1244,7 @@ const printerTs = ast.definePrinter((options) => {
|
|
|
1110
1244
|
const { name, syntaxType = "type", description, keysToOmit } = this.options;
|
|
1111
1245
|
const transformed = this.transform(node);
|
|
1112
1246
|
if (!transformed) return null;
|
|
1113
|
-
const meta =
|
|
1247
|
+
const meta = syncSchemaRef(node);
|
|
1114
1248
|
if (!name) {
|
|
1115
1249
|
const withNullable = meta.nullable ? createUnionDeclaration({ nodes: [transformed, keywordTypeNodes.null] }) : transformed;
|
|
1116
1250
|
const result = (meta.nullish || meta.optional) && addsUndefined ? createUnionDeclaration({ nodes: [withNullable, keywordTypeNodes.undefined] }) : withNullable;
|
|
@@ -1232,9 +1366,9 @@ const typeGenerator = defineGenerator({
|
|
|
1232
1366
|
});
|
|
1233
1367
|
},
|
|
1234
1368
|
operation(node, ctx) {
|
|
1235
|
-
const { enum: enumOptions, optionalType, arrayType, syntaxType,
|
|
1369
|
+
const { enum: enumOptions, optionalType, arrayType, syntaxType, group, output, printer } = ctx.options;
|
|
1236
1370
|
const { adapter, config, resolver, root } = ctx;
|
|
1237
|
-
const params =
|
|
1371
|
+
const params = caseParams(node.parameters, "camelcase");
|
|
1238
1372
|
const meta = { file: resolver.resolveFile({
|
|
1239
1373
|
name: node.operationId,
|
|
1240
1374
|
extname: ".ts",
|
|
@@ -1298,9 +1432,9 @@ const typeGenerator = defineGenerator({
|
|
|
1298
1432
|
*/
|
|
1299
1433
|
function buildContentTypeVariants(entries, baseName, decorate) {
|
|
1300
1434
|
const variants = resolveContentTypeVariants(entries, baseName);
|
|
1301
|
-
const unionSchema = ast.createSchema({
|
|
1435
|
+
const unionSchema = ast.factory.createSchema({
|
|
1302
1436
|
type: "union",
|
|
1303
|
-
members: variants.map((variant) => ast.createSchema({
|
|
1437
|
+
members: variants.map((variant) => ast.factory.createSchema({
|
|
1304
1438
|
type: "ref",
|
|
1305
1439
|
name: variant.name
|
|
1306
1440
|
}))
|
|
@@ -1315,7 +1449,10 @@ const typeGenerator = defineGenerator({
|
|
|
1315
1449
|
})] });
|
|
1316
1450
|
}
|
|
1317
1451
|
const paramTypes = params.map((param) => renderSchemaType({
|
|
1318
|
-
schema:
|
|
1452
|
+
schema: {
|
|
1453
|
+
...param.schema,
|
|
1454
|
+
optional: !param.required
|
|
1455
|
+
},
|
|
1319
1456
|
name: resolver.resolveParamName(node, param)
|
|
1320
1457
|
}));
|
|
1321
1458
|
const requestBodyContent = node.requestBody?.content ?? [];
|
|
@@ -1511,7 +1648,7 @@ const pluginTs = definePlugin((options) => {
|
|
|
1511
1648
|
const { output = {
|
|
1512
1649
|
path: "types",
|
|
1513
1650
|
barrel: { type: "named" }
|
|
1514
|
-
}, group, exclude = [], include, override = [], enum: enumOptions = {}, optionalType = "questionToken", arrayType = "array", syntaxType = "type",
|
|
1651
|
+
}, group, exclude = [], include, override = [], enum: enumOptions = {}, optionalType = "questionToken", arrayType = "array", syntaxType = "type", printer, resolver: userResolver, macros: userMacros } = options;
|
|
1515
1652
|
const groupConfig = createGroupConfig(group);
|
|
1516
1653
|
const resolvedEnum = {
|
|
1517
1654
|
type: enumOptions.type ?? "asConst",
|
|
@@ -1533,52 +1670,237 @@ const pluginTs = definePlugin((options) => {
|
|
|
1533
1670
|
arrayType,
|
|
1534
1671
|
enum: resolvedEnum,
|
|
1535
1672
|
syntaxType,
|
|
1536
|
-
paramsCasing,
|
|
1537
1673
|
printer
|
|
1538
1674
|
});
|
|
1539
1675
|
ctx.setResolver(userResolver ? {
|
|
1540
1676
|
...resolverTs,
|
|
1541
1677
|
...userResolver
|
|
1542
1678
|
} : resolverTs);
|
|
1543
|
-
if (
|
|
1679
|
+
if (userMacros?.length) ctx.setMacros(userMacros);
|
|
1544
1680
|
ctx.addGenerator(typeGenerator);
|
|
1545
|
-
for (const gen of userGenerators) ctx.addGenerator(gen);
|
|
1546
1681
|
} }
|
|
1547
1682
|
};
|
|
1548
1683
|
});
|
|
1549
1684
|
//#endregion
|
|
1685
|
+
//#region src/printers/functionParams.ts
|
|
1686
|
+
/**
|
|
1687
|
+
* Narrows a {@link TypeExpression} to a {@link TypeLiteralNode}.
|
|
1688
|
+
*/
|
|
1689
|
+
function isTypeLiteral(type) {
|
|
1690
|
+
return typeof type !== "string" && type.kind === "TypeLiteral";
|
|
1691
|
+
}
|
|
1692
|
+
/**
|
|
1693
|
+
* Narrows a {@link TypeExpression} to an {@link IndexedAccessTypeNode}.
|
|
1694
|
+
*/
|
|
1695
|
+
function isIndexedAccessType(type) {
|
|
1696
|
+
return typeof type !== "string" && type.kind === "IndexedAccessType";
|
|
1697
|
+
}
|
|
1698
|
+
/**
|
|
1699
|
+
* Creates a {@link TypeLiteralNode} representing an inline anonymous object type.
|
|
1700
|
+
*
|
|
1701
|
+
* @example
|
|
1702
|
+
* ```ts
|
|
1703
|
+
* createTypeLiteral({ members: [{ name: 'petId', type: 'string', optional: false }] })
|
|
1704
|
+
* // { petId: string }
|
|
1705
|
+
* ```
|
|
1706
|
+
*/
|
|
1707
|
+
function createTypeLiteral(props) {
|
|
1708
|
+
return {
|
|
1709
|
+
kind: "TypeLiteral",
|
|
1710
|
+
...props
|
|
1711
|
+
};
|
|
1712
|
+
}
|
|
1713
|
+
/**
|
|
1714
|
+
* Creates an {@link IndexedAccessTypeNode} representing a single field accessed from a named type.
|
|
1715
|
+
*
|
|
1716
|
+
* @example
|
|
1717
|
+
* ```ts
|
|
1718
|
+
* createIndexedAccessType({ target: 'DeletePetPathParams', key: 'petId' })
|
|
1719
|
+
* // DeletePetPathParams['petId']
|
|
1720
|
+
* ```
|
|
1721
|
+
*/
|
|
1722
|
+
function createIndexedAccessType(props) {
|
|
1723
|
+
return {
|
|
1724
|
+
kind: "IndexedAccessType",
|
|
1725
|
+
...props
|
|
1726
|
+
};
|
|
1727
|
+
}
|
|
1728
|
+
/**
|
|
1729
|
+
* Creates an {@link ObjectBindingPatternNode} for a destructured parameter binding.
|
|
1730
|
+
*
|
|
1731
|
+
* @example
|
|
1732
|
+
* ```ts
|
|
1733
|
+
* createObjectBindingPattern({ elements: [{ name: 'id' }, { name: 'name' }] })
|
|
1734
|
+
* // { id, name }
|
|
1735
|
+
* ```
|
|
1736
|
+
*/
|
|
1737
|
+
function createObjectBindingPattern(props) {
|
|
1738
|
+
return {
|
|
1739
|
+
kind: "ObjectBindingPattern",
|
|
1740
|
+
...props
|
|
1741
|
+
};
|
|
1742
|
+
}
|
|
1743
|
+
/**
|
|
1744
|
+
* Creates a {@link FunctionParameterNode}. `optional` defaults to `false`.
|
|
1745
|
+
* Passing `properties` builds a destructured group: an {@link ObjectBindingPatternNode} name
|
|
1746
|
+
* paired with a {@link TypeLiteralNode} type.
|
|
1747
|
+
*
|
|
1748
|
+
* @example Optional param
|
|
1749
|
+
* ```ts
|
|
1750
|
+
* createFunctionParameter({ name: 'params', type: 'QueryParams', optional: true })
|
|
1751
|
+
* // → params?: QueryParams
|
|
1752
|
+
* ```
|
|
1753
|
+
*
|
|
1754
|
+
* @example Destructured group
|
|
1755
|
+
* ```ts
|
|
1756
|
+
* createFunctionParameter({ properties: [{ name: 'id', type: 'string' }, { name: 'name', type: 'string', optional: true }], default: '{}' })
|
|
1757
|
+
* // → { id, name }: { id: string; name?: string } = {}
|
|
1758
|
+
* ```
|
|
1759
|
+
*/
|
|
1760
|
+
function createFunctionParameter(input) {
|
|
1761
|
+
if ("properties" in input) return {
|
|
1762
|
+
kind: "FunctionParameter",
|
|
1763
|
+
name: createObjectBindingPattern({ elements: input.properties.map((p) => ({ name: p.name })) }),
|
|
1764
|
+
type: createTypeLiteral({ members: input.properties.map((p) => ({
|
|
1765
|
+
name: p.name,
|
|
1766
|
+
type: p.type,
|
|
1767
|
+
optional: p.optional ?? false
|
|
1768
|
+
})) }),
|
|
1769
|
+
optional: input.optional ?? false,
|
|
1770
|
+
...input.default !== void 0 ? { default: input.default } : {}
|
|
1771
|
+
};
|
|
1772
|
+
return {
|
|
1773
|
+
kind: "FunctionParameter",
|
|
1774
|
+
optional: false,
|
|
1775
|
+
...input
|
|
1776
|
+
};
|
|
1777
|
+
}
|
|
1778
|
+
/**
|
|
1779
|
+
* Creates a {@link FunctionParametersNode} from an ordered list of parameters.
|
|
1780
|
+
*
|
|
1781
|
+
* @example
|
|
1782
|
+
* ```ts
|
|
1783
|
+
* const empty = createFunctionParameters()
|
|
1784
|
+
* // { params: [] }
|
|
1785
|
+
* ```
|
|
1786
|
+
*/
|
|
1787
|
+
function createFunctionParameters(props = {}) {
|
|
1788
|
+
return {
|
|
1789
|
+
kind: "FunctionParameters",
|
|
1790
|
+
params: [],
|
|
1791
|
+
...props
|
|
1792
|
+
};
|
|
1793
|
+
}
|
|
1794
|
+
//#endregion
|
|
1550
1795
|
//#region src/printers/functionPrinter.ts
|
|
1551
|
-
const kindToHandlerKey = {
|
|
1552
|
-
FunctionParameter: "functionParameter",
|
|
1553
|
-
ParameterGroup: "parameterGroup",
|
|
1554
|
-
FunctionParameters: "functionParameters",
|
|
1555
|
-
ParamsType: "paramsType"
|
|
1556
|
-
};
|
|
1557
1796
|
/**
|
|
1558
|
-
*
|
|
1797
|
+
* Renders a {@link TypeExpression} to its TypeScript source.
|
|
1798
|
+
*
|
|
1799
|
+
* - a `string` is a type reference, returned as-is
|
|
1800
|
+
* - an `IndexedAccessType` becomes `objectType['indexType']`
|
|
1801
|
+
* - a `TypeLiteral` becomes `{ key: Type; key?: Type }`
|
|
1559
1802
|
*
|
|
1560
|
-
*
|
|
1561
|
-
*
|
|
1803
|
+
* `transformType` is applied once to the fully rendered type, matching how the
|
|
1804
|
+
* printer wrapped reference types before the `ts.factory` model.
|
|
1562
1805
|
*/
|
|
1563
|
-
|
|
1806
|
+
function renderType(type, transformType) {
|
|
1807
|
+
const rendered = renderTypeExpression(type);
|
|
1808
|
+
return transformType ? transformType(rendered) : rendered;
|
|
1809
|
+
}
|
|
1810
|
+
/**
|
|
1811
|
+
* Renders an object-type key, quoting it as a string literal when it is not a valid
|
|
1812
|
+
* identifier so `{ 'content-type': string }` stays valid TypeScript.
|
|
1813
|
+
*/
|
|
1814
|
+
function renderKey(name) {
|
|
1815
|
+
return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name) ? name : JSON.stringify(name);
|
|
1816
|
+
}
|
|
1817
|
+
function renderTypeExpression(type) {
|
|
1818
|
+
if (typeof type === "string") return type;
|
|
1819
|
+
if (isIndexedAccessType(type)) return `${type.target}['${type.key}']`;
|
|
1820
|
+
return `{ ${type.members.map((member) => {
|
|
1821
|
+
const value = renderTypeExpression(member.type);
|
|
1822
|
+
return member.optional ? `${renderKey(member.name)}?: ${value}` : `${renderKey(member.name)}: ${value}`;
|
|
1823
|
+
}).join("; ")} }`;
|
|
1824
|
+
}
|
|
1825
|
+
function groupMembers(param) {
|
|
1826
|
+
if (typeof param.name === "string") return null;
|
|
1827
|
+
return param.type && isTypeLiteral(param.type) ? param.type.members : [];
|
|
1828
|
+
}
|
|
1564
1829
|
function rank(param) {
|
|
1565
|
-
if (param.kind === "ParameterGroup") {
|
|
1566
|
-
if (param.default) return PARAM_RANK.withDefault;
|
|
1567
|
-
return param.optional ?? param.properties.every((p) => p.optional || p.default !== void 0) ? PARAM_RANK.optional : PARAM_RANK.required;
|
|
1568
|
-
}
|
|
1569
1830
|
if (param.rest) return PARAM_RANK.rest;
|
|
1570
1831
|
if (param.default) return PARAM_RANK.withDefault;
|
|
1832
|
+
const members = groupMembers(param);
|
|
1833
|
+
if (members) return members.every((m) => m.optional) ? PARAM_RANK.optional : PARAM_RANK.required;
|
|
1571
1834
|
return param.optional ? PARAM_RANK.optional : PARAM_RANK.required;
|
|
1572
1835
|
}
|
|
1573
1836
|
function sortParams(params) {
|
|
1574
1837
|
return params.toSorted((a, b) => rank(a) - rank(b));
|
|
1575
1838
|
}
|
|
1576
|
-
function
|
|
1577
|
-
|
|
1839
|
+
function sortedGroupMembers(name, type) {
|
|
1840
|
+
const members = type && isTypeLiteral(type) ? type.members : [];
|
|
1841
|
+
const memberRank = (optional) => optional ? PARAM_RANK.optional : PARAM_RANK.required;
|
|
1842
|
+
return name.elements.map((element, index) => ({
|
|
1843
|
+
name: element.name,
|
|
1844
|
+
propertyName: element.propertyName,
|
|
1845
|
+
type: members[index]?.type,
|
|
1846
|
+
optional: members[index]?.optional
|
|
1847
|
+
})).toSorted((a, b) => memberRank(a.optional) - memberRank(b.optional));
|
|
1848
|
+
}
|
|
1849
|
+
/**
|
|
1850
|
+
* Renders one binding element: the local name, prefixed with its source key when the
|
|
1851
|
+
* binding renames the property, as in `{ petId: id }`.
|
|
1852
|
+
*/
|
|
1853
|
+
function renderBindingMember(member, transformName) {
|
|
1854
|
+
const local = transformName ? transformName(member.name) : member.name;
|
|
1855
|
+
return member.propertyName ? `${member.propertyName}: ${local}` : local;
|
|
1578
1856
|
}
|
|
1579
1857
|
/**
|
|
1580
|
-
*
|
|
1581
|
-
*
|
|
1858
|
+
* Renders the type annotation of a destructured group. An inline object type is
|
|
1859
|
+
* rendered from the already-sorted members so its key order matches the binding;
|
|
1860
|
+
* a reference type is rendered as-is.
|
|
1861
|
+
*/
|
|
1862
|
+
function renderGroupType(type, sorted, transformType) {
|
|
1863
|
+
if (!type) return void 0;
|
|
1864
|
+
if (!isTypeLiteral(type)) return renderType(type);
|
|
1865
|
+
const typed = sorted.filter((member) => member.type !== void 0);
|
|
1866
|
+
if (!typed.length) return void 0;
|
|
1867
|
+
return `{ ${typed.map((member) => {
|
|
1868
|
+
const key = renderKey(member.propertyName ?? member.name);
|
|
1869
|
+
const value = renderType(member.type, transformType);
|
|
1870
|
+
return member.optional ? `${key}?: ${value}` : `${key}: ${value}`;
|
|
1871
|
+
}).join("; ")} }`;
|
|
1872
|
+
}
|
|
1873
|
+
function printParameter(node, options) {
|
|
1874
|
+
const { mode, transformName, transformType } = options;
|
|
1875
|
+
const isGroup = typeof node.name !== "string";
|
|
1876
|
+
if (mode === "call") {
|
|
1877
|
+
if (isGroup) return `{ ${sortedGroupMembers(node.name, node.type).map((member) => renderBindingMember(member)).join(", ")} }`;
|
|
1878
|
+
const name = transformName ? transformName(node.name) : node.name;
|
|
1879
|
+
return node.rest ? `...${name}` : name;
|
|
1880
|
+
}
|
|
1881
|
+
if (isGroup) {
|
|
1882
|
+
const sorted = sortedGroupMembers(node.name, node.type);
|
|
1883
|
+
const binding = `{ ${sorted.map((member) => renderBindingMember(member, transformName)).join(", ")} }`;
|
|
1884
|
+
const allOptional = sorted.every((member) => member.optional);
|
|
1885
|
+
const type = renderGroupType(node.type, sorted, transformType);
|
|
1886
|
+
if (type) {
|
|
1887
|
+
if (allOptional) return `${binding}: ${type} = ${node.default ?? "{}"}`;
|
|
1888
|
+
return node.default ? `${binding}: ${type} = ${node.default}` : `${binding}: ${type}`;
|
|
1889
|
+
}
|
|
1890
|
+
return node.default ? `${binding} = ${node.default}` : binding;
|
|
1891
|
+
}
|
|
1892
|
+
const name = transformName ? transformName(node.name) : node.name;
|
|
1893
|
+
const type = node.type ? renderType(node.type, transformType) : void 0;
|
|
1894
|
+
if (node.rest) return type ? `...${name}: ${type}` : `...${name}`;
|
|
1895
|
+
if (type) {
|
|
1896
|
+
if (node.optional) return `${name}?: ${type}`;
|
|
1897
|
+
return node.default ? `${name}: ${type} = ${node.default}` : `${name}: ${type}`;
|
|
1898
|
+
}
|
|
1899
|
+
return node.default ? `${name} = ${node.default}` : name;
|
|
1900
|
+
}
|
|
1901
|
+
/**
|
|
1902
|
+
* Default function-signature printer. Renders a parameter list in one of two modes:
|
|
1903
|
+
* `declaration` for the function signature and `call` for the call arguments.
|
|
1582
1904
|
*
|
|
1583
1905
|
* @example
|
|
1584
1906
|
* ```ts
|
|
@@ -1594,68 +1916,198 @@ function sortChildParams(params) {
|
|
|
1594
1916
|
* printer.print(sig) // → "petId: string, config: Config = {}"
|
|
1595
1917
|
* ```
|
|
1596
1918
|
*/
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
if (node.variant === "member") return `${node.base}['${node.key}']`;
|
|
1604
|
-
if (node.variant === "struct") return `{ ${node.properties.map((p) => {
|
|
1605
|
-
const typeStr = this.transform(p.type);
|
|
1606
|
-
const key = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(p.name) ? p.name : JSON.stringify(p.name);
|
|
1607
|
-
return p.optional ? `${key}?: ${typeStr}` : `${key}: ${typeStr}`;
|
|
1608
|
-
}).join("; ")} }`;
|
|
1609
|
-
if (node.variant === "reference") return node.name;
|
|
1610
|
-
return null;
|
|
1611
|
-
},
|
|
1612
|
-
functionParameter(node) {
|
|
1613
|
-
const { mode, transformName, transformType } = this.options;
|
|
1614
|
-
const name = transformName ? transformName(node.name) : node.name;
|
|
1615
|
-
const rawType = node.type ? this.transform(node.type) : void 0;
|
|
1616
|
-
const type = rawType != null && transformType ? transformType(rawType) : rawType;
|
|
1617
|
-
if (mode === "keys" || mode === "values") return node.rest ? `...${name}` : name;
|
|
1618
|
-
if (mode === "call") return node.rest ? `...${name}` : name;
|
|
1619
|
-
if (node.rest) return type ? `...${name}: ${type}` : `...${name}`;
|
|
1620
|
-
if (type) {
|
|
1621
|
-
if (node.optional) return `${name}?: ${type}`;
|
|
1622
|
-
return node.default ? `${name}: ${type} = ${node.default}` : `${name}: ${type}`;
|
|
1623
|
-
}
|
|
1624
|
-
return node.default ? `${name} = ${node.default}` : name;
|
|
1625
|
-
},
|
|
1626
|
-
parameterGroup(node) {
|
|
1627
|
-
const { mode, transformName, transformType } = this.options;
|
|
1628
|
-
const sorted = sortChildParams(node.properties);
|
|
1629
|
-
const isOptional = node.optional ?? sorted.every((p) => p.optional || p.default !== void 0);
|
|
1630
|
-
if (node.inline) return sorted.map((p) => this.transform(p)).filter(Boolean).join(", ");
|
|
1631
|
-
if (mode === "keys" || mode === "values") return `{ ${sorted.map((p) => p.name).join(", ")} }`;
|
|
1632
|
-
if (mode === "call") return `{ ${sorted.map((p) => p.name).join(", ")} }`;
|
|
1633
|
-
const names = sorted.map((p) => {
|
|
1634
|
-
return transformName ? transformName(p.name) : p.name;
|
|
1635
|
-
});
|
|
1636
|
-
const nameStr = names.length ? `{ ${names.join(", ")} }` : void 0;
|
|
1637
|
-
if (!nameStr) return null;
|
|
1638
|
-
let typeAnnotation = node.type ? this.transform(node.type) ?? void 0 : void 0;
|
|
1639
|
-
if (!typeAnnotation) {
|
|
1640
|
-
const typeParts = sorted.filter((p) => p.type).map((p) => {
|
|
1641
|
-
const rawT = p.type ? this.transform(p.type) : void 0;
|
|
1642
|
-
const t = rawT != null && transformType ? transformType(rawT) : rawT;
|
|
1643
|
-
return p.optional || p.default !== void 0 ? `${p.name}?: ${t}` : `${p.name}: ${t}`;
|
|
1644
|
-
});
|
|
1645
|
-
typeAnnotation = typeParts.length ? `{ ${typeParts.join("; ")} }` : void 0;
|
|
1646
|
-
}
|
|
1647
|
-
if (typeAnnotation) {
|
|
1648
|
-
if (isOptional) return `${nameStr}: ${typeAnnotation} = ${node.default ?? "{}"}`;
|
|
1649
|
-
return node.default ? `${nameStr}: ${typeAnnotation} = ${node.default}` : `${nameStr}: ${typeAnnotation}`;
|
|
1650
|
-
}
|
|
1651
|
-
return node.default ? `${nameStr} = ${node.default}` : nameStr;
|
|
1652
|
-
},
|
|
1653
|
-
functionParameters(node) {
|
|
1654
|
-
return sortParams(node.params).map((p) => this.transform(p)).filter(Boolean).join(", ");
|
|
1919
|
+
function functionPrinter(options) {
|
|
1920
|
+
return {
|
|
1921
|
+
name: "functionParameters",
|
|
1922
|
+
options,
|
|
1923
|
+
print(node) {
|
|
1924
|
+
return sortParams(node.params).map((p) => printParameter(p, options)).filter(Boolean).join(", ");
|
|
1655
1925
|
}
|
|
1926
|
+
};
|
|
1927
|
+
}
|
|
1928
|
+
//#endregion
|
|
1929
|
+
//#region src/printers/operationParams.ts
|
|
1930
|
+
/**
|
|
1931
|
+
* Resolves the {@link TypeExpression} for an individual parameter.
|
|
1932
|
+
*
|
|
1933
|
+
* Without a resolver, it falls back to the schema primitive (a plain type-name string). When the
|
|
1934
|
+
* parameter belongs to a named group, it emits an `IndexedAccessType` like `GroupParams['petId']`,
|
|
1935
|
+
* otherwise the resolved individual name.
|
|
1936
|
+
*/
|
|
1937
|
+
function resolveParamType({ node, param, resolver }) {
|
|
1938
|
+
if (!resolver) return param.schema.primitive ?? "unknown";
|
|
1939
|
+
const individualName = resolver.resolveParamName(node, param);
|
|
1940
|
+
const groupLocation = param.in === "path" || param.in === "query" || param.in === "header" ? param.in : void 0;
|
|
1941
|
+
const groupResolvers = {
|
|
1942
|
+
path: resolver.resolvePathParamsName,
|
|
1943
|
+
query: resolver.resolveQueryParamsName,
|
|
1944
|
+
header: resolver.resolveHeaderParamsName
|
|
1945
|
+
};
|
|
1946
|
+
const groupName = groupLocation ? groupResolvers[groupLocation].call(resolver, node, param) : void 0;
|
|
1947
|
+
if (groupName && groupName !== individualName) return createIndexedAccessType({
|
|
1948
|
+
target: groupName,
|
|
1949
|
+
key: param.name
|
|
1950
|
+
});
|
|
1951
|
+
return individualName;
|
|
1952
|
+
}
|
|
1953
|
+
/**
|
|
1954
|
+
* Derives a {@link ParamGroupType} for a query or header group from the resolver.
|
|
1955
|
+
*
|
|
1956
|
+
* Returns `null` when there is no resolver, no params, or the group name equals the
|
|
1957
|
+
* individual param name (so there is no real group to emit).
|
|
1958
|
+
*/
|
|
1959
|
+
function resolveGroupType({ node, params, group, resolver }) {
|
|
1960
|
+
if (!resolver || !params.length) return null;
|
|
1961
|
+
const firstParam = params[0];
|
|
1962
|
+
const groupName = (group === "query" ? resolver.resolveQueryParamsName : resolver.resolveHeaderParamsName).call(resolver, node, firstParam);
|
|
1963
|
+
if (groupName === resolver.resolveParamName(node, firstParam)) return null;
|
|
1964
|
+
return {
|
|
1965
|
+
type: groupName,
|
|
1966
|
+
optional: params.every((p) => !p.required)
|
|
1967
|
+
};
|
|
1968
|
+
}
|
|
1969
|
+
/**
|
|
1970
|
+
* Converts an `OperationNode` into function parameters for code generation.
|
|
1971
|
+
*
|
|
1972
|
+
* Centralizes parameter grouping logic for all plugins. `paramsType` chooses between one
|
|
1973
|
+
* destructured object parameter (`object`) and separate top-level parameters (`inline`), while
|
|
1974
|
+
* `pathParamsType` controls how path params render in inline mode. Provide a `resolver` for type
|
|
1975
|
+
* name resolution and `extraParams` for plugin-specific trailing parameters such as an `options` object.
|
|
1976
|
+
*/
|
|
1977
|
+
function createOperationParams(node, options) {
|
|
1978
|
+
const { paramsType, pathParamsType, paramsCasing, resolver, pathParamsDefault, extraParams = [], paramNames, typeWrapper } = options;
|
|
1979
|
+
const dataName = paramNames?.data ?? "data";
|
|
1980
|
+
const paramsName = paramNames?.params ?? "params";
|
|
1981
|
+
const headersName = paramNames?.headers ?? "headers";
|
|
1982
|
+
const pathName = paramNames?.path ?? "pathParams";
|
|
1983
|
+
const wrapType = (type) => typeWrapper ? typeWrapper(type) : type;
|
|
1984
|
+
const wrapTypeExpression = (type) => typeof type === "string" ? wrapType(type) : type;
|
|
1985
|
+
const casedParams = caseParams(node.parameters, paramsCasing);
|
|
1986
|
+
const pathParams = casedParams.filter((p) => p.in === "path");
|
|
1987
|
+
const queryParams = casedParams.filter((p) => p.in === "query");
|
|
1988
|
+
const headerParams = casedParams.filter((p) => p.in === "header");
|
|
1989
|
+
const toProperty = (param) => ({
|
|
1990
|
+
name: param.name,
|
|
1991
|
+
type: wrapTypeExpression(resolveParamType({
|
|
1992
|
+
node,
|
|
1993
|
+
param,
|
|
1994
|
+
resolver
|
|
1995
|
+
})),
|
|
1996
|
+
optional: !param.required
|
|
1997
|
+
});
|
|
1998
|
+
const emptyObjectDefault = (props) => props.every((p) => p.optional) ? "{}" : void 0;
|
|
1999
|
+
const bodyType = node.requestBody?.content?.[0]?.schema ? wrapType(resolver?.resolveDataName(node) ?? "unknown") : void 0;
|
|
2000
|
+
const bodyProperty = bodyType ? [{
|
|
2001
|
+
name: dataName,
|
|
2002
|
+
type: bodyType,
|
|
2003
|
+
optional: !(node.requestBody?.required ?? false)
|
|
2004
|
+
}] : [];
|
|
2005
|
+
const trailingGroups = [{
|
|
2006
|
+
name: paramsName,
|
|
2007
|
+
node,
|
|
2008
|
+
params: queryParams,
|
|
2009
|
+
groupType: resolveGroupType({
|
|
2010
|
+
node,
|
|
2011
|
+
params: queryParams,
|
|
2012
|
+
group: "query",
|
|
2013
|
+
resolver
|
|
2014
|
+
}),
|
|
2015
|
+
resolver,
|
|
2016
|
+
wrapType
|
|
2017
|
+
}, {
|
|
2018
|
+
name: headersName,
|
|
2019
|
+
node,
|
|
2020
|
+
params: headerParams,
|
|
2021
|
+
groupType: resolveGroupType({
|
|
2022
|
+
node,
|
|
2023
|
+
params: headerParams,
|
|
2024
|
+
group: "header",
|
|
2025
|
+
resolver
|
|
2026
|
+
}),
|
|
2027
|
+
resolver,
|
|
2028
|
+
wrapType
|
|
2029
|
+
}];
|
|
2030
|
+
const params = [];
|
|
2031
|
+
if (paramsType === "object") {
|
|
2032
|
+
const children = [
|
|
2033
|
+
...pathParams.map(toProperty),
|
|
2034
|
+
...bodyProperty,
|
|
2035
|
+
...trailingGroups.flatMap(buildGroupProperty)
|
|
2036
|
+
];
|
|
2037
|
+
if (children.length) params.push(createFunctionParameter({
|
|
2038
|
+
properties: children,
|
|
2039
|
+
default: emptyObjectDefault(children)
|
|
2040
|
+
}));
|
|
2041
|
+
} else {
|
|
2042
|
+
if (pathParamsType === "inlineSpread" && pathParams.length) {
|
|
2043
|
+
const spreadType = resolver?.resolvePathParamsName(node, pathParams[0]);
|
|
2044
|
+
params.push(createFunctionParameter({
|
|
2045
|
+
name: pathName,
|
|
2046
|
+
type: spreadType ? wrapType(spreadType) : void 0,
|
|
2047
|
+
rest: true
|
|
2048
|
+
}));
|
|
2049
|
+
} else if (pathParamsType === "inline") params.push(...pathParams.map((p) => createFunctionParameter(toProperty(p))));
|
|
2050
|
+
else if (pathParams.length) {
|
|
2051
|
+
const pathChildren = pathParams.map(toProperty);
|
|
2052
|
+
params.push(createFunctionParameter({
|
|
2053
|
+
properties: pathChildren,
|
|
2054
|
+
default: pathParamsDefault ?? emptyObjectDefault(pathChildren)
|
|
2055
|
+
}));
|
|
2056
|
+
}
|
|
2057
|
+
params.push(...bodyProperty.map((p) => createFunctionParameter(p)));
|
|
2058
|
+
params.push(...trailingGroups.flatMap(buildGroupParam));
|
|
1656
2059
|
}
|
|
1657
|
-
|
|
2060
|
+
params.push(...extraParams);
|
|
2061
|
+
return createFunctionParameters({ params });
|
|
2062
|
+
}
|
|
2063
|
+
/**
|
|
2064
|
+
* Builds the property descriptor for a query or header group.
|
|
2065
|
+
* Returns an empty array when there are no params to emit.
|
|
2066
|
+
*
|
|
2067
|
+
* A pre-resolved `groupType` emits `name: GroupType`. Otherwise it builds an inline
|
|
2068
|
+
* {@link TypeLiteralNode} from the individual params.
|
|
2069
|
+
*/
|
|
2070
|
+
function buildGroupProperty({ name, node, params, groupType, resolver, wrapType }) {
|
|
2071
|
+
if (groupType) return [{
|
|
2072
|
+
name,
|
|
2073
|
+
type: typeof groupType.type === "string" ? wrapType(groupType.type) : groupType.type,
|
|
2074
|
+
optional: groupType.optional
|
|
2075
|
+
}];
|
|
2076
|
+
if (params.length) return [{
|
|
2077
|
+
name,
|
|
2078
|
+
type: buildTypeLiteral({
|
|
2079
|
+
node,
|
|
2080
|
+
params,
|
|
2081
|
+
resolver
|
|
2082
|
+
}),
|
|
2083
|
+
optional: params.every((p) => !p.required)
|
|
2084
|
+
}];
|
|
2085
|
+
return [];
|
|
2086
|
+
}
|
|
2087
|
+
/**
|
|
2088
|
+
* Builds a single {@link FunctionParameterNode} for a query or header group.
|
|
2089
|
+
* Returns an empty array when there are no params to emit.
|
|
2090
|
+
*/
|
|
2091
|
+
function buildGroupParam(args) {
|
|
2092
|
+
return buildGroupProperty(args).map((p) => createFunctionParameter(p));
|
|
2093
|
+
}
|
|
2094
|
+
/**
|
|
2095
|
+
* Builds a {@link TypeLiteralNode} for an inline anonymous type grouping named fields.
|
|
2096
|
+
*
|
|
2097
|
+
* Used when query or header parameters have no dedicated group type name.
|
|
2098
|
+
*/
|
|
2099
|
+
function buildTypeLiteral({ node, params, resolver }) {
|
|
2100
|
+
return createTypeLiteral({ members: params.map((p) => ({
|
|
2101
|
+
name: p.name,
|
|
2102
|
+
type: resolveParamType({
|
|
2103
|
+
node,
|
|
2104
|
+
param: p,
|
|
2105
|
+
resolver
|
|
2106
|
+
}),
|
|
2107
|
+
optional: !p.required
|
|
2108
|
+
})) });
|
|
2109
|
+
}
|
|
1658
2110
|
//#endregion
|
|
1659
|
-
export { Enum, Type, pluginTs as default, pluginTs, functionPrinter, pluginTsName, printerTs, resolverTs, typeGenerator };
|
|
2111
|
+
export { Enum, Type, createFunctionParameter, createFunctionParameters, createIndexedAccessType, createObjectBindingPattern, createOperationParams, createTypeLiteral, pluginTs as default, pluginTs, functionPrinter, pluginTsName, printerTs, renderType, resolverTs, typeGenerator };
|
|
1660
2112
|
|
|
1661
2113
|
//# sourceMappingURL=index.js.map
|