@kubb/plugin-ts 5.0.0-beta.99 → 5.1.0-canary.20260819T202653

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 CHANGED
@@ -32,7 +32,7 @@ var __copyProps = (to, from, except, desc) => {
32
32
  }
33
33
  return to;
34
34
  };
35
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
35
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
36
36
  value: mod,
37
37
  enumerable: true
38
38
  }) : target, mod));
@@ -856,7 +856,7 @@ function buildTupleNode(node, print) {
856
856
  */
857
857
  function buildPropertyType(schema, baseType, optionalType, optional) {
858
858
  const addsUndefined = OPTIONAL_ADDS_UNDEFINED.has(optionalType);
859
- const meta = kubb_kit.ast.syncSchemaRef(schema);
859
+ const meta = (0, kubb_kit.syncSchemaRef)(schema);
860
860
  let type = baseType;
861
861
  if (meta.nullable) type = createUnionDeclaration({ nodes: [type, keywordTypeNodes.null] });
862
862
  if ((optional || meta.nullish || meta.optional) && addsUndefined) type = createUnionDeclaration({ nodes: [type, keywordTypeNodes.undefined] });
@@ -1017,16 +1017,81 @@ function resolveContentTypeVariants(entries, baseName) {
1017
1017
  };
1018
1018
  });
1019
1019
  }
