@kubb/plugin-client 5.0.0-beta.22 → 5.0.0-beta.27

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.
Files changed (37) hide show
  1. package/dist/clients/axios.cjs +18 -3
  2. package/dist/clients/axios.cjs.map +1 -1
  3. package/dist/clients/axios.d.ts +8 -2
  4. package/dist/clients/axios.js +18 -3
  5. package/dist/clients/axios.js.map +1 -1
  6. package/dist/clients/fetch.cjs +16 -1
  7. package/dist/clients/fetch.cjs.map +1 -1
  8. package/dist/clients/fetch.d.ts +8 -2
  9. package/dist/clients/fetch.js +16 -1
  10. package/dist/clients/fetch.js.map +1 -1
  11. package/dist/index.cjs +171 -94
  12. package/dist/index.cjs.map +1 -1
  13. package/dist/index.d.ts +125 -65
  14. package/dist/index.js +171 -94
  15. package/dist/index.js.map +1 -1
  16. package/dist/templates/clients/axios.source.cjs +1 -1
  17. package/dist/templates/clients/axios.source.js +1 -1
  18. package/dist/templates/clients/fetch.source.cjs +1 -1
  19. package/dist/templates/clients/fetch.source.js +1 -1
  20. package/extension.yaml +774 -260
  21. package/package.json +6 -6
  22. package/src/clients/axios.ts +28 -5
  23. package/src/clients/fetch.ts +25 -2
  24. package/src/components/ClassClient.tsx +3 -3
  25. package/src/components/Client.tsx +27 -19
  26. package/src/components/StaticClassClient.tsx +3 -3
  27. package/src/components/Url.tsx +1 -1
  28. package/src/functionParams.ts +8 -8
  29. package/src/generators/classClientGenerator.tsx +16 -11
  30. package/src/generators/clientGenerator.tsx +16 -8
  31. package/src/generators/groupedClientGenerator.tsx +9 -3
  32. package/src/generators/operationsGenerator.tsx +7 -1
  33. package/src/generators/staticClassClientGenerator.tsx +16 -10
  34. package/src/plugin.ts +24 -11
  35. package/src/resolvers/resolverClient.ts +16 -9
  36. package/src/types.ts +66 -53
  37. package/src/utils.ts +17 -16
package/dist/index.cjs CHANGED
@@ -191,6 +191,26 @@ function isValidVarName(name) {
191
191
  if (!name || reservedWords.has(name)) return false;
192
192
  return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
193
193
  }
194
+ /**
195
+ * Returns `name` when it's a syntactically valid JavaScript variable name,
196
+ * otherwise prefixes it with `_` so the result is a valid identifier.
197
+ *
198
+ * Useful for sanitizing OpenAPI schema names or operation IDs that start with
199
+ * a digit (e.g. `409`, `504AccountCancel`) before using them as exported
200
+ * variable, type, or function names.
201
+ *
202
+ * @example
203
+ * ```ts
204
+ * ensureValidVarName('409') // '_409'
205
+ * ensureValidVarName('504AccountCancel') // '_504AccountCancel'
206
+ * ensureValidVarName('Pet') // 'Pet'
207
+ * ensureValidVarName('class') // '_class'
208
+ * ```
209
+ */
210
+ function ensureValidVarName(name) {
211
+ if (!name || isValidVarName(name)) return name;
212
+ return `_${name}`;
213
+ }
194
214
  //#endregion
195
215
  //#region ../../internals/utils/src/urlPath.ts
196
216
  /**
@@ -257,12 +277,12 @@ var URLPath = class {
257
277
  get object() {
258
278
  return this.toObject();
259
279
  }
260
- /** Returns a map of path parameter names, or `undefined` when the path has no parameters.
280
+ /** Returns a map of path parameter names, or `null` when the path has no parameters.
261
281
  *
262
282
  * @example
263
283
  * ```ts
264
284
  * new URLPath('/pet/{petId}').params // { petId: 'petId' }
265
- * new URLPath('/pet').params // undefined
285
+ * new URLPath('/pet').params // null
266
286
  * ```
267
287
  */
268
288
  get params() {
@@ -325,7 +345,7 @@ var URLPath = class {
325
345
  const key = replacer ? replacer(param) : param;
326
346
  params[key] = key;
327
347
  });
328
- return Object.keys(params).length > 0 ? params : void 0;
348
+ return Object.keys(params).length > 0 ? params : null;
329
349
  }
330
350
  /** Converts the OpenAPI path to Express-style colon syntax.
331
351
  *
@@ -341,9 +361,9 @@ var URLPath = class {
341
361
  //#endregion
342
362
  //#region ../../internals/shared/src/operation.ts
343
363
  function getOperationLink(node, link) {
344
- if (!link) return;
345
- if (typeof link === "function") return link(node);
346
- if (link === "urlPath") return node.path ? `{@link ${new URLPath(node.path).URL}}` : void 0;
364
+ if (!link) return null;
365
+ if (typeof link === "function") return link(node) ?? null;
366
+ if (link === "urlPath") return node.path ? `{@link ${new URLPath(node.path).URL}}` : null;
347
367
  return `{@link ${node.path.replaceAll("{", ":").replaceAll("}", "")}}`;
348
368
  }
349
369
  function getContentTypeInfo(node) {
@@ -358,9 +378,9 @@ function getContentTypeInfo(node) {
358
378
  };
359
379
  }
360
380
  function buildRequestConfigType(node, resolver) {
361
- const requestName = node.requestBody?.content?.[0]?.schema ? resolver.resolveDataName(node) : void 0;
381
+ const requestName = node.requestBody?.content?.[0]?.schema ? resolver.resolveDataName(node) : null;
362
382
  const { isMultipleContentTypes, contentTypeUnion } = getContentTypeInfo(node);
363
- return `${requestName ? `Partial<RequestConfig<${requestName}>>` : "Partial<RequestConfig>"} & { ${["client?: Client", isMultipleContentTypes ? `contentType?: ${contentTypeUnion}` : void 0].filter(Boolean).join("; ")} }`;
383
+ return `${requestName ? `Partial<RequestConfig<${requestName}>>` : "Partial<RequestConfig>"} & { ${["client?: Client", isMultipleContentTypes ? `contentType?: ${contentTypeUnion}` : null].filter(Boolean).join("; ")} }`;
364
384
  }
365
385
  function buildOperationComments(node, options = {}) {
366
386
  const { link = "pathTemplate", linkPosition = "afterDeprecated", splitLines = false } = options;
@@ -390,15 +410,22 @@ function getOperationParameters(node, options = {}) {
390
410
  }
391
411
  function getStatusCodeNumber(statusCode) {
392
412
  const code = Number(statusCode);
393
- return Number.isNaN(code) ? void 0 : code;
413
+ return Number.isNaN(code) ? null : code;
414
+ }
415
+ function isSuccessStatusCode(statusCode) {
416
+ const code = getStatusCodeNumber(statusCode);
417
+ return code !== null && code >= 200 && code < 300;
394
418
  }
395
419
  function isErrorStatusCode(statusCode) {
396
420
  const code = getStatusCodeNumber(statusCode);
397
- return code !== void 0 && code >= 400;
421
+ return code !== null && code >= 400;
398
422
  }
399
423
  function resolveErrorNames(node, resolver) {
400
424
  return node.responses.filter((response) => isErrorStatusCode(response.statusCode)).map((response) => resolver.resolveResponseStatusName(node, response.statusCode));
401
425
  }
426
+ function resolveSuccessNames(node, resolver) {
427
+ return node.responses.filter((response) => isSuccessStatusCode(response.statusCode)).map((response) => resolver.resolveResponseStatusName(node, response.statusCode));
428
+ }
402
429
  function resolveStatusCodeNames(node, resolver) {
403
430
  return node.responses.map((response) => resolver.resolveResponseStatusName(node, response.statusCode));
404
431
  }
@@ -421,7 +448,7 @@ function resolveOperationTypeNames(node, resolver, options = {}) {
421
448
  ...query.map((param) => resolver.resolveQueryParamsName(node, param)),
422
449
  ...header.map((param) => resolver.resolveHeaderParamsName(node, param))
423
450
  ];
424
- const bodyAndResponseNames = [node.requestBody?.content?.[0]?.schema ? resolver.resolveDataName(node) : void 0, resolver.resolveResponseName(node)];
451
+ const bodyAndResponseNames = [node.requestBody?.content?.[0]?.schema ? resolver.resolveDataName(node) : null, resolver.resolveResponseName(node)];
425
452
  const result = (options.order === "body-response-first" ? [
426
453
  ...bodyAndResponseNames,
427
454
  ...paramNames,
@@ -444,7 +471,7 @@ function buildParamsMapping(originalParams, mappedParams) {
444
471
  mapping[param.name] = mappedName;
445
472
  if (param.name !== mappedName) hasChanged = true;
446
473
  });
447
- return hasChanged ? mapping : void 0;
474
+ return hasChanged ? mapping : null;
448
475
  }
449
476
  //#endregion
450
477
  //#region src/functionParams.ts
@@ -457,18 +484,18 @@ function createType(type) {
457
484
  return type ? _kubb_core.ast.createParamsType({
458
485
  variant: "reference",
459
486
  name: type
460
- }) : void 0;
487
+ }) : null;
461
488
  }
462
489
  function createDeclarationLeaf(name, spec) {
463
490
  if (spec.default !== void 0) return _kubb_core.ast.createFunctionParameter({
464
491
  name,
465
- type: createType(spec.type),
492
+ type: createType(spec.type) ?? void 0,
466
493
  default: spec.default,
467
494
  rest: spec.mode === "inlineSpread"
468
495
  });
469
496
  return _kubb_core.ast.createFunctionParameter({
470
497
  name,
471
- type: createType(spec.type),
498
+ type: createType(spec.type) ?? void 0,
472
499
  optional: !!spec.optional,
473
500
  rest: spec.mode === "inlineSpread"
474
501
  });
@@ -477,14 +504,14 @@ function createDeclarationParam(name, spec) {
477
504
  if (isGroup(spec)) return _kubb_core.ast.createParameterGroup({
478
505
  inline: spec.mode === "inlineSpread",
479
506
  default: spec.default,
480
- properties: Object.entries(spec.children).filter(([, child]) => child !== void 0).map(([childName, child]) => createDeclarationLeaf(childName, child))
507
+ properties: Object.entries(spec.children).filter(([, child]) => child != null).map(([childName, child]) => createDeclarationLeaf(childName, child))
481
508
  });
482
509
  return createDeclarationLeaf(name, spec);
483
510
  }
484
511
  function createCallParam(name, spec) {
485
512
  if (isGroup(spec)) return _kubb_core.ast.createParameterGroup({
486
513
  inline: spec.mode === "inlineSpread",
487
- properties: Object.entries(spec.children).filter(([, child]) => child !== void 0).map(([childName, child]) => _kubb_core.ast.createFunctionParameter({
514
+ properties: Object.entries(spec.children).filter(([, child]) => child != null).map(([childName, child]) => _kubb_core.ast.createFunctionParameter({
488
515
  name: child?.mode === "inlineSpread" ? spec.mode === "inlineSpread" ? child.value ?? childName : `...${child.value ?? childName}` : child?.value ? `${childName}: ${child.value}` : childName,
489
516
  rest: spec.mode === "inlineSpread" && child?.mode === "inlineSpread"
490
517
  }))
@@ -499,7 +526,7 @@ function createCallParam(name, spec) {
499
526
  * Returns utilities to output constructor signatures (`toConstructor()`) or call expressions (`toCall()`).
500
527
  */
