@kubb/plugin-fetch 5.0.0-beta.84 → 5.0.0-beta.85

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
@@ -367,6 +367,34 @@ function dedupeByCasedName(params) {
367
367
  return true;
368
368
  });
369
369
  }
370
+ function buildParamsMapping(originalParams, mappedParams) {
371
+ const mapping = {};
372
+ let hasChanged = false;
373
+ originalParams.forEach((param, i) => {
374
+ const mappedName = mappedParams[i]?.name ?? param.name;
375
+ mapping[param.name] = mappedName;
376
+ if (param.name !== mappedName) hasChanged = true;
377
+ });
378
+ return hasChanged ? mapping : null;
379
+ }
380
+ function toAccess(object, name) {
381
+ return isValidVarName(name) ? `${object}.${name}` : `${object}[${JSON.stringify(name)}]`;
382
+ }
383
+ /**
384
+ * Renders the object-literal expression that renames the camelCased keys of a grouped request
385
+ * option back to the names the OpenAPI document declares, guarded so an omitted optional group
386
+ * stays omitted. Shared by the client and cypress generators, which pass a `buildParamsMapping`
387
+ * result and the source expression to read the keys from.
388
+ *
389
+ * @example
390
+ * ```ts
391
+ * buildParamsRemapExpression({ source: 'config.query', mapping: { include_deleted: 'includeDeleted' } })
392
+ * // 'config.query ? { "include_deleted": config.query.includeDeleted } : config.query'
393
+ * ```
394
+ */
395
+ function buildParamsRemapExpression({ source, mapping }) {
396
+ return `${source} ? { ${Object.entries(mapping).map(([originalName, casedName]) => `${JSON.stringify(originalName)}: ${toAccess(source, casedName)}`).join(", ")} } : ${source}`;
397
+ }
370
398
  //#endregion
371
399
  //#region ../../internals/shared/src/operation.ts
372
400
  /**
@@ -688,6 +716,38 @@ function buildSecurityMetadata({ security }) {
688
716
  return `[${security.map(serializeAuth).join(", ")}]`;
689
717
  }
690
718
  //#endregion
719
+ //#region ../../internals/client/src/builders/paramsRemap.ts
720
+ /**
721
+ * Builds the call-config entries that rename the camelCased `query` and `headers` keys back to the
722
+ * names the OpenAPI document declares, so the wire format follows the spec while the generated
723
+ * types keep camelCase keys. Returns an empty array when no name changes. Path parameters need no
724
+ * remap because the URL template placeholders are renamed in sync with the `path` keys. Emit the
725
+ * entries after the `...config` spread so they override the camelCased groups the caller passes in.
726
+ *
727
+ * @example
728
+ * ```ts
729
+ * // a query param named include_deleted in the spec
730
+ * buildParamsRemap({ node }) // ['query: config.query ? { "include_deleted": config.query.includeDeleted } : config.query']
731
+ * ```
732
+ */
733
+ function buildParamsRemap({ node }) {
734
+ if (!kubb_kit.ast.isHttpOperationNode(node)) return [];
735
+ const original = getOperationParameters(node, { paramsCasing: "original" });
736
+ const cased = getOperationParameters(node);
737
+ const queryMapping = buildParamsMapping(original.query, cased.query);
738
+ const headerMapping = buildParamsMapping(original.header, cased.header);
739
+ const entries = [];
740
+ if (queryMapping) entries.push(`query: ${buildParamsRemapExpression({
741
+ source: "config.query",
742
+ mapping: queryMapping
743
+ })}`);
744
+ if (headerMapping) entries.push(`headers: ${buildParamsRemapExpression({
745
+ source: "config.headers",
746
+ mapping: headerMapping
747
+ })}`);
748
+ return entries;
749
+ }
750
+ //#endregion
691
751
  //#region ../../internals/client/src/builders/generics.ts
692
752
  /**
693
753
  * Builds the `RequestResult` generic arguments for one operation: the plugin-ts per-status responses
@@ -750,12 +810,13 @@ function buildGroupedOptionsSignature({ node, tsResolver }) {
750
810
  //#endregion
751
811
  //#region ../../internals/client/src/builders/styles.ts
752
812
  /**
753
- * Renders a parameter name as an object-literal key, quoting it when the camelCased name is not a
754
- * bare identifier (for example a name that starts with a digit) so the emitted literal stays valid.
813
+ * Renders a parameter name as an object-literal key, quoted when it is not a bare identifier.
814
+ * Path keys are camelCased to match the URL template placeholders. Query, header, and cookie keys
815
+ * keep the spec name, matching the remapped keys the runtime serializes.
755
816
  */
756
- function toKey(name) {
757
- const cased = camelCase(name);
758
- return isValidVarName(cased) ? cased : JSON.stringify(cased);
817
+ function toKey(name, location) {
818
+ const key = location === "path" ? camelCase(name) : name;
819
+ return isValidVarName(key) ? key : JSON.stringify(key);
759
820
  }
760
821
  /**
761
822
  * Serializes one parameter's metadata into a `{ style, explode }` literal, or `null` when the
@@ -769,8 +830,9 @@ function serializeParameter(parameter) {
769
830
  return parts.length > 0 ? `{ ${parts.join(", ")} }` : null;
770
831
  }
771
832
  /**
772
- * Builds the per-operation `styles` literal from the operation's parameters, grouped by location and
773
- * keyed by the camelCased parameter name to match the generated `path` / `query` / `headers` keys.
833
+ * Builds the per-operation `styles` literal from the operation's parameters, grouped by location.
834
+ * Path entries are keyed by the camelCased name to match the URL template placeholders; query,
835
+ * header, and cookie entries keep the spec name to match the keys the runtime serializes.
774
836
  * Only parameters whose source defines `style` or `explode` are emitted, so calls without
775
837
  * serialization metadata keep the runtime defaults and existing output is unchanged. Returns `null`
776
838
  * when no parameter carries metadata.
@@ -792,7 +854,7 @@ function buildStyles({ node }) {
792
854
  for (const parameter of node.parameters) {
793
855
  const literal = serializeParameter(parameter);
794
856
  if (!literal) continue;
795
- groups[parameter.in].push(`${toKey(parameter.name)}: ${literal}`);
857
+ groups[parameter.in].push(`${toKey(parameter.name, parameter.in)}: ${literal}`);
796
858
  }
797
859
  const locations = Object.keys(groups).filter((location) => groups[location].length > 0);
798
860
  if (locations.length === 0) return null;
@@ -865,7 +927,8 @@ function Operation({ name, node, tsResolver, zodResolver, validator, security, i
865
927
  validatorLiteral,
866
928
  contentTypeLiteral,
867
929
  responseTypeLiteral,
868
- "...config"
930
+ "...config",
931
+ ...buildParamsRemap({ node })
869
932
  ].filter(Boolean).join(", ")} }`;
870
933
  const eventType = `SuccessOf<${tsResolver.resolveResponsesName(node)}>`;
871
934
  const returnType = eventStream ? `Promise<EventStreamResult<${eventType}>>` : signature.returnType;
@@ -918,7 +981,8 @@ function buildCallConfig({ node, validator, zodResolver, security }) {
918
981
  `url: '${Url.toCasedTemplate(node.path, { casing: "camelcase" })}'`,
919
982
  securityLiteral ? `security: ${securityLiteral}` : null,
920
983
  validatorLiteral,
921
- "...config"
984
+ "...config",
985
+ ...buildParamsRemap({ node })
922
986
  ].filter(Boolean).join(", ")} }`;
923
987
  }
924
988
  /**