@kubb/plugin-ts 5.0.0 → 5.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +175 -160
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +17 -17
- package/dist/index.js +175 -160
- package/dist/index.js.map +1 -1
- package/package.json +21 -5
package/dist/index.d.ts
CHANGED
|
@@ -110,7 +110,7 @@ type PrinterTsFactory = ast.PrinterFactoryOptions<'typescript', PrinterTsOptions
|
|
|
110
110
|
* const declaration = printer.print(schemaNode) // ts.TypeAliasDeclaration | ts.InterfaceDeclaration
|
|
111
111
|
* ```
|
|
112
112
|
*/
|
|
113
|
-
declare const printerTs: (options?: PrinterTsOptions | undefined) => ast.Printer<PrinterTsFactory>;
|
|
113
|
+
export declare const printerTs: (options?: PrinterTsOptions | undefined) => ast.Printer<PrinterTsFactory>;
|
|
114
114
|
//#endregion
|
|
115
115
|
//#region src/types.d.ts
|
|
116
116
|
/**
|
|
@@ -457,7 +457,7 @@ type Props$1 = {
|
|
|
457
457
|
* The emitted `File.Source` nodes carry the resolved names so that the barrel
|
|
458
458
|
* index picks up the correct export identifiers.
|
|
459
459
|
*/
|
|
460
|
-
declare function Enum({ node, enum: enumOptions, resolver }: Props$1): KubbReactNode;
|
|
460
|
+
export declare function Enum({ node, enum: enumOptions, resolver }: Props$1): KubbReactNode;
|
|
461
461
|
//#endregion
|
|
462
462
|
//#region src/components/Type.d.ts
|
|
463
463
|
type Props = {
|
|
@@ -471,7 +471,7 @@ type Props = {
|
|
|
471
471
|
enum: PluginTs['resolvedOptions']['enum'];
|
|
472
472
|
resolver: ResolverTs;
|
|
473
473
|
};
|
|
474
|
-
declare function Type({ name, node, printer, enum: enumOptions, resolver }: Props): KubbReactNode;
|
|
474
|
+
export declare function Type({ name, node, printer, enum: enumOptions, resolver }: Props): KubbReactNode;
|
|
475
475
|
//#endregion
|
|
476
476
|
//#region src/generators/typeGenerator.d.ts
|
|
477
477
|
/**
|
|
@@ -480,14 +480,14 @@ declare function Type({ name, node, printer, enum: enumOptions, resolver }: Prop
|
|
|
480
480
|
* types. Drop-replace with a custom `Generator<PluginTs>` to change how
|
|
481
481
|
* TypeScript output is produced.
|
|
482
482
|
*/
|
|
483
|
-
declare const typeGenerator: import("kubb/kit").Generator<PluginTs, unknown>;
|
|
483
|
+
export declare const typeGenerator: import("kubb/kit").Generator<PluginTs, unknown>;
|
|
484
484
|
//#endregion
|
|
485
485
|
//#region src/plugin.d.ts
|
|
486
486
|
/**
|
|
487
487
|
* Canonical plugin name for `@kubb/plugin-ts`. Used for driver lookups and
|
|
488
488
|
* cross-plugin dependency references.
|
|
489
489
|
*/
|
|
490
|
-
declare const pluginTsName = "plugin-ts";
|
|
490
|
+
export declare const pluginTsName = "plugin-ts";
|
|
491
491
|
/**
|
|
492
492
|
* Generates TypeScript `type` aliases and `interface` declarations from an
|
|
493
493
|
* OpenAPI spec. The foundation that every other Kubb plugin builds on:
|
|
@@ -512,7 +512,7 @@ declare const pluginTsName = "plugin-ts";
|
|
|
512
512
|
* })
|
|
513
513
|
* ```
|
|
514
514
|
*/
|
|
515
|
-
declare const pluginTs: (options?: Options | undefined) => import("kubb/kit").Plugin<PluginTs>;
|
|
515
|
+
export declare const pluginTs: (options?: Options | undefined) => import("kubb/kit").Plugin<PluginTs>;
|
|
516
516
|
//#endregion
|
|
517
517
|
//#region src/printers/functionParams.d.ts
|
|
518
518
|
/**
|
|
@@ -646,7 +646,7 @@ type FunctionParametersNode = {
|
|
|
646
646
|
* // { petId: string }
|
|
647
647
|
* ```
|
|
648
648
|
*/
|
|
649
|
-
declare function createTypeLiteral(props: Omit<TypeLiteralNode, 'kind'>): TypeLiteralNode;
|
|
649
|
+
export declare function createTypeLiteral(props: Omit<TypeLiteralNode, 'kind'>): TypeLiteralNode;
|
|
650
650
|
/**
|
|
651
651
|
* Creates an {@link IndexedAccessTypeNode} representing a single field accessed from a named type.
|
|
652
652
|
*
|
|
@@ -656,7 +656,7 @@ declare function createTypeLiteral(props: Omit<TypeLiteralNode, 'kind'>): TypeLi
|
|
|
656
656
|
* // DeletePetPathParams['petId']
|
|
657
657
|
* ```
|
|
658
658
|
*/
|
|
659
|
-
declare function createIndexedAccessType(props: Omit<IndexedAccessTypeNode, 'kind'>): IndexedAccessTypeNode;
|
|
659
|
+
export declare function createIndexedAccessType(props: Omit<IndexedAccessTypeNode, 'kind'>): IndexedAccessTypeNode;
|
|
660
660
|
/**
|
|
661
661
|
* Creates an {@link ObjectBindingPatternNode} for a destructured parameter binding.
|
|
662
662
|
*
|
|
@@ -666,7 +666,7 @@ declare function createIndexedAccessType(props: Omit<IndexedAccessTypeNode, 'kin
|
|
|
666
666
|
* // { id, name }
|
|
667
667
|
* ```
|
|
668
668
|
*/
|
|
669
|
-
declare function createObjectBindingPattern(props: Omit<ObjectBindingPatternNode, 'kind'>): ObjectBindingPatternNode;
|
|
669
|
+
export declare function createObjectBindingPattern(props: Omit<ObjectBindingPatternNode, 'kind'>): ObjectBindingPatternNode;
|
|
670
670
|
/**
|
|
671
671
|
* Plain property descriptor for a destructured group built by {@link createFunctionParameter}.
|
|
672
672
|
*/
|
|
@@ -703,7 +703,7 @@ type FunctionParameterInput = {
|
|
|
703
703
|
* // → { id, name }: { id: string; name?: string } = {}
|
|
704
704
|
* ```
|
|
705
705
|
*/
|
|
706
|
-
declare function createFunctionParameter(input: FunctionParameterInput): FunctionParameterNode;
|
|
706
|
+
export declare function createFunctionParameter(input: FunctionParameterInput): FunctionParameterNode;
|
|
707
707
|
/**
|
|
708
708
|
* Creates a {@link FunctionParametersNode} from an ordered list of parameters.
|
|
709
709
|
*
|
|
@@ -713,7 +713,7 @@ declare function createFunctionParameter(input: FunctionParameterInput): Functio
|
|
|
713
713
|
* // { params: [] }
|
|
714
714
|
* ```
|
|
715
715
|
*/
|
|
716
|
-
declare function createFunctionParameters(props?: Partial<Omit<FunctionParametersNode, 'kind'>>): FunctionParametersNode;
|
|
716
|
+
export declare function createFunctionParameters(props?: Partial<Omit<FunctionParametersNode, 'kind'>>): FunctionParametersNode;
|
|
717
717
|
//#endregion
|
|
718
718
|
//#region src/printers/functionPrinter.d.ts
|
|
719
719
|
/**
|
|
@@ -726,7 +726,7 @@ declare function createFunctionParameters(props?: Partial<Omit<FunctionParameter
|
|
|
726
726
|
* `transformType` is applied once to the fully rendered type, matching how the
|
|
727
727
|
* printer wrapped reference types before the `ts.factory` model.
|
|
728
728
|
*/
|
|
729
|
-
declare function renderType(type: TypeExpression, transformType?: (type: string) => string): string;
|
|
729
|
+
export declare function renderType(type: TypeExpression, transformType?: (type: string) => string): string;
|
|
730
730
|
type FunctionPrinterOptions = {
|
|
731
731
|
/**
|
|
732
732
|
* Rendering modes supported by `functionPrinter`.
|
|
@@ -764,7 +764,7 @@ type FunctionPrinterOptions = {
|
|
|
764
764
|
* printer.print(sig) // → "petId: string, config: Config = {}"
|
|
765
765
|
* ```
|
|
766
766
|
*/
|
|
767
|
-
declare function functionPrinter(options: FunctionPrinterOptions): {
|
|
767
|
+
export declare function functionPrinter(options: FunctionPrinterOptions): {
|
|
768
768
|
name: "functionParameters";
|
|
769
769
|
options: FunctionPrinterOptions;
|
|
770
770
|
print(node: FunctionParametersNode): string;
|
|
@@ -911,7 +911,7 @@ type CreateOperationParamsOptions = {
|
|
|
911
911
|
* `pathParamsType` controls how path params render in inline mode. Provide a `resolver` for type
|
|
912
912
|
* name resolution and `extraParams` for plugin-specific trailing parameters such as an `options` object.
|
|
913
913
|
*/
|
|
914
|
-
declare function createOperationParams(node: ast.OperationNode, options: CreateOperationParamsOptions): FunctionParametersNode;
|
|
914
|
+
export declare function createOperationParams(node: ast.OperationNode, options: CreateOperationParamsOptions): FunctionParametersNode;
|
|
915
915
|
//#endregion
|
|
916
916
|
//#region src/resolvers/resolverTs.d.ts
|
|
917
917
|
/**
|
|
@@ -933,7 +933,7 @@ declare function createOperationParams(node: ast.OperationNode, options: CreateO
|
|
|
933
933
|
* resolverTs.response.status(node, 200) // 'ListPetsStatus200'
|
|
934
934
|
* ```
|
|
935
935
|
*/
|
|
936
|
-
declare const resolverTs: ResolverTs;
|
|
936
|
+
export declare const resolverTs: ResolverTs;
|
|
937
937
|
//#endregion
|
|
938
938
|
//#region src/utils.d.ts
|
|
939
939
|
type BuildParamsSchemaOptions = {
|
|
@@ -944,7 +944,7 @@ type BuildParamsSchemaOptions = {
|
|
|
944
944
|
* header), embedding each param's own schema (and JSDoc) directly rather than referencing a
|
|
945
945
|
* separate per-param type — the group itself is the only type these params get exported as.
|
|
946
946
|
*/
|
|
947
|
-
declare function buildParams({ params }: BuildParamsSchemaOptions): ast.SchemaNode;
|
|
947
|
+
export declare function buildParams({ params }: BuildParamsSchemaOptions): ast.SchemaNode;
|
|
948
948
|
//#endregion
|
|
949
|
-
export { type CreateOperationParamsOptions,
|
|
949
|
+
export { type CreateOperationParamsOptions, type FunctionParameterNode, type FunctionParametersNode, type IndexedAccessTypeNode, type ObjectBindingPatternNode, type PluginTs, type PrinterTsFactory, type PrinterTsNodes, type PrinterTsOptions, type ResolverTs, type TypeExpression, type TypeLiteralNode, pluginTs as default };
|
|
950
950
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -626,8 +626,10 @@ function createEnumDeclaration({ type = "enum", name, typeName, enums, enumKeyCa
|
|
|
626
626
|
}).filter((node) => node !== void 0)))];
|
|
627
627
|
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, description]) => {
|
|
628
628
|
let initializer = factory.createStringLiteral(value?.toString());
|
|
629
|
-
if (Number.parseInt(value.toString(), 10) === value && isNumber(value))
|
|
630
|
-
|
|
629
|
+
if (Number.parseInt(value.toString(), 10) === value && isNumber(value)) {
|
|
630
|
+
if (value < 0) initializer = factory.createPrefixUnaryExpression(ts.SyntaxKind.MinusToken, factory.createNumericLiteral(Math.abs(value)));
|
|
631
|
+
else initializer = factory.createNumericLiteral(value);
|
|
632
|
+
}
|
|
631
633
|
if (typeof value === "boolean") initializer = value ? factory.createTrue() : factory.createFalse();
|
|
632
634
|
if (isNumber(Number.parseInt(key.toString(), 10))) {
|
|
633
635
|
const casingKey = applyEnumKeyCasing(`${typeName}_${key}`, enumKeyCasing);
|
|
@@ -648,8 +650,10 @@ function createEnumDeclaration({ type = "enum", name, typeName, enums, enumKeyCa
|
|
|
648
650
|
if (enums.length === 0) return [void 0, factory.createTypeAliasDeclaration([factory.createToken(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier(typeName), void 0, factory.createKeywordTypeNode(ts.SyntaxKind.NeverKeyword))];
|
|
649
651
|
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, description]) => {
|
|
650
652
|
let initializer = factory.createStringLiteral(value?.toString());
|
|
651
|
-
if (isNumber(value))
|
|
652
|
-
|
|
653
|
+
if (isNumber(value)) {
|
|
654
|
+
if (value < 0) initializer = factory.createPrefixUnaryExpression(ts.SyntaxKind.MinusToken, factory.createNumericLiteral(Math.abs(value)));
|
|
655
|
+
else initializer = factory.createNumericLiteral(value);
|
|
656
|
+
}
|
|
653
657
|
if (typeof value === "boolean") initializer = value ? factory.createTrue() : factory.createFalse();
|
|
654
658
|
if (key !== null && key !== void 0) {
|
|
655
659
|
const casingKey = applyEnumKeyCasing(key.toString(), enumKeyCasing);
|
|
@@ -911,6 +915,115 @@ function Enum({ node, enum: enumOptions, resolver }) {
|
|
|
911
915
|
})] });
|
|
912
916
|
}
|
|
913
917
|
//#endregion
|
|
918
|
+
//#region src/utils.ts
|
|
919
|
+
/**
|
|
920
|
+
* Tells whether a `const` (single-value enum) should render as a bare literal type (`'active'`)
|
|
921
|
+
* rather than a named enum reference or a runtime enum declaration.
|
|
922
|
+
*
|
|
923
|
+
* The parser folds `const` into a single-value enum node. The adapter decides which schemas are
|
|
924
|
+
* named enums and lists them in `enumSchemaNames`, and references to those names get suffixed (for
|
|
925
|
+
* example `StatusKey`). A const renders as a literal only when the adapter has not registered it as
|
|
926
|
+
* a named enum, which keeps the declaration and its references in sync across adapter versions.
|
|
927
|
+
*/
|
|
928
|
+
function isInlineConstEnum(node, enumSchemaNames) {
|
|
929
|
+
return (node.namedEnumValues ?? node.enumValues ?? []).length === 1 && !(node.name && enumSchemaNames?.has(node.name));
|
|
930
|
+
}
|
|
931
|
+
/**
|
|
932
|
+
* Collects JSDoc annotation strings for a schema node.
|
|
933
|
+
*
|
|
934
|
+
* Only uses official JSDoc tags from https://jsdoc.app/: `@description`, `@deprecated`, `@default`, `@example`, `@type`.
|
|
935
|
+
* Constraint metadata (min/max length, pattern, multipleOf, min/maxProperties) is emitted as plain-text lines.
|
|
936
|
+
|
|
937
|
+
*/
|
|
938
|
+
function isSchemaOptional(schema) {
|
|
939
|
+
return Boolean("optional" in schema && schema.optional || "nullish" in schema && schema.nullish);
|
|
940
|
+
}
|
|
941
|
+
function formatExample(value) {
|
|
942
|
+
if (value === null || typeof value !== "object") return String(value);
|
|
943
|
+
return (JSON.stringify(value) ?? String(value)).replaceAll("*/", "*\\/");
|
|
944
|
+
}
|
|
945
|
+
function buildPropertyJSDocComments(schema, optional) {
|
|
946
|
+
const meta = syncSchemaRef(schema);
|
|
947
|
+
const isArray = meta?.primitive === "array";
|
|
948
|
+
const hasDescription = meta && "description" in meta && meta.description;
|
|
949
|
+
const formatComment = meta && "format" in meta && meta.format ? hasDescription ? [" ", `Format: \`${meta.format}\``] : ["@description", `Format: \`${meta.format}\``] : [];
|
|
950
|
+
const exampleValues = meta?.examples ?? [];
|
|
951
|
+
const comments = [
|
|
952
|
+
hasDescription ? `@description ${jsStringEscape(meta.description)}` : null,
|
|
953
|
+
...formatComment,
|
|
954
|
+
meta && "deprecated" in meta && meta.deprecated ? "@deprecated" : null,
|
|
955
|
+
!isArray && meta && "min" in meta && meta.min !== void 0 ? `@minLength ${meta.min}` : null,
|
|
956
|
+
!isArray && meta && "max" in meta && meta.max !== void 0 ? `@maxLength ${meta.max}` : null,
|
|
957
|
+
meta && "pattern" in meta && meta.pattern ? `@pattern ${meta.pattern}` : null,
|
|
958
|
+
meta && "default" in meta && meta.default !== void 0 ? `@default ${"primitive" in meta && meta.primitive === "string" && typeof meta.default === "string" ? stringify(meta.default) : meta.default}` : null,
|
|
959
|
+
...exampleValues.map((example) => `@example ${formatExample(example)}`)
|
|
960
|
+
].filter(Boolean);
|
|
961
|
+
const typeTag = comments.length && meta && "primitive" in meta && meta.primitive ? [`@type ${meta.primitive}`, optional ?? isSchemaOptional(schema) ? " | undefined" : null].filter(Boolean).join("") : null;
|
|
962
|
+
return [...comments, typeTag].filter(Boolean);
|
|
963
|
+
}
|
|
964
|
+
/**
|
|
965
|
+
* Builds the object schema for a group of parameters sharing one `in` location (path, query, or
|
|
966
|
+
* header), embedding each param's own schema (and JSDoc) directly rather than referencing a
|
|
967
|
+
* separate per-param type — the group itself is the only type these params get exported as.
|
|
968
|
+
*/
|
|
969
|
+
function buildParams({ params }) {
|
|
970
|
+
return ast.factory.createSchema({
|
|
971
|
+
type: "object",
|
|
972
|
+
properties: params.map((param) => ast.factory.createProperty({
|
|
973
|
+
name: param.name,
|
|
974
|
+
required: param.required,
|
|
975
|
+
schema: ast.factory.createSchema({
|
|
976
|
+
...param.schema,
|
|
977
|
+
optional: !param.required
|
|
978
|
+
})
|
|
979
|
+
}))
|
|
980
|
+
});
|
|
981
|
+
}
|
|
982
|
+
function buildResponseUnion(node, { resolver }) {
|
|
983
|
+
const responsesWithSchema = node.responses.filter((res) => res.content?.some((entry) => entry.schema));
|
|
984
|
+
if (responsesWithSchema.length === 0) return null;
|
|
985
|
+
return ast.factory.createSchema({
|
|
986
|
+
type: "union",
|
|
987
|
+
members: responsesWithSchema.map((res) => ast.factory.createSchema({
|
|
988
|
+
type: "ref",
|
|
989
|
+
name: resolver.response.status(node, res.statusCode)
|
|
990
|
+
}))
|
|
991
|
+
});
|
|
992
|
+
}
|
|
993
|
+
//#endregion
|
|
994
|
+
//#region src/components/Type.tsx
|
|
995
|
+
function Type({ name, node, printer, enum: enumOptions, resolver }) {
|
|
996
|
+
const enumSchemaNodes = ast.collectSync(node, { schema(n) {
|
|
997
|
+
const enumNode = ast.narrowSchema(n, ast.schemaTypes.enum);
|
|
998
|
+
if (enumNode?.name && !isInlineConstEnum(enumNode, printer.options.enumSchemaNames)) return enumNode;
|
|
999
|
+
} });
|
|
1000
|
+
const output = printer.print(node);
|
|
1001
|
+
if (!output) return;
|
|
1002
|
+
const enums = [...new Map(enumSchemaNodes.map((n) => [n.name, n])).values()].map((node) => {
|
|
1003
|
+
return {
|
|
1004
|
+
node,
|
|
1005
|
+
...getEnumNames({
|
|
1006
|
+
node,
|
|
1007
|
+
enum: enumOptions,
|
|
1008
|
+
resolver
|
|
1009
|
+
})
|
|
1010
|
+
};
|
|
1011
|
+
});
|
|
1012
|
+
const shouldExportEnums = enumOptions.type !== "inlineLiteral";
|
|
1013
|
+
const shouldExportType = enumOptions.type === "inlineLiteral" || enums.every((item) => item.typeName !== name);
|
|
1014
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [shouldExportEnums && enums.map(({ node }) => /* @__PURE__ */ jsx(Enum, {
|
|
1015
|
+
node,
|
|
1016
|
+
enum: enumOptions,
|
|
1017
|
+
resolver
|
|
1018
|
+
}, node.name)), shouldExportType && /* @__PURE__ */ jsx(File.Source, {
|
|
1019
|
+
name,
|
|
1020
|
+
isTypeOnly: true,
|
|
1021
|
+
isExportable: true,
|
|
1022
|
+
isIndexable: true,
|
|
1023
|
+
children: output
|
|
1024
|
+
})] });
|
|
1025
|
+
}
|
|
1026
|
+
//#endregion
|
|
914
1027
|
//#region ../../internals/shared/src/params.ts
|
|
915
1028
|
/**
|
|
916
1029
|
* Drops parameters that share the same name, keeping the first.
|
|
@@ -1054,6 +1167,62 @@ function buildOptionsSchema(node, resolver) {
|
|
|
1054
1167
|
})]
|
|
1055
1168
|
});
|
|
1056
1169
|
}
|
|
1170
|
+
/**
|
|
1171
|
+
* The schema a status occupies in the `<Name>Responses` record. A status that documents several
|
|
1172
|
+
* content types becomes a `{ contentType; data }` union so the runtime can surface the negotiated type
|
|
1173
|
+
* on `result.parsed`, while the standalone `<Name>StatusNNN` alias stays the plain body union that the
|
|
1174
|
+
* query hooks and `result.data` use.
|
|
1175
|
+
*/
|
|
1176
|
+
function buildResponseRecordEntry(node, res, resolver) {
|
|
1177
|
+
const statusName = resolver.response.status(node, res.statusCode);
|
|
1178
|
+
const variants = (res.content ?? []).filter((entry) => entry.schema);
|
|
1179
|
+
if (variants.length <= 1) return ast.factory.createSchema({
|
|
1180
|
+
type: "ref",
|
|
1181
|
+
name: statusName
|
|
1182
|
+
});
|
|
1183
|
+
return ast.factory.createSchema({
|
|
1184
|
+
type: "union",
|
|
1185
|
+
members: resolveContentTypeVariants(variants, statusName).map((variant) => ast.factory.createSchema({
|
|
1186
|
+
type: "object",
|
|
1187
|
+
primitive: "object",
|
|
1188
|
+
properties: [ast.factory.createProperty({
|
|
1189
|
+
name: "contentType",
|
|
1190
|
+
required: true,
|
|
1191
|
+
schema: ast.factory.createSchema({
|
|
1192
|
+
type: "enum",
|
|
1193
|
+
enumValues: [variant.contentType]
|
|
1194
|
+
})
|
|
1195
|
+
}), ast.factory.createProperty({
|
|
1196
|
+
name: "data",
|
|
1197
|
+
required: true,
|
|
1198
|
+
schema: ast.factory.createSchema({
|
|
1199
|
+
type: "ref",
|
|
1200
|
+
name: variant.name
|
|
1201
|
+
})
|
|
1202
|
+
})]
|
|
1203
|
+
}))
|
|
1204
|
+
});
|
|
1205
|
+
}
|
|
1206
|
+
/**
|
|
1207
|
+
* Builds the per-status `<Name>Responses` record for an operation, referencing the already-resolved
|
|
1208
|
+
* `<Name>StatusNNN` names. Shared by `@kubb/plugin-ts`'s `Responses` type and `@kubb/plugin-zod`'s
|
|
1209
|
+
* inferred responses schema, so both emit the same shape from the same inputs.
|
|
1210
|
+
*
|
|
1211
|
+
* Always emits the keyed record, even when an operation declares no responses. An operation with no
|
|
1212
|
+
* responses renders as an empty object, which keeps every consumer's import (for example the axios
|
|
1213
|
+
* SDK's `RequestResult<XResponses>`) resolvable instead of pointing at a missing export.
|
|
1214
|
+
*/
|
|
1215
|
+
function buildResponses(node, resolver) {
|
|
1216
|
+
return ast.factory.createSchema({
|
|
1217
|
+
type: "object",
|
|
1218
|
+
primitive: "object",
|
|
1219
|
+
properties: node.responses.map((res) => ast.factory.createProperty({
|
|
1220
|
+
name: String(res.statusCode),
|
|
1221
|
+
required: true,
|
|
1222
|
+
schema: buildResponseRecordEntry(node, res, resolver)
|
|
1223
|
+
}))
|
|
1224
|
+
});
|
|
1225
|
+
}
|
|
1057
1226
|
//#endregion
|
|
1058
1227
|
//#region ../../internals/shared/src/resolver.ts
|
|
1059
1228
|
/**
|
|
@@ -1204,160 +1373,6 @@ function mapSchemaItems(node, transform) {
|
|
|
1204
1373
|
}));
|
|
1205
1374
|
}
|
|
1206
1375
|
//#endregion
|
|
1207
|
-
//#region src/utils.ts
|
|
1208
|
-
/**
|
|
1209
|
-
* Tells whether a `const` (single-value enum) should render as a bare literal type (`'active'`)
|
|
1210
|
-
* rather than a named enum reference or a runtime enum declaration.
|
|
1211
|
-
*
|
|
1212
|
-
* The parser folds `const` into a single-value enum node. The adapter decides which schemas are
|
|
1213
|
-
* named enums and lists them in `enumSchemaNames`, and references to those names get suffixed (for
|
|
1214
|
-
* example `StatusKey`). A const renders as a literal only when the adapter has not registered it as
|
|
1215
|
-
* a named enum, which keeps the declaration and its references in sync across adapter versions.
|
|
1216
|
-
*/
|
|
1217
|
-
function isInlineConstEnum(node, enumSchemaNames) {
|
|
1218
|
-
return (node.namedEnumValues ?? node.enumValues ?? []).length === 1 && !(node.name && enumSchemaNames?.has(node.name));
|
|
1219
|
-
}
|
|
1220
|
-
/**
|
|
1221
|
-
* Collects JSDoc annotation strings for a schema node.
|
|
1222
|
-
*
|
|
1223
|
-
* Only uses official JSDoc tags from https://jsdoc.app/: `@description`, `@deprecated`, `@default`, `@example`, `@type`.
|
|
1224
|
-
* Constraint metadata (min/max length, pattern, multipleOf, min/maxProperties) is emitted as plain-text lines.
|
|
1225
|
-
|
|
1226
|
-
*/
|
|
1227
|
-
function isSchemaOptional(schema) {
|
|
1228
|
-
return Boolean("optional" in schema && schema.optional || "nullish" in schema && schema.nullish);
|
|
1229
|
-
}
|
|
1230
|
-
function formatExample(value) {
|
|
1231
|
-
if (value === null || typeof value !== "object") return String(value);
|
|
1232
|
-
return (JSON.stringify(value) ?? String(value)).replaceAll("*/", "*\\/");
|
|
1233
|
-
}
|
|
1234
|
-
function buildPropertyJSDocComments(schema, optional) {
|
|
1235
|
-
const meta = syncSchemaRef(schema);
|
|
1236
|
-
const isArray = meta?.primitive === "array";
|
|
1237
|
-
const hasDescription = meta && "description" in meta && meta.description;
|
|
1238
|
-
const formatComment = meta && "format" in meta && meta.format ? hasDescription ? [" ", `Format: \`${meta.format}\``] : ["@description", `Format: \`${meta.format}\``] : [];
|
|
1239
|
-
const exampleValues = meta?.examples ?? [];
|
|
1240
|
-
const comments = [
|
|
1241
|
-
hasDescription ? `@description ${jsStringEscape(meta.description)}` : null,
|
|
1242
|
-
...formatComment,
|
|
1243
|
-
meta && "deprecated" in meta && meta.deprecated ? "@deprecated" : null,
|
|
1244
|
-
!isArray && meta && "min" in meta && meta.min !== void 0 ? `@minLength ${meta.min}` : null,
|
|
1245
|
-
!isArray && meta && "max" in meta && meta.max !== void 0 ? `@maxLength ${meta.max}` : null,
|
|
1246
|
-
meta && "pattern" in meta && meta.pattern ? `@pattern ${meta.pattern}` : null,
|
|
1247
|
-
meta && "default" in meta && meta.default !== void 0 ? `@default ${"primitive" in meta && meta.primitive === "string" && typeof meta.default === "string" ? stringify(meta.default) : meta.default}` : null,
|
|
1248
|
-
...exampleValues.map((example) => `@example ${formatExample(example)}`)
|
|
1249
|
-
].filter(Boolean);
|
|
1250
|
-
const typeTag = comments.length && meta && "primitive" in meta && meta.primitive ? [`@type ${meta.primitive}`, optional ?? isSchemaOptional(schema) ? " | undefined" : null].filter(Boolean).join("") : null;
|
|
1251
|
-
return [...comments, typeTag].filter(Boolean);
|
|
1252
|
-
}
|
|
1253
|
-
/**
|
|
1254
|
-
* Builds the object schema for a group of parameters sharing one `in` location (path, query, or
|
|
1255
|
-
* header), embedding each param's own schema (and JSDoc) directly rather than referencing a
|
|
1256
|
-
* separate per-param type — the group itself is the only type these params get exported as.
|
|
1257
|
-
*/
|
|
1258
|
-
function buildParams({ params }) {
|
|
1259
|
-
return ast.factory.createSchema({
|
|
1260
|
-
type: "object",
|
|
1261
|
-
properties: params.map((param) => ast.factory.createProperty({
|
|
1262
|
-
name: param.name,
|
|
1263
|
-
required: param.required,
|
|
1264
|
-
schema: ast.factory.createSchema({
|
|
1265
|
-
...param.schema,
|
|
1266
|
-
optional: !param.required
|
|
1267
|
-
})
|
|
1268
|
-
}))
|
|
1269
|
-
});
|
|
1270
|
-
}
|
|
1271
|
-
/**
|
|
1272
|
-
* The schema a status occupies in the `<Name>Responses` record. A status that documents several
|
|
1273
|
-
* content types becomes a `{ contentType; data }` union so the runtime can surface the negotiated type
|
|
1274
|
-
* on `result.parsed`, while the standalone `<Name>StatusNNN` alias stays the plain body union that the
|
|
1275
|
-
* query hooks and `result.data` use.
|
|
1276
|
-
*/
|
|
1277
|
-
function buildResponseRecordEntry(node, res, resolver) {
|
|
1278
|
-
const statusName = resolver.response.status(node, res.statusCode);
|
|
1279
|
-
const variants = (res.content ?? []).filter((entry) => entry.schema);
|
|
1280
|
-
if (variants.length <= 1) return ast.factory.createSchema({
|
|
1281
|
-
type: "ref",
|
|
1282
|
-
name: statusName
|
|
1283
|
-
});
|
|
1284
|
-
return ast.factory.createSchema({
|
|
1285
|
-
type: "union",
|
|
1286
|
-
members: resolveContentTypeVariants(variants, statusName).map((variant) => ast.factory.createSchema({
|
|
1287
|
-
type: "object",
|
|
1288
|
-
properties: [ast.factory.createProperty({
|
|
1289
|
-
name: "contentType",
|
|
1290
|
-
required: true,
|
|
1291
|
-
schema: ast.factory.createSchema({
|
|
1292
|
-
type: "enum",
|
|
1293
|
-
enumValues: [variant.contentType]
|
|
1294
|
-
})
|
|
1295
|
-
}), ast.factory.createProperty({
|
|
1296
|
-
name: "data",
|
|
1297
|
-
required: true,
|
|
1298
|
-
schema: ast.factory.createSchema({
|
|
1299
|
-
type: "ref",
|
|
1300
|
-
name: variant.name
|
|
1301
|
-
})
|
|
1302
|
-
})]
|
|
1303
|
-
}))
|
|
1304
|
-
});
|
|
1305
|
-
}
|
|
1306
|
-
function buildResponses(node, { resolver }) {
|
|
1307
|
-
return ast.factory.createSchema({
|
|
1308
|
-
type: "object",
|
|
1309
|
-
properties: node.responses.map((res) => ast.factory.createProperty({
|
|
1310
|
-
name: String(res.statusCode),
|
|
1311
|
-
required: true,
|
|
1312
|
-
schema: buildResponseRecordEntry(node, res, resolver)
|
|
1313
|
-
}))
|
|
1314
|
-
});
|
|
1315
|
-
}
|
|
1316
|
-
function buildResponseUnion(node, { resolver }) {
|
|
1317
|
-
const responsesWithSchema = node.responses.filter((res) => res.content?.some((entry) => entry.schema));
|
|
1318
|
-
if (responsesWithSchema.length === 0) return null;
|
|
1319
|
-
return ast.factory.createSchema({
|
|
1320
|
-
type: "union",
|
|
1321
|
-
members: responsesWithSchema.map((res) => ast.factory.createSchema({
|
|
1322
|
-
type: "ref",
|
|
1323
|
-
name: resolver.response.status(node, res.statusCode)
|
|
1324
|
-
}))
|
|
1325
|
-
});
|
|
1326
|
-
}
|
|
1327
|
-
//#endregion
|
|
1328
|
-
//#region src/components/Type.tsx
|
|
1329
|
-
function Type({ name, node, printer, enum: enumOptions, resolver }) {
|
|
1330
|
-
const enumSchemaNodes = ast.collectSync(node, { schema(n) {
|
|
1331
|
-
const enumNode = ast.narrowSchema(n, ast.schemaTypes.enum);
|
|
1332
|
-
if (enumNode?.name && !isInlineConstEnum(enumNode, printer.options.enumSchemaNames)) return enumNode;
|
|
1333
|
-
} });
|
|
1334
|
-
const output = printer.print(node);
|
|
1335
|
-
if (!output) return;
|
|
1336
|
-
const enums = [...new Map(enumSchemaNodes.map((n) => [n.name, n])).values()].map((node) => {
|
|
1337
|
-
return {
|
|
1338
|
-
node,
|
|
1339
|
-
...getEnumNames({
|
|
1340
|
-
node,
|
|
1341
|
-
enum: enumOptions,
|
|
1342
|
-
resolver
|
|
1343
|
-
})
|
|
1344
|
-
};
|
|
1345
|
-
});
|
|
1346
|
-
const shouldExportEnums = enumOptions.type !== "inlineLiteral";
|
|
1347
|
-
const shouldExportType = enumOptions.type === "inlineLiteral" || enums.every((item) => item.typeName !== name);
|
|
1348
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [shouldExportEnums && enums.map(({ node }) => /* @__PURE__ */ jsx(Enum, {
|
|
1349
|
-
node,
|
|
1350
|
-
enum: enumOptions,
|
|
1351
|
-
resolver
|
|
1352
|
-
}, node.name)), shouldExportType && /* @__PURE__ */ jsx(File.Source, {
|
|
1353
|
-
name,
|
|
1354
|
-
isTypeOnly: true,
|
|
1355
|
-
isExportable: true,
|
|
1356
|
-
isIndexable: true,
|
|
1357
|
-
children: output
|
|
1358
|
-
})] });
|
|
1359
|
-
}
|
|
1360
|
-
//#endregion
|
|
1361
1376
|
//#region src/printers/printerTs.ts
|
|
1362
1377
|
const { isNonNullable } = factory_exports;
|
|
1363
1378
|
/**
|
|
@@ -1419,7 +1434,7 @@ const printerTs = ast.createPrinter((options) => {
|
|
|
1419
1434
|
return createTypeReferenceNode(name, void 0);
|
|
1420
1435
|
},
|
|
1421
1436
|
enum(node) {
|
|
1422
|
-
const values =
|
|
1437
|
+
const values = ast.getSchemaLiteralValues(node);
|
|
1423
1438
|
if (this.options.enum.type === "inlineLiteral" || !node.name || isInlineConstEnum(node, this.options.enumSchemaNames)) return createUnionDeclaration({
|
|
1424
1439
|
withParentheses: true,
|
|
1425
1440
|
nodes: values.filter((v) => v !== null && v !== void 0).map((value) => constToTypeNode(value, typeof value)).filter(isNonNullable)
|
|
@@ -1751,7 +1766,7 @@ const typeGenerator = defineGenerator({
|
|
|
1751
1766
|
name: resolver.response.options(node)
|
|
1752
1767
|
});
|
|
1753
1768
|
const responsesType = renderSchemaType({
|
|
1754
|
-
schema: buildResponses(node,
|
|
1769
|
+
schema: buildResponses(node, resolver),
|
|
1755
1770
|
name: resolver.response.responses(node)
|
|
1756
1771
|
});
|
|
1757
1772
|
function buildResponseType() {
|