501
528
  function createFunctionParams(params) {
502
- const entries = Object.entries(params).filter(([, spec]) => spec !== void 0);
529
+ const entries = Object.entries(params).filter(([, spec]) => spec != null);
503
530
  return {
504
531
  toConstructor() {
505
532
  return declarationPrinter$4.print(_kubb_core.ast.createFunctionParameters({ params: entries.map(([name, spec]) => createDeclarationParam(name, spec)) })) ?? "";
@@ -537,7 +564,7 @@ function Url({ name, isExportable = true, isIndexable = true, baseURL, paramsTyp
537
564
  const paramsSignature = declarationPrinter$3.print(paramsNode) ?? "";
538
565
  const { path: originalPathParams } = getOperationParameters(node);
539
566
  const { path: casedPathParams } = getOperationParameters(node, { paramsCasing });
540
- const pathParamsMapping = paramsCasing ? buildParamsMapping(originalPathParams, casedPathParams) : void 0;
567
+ const pathParamsMapping = paramsCasing ? buildParamsMapping(originalPathParams, casedPathParams) : null;
541
568
  return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
542
569
  name,
543
570
  isExportable,
@@ -584,19 +611,20 @@ function Client({ name, isExportable = true, isIndexable = true, returnType, bas
584
611
  const isFormData = !isMultipleContentTypes && contentType === "multipart/form-data";
585
612
  const { path: originalPathParams, query: originalQueryParams, header: originalHeaderParams } = getOperationParameters(node);
586
613
  const { path: casedPathParams, query: casedQueryParams, header: casedHeaderParams } = getOperationParameters(node, { paramsCasing });
587
- const pathParamsMapping = paramsCasing && !urlName ? buildParamsMapping(originalPathParams, casedPathParams) : void 0;
588
- const queryParamsMapping = paramsCasing ? buildParamsMapping(originalQueryParams, casedQueryParams) : void 0;
589
- const headerParamsMapping = paramsCasing ? buildParamsMapping(originalHeaderParams, casedHeaderParams) : void 0;
590
- const requestName = node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : void 0;
591
- const responseName = tsResolver.resolveResponseName(node);
592
- const queryParamsName = originalQueryParams.length > 0 ? tsResolver.resolveQueryParamsName(node, originalQueryParams[0]) : void 0;
593
- const headerParamsName = originalHeaderParams.length > 0 ? tsResolver.resolveHeaderParamsName(node, originalHeaderParams[0]) : void 0;
594
- const zodResponseName = zodResolver && parser === "zod" ? zodResolver.resolveResponseName?.(node) : void 0;
595
- const zodRequestName = zodResolver && parser === "zod" && node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : void 0;
614
+ const pathParamsMapping = paramsCasing && !urlName ? buildParamsMapping(originalPathParams, casedPathParams) : null;
615
+ const queryParamsMapping = paramsCasing ? buildParamsMapping(originalQueryParams, casedQueryParams) : null;
616
+ const headerParamsMapping = paramsCasing ? buildParamsMapping(originalHeaderParams, casedHeaderParams) : null;
617
+ const requestName = node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : null;
618
+ const successNames = resolveSuccessNames(node, tsResolver);
619
+ const responseName = successNames.length > 0 ? successNames.join(" | ") : tsResolver.resolveResponseName(node);
620
+ const queryParamsName = originalQueryParams.length > 0 ? tsResolver.resolveQueryParamsName(node, originalQueryParams[0]) : null;
621
+ const headerParamsName = originalHeaderParams.length > 0 ? tsResolver.resolveHeaderParamsName(node, originalHeaderParams[0]) : null;
622
+ const zodResponseName = zodResolver && parser === "zod" ? zodResolver.resolveResponseName?.(node) : null;
623
+ const zodRequestName = zodResolver && parser === "zod" && node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : null;
596
624
  const errorNames = node.responses.filter((r) => {
597
625
  return Number.parseInt(r.statusCode, 10) >= 400;
598
626
  }).map((r) => tsResolver.resolveResponseStatusName(node, r.statusCode));
599
- const headers = [!isMultipleContentTypes && contentType !== "application/json" && contentType !== "multipart/form-data" ? `'Content-Type': '${contentType}'` : void 0, headerParamsName ? headerParamsMapping ? "...mappedHeaders" : "...headers" : void 0].filter(Boolean);
627
+ const headers = [!isMultipleContentTypes && contentType !== "application/json" && contentType !== "multipart/form-data" ? `'Content-Type': '${contentType}'` : null, headerParamsName ? headerParamsMapping ? "...mappedHeaders" : "...headers" : null].filter(Boolean);
600
628
  const generics = [
601
629
  responseName,
602
630
  `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(" | ") : "Error"}>`,
@@ -624,12 +652,12 @@ function Client({ name, isExportable = true, isIndexable = true, returnType, bas
624
652
  children: {
625
653
  method: { value: JSON.stringify(node.method.toUpperCase()) },
626
654
  url: { value: urlName ? `${urlName}(${urlParamsCall}).url.toString()` : path.template },
627
- baseURL: baseURL && !urlName ? { value: `\`${baseURL}\`` } : void 0,
628
- params: queryParamsName ? queryParamsMapping ? { value: "mappedParams" } : {} : void 0,
629
- data: requestName ? { value: isMultipleContentTypes && hasFormData ? "contentType === 'multipart/form-data' ? formData as FormData : requestData" : isFormData ? "formData as FormData" : "requestData" } : void 0,
630
- contentType: isConfigurable && isMultipleContentTypes ? {} : void 0,
631
- requestConfig: isConfigurable ? { mode: "inlineSpread" } : void 0,
632
- headers: headers.length ? { value: isConfigurable ? `{ ${headers.join(", ")}, ...requestConfig.headers }` : `{ ${headers.join(", ")} }` } : void 0
655
+ baseURL: baseURL && !urlName ? { value: `\`${baseURL}\`` } : null,
656
+ params: queryParamsName ? queryParamsMapping ? { value: "mappedParams" } : {} : null,
657
+ data: requestName ? { value: isMultipleContentTypes && hasFormData ? "contentType === 'multipart/form-data' ? formData as FormData : requestData" : isFormData ? "formData as FormData" : "requestData" } : null,
658
+ contentType: isConfigurable && isMultipleContentTypes ? {} : null,
659
+ requestConfig: isConfigurable ? { mode: "inlineSpread" } : null,
660
+ headers: headers.length ? { value: isConfigurable ? `{ ${headers.join(", ")}, ...requestConfig.headers }` : `{ ${headers.join(", ")} }` } : null
633
661
  }
634
662
  } });
635
663
  const childrenElement = children ? children : /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [
@@ -687,15 +715,16 @@ function Client({ name, isExportable = true, isIndexable = true, returnType, bas
687
715
  * Includes Content-Type (if not default) and spreads header parameters if present.
688
716
  */
689
717
  function buildHeaders(contentType, hasHeaderParams) {
690
- return [contentType !== "application/json" && contentType !== "multipart/form-data" ? `'Content-Type': '${contentType}'` : void 0, hasHeaderParams ? "...headers" : void 0].filter(Boolean);
718
+ return [contentType !== "application/json" && contentType !== "multipart/form-data" ? `'Content-Type': '${contentType}'` : null, hasHeaderParams ? "...headers" : null].filter(Boolean);
691
719
  }
692
720
  /**
693
721
  * Builds TypeScript generic parameters for a client method.
694
722
  * Includes response type, error type, and optional request type.
695
723
  */
696
724
  function buildGenerics(node, tsResolver) {
697
- const responseName = tsResolver.resolveResponseName(node);
698
- const requestName = node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : void 0;
725
+ const successNames = resolveSuccessNames(node, tsResolver);
726
+ const responseName = successNames.length > 0 ? successNames.join(" | ") : tsResolver.resolveResponseName(node);
727
+ const requestName = node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : null;
699
728
  const errorNames = node.responses.filter((r) => Number.parseInt(r.statusCode, 10) >= 400).map((r) => tsResolver.resolveResponseStatusName(node, r.statusCode));
700
729
  return [
701
730
  responseName,
@@ -709,19 +738,19 @@ function buildGenerics(node, tsResolver) {
709
738
  */
710
739
  function buildClassClientParams({ node, path, baseURL, tsResolver, isFormData, isMultipleContentTypes, hasFormData, headers }) {
711
740
  const { query: queryParams } = getOperationParameters(node);
712
- const queryParamsName = queryParams.length > 0 ? tsResolver.resolveQueryParamsName(node, queryParams[0]) : void 0;
713
- const requestName = node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : void 0;
741
+ const queryParamsName = queryParams.length > 0 ? tsResolver.resolveQueryParamsName(node, queryParams[0]) : null;
742
+ const requestName = node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : null;
714
743
  return createFunctionParams({ config: {
715
744
  mode: "object",
716
745
  children: {
717
746
  requestConfig: { mode: "inlineSpread" },
718
747
  method: { value: JSON.stringify(node.method.toUpperCase()) },
719
748
  url: { value: path.template },
720
- baseURL: baseURL ? { value: JSON.stringify(baseURL) } : void 0,
721
- params: queryParamsName ? {} : void 0,
722
- data: requestName ? { value: isMultipleContentTypes && hasFormData ? "contentType === 'multipart/form-data' ? formData as FormData : requestData" : isFormData ? "formData as FormData" : "requestData" } : void 0,
723
- contentType: isMultipleContentTypes ? {} : void 0,
724
- headers: headers.length ? { value: `{ ${headers.join(", ")}, ...requestConfig.headers }` } : void 0
749
+ baseURL: baseURL ? { value: JSON.stringify(baseURL) } : null,
750
+ params: queryParamsName ? {} : null,
751
+ data: requestName ? { value: isMultipleContentTypes && hasFormData ? "contentType === 'multipart/form-data' ? formData as FormData : requestData" : isFormData ? "formData as FormData" : "requestData" } : null,
752
+ contentType: isMultipleContentTypes ? {} : null,
753
+ headers: headers.length ? { value: `{ ${headers.join(", ")}, ...requestConfig.headers }` } : null
725
754
  }
726
755
  } });
727
756
  }
@@ -730,7 +759,7 @@ function buildClassClientParams({ node, path, baseURL, tsResolver, isFormData, i
730
759
  * Applies Zod validation if configured, otherwise uses data directly.
731
760
  */
732
761
  function buildRequestDataLine({ parser, node, zodResolver }) {
733
- const zodRequestName = zodResolver && parser === "zod" && node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : void 0;
762
+ const zodRequestName = zodResolver && parser === "zod" && node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : null;
734
763
  if (parser === "zod" && zodRequestName) return `const requestData = ${zodRequestName}.parse(data)`;
735
764
  if (node.requestBody?.content?.[0]?.schema) return "const requestData = data";
736
765
  return "";
@@ -747,7 +776,7 @@ function buildFormDataLine(isFormData, hasRequest) {
747
776
  * Applies Zod validation to response data if configured, otherwise returns raw response.
748
777
  */
749
778
  function buildReturnStatement({ dataReturnType, parser, node, zodResolver }) {
750
- const zodResponseName = zodResolver && parser === "zod" ? zodResolver.resolveResponseName?.(node) : void 0;
779
+ const zodResponseName = zodResolver && parser === "zod" ? zodResolver.resolveResponseName?.(node) : null;
751
780
  if (dataReturnType === "full" && parser === "zod" && zodResponseName) return `return {...res, data: ${zodResponseName}.parse(res.data)}`;
752
781
  if (dataReturnType === "data" && parser === "zod" && zodResponseName) return `return ${zodResponseName}.parse(res.data)`;
753
782
  if (dataReturnType === "full" && parser === "client") return "return res";
@@ -761,7 +790,7 @@ function generateMethod$1({ node, name, tsResolver, zodResolver, baseURL, dataRe
761
790
  const { defaultContentType: contentType, isMultipleContentTypes, hasFormData } = getContentTypeInfo(node);
762
791
  const isFormData = !isMultipleContentTypes && contentType === "multipart/form-data";
763
792
  const { header: headerParams } = getOperationParameters(node);
764
- const headerParamsName = headerParams.length > 0 ? tsResolver.resolveHeaderParamsName(node, headerParams[0]) : void 0;
793
+ const headerParamsName = headerParams.length > 0 ? tsResolver.resolveHeaderParamsName(node, headerParams[0]) : null;
765
794
  const headers = isMultipleContentTypes ? headerParamsName ? ["...headers"] : [] : buildHeaders(contentType, !!headerParamsName);
766
795
  const generics = buildGenerics(node, tsResolver);
767
796
  const paramsNode = buildClientParamsNode({
@@ -862,9 +891,14 @@ function resolveTypeImportNames$1(node, tsResolver) {
862
891
  }
863
892
  require_chunk.__name(resolveTypeImportNames$1, "resolveTypeImportNames");
864
893
  function resolveZodImportNames$1(node, zodResolver) {
865
- return [zodResolver.resolveResponseName?.(node), node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : void 0].filter((n) => Boolean(n));
894
+ return [zodResolver.resolveResponseName?.(node), node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : null].filter((n) => Boolean(n));
866
895
  }
867
896
  require_chunk.__name(resolveZodImportNames$1, "resolveZodImportNames");
897
+ /**
898
+ * Built-in `operations` generator for `@kubb/plugin-client` when
899
+ * `clientType: 'class'`. Emits one class per tag, with one instance method
900
+ * per operation and a shared constructor for request configuration.
901
+ */
868
902
  const classClientGenerator = (0, _kubb_core.defineGenerator)({
869
903
  name: "classClient",
870
904
  renderer: _kubb_renderer_jsx.jsxRendererSync,
@@ -876,8 +910,8 @@ const classClientGenerator = (0, _kubb_core.defineGenerator)({
876
910
  if (!pluginTs) return null;
877
911
  const tsResolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
878
912
  const tsPluginOptions = pluginTs.options;
879
- const pluginZod = parser === "zod" ? driver.getPlugin(_kubb_plugin_zod.pluginZodName) : void 0;
880
- const zodResolver = pluginZod ? driver.getResolver(_kubb_plugin_zod.pluginZodName) : void 0;
913
+ const pluginZod = parser === "zod" ? driver.getPlugin(_kubb_plugin_zod.pluginZodName) : null;
914
+ const zodResolver = pluginZod ? driver.getResolver(_kubb_plugin_zod.pluginZodName) : null;
881
915
  function buildOperationData(node) {
882
916
  const typeFile = tsResolver.resolveFile({
883
917
  name: node.operationId,
@@ -897,8 +931,8 @@ const classClientGenerator = (0, _kubb_core.defineGenerator)({
897
931
  }, {
898
932
  root,
899
933
  output: pluginZod.options?.output ?? output,
900
- group: pluginZod.options?.group
901
- }) : void 0;
934
+ group: pluginZod.options?.group ?? void 0
935
+ }) : null;
902
936
  return {
903
937
  node,
904
938
  name: resolver.resolveName(node.operationId),
@@ -919,7 +953,7 @@ const classClientGenerator = (0, _kubb_core.defineGenerator)({
919
953
  }, {
920
954
  root,
921
955
  output,
922
- group
956
+ group: group ?? void 0
923
957
  });
924
958
  const operationData = buildOperationData(operationNode);
925
959
  const previous = acc.find((item) => item.file.path === file.path);
@@ -941,7 +975,7 @@ const classClientGenerator = (0, _kubb_core.defineGenerator)({
941
975
  }, {
942
976
  root,
943
977
  output,
944
- group
978
+ group: group ?? void 0
945
979
  });
946
980
  const operationData = buildOperationData(operationNode);
947
981
  const previous = acc.find((item) => item.file.path === file.path);
@@ -1098,7 +1132,7 @@ const classClientGenerator = (0, _kubb_core.defineGenerator)({
1098
1132
  }, {
1099
1133
  root,
1100
1134
  output,
1101
- group
1135
+ group: group ?? void 0
1102
1136
  });
1103
1137
  files.push(/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.File, {
1104
1138
  baseName: sdkFile.baseName,
@@ -1143,6 +1177,11 @@ const classClientGenerator = (0, _kubb_core.defineGenerator)({
1143
1177
  });
1144
1178
  //#endregion
1145
1179
  //#region src/generators/clientGenerator.tsx
1180
+ /**
1181
+ * Built-in operation generator for `@kubb/plugin-client`. Emits one async
1182
+ * function per OpenAPI operation, plus the matching URL helper. Used when
1183
+ * `clientType: 'function'` (the default).
1184
+ */
1146
1185
  const clientGenerator = (0, _kubb_core.defineGenerator)({
1147
1186
  name: "client",
1148
1187
  renderer: _kubb_renderer_jsx.jsxRendererSync,
@@ -1153,10 +1192,10 @@ const clientGenerator = (0, _kubb_core.defineGenerator)({
1153
1192
  const pluginTs = driver.getPlugin(_kubb_plugin_ts.pluginTsName);
1154
1193
  if (!pluginTs) return null;
1155
1194
  const tsResolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
1156
- const pluginZod = parser === "zod" ? driver.getPlugin(_kubb_plugin_zod.pluginZodName) : void 0;
1157
- const zodResolver = pluginZod ? driver.getResolver(_kubb_plugin_zod.pluginZodName) : void 0;
1195
+ const pluginZod = parser === "zod" ? driver.getPlugin(_kubb_plugin_zod.pluginZodName) : null;
1196
+ const zodResolver = pluginZod ? driver.getResolver(_kubb_plugin_zod.pluginZodName) : null;
1158
1197
  const importedTypeNames = resolveOperationTypeNames(node, tsResolver, { paramsCasing });
1159
- const importedZodNames = zodResolver && parser === "zod" ? [zodResolver.resolveResponseName?.(node), node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : void 0].filter((name) => Boolean(name)) : [];
1198
+ const importedZodNames = zodResolver && parser === "zod" ? [zodResolver.resolveResponseName?.(node), node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : null].filter((name) => Boolean(name)) : [];
1160
1199
  const meta = {
1161
1200
  name: resolver.resolveName(node.operationId),
1162
1201
  urlName: resolver.resolveUrlName(node),
@@ -1168,7 +1207,7 @@ const clientGenerator = (0, _kubb_core.defineGenerator)({
1168
1207
  }, {
1169
1208
  root,
1170
1209
  output,
1171
- group
1210
+ group: group ?? void 0
1172
1211
  }),
1173
1212
  fileTs: tsResolver.resolveFile({
1174
1213
  name: node.operationId,
@@ -1178,7 +1217,7 @@ const clientGenerator = (0, _kubb_core.defineGenerator)({
1178
1217
  }, {
1179
1218
  root,
1180
1219
  output: pluginTs.options?.output ?? output,
1181
- group: pluginTs.options?.group
1220
+ group: pluginTs.options?.group ?? void 0
1182
1221
  }),
1183
1222
  fileZod: zodResolver && pluginZod?.options ? zodResolver.resolveFile({
1184
1223
  name: node.operationId,
@@ -1188,8 +1227,8 @@ const clientGenerator = (0, _kubb_core.defineGenerator)({
1188
1227
  }, {
1189
1228
  root,
1190
1229
  output: pluginZod.options.output ?? output,
1191
- group: pluginZod.options?.group
1192
- }) : void 0
1230
+ group: pluginZod.options?.group ?? void 0
1231
+ }) : null
1193
1232
  };
1194
1233
  const hasFormData = node.requestBody?.content?.some((e) => e.contentType === "multipart/form-data") ?? false;
1195
1234
  return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.File, {
@@ -1276,6 +1315,12 @@ const clientGenerator = (0, _kubb_core.defineGenerator)({
1276
1315
  });
1277
1316
  //#endregion
1278
1317
  //#region src/generators/groupedClientGenerator.tsx
1318
+ /**
1319
+ * Emits one aggregate file per tag/group when `group` is configured. Each
1320
+ * file re-exports every client function for that group, so callers can
1321
+ * `import { petController } from './gen/clients'` instead of importing
1322
+ * each operation individually.
1323
+ */
1279
1324
  const groupedClientGenerator = (0, _kubb_core.defineGenerator)({
1280
1325
  name: "groupedClient",
1281
1326
  renderer: _kubb_renderer_jsx.jsxRendererSync,
@@ -1285,7 +1330,7 @@ const groupedClientGenerator = (0, _kubb_core.defineGenerator)({
1285
1330
  return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: nodes.reduce((acc, operationNode) => {
1286
1331
  if (group?.type === "tag") {
1287
1332
  const tag = operationNode.tags[0];
1288
- const name = tag ? group?.name?.({ group: camelCase(tag) }) : void 0;
1333
+ const name = tag ? group?.name?.({ group: camelCase(tag) }) : null;
1289
1334
  if (!tag || !name) return acc;
1290
1335
  const file = resolver.resolveFile({
1291
1336
  name,
@@ -1294,7 +1339,7 @@ const groupedClientGenerator = (0, _kubb_core.defineGenerator)({
1294
1339
  }, {
1295
1340
  root,
1296
1341
  output,
1297
- group
1342
+ group: group ?? void 0
1298
1343
  });
1299
1344
  const clientFile = resolver.resolveFile({
1300
1345
  name: operationNode.operationId,
@@ -1304,7 +1349,7 @@ const groupedClientGenerator = (0, _kubb_core.defineGenerator)({
1304
1349
  }, {
1305
1350
  root,
1306
1351
  output,
1307
- group
1352
+ group: group ?? void 0
1308
1353
  });
1309
1354
  const client = {
1310
1355
  name: resolver.resolveName(operationNode.operationId),
@@ -1373,6 +1418,12 @@ function Operations({ name, nodes }) {
1373
1418
  }
1374
1419
  //#endregion
1375
1420
  //#region src/generators/operationsGenerator.tsx
1421
+ /**
1422
+ * Generates an `operations.ts` file that re-exports every operation grouped
1423
+ * by HTTP method. Enabled when `pluginClient({ operations: true })`. Useful
1424
+ * for building meta-tooling on top of the generated client (route
1425
+ * registries, API explorers).
1426
+ */
1376
1427
  const operationsGenerator = (0, _kubb_core.defineGenerator)({
1377
1428
  name: "client",
1378
1429
  renderer: _kubb_renderer_jsx.jsxRendererSync,
@@ -1386,7 +1437,7 @@ const operationsGenerator = (0, _kubb_core.defineGenerator)({
1386
1437
  }, {
1387
1438
  root,
1388
1439
  output,
1389
- group
1440
+ group: group ?? void 0
1390
1441
  });
1391
1442
  return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File, {
1392
1443
  baseName: file.baseName,
@@ -1415,7 +1466,7 @@ function generateMethod({ node, name, tsResolver, zodResolver, baseURL, dataRetu
1415
1466
  const { defaultContentType: contentType, isMultipleContentTypes, hasFormData } = getContentTypeInfo(node);
1416
1467
  const isFormData = !isMultipleContentTypes && contentType === "multipart/form-data";
1417
1468
  const { header: headerParams } = getOperationParameters(node);
1418
- const headerParamsName = headerParams.length > 0 ? tsResolver.resolveHeaderParamsName(node, headerParams[0]) : void 0;
1469
+ const headerParamsName = headerParams.length > 0 ? tsResolver.resolveHeaderParamsName(node, headerParams[0]) : null;
1419
1470
  const headers = isMultipleContentTypes ? headerParamsName ? ["...headers"] : [] : buildHeaders(contentType, !!headerParamsName);
1420
1471
  const generics = buildGenerics(node, tsResolver);
1421
1472
  const paramsNode = buildClientParamsNode({
@@ -1489,8 +1540,14 @@ function resolveTypeImportNames(node, tsResolver) {
1489
1540
  return resolveOperationTypeNames(node, tsResolver, { order: "body-response-first" });
1490
1541
  }
1491
1542
  function resolveZodImportNames(node, zodResolver) {
1492
- return [zodResolver.resolveResponseName?.(node), node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : void 0].filter((n) => Boolean(n));
1543
+ return [zodResolver.resolveResponseName?.(node), node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : null].filter((n) => Boolean(n));
1493
1544
  }
1545
+ /**
1546
+ * Built-in `operations` generator for `@kubb/plugin-client` when
1547
+ * `clientType: 'staticClass'`. Emits one class per tag, with a static method
1548
+ * per operation so callers can use `Pet.getPetById(...)` without
1549
+ * instantiating the class.
1550
+ */
1494
1551
  const staticClassClientGenerator = (0, _kubb_core.defineGenerator)({
1495
1552
  name: "staticClassClient",
1496
1553
  renderer: _kubb_renderer_jsx.jsxRendererSync,
@@ -1502,8 +1559,8 @@ const staticClassClientGenerator = (0, _kubb_core.defineGenerator)({
1502
1559
  if (!pluginTs) return null;
1503
1560
  const tsResolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
1504
1561
  const tsPluginOptions = pluginTs.options;
1505
- const pluginZod = parser === "zod" ? driver.getPlugin(_kubb_plugin_zod.pluginZodName) : void 0;
1506
- const zodResolver = pluginZod ? driver.getResolver(_kubb_plugin_zod.pluginZodName) : void 0;
1562
+ const pluginZod = parser === "zod" ? driver.getPlugin(_kubb_plugin_zod.pluginZodName) : null;
1563
+ const zodResolver = pluginZod ? driver.getResolver(_kubb_plugin_zod.pluginZodName) : null;
1507
1564
  function buildOperationData(node) {
1508
1565
  const typeFile = tsResolver.resolveFile({
1509
1566
  name: node.operationId,
@@ -1523,8 +1580,8 @@ const staticClassClientGenerator = (0, _kubb_core.defineGenerator)({
1523
1580
  }, {
1524
1581
  root,
1525
1582
  output: pluginZod.options?.output ?? output,
1526
- group: pluginZod.options?.group
1527
- }) : void 0;
1583
+ group: pluginZod.options?.group ?? void 0
1584
+ }) : null;
1528
1585
  return {
1529
1586
  node,
1530
1587
  name: resolver.resolveName(node.operationId),
@@ -1545,7 +1602,7 @@ const staticClassClientGenerator = (0, _kubb_core.defineGenerator)({
1545
1602
  }, {
1546
1603
  root,
1547
1604
  output,
1548
- group
1605
+ group: group ?? void 0
1549
1606
  });
1550
1607
  const operationData = buildOperationData(operationNode);
1551
1608
  const previous = acc.find((item) => item.file.path === file.path);
@@ -1566,7 +1623,7 @@ const staticClassClientGenerator = (0, _kubb_core.defineGenerator)({
1566
1623
  }, {
1567
1624
  root,
1568
1625
  output,
1569
- group
1626
+ group: group ?? void 0
1570
1627
  });
1571
1628
  const operationData = buildOperationData(operationNode);
1572
1629
  const previous = acc.find((item) => item.file.path === file.path);
@@ -1720,18 +1777,25 @@ const staticClassClientGenerator = (0, _kubb_core.defineGenerator)({
1720
1777
  //#endregion
1721
1778
  //#region src/resolvers/resolverClient.ts
1722
1779
  /**
1723
- * Naming convention resolver for client plugin.
1780
+ * Default resolver used by `@kubb/plugin-client`. Decides the names and file
1781
+ * paths for every generated client function or class. Functions and files use
1782
+ * camelCase; classes and tag groups use PascalCase.
1724
1783
  *
1725
- * Provides default naming helpers using camelCase for functions and file paths.
1784
+ * @example Resolve client function and class names
1785
+ * ```ts
1786
+ * import { resolverClient } from '@kubb/plugin-client'
1726
1787
  *
1727
- * @example
1728
- * `resolverClient.default('list pets', 'function') // 'listPets'`
1788
+ * resolverClient.default('list pets', 'function') // 'listPets'
1789
+ * resolverClient.resolveClassName('pet') // 'Pet'
1790
+ * resolverClient.resolveUrlName(operationNode) // 'getShowPetByIdUrl'
1791
+ * ```
1729
1792
  */
1730
1793
  const resolverClient = (0, _kubb_core.defineResolver)(() => ({
1731
1794
  name: "default",
1732
1795
  pluginName: "plugin-client",
1733
1796
  default(name, type) {
1734
- return camelCase(name, { isFile: type === "file" });
1797
+ const resolved = camelCase(name, { isFile: type === "file" });
1798
+ return type === "file" ? resolved : ensureValidVarName(resolved);
1735
1799
  },
1736
1800
  resolveName(name) {
1737
1801
  return this.default(name, "function");
@@ -1740,13 +1804,13 @@ const resolverClient = (0, _kubb_core.defineResolver)(() => ({
1740
1804
  return this.default(name, type);
1741
1805
  },
1742
1806
  resolveClassName(name) {
1743
- return pascalCase(name);
1807
+ return ensureValidVarName(pascalCase(name));
1744
1808
  },
1745
1809
  resolveGroupName(name) {
1746
- return pascalCase(name);
1810
+ return ensureValidVarName(pascalCase(name));
1747
1811
  },
1748
1812
  resolveClientPropertyName(name) {
1749
- return camelCase(name);
1813
+ return ensureValidVarName(camelCase(name));
1750
1814
  },
1751
1815
  resolveUrlName(node) {
1752
1816
  const name = this.resolveName(node.operationId);
@@ -1756,19 +1820,32 @@ const resolverClient = (0, _kubb_core.defineResolver)(() => ({
1756
1820
  //#endregion
1757
1821
  //#region src/plugin.ts
1758
1822
  /**
1759
- * Canonical plugin name for `@kubb/plugin-client`, used in driver lookups and warnings.
1823
+ * Canonical plugin name for `@kubb/plugin-client`. Used for driver lookups and
1824
+ * cross-plugin dependency references.
1760
1825
  */
1761
1826
  const pluginClientName = "plugin-client";
1762
1827
  /**
1763
- * Generates type-safe HTTP client functions or classes from an OpenAPI specification.
1764
- * Creates client APIs by walking operations and delegating to generators.
1765
- * Writes barrel files based on the configured `barrelType`.
1828
+ * Generates one HTTP client function per OpenAPI operation. Each function has
1829
+ * typed path params, query params, body, and response, so callers use the API
1830
+ * like any other typed function. Ships with `axios` and `fetch` runtimes; bring
1831
+ * your own by setting `importPath`.
1766
1832
  *
1767
- * @example Client generator
1833
+ * @example
1768
1834
  * ```ts
1769
- * import pluginClient from '@kubb/plugin-client'
1835
+ * import { defineConfig } from 'kubb'
1836
+ * import { pluginTs } from '@kubb/plugin-ts'
1837
+ * import { pluginClient } from '@kubb/plugin-client'
1838
+ *
1770
1839
  * export default defineConfig({
1771
- * plugins: [pluginClient({ output: { path: 'clients' } })]
1840
+ * input: { path: './petStore.yaml' },
1841
+ * output: { path: './src/gen' },
1842
+ * plugins: [
1843
+ * pluginTs(),
1844
+ * pluginClient({
1845
+ * output: { path: './clients' },
1846
+ * client: 'fetch',
1847
+ * }),
1848
+ * ],
1772
1849
  * })
1773
1850
  * ```
1774
1851
  */
@@ -1780,8 +1857,8 @@ const pluginClient = (0, _kubb_core.definePlugin)((options) => {
1780
1857
  const resolvedImportPath = importPath ?? (!bundle ? `@kubb/plugin-client/clients/${client}` : void 0);
1781
1858
  const selectedGenerators = options.generators ?? [
1782
1859
  clientType === "staticClass" ? staticClassClientGenerator : clientType === "class" ? classClientGenerator : clientGenerator,
1783
- group && clientType === "function" ? groupedClientGenerator : void 0,
1784
- operations ? operationsGenerator : void 0
1860
+ group && clientType === "function" ? groupedClientGenerator : null,
1861
+ operations ? operationsGenerator : null
1785
1862
  ].filter((x) => Boolean(x));
1786
1863
  const groupConfig = group ? {
1787
1864
  ...group,
@@ -1789,11 +1866,11 @@ const pluginClient = (0, _kubb_core.definePlugin)((options) => {
1789
1866
  if (group.type === "path") return `${ctx.group.split("/")[1]}`;
1790
1867
  return `${camelCase(ctx.group)}Controller`;
1791
1868
  }
1792
- } : void 0;
1869
+ } : null;
1793
1870
  return {
1794
1871
  name: pluginClientName,
1795
1872
  options,
1796
- dependencies: [_kubb_plugin_ts.pluginTsName, parser === "zod" ? _kubb_plugin_zod.pluginZodName : void 0].filter((dependency) => Boolean(dependency)),
1873
+ dependencies: [_kubb_plugin_ts.pluginTsName, parser === "zod" ? _kubb_plugin_zod.pluginZodName : null].filter((dependency) => Boolean(dependency)),
1797
1874
  hooks: { "kubb:plugin:setup"(ctx) {
1798
1875
  const resolver = userResolver ? {
1799
1876
  ...resolverClient,