1020
+ const operationParameterGroupsByNode = /* @__PURE__ */ new WeakMap();
1021
+ /**
1022
+ * Groups an operation's parameters by location (`path`/`query`/`header`/`cookie`), deduping each
1023
+ * group by name. Every plugin generator visiting the same `OperationNode` shares one AST instance
1024
+ * (see `KubbDriver`), so the result is cached per node to avoid re-filtering and re-deduping the
1025
+ * same parameters once per plugin.
1026
+ */
1020
1027
  function getOperationParameters(node) {
1021
- return {
1022
- path: dedupeParams(node.parameters.filter((param) => param.in === "path").map((param) => isValidVarName(param.name) ? param : {
1023
- ...param,
1024
- name: camelCase(param.name)
1025
- })),
1028
+ const cached = operationParameterGroupsByNode.get(node);
1029
+ if (cached) return cached;
1030
+ const groups = {
1031
+ path: dedupeParams(node.parameters.filter((param) => param.in === "path")),
1026
1032
  query: dedupeParams(node.parameters.filter((param) => param.in === "query")),
1027
1033
  header: dedupeParams(node.parameters.filter((param) => param.in === "header")),
1028
1034
  cookie: dedupeParams(node.parameters.filter((param) => param.in === "cookie"))
1029
1035
  };
1036
+ operationParameterGroupsByNode.set(node, groups);
1037
+ return groups;
1038
+ }
1039
+ /**
1040
+ * Builds the combined `{ body, path, query, headers }` options object schema for an operation,
1041
+ * referencing the already-resolved body and grouped param names. Shared by `@kubb/plugin-ts`'s
1042
+ * `Options` type and `@kubb/plugin-zod`'s inferred options schema, so both printers emit the same
1043
+ * shape from the same inputs. `primitive: 'object'` is a no-op for the TS printer and tells the Zod
1044
+ * printer to emit `z.object(…)` rather than a record.
1045
+ */
1046
+ function buildOptionsSchema(node, resolver) {
1047
+ const { path, query, header } = getOperationParameters(node);
1048
+ const hasBody = Boolean(node.requestBody?.content?.[0]?.schema);
1049
+ const createNever = () => kubb_kit.ast.factory.createSchema({
1050
+ type: "never",
1051
+ primitive: void 0,
1052
+ optional: true
1053
+ });
1054
+ const groups = [
1055
+ {
1056
+ name: "path",
1057
+ params: path,
1058
+ resolve: resolver.param.path
1059
+ },
1060
+ {
1061
+ name: "query",
1062
+ params: query,
1063
+ resolve: resolver.param.query
1064
+ },
1065
+ {
1066
+ name: "headers",
1067
+ params: header,
1068
+ resolve: resolver.param.headers
1069
+ }
1070
+ ];
1071
+ return kubb_kit.ast.factory.createSchema({
1072
+ type: "object",
1073
+ primitive: "object",
1074
+ deprecated: node.deprecated,
1075
+ properties: [kubb_kit.ast.factory.createProperty({
1076
+ name: "body",
1077
+ required: hasBody,
1078
+ schema: hasBody ? kubb_kit.ast.factory.createSchema({
1079
+ type: "ref",
1080
+ name: resolver.response.body(node)
1081
+ }) : createNever()
1082
+ }), ...groups.map(({ name, params, resolve }) => {
1083
+ const required = params.some((param) => param.required);
1084
+ return kubb_kit.ast.factory.createProperty({
1085
+ name,
1086
+ required,
1087
+ schema: params.length > 0 ? kubb_kit.ast.factory.createSchema({
1088
+ type: "ref",
1089
+ name: resolve.call(resolver.param, node, params[0]),
1090
+ optional: !required
1091
+ }) : createNever()
1092
+ });
1093
+ })]
1094
+ });
1030
1095
  }
1031
1096
  //#endregion
1032
1097
  //#region ../../internals/shared/src/resolver.ts
@@ -1111,7 +1176,7 @@ function createCasedFile(caseLast) {
1111
1176
  * `resolver.imports` would resolve file paths that are then discarded.
1112
1177
  */
1113
1178
  function collectRefNames(schema) {
1114
- return kubb_kit.ast.collect(schema, { schema: (node) => {
1179
+ return kubb_kit.ast.collectSync(schema, { schema: (node) => {
1115
1180
  const refNode = kubb_kit.ast.narrowSchema(node, "ref");
1116
1181
  if (!refNode?.ref) return null;
1117
1182
  return kubb_kit.ast.resolveRefName(refNode);
@@ -1206,12 +1271,12 @@ function formatExample(value) {
1206
1271
  return (JSON.stringify(value) ?? String(value)).replaceAll("*/", "*\\/");
1207
1272
  }
1208
1273
  function buildPropertyJSDocComments(schema, optional) {
1209
- const meta = kubb_kit.ast.syncSchemaRef(schema);
1274
+ const meta = (0, kubb_kit.syncSchemaRef)(schema);
1210
1275
  const isArray = meta?.primitive === "array";
1211
1276
  const hasDescription = meta && "description" in meta && meta.description;
1212
1277
  const formatComment = meta && "format" in meta && meta.format ? hasDescription ? [" ", `Format: \`${meta.format}\``] : ["@description", `Format: \`${meta.format}\``] : [];
1213
1278
  const exampleValues = meta?.examples ?? [];
1214
- return [
1279
+ const comments = [
1215
1280
  hasDescription ? `@description ${jsStringEscape(meta.description)}` : null,
1216
1281
  ...formatComment,
1217
1282
  meta && "deprecated" in meta && meta.deprecated ? "@deprecated" : null,
@@ -1219,9 +1284,10 @@ function buildPropertyJSDocComments(schema, optional) {
1219
1284
  !isArray && meta && "max" in meta && meta.max !== void 0 ? `@maxLength ${meta.max}` : null,
1220
1285
  meta && "pattern" in meta && meta.pattern ? `@pattern ${meta.pattern}` : null,
1221
1286
  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,
1222
- ...exampleValues.map((example) => `@example ${formatExample(example)}`),
1223
- meta && "primitive" in meta && meta.primitive ? [`@type ${meta.primitive}`, optional ?? isSchemaOptional(schema) ? " | undefined" : null].filter(Boolean).join("") : null
1287
+ ...exampleValues.map((example) => `@example ${formatExample(example)}`)
1224
1288
  ].filter(Boolean);
1289
+ const typeTag = comments.length && meta && "primitive" in meta && meta.primitive ? [`@type ${meta.primitive}`, optional ?? isSchemaOptional(schema) ? " | undefined" : null].filter(Boolean).join("") : null;
1290
+ return [...comments, typeTag].filter(Boolean);
1225
1291
  }
1226
1292
  /**
1227
1293
  * Builds the object schema for a group of parameters sharing one `in` location (path, query, or
@@ -1241,70 +1307,6 @@ function buildParams({ params }) {
1241
1307
  }))
1242
1308
  });
1243
1309
  }
1244
- function buildOptions(node, { resolver }) {
1245
- const { path: pathParams, query: queryParams, header: headerParams } = getOperationParameters(node);
1246
- const hasBody = Boolean(node.requestBody?.content?.[0]?.schema);
1247
- const hasRequiredPath = pathParams.some((param) => param.required);
1248
- const hasRequiredQuery = queryParams.some((param) => param.required);
1249
- const hasRequiredHeader = headerParams.some((param) => param.required);
1250
- return kubb_kit.ast.factory.createSchema({
1251
- type: "object",
1252
- deprecated: node.deprecated,
1253
- properties: [
1254
- kubb_kit.ast.factory.createProperty({
1255
- name: "body",
1256
- required: hasBody,
1257
- schema: hasBody ? kubb_kit.ast.factory.createSchema({
1258
- type: "ref",
1259
- name: resolver.response.body(node)
1260
- }) : kubb_kit.ast.factory.createSchema({
1261
- type: "never",
1262
- primitive: void 0,
1263
- optional: true
1264
- })
1265
- }),
1266
- kubb_kit.ast.factory.createProperty({
1267
- name: "path",
1268
- required: hasRequiredPath,
1269
- schema: pathParams.length > 0 ? kubb_kit.ast.factory.createSchema({
1270
- type: "ref",
1271
- name: resolver.param.path(node, pathParams[0]),
1272
- optional: !hasRequiredPath
1273
- }) : kubb_kit.ast.factory.createSchema({
1274
- type: "never",
1275
- primitive: void 0,
1276
- optional: true
1277
- })
1278
- }),
1279
- kubb_kit.ast.factory.createProperty({
1280
- name: "query",
1281
- required: hasRequiredQuery,
1282
- schema: queryParams.length > 0 ? kubb_kit.ast.factory.createSchema({
1283
- type: "ref",
1284
- name: resolver.param.query(node, queryParams[0]),
1285
- optional: !hasRequiredQuery
1286
- }) : kubb_kit.ast.factory.createSchema({
1287
- type: "never",
1288
- primitive: void 0,
1289
- optional: true
1290
- })
1291
- }),
1292
- kubb_kit.ast.factory.createProperty({
1293
- name: "headers",
1294
- required: hasRequiredHeader,
1295
- schema: headerParams.length > 0 ? kubb_kit.ast.factory.createSchema({
1296
- type: "ref",
1297
- name: resolver.param.headers(node, headerParams[0]),
1298
- optional: !hasRequiredHeader
1299
- }) : kubb_kit.ast.factory.createSchema({
1300
- type: "never",
1301
- primitive: void 0,
1302
- optional: true
1303
- })
1304
- })
1305
- ]
1306
- });
1307
- }
1308
1310
  /**
1309
1311
  * The schema a status occupies in the `<Name>Responses` record. A status that documents several
1310
1312
  * content types becomes a `{ contentType; data }` union so the runtime can surface the negotiated type
@@ -1364,7 +1366,7 @@ function buildResponseUnion(node, { resolver }) {
1364
1366
  //#endregion
1365
1367
  //#region src/components/Type.tsx
1366
1368
  function Type({ name, node, printer, enum: enumOptions, resolver }) {
1367
- const enumSchemaNodes = kubb_kit.ast.collect(node, { schema(n) {
1369
+ const enumSchemaNodes = kubb_kit.ast.collectSync(node, { schema(n) {
1368
1370
  const enumNode = kubb_kit.ast.narrowSchema(n, kubb_kit.ast.schemaTypes.enum);
1369
1371
  if (enumNode?.name && !isInlineConstEnum(enumNode, printer.options.enumSchemaNames)) return enumNode;
1370
1372
  } });
@@ -1469,11 +1471,11 @@ const printerTs = kubb_kit.ast.createPrinter((options) => {
1469
1471
  const hasStringLiteral = members.some((m) => {
1470
1472
  return kubb_kit.ast.narrowSchema(m, kubb_kit.ast.schemaTypes.enum)?.primitive === "string";
1471
1473
  });
1472
- const hasPlainString = members.some((m) => kubb_kit.ast.isStringType(m));
1474
+ const hasPlainString = members.some((m) => (0, kubb_kit.isStringType)(m));
1473
1475
  if (hasStringLiteral && hasPlainString) return createUnionDeclaration({
1474
1476
  withParentheses: true,
1475
1477
  nodes: members.map((m) => {
1476
- if (kubb_kit.ast.isStringType(m)) return createIntersectionDeclaration({
1478
+ if ((0, kubb_kit.isStringType)(m)) return createIntersectionDeclaration({
1477
1479
  nodes: [keywordTypeNodes.string, createTypeLiteralNode([])],
1478
1480
  withParentheses: true
1479
1481
  });
@@ -1507,7 +1509,7 @@ const printerTs = kubb_kit.ast.createPrinter((options) => {
1507
1509
  const baseType = output ?? keywordTypeNodes.unknown;
1508
1510
  const optional = !property.required || !!property.schema.optional || !!property.schema.nullish;
1509
1511
  const type = buildPropertyType(property.schema, baseType, options.optionalType, optional);
1510
- const propMeta = kubb_kit.ast.syncSchemaRef(property.schema);
1512
+ const propMeta = (0, kubb_kit.syncSchemaRef)(property.schema);
1511
1513
  return appendJSDocToNode({
1512
1514
  node: createPropertySignature({
1513
1515
  questionToken: optional ? addsQuestionToken : false,
@@ -1528,7 +1530,7 @@ const printerTs = kubb_kit.ast.createPrinter((options) => {
1528
1530
  const { name, syntaxType = "type", description, keysToOmit } = this.options;
1529
1531
  const transformed = this.transform(node);
1530
1532
  if (!transformed) return null;
1531
- const meta = kubb_kit.ast.syncSchemaRef(node);
1533
+ const meta = (0, kubb_kit.syncSchemaRef)(node);
1532
1534
  if (!name) {
1533
1535
  const withNullable = meta.nullable ? createUnionDeclaration({ nodes: [transformed, keywordTypeNodes.null] }) : transformed;
1534
1536
  const result = (meta.nullish || meta.optional) && addsUndefined ? createUnionDeclaration({ nodes: [withNullable, keywordTypeNodes.undefined] }) : withNullable;
@@ -1784,7 +1786,7 @@ const typeGenerator = (0, kubb_kit.defineGenerator)({
1784
1786
  });
1785
1787
  });
1786
1788
  const optionsType = renderSchemaType({
1787
- schema: buildOptions(node, { resolver }),
1789
+ schema: buildOptionsSchema(node, resolver),
1788
1790
  name: resolver.response.options(node)
1789
1791
  });
1790
1792
  const responsesType = renderSchemaType({