@kubb/plugin-fetch 5.0.0-beta.73

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 ADDED
@@ -0,0 +1,1260 @@
1
+ Object.defineProperties(exports, {
2
+ __esModule: { value: true },
3
+ [Symbol.toStringTag]: { value: "Module" }
4
+ });
5
+ //#region \0rolldown/runtime.js
6
+ var __create = Object.create;
7
+ var __defProp = Object.defineProperty;
8
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
9
+ var __getOwnPropNames = Object.getOwnPropertyNames;
10
+ var __getProtoOf = Object.getPrototypeOf;
11
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
14
+ key = keys[i];
15
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
16
+ get: ((k) => from[k]).bind(null, key),
17
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
18
+ });
19
+ }
20
+ return to;
21
+ };
22
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
23
+ value: mod,
24
+ enumerable: true
25
+ }) : target, mod));
26
+ //#endregion
27
+ let node_path = require("node:path");
28
+ node_path = __toESM(node_path, 1);
29
+ let _kubb_core = require("@kubb/core");
30
+ let _kubb_renderer_jsx = require("@kubb/renderer-jsx");
31
+ let _kubb_plugin_ts = require("@kubb/plugin-ts");
32
+ let _kubb_renderer_jsx_jsx_runtime = require("@kubb/renderer-jsx/jsx-runtime");
33
+ let _kubb_plugin_zod = require("@kubb/plugin-zod");
34
+ let _kubb_ast_utils = require("@kubb/ast/utils");
35
+ let _kubb_ast_macros = require("@kubb/ast/macros");
36
+ let node_url = require("node:url");
37
+ //#region ../../internals/client/src/builders/parser.ts
38
+ /**
39
+ * Returns `true` when any direction of the parser uses zod (used for dependency checks).
40
+ */
41
+ function isParserEnabled(parser) {
42
+ if (!parser) return false;
43
+ if (parser === "zod") return true;
44
+ return Boolean(parser.request || parser.response);
45
+ }
46
+ /**
47
+ * Returns `'zod'` when request body parsing is enabled, `null` otherwise. The string shorthand
48
+ * `'zod'` validates the response only, so it does not enable request parsing.
49
+ */
50
+ function resolveRequestParser(parser) {
51
+ if (!parser || parser === "zod") return null;
52
+ return parser.request ?? null;
53
+ }
54
+ /**
55
+ * Returns `'zod'` when query-parameters parsing is enabled, `null` otherwise. Only the object form
56
+ * `{ request: 'zod' }` enables it.
57
+ */
58
+ function resolveQueryParamsParser(parser) {
59
+ if (!parser || parser === "zod") return null;
60
+ return parser.request ?? null;
61
+ }
62
+ /**
63
+ * Returns `'zod'` when response parsing is enabled, `null` otherwise. The string shorthand `'zod'`
64
+ * maps to response parsing.
65
+ */
66
+ function resolveResponseParser(parser) {
67
+ if (!parser) return null;
68
+ if (parser === "zod") return "zod";
69
+ return parser.response ?? null;
70
+ }
71
+ /**
72
+ * Resolves the zod expression a generated client validates a success response with. Only success
73
+ * (2xx) bodies reach the parse under the throw-on-error contract, so the success-only
74
+ * `<operation>ResponseSchema` is used; error bodies are never zod-parsed.
75
+ */
76
+ function buildZodResponseParse(node, zodResolver) {
77
+ const name = zodResolver.resolveResponseName?.(node);
78
+ return name ? {
79
+ expression: name,
80
+ importNames: [name]
81
+ } : null;
82
+ }
83
+ //#endregion
84
+ //#region ../../internals/client/src/builders/security.ts
85
+ function serializeAuth(auth) {
86
+ const parts = [`type: '${auth.type}'`];
87
+ if (auth.scheme) parts.push(`scheme: '${auth.scheme}'`);
88
+ if (auth.name) parts.push(`name: '${auth.name}'`);
89
+ if (auth.in) parts.push(`in: '${auth.in}'`);
90
+ return `{ ${parts.join(", ")} }`;
91
+ }
92
+ /**
93
+ * Maps an OpenAPI security scheme to the inline `Auth` object, or `null` when the runtime cannot
94
+ * place it (an unresolved `$ref`, or an `apiKey` without a name or outside `header` / `query` /
95
+ * `cookie`). `http` schemes other than `basic` are treated as bearer.
96
+ */
97
+ function resolveSecurityScheme(scheme) {
98
+ if (!scheme || "$ref" in scheme) return null;
99
+ if (scheme.type === "apiKey") {
100
+ if (!scheme.name || scheme.in !== "header" && scheme.in !== "query" && scheme.in !== "cookie") return null;
101
+ return {
102
+ type: "apiKey",
103
+ name: scheme.name,
104
+ in: scheme.in
105
+ };
106
+ }
107
+ if (scheme.type === "http") return {
108
+ type: "http",
109
+ scheme: scheme.scheme?.toLowerCase() === "basic" ? "basic" : "bearer"
110
+ };
111
+ if (scheme.type === "oauth2") return { type: "oauth2" };
112
+ if (scheme.type === "openIdConnect") return { type: "openIdConnect" };
113
+ return null;
114
+ }
115
+ /**
116
+ * Derives the per-operation security metadata from the OpenAPI document. The operation's own
117
+ * `security` overrides the global `security` (an explicit empty array disables auth), and every
118
+ * referenced scheme is resolved from `components.securitySchemes` into a flat, de-duplicated list of
119
+ * `Auth` objects the runtime walks in order.
120
+ *
121
+ * @example
122
+ * `getOperationSecurity({ document, method: 'POST', path: '/pet' })`
123
+ * `// [{ type: 'http', scheme: 'bearer' }]`
124
+ */
125
+ function getOperationSecurity({ document, method, path }) {
126
+ if (!document) return void 0;
127
+ const requirements = (document.paths?.[path]?.[method.toLowerCase()])?.security ?? document.security;
128
+ if (!requirements?.length) return void 0;
129
+ const definitions = document.components?.securitySchemes ?? {};
130
+ const security = [];
131
+ const seen = /* @__PURE__ */ new Set();
132
+ for (const requirement of requirements) for (const schemeName of Object.keys(requirement)) {
133
+ if (seen.has(schemeName)) continue;
134
+ seen.add(schemeName);
135
+ const auth = resolveSecurityScheme(definitions[schemeName]);
136
+ if (auth) security.push(auth);
137
+ }
138
+ return security.length ? security : void 0;
139
+ }
140
+ /**
141
+ * Serializes the per-operation security into the literal emitted on each generated call's `security`
142
+ * field. The runtime `resolveAuth` helper walks it, calling the configured `auth` resolver per entry.
143
+ *
144
+ * @example
145
+ * `buildSecurityMetadata({ security: [{ type: 'http', scheme: 'bearer' }] }) // "[{ type: 'http', scheme: 'bearer' }]"`
146
+ */
147
+ function buildSecurityMetadata({ security }) {
148
+ if (!security?.length) return null;
149
+ return `[${security.map(serializeAuth).join(", ")}]`;
150
+ }
151
+ //#endregion
152
+ //#region ../../internals/utils/src/casing.ts
153
+ /**
154
+ * Shared implementation for camelCase and PascalCase conversion.
155
+ * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)
156
+ * and capitalizes each word according to `pascal`.
157
+ *
158
+ * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
159
+ */
160
+ function toCamelOrPascal(text, pascal) {
161
+ 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) => {
162
+ if (word.length > 1 && word === word.toUpperCase()) return word;
163
+ return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
164
+ }).join("").replace(/[^a-zA-Z0-9]/g, "");
165
+ }
166
+ /**
167
+ * Converts `text` to camelCase.
168
+ *
169
+ * @example Word boundaries
170
+ * `camelCase('hello-world') // 'helloWorld'`
171
+ *
172
+ * @example With a prefix
173
+ * `camelCase('tag', { prefix: 'create' }) // 'createTag'`
174
+ */
175
+ function camelCase(text, { prefix = "", suffix = "" } = {}) {
176
+ return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
177
+ }
178
+ /**
179
+ * Converts `text` to PascalCase.
180
+ *
181
+ * @example Word boundaries
182
+ * `pascalCase('hello-world') // 'HelloWorld'`
183
+ *
184
+ * @example With a suffix
185
+ * `pascalCase('tag', { suffix: 'schema' }) // 'TagSchema'`
186
+ */
187
+ function pascalCase(text, { prefix = "", suffix = "" } = {}) {
188
+ return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true);
189
+ }
190
+ //#endregion
191
+ //#region ../../internals/utils/src/fs.ts
192
+ /**
193
+ * Builds a nested file path from a dotted name. Splits on dots that precede a letter
194
+ * (so version numbers embedded in operationIds like `v2025.0` stay intact), camelCases
195
+ * every earlier segment, applies `caseLast` to the final segment, and joins with `/`.
196
+ *
197
+ * Empty segments are dropped before joining. They arise when the name starts with a dot
198
+ * followed by a letter (e.g. `..Schema` splits into `['..', 'Schema']` and `'..'` cases to
199
+ * an empty string). Without this a leading `/` would form, which `path.resolve` reads as an
200
+ * absolute path, letting generated files escape the configured output directory.
201
+ *
202
+ * @example Nested path from a dotted name
203
+ * `toFilePath('pet.petId') // 'pet/petId'`
204
+ *
205
+ * @example PascalCase the final segment
206
+ * `toFilePath('pet.Pet', pascalCase) // 'pet/Pet'`
207
+ *
208
+ * @example Suffix applied to the final segment only
209
+ * `toFilePath('tag.tag', (part) => camelCase(part, { suffix: 'schema' })) // 'tag/tagSchema'`
210
+ */
211
+ function toFilePath(name, caseLast = camelCase) {
212
+ const parts = name.split(/\.(?=[a-zA-Z])/);
213
+ return parts.map((part, i) => i === parts.length - 1 ? caseLast(part) : camelCase(part)).filter(Boolean).join("/");
214
+ }
215
+ //#endregion
216
+ //#region ../../internals/utils/src/reserved.ts
217
+ /**
218
+ * JavaScript and Java reserved words.
219
+ * @link https://github.com/jonschlinkert/reserved/blob/master/index.js
220
+ */
221
+ const reservedWords = new Set([
222
+ "abstract",
223
+ "arguments",
224
+ "boolean",
225
+ "break",
226
+ "byte",
227
+ "case",
228
+ "catch",
229
+ "char",
230
+ "class",
231
+ "const",
232
+ "continue",
233
+ "debugger",
234
+ "default",
235
+ "delete",
236
+ "do",
237
+ "double",
238
+ "else",
239
+ "enum",
240
+ "eval",
241
+ "export",
242
+ "extends",
243
+ "false",
244
+ "final",
245
+ "finally",
246
+ "float",
247
+ "for",
248
+ "function",
249
+ "goto",
250
+ "if",
251
+ "implements",
252
+ "import",
253
+ "in",
254
+ "instanceof",
255
+ "int",
256
+ "interface",
257
+ "let",
258
+ "long",
259
+ "native",
260
+ "new",
261
+ "null",
262
+ "package",
263
+ "private",
264
+ "protected",
265
+ "public",
266
+ "return",
267
+ "short",
268
+ "static",
269
+ "super",
270
+ "switch",
271
+ "synchronized",
272
+ "this",
273
+ "throw",
274
+ "throws",
275
+ "transient",
276
+ "true",
277
+ "try",
278
+ "typeof",
279
+ "var",
280
+ "void",
281
+ "volatile",
282
+ "while",
283
+ "with",
284
+ "yield",
285
+ "Array",
286
+ "Date",
287
+ "hasOwnProperty",
288
+ "Infinity",
289
+ "isFinite",
290
+ "isNaN",
291
+ "isPrototypeOf",
292
+ "length",
293
+ "Math",
294
+ "name",
295
+ "NaN",
296
+ "Number",
297
+ "Object",
298
+ "prototype",
299
+ "String",
300
+ "toString",
301
+ "undefined",
302
+ "valueOf"
303
+ ]);
304
+ /**
305
+ * Returns `true` when `name` is a syntactically valid JavaScript variable name.
306
+ *
307
+ * @example
308
+ * ```ts
309
+ * isValidVarName('status') // true
310
+ * isValidVarName('class') // false (reserved word)
311
+ * isValidVarName('42foo') // false (starts with digit)
312
+ * ```
313
+ */
314
+ function isValidVarName(name) {
315
+ if (!name || reservedWords.has(name)) return false;
316
+ return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
317
+ }
318
+ /**
319
+ * Returns `name` when it's a syntactically valid JavaScript variable name,
320
+ * otherwise prefixes it with `_` so the result is a valid identifier.
321
+ *
322
+ * Useful for sanitizing OpenAPI schema names or operation IDs that start with
323
+ * a digit (e.g. `409`, `504AccountCancel`) before using them as exported
324
+ * variable, type, or function names.
325
+ *
326
+ * @example
327
+ * ```ts
328
+ * ensureValidVarName('409') // '_409'
329
+ * ensureValidVarName('504AccountCancel') // '_504AccountCancel'
330
+ * ensureValidVarName('Pet') // 'Pet'
331
+ * ensureValidVarName('class') // '_class'
332
+ * ```
333
+ */
334
+ function ensureValidVarName(name) {
335
+ if (!name || isValidVarName(name)) return name;
336
+ return `_${name}`;
337
+ }
338
+ //#endregion
339
+ //#region ../../internals/utils/src/url.ts
340
+ function transformParam(raw, casing) {
341
+ const param = isValidVarName(raw) ? raw : camelCase(raw);
342
+ return casing === "camelcase" ? camelCase(param) : param;
343
+ }
344
+ function toParamsObject(path, { replacer, casing } = {}) {
345
+ const params = {};
346
+ for (const match of path.matchAll(/\{([^}]+)\}/g)) {
347
+ const param = transformParam(match[1], casing);
348
+ const key = replacer ? replacer(param) : param;
349
+ params[key] = key;
350
+ }
351
+ return Object.keys(params).length > 0 ? params : null;
352
+ }
353
+ /**
354
+ * Helpers for OpenAPI/Swagger paths, plus a thin wrapper over the native `URL`.
355
+ */
356
+ var Url = class Url {
357
+ /**
358
+ * Reports whether `url` is a parseable absolute URL. Delegates to the native `URL.canParse`.
359
+ *
360
+ * @example
361
+ * Url.canParse('https://petstore.swagger.io/v2') // true
362
+ * Url.canParse('/pet/{petId}') // false
363
+ */
364
+ static canParse(url, base) {
365
+ return URL.canParse(url, base);
366
+ }
367
+ /**
368
+ * Converts an OpenAPI/Swagger path to Express-style colon syntax.
369
+ *
370
+ * @example
371
+ * Url.toPath('/pet/{petId}') // '/pet/:petId'
372
+ */
373
+ static toPath(path) {
374
+ return path.replace(/\{([^}]+)\}/g, ":$1");
375
+ }
376
+ /**
377
+ * Converts an OpenAPI/Swagger path to a TypeScript template literal string.
378
+ * `prefix` is prepended inside the literal, `replacer` transforms each parameter name,
379
+ * and `casing` controls parameter identifier casing.
380
+ *
381
+ * @example
382
+ * Url.toTemplateString('/pet/{petId}') // '`/pet/${petId}`'
383
+ *
384
+ * @example
385
+ * Url.toTemplateString('/pet/{petId}', { prefix: 'https://api' }) // '`https://api/pet/${petId}`'
386
+ */
387
+ static toTemplateString(path, { prefix, replacer, casing } = {}) {
388
+ const result = path.split(/\{([^}]+)\}/).map((part, i) => {
389
+ if (i % 2 === 0) return part;
390
+ const param = transformParam(part, casing);
391
+ return `\${${replacer ? replacer(param) : param}}`;
392
+ }).join("");
393
+ return `\`${prefix ?? ""}${result}\``;
394
+ }
395
+ /**
396
+ * Converts an OpenAPI/Swagger path to a template literal that reads each parameter off the
397
+ * grouped `path` request option, e.g. `/pet/{petId}` becomes `` `/pet/${path.petId}` ``. Parameter
398
+ * names are camelCased to match the generated `path` type, and `prefix` is prepended inside the
399
+ * literal. Shared by the client and cypress generators that pass a grouped `path` object.
400
+ *
401
+ * @example
402
+ * Url.toGroupedTemplateString('/pet/{petId}') // '`/pet/${path.petId}`'
403
+ */
404
+ static toGroupedTemplateString(path, { prefix } = {}) {
405
+ return Url.toTemplateString(path, {
406
+ prefix,
407
+ casing: "camelcase",
408
+ replacer: (name) => `path.${name}`
409
+ });
410
+ }
411
+ /**
412
+ * Returns the path and its extracted params as a structured `URLObject`, or as a stringified
413
+ * expression when `stringify` is set.
414
+ *
415
+ * @example
416
+ * Url.toObject('/pet/{petId}')
417
+ * // { url: '/pet/:petId', params: { petId: 'petId' } }
418
+ */
419
+ static toObject(path, { type = "path", replacer, stringify, casing } = {}) {
420
+ const object = {
421
+ url: type === "path" ? Url.toPath(path) : Url.toTemplateString(path, {
422
+ replacer,
423
+ casing
424
+ }),
425
+ params: toParamsObject(path, {
426
+ replacer,
427
+ casing
428
+ })
429
+ };
430
+ if (stringify) {
431
+ if (type === "template") return JSON.stringify(object).replaceAll("'", "").replaceAll(`"`, "");
432
+ if (object.params) return `{ url: '${object.url}', params: ${JSON.stringify(object.params).replaceAll("'", "").replaceAll(`"`, "")} }`;
433
+ return `{ url: '${object.url}' }`;
434
+ }
435
+ return object;
436
+ }
437
+ };
438
+ //#endregion
439
+ //#region ../../internals/shared/src/params.ts
440
+ const caseParamsCache = /* @__PURE__ */ new WeakMap();
441
+ /**
442
+ * Applies camelCase to parameter names and returns a new array without mutating the input.
443
+ *
444
+ * Run it before handing parameters to schema builders so output property keys get the right casing
445
+ * while `OperationNode.parameters` stays intact for other consumers. When `casing` is unset, the
446
+ * original array is returned unchanged. Results are cached per input array.
447
+ */
448
+ function caseParams(params, casing) {
449
+ if (!casing) return params;
450
+ const cached = caseParamsCache.get(params);
451
+ if (cached) return cached;
452
+ const result = params.map((param) => ({
453
+ ...param,
454
+ name: camelCase(param.name)
455
+ }));
456
+ caseParamsCache.set(params, result);
457
+ return result;
458
+ }
459
+ //#endregion
460
+ //#region ../../internals/shared/src/operation.ts
461
+ /**
462
+ * Builds the `ResolverFileParams` every operation generator passes to
463
+ * `resolver.resolveFile`: a file named `name`, tagged by the operation's first
464
+ * tag (or `'default'`), at the operation's path. Centralizes the entry object
465
+ * that was repeated at dozens of call sites across the client and query plugins.
466
+ *
467
+ * @example
468
+ * ```ts
469
+ * resolver.resolveFile(operationFileEntry(node, node.operationId), { root, output, group })
470
+ * ```
471
+ */
472
+ function operationFileEntry(node, name, extname = ".ts") {
473
+ return {
474
+ name,
475
+ extname,
476
+ tag: node.tags[0] ?? "default",
477
+ path: node.path
478
+ };
479
+ }
480
+ function getOperationLink(node, link) {
481
+ if (!link) return null;
482
+ if (typeof link === "function") return link(node) ?? null;
483
+ if (link === "urlPath") return node.path ? `{@link ${Url.toPath(node.path)}}` : null;
484
+ return node.path ? `{@link ${node.path.replaceAll("{", ":").replaceAll("}", "")}}` : null;
485
+ }
486
+ function buildOperationComments(node, options = {}) {
487
+ const { link = "pathTemplate", linkPosition = "afterDeprecated", splitLines = false } = options;
488
+ const linkComment = getOperationLink(node, link);
489
+ const filteredComments = (linkPosition === "beforeDeprecated" ? [
490
+ node.description && `@description ${node.description}`,
491
+ node.summary && `@summary ${node.summary}`,
492
+ linkComment,
493
+ node.deprecated && "@deprecated"
494
+ ] : [
495
+ node.description && `@description ${node.description}`,
496
+ node.summary && `@summary ${node.summary}`,
497
+ node.deprecated && "@deprecated",
498
+ linkComment
499
+ ]).filter((comment) => Boolean(comment));
500
+ if (!splitLines) return filteredComments;
501
+ return filteredComments.flatMap((text) => text.split(/\r?\n/).map((line) => line.trim())).filter((comment) => Boolean(comment));
502
+ }
503
+ function getOperationParameters(node, options = {}) {
504
+ const params = caseParams(node.parameters, options.paramsCasing === "original" ? void 0 : "camelcase");
505
+ return {
506
+ path: params.filter((param) => param.in === "path"),
507
+ query: params.filter((param) => param.in === "query"),
508
+ header: params.filter((param) => param.in === "header"),
509
+ cookie: params.filter((param) => param.in === "cookie")
510
+ };
511
+ }
512
+ //#endregion
513
+ //#region ../../internals/shared/src/group.ts
514
+ /**
515
+ * Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the
516
+ * shared default naming so every plugin groups output consistently:
517
+ *
518
+ * - `path` groups use the second path segment (`/pet/findByStatus` → `pet`).
519
+ * - other groups use the camelCased group (`pet store` → `petStore`).
520
+ *
521
+ * A user-provided `group.name` always wins over the default namer, so callers stay in
522
+ * control of their output folders. Returns `null` when grouping is disabled, matching the
523
+ * per-plugin convention.
524
+ *
525
+ * @param group - The user-supplied group option, or `undefined` to disable grouping.
526
+ *
527
+ * @example
528
+ * ```ts
529
+ * createGroupConfig(group) // shared across every plugin
530
+ * ```
531
+ */
532
+ function createGroupConfig(group) {
533
+ if (!group) return null;
534
+ const defaultName = (ctx) => {
535
+ if (group.type === "path") return `${ctx.group.split("/")[1]}`;
536
+ return camelCase(ctx.group);
537
+ };
538
+ return {
539
+ ...group,
540
+ name: group.name ? group.name : defaultName
541
+ };
542
+ }
543
+ //#endregion
544
+ //#region ../../internals/client/src/builders/generics.ts
545
+ /**
546
+ * Builds the `RequestResult` generic arguments for one operation: the plugin-ts per-status responses
547
+ * record plus the per-call `ThrowOnError` flag. `SuccessOf` / `ErrorOf` split the record inside the
548
+ * runtime, so this only names the record and threads `ThrowOnError`.
549
+ *
550
+ * @example
551
+ * `buildRequestResultGenerics({ node, tsResolver }) // 'AddPetResponses, ThrowOnError'`
552
+ */
553
+ function buildRequestResultGenerics({ node, tsResolver }) {
554
+ return `${tsResolver.resolveResponsesName(node)}, ThrowOnError`;
555
+ }
556
+ //#endregion
557
+ //#region ../../internals/client/src/builders/returnStatement.ts
558
+ /**
559
+ * Builds the return statement of a generated operation function. The runtime call already resolves
560
+ * to `{ data, error, request, response }`; the generated code forwards that result and casts it to
561
+ * the operation's `RequestResult`, which carries the `throwOnError` discrimination.
562
+ *
563
+ * @example
564
+ * `return request({ method: 'POST', url: '/pet', ...config }) as Promise<RequestResult<AddPetResponses, ThrowOnError>>`
565
+ */
566
+ function buildReturnStatement({ node, tsResolver, callConfig }) {
567
+ return `return request(${callConfig}) as Promise<RequestResult<${buildRequestResultGenerics({
568
+ node,
569
+ tsResolver
570
+ })}>>`;
571
+ }
572
+ //#endregion
573
+ //#region ../../internals/client/src/builders/signature.ts
574
+ const declarationPrinter = (0, _kubb_plugin_ts.functionPrinter)({ mode: "declaration" });
575
+ /**
576
+ * Builds the grouped-options signature for one operation: a single `options` object whose `TData`
577
+ * is the plugin-ts `<Name>RequestConfig` (carrying a literal `url`), and a `RequestResult` return type
578
+ * keyed to the plugin-ts per-status responses record. There are no positional arguments.
579
+ *
580
+ * The generated file imports `<Name>RequestConfig` and `<Name>Responses` and uses them directly, so no
581
+ * per-operation input type has to be emitted.
582
+ */
583
+ function buildGroupedOptionsSignature({ node, tsResolver }) {
584
+ const requestConfigName = tsResolver.resolveRequestConfigName(node);
585
+ const responsesName = tsResolver.resolveResponsesName(node);
586
+ const resultGenerics = buildRequestResultGenerics({
587
+ node,
588
+ tsResolver
589
+ });
590
+ return {
591
+ dataTypeName: requestConfigName,
592
+ paramsSignature: declarationPrinter.print((0, _kubb_plugin_ts.createFunctionParameters)({ params: [(0, _kubb_plugin_ts.createFunctionParameter)({
593
+ name: "options",
594
+ type: `Options<${requestConfigName}, ThrowOnError>`
595
+ })] })) ?? "",
596
+ returnType: `Promise<RequestResult<${resultGenerics}>>`,
597
+ generics: ["ThrowOnError extends boolean = true"],
598
+ importedTypeNames: [requestConfigName, responsesName]
599
+ };
600
+ }
601
+ //#endregion
602
+ //#region ../../internals/client/src/builders/validator.ts
603
+ /**
604
+ * Builds the parser-hook expressions for one operation. Request parsing runs before the send;
605
+ * response parsing runs on the success body only. Returns `null` expressions when the matching
606
+ * parser direction is disabled or the schema is absent.
607
+ */
608
+ function buildParserHooks({ node, parser, zodResolver }) {
609
+ const importedZodNames = [];
610
+ const hasRequestBody = Boolean(node.requestBody?.content?.[0]?.schema);
611
+ const zodRequestName = zodResolver && resolveRequestParser(parser) === "zod" && hasRequestBody ? zodResolver.resolveDataName?.(node) : null;
612
+ const request = zodRequestName ? `(data: unknown) => ${zodRequestName}.parse(data)` : null;
613
+ if (zodRequestName) importedZodNames.push(zodRequestName);
614
+ const responseParse = zodResolver && resolveResponseParser(parser) === "zod" ? buildZodResponseParse(node, zodResolver) : null;
615
+ const response = responseParse ? `(data: unknown) => ${responseParse.expression}.parse(data)` : null;
616
+ if (responseParse) importedZodNames.push(...responseParse.importNames);
617
+ return {
618
+ request,
619
+ response,
620
+ importedZodNames
621
+ };
622
+ }
623
+ //#endregion
624
+ //#region ../../internals/client/src/components/Operation.tsx
625
+ /**
626
+ * Renders one client operation: the grouped `<Name>Request` type and the function that forwards a
627
+ * single `options` object to the resolved client and returns the `RequestResult`. The type, signature,
628
+ * and call config are built with the AST factory, and only the jsx-renderer emits the source.
629
+ */
630
+ function Operation({ name, node, tsResolver, zodResolver, parser, security, isExportable = true, isIndexable = true }) {
631
+ if (!_kubb_core.ast.isHttpOperationNode(node)) return null;
632
+ const signature = buildGroupedOptionsSignature({
633
+ node,
634
+ tsResolver
635
+ });
636
+ const parsers = buildParserHooks({
637
+ node,
638
+ parser,
639
+ zodResolver
640
+ });
641
+ const securityLiteral = buildSecurityMetadata({ security });
642
+ const parserEntries = [parsers.request ? `request: ${parsers.request}` : null, parsers.response ? `response: ${parsers.response}` : null].filter(Boolean);
643
+ const parserLiteral = parserEntries.length ? `parser: { ${parserEntries.join(", ")} }` : null;
644
+ const callConfig = `{ ${[
645
+ `method: '${node.method.toUpperCase()}'`,
646
+ `url: '${node.path}'`,
647
+ securityLiteral ? `security: ${securityLiteral}` : null,
648
+ parserLiteral,
649
+ "...config"
650
+ ].filter(Boolean).join(", ")} }`;
651
+ return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
652
+ name,
653
+ isExportable,
654
+ isIndexable,
655
+ children: /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.Function, {
656
+ name,
657
+ export: isExportable,
658
+ generics: signature.generics,
659
+ params: signature.paramsSignature,
660
+ returnType: signature.returnType,
661
+ JSDoc: { comments: buildOperationComments(node, {
662
+ link: "urlPath",
663
+ linkPosition: "beforeDeprecated",
664
+ splitLines: true
665
+ }) },
666
+ children: [
667
+ "const { client: request = client, ...config } = options",
668
+ /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)("br", {}),
669
+ buildReturnStatement({
670
+ node,
671
+ tsResolver,
672
+ callConfig
673
+ })
674
+ ]
675
+ })
676
+ });
677
+ }
678
+ //#endregion
679
+ //#region ../../internals/client/src/builders/sdkMethod.ts
680
+ /**
681
+ * Builds the call config literal forwarded to the contract client, mirroring the shared `Operation`
682
+ * component: `{ method, url, security?, parser?, ...config }`. The `...config` spread carries every
683
+ * per-call field (including `throwOnError`), so the method stays a thin wrapper over the contract.
684
+ */
685
+ function buildCallConfig({ node, parser, zodResolver, security }) {
686
+ const parsers = buildParserHooks({
687
+ node,
688
+ parser,
689
+ zodResolver
690
+ });
691
+ const parserEntries = [parsers.request ? `request: ${parsers.request}` : null, parsers.response ? `response: ${parsers.response}` : null].filter(Boolean);
692
+ const parserLiteral = parserEntries.length ? `parser: { ${parserEntries.join(", ")} }` : null;
693
+ const securityLiteral = buildSecurityMetadata({ security });
694
+ return `{ ${[
695
+ `method: '${node.method.toUpperCase()}'`,
696
+ `url: '${node.path}'`,
697
+ securityLiteral ? `security: ${securityLiteral}` : null,
698
+ parserLiteral,
699
+ "...config"
700
+ ].filter(Boolean).join(", ")} }`;
701
+ }
702
+ /**
703
+ * Builds a single instance method for a generated SDK class. The body forwards the single grouped
704
+ * `options` object to the instance's own client (`this.client`, built once in the constructor) and
705
+ * returns the `RequestResult`. A per-call `options.client` still overrides the instance client, so
706
+ * one operation can be routed to a different environment without a new instance.
707
+ */
708
+ function buildSdkMethod({ node, name, tsResolver, zodResolver, parser, security }) {
709
+ if (!_kubb_core.ast.isHttpOperationNode(node)) return "";
710
+ const signature = buildGroupedOptionsSignature({
711
+ node,
712
+ tsResolver
713
+ });
714
+ const returnStatement = buildReturnStatement({
715
+ node,
716
+ tsResolver,
717
+ callConfig: buildCallConfig({
718
+ node,
719
+ parser,
720
+ zodResolver,
721
+ security
722
+ })
723
+ });
724
+ const generics = signature.generics.length ? `<${signature.generics.join(", ")}>` : "";
725
+ const jsdoc = (0, _kubb_ast_utils.buildJSDoc)(buildOperationComments(node, {
726
+ link: "urlPath",
727
+ linkPosition: "beforeDeprecated",
728
+ splitLines: true
729
+ }));
730
+ const methodBody = [
731
+ "const { client: request = this.client, ...config } = options",
732
+ "",
733
+ returnStatement
734
+ ].map((line) => line ? ` ${line}` : "").join("\n");
735
+ return `${jsdoc} public ${name}${generics}(${signature.paramsSignature}): ${signature.returnType} {\n${methodBody}\n }`;
736
+ }
737
+ //#endregion
738
+ //#region ../../internals/client/src/components/SdkClient.tsx
739
+ /**
740
+ * Renders one instance class per tag with one method per operation. The constructor takes a client
741
+ * config object and builds its own client through `createClient`, so each environment is a separate
742
+ * instance: `const api = new PetClient({ baseURL }); api.getPetById(...)`. A per-call `client` option
743
+ * still overrides the instance client for a one-off call.
744
+ */
745
+ function SdkClient({ name, isExportable = true, isIndexable = true, operations, parser, children }) {
746
+ const methods = operations.map(({ node, name: methodName, tsResolver, zodResolver, security }) => buildSdkMethod({
747
+ node,
748
+ name: methodName,
749
+ tsResolver,
750
+ zodResolver,
751
+ parser,
752
+ security
753
+ }));
754
+ const classCode = `export class ${name} {\n${[
755
+ " private readonly client: ClientInstance",
756
+ "",
757
+ " constructor(config: ClientConfig = {}) {",
758
+ " this.client = createClient(config)",
759
+ " }"
760
+ ].join("\n")}\n\n${methods.join("\n\n")}\n}`;
761
+ return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.File.Source, {
762
+ name,
763
+ isExportable,
764
+ isIndexable,
765
+ children: [classCode, children]
766
+ });
767
+ }
768
+ //#endregion
769
+ //#region ../../internals/client/src/components/SdkFacade.tsx
770
+ /**
771
+ * Renders a composed root SDK class that instantiates every tag client from one shared config, so
772
+ * `new PetStore({ baseURL }).petClient.getPetById(...)` reaches an operation through a single entry
773
+ * point bound to one environment. The per-tag clients are read-only fields built in the constructor.
774
+ */
775
+ function SdkFacade({ name, isExportable = true, isIndexable = true, members, children }) {
776
+ const fields = members.map((member) => ` readonly ${member.propName}: ${member.className}`);
777
+ const assignments = members.map((member) => ` this.${member.propName} = new ${member.className}(config)`);
778
+ const classCode = `export class ${name} {\n${[
779
+ ...fields,
780
+ "",
781
+ " constructor(config: ClientConfig = {}) {",
782
+ ...assignments,
783
+ " }"
784
+ ].join("\n")}\n}`;
785
+ return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.File.Source, {
786
+ name,
787
+ isExportable,
788
+ isIndexable,
789
+ children: [classCode, children]
790
+ });
791
+ }
792
+ //#endregion
793
+ //#region ../../internals/client/src/generators/sdkGenerator.tsx
794
+ function resolveTypeImportNames(node, tsResolver) {
795
+ return [tsResolver.resolveRequestConfigName(node), tsResolver.resolveResponsesName(node)];
796
+ }
797
+ function resolveZodImportNames(node, zodResolver, parser) {
798
+ const { query: queryParams } = getOperationParameters(node, { paramsCasing: "original" });
799
+ return [
800
+ resolveResponseParser(parser) === "zod" ? zodResolver.resolveResponseName?.(node) : null,
801
+ resolveRequestParser(parser) === "zod" && node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : null,
802
+ resolveQueryParamsParser(parser) === "zod" && queryParams.length > 0 ? zodResolver.resolveQueryParamsName?.(node, queryParams[0]) : null
803
+ ].filter((n) => Boolean(n));
804
+ }
805
+ /**
806
+ * Groups operations into one controller per tag. Operations without a tag fall back to a single
807
+ * `Client`/`ApiClient` controller, matching the resolver's default naming.
808
+ */
809
+ function buildControllers(nodes, ctx) {
810
+ const { driver, resolver, root } = ctx;
811
+ const { output, group, parser } = ctx.options;
812
+ const pluginTs = driver.getPlugin(_kubb_plugin_ts.pluginTsName);
813
+ const tsResolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
814
+ const tsPluginOptions = pluginTs.options;
815
+ const pluginZod = isParserEnabled(parser) ? driver.getPlugin(_kubb_plugin_zod.pluginZodName) : null;
816
+ const zodResolver = pluginZod ? driver.getResolver(_kubb_plugin_zod.pluginZodName) : null;
817
+ const document = ctx.adapter.document;
818
+ function buildOperationData(node) {
819
+ const typeFile = tsResolver.resolveFile(operationFileEntry(node, node.operationId), {
820
+ root,
821
+ output: tsPluginOptions?.output ?? output,
822
+ group: tsPluginOptions?.group
823
+ });
824
+ const zodFile = zodResolver && pluginZod?.options ? zodResolver.resolveFile(operationFileEntry(node, node.operationId), {
825
+ root,
826
+ output: pluginZod.options?.output ?? output,
827
+ group: pluginZod.options?.group ?? void 0
828
+ }) : null;
829
+ const security = _kubb_core.ast.isHttpOperationNode(node) ? getOperationSecurity({
830
+ document,
831
+ method: node.method,
832
+ path: node.path
833
+ }) : void 0;
834
+ return {
835
+ node,
836
+ name: resolver.resolveName(node.operationId),
837
+ tsResolver,
838
+ zodResolver,
839
+ typeFile,
840
+ zodFile,
841
+ security
842
+ };
843
+ }
844
+ return nodes.reduce((acc, operationNode) => {
845
+ if (!_kubb_core.ast.isHttpOperationNode(operationNode)) return acc;
846
+ const tag = operationNode.tags[0];
847
+ const name = tag ? group?.name?.({ group: camelCase(tag) }) ?? resolver.resolveGroupName(tag) : resolver.resolveClassName("ApiClient");
848
+ const file = resolver.resolveFile({
849
+ name,
850
+ extname: ".ts",
851
+ tag
852
+ }, {
853
+ root,
854
+ output,
855
+ group: group ?? void 0
856
+ });
857
+ const operationData = buildOperationData(operationNode);
858
+ const previous = acc.find((item) => item.file.path === file.path);
859
+ if (previous) previous.operations.push(operationData);
860
+ else acc.push({
861
+ name,
862
+ tag,
863
+ file,
864
+ operations: [operationData]
865
+ });
866
+ return acc;
867
+ }, []);
868
+ }
869
+ function collectImportsByFile(ops, pick) {
870
+ const namesByPath = /* @__PURE__ */ new Map();
871
+ const filesByPath = /* @__PURE__ */ new Map();
872
+ ops.forEach((op) => {
873
+ const { file, names } = pick(op);
874
+ if (!file || names.length === 0) return;
875
+ if (!namesByPath.has(file.path)) namesByPath.set(file.path, /* @__PURE__ */ new Set());
876
+ const set = namesByPath.get(file.path);
877
+ names.forEach((n) => set.add(n));
878
+ filesByPath.set(file.path, file);
879
+ });
880
+ return {
881
+ namesByPath,
882
+ filesByPath
883
+ };
884
+ }
885
+ /**
886
+ * Builds the class-based SDK generator for a client plugin (`@kubb/plugin-fetch`,
887
+ * `@kubb/plugin-axios`). Only registered when `sdk` is set; otherwise the plugin keeps its
888
+ * standalone per-operation functions.
889
+ *
890
+ * Every tag client is an instance class whose constructor takes a client config and builds its own
891
+ * client, so each environment is a separate instance. With `sdk.mode: 'tag'` (the default) it
892
+ * emits one class per tag and, when `sdk.name` is set, a composed root that instantiates every tag
893
+ * client. With `sdk.mode: 'flat'` it emits one class named by `sdk.name`, with every operation as a
894
+ * direct method.
895
+ */
896
+ function createSdkGenerator() {
897
+ return (0, _kubb_core.defineGenerator)({
898
+ name: "sdk",
899
+ renderer: _kubb_renderer_jsx.jsxRenderer,
900
+ operations(nodes, ctx) {
901
+ const { config, resolver, root } = ctx;
902
+ const { output, group, parser, sdk } = ctx.options;
903
+ if (!ctx.driver.getPlugin(_kubb_plugin_ts.pluginTsName) || !sdk) return null;
904
+ const controllers = buildControllers(nodes, ctx);
905
+ const clientPath = node_path.default.resolve(root, ".kubb/client.ts");
906
+ const banner = (file) => resolver.resolveBanner(ctx.meta, {
907
+ output,
908
+ config,
909
+ file: {
910
+ path: file.path,
911
+ baseName: file.baseName
912
+ }
913
+ });
914
+ const footer = (file) => resolver.resolveFooter(ctx.meta, {
915
+ output,
916
+ config,
917
+ file: {
918
+ path: file.path,
919
+ baseName: file.baseName
920
+ }
921
+ });
922
+ const renderClassFile = (className, file, ops) => {
923
+ const { namesByPath: typeNamesByPath, filesByPath: typeFilesByPath } = collectImportsByFile(ops, (op) => ({
924
+ file: op.typeFile,
925
+ names: resolveTypeImportNames(op.node, op.tsResolver)
926
+ }));
927
+ const { namesByPath: zodNamesByPath, filesByPath: zodFilesByPath } = isParserEnabled(parser) ? collectImportsByFile(ops, (op) => ({
928
+ file: op.zodFile,
929
+ names: op.zodResolver ? resolveZodImportNames(op.node, op.zodResolver, parser) : []
930
+ })) : {
931
+ namesByPath: /* @__PURE__ */ new Map(),
932
+ filesByPath: /* @__PURE__ */ new Map()
933
+ };
934
+ return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.File, {
935
+ baseName: file.baseName,
936
+ path: file.path,
937
+ meta: file.meta,
938
+ banner: banner(file),
939
+ footer: footer(file),
940
+ children: [
941
+ /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
942
+ name: ["createClient"],
943
+ root: file.path,
944
+ path: clientPath
945
+ }),
946
+ /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
947
+ name: [
948
+ "ClientConfig",
949
+ "ClientInstance",
950
+ "Options",
951
+ "RequestResult"
952
+ ],
953
+ root: file.path,
954
+ path: clientPath,
955
+ isTypeOnly: true
956
+ }),
957
+ parser === "zod" && ops.some((op) => op.node.requestBody?.content?.[0]?.schema != null) && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
958
+ name: ["z"],
959
+ path: "zod",
960
+ isTypeOnly: true
961
+ }),
962
+ Array.from(typeNamesByPath.entries()).map(([filePath, set]) => /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
963
+ name: Array.from(set),
964
+ root: file.path,
965
+ path: typeFilesByPath.get(filePath).path,
966
+ isTypeOnly: true
967
+ }, filePath)),
968
+ isParserEnabled(parser) && Array.from(zodNamesByPath.entries()).map(([filePath, set]) => /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
969
+ name: Array.from(set),
970
+ root: file.path,
971
+ path: zodFilesByPath.get(filePath).path
972
+ }, filePath)),
973
+ /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(SdkClient, {
974
+ name: className,
975
+ operations: ops,
976
+ parser
977
+ })
978
+ ]
979
+ }, file.path);
980
+ };
981
+ if (sdk.mode === "flat") return renderClassFile(resolver.resolveClassName(sdk.name ?? "sdk"), resolver.resolveFile({
982
+ name: sdk.name ?? "sdk",
983
+ extname: ".ts"
984
+ }, {
985
+ root,
986
+ output,
987
+ group: group ?? void 0
988
+ }), controllers.flatMap((controller) => controller.operations));
989
+ const classFiles = controllers.map(({ name, file, operations: ops }) => renderClassFile(name, file, ops));
990
+ if (!sdk.name) return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: classFiles });
991
+ const sdkFile = resolver.resolveFile({
992
+ name: sdk.name,
993
+ extname: ".ts"
994
+ }, {
995
+ root,
996
+ output,
997
+ group: group ?? void 0
998
+ });
999
+ const facadeName = resolver.resolveClassName(sdk.name);
1000
+ const members = controllers.map(({ name, tag }) => ({
1001
+ className: name,
1002
+ propName: resolver.resolveClientPropertyName(tag ?? name)
1003
+ }));
1004
+ return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [classFiles, /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.File, {
1005
+ baseName: sdkFile.baseName,
1006
+ path: sdkFile.path,
1007
+ meta: sdkFile.meta,
1008
+ banner: banner(sdkFile),
1009
+ footer: footer(sdkFile),
1010
+ children: [
1011
+ /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
1012
+ name: ["ClientConfig"],
1013
+ root: sdkFile.path,
1014
+ path: clientPath,
1015
+ isTypeOnly: true
1016
+ }),
1017
+ controllers.map(({ name, file }) => /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
1018
+ name: [name],
1019
+ root: sdkFile.path,
1020
+ path: file.path
1021
+ }, name)),
1022
+ /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(SdkFacade, {
1023
+ name: facadeName,
1024
+ members
1025
+ })
1026
+ ]
1027
+ }, sdkFile.path)] });
1028
+ }
1029
+ });
1030
+ }
1031
+ //#endregion
1032
+ //#region ../../internals/client/src/macros.ts
1033
+ /**
1034
+ * Macros the client plugins apply by default, ahead of any user macros. `macroSimplifyUnion`
1035
+ * drops union members a broader scalar already covers, keeping the generated response and error
1036
+ * unions tidy. A plugin wires them with `ctx.setMacros([...defaultMacros, ...userMacros])`.
1037
+ */
1038
+ const defaultMacros = [_kubb_ast_macros.macroSimplifyUnion];
1039
+ //#endregion
1040
+ //#region ../../internals/client/src/resolver.ts
1041
+ /**
1042
+ * Default resolver shared by the client plugins. Functions and files use camelCase; classes and
1043
+ * tag groups use PascalCase.
1044
+ *
1045
+ * @example
1046
+ * ```ts
1047
+ * resolverClient.resolveName('show pet by id') // 'showPetById'
1048
+ * resolverClient.resolveGroupName('pet') // 'PetClient'
1049
+ * ```
1050
+ */
1051
+ const resolverClient = (0, _kubb_core.defineResolver)(() => ({
1052
+ name: "default",
1053
+ pluginName: "plugin-contract-client",
1054
+ default(name, type) {
1055
+ if (type === "file") return toFilePath(name);
1056
+ return ensureValidVarName(camelCase(name));
1057
+ },
1058
+ resolveName(name) {
1059
+ return this.default(name, "function");
1060
+ },
1061
+ resolvePathName(name, type) {
1062
+ return this.default(name, type);
1063
+ },
1064
+ resolveClassName(name) {
1065
+ return ensureValidVarName(pascalCase(name));
1066
+ },
1067
+ resolveGroupName(name) {
1068
+ return ensureValidVarName(pascalCase(`${name} Client`));
1069
+ },
1070
+ resolveClientPropertyName(name) {
1071
+ return ensureValidVarName(camelCase(name));
1072
+ }
1073
+ }));
1074
+ //#endregion
1075
+ //#region src/generators/clientGenerator.tsx
1076
+ /**
1077
+ * Built-in operation generator for `@kubb/plugin-fetch`. Emits one async function per OpenAPI
1078
+ * operation using the shared `Operation` component: a grouped `<Name>Request` type and a function that
1079
+ * forwards a single `options` object to the bundled `client` and returns the `RequestResult`.
1080
+ */
1081
+ const clientGenerator = (0, _kubb_core.defineGenerator)({
1082
+ name: "fetch",
1083
+ renderer: _kubb_renderer_jsx.jsxRenderer,
1084
+ operation(node, ctx) {
1085
+ if (!_kubb_core.ast.isHttpOperationNode(node)) return null;
1086
+ const { config, driver, resolver, root } = ctx;
1087
+ const { output, parser, group } = ctx.options;
1088
+ const pluginTs = driver.getPlugin(_kubb_plugin_ts.pluginTsName);
1089
+ if (!pluginTs) return null;
1090
+ const tsResolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
1091
+ const pluginZod = resolveResponseParser(parser) === "zod" || resolveRequestParser(parser) === "zod" ? driver.getPlugin(_kubb_plugin_zod.pluginZodName) : null;
1092
+ const zodResolver = pluginZod ? driver.getResolver(_kubb_plugin_zod.pluginZodName) : null;
1093
+ const hasRequestBody = Boolean(node.requestBody?.content?.[0]?.schema);
1094
+ const importedTypeNames = [tsResolver.resolveRequestConfigName(node), tsResolver.resolveResponsesName(node)];
1095
+ const importedZodNames = zodResolver ? [resolveResponseParser(parser) === "zod" ? zodResolver.resolveResponseName?.(node) : null, resolveRequestParser(parser) === "zod" && hasRequestBody ? zodResolver.resolveDataName?.(node) : null].filter((name) => Boolean(name)) : [];
1096
+ const meta = {
1097
+ name: resolver.resolveName(node.operationId),
1098
+ file: resolver.resolveFile(operationFileEntry(node, node.operationId), {
1099
+ root,
1100
+ output,
1101
+ group: group ?? void 0
1102
+ }),
1103
+ fileTs: tsResolver.resolveFile(operationFileEntry(node, node.operationId), {
1104
+ root,
1105
+ output: pluginTs.options?.output ?? output,
1106
+ group: pluginTs.options?.group ?? void 0
1107
+ }),
1108
+ fileZod: zodResolver && pluginZod?.options ? zodResolver.resolveFile(operationFileEntry(node, node.operationId), {
1109
+ root,
1110
+ output: pluginZod.options.output ?? output,
1111
+ group: pluginZod.options?.group ?? void 0
1112
+ }) : null
1113
+ };
1114
+ const security = getOperationSecurity({
1115
+ document: ctx.adapter.document,
1116
+ method: node.method,
1117
+ path: node.path
1118
+ });
1119
+ const clientPath = node_path.default.resolve(root, ".kubb/client.ts");
1120
+ return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.File, {
1121
+ baseName: meta.file.baseName,
1122
+ path: meta.file.path,
1123
+ meta: meta.file.meta,
1124
+ banner: resolver.resolveBanner(ctx.meta, {
1125
+ output,
1126
+ config,
1127
+ file: {
1128
+ path: meta.file.path,
1129
+ baseName: meta.file.baseName
1130
+ }
1131
+ }),
1132
+ footer: resolver.resolveFooter(ctx.meta, {
1133
+ output,
1134
+ config,
1135
+ file: {
1136
+ path: meta.file.path,
1137
+ baseName: meta.file.baseName
1138
+ }
1139
+ }),
1140
+ children: [
1141
+ /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
1142
+ name: ["client"],
1143
+ root: meta.file.path,
1144
+ path: clientPath
1145
+ }),
1146
+ /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
1147
+ name: ["Options", "RequestResult"],
1148
+ root: meta.file.path,
1149
+ path: clientPath,
1150
+ isTypeOnly: true
1151
+ }),
1152
+ meta.fileTs && importedTypeNames.length > 0 && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
1153
+ name: Array.from(new Set(importedTypeNames)),
1154
+ root: meta.file.path,
1155
+ path: meta.fileTs.path,
1156
+ isTypeOnly: true
1157
+ }),
1158
+ meta.fileZod && importedZodNames.length > 0 && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
1159
+ name: importedZodNames,
1160
+ root: meta.file.path,
1161
+ path: meta.fileZod.path
1162
+ }),
1163
+ /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(Operation, {
1164
+ name: meta.name,
1165
+ node,
1166
+ tsResolver,
1167
+ zodResolver,
1168
+ parser,
1169
+ security
1170
+ })
1171
+ ]
1172
+ });
1173
+ }
1174
+ });
1175
+ //#endregion
1176
+ //#region src/templates.ts
1177
+ /**
1178
+ * Absolute path to the fetch client runtime template, resolved relative to this package's own
1179
+ * location so it stays correct no matter which package imports it. Pass it to a file node's `copy`
1180
+ * field to emit the runtime into the generated `.kubb/client.ts` verbatim.
1181
+ */
1182
+ const fetchClientTemplatePath = (0, node_url.fileURLToPath)(new URL("../templates/fetch.ts", require("url").pathToFileURL(__filename).href));
1183
+ //#endregion
1184
+ //#region src/plugin.ts
1185
+ /**
1186
+ * Canonical plugin name for `@kubb/plugin-fetch`. Used for driver lookups and cross-plugin
1187
+ * dependency references.
1188
+ */
1189
+ const pluginFetchName = "plugin-fetch";
1190
+ /**
1191
+ * Generates a type-safe HTTP client pinned to the Fetch API. Each operation becomes one async
1192
+ * function that takes a single grouped `options` object and returns the shared `RequestResult`
1193
+ * contract. The runtime is always bundled into `.kubb/client.ts`, so generated code never imports
1194
+ * from `@kubb/plugin-fetch` and the only runtime dependency is the global `fetch`.
1195
+ *
1196
+ * @example
1197
+ * ```ts
1198
+ * import { defineConfig } from 'kubb'
1199
+ * import { pluginTs } from '@kubb/plugin-ts'
1200
+ * import { pluginFetch } from '@kubb/plugin-fetch'
1201
+ *
1202
+ * export default defineConfig({
1203
+ * input: { path: './petStore.yaml' },
1204
+ * output: { path: './src/gen' },
1205
+ * plugins: [
1206
+ * pluginTs(),
1207
+ * pluginFetch({ output: { path: './clients' } }),
1208
+ * ],
1209
+ * })
1210
+ * ```
1211
+ */
1212
+ const pluginFetch = (0, _kubb_core.definePlugin)((options) => {
1213
+ const { output = {
1214
+ path: "clients",
1215
+ barrel: { type: "named" }
1216
+ }, exclude = [], include, override = [], baseURL, parser = false, group, sdk, resolver: userResolver } = options;
1217
+ const resolved = {
1218
+ output,
1219
+ exclude,
1220
+ include,
1221
+ override,
1222
+ group: createGroupConfig(group),
1223
+ baseURL,
1224
+ parser,
1225
+ sdk: sdk ? {
1226
+ mode: sdk.mode ?? "tag",
1227
+ name: sdk.name
1228
+ } : void 0,
1229
+ resolver: userResolver ? {
1230
+ ...resolverClient,
1231
+ ...userResolver
1232
+ } : resolverClient
1233
+ };
1234
+ const selectedGenerators = resolved.sdk ? [createSdkGenerator()] : [clientGenerator];
1235
+ return {
1236
+ name: pluginFetchName,
1237
+ options,
1238
+ dependencies: [_kubb_plugin_ts.pluginTsName, isParserEnabled(resolved.parser) ? _kubb_plugin_zod.pluginZodName : null].filter((dependency) => Boolean(dependency)),
1239
+ hooks: { "kubb:plugin:setup"(ctx) {
1240
+ ctx.setOptions(resolved);
1241
+ ctx.setResolver(resolved.resolver);
1242
+ ctx.setMacros([...defaultMacros, ...options.macros ?? []]);
1243
+ for (const gen of selectedGenerators) ctx.addGenerator(gen);
1244
+ const root = node_path.default.resolve(ctx.config.root, ctx.config.output.path);
1245
+ ctx.injectFile({
1246
+ baseName: "client.ts",
1247
+ path: node_path.default.resolve(root, ".kubb/client.ts"),
1248
+ copy: fetchClientTemplatePath,
1249
+ footer: baseURL ? `client.setConfig({ baseURL: ${JSON.stringify(baseURL)} })` : void 0
1250
+ });
1251
+ } }
1252
+ };
1253
+ });
1254
+ //#endregion
1255
+ exports.clientGenerator = clientGenerator;
1256
+ exports.default = pluginFetch;
1257
+ exports.pluginFetch = pluginFetch;
1258
+ exports.pluginFetchName = pluginFetchName;
1259
+
1260
+ //# sourceMappingURL=index.cjs.map