@kubb/plugin-ts 5.0.0-beta.99 → 5.0.0
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 +84 -82
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +84 -82
- package/dist/index.js.map +1 -1
- package/package.json +4 -7
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { n as __name, t as __exportAll } from "./rolldown-runtime-CNktS9qV.js";
|
|
2
2
|
import { parserTs } from "@kubb/parser-ts";
|
|
3
3
|
import { File, jsxRenderer } from "kubb/jsx";
|
|
4
|
-
import { Resolver, ast, createResolver, defineGenerator, definePlugin } from "kubb/kit";
|
|
4
|
+
import { Resolver, ast, createResolver, defineGenerator, definePlugin, isStringType, syncSchemaRef } from "kubb/kit";
|
|
5
5
|
import ts from "typescript";
|
|
6
6
|
import { Fragment, jsx, jsxs } from "kubb/jsx/jsx-runtime";
|
|
7
7
|
//#region ../../internals/utils/src/casing.ts
|
|
@@ -817,7 +817,7 @@ function buildTupleNode(node, print) {
|
|
|
817
817
|
*/
|
|
818
818
|
function buildPropertyType(schema, baseType, optionalType, optional) {
|
|
819
819
|
const addsUndefined = OPTIONAL_ADDS_UNDEFINED.has(optionalType);
|
|
820
|
-
const meta =
|
|
820
|
+
const meta = syncSchemaRef(schema);
|
|
821
821
|
let type = baseType;
|
|
822
822
|
if (meta.nullable) type = createUnionDeclaration({ nodes: [type, keywordTypeNodes.null] });
|
|
823
823
|
if ((optional || meta.nullish || meta.optional) && addsUndefined) type = createUnionDeclaration({ nodes: [type, keywordTypeNodes.undefined] });
|
|
@@ -978,16 +978,81 @@ function resolveContentTypeVariants(entries, baseName) {
|
|
|
978
978
|
};
|
|
979
979
|
});
|
|
980
980
|
}
|
|
981
|
+
const operationParameterGroupsByNode = /* @__PURE__ */ new WeakMap();
|
|
982
|
+
/**
|
|
983
|
+
* Groups an operation's parameters by location (`path`/`query`/`header`/`cookie`), deduping each
|
|
984
|
+
* group by name. Every plugin generator visiting the same `OperationNode` shares one AST instance
|
|
985
|
+
* (see `KubbDriver`), so the result is cached per node to avoid re-filtering and re-deduping the
|
|
986
|
+
* same parameters once per plugin.
|
|
987
|
+
*/
|
|
981
988
|
function getOperationParameters(node) {
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
})),
|
|
989
|
+
const cached = operationParameterGroupsByNode.get(node);
|
|
990
|
+
if (cached) return cached;
|
|
991
|
+
const groups = {
|
|
992
|
+
path: dedupeParams(node.parameters.filter((param) => param.in === "path")),
|
|
987
993
|
query: dedupeParams(node.parameters.filter((param) => param.in === "query")),
|
|
988
994
|
header: dedupeParams(node.parameters.filter((param) => param.in === "header")),
|
|
989
995
|
cookie: dedupeParams(node.parameters.filter((param) => param.in === "cookie"))
|
|
990
996
|
};
|
|
997
|
+
operationParameterGroupsByNode.set(node, groups);
|
|
998
|
+
return groups;
|
|
999
|
+
}
|
|
1000
|
+
/**
|
|
1001
|
+
* Builds the combined `{ body, path, query, headers }` options object schema for an operation,
|
|
1002
|
+
* referencing the already-resolved body and grouped param names. Shared by `@kubb/plugin-ts`'s
|
|
1003
|
+
* `Options` type and `@kubb/plugin-zod`'s inferred options schema, so both printers emit the same
|
|
1004
|
+
* shape from the same inputs. `primitive: 'object'` is a no-op for the TS printer and tells the Zod
|
|
1005
|
+
* printer to emit `z.object(…)` rather than a record.
|
|
1006
|
+
*/
|
|
1007
|
+
function buildOptionsSchema(node, resolver) {
|
|
1008
|
+
const { path, query, header } = getOperationParameters(node);
|
|
1009
|
+
const hasBody = Boolean(node.requestBody?.content?.[0]?.schema);
|
|
1010
|
+
const createNever = () => ast.factory.createSchema({
|
|
1011
|
+
type: "never",
|
|
1012
|
+
primitive: void 0,
|
|
1013
|
+
optional: true
|
|
1014
|
+
});
|
|
1015
|
+
const groups = [
|
|
1016
|
+
{
|
|
1017
|
+
name: "path",
|
|
1018
|
+
params: path,
|
|
1019
|
+
resolve: resolver.param.path
|
|
1020
|
+
},
|
|
1021
|
+
{
|
|
1022
|
+
name: "query",
|
|
1023
|
+
params: query,
|
|
1024
|
+
resolve: resolver.param.query
|
|
1025
|
+
},
|
|
1026
|
+
{
|
|
1027
|
+
name: "headers",
|
|
1028
|
+
params: header,
|
|
1029
|
+
resolve: resolver.param.headers
|
|
1030
|
+
}
|
|
1031
|
+
];
|
|
1032
|
+
return ast.factory.createSchema({
|
|
1033
|
+
type: "object",
|
|
1034
|
+
primitive: "object",
|
|
1035
|
+
deprecated: node.deprecated,
|
|
1036
|
+
properties: [ast.factory.createProperty({
|
|
1037
|
+
name: "body",
|
|
1038
|
+
required: hasBody,
|
|
1039
|
+
schema: hasBody ? ast.factory.createSchema({
|
|
1040
|
+
type: "ref",
|
|
1041
|
+
name: resolver.response.body(node)
|
|
1042
|
+
}) : createNever()
|
|
1043
|
+
}), ...groups.map(({ name, params, resolve }) => {
|
|
1044
|
+
const required = params.some((param) => param.required);
|
|
1045
|
+
return ast.factory.createProperty({
|
|
1046
|
+
name,
|
|
1047
|
+
required,
|
|
1048
|
+
schema: params.length > 0 ? ast.factory.createSchema({
|
|
1049
|
+
type: "ref",
|
|
1050
|
+
name: resolve.call(resolver.param, node, params[0]),
|
|
1051
|
+
optional: !required
|
|
1052
|
+
}) : createNever()
|
|
1053
|
+
});
|
|
1054
|
+
})]
|
|
1055
|
+
});
|
|
991
1056
|
}
|
|
992
1057
|
//#endregion
|
|
993
1058
|
//#region ../../internals/shared/src/resolver.ts
|
|
@@ -1072,7 +1137,7 @@ function createCasedFile(caseLast) {
|
|
|
1072
1137
|
* `resolver.imports` would resolve file paths that are then discarded.
|
|
1073
1138
|
*/
|
|
1074
1139
|
function collectRefNames(schema) {
|
|
1075
|
-
return ast.
|
|
1140
|
+
return ast.collectSync(schema, { schema: (node) => {
|
|
1076
1141
|
const refNode = ast.narrowSchema(node, "ref");
|
|
1077
1142
|
if (!refNode?.ref) return null;
|
|
1078
1143
|
return ast.resolveRefName(refNode);
|
|
@@ -1167,12 +1232,12 @@ function formatExample(value) {
|
|
|
1167
1232
|
return (JSON.stringify(value) ?? String(value)).replaceAll("*/", "*\\/");
|
|
1168
1233
|
}
|
|
1169
1234
|
function buildPropertyJSDocComments(schema, optional) {
|
|
1170
|
-
const meta =
|
|
1235
|
+
const meta = syncSchemaRef(schema);
|
|
1171
1236
|
const isArray = meta?.primitive === "array";
|
|
1172
1237
|
const hasDescription = meta && "description" in meta && meta.description;
|
|
1173
1238
|
const formatComment = meta && "format" in meta && meta.format ? hasDescription ? [" ", `Format: \`${meta.format}\``] : ["@description", `Format: \`${meta.format}\``] : [];
|
|
1174
1239
|
const exampleValues = meta?.examples ?? [];
|
|
1175
|
-
|
|
1240
|
+
const comments = [
|
|
1176
1241
|
hasDescription ? `@description ${jsStringEscape(meta.description)}` : null,
|
|
1177
1242
|
...formatComment,
|
|
1178
1243
|
meta && "deprecated" in meta && meta.deprecated ? "@deprecated" : null,
|
|
@@ -1180,9 +1245,10 @@ function buildPropertyJSDocComments(schema, optional) {
|
|
|
1180
1245
|
!isArray && meta && "max" in meta && meta.max !== void 0 ? `@maxLength ${meta.max}` : null,
|
|
1181
1246
|
meta && "pattern" in meta && meta.pattern ? `@pattern ${meta.pattern}` : null,
|
|
1182
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,
|
|
1183
|
-
...exampleValues.map((example) => `@example ${formatExample(example)}`)
|
|
1184
|
-
meta && "primitive" in meta && meta.primitive ? [`@type ${meta.primitive}`, optional ?? isSchemaOptional(schema) ? " | undefined" : null].filter(Boolean).join("") : null
|
|
1248
|
+
...exampleValues.map((example) => `@example ${formatExample(example)}`)
|
|
1185
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);
|
|
1186
1252
|
}
|
|
1187
1253
|
/**
|
|
1188
1254
|
* Builds the object schema for a group of parameters sharing one `in` location (path, query, or
|
|
@@ -1202,70 +1268,6 @@ function buildParams({ params }) {
|
|
|
1202
1268
|
}))
|
|
1203
1269
|
});
|
|
1204
1270
|
}
|
|
1205
|
-
function buildOptions(node, { resolver }) {
|
|
1206
|
-
const { path: pathParams, query: queryParams, header: headerParams } = getOperationParameters(node);
|
|
1207
|
-
const hasBody = Boolean(node.requestBody?.content?.[0]?.schema);
|
|
1208
|
-
const hasRequiredPath = pathParams.some((param) => param.required);
|
|
1209
|
-
const hasRequiredQuery = queryParams.some((param) => param.required);
|
|
1210
|
-
const hasRequiredHeader = headerParams.some((param) => param.required);
|
|
1211
|
-
return ast.factory.createSchema({
|
|
1212
|
-
type: "object",
|
|
1213
|
-
deprecated: node.deprecated,
|
|
1214
|
-
properties: [
|
|
1215
|
-
ast.factory.createProperty({
|
|
1216
|
-
name: "body",
|
|
1217
|
-
required: hasBody,
|
|
1218
|
-
schema: hasBody ? ast.factory.createSchema({
|
|
1219
|
-
type: "ref",
|
|
1220
|
-
name: resolver.response.body(node)
|
|
1221
|
-
}) : ast.factory.createSchema({
|
|
1222
|
-
type: "never",
|
|
1223
|
-
primitive: void 0,
|
|
1224
|
-
optional: true
|
|
1225
|
-
})
|
|
1226
|
-
}),
|
|
1227
|
-
ast.factory.createProperty({
|
|
1228
|
-
name: "path",
|
|
1229
|
-
required: hasRequiredPath,
|
|
1230
|
-
schema: pathParams.length > 0 ? ast.factory.createSchema({
|
|
1231
|
-
type: "ref",
|
|
1232
|
-
name: resolver.param.path(node, pathParams[0]),
|
|
1233
|
-
optional: !hasRequiredPath
|
|
1234
|
-
}) : ast.factory.createSchema({
|
|
1235
|
-
type: "never",
|
|
1236
|
-
primitive: void 0,
|
|
1237
|
-
optional: true
|
|
1238
|
-
})
|
|
1239
|
-
}),
|
|
1240
|
-
ast.factory.createProperty({
|
|
1241
|
-
name: "query",
|
|
1242
|
-
required: hasRequiredQuery,
|
|
1243
|
-
schema: queryParams.length > 0 ? ast.factory.createSchema({
|
|
1244
|
-
type: "ref",
|
|
1245
|
-
name: resolver.param.query(node, queryParams[0]),
|
|
1246
|
-
optional: !hasRequiredQuery
|
|
1247
|
-
}) : ast.factory.createSchema({
|
|
1248
|
-
type: "never",
|
|
1249
|
-
primitive: void 0,
|
|
1250
|
-
optional: true
|
|
1251
|
-
})
|
|
1252
|
-
}),
|
|
1253
|
-
ast.factory.createProperty({
|
|
1254
|
-
name: "headers",
|
|
1255
|
-
required: hasRequiredHeader,
|
|
1256
|
-
schema: headerParams.length > 0 ? ast.factory.createSchema({
|
|
1257
|
-
type: "ref",
|
|
1258
|
-
name: resolver.param.headers(node, headerParams[0]),
|
|
1259
|
-
optional: !hasRequiredHeader
|
|
1260
|
-
}) : ast.factory.createSchema({
|
|
1261
|
-
type: "never",
|
|
1262
|
-
primitive: void 0,
|
|
1263
|
-
optional: true
|
|
1264
|
-
})
|
|
1265
|
-
})
|
|
1266
|
-
]
|
|
1267
|
-
});
|
|
1268
|
-
}
|
|
1269
1271
|
/**
|
|
1270
1272
|
* The schema a status occupies in the `<Name>Responses` record. A status that documents several
|
|
1271
1273
|
* content types becomes a `{ contentType; data }` union so the runtime can surface the negotiated type
|
|
@@ -1325,7 +1327,7 @@ function buildResponseUnion(node, { resolver }) {
|
|
|
1325
1327
|
//#endregion
|
|
1326
1328
|
//#region src/components/Type.tsx
|
|
1327
1329
|
function Type({ name, node, printer, enum: enumOptions, resolver }) {
|
|
1328
|
-
const enumSchemaNodes = ast.
|
|
1330
|
+
const enumSchemaNodes = ast.collectSync(node, { schema(n) {
|
|
1329
1331
|
const enumNode = ast.narrowSchema(n, ast.schemaTypes.enum);
|
|
1330
1332
|
if (enumNode?.name && !isInlineConstEnum(enumNode, printer.options.enumSchemaNames)) return enumNode;
|
|
1331
1333
|
} });
|
|
@@ -1430,11 +1432,11 @@ const printerTs = ast.createPrinter((options) => {
|
|
|
1430
1432
|
const hasStringLiteral = members.some((m) => {
|
|
1431
1433
|
return ast.narrowSchema(m, ast.schemaTypes.enum)?.primitive === "string";
|
|
1432
1434
|
});
|
|
1433
|
-
const hasPlainString = members.some((m) =>
|
|
1435
|
+
const hasPlainString = members.some((m) => isStringType(m));
|
|
1434
1436
|
if (hasStringLiteral && hasPlainString) return createUnionDeclaration({
|
|
1435
1437
|
withParentheses: true,
|
|
1436
1438
|
nodes: members.map((m) => {
|
|
1437
|
-
if (
|
|
1439
|
+
if (isStringType(m)) return createIntersectionDeclaration({
|
|
1438
1440
|
nodes: [keywordTypeNodes.string, createTypeLiteralNode([])],
|
|
1439
1441
|
withParentheses: true
|
|
1440
1442
|
});
|
|
@@ -1468,7 +1470,7 @@ const printerTs = ast.createPrinter((options) => {
|
|
|
1468
1470
|
const baseType = output ?? keywordTypeNodes.unknown;
|
|
1469
1471
|
const optional = !property.required || !!property.schema.optional || !!property.schema.nullish;
|
|
1470
1472
|
const type = buildPropertyType(property.schema, baseType, options.optionalType, optional);
|
|
1471
|
-
const propMeta =
|
|
1473
|
+
const propMeta = syncSchemaRef(property.schema);
|
|
1472
1474
|
return appendJSDocToNode({
|
|
1473
1475
|
node: createPropertySignature({
|
|
1474
1476
|
questionToken: optional ? addsQuestionToken : false,
|
|
@@ -1489,7 +1491,7 @@ const printerTs = ast.createPrinter((options) => {
|
|
|
1489
1491
|
const { name, syntaxType = "type", description, keysToOmit } = this.options;
|
|
1490
1492
|
const transformed = this.transform(node);
|
|
1491
1493
|
if (!transformed) return null;
|
|
1492
|
-
const meta =
|
|
1494
|
+
const meta = syncSchemaRef(node);
|
|
1493
1495
|
if (!name) {
|
|
1494
1496
|
const withNullable = meta.nullable ? createUnionDeclaration({ nodes: [transformed, keywordTypeNodes.null] }) : transformed;
|
|
1495
1497
|
const result = (meta.nullish || meta.optional) && addsUndefined ? createUnionDeclaration({ nodes: [withNullable, keywordTypeNodes.undefined] }) : withNullable;
|
|
@@ -1745,7 +1747,7 @@ const typeGenerator = defineGenerator({
|
|
|
1745
1747
|
});
|
|
1746
1748
|
});
|
|
1747
1749
|
const optionsType = renderSchemaType({
|
|
1748
|
-
schema:
|
|
1750
|
+
schema: buildOptionsSchema(node, resolver),
|
|
1749
1751
|
name: resolver.response.options(node)
|
|
1750
1752
|
});
|
|
1751
1753
|
const responsesType = renderSchemaType({
|