@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.d.ts CHANGED
@@ -845,10 +845,6 @@ type CreateOperationParamsOptions = {
845
845
  * - `'inlineSpread'` emits a single rest parameter `...pathParams: PathParams`
846
846
  */
847
847
  pathParamsType: 'object' | 'inline' | 'inlineSpread';
848
- /**
849
- * Converts parameter names to camelCase before output.
850
- */
851
- paramsCasing?: 'camelcase';
852
848
  /**
853
849
  * Resolver for parameter and request body type names.
854
850
  * Pass `ResolverTs` from `@kubb/plugin-ts` directly.
package/dist/index.js CHANGED
@@ -912,39 +912,19 @@ function Enum({ node, enum: enumOptions, resolver }) {
912
912
  }
913
913
  //#endregion
914
914
  //#region ../../internals/shared/src/params.ts
915
- const caseParamsCache = /* @__PURE__ */ new WeakMap();
916
915
  /**
917
- * Applies camelCase to parameter names and returns a new array without mutating the input.
916
+ * Drops parameters that share the same name, keeping the first.
918
917
  *
919
- * Run it before handing parameters to schema builders so output property keys get the right casing
920
- * while `OperationNode.parameters` stays intact for other consumers. When `casing` is unset, the
921
- * original array is returned unchanged. Results are cached per input array.
918
+ * A malformed spec can declare the same parameter name twice within one `in` location. Both would
919
+ * resolve to the same output property, so emitting both would yield an object type with a duplicate
920
+ * member, which TypeScript rejects. This is a defensive guard against that case, not a casing guard:
921
+ * parameter names flow through unchanged, so no two distinct names ever collide here anymore.
922
922
  */
923
- function caseParams(params, casing) {
924
- if (!casing) return params;
925
- const cached = caseParamsCache.get(params);
926
- if (cached) return cached;
927
- const result = params.map((param) => ({
928
- ...param,
929
- name: camelCase(param.name)
930
- }));
931
- caseParamsCache.set(params, result);
932
- return result;
933
- }
934
- /**
935
- * Drops parameters that collapse to the same property identity once camelCased, keeping the first.
936
- *
937
- * Some specs declare the same parameter twice under different casings (for example AWS S3 lists both
938
- * `max-uploads` and `MaxUploads`). Both resolve to one output property, so emitting both would yield
939
- * an object type with a duplicate member, which TypeScript rejects. De-duplicate by the camelCased
940
- * identity so the resulting group is collision-free regardless of the names each caller carries.
941
- */
942
- function dedupeByCasedName(params) {
923
+ function dedupeParams(params) {
943
924
  const seen = /* @__PURE__ */ new Set();
944
925
  return params.filter((param) => {
945
- const key = camelCase(param.name);
946
- if (seen.has(key)) return false;
947
- seen.add(key);
926
+ if (seen.has(param.name)) return false;
927
+ seen.add(param.name);
948
928
  return true;
949
929
  });
950
930
  }
@@ -998,13 +978,15 @@ function resolveContentTypeVariants(entries, baseName) {
998
978
  };
999
979
  });
1000
980
  }
1001
- function getOperationParameters(node, options = {}) {
1002
- const params = caseParams(node.parameters, options.paramsCasing === "original" ? void 0 : "camelcase");
981
+ function getOperationParameters(node) {
1003
982
  return {
1004
- path: dedupeByCasedName(params.filter((param) => param.in === "path")),
1005
- query: dedupeByCasedName(params.filter((param) => param.in === "query")),
1006
- header: dedupeByCasedName(params.filter((param) => param.in === "header")),
1007
- cookie: dedupeByCasedName(params.filter((param) => param.in === "cookie"))
983
+ path: dedupeParams(node.parameters.filter((param) => param.in === "path").map((param) => isValidVarName(param.name) ? param : {
984
+ ...param,
985
+ name: camelCase(param.name)
986
+ })),
987
+ query: dedupeParams(node.parameters.filter((param) => param.in === "query")),
988
+ header: dedupeParams(node.parameters.filter((param) => param.in === "header")),
989
+ cookie: dedupeParams(node.parameters.filter((param) => param.in === "cookie"))
1008
990
  };
1009
991
  }
1010
992
  //#endregion
@@ -1128,6 +1110,35 @@ function createGroupConfig(group) {
1128
1110
  };
1129
1111
  }
1130
1112
  //#endregion
1113
+ //#region ../../internals/shared/src/schemaTraversal.ts
1114
+ /**
1115
+ * Maps each property of an object schema to its transformed output. Pairs every result with the
1116
+ * original property so the printer keeps full control over modifiers, getters, and key syntax.
1117
+ *
1118
+ * @example
1119
+ * ```ts
1120
+ * const entries = mapSchemaProperties(node, (schema) => this.transform(schema))
1121
+ * // entries: [{ name: 'id', property, output: 'z.number()' }, ...]
1122
+ * ```
1123
+ */
1124
+ function mapSchemaProperties(node, transform) {
1125
+ return node.properties.map((property) => ({
1126
+ name: property.name,
1127
+ property,
1128
+ output: transform(property.schema)
1129
+ }));
1130
+ }
1131
+ /**
1132
+ * Maps each item of an array or tuple schema to its transformed output, pairing every result with
1133
+ * the original item.
1134
+ */
1135
+ function mapSchemaItems(node, transform) {
1136
+ return (node.items ?? []).map((schema) => ({
1137
+ schema,
1138
+ output: transform(schema)
1139
+ }));
1140
+ }
1141
+ //#endregion
1131
1142
  //#region src/utils.ts
