@kubb/plugin-client 5.8.0-canary.20261025T201031 → 5.8.1

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.js CHANGED
@@ -1,11 +1,10 @@
1
- import { Diagnostics, Resolver, Url, addGenerator, ast, createResolver, defineExtension, defineGenerator, macroSimplifyUnion, setMacros, setResolver } from "kubb/kit";
1
+ import { Diagnostics, Resolver, Url, addGenerator, ast, camelCase, createResolver, defineExtension, defineGenerator, macroSimplifyUnion, pascalCase, setMacros, setResolver } from "kubb/kit";
2
2
  import path from "node:path";
3
3
  import { createFunctionParameter, createFunctionParameters, functionPrinter, pluginTsName } from "@kubb/plugin-ts";
4
4
  import { pluginZodName } from "@kubb/plugin-zod";
5
5
  import { File, Function, jsxRenderer } from "kubb/jsx";
6
6
  import { jsx, jsxs } from "kubb/jsx/jsx-runtime";
7
- //#endregion
8
- //#region ../../internals/shared/src/operation.ts
7
+ // ../../internals/shared/src/operation.ts
9
8
  /**
10
9
  * Builds the `ResolverFileParams` every operation generator passes to
11
10
  * `resolver.file`: a file named `name`, tagged by the operation's first
@@ -183,6 +182,16 @@ function getOperationParameters(node) {
183
182
  operationParameterGroupsByNode.set(node, groups);
184
183
  return groups;
185
184
  }
185
+ /**
186
+ * Builds the combined `{ body, path, query, headers }` options object schema for an operation,
187
+ * referencing the already-resolved body and grouped param names. Shared by `@kubb/plugin-ts`'s
188
+ * `Options` type and `@kubb/plugin-zod`'s inferred options schema, so both printers emit the same
189
+ * shape from the same inputs. `primitive: 'object'` is a no-op for the TS printer and tells the Zod
190
+ * printer to emit `z.object(…)` rather than a record.
191
+ */
192
+ function hasRequestContentTypeChoice(node) {
193
+ return (node.requestBody?.content ?? []).filter((entry) => entry.schema).length > 1;
194
+ }
186
195
  function getStatusCodeNumber(statusCode) {
187
196
  const code = Number(statusCode);
188
197
  return Number.isNaN(code) ? null : code;
@@ -200,58 +209,7 @@ function getOperationSuccessResponses(node) {
200
209
  function getPrimarySuccessResponse(node) {
201
210
  return getOperationSuccessResponses(node)[0] ?? null;
202
211
  }
203
- //#endregion
204
- //#region ../../internals/utils/src/casing.ts
205
- /**
206
- * Shared implementation for camelCase and PascalCase conversion.
207
- * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)
208
- * and capitalizes each word according to `pascal`.
209
- *
210
- * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
211
- */
212
- function convert(text, pascal) {
213
- return text.trim().replace(/([a-z\d])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/(\d)([a-z])/g, "$1 $2").split(/[\s\-_./\\:]+/).filter(Boolean).map((word, i) => {
214
- if (word.length > 1 && word === word.toUpperCase()) return word;
215
- return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
216
- }).join("").replace(/[^a-zA-Z0-9]/g, "");
217
- }
218
- const cache = /* @__PURE__ */ new Map();
219
- const cacheLimit = 1e4;
220
- function toCamelOrPascal(text, pascal) {
221
- const key = `${pascal ? "P" : "c"}${text}`;
222
- const cached = cache.get(key);
223
- if (cached !== void 0) return cached;
224
- const result = convert(text, pascal);
225
- if (cache.size >= cacheLimit) cache.clear();
226
- cache.set(key, result);
227
- return result;
228
- }
229
- /**
230
- * Converts `text` to camelCase.
231
- *
232
- * @example Word boundaries
233
- * `camelCase('hello-world') // 'helloWorld'`
234
- *
235
- * @example With a prefix
236
- * `camelCase('tag', { prefix: 'create' }) // 'createTag'`
237
- */
238
- function camelCase(text, { prefix = "", suffix = "" } = {}) {
239
- return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
240
- }
241
- /**
242
- * Converts `text` to PascalCase.
243
- *
244
- * @example Word boundaries
245
- * `pascalCase('hello-world') // 'HelloWorld'`
246
- *
247
- * @example With a suffix
248
- * `pascalCase('tag', { suffix: 'schema' }) // 'TagSchema'`
249
- */
250
- function pascalCase(text, { prefix = "", suffix = "" } = {}) {
251
- return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true);
252
- }
253
- //#endregion
254
- //#region ../../internals/utils/src/reserved.ts
212
+ // ../../internals/utils/src/reserved.ts
255
213
  /**
256
214
  * JavaScript and Java reserved words.
257
215
  * @link https://github.com/jonschlinkert/reserved/blob/master/index.js
@@ -259,6 +217,7 @@ function pascalCase(text, { prefix = "", suffix = "" } = {}) {
259
217
  const reservedWords = /* @__PURE__ */ new Set([
260
218
  "abstract",
261
219
  "arguments",
220
+ "await",
262
221
  "boolean",
263
222
  "break",
264
223
  "byte",
@@ -389,8 +348,32 @@ function ensureValidVarName(name) {
389
348
  function isIdentifier(name) {
390
349
  return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
391
350
  }
392
- //#endregion
393
- //#region ../../internals/shared/src/group.ts
351
+ // ../../internals/shared/src/resolver.ts
352
+ /**
353
+ * The shared top-level `name` of the operation plugins, computed once per operation name and build.
354
+ */
355
+ function resolveOperationName(name) {
356
+ return this.memo(`operation:${name}`, () => ensureValidVarName(camelCase(name)));
357
+ }
358
+ /**
359
+ * Builds the allocation key for a declaration an operation owns. `scope` names which declaration
360
+ * it is, so two of them never share an allocation even when a custom resolver gives both the same
361
+ * name. Leave `scope` empty for the operation's own declaration.
362
+ *
363
+ * @example
364
+ * ```ts
365
+ * resolver.resolveName({ key: operationKey(node, 'response', 'status', 404), name })
366
+ * ```
367
+ */
368
+ function operationKey(node, ...scope) {
369
+ return [
370
+ "operation",
371
+ node.method,
372
+ node.path,
373
+ ...scope.map(String)
374
+ ];
375
+ }
376
+ // ../../internals/shared/src/group.ts
394
377
  /**
395
378
  * Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the
396
379
  * shared default naming so every plugin groups output consistently:
@@ -420,17 +403,14 @@ function createGroupConfig(group) {
420
403
  name: group.name ? group.name : defaultName
421
404
  };
422
405
  }
423
- //#endregion
424
- //#region kubb-extension.json
406
+ // kubb-extension.json
425
407
  var compatibility = {
426
- "kubb": ">=5.8.3",
408
+ "kubb": ">=5.14.6",
427
409
  "node": ">=22.22"
428
410
  };
429
- //#endregion
430
- //#region package.json
431
- var version = "5.8.0-canary.20261025T201031";
432
- //#endregion
433
- //#region ../../internals/client/src/builders/validatorOptions.ts
411
+ // package.json
412
+ var version = "5.8.1";
413
+ // ../../internals/client/src/builders/validatorOptions.ts
434
414
  /**
435
415
  * Returns `true` when any direction of the validator uses zod (used for dependency checks).
436
416
  */
@@ -473,8 +453,7 @@ function buildZodErrorParse(node, zodResolver) {
473
453
  if (!node.responses.some((res) => !isSuccessStatusCode(res.statusCode) && res.content?.some((entry) => entry.schema))) return null;
474
454
  return zodResolver.response.error?.(node) || null;
475
455
  }
476
- //#endregion
477
- //#region ../../internals/client/src/builders/security.ts
456
+ // ../../internals/client/src/builders/security.ts
478
457
  function serializeAuth(auth) {
479
458
  const parts = [`type: '${auth.type}'`];
480
459
  if (auth.scheme) parts.push(`scheme: '${auth.scheme}'`);
@@ -545,8 +524,7 @@ function buildSecurityMetadata({ security }) {
545
524
  if (!security?.length) return null;
546
525
  return `[${security.map(serializeAuth).join(", ")}]`;
547
526
  }
548
- //#endregion
549
- //#region ../../internals/client/src/builders/validator.ts
527
+ // ../../internals/client/src/builders/validator.ts
550
528
  /**
551
529
  * Builds the validator-hook references for one operation. Request body and params validation run before the send.
552
530
  * Response validation runs on the success body only. Returns `null` references when the matching
@@ -588,17 +566,16 @@ function buildValidatorLiteral(hooks, keys) {
588
566
  const entries = keys.flatMap((key) => hooks?.[key] ? [`${key}: ${hooks[key]}`] : []);
589
567
  return entries.length ? `validator: { ${entries.join(", ")} }` : null;
590
568
  }
591
- //#endregion
592
- //#region ../../internals/client/src/builders/contentType.ts
569
+ // ../../internals/client/src/builders/contentType.ts
593
570
  /**
594
- * Builds the `contentType` entry baked into the call config, or `null` for the JSON default.
571
+ * Builds the `contentType` entry baked into the call config, or `null` without a request body.
595
572
  *
596
573
  * `merge` is `true` when the generated function must destructure `contentType` from `options` and
597
574
  * merge it over the baked request default, because the caller can also pick a response content type.
598
575
  */
599
576
  function buildContentType({ node }) {
600
577
  const { defaultContentType } = getContentTypeInfo(node);
601
- const requestContentType = Boolean(node.requestBody?.content?.[0]?.schema) && defaultContentType !== "application/json" ? defaultContentType : null;
578
+ const requestContentType = Boolean(node.requestBody?.content?.[0]?.schema) ? defaultContentType : null;
602
579
  if (!requestContentType) return {
603
580
  literal: null,
604
581
  merge: false
@@ -609,8 +586,7 @@ function buildContentType({ node }) {
609
586
  literal: merge ? `contentType: { request: '${requestContentType}', ...(typeof contentType === 'string' ? { request: contentType } : contentType) }` : `contentType: { request: '${requestContentType}' }`
610
587
  };
611
588
  }
612
- //#endregion
613
- //#region ../../internals/client/src/builders/generics.ts
589
+ // ../../internals/client/src/builders/generics.ts
614
590
  /**
615
591
  * Builds the `RequestResult` generic arguments for one operation: the per-status responses record
616
592
  * plus the per-call `ThrowOnError` flag. `SuccessOf` / `ErrorOf` split the record inside the
@@ -641,8 +617,7 @@ function buildResultType({ node, types, returnType }) {
641
617
  if (returnType === "plain") return `Promise<RequestResult<${generics}>>`;
642
618
  return `Unwrappable<RequestResult<${generics}>>`;
643
619
  }
644
- //#endregion
645
- //#region ../../internals/client/src/builders/returnStatement.ts
620
+ // ../../internals/client/src/builders/returnStatement.ts
646
621
  /**
647
622
  * Builds the return statement of a generated operation function. With the default
648
623
  * `returnType: 'full'` the runtime call already resolves to `{ data, error, request, response }`.
@@ -666,22 +641,22 @@ function buildResultType({ node, types, returnType }) {
666
641
  * `return request({ method: 'POST', url: '/pet', ...config }) as Promise<RequestResult<AddPetResponses, ThrowOnError>>`
667
642
  */
668
643
  function buildReturnStatement({ node, types, callConfig, returnType, throwOnErrorDefault }) {
669
- if (returnType === "data") return `return unwrapResult(request(${callConfig}), config.throwOnError ?? ${throwOnErrorDefault}) as ${buildResultType({
644
+ const request = returnType !== "plain" && hasRequestContentTypeChoice(node) ? `request<${types.response.options(node)}['body']>` : "request";
645
+ if (returnType === "data") return `return unwrapResult(${request}(${callConfig}), config.throwOnError ?? ${throwOnErrorDefault}) as ${buildResultType({
670
646
  node,
671
647
  types,
672
648
  returnType
673
649
  })}`;
674
- if (returnType === "plain") return `return request(${callConfig}) as Promise<RequestResult<${buildRequestResultGenerics({
650
+ if (returnType === "plain") return `return ${request}(${callConfig}) as Promise<RequestResult<${buildRequestResultGenerics({
675
651
  node,
676
652
  types
677
653
  })}>>`;
678
- return `return withUnwrap(request(${callConfig}) as Promise<RequestResult<${buildRequestResultGenerics({
654
+ return `return withUnwrap(${request}(${callConfig}) as Promise<RequestResult<${buildRequestResultGenerics({
679
655
  node,
680
656
  types
681
657
  })}>>)`;
682
658
  }
683
- //#endregion
684
- //#region ../../internals/client/src/builders/signature.ts
659
+ // ../../internals/client/src/builders/signature.ts
685
660
  const declarationPrinter = functionPrinter({ mode: "declaration" });
686
661
  /**
687
662
  * Builds the grouped-options signature for one operation: a single `options` object whose `TData`
@@ -709,8 +684,7 @@ function buildGroupedOptionsSignature({ node, types, returnType, throwOnErrorDef
709
684
  generics: [`ThrowOnError extends boolean = ${throwOnErrorDefault}`]
710
685
  };
711
686
  }
712
- //#endregion
713
- //#region ../../internals/client/src/builders/styles.ts
687
+ // ../../internals/client/src/builders/styles.ts
714
688
  /**
715
689
  * Renders a parameter name as an object-literal key, quoted when it is not a bare identifier. Every
716
690
  * location keeps the spec name: the runtime looks path styles up by the `{name}` placeholder in the
@@ -782,8 +756,7 @@ function buildStyles({ node }) {
782
756
  const entries = [...Object.keys(groups).filter((location) => groups[location].length > 0).map((location) => `${location}: { ${groups[location].join(", ")} }`), serializeBodyEncoding(node)].filter(Boolean);
783
757
  return entries.length > 0 ? `{ ${entries.join(", ")} }` : null;
784
758
  }
785
- //#endregion
786
- //#region ../../internals/client/src/components/Operation.tsx
759
+ // ../../internals/client/src/components/Operation.tsx
787
760
  /**
788
761
  * Renders one client operation: the grouped `<Name>Request` type and the function that forwards a
789
762
  * single `options` object to the resolved client and returns the `Unwrappable<RequestResult>`. The
@@ -860,8 +833,7 @@ function Operation({ name, node, types, zodResolver, validator, returnType, thro
860
833
  })
861
834
  });
862
835
  }
863
- //#endregion
864
- //#region ../../internals/client/src/resolveOperationTypes.ts
836
+ // ../../internals/client/src/resolveOperationTypes.ts
865
837
  /**
866
838
  * A `plugin-ts` shaped resolver whose operation type names point at the types `pluginZod({ inferred })`
867
839
  * exports next to each schema, so code written against `plugin-ts` names picks up the zod types.
@@ -871,6 +843,7 @@ function toZodTypeResolver(resolver) {
871
843
  return {
872
844
  ...resolver,
873
845
  file: resolver.file.bind(resolver),
846
+ memo: (key, compute) => resolver.memo(`zodTypes:${key}`, compute),
874
847
  param: {
875
848
  name: (node, p) => type(resolver.param.name(node, p)),
876
849
  path: (node, p) => type(resolver.param.path(node, p)),
@@ -927,8 +900,7 @@ function resolveOperationTypes(driver, pluginName) {
927
900
  group: pluginZod.options.group ?? void 0
928
901
  };
929
902
  }
930
- //#endregion
931
- //#region ../../internals/client/src/generators/clientGenerator.tsx
903
+ // ../../internals/client/src/generators/clientGenerator.tsx
932
904
  /**
933
905
  * Builds the built-in per-operation generator shared by the client plugins (`@kubb/plugin-fetch`,
934
906
  * `@kubb/plugin-axios`). Emits one async function per OpenAPI operation using the shared
@@ -955,8 +927,12 @@ function createClientGenerator(name, resolveClientPath) {
955
927
  zodResolver
956
928
  });
957
929
  const importedZodNames = validatorHooks.importedZodNames;
930
+ const operationName = resolver.name(node.operationId);
958
931
  const meta = {
959
- name: resolver.name(node.operationId),
932
+ name: resolver.resolveName({
933
+ key: operationKey(node),
934
+ name: operationName
935
+ }),
960
936
  file: resolver.file({
961
937
  ...operationFileEntry(node, node.operationId),
962
938
  root,
@@ -1071,19 +1047,17 @@ function createClientGenerator(name, resolveClientPath) {
1071
1047
  }
1072
1048
  });
1073
1049
  }
1074
- //#endregion
1075
- //#region ../../internals/client/src/macros.ts
1050
+ // ../../internals/client/src/macros.ts
1076
1051
  /**
1077
1052
  * Macros the client plugins apply by default, ahead of any user macros. `macroSimplifyUnion`
1078
1053
  * drops union members a broader scalar already covers, keeping the generated response and error
1079
1054
  * unions tidy. A plugin wires them with `ctx.setMacros([...defaultMacros, ...userMacros])`.
1080
1055
  */
1081
1056
  const defaultMacros = [macroSimplifyUnion];
1082
- //#endregion
1083
- //#region ../../internals/client/src/resolver.ts
1057
+ // ../../internals/client/src/resolver.ts
1084
1058
  /**
1085
- * Default resolver shared by the client plugins. Functions and files inherit the built-in camelCase
1086
- * `name` and `file`; classes and tag groups use PascalCase.
1059
+ * Default resolver shared by the client plugins. Functions use safe camelCase identifiers and
1060
+ * files inherit the built-in casing; classes and tag groups use PascalCase.
1087
1061
  *
1088
1062
  * @example
1089
1063
  * ```ts
@@ -1093,6 +1067,7 @@ const defaultMacros = [macroSimplifyUnion];
1093
1067
  */
1094
1068
  const resolverClient = createResolver({
1095
1069
  pluginName: "plugin-contract-client",
1070
+ name: resolveOperationName,
1096
1071
  className(name) {
1097
1072
  return ensureValidVarName(pascalCase(name));
1098
1073
  },
@@ -1103,16 +1078,14 @@ const resolverClient = createResolver({
1103
1078
  return ensureValidVarName(camelCase(name));
1104
1079
  }
1105
1080
  });
1106
- //#endregion
1107
- //#region src/generators/clientGenerator.tsx
1081
+ // src/generators/clientGenerator.tsx
1108
1082
  /**
1109
1083
  * Built-in operation generator for `@kubb/plugin-client`. Emits one async function per OpenAPI
1110
1084
  * operation using the shared `Operation` component: a grouped `<Name>Request` type and a function
1111
1085
  * that forwards a single `options` object to the user-provided client module and returns the `RequestResult`.
1112
1086
  */
1113
1087
  const clientGenerator = createClientGenerator("client", (options) => options.importPath);
1114
- //#endregion
1115
- //#region src/plugin.ts
1088
+ // src/plugin.ts
1116
1089
  /**
1117
1090
  * Canonical plugin name for `@kubb/plugin-client`.
1118
1091
  */
@@ -1163,7 +1136,6 @@ const pluginClient = defineExtension({
1163
1136
  };
1164
1137
  }
1165
1138
  });
1166
- //#endregion
1167
1139
  export { pluginClient as default, pluginClient, pluginClientName };
1168
1140
 
1169
1141
  //# sourceMappingURL=index.js.map