@kubb/plugin-ts 5.0.0-beta.98 → 5.0.0-beta.99

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
@@ -951,39 +951,19 @@ function Enum({ node, enum: enumOptions, resolver }) {
951
951
  }
952
952
  //#endregion
953
953
  //#region ../../internals/shared/src/params.ts
954
- const caseParamsCache = /* @__PURE__ */ new WeakMap();
955
954
  /**
956
- * Applies camelCase to parameter names and returns a new array without mutating the input.
955
+ * Drops parameters that share the same name, keeping the first.
957
956
  *
958
- * Run it before handing parameters to schema builders so output property keys get the right casing
959
- * while `OperationNode.parameters` stays intact for other consumers. When `casing` is unset, the
960
- * original array is returned unchanged. Results are cached per input array.
957
+ * A malformed spec can declare the same parameter name twice within one `in` location. Both would
958
+ * resolve to the same output property, so emitting both would yield an object type with a duplicate
959
+ * member, which TypeScript rejects. This is a defensive guard against that case, not a casing guard:
960
+ * parameter names flow through unchanged, so no two distinct names ever collide here anymore.
961
961
  */
962
- function caseParams(params, casing) {
963
- if (!casing) return params;
964
- const cached = caseParamsCache.get(params);
965
- if (cached) return cached;
966
- const result = params.map((param) => ({
967
- ...param,
968
- name: camelCase(param.name)
969
- }));
970
- caseParamsCache.set(params, result);
971
- return result;
972
- }
973
- /**
974
- * Drops parameters that collapse to the same property identity once camelCased, keeping the first.
975
- *
976
- * Some specs declare the same parameter twice under different casings (for example AWS S3 lists both
977
- * `max-uploads` and `MaxUploads`). Both resolve to one output property, so emitting both would yield
978
- * an object type with a duplicate member, which TypeScript rejects. De-duplicate by the camelCased
979
- * identity so the resulting group is collision-free regardless of the names each caller carries.
980
- */
981
- function dedupeByCasedName(params) {
962
+ function dedupeParams(params) {
982
963
  const seen = /* @__PURE__ */ new Set();
983
964
  return params.filter((param) => {
984
- const key = camelCase(param.name);
985
- if (seen.has(key)) return false;
986
- seen.add(key);
965
+ if (seen.has(param.name)) return false;
966
+ seen.add(param.name);
987
967
  return true;
988
968
  });
989
969
  }
@@ -1037,13 +1017,15 @@ function resolveContentTypeVariants(entries, baseName) {
1037
1017
  };
1038
1018
  });
1039
1019
  }
1040
- function getOperationParameters(node, options = {}) {
1041
- const params = caseParams(node.parameters, options.paramsCasing === "original" ? void 0 : "camelcase");
1020
+ function getOperationParameters(node) {
1042
1021
  return {
1043
- path: dedupeByCasedName(params.filter((param) => param.in === "path")),
1044
- query: dedupeByCasedName(params.filter((param) => param.in === "query")),
1045
- header: dedupeByCasedName(params.filter((param) => param.in === "header")),
1046
- cookie: dedupeByCasedName(params.filter((param) => param.in === "cookie"))
1022
+ path: dedupeParams(node.parameters.filter((param) => param.in === "path").map((param) => isValidVarName(param.name) ? param : {
1023
+ ...param,
1024
+ name: camelCase(param.name)
1025
+ })),
1026
+ query: dedupeParams(node.parameters.filter((param) => param.in === "query")),
1027
+ header: dedupeParams(node.parameters.filter((param) => param.in === "header")),
1028
+ cookie: dedupeParams(node.parameters.filter((param) => param.in === "cookie"))
1047
1029
  };
1048
1030
  }
1049
1031
  //#endregion
@@ -1167,6 +1149,35 @@ function createGroupConfig(group) {
1167
1149
  };
1168
1150
  }
1169
1151
  //#endregion
1152
+ //#region ../../internals/shared/src/schemaTraversal.ts
1153
+ /**
1154
+ * Maps each property of an object schema to its transformed output. Pairs every result with the
1155
+ * original property so the printer keeps full control over modifiers, getters, and key syntax.
1156
+ *
1157
+ * @example
1158
+ * ```ts
1159
+ * const entries = mapSchemaProperties(node, (schema) => this.transform(schema))
1160
+ * // entries: [{ name: 'id', property, output: 'z.number()' }, ...]
1161
+ * ```
1162
+ */
1163
+ function mapSchemaProperties(node, transform) {
1164
+ return node.properties.map((property) => ({
1165
+ name: property.name,
1166
+ property,
1167
+ output: transform(property.schema)
1168
+ }));
1169
+ }
1170
+ /**
1171
+ * Maps each item of an array or tuple schema to its transformed output, pairing every result with
1172
+ * the original item.
1173
+ */
1174
+ function mapSchemaItems(node, transform) {
1175
+ return (node.items ?? []).map((schema) => ({
1176
+ schema,
1177
+ output: transform(schema)
1178
+ }));
1179
+ }
1180
+ //#endregion
1170
1181
  //#region src/utils.ts
1171
1182
  /**
1172
1183
  * Tells whether a `const` (single-value enum) should render as a bare literal type (`'active'`)
@@ -1231,7 +1242,7 @@ function buildParams({ params }) {
1231
1242
  });
1232
1243
  }
1233
1244
  function buildOptions(node, { resolver }) {
1234
- const { path: pathParams, query: queryParams, header: headerParams } = getOperationParameters(node, { paramsCasing: "original" });
1245
+ const { path: pathParams, query: queryParams, header: headerParams } = getOperationParameters(node);
1235
1246
  const hasBody = Boolean(node.requestBody?.content?.[0]?.schema);
1236
1247
  const hasRequiredPath = pathParams.some((param) => param.required);
1237
1248
  const hasRequiredQuery = queryParams.some((param) => param.required);
@@ -1482,7 +1493,7 @@ const printerTs = kubb_kit.ast.createPrinter((options) => {
1482
1493
  },
1483
1494
  array(node) {
1484
1495
  return createArrayDeclaration({
1485
- nodes: kubb_kit.ast.mapSchemaItems(node, (item) => this.transform(item)).map(({ output }) => output).filter(isNonNullable),
1496
+ nodes: mapSchemaItems(node, (item) => this.transform(item)).map(({ output }) => output).filter(isNonNullable),
1486
1497
  arrayType: this.options.arrayType
1487
1498
  }) ?? null;
1488
1499
  },
@@ -1492,7 +1503,7 @@ const printerTs = kubb_kit.ast.createPrinter((options) => {
1492
1503
  object(node) {
1493
1504
  const { transform, options } = this;
1494
1505
  const addsQuestionToken = OPTIONAL_ADDS_QUESTION_TOKEN.has(options.optionalType);
1495
- const propertyNodes = kubb_kit.ast.mapSchemaProperties(node, (schema) => transform(schema)).map(({ name, property, output }) => {
1506
+ const propertyNodes = mapSchemaProperties(node, (schema) => transform(schema)).map(({ name, property, output }) => {
1496
1507
  const baseType = output ?? keywordTypeNodes.unknown;
1497
1508
  const optional = !property.required || !!property.schema.optional || !!property.schema.nullish;
1498
1509
  const type = buildPropertyType(property.schema, baseType, options.optionalType, optional);
@@ -1648,7 +1659,6 @@ const typeGenerator = (0, kubb_kit.defineGenerator)({
1648
1659
  operation(node, ctx) {
1649
1660
  const { enum: enumOptions, optionalType, arrayType, syntaxType, group, output, printer } = ctx.options;
1650
1661
  const { config, resolver, root } = ctx;
1651
- const params = caseParams(node.parameters, "camelcase");
1652
1662
  const meta = { file: resolver.file({
1653
1663
  name: node.operationId,
1654
1664
  extname: ".ts",
@@ -1727,10 +1737,7 @@ const typeGenerator = (0, kubb_kit.defineGenerator)({
1727
1737
  name: baseName
1728
1738
  })] });
1729
1739
  }
1730
- const { path: pathParams, query: queryParams, header: headerParams } = getOperationParameters({
1731
- ...node,
1732
- parameters: params
1733
- }, { paramsCasing: "original" });
1740
+ const { path: pathParams, query: queryParams, header: headerParams } = getOperationParameters(node);
1734
1741
  const paramGroupTypes = [
1735
1742
  pathParams.length > 0 && renderSchemaType({
1736
1743
  schema: buildParams({ params: pathParams }),
@@ -1777,10 +1784,7 @@ const typeGenerator = (0, kubb_kit.defineGenerator)({
1777
1784
  });
1778
1785
  });
1779
1786
  const optionsType = renderSchemaType({
1780
- schema: buildOptions({
1781
- ...node,
1782
- parameters: params
1783
- }, { resolver }),
1787
+ schema: buildOptions(node, { resolver }),
1784
1788
  name: resolver.response.options(node)
1785
1789
  });
1786
1790
  const responsesType = renderSchemaType({
@@ -2230,17 +2234,14 @@ function resolveGroupType({ node, params, group, resolver }) {
2230
2234
  * name resolution and `extraParams` for plugin-specific trailing parameters such as an `options` object.
2231
2235
  */
2232
2236
  function createOperationParams(node, options) {
2233
- const { paramsType, pathParamsType, paramsCasing, resolver, pathParamsDefault, extraParams = [], paramNames, typeWrapper } = options;
2237
+ const { paramsType, pathParamsType, resolver, pathParamsDefault, extraParams = [], paramNames, typeWrapper } = options;
2234
2238
  const dataName = paramNames?.data ?? "data";
2235
2239
  const paramsName = paramNames?.params ?? "params";
2236
2240
  const headersName = paramNames?.headers ?? "headers";
2237
2241
  const pathName = paramNames?.path ?? "pathParams";
2238
2242
  const wrapType = (type) => typeWrapper ? typeWrapper(type) : type;
2239
2243
  const wrapTypeExpression = (type) => typeof type === "string" ? wrapType(type) : type;
2240
- const casedParams = caseParams(node.parameters, paramsCasing);
2241
- const pathParams = casedParams.filter((p) => p.in === "path");
2242
- const queryParams = casedParams.filter((p) => p.in === "query");
2243
- const headerParams = casedParams.filter((p) => p.in === "header");
2244
+ const { path: pathParams, query: queryParams, header: headerParams } = getOperationParameters(node);
2244
2245
  const toProperty = (param) => ({
2245
2246
  name: param.name,
2246
2247
  type: wrapTypeExpression(resolveParamType({