@kubb/plugin-swr 5.0.0-beta.64 → 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.js CHANGED
@@ -1,14 +1,37 @@
1
- import "./chunk-C0LytTxp.js";
2
- import { c as mutationKeyTransformer, o as queryKeyTransformer, u as camelCase } from "./components-mWBRE6E4.js";
3
- import { n as mutationGenerator, t as queryGenerator } from "./generators-D2blgLOY.js";
1
+ import { t as __name } from "./rolldown-runtime-C0LytTxp.js";
4
2
  import path from "node:path";
5
- import { ast, definePlugin, defineResolver } from "@kubb/core";
6
- import { isParserEnabled, pluginClientName } from "@kubb/plugin-client";
7
- import { source } from "@kubb/plugin-client/templates/clients/axios.source";
8
- import { source as source$1 } from "@kubb/plugin-client/templates/clients/fetch.source";
9
- import { source as source$2 } from "@kubb/plugin-client/templates/config.source";
10
- import { pluginTsName } from "@kubb/plugin-ts";
3
+ import { ast, defineGenerator, definePlugin, defineResolver } from "@kubb/core";
4
+ import { createFunctionParameter, createFunctionParameters, createObjectBindingPattern, createTypeLiteral, functionPrinter, pluginTsName } from "@kubb/plugin-ts";
11
5
  import { pluginZodName } from "@kubb/plugin-zod";
6
+ import { File, Function, Type, jsxRenderer } from "@kubb/renderer-jsx";
7
+ import { Fragment, jsx, jsxs } from "@kubb/renderer-jsx/jsx-runtime";
8
+ //#region ../../internals/utils/src/casing.ts
9
+ /**
10
+ * Shared implementation for camelCase and PascalCase conversion.
11
+ * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)
12
+ * and capitalizes each word according to `pascal`.
13
+ *
14
+ * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
15
+ */
16
+ function toCamelOrPascal(text, pascal) {
17
+ 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) => {
18
+ if (word.length > 1 && word === word.toUpperCase()) return word;
19
+ return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
20
+ }).join("").replace(/[^a-zA-Z0-9]/g, "");
21
+ }
22
+ /**
23
+ * Converts `text` to camelCase.
24
+ *
25
+ * @example Word boundaries
26
+ * `camelCase('hello-world') // 'helloWorld'`
27
+ *
28
+ * @example With a prefix
29
+ * `camelCase('tag', { prefix: 'create' }) // 'createTag'`
30
+ */
31
+ function camelCase(text, { prefix = "", suffix = "" } = {}) {
32
+ return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
33
+ }
34
+ //#endregion
12
35
  //#region ../../internals/utils/src/fs.ts