1132
1143
  /**
1133
1144
  * Tells whether a `const` (single-value enum) should render as a bare literal type (`'active'`)
@@ -1192,7 +1203,7 @@ function buildParams({ params }) {
1192
1203
  });
1193
1204
  }
1194
1205
  function buildOptions(node, { resolver }) {
1195
- const { path: pathParams, query: queryParams, header: headerParams } = getOperationParameters(node, { paramsCasing: "original" });
1206
+ const { path: pathParams, query: queryParams, header: headerParams } = getOperationParameters(node);
1196
1207
  const hasBody = Boolean(node.requestBody?.content?.[0]?.schema);
1197
1208
  const hasRequiredPath = pathParams.some((param) => param.required);
1198
1209
  const hasRequiredQuery = queryParams.some((param) => param.required);
@@ -1443,7 +1454,7 @@ const printerTs = ast.createPrinter((options) => {
1443
1454
  },
1444
1455
  array(node) {
1445
1456
  return createArrayDeclaration({
1446
- nodes: ast.mapSchemaItems(node, (item) => this.transform(item)).map(({ output }) => output).filter(isNonNullable),
1457
+ nodes: mapSchemaItems(node, (item) => this.transform(item)).map(({ output }) => output).filter(isNonNullable),
1447
1458
  arrayType: this.options.arrayType
1448
1459
  }) ?? null;
1449
1460
  },
@@ -1453,7 +1464,7 @@ const printerTs = ast.createPrinter((options) => {
1453
1464
  object(node) {
1454
1465
  const { transform, options } = this;
1455
1466
  const addsQuestionToken = OPTIONAL_ADDS_QUESTION_TOKEN.has(options.optionalType);
1456
- const propertyNodes = ast.mapSchemaProperties(node, (schema) => transform(schema)).map(({ name, property, output }) => {
1467
+ const propertyNodes = mapSchemaProperties(node, (schema) => transform(schema)).map(({ name, property, output }) => {
1457
1468
  const baseType = output ?? keywordTypeNodes.unknown;
1458
1469
  const optional = !property.required || !!property.schema.optional || !!property.schema.nullish;
1459
1470
  const type = buildPropertyType(property.schema, baseType, options.optionalType, optional);
@@ -1609,7 +1620,6 @@ const typeGenerator = defineGenerator({
1609
1620
  operation(node, ctx) {
1610
1621
  const { enum: enumOptions, optionalType, arrayType, syntaxType, group, output, printer } = ctx.options;
1611
1622
  const { config, resolver, root } = ctx;
1612
- const params = caseParams(node.parameters, "camelcase");
1613
1623
  const meta = { file: resolver.file({
1614
1624
  name: node.operationId,
1615
1625
  extname: ".ts",
@@ -1688,10 +1698,7 @@ const typeGenerator = defineGenerator({
1688
1698
  name: baseName
1689
1699
  })] });
1690
1700
  }
1691
- const { path: pathParams, query: queryParams, header: headerParams } = getOperationParameters({
1692
- ...node,
1693
- parameters: params
1694
- }, { paramsCasing: "original" });
1701
+ const { path: pathParams, query: queryParams, header: headerParams } = getOperationParameters(node);
1695
1702
  const paramGroupTypes = [
1696
1703
  pathParams.length > 0 && renderSchemaType({
1697
1704
  schema: buildParams({ params: pathParams }),
@@ -1738,10 +1745,7 @@ const typeGenerator = defineGenerator({
1738
1745
  });
1739
1746
  });
1740
1747
  const optionsType = renderSchemaType({
1741
- schema: buildOptions({
1742
- ...node,
1743
- parameters: params
1744
- }, { resolver }),
1748
+ schema: buildOptions(node, { resolver }),
1745
1749
  name: resolver.response.options(node)
1746
1750
  });
1747
1751
  const responsesType = renderSchemaType({
@@ -2191,17 +2195,14 @@ function resolveGroupType({ node, params, group, resolver }) {
2191
2195
  * name resolution and `extraParams` for plugin-specific trailing parameters such as an `options` object.
2192
2196
  */
2193
2197
  function createOperationParams(node, options) {
2194
- const { paramsType, pathParamsType, paramsCasing, resolver, pathParamsDefault, extraParams = [], paramNames, typeWrapper } = options;
2198
+ const { paramsType, pathParamsType, resolver, pathParamsDefault, extraParams = [], paramNames, typeWrapper } = options;
2195
2199
  const dataName = paramNames?.data ?? "data";
2196
2200
  const paramsName = paramNames?.params ?? "params";
2197
2201
  const headersName = paramNames?.headers ?? "headers";
2198
2202
  const pathName = paramNames?.path ?? "pathParams";
2199
2203
  const wrapType = (type) => typeWrapper ? typeWrapper(type) : type;
2200
2204
  const wrapTypeExpression = (type) => typeof type === "string" ? wrapType(type) : type;
2201
- const casedParams = caseParams(node.parameters, paramsCasing);
2202
- const pathParams = casedParams.filter((p) => p.in === "path");
2203
- const queryParams = casedParams.filter((p) => p.in === "query");
2204
- const headerParams = casedParams.filter((p) => p.in === "header");
2205
+ const { path: pathParams, query: queryParams, header: headerParams } = getOperationParameters(node);
2205
2206
  const toProperty = (param) => ({
2206
2207
  name: param.name,
2207
2208
  type: wrapTypeExpression(resolveParamType({