13
36
  /**
14
37
  * Builds a nested file path from a dotted name. Splits on dots that precede a letter
@@ -34,6 +57,386 @@ function toFilePath(name, caseLast = camelCase) {
34
57
  return parts.map((part, i) => i === parts.length - 1 ? caseLast(part) : camelCase(part)).filter(Boolean).join("/");
35
58
  }
36
59
  //#endregion
60
+ //#region ../../internals/utils/src/reserved.ts
61
+ /**
62
+ * JavaScript and Java reserved words.
63
+ * @link https://github.com/jonschlinkert/reserved/blob/master/index.js
64
+ */
65
+ const reservedWords = new Set([
66
+ "abstract",
67
+ "arguments",
68
+ "boolean",
69
+ "break",
70
+ "byte",
71
+ "case",
72
+ "catch",
73
+ "char",
74
+ "class",
75
+ "const",
76
+ "continue",
77
+ "debugger",
78
+ "default",
79
+ "delete",
80
+ "do",
81
+ "double",
82
+ "else",
83
+ "enum",
84
+ "eval",
85
+ "export",
86
+ "extends",
87
+ "false",
88
+ "final",
89
+ "finally",
90
+ "float",
91
+ "for",
92
+ "function",
93
+ "goto",
94
+ "if",
95
+ "implements",
96
+ "import",
97
+ "in",
98
+ "instanceof",
99
+ "int",
100
+ "interface",
101
+ "let",
102
+ "long",
103
+ "native",
104
+ "new",
105
+ "null",
106
+ "package",
107
+ "private",
108
+ "protected",
109
+ "public",
110
+ "return",
111
+ "short",
112
+ "static",
113
+ "super",
114
+ "switch",
115
+ "synchronized",
116
+ "this",
117
+ "throw",
118
+ "throws",
119
+ "transient",
120
+ "true",
121
+ "try",
122
+ "typeof",
123
+ "var",
124
+ "void",
125
+ "volatile",
126
+ "while",
127
+ "with",
128
+ "yield",
129
+ "Array",
130
+ "Date",
131
+ "hasOwnProperty",
132
+ "Infinity",
133
+ "isFinite",
134
+ "isNaN",
135
+ "isPrototypeOf",
136
+ "length",
137
+ "Math",
138
+ "name",
139
+ "NaN",
140
+ "Number",
141
+ "Object",
142
+ "prototype",
143
+ "String",
144
+ "toString",
145
+ "undefined",
146
+ "valueOf"
147
+ ]);
148
+ /**
149
+ * Returns `true` when `name` is a syntactically valid JavaScript variable name.
150
+ *
151
+ * @example
152
+ * ```ts
153
+ * isValidVarName('status') // true
154
+ * isValidVarName('class') // false (reserved word)
155
+ * isValidVarName('42foo') // false (starts with digit)
156
+ * ```
157
+ */
158
+ function isValidVarName(name) {
159
+ if (!name || reservedWords.has(name)) return false;
160
+ return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
161
+ }
162
+ //#endregion
163
+ //#region ../../internals/utils/src/url.ts
164
+ function transformParam(raw, casing) {
165
+ const param = isValidVarName(raw) ? raw : camelCase(raw);
166
+ return casing === "camelcase" ? camelCase(param) : param;
167
+ }
168
+ function toParamsObject(path, { replacer, casing } = {}) {
169
+ const params = {};
170
+ for (const match of path.matchAll(/\{([^}]+)\}/g)) {
171
+ const param = transformParam(match[1], casing);
172
+ const key = replacer ? replacer(param) : param;
173
+ params[key] = key;
174
+ }
175
+ return Object.keys(params).length > 0 ? params : null;
176
+ }
177
+ /**
178
+ * Helpers for OpenAPI/Swagger paths, plus a thin wrapper over the native `URL`.
179
+ */
180
+ var Url = class Url {
181
+ /**
182
+ * Reports whether `url` is a parseable absolute URL. Delegates to the native `URL.canParse`.
183
+ *
184
+ * @example
185
+ * Url.canParse('https://petstore.swagger.io/v2') // true
186
+ * Url.canParse('/pet/{petId}') // false
187
+ */
188
+ static canParse(url, base) {
189
+ return URL.canParse(url, base);
190
+ }
191
+ /**
192
+ * Converts an OpenAPI/Swagger path to Express-style colon syntax.
193
+ *
194
+ * @example
195
+ * Url.toPath('/pet/{petId}') // '/pet/:petId'
196
+ */
197
+ static toPath(path) {
198
+ return path.replace(/\{([^}]+)\}/g, ":$1");
199
+ }
200
+ /**
201
+ * Converts an OpenAPI/Swagger path to a TypeScript template literal string.
202
+ * `prefix` is prepended inside the literal, `replacer` transforms each parameter name,
203
+ * and `casing` controls parameter identifier casing.
204
+ *
205
+ * @example
206
+ * Url.toTemplateString('/pet/{petId}') // '`/pet/${petId}`'
207
+ *
208
+ * @example
209
+ * Url.toTemplateString('/pet/{petId}', { prefix: 'https://api' }) // '`https://api/pet/${petId}`'
210
+ */
211
+ static toTemplateString(path, { prefix, replacer, casing } = {}) {
212
+ const result = path.split(/\{([^}]+)\}/).map((part, i) => {
213
+ if (i % 2 === 0) return part;
214
+ const param = transformParam(part, casing);
215
+ return `\${${replacer ? replacer(param) : param}}`;
216
+ }).join("");
217
+ return `\`${prefix ?? ""}${result}\``;
218
+ }
219
+ /**
220
+ * Converts an OpenAPI/Swagger path to a template literal that reads each parameter off the
221
+ * grouped `path` request option, e.g. `/pet/{petId}` becomes `` `/pet/${path.petId}` ``. Parameter
222
+ * names are camelCased to match the generated `path` type, and `prefix` is prepended inside the
223
+ * literal. Shared by the client and cypress generators that pass a grouped `path` object.
224
+ *
225
+ * @example
226
+ * Url.toGroupedTemplateString('/pet/{petId}') // '`/pet/${path.petId}`'
227
+ */
228
+ static toGroupedTemplateString(path, { prefix } = {}) {
229
+ return Url.toTemplateString(path, {
230
+ prefix,
231
+ casing: "camelcase",
232
+ replacer: (name) => `path.${name}`
233
+ });
234
+ }
235
+ /**
236
+ * Returns the path and its extracted params as a structured `URLObject`, or as a stringified
237
+ * expression when `stringify` is set.
238
+ *
239
+ * @example
240
+ * Url.toObject('/pet/{petId}')
241
+ * // { url: '/pet/:petId', params: { petId: 'petId' } }
242
+ */
243
+ static toObject(path, { type = "path", replacer, stringify, casing } = {}) {
244
+ const object = {
245
+ url: type === "path" ? Url.toPath(path) : Url.toTemplateString(path, {
246
+ replacer,
247
+ casing
248
+ }),
249
+ params: toParamsObject(path, {
250
+ replacer,
251
+ casing
252
+ })
253
+ };
254
+ if (stringify) {
255
+ if (type === "template") return JSON.stringify(object).replaceAll("'", "").replaceAll(`"`, "");
256
+ if (object.params) return `{ url: '${object.url}', params: ${JSON.stringify(object.params).replaceAll("'", "").replaceAll(`"`, "")} }`;
257
+ return `{ url: '${object.url}' }`;
258
+ }
259
+ return object;
260
+ }
261
+ };
262
+ //#endregion
263
+ //#region ../../internals/shared/src/params.ts
264
+ const caseParamsCache = /* @__PURE__ */ new WeakMap();
265
+ /**
266
+ * Applies camelCase to parameter names and returns a new array without mutating the input.
267
+ *
268
+ * Run it before handing parameters to schema builders so output property keys get the right casing
269
+ * while `OperationNode.parameters` stays intact for other consumers. When `casing` is unset, the
270
+ * original array is returned unchanged. Results are cached per input array.
271
+ */
272
+ function caseParams(params, casing) {
273
+ if (!casing) return params;
274
+ const cached = caseParamsCache.get(params);
275
+ if (cached) return cached;
276
+ const result = params.map((param) => ({
277
+ ...param,
278
+ name: camelCase(param.name)
279
+ }));
280
+ caseParamsCache.set(params, result);
281
+ return result;
282
+ }
283
+ //#endregion
284
+ //#region ../../internals/shared/src/operation.ts
285
+ /**
286
+ * Builds the `ResolverFileParams` every operation generator passes to
287
+ * `resolver.resolveFile`: a file named `name`, tagged by the operation's first
288
+ * tag (or `'default'`), at the operation's path. Centralizes the entry object
289
+ * that was repeated at dozens of call sites across the client and query plugins.
290
+ *
291
+ * @example
292
+ * ```ts
293
+ * resolver.resolveFile(operationFileEntry(node, node.operationId), { root, output, group })
294
+ * ```
295
+ */
296
+ function operationFileEntry(node, name, extname = ".ts") {
297
+ return {
298
+ name,
299
+ extname,
300
+ tag: node.tags[0] ?? "default",
301
+ path: node.path
302
+ };
303
+ }
304
+ function getOperationLink(node, link) {
305
+ if (!link) return null;
306
+ if (typeof link === "function") return link(node) ?? null;
307
+ if (link === "urlPath") return node.path ? `{@link ${Url.toPath(node.path)}}` : null;
308
+ return node.path ? `{@link ${node.path.replaceAll("{", ":").replaceAll("}", "")}}` : null;
309
+ }
310
+ function getContentTypeInfo(node) {
311
+ const contentTypes = node.requestBody?.content?.map((e) => e.contentType) ?? [];
312
+ const isMultipleContentTypes = contentTypes.length > 1;
313
+ return {
314
+ contentTypes,
315
+ isMultipleContentTypes,
316
+ contentTypeUnion: isMultipleContentTypes ? contentTypes.map((ct) => JSON.stringify(ct)).join(" | ") : "",
317
+ defaultContentType: contentTypes[0] ?? "application/json",
318
+ hasFormData: contentTypes.some((ct) => ct === "multipart/form-data")
319
+ };
320
+ }
321
+ function buildRequestConfigType(node) {
322
+ const { isMultipleContentTypes, contentTypeUnion } = getContentTypeInfo(node);
323
+ const configType = `Partial<Omit<RequestConfig, 'path' | 'query' | 'body' | 'headers' | 'url'>>`;
324
+ const contentTypeProp = isMultipleContentTypes ? `contentType?: ${contentTypeUnion}` : null;
325
+ return contentTypeProp ? `${configType} & { ${contentTypeProp} }` : configType;
326
+ }
327
+ /**
328
+ * Builds the `client?:` option type shared by the generated query hooks (`useQuery`,
329
+ * `useInfiniteQuery`, `useSWR`, ...). Unlike {@link buildRequestConfigType}, it never adds a
330
+ * `contentType?:` member: query hooks wrap GET operations, which carry no request body to select a
331
+ * content type for.
332
+ */
333
+ function buildClientOptionType() {
334
+ return `Partial<Omit<RequestConfig, 'path' | 'query' | 'body' | 'headers' | 'url'>>`;
335
+ }
336
+ /**
337
+ * Which of the grouped request options an operation carries.
338
+ */
339
+ function getRequestGroups(node) {
340
+ const { path, query, header } = getOperationParameters(node);
341
+ return {
342
+ path: path.length > 0,
343
+ query: query.length > 0,
344
+ body: Boolean(node.requestBody?.content?.[0]?.schema),
345
+ headers: header.length > 0
346
+ };
347
+ }
348
+ /**
349
+ * Resolves which grouped request options an operation carries together with whether each group
350
+ * holds a required member. The grouped parameter stays optional only when nothing inside it is
351
+ * required, matching the generated `RequestConfig` type.
352
+ */
353
+ function getRequestGroupOptionality(node) {
354
+ const groups = getRequestGroups(node);
355
+ const { path, query, header } = getOperationParameters(node);
356
+ const hasRequiredPath = path.some((param) => param.required);
357
+ const hasRequiredQuery = query.some((param) => param.required);
358
+ const hasRequiredHeader = header.some((param) => param.required);
359
+ return {
360
+ groups,
361
+ hasRequiredPath,
362
+ hasRequiredQuery,
363
+ hasRequiredHeader,
364
+ isOptional: !hasRequiredPath && !hasRequiredQuery && !hasRequiredHeader && !groups.body
365
+ };
366
+ }
367
+ function buildOperationComments(node, options = {}) {
368
+ const { link = "pathTemplate", linkPosition = "afterDeprecated", splitLines = false } = options;
369
+ const linkComment = getOperationLink(node, link);
370
+ const filteredComments = (linkPosition === "beforeDeprecated" ? [
371
+ node.description && `@description ${node.description}`,
372
+ node.summary && `@summary ${node.summary}`,
373
+ linkComment,
374
+ node.deprecated && "@deprecated"
375
+ ] : [
376
+ node.description && `@description ${node.description}`,
377
+ node.summary && `@summary ${node.summary}`,
378
+ node.deprecated && "@deprecated",
379
+ linkComment
380
+ ]).filter((comment) => Boolean(comment));
381
+ if (!splitLines) return filteredComments;
382
+ return filteredComments.flatMap((text) => text.split(/\r?\n/).map((line) => line.trim())).filter((comment) => Boolean(comment));
383
+ }
384
+ function getOperationParameters(node, options = {}) {
385
+ const params = caseParams(node.parameters, options.paramsCasing === "original" ? void 0 : "camelcase");
386
+ return {
387
+ path: params.filter((param) => param.in === "path"),
388
+ query: params.filter((param) => param.in === "query"),
389
+ header: params.filter((param) => param.in === "header"),
390
+ cookie: params.filter((param) => param.in === "cookie")
391
+ };
392
+ }
393
+ function getStatusCodeNumber(statusCode) {
394
+ const code = Number(statusCode);
395
+ return Number.isNaN(code) ? null : code;
396
+ }
397
+ function isErrorStatusCode(statusCode) {
398
+ const code = getStatusCodeNumber(statusCode);
399
+ return code !== null && code >= 400;
400
+ }
401
+ function resolveErrorNames(node, resolver) {
402
+ return node.responses.filter((response) => isErrorStatusCode(response.statusCode)).map((response) => resolver.resolveResponseStatusName(node, response.statusCode));
403
+ }
404
+ function resolveStatusCodeNames(node, resolver) {
405
+ return node.responses.map((response) => resolver.resolveResponseStatusName(node, response.statusCode));
406
+ }
407
+ const typeNamesByResolver = /* @__PURE__ */ new WeakMap();
408
+ function resolveOperationTypeNames(node, resolver, options = {}) {
409
+ const cacheKey = `${node.operationId}\0${options.paramsCasing ?? ""}\0${options.order ?? ""}\0${options.responseStatusNames ?? ""}\0${options.includeParams === false ? "noparams" : ""}\0${(options.exclude ?? []).join(",")}`;
410
+ let byResolver = typeNamesByResolver.get(resolver);
411
+ if (byResolver) {
412
+ const cached = byResolver.get(cacheKey);
413
+ if (cached) return cached;
414
+ } else {
415
+ byResolver = /* @__PURE__ */ new Map();
416
+ typeNamesByResolver.set(resolver, byResolver);
417
+ }
418
+ const { path, query, header } = getOperationParameters(node, { paramsCasing: options.paramsCasing });
419
+ const responseStatusNames = options.responseStatusNames === "error" ? resolveErrorNames(node, resolver) : options.responseStatusNames === false ? [] : resolveStatusCodeNames(node, resolver);
420
+ const exclude = new Set(options.exclude ?? []);
421
+ const paramNames = options.includeParams === false ? [] : [
422
+ ...path.map((param) => resolver.resolvePathParamsName(node, param)),
423
+ ...query.map((param) => resolver.resolveQueryParamsName(node, param)),
424
+ ...header.map((param) => resolver.resolveHeaderParamsName(node, param))
425
+ ];
426
+ const bodyAndResponseNames = [node.requestBody?.content?.[0]?.schema ? resolver.resolveDataName(node) : null, resolver.resolveResponseName(node)];
427
+ const result = (options.order === "body-response-first" ? [
428
+ ...bodyAndResponseNames,
429
+ ...paramNames,
430
+ ...responseStatusNames
431
+ ] : [
432
+ ...paramNames,
433
+ ...bodyAndResponseNames,
434
+ ...responseStatusNames
435
+ ]).filter((name) => Boolean(name) && !exclude.has(name));
436
+ byResolver.set(cacheKey, result);
437
+ return result;
438
+ }
439
+ //#endregion
37
440
  //#region ../../internals/shared/src/group.ts
38
441
  /**
39
442
  * Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the
@@ -65,6 +468,826 @@ function createGroupConfig(group) {
65
468
  };
66
469
  }
67
470
  //#endregion
471
+ //#region ../../internals/client/src/builders/parser.ts
472
+ /**
473
+ * Returns `true` when any direction of the parser uses zod (used for dependency checks).
474
+ */
475
+ function isParserEnabled(parser) {
476
+ if (!parser) return false;
477
+ if (parser === "zod") return true;
478
+ return Boolean(parser.request || parser.response);
479
+ }
480
+ //#endregion
481
+ //#region ../../internals/client/src/resolveClient.ts
482
+ /**
483
+ * Resolves which client plugin a consumer (react-query, vue-query, swr, mcp) should call for an
484
+ * operation, shared so the selection rules and diagnostics stay in one place.
485
+ *
486
+ * Every client runtime lives in a dedicated client plugin, so a consumer always calls a registered
487
+ * contract client plugin (plugin-fetch or plugin-axios) and never emits its own inline client:
488
+ *
489
+ * - `contract` — a registered contract client plugin owns the `<op>` functions and the consumer
490
+ * imports and calls them.
491
+ * - `error` — no client plugin is registered, several are registered without a selector, or the
492
+ * requested one is missing.
493
+ *
494
+ * The `client` string selects explicitly (`'fetch'` / `'axios'`); when it is unset a lone registered
495
+ * contract client plugin is picked up automatically.
496
+ */
497
+ const pluginFetchName = "plugin-fetch";
498
+ const pluginAxiosName = "plugin-axios";
499
+ const selectorToPlugin = {
500
+ fetch: pluginFetchName,
501
+ axios: pluginAxiosName
502
+ };
503
+ const contractPlugins = [pluginFetchName, pluginAxiosName];
504
+ /**
505
+ * Applies the `client` resolution rules. See the module comment for the strategy shape.
506
+ *
507
+ * @example
508
+ * ```ts
509
+ * resolveClient({ client: 'fetch', pluginNames: ['plugin-ts', 'plugin-fetch'] })
510
+ * // { kind: 'contract', pluginName: 'plugin-fetch' }
511
+ * ```
512
+ *
513
+ * @example
514
+ * ```ts
515
+ * resolveClient({ client: undefined, pluginNames: ['plugin-ts'] })
516
+ * // { kind: 'error', message: 'No client plugin is registered…' }
517
+ * ```
518
+ */
519
+ function resolveClient(options) {
520
+ const { client, pluginNames } = options;
521
+ const has = (name) => pluginNames.includes(name);
522
+ if (client === "fetch" || client === "axios") {
523
+ const pluginName = selectorToPlugin[client];
524
+ if (!has(pluginName)) return {
525
+ kind: "error",
526
+ message: `\`client: '${client}'\` is set but \`@kubb/plugin-${client}\` is not registered in \`plugins\`. Add it, or drop \`client\` to use a different client plugin.`
527
+ };
528
+ return {
529
+ kind: "contract",
530
+ pluginName
531
+ };
532
+ }
533
+ const registered = contractPlugins.filter(has);
534
+ if (registered.length === 1) return {
535
+ kind: "contract",
536
+ pluginName: registered[0]
537
+ };
538
+ if (registered.length > 1) return {
539
+ kind: "error",
540
+ message: `Multiple client plugins are registered (${registered.map((name) => `\`@kubb/${name}\``).join(", ")}). Set \`client: 'fetch' | 'axios'\` to choose which client the hooks call, or register a single client plugin.`
541
+ };
542
+ return {
543
+ kind: "error",
544
+ message: "No client plugin is registered. Add `@kubb/plugin-axios` or `@kubb/plugin-fetch` to `plugins` so the generated code has an HTTP client to call."
545
+ };
546
+ }
547
+ //#endregion
548
+ //#region ../../internals/client/src/resolveClientOperation.ts
549
+ /**
550
+ * Resolves the contract client `<op>` a consumer (query hook, MCP handler) imports, by looking up
551
+ * the registered contract client plugin's resolver and output. Works for any contract client plugin
552
+ * (plugin-fetch or plugin-axios). Returns `null` when no contract plugin is in play (the inline
553
+ * path). The plugin injects `.kubb/client.ts` at the global output root, the same path consumers
554
+ * read `RequestConfig` / `ResponseErrorConfig` from.
555
+ */
556
+ function resolveClientOperation(options) {
557
+ const { clientPlugin, driver, node, root, output } = options;
558
+ if (!clientPlugin) return null;
559
+ const resolver = driver.getResolver(clientPlugin.pluginName);
560
+ if (!resolver) return null;
561
+ const plugin = driver.getPlugin(clientPlugin.pluginName);
562
+ const file = resolver.resolveFile(operationFileEntry(node, node.operationId), {
563
+ root,
564
+ output: plugin?.options?.output ?? output,
565
+ group: plugin?.options?.group ?? void 0
566
+ });
567
+ return {
568
+ name: resolver.resolveName(node.operationId),
569
+ path: file.path,
570
+ clientPath: path.resolve(root, ".kubb/client.ts")
571
+ };
572
+ }
573
+ //#endregion
574
+ //#region ../../internals/tanstack-query/src/components/MutationKey.tsx
575
+ const declarationPrinter$4 = functionPrinter({ mode: "declaration" });
576
+ const mutationKeyTransformer = ({ node }) => {
577
+ if (!node.path) return [];
578
+ return [`{ url: '${Url.toPath(node.path)}' }`];
579
+ };
580
+ function MutationKey$1({ name, node, transformer }) {
581
+ const paramsNode = createFunctionParameters({ params: [] });
582
+ const paramsSignature = declarationPrinter$4.print(paramsNode) ?? "";
583
+ const keys = (transformer ?? mutationKeyTransformer)({
584
+ node,
585
+ casing: "camelcase"
586
+ });
587
+ return /* @__PURE__ */ jsx(File.Source, {
588
+ name,
589
+ isExportable: true,
590
+ isIndexable: true,
591
+ children: /* @__PURE__ */ jsx(Function.Arrow, {
592
+ name,
593
+ export: true,
594
+ params: paramsSignature,
595
+ singleLine: true,
596
+ children: `[${keys.join(", ")}] as const`
597
+ })
598
+ });
599
+ }
600
+ __name(MutationKey$1, "MutationKey");
601
+ //#endregion
602
+ //#region ../../internals/tanstack-query/src/utils.ts
603
+ /**
604
+ * The grouped request options, ordered for both the destructured signature and the
605
+ * call passed to the underlying client.
606
+ */
607
+ const requestGroupOrder = [
608
+ "path",
609
+ "query",
610
+ "body",
611
+ "headers"
612
+ ];
613
+ /**
614
+ * Builds the grouped `{ path, query, body, headers }` parameter that mirrors the client
615
+ * function signature. Only the groups the operation carries are emitted, typed from the
616
+ * operation's `RequestConfig`. `keys` narrows the emitted groups, used by the query key which
617
+ * never carries `headers`.
618
+ *
619
+ * By default the whole group is typed as the single `RequestConfig` reference. When
620
+ * `memberTypeWrapper` is set, each group is emitted as its own member typed from the matching
621
+ * `RequestConfig['<group>']` slice and wrapped, used by vue-query to apply
622
+ * `MaybeRefOrGetter` per group.
623
+ */
624
+ function buildGroupedRequestParam(node, options) {
625
+ const { resolver, keys = requestGroupOrder, memberTypeWrapper } = options;
626
+ const { groups, hasRequiredPath, hasRequiredQuery, hasRequiredHeader } = getRequestGroupOptionality(node);
627
+ const names = keys.filter((key) => groups[key]);
628
+ if (names.length === 0) return null;
629
+ const requiredByGroup = {
630
+ path: hasRequiredPath,
631
+ query: hasRequiredQuery,
632
+ body: groups.body,
633
+ headers: hasRequiredHeader
634
+ };
635
+ const isOptional = names.every((name) => !requiredByGroup[name]);
636
+ const requestConfigName = resolver.resolveRequestConfigName(node);
637
+ const omittedKeys = requestGroupOrder.filter((key) => !keys.includes(key));
638
+ const requestConfigType = omittedKeys.length > 0 ? `Omit<${requestConfigName}, ${omittedKeys.map((key) => `'${key}'`).join(" | ")}>` : requestConfigName;
639
+ if (memberTypeWrapper) {
640
+ const members = names.map((name) => ({
641
+ name,
642
+ type: memberTypeWrapper(`${requestConfigType}['${name}']`),
643
+ optional: !requiredByGroup[name]
644
+ }));
645
+ return createFunctionParameter({
646
+ name: createObjectBindingPattern({ elements: names.map((name) => ({ name })) }),
647
+ type: createTypeLiteral({ members }),
648
+ optional: false,
649
+ ...isOptional ? { default: "{}" } : {}
650
+ });
651
+ }
652
+ return createFunctionParameter({
653
+ name: createObjectBindingPattern({ elements: names.map((name) => ({ name })) }),
654
+ type: requestConfigType,
655
+ optional: false,
656
+ ...isOptional ? { default: "{}" } : {}
657
+ });
658
+ }
659
+ /**
660
+ * Builds the shared `({ path, query, body, headers }, config = {})` parameter list for a
661
+ * TanStack query-options function. The leading parameter mirrors the client signature, and the
662
+ * trailing `config` is a partial `RequestConfig` minus the grouped data-shape keys, which are passed
663
+ * explicitly. Framework plugins wrap the result when needed, for example vue-query applies `MaybeRefOrGetter`.
664
+ */
665
+ function buildQueryOptionsParams(node, options) {
666
+ const { resolver, memberTypeWrapper } = options;
667
+ return createFunctionParameters({ params: [buildGroupedRequestParam(node, {
668
+ resolver,
669
+ memberTypeWrapper
670
+ }), createFunctionParameter({
671
+ name: "config",
672
+ type: `Partial<Omit<RequestConfig, 'path' | 'query' | 'body' | 'headers' | 'url'>>`,
673
+ default: "{}"
674
+ })].filter((param) => param !== null) });
675
+ }
676
+ /**
677
+ * Builds the call to a client `<op>` function inside a query/mutation hook body. The function takes
678
+ * a single grouped options object, so the operation's request groups are passed as
679
+ * shorthand alongside the spread `config`, with `throwOnError: true` pinned last so a caller's config
680
+ * can't flip the query's error semantics. Queries thread the TanStack `signal`; mutations omit it.
681
+ *
682
+ * @example
683
+ * ```ts
684
+ * buildClientCall(node, { clientName: 'getPetById', signal: true })
685
+ * // getPetById({ path, ...config, signal: config.signal ?? signal, throwOnError: true })
686
+ * ```
687
+ */
688
+ function buildClientCall(node, options) {
689
+ const { clientName, signal = false } = options;
690
+ const { groups } = getRequestGroupOptionality(node);
691
+ return `${clientName}({ ${[
692
+ "...config",
693
+ ...requestGroupOrder.filter((key) => groups[key]),
694
+ signal ? "signal: config.signal ?? signal" : null,
695
+ "throwOnError: true"
696
+ ].filter((part) => part !== null).join(", ")} })`;
697
+ }
698
+ /**
699
+ * Returns `'zod'` when response-direction parsing is enabled.
700
+ * The string shorthand `'zod'` also enables response parsing.
701
+ */
702
+ function resolveResponseParser(parser) {
703
+ if (!parser) return null;
704
+ if (parser === "zod") return "zod";
705
+ return parser.response ?? null;
706
+ }
707
+ /**
708
+ * Returns `'zod'` when request body parsing is enabled.
709
+ * The string shorthand `'zod'` also enables request body parsing (existing behavior).
710
+ */
711
+ function resolveRequestParser(parser) {
712
+ if (!parser) return null;
713
+ if (parser === "zod") return "zod";
714
+ return parser.request ?? null;
715
+ }
716
+ /**
717
+ * Returns `'zod'` when query-params parsing is enabled.
718
+ * Only the object form `{ request: 'zod' }` enables this. `parser: 'zod'` does not.
719
+ */
720
+ function resolveQueryParamsParser(parser) {
721
+ if (!parser || parser === "zod") return null;
722
+ return parser.request ?? null;
723
+ }
724
+ /**
725
+ * Collects the Zod schema import names for an operation based on the active parser directions.
726
+ *
727
+ * - `parser: 'zod'`: response and request body names (backward-compatible behavior).
728
+ * - `parser: { request: 'zod' }`: request body and query params names.
729
+ * - `parser: { response: 'zod' }`: response name only.
730
+ * - `parser: { request: 'zod', response: 'zod' }`: all three.
731
+ *
732
+ * Returns an empty array when no resolver is provided or `parser` is falsy.
733
+ */
734
+ function resolveZodSchemaNames(node, zodResolver, parser) {
735
+ if (!zodResolver || !parser) return [];
736
+ const { query: queryParams } = getOperationParameters(node, { paramsCasing: "original" });
737
+ return [
738
+ resolveResponseParser(parser) === "zod" ? zodResolver.resolveResponseName?.(node) : null,
739
+ resolveRequestParser(parser) === "zod" && node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : null,
740
+ resolveQueryParamsParser(parser) === "zod" && queryParams.length > 0 ? zodResolver.resolveQueryParamsName?.(node, queryParams[0]) : null
741
+ ].filter((n) => Boolean(n));
742
+ }
743
+ /**
744
+ * Build QueryKey params as the grouped `{ path, query, body }` object (NO headers, NO config),
745
+ * typed from the operation's `RequestConfig` minus `url`. The query key transformer reads the
746
+ * grouped `path`/`query`/`body` bindings.
747
+ */
748
+ function buildQueryKeyParams(node, options) {
749
+ const { resolver } = options;
750
+ const groupedParam = buildGroupedRequestParam(node, {
751
+ resolver,
752
+ keys: [
753
+ "path",
754
+ "query",
755
+ "body"
756
+ ]
757
+ });
758
+ return createFunctionParameters({ params: groupedParam ? [groupedParam] : [] });
759
+ }
760
+ //#endregion
761
+ //#region ../../internals/tanstack-query/src/components/QueryKey.tsx
762
+ const declarationPrinter$3 = functionPrinter({ mode: "declaration" });
763
+ const queryKeyTransformer = ({ node }) => {
764
+ if (!node.path) return [];
765
+ const hasPathParams = getOperationParameters(node).path.length > 0;
766
+ const hasQueryParams = getOperationParameters(node).query.length > 0;
767
+ const hasRequestBody = !!node.requestBody?.content?.[0]?.schema;
768
+ return [
769
+ hasPathParams ? `{ url: '${Url.toPath(node.path)}', params: path }` : `{ url: '${Url.toPath(node.path)}' }`,
770
+ hasQueryParams ? "...(query ? [query] : [])" : null,
771
+ hasRequestBody ? "...(body ? [body] : [])" : null
772
+ ].filter(Boolean);
773
+ };
774
+ function QueryKey({ name, node, tsResolver, typeName, transformer }) {
775
+ const paramsNode = buildQueryKeyParams(node, { resolver: tsResolver });
776
+ const paramsSignature = declarationPrinter$3.print(paramsNode) ?? "";
777
+ const keys = (transformer ?? queryKeyTransformer)({
778
+ node,
779
+ casing: "camelcase"
780
+ });
781
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(File.Source, {
782
+ name,
783
+ isExportable: true,
784
+ isIndexable: true,
785
+ children: /* @__PURE__ */ jsx(Function.Arrow, {
786
+ name,
787
+ export: true,
788
+ params: paramsSignature,
789
+ singleLine: true,
790
+ children: `[${keys.join(", ")}] as const`
791
+ })
792
+ }), /* @__PURE__ */ jsx(File.Source, {
793
+ name: typeName,
794
+ isTypeOnly: true,
795
+ children: /* @__PURE__ */ jsx(Type, {
796
+ name: typeName,
797
+ children: `ReturnType<typeof ${name}>`
798
+ })
799
+ })] });
800
+ }
801
+ //#endregion
802
+ //#region src/components/Mutation.tsx
803
+ const declarationPrinter$2 = functionPrinter({ mode: "declaration" });
804
+ const callPrinter$1 = functionPrinter({ mode: "call" });
805
+ function buildMutationParamsNode(node, options) {
806
+ const { mutationKeyTypeName, mutationArgTypeName, resolver } = options;
807
+ const responseName = resolver.resolveResponseName(node);
808
+ const errorNames = resolveErrorNames(node, resolver);
809
+ return createFunctionParameters({ params: [createFunctionParameter({
810
+ name: "options",
811
+ type: `{
812
+ mutation?: SWRMutationConfiguration<${responseName}, ${`ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(" | ") : "Error"}>`}, ${mutationKeyTypeName} | null, ${mutationArgTypeName}> & { throwOnError?: boolean },
813
+ client?: ${buildRequestConfigType(node)},
814
+ shouldFetch?: boolean,
815
+ }`,
816
+ default: "{}"
817
+ })] });
818
+ }
819
+ function Mutation({ name, clientName, mutationKeyName, mutationKeyTypeName, mutationArgTypeName, node, tsResolver }) {
820
+ const responseName = tsResolver.resolveResponseName(node);
821
+ const errorNames = resolveErrorNames(node, tsResolver);
822
+ const TData = responseName;
823
+ const TError = `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(" | ") : "Error"}>`;
824
+ const groupedParam = buildGroupedRequestParam(node, { resolver: tsResolver });
825
+ const hasMutationParams = groupedParam !== null;
826
+ const groupedParamsNode = createFunctionParameters({ params: groupedParam ? [groupedParam] : [] });
827
+ const argTypeBody = hasMutationParams ? tsResolver.resolveRequestConfigName(node) : "";
828
+ const argBindingStr = hasMutationParams ? callPrinter$1.print(groupedParamsNode) ?? "" : "";
829
+ const mutationFnBody = `const { data } = await ${buildClientCall(node, {
830
+ clientName,
831
+ signal: false
832
+ })}
833
+ return data`;
834
+ const generics = [
835
+ TData,
836
+ TError,
837
+ `${mutationKeyTypeName} | null`,
838
+ mutationArgTypeName
839
+ ];
840
+ const paramsNode = buildMutationParamsNode(node, {
841
+ mutationKeyTypeName,
842
+ mutationArgTypeName,
843
+ resolver: tsResolver
844
+ });
845
+ const paramsSignature = declarationPrinter$2.print(paramsNode) ?? "";
846
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(File.Source, {
847
+ name: mutationArgTypeName,
848
+ isExportable: true,
849
+ isIndexable: true,
850
+ isTypeOnly: true,
851
+ children: /* @__PURE__ */ jsx(Type, {
852
+ name: mutationArgTypeName,
853
+ export: true,
854
+ children: hasMutationParams ? argTypeBody : "never"
855
+ })
856
+ }), /* @__PURE__ */ jsx(File.Source, {
857
+ name,
858
+ isExportable: true,
859
+ isIndexable: true,
860
+ children: /* @__PURE__ */ jsx(Function, {
861
+ name,
862
+ export: true,
863
+ params: paramsSignature,
864
+ JSDoc: { comments: buildOperationComments(node) },
865
+ children: `
866
+ const { mutation: mutationOptions, client: config = {}, shouldFetch = true } = options ?? {}
867
+ const mutationKey = ${mutationKeyName}()
868
+
869
+ return useSWRMutation<${generics.join(", ")}>(
870
+ shouldFetch ? mutationKey : null,
871
+ async (_url${hasMutationParams ? `, { arg: ${argBindingStr} }` : ""}) => {
872
+ ${mutationFnBody}
873
+ },
874
+ mutationOptions
875
+ )
876
+ `
877
+ })
878
+ })] });
879
+ }
880
+ //#endregion
881
+ //#region src/components/MutationKey.tsx
882
+ function MutationKey({ name, typeName, node, transformer }) {
883
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(MutationKey$1, {
884
+ name,
885
+ node,
886
+ transformer
887
+ }), /* @__PURE__ */ jsx(File.Source, {
888
+ name: typeName,
889
+ isExportable: true,
890
+ isIndexable: true,
891
+ isTypeOnly: true,
892
+ children: /* @__PURE__ */ jsx(Type, {
893
+ export: true,
894
+ name: typeName,
895
+ children: `ReturnType<typeof ${name}>`
896
+ })
897
+ })] });
898
+ }
899
+ //#endregion
900
+ //#region src/components/QueryOptions.tsx
901
+ const declarationPrinter$1 = functionPrinter({ mode: "declaration" });
902
+ function getQueryOptionsParams(node, options) {
903
+ return buildQueryOptionsParams(node, options);
904
+ }
905
+ function QueryOptions({ name, clientName, node, tsResolver }) {
906
+ const paramsNode = getQueryOptionsParams(node, { resolver: tsResolver });
907
+ const paramsSignature = declarationPrinter$1.print(paramsNode) ?? "";
908
+ const fetcherBody = `const { data } = await ${buildClientCall(node, {
909
+ clientName,
910
+ signal: false
911
+ })}
912
+ return data`;
913
+ return /* @__PURE__ */ jsx(File.Source, {
914
+ name,
915
+ isExportable: true,
916
+ isIndexable: true,
917
+ children: /* @__PURE__ */ jsx(Function, {
918
+ name,
919
+ export: true,
920
+ params: paramsSignature,
921
+ children: `
922
+ return {
923
+ fetcher: async () => {
924
+ ${fetcherBody}
925
+ },
926
+ }
927
+ `
928
+ })
929
+ });
930
+ }
931
+ //#endregion
932
+ //#region src/components/Query.tsx
933
+ const declarationPrinter = functionPrinter({ mode: "declaration" });
934
+ const callPrinter = functionPrinter({ mode: "call" });
935
+ function buildQueryParamsNode(node, options) {
936
+ const { resolver } = options;
937
+ const responseName = resolver.resolveResponseName(node);
938
+ const errorNames = resolveErrorNames(node, resolver);
939
+ const optionsParam = createFunctionParameter({
940
+ name: "options",
941
+ type: `{
942
+ query?: SWRConfiguration<${[responseName, `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(" | ") : "Error"}>`].join(", ")}>,
943
+ client?: ${buildClientOptionType()},
944
+ shouldFetch?: boolean,
945
+ immutable?: boolean
946
+ }`,
947
+ default: "{}"
948
+ });
949
+ return createFunctionParameters({ params: [buildGroupedRequestParam(node, { resolver }), optionsParam].filter((param) => param !== null) });
950
+ }
951
+ function Query({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, tsResolver }) {
952
+ const responseName = tsResolver.resolveResponseName(node);
953
+ const errorNames = resolveErrorNames(node, tsResolver);
954
+ const generics = [
955
+ responseName,
956
+ `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(" | ") : "Error"}>`,
957
+ `${queryKeyTypeName} | null`
958
+ ];
959
+ const queryKeyParamsNode = buildQueryKeyParams(node, { resolver: tsResolver });
960
+ const queryKeyParamsCall = callPrinter.print(queryKeyParamsNode) ?? "";
961
+ const queryOptionsParamsNode = getQueryOptionsParams(node, { resolver: tsResolver });
962
+ const queryOptionsParamsCall = callPrinter.print(queryOptionsParamsNode) ?? "";
963
+ const paramsNode = buildQueryParamsNode(node, { resolver: tsResolver });
964
+ const paramsSignature = declarationPrinter.print(paramsNode) ?? "";
965
+ return /* @__PURE__ */ jsx(File.Source, {
966
+ name,
967
+ isExportable: true,
968
+ isIndexable: true,
969
+ children: /* @__PURE__ */ jsx(Function, {
970
+ name,
971
+ export: true,
972
+ params: paramsSignature,
973
+ JSDoc: { comments: buildOperationComments(node) },
974
+ children: `
975
+ const { query: queryOptions, client: config = {}, shouldFetch = true, immutable } = options ?? {}
976
+
977
+ const queryKey = ${queryKeyName}(${queryKeyParamsCall})
978
+
979
+ return useSWR<${generics.join(", ")}>(
980
+ shouldFetch ? queryKey : null,
981
+ {
982
+ ...${queryOptionsName}(${queryOptionsParamsCall}),
983
+ ...(immutable ? {
984
+ revalidateIfStale: false,
985
+ revalidateOnFocus: false,
986
+ revalidateOnReconnect: false
987
+ } : { }),
988
+ ...queryOptions,
989
+ }
990
+ )
991
+ `
992
+ })
993
+ });
994
+ }
995
+ //#endregion
996
+ //#region src/generators/mutationGenerator.tsx
997
+ /**
998
+ * Built-in generator for `useSWRMutation` hooks. Emits one `useFooMutation` hook
999
+ * per POST/PUT/DELETE operation (configurable via `mutation.methods`) plus
1000
+ * the matching `fooMutationKey` helper.
1001
+ */
1002
+ const mutationGenerator = defineGenerator({
1003
+ name: "swr-mutation",
1004
+ renderer: jsxRenderer,
1005
+ operation(node, ctx) {
1006
+ if (!ast.isHttpOperationNode(node)) return null;
1007
+ const { config, driver, resolver, root } = ctx;
1008
+ const { output, query, mutation, parser, client, group } = ctx.options;
1009
+ const pluginTs = driver.getPlugin(pluginTsName);
1010
+ if (!pluginTs) return null;
1011
+ const tsResolver = driver.getResolver(pluginTsName);
1012
+ const isQuery = query === false || !!query && query.methods.some((method) => node.method.toLowerCase() === method.toLowerCase());
1013
+ const queryMethods = new Set(query ? query.methods : []);
1014
+ if (!(mutation !== false && !isQuery && (mutation ? mutation.methods : []).some((method) => !queryMethods.has(method) && node.method.toLowerCase() === method.toLowerCase()))) return null;
1015
+ const importPath = mutation ? mutation.importPath : "swr/mutation";
1016
+ const contractOp = resolveClientOperation({
1017
+ clientPlugin: { pluginName: client.pluginName },
1018
+ driver,
1019
+ node,
1020
+ root,
1021
+ output
1022
+ });
1023
+ if (!contractOp) return null;
1024
+ const mutationHookName = resolver.resolveMutationName(node);
1025
+ const mutationKeyName = resolver.resolveMutationKeyName(node);
1026
+ const mutationKeyTypeName = resolver.resolveMutationKeyTypeName(node);
1027
+ const mutationArgTypeName = resolver.resolveMutationArgTypeName(node);
1028
+ const meta = {
1029
+ file: resolver.resolveFile({
1030
+ name: mutationHookName,
1031
+ extname: ".ts",
1032
+ tag: node.tags[0] ?? "default",
1033
+ path: node.path
1034
+ }, {
1035
+ root,
1036
+ output,
1037
+ group
1038
+ }),
1039
+ fileTs: tsResolver.resolveFile({
1040
+ name: node.operationId,
1041
+ extname: ".ts",
1042
+ tag: node.tags[0] ?? "default",
1043
+ path: node.path
1044
+ }, {
1045
+ root,
1046
+ output: pluginTs.options?.output ?? output,
1047
+ group: pluginTs.options?.group
1048
+ })
1049
+ };
1050
+ const importedTypeNames = [tsResolver.resolveRequestConfigName(node), ...resolveOperationTypeNames(node, tsResolver, {
1051
+ order: "body-response-first",
1052
+ includeParams: false
1053
+ })].filter((name) => Boolean(name));
1054
+ const pluginZod = isParserEnabled(parser) ? driver.getPlugin(pluginZodName) : void 0;
1055
+ const zodResolver = pluginZod ? driver.getResolver(pluginZodName) : void 0;
1056
+ const fileZod = zodResolver ? zodResolver.resolveFile({
1057
+ name: node.operationId,
1058
+ extname: ".ts",
1059
+ tag: node.tags[0] ?? "default",
1060
+ path: node.path
1061
+ }, {
1062
+ root,
1063
+ output: pluginZod?.options?.output ?? output,
1064
+ group: pluginZod?.options?.group
1065
+ }) : void 0;
1066
+ const zodSchemaNames = resolveZodSchemaNames(node, zodResolver, parser);
1067
+ const calledClientName = contractOp.name;
1068
+ return /* @__PURE__ */ jsxs(File, {
1069
+ baseName: meta.file.baseName,
1070
+ path: meta.file.path,
1071
+ meta: meta.file.meta,
1072
+ banner: resolver.resolveBanner(ctx.meta, {
1073
+ output,
1074
+ config,
1075
+ file: {
1076
+ path: meta.file.path,
1077
+ baseName: meta.file.baseName
1078
+ }
1079
+ }),
1080
+ footer: resolver.resolveFooter(ctx.meta, {
1081
+ output,
1082
+ config,
1083
+ file: {
1084
+ path: meta.file.path,
1085
+ baseName: meta.file.baseName
1086
+ }
1087
+ }),
1088
+ children: [
1089
+ fileZod && zodSchemaNames.length > 0 && /* @__PURE__ */ jsx(File.Import, {
1090
+ name: zodSchemaNames,
1091
+ root: meta.file.path,
1092
+ path: fileZod.path
1093
+ }),
1094
+ /* @__PURE__ */ jsx(File.Import, {
1095
+ name: [contractOp.name],
1096
+ root: meta.file.path,
1097
+ path: contractOp.path
1098
+ }),
1099
+ /* @__PURE__ */ jsx(File.Import, {
1100
+ name: ["RequestConfig", "ResponseErrorConfig"],
1101
+ root: meta.file.path,
1102
+ path: contractOp.clientPath,
1103
+ isTypeOnly: true
1104
+ }),
1105
+ meta.fileTs && importedTypeNames.length > 0 && /* @__PURE__ */ jsx(File.Import, {
1106
+ name: Array.from(new Set(importedTypeNames)),
1107
+ root: meta.file.path,
1108
+ path: meta.fileTs.path,
1109
+ isTypeOnly: true
1110
+ }),
1111
+ /* @__PURE__ */ jsx(MutationKey, {
1112
+ name: mutationKeyName,
1113
+ typeName: mutationKeyTypeName,
1114
+ node,
1115
+ transformer: ctx.options.mutationKey
1116
+ }),
1117
+ mutation && /* @__PURE__ */ jsxs(Fragment, { children: [
1118
+ /* @__PURE__ */ jsx(File.Import, {
1119
+ name: "useSWRMutation",
1120
+ path: importPath
1121
+ }),
1122
+ /* @__PURE__ */ jsx(File.Import, {
1123
+ name: ["SWRMutationConfiguration"],
1124
+ path: importPath,
1125
+ isTypeOnly: true
1126
+ }),
1127
+ /* @__PURE__ */ jsx(Mutation, {
1128
+ name: mutationHookName,
1129
+ clientName: calledClientName,
1130
+ mutationKeyName,
1131
+ mutationKeyTypeName,
1132
+ mutationArgTypeName,
1133
+ node,
1134
+ tsResolver
1135
+ })
1136
+ ] })
1137
+ ]
1138
+ });
1139
+ }
1140
+ });
1141
+ //#endregion
1142
+ //#region src/generators/queryGenerator.tsx
1143
+ const queryGenerator = defineGenerator({
1144
+ name: "swr-query",
1145
+ renderer: jsxRenderer,
1146
+ operation(node, ctx) {
1147
+ if (!ast.isHttpOperationNode(node)) return null;
1148
+ const { config, driver, resolver, root } = ctx;
1149
+ const { output, query, mutation, parser, client, group } = ctx.options;
1150
+ const pluginTs = driver.getPlugin(pluginTsName);
1151
+ if (!pluginTs) return null;
1152
+ const tsResolver = driver.getResolver(pluginTsName);
1153
+ const isQuery = query === false || !!query && query.methods.some((method) => node.method.toLowerCase() === method.toLowerCase());
1154
+ const queryMethods = new Set(query ? query.methods : []);
1155
+ const isMutation = mutation !== false && !isQuery && (mutation ? mutation.methods : []).some((method) => !queryMethods.has(method) && node.method.toLowerCase() === method.toLowerCase());
1156
+ if (!isQuery || isMutation) return null;
1157
+ const importPath = query ? query.importPath : "swr";
1158
+ const contractOp = resolveClientOperation({
1159
+ clientPlugin: { pluginName: client.pluginName },
1160
+ driver,
1161
+ node,
1162
+ root,
1163
+ output
1164
+ });
1165
+ if (!contractOp) return null;
1166
+ const queryName = resolver.resolveQueryName(node);
1167
+ const queryOptionsName = resolver.resolveQueryOptionsName(node);
1168
+ const queryKeyName = resolver.resolveQueryKeyName(node);
1169
+ const queryKeyTypeName = resolver.resolveQueryKeyTypeName(node);
1170
+ const meta = {
1171
+ file: resolver.resolveFile({
1172
+ name: queryName,
1173
+ extname: ".ts",
1174
+ tag: node.tags[0] ?? "default",
1175
+ path: node.path
1176
+ }, {
1177
+ root,
1178
+ output,
1179
+ group
1180
+ }),
1181
+ fileTs: tsResolver.resolveFile({
1182
+ name: node.operationId,
1183
+ extname: ".ts",
1184
+ tag: node.tags[0] ?? "default",
1185
+ path: node.path
1186
+ }, {
1187
+ root,
1188
+ output: pluginTs.options?.output ?? output,
1189
+ group: pluginTs.options?.group
1190
+ })
1191
+ };
1192
+ const importedTypeNames = [tsResolver.resolveRequestConfigName(node), ...resolveOperationTypeNames(node, tsResolver, {
1193
+ exclude: [queryKeyTypeName],
1194
+ order: "body-response-first",
1195
+ includeParams: false
1196
+ })].filter((name) => Boolean(name));
1197
+ const pluginZod = isParserEnabled(parser) ? driver.getPlugin(pluginZodName) : void 0;
1198
+ const zodResolver = pluginZod ? driver.getResolver(pluginZodName) : void 0;
1199
+ const fileZod = zodResolver ? zodResolver.resolveFile({
1200
+ name: node.operationId,
1201
+ extname: ".ts",
1202
+ tag: node.tags[0] ?? "default",
1203
+ path: node.path
1204
+ }, {
1205
+ root,
1206
+ output: pluginZod?.options?.output ?? output,
1207
+ group: pluginZod?.options?.group
1208
+ }) : void 0;
1209
+ const zodSchemaNames = resolveZodSchemaNames(node, zodResolver, parser);
1210
+ const calledClientName = contractOp.name;
1211
+ return /* @__PURE__ */ jsxs(File, {
1212
+ baseName: meta.file.baseName,
1213
+ path: meta.file.path,
1214
+ meta: meta.file.meta,
1215
+ banner: resolver.resolveBanner(ctx.meta, {
1216
+ output,
1217
+ config,
1218
+ file: {
1219
+ path: meta.file.path,
1220
+ baseName: meta.file.baseName
1221
+ }
1222
+ }),
1223
+ footer: resolver.resolveFooter(ctx.meta, {
1224
+ output,
1225
+ config,
1226
+ file: {
1227
+ path: meta.file.path,
1228
+ baseName: meta.file.baseName
1229
+ }
1230
+ }),
1231
+ children: [
1232
+ fileZod && zodSchemaNames.length > 0 && /* @__PURE__ */ jsx(File.Import, {
1233
+ name: zodSchemaNames,
1234
+ root: meta.file.path,
1235
+ path: fileZod.path
1236
+ }),
1237
+ /* @__PURE__ */ jsx(File.Import, {
1238
+ name: [contractOp.name],
1239
+ root: meta.file.path,
1240
+ path: contractOp.path
1241
+ }),
1242
+ /* @__PURE__ */ jsx(File.Import, {
1243
+ name: ["RequestConfig", "ResponseErrorConfig"],
1244
+ root: meta.file.path,
1245
+ path: contractOp.clientPath,
1246
+ isTypeOnly: true
1247
+ }),
1248
+ meta.fileTs && importedTypeNames.length > 0 && /* @__PURE__ */ jsx(File.Import, {
1249
+ name: Array.from(new Set(importedTypeNames)),
1250
+ root: meta.file.path,
1251
+ path: meta.fileTs.path,
1252
+ isTypeOnly: true
1253
+ }),
1254
+ /* @__PURE__ */ jsx(QueryKey, {
1255
+ name: queryKeyName,
1256
+ typeName: queryKeyTypeName,
1257
+ node,
1258
+ tsResolver,
1259
+ transformer: ctx.options.queryKey
1260
+ }),
1261
+ /* @__PURE__ */ jsx(QueryOptions, {
1262
+ name: queryOptionsName,
1263
+ clientName: calledClientName,
1264
+ node,
1265
+ tsResolver
1266
+ }),
1267
+ query && /* @__PURE__ */ jsxs(Fragment, { children: [
1268
+ /* @__PURE__ */ jsx(File.Import, {
1269
+ name: "useSWR",
1270
+ path: importPath
1271
+ }),
1272
+ /* @__PURE__ */ jsx(File.Import, {
1273
+ name: ["SWRConfiguration"],
1274
+ path: importPath,
1275
+ isTypeOnly: true
1276
+ }),
1277
+ /* @__PURE__ */ jsx(Query, {
1278
+ name: queryName,
1279
+ queryOptionsName,
1280
+ queryKeyName,
1281
+ queryKeyTypeName,
1282
+ node,
1283
+ tsResolver
1284
+ })
1285
+ ] })
1286
+ ]
1287
+ });
1288
+ }
1289
+ });
1290
+ //#endregion
68
1291
  //#region src/resolvers/resolverSwr.ts
69
1292
  function capitalize(name) {
70
1293
  return `${name.charAt(0).toUpperCase()}${name.slice(1)}`;
@@ -124,10 +1347,8 @@ const pluginSwr = definePlugin((options) => {
124
1347
  const { output = {
125
1348
  path: "hooks",
126
1349
  barrel: { type: "named" }
127
- }, group, exclude = [], include, override = [], parser = false, paramsType = "inline", pathParamsType = paramsType === "object" ? "object" : options.pathParamsType || "inline", mutation = {}, query = {}, mutationKey = mutationKeyTransformer, queryKey = queryKeyTransformer, paramsCasing, client, resolver: userResolver, macros: userMacros, generators: userGenerators = [] } = options;
128
- const clientName = client?.client ?? "axios";
129
- const clientImportPath = client?.importPath ?? (!client?.bundle ? `@kubb/plugin-client/clients/${clientName}` : void 0);
130
- const selectedGenerators = options.generators ?? [queryGenerator, mutationGenerator].filter((generator) => Boolean(generator));
1350
+ }, group, exclude = [], include, override = [], parser = false, mutation = {}, query = {}, mutationKey = mutationKeyTransformer, queryKey = queryKeyTransformer, client, resolver: userResolver, macros: userMacros } = options;
1351
+ const selectedGenerators = [queryGenerator, mutationGenerator].filter((generator) => Boolean(generator));
131
1352
  const groupConfig = createGroupConfig(group) ?? void 0;
132
1353
  return {
133
1354
  name: pluginSwrName,
@@ -138,17 +1359,18 @@ const pluginSwr = definePlugin((options) => {
138
1359
  ...resolverSwr,
139
1360
  ...userResolver
140
1361
  } : resolverSwr;
1362
+ const resolvedClient = resolveClient({
1363
+ client,
1364
+ pluginNames: (ctx.config.plugins ?? []).map((p) => p.name).filter((name) => Boolean(name))
1365
+ });
1366
+ if (resolvedClient.kind === "error") throw new Error(resolvedClient.message);
1367
+ const resolvedClientDescriptor = {
1368
+ kind: "contract",
1369
+ pluginName: resolvedClient.pluginName
1370
+ };
141
1371
  ctx.setOptions({
142
1372
  output,
143
- client: {
144
- bundle: client?.bundle,
145
- baseURL: client?.baseURL,
146
- client: clientName,
147
- clientType: client?.clientType ?? "function",
148
- importPath: clientImportPath,
149
- dataReturnType: client?.dataReturnType ?? "data",
150
- paramsCasing
151
- },
1373
+ client: resolvedClientDescriptor,
152
1374
  queryKey,
153
1375
  query: query === false ? false : {
154
1376
  importPath: "swr",
@@ -167,9 +1389,6 @@ const pluginSwr = definePlugin((options) => {
167
1389
  ...mutation
168
1390
  },
169
1391
  parser,
170
- paramsType,
171
- pathParamsType,
172
- paramsCasing,
173
1392
  group: groupConfig,
174
1393
  exclude,
175
1394
  include,
@@ -179,29 +1398,6 @@ const pluginSwr = definePlugin((options) => {
179
1398
  ctx.setResolver(resolver);
180
1399
  if (userMacros?.length) ctx.setMacros(userMacros);
181
1400
  for (const gen of selectedGenerators) ctx.addGenerator(gen);
182
- for (const gen of userGenerators) ctx.addGenerator(gen);
183
- const root = path.resolve(ctx.config.root, ctx.config.output.path);
184
- const hasClientPlugin = !!ctx.config.plugins?.some((p) => p.name === pluginClientName);
185
- if (client?.bundle && !hasClientPlugin && !clientImportPath) ctx.injectFile({
186
- baseName: "client.ts",
187
- path: path.resolve(root, ".kubb/client.ts"),
188
- sources: [ast.factory.createSource({
189
- name: "client",
190
- nodes: [ast.factory.createText(clientName === "fetch" ? source$1 : source)],
191
- isExportable: true,
192
- isIndexable: true
193
- })]
194
- });
195
- if (!hasClientPlugin) ctx.injectFile({
196
- baseName: "config.ts",
197
- path: path.resolve(root, ".kubb/config.ts"),
198
- sources: [ast.factory.createSource({
199
- name: "config",
200
- nodes: [ast.factory.createText(source$2)],
201
- isExportable: false,
202
- isIndexable: false
203
- })]
204
- });
205
1401
  } }
206
1402
  };
207
1403
  });