@kubb/plugin-swr 5.0.0-beta.99 → 5.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -23,240 +23,17 @@ var __copyProps = (to, from, except, desc) => {
23
23
  }
24
24
  return to;
25
25
  };
26
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
26
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
27
27
  value: mod,
28
28
  enumerable: true
29
29
  }) : target, mod));
30
30
  //#endregion
31
+ let kubb_kit = require("kubb/kit");
31
32
  let node_path = require("node:path");
32
33
  node_path = __toESM(node_path, 1);
33
- let kubb_kit = require("kubb/kit");
34
34
  let _kubb_plugin_ts = require("@kubb/plugin-ts");
35
35
  let kubb_jsx = require("kubb/jsx");
36
36
  let kubb_jsx_jsx_runtime = require("kubb/jsx/jsx-runtime");
37
- //#region ../../internals/utils/src/casing.ts
38
- /**
39
- * Shared implementation for camelCase and PascalCase conversion.
40
- * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)
41
- * and capitalizes each word according to `pascal`.
42
- *
43
- * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
44
- */
45
- function toCamelOrPascal(text, pascal) {
46
- 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) => {
47
- if (word.length > 1 && word === word.toUpperCase()) return word;
48
- return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
49
- }).join("").replace(/[^a-zA-Z0-9]/g, "");
50
- }
51
- /**
52
- * Converts `text` to camelCase.
53
- *
54
- * @example Word boundaries
55
- * `camelCase('hello-world') // 'helloWorld'`
56
- *
57
- * @example With a prefix
58
- * `camelCase('tag', { prefix: 'create' }) // 'createTag'`
59
- */
60
- function camelCase(text, { prefix = "", suffix = "" } = {}) {
61
- return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
62
- }
63
- /**
64
- * Uppercases only the first character of `text`, leaving the rest untouched.
65
- * Unlike {@link pascalCase} it never re-splits word boundaries or strips characters.
66
- *
67
- * @example
68
- * `capitalize('getPetById') // 'GetPetById'`
69
- */
70
- function capitalize(text) {
71
- return `${text.charAt(0).toUpperCase()}${text.slice(1)}`;
72
- }
73
- //#endregion
74
- //#region ../../internals/utils/src/reserved.ts
75
- /**
76
- * JavaScript and Java reserved words.
77
- * @link https://github.com/jonschlinkert/reserved/blob/master/index.js
78
- */
79
- const reservedWords = /* @__PURE__ */ new Set([
80
- "abstract",
81
- "arguments",
82
- "boolean",
83
- "break",
84
- "byte",
85
- "case",
86
- "catch",
87
- "char",
88
- "class",
89
- "const",
90
- "continue",
91
- "debugger",
92
- "default",
93
- "delete",
94
- "do",
95
- "double",
96
- "else",
97
- "enum",
98
- "eval",
99
- "export",
100
- "extends",
101
- "false",
102
- "final",
103
- "finally",
104
- "float",
105
- "for",
106
- "function",
107
- "goto",
108
- "if",
109
- "implements",
110
- "import",
111
- "in",
112
- "instanceof",
113
- "int",
114
- "interface",
115
- "let",
116
- "long",
117
- "native",
118
- "new",
119
- "null",
120
- "package",
121
- "private",
122
- "protected",
123
- "public",
124
- "return",
125
- "short",
126
- "static",
127
- "super",
128
- "switch",
129
- "synchronized",
130
- "this",
131
- "throw",
132
- "throws",
133
- "transient",
134
- "true",
135
- "try",
136
- "typeof",
137
- "var",
138
- "void",
139
- "volatile",
140
- "while",
141
- "with",
142
- "yield",
143
- "Array",
144
- "Date",
145
- "hasOwnProperty",
146
- "Infinity",
147
- "isFinite",
148
- "isNaN",
149
- "isPrototypeOf",
150
- "length",
151
- "Math",
152
- "name",
153
- "NaN",
154
- "Number",
155
- "Object",
156
- "prototype",
157
- "String",
158
- "toString",
159
- "undefined",
160
- "valueOf"
161
- ]);
162
- /**
163
- * Returns `true` when `name` is a syntactically valid JavaScript variable name.
164
- *
165
- * @example
166
- * ```ts
167
- * isValidVarName('status') // true
168
- * isValidVarName('class') // false (reserved word)
169
- * isValidVarName('42foo') // false (starts with digit)
170
- * ```
171
- */
172
- function isValidVarName(name) {
173
- if (!name || reservedWords.has(name)) return false;
174
- return isIdentifier(name);
175
- }
176
- /**
177
- * Returns `true` when `name` is syntactically a valid identifier, ignoring reserved words.
178
- *
179
- * Reserved words and globals (`class`, `name`, `Date`, …) are valid as bare object-literal keys
180
- * even though they are not valid variable names, so use this (not {@link isValidVarName}) when
181
- * deciding whether an object key needs quoting.
182
- *
183
- * @example
184
- * ```ts
185
- * isIdentifier('name') // true
186
- * isIdentifier('x-total')// false
187
- * ```
188
- */
189
- function isIdentifier(name) {
190
- return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
191
- }
192
- //#endregion
193
- //#region ../../internals/utils/src/url.ts
194
- /**
195
- * Keeps the OpenAPI parameter name as-is when it is already a valid JS identifier, and
196
- * camelCases it only enough to become one otherwise (for example a hyphenated path segment).
197
- */
198
- function transformParam(raw) {
199
- return isValidVarName(raw) ? raw : camelCase(raw);
200
- }
201
- /**
202
- * Helpers for OpenAPI/Swagger paths.
203
- */
204
- var Url = class Url {
205
- /**
206
- * Converts an OpenAPI/Swagger path to Express-style colon syntax.
207
- *
208
- * @example
209
- * Url.toPath('/pet/{petId}') // '/pet/:petId'
210
- */
211
- static toPath(path) {
212
- return path.replace(/\{([^}]+)\}/g, ":$1");
213
- }
214
- /**
215
- * Rewrites OpenAPI placeholder names while keeping the `{...}` braces, so the generated `url`
216
- * literal aligns with the grouped `path` request option that the runtime client interpolates by
217
- * key.
218
- *
219
- * @example
220
- * Url.toSafeTemplate('/user/{monetary-account-id}') // '/user/{monetaryAccountId}'
221
- */
222
- static toSafeTemplate(path) {
223
- return path.replace(/\{([^}]+)\}/g, (_, name) => `{${transformParam(name)}}`);
224
- }
225
- /**
226
- * Converts an OpenAPI/Swagger path to a TypeScript template literal string.
227
- * `prefix` is prepended inside the literal, and `replacer` transforms each parameter name.
228
- *
229
- * @example
230
- * Url.toTemplateString('/pet/{petId}') // '`/pet/${petId}`'
231
- *
232
- * @example
233
- * Url.toTemplateString('/pet/{petId}', { prefix: 'https://api' }) // '`https://api/pet/${petId}`'
234
- */
235
- static toTemplateString(path, { prefix, replacer } = {}) {
236
- const result = path.split(/\{([^}]+)\}/).map((part, i) => {
237
- if (i % 2 === 0) return part;
238
- const param = transformParam(part);
239
- return `\${${replacer ? replacer(param) : param}}`;
240
- }).join("");
241
- return `\`${prefix ?? ""}${result}\``;
242
- }
243
- /**
244
- * Converts an OpenAPI/Swagger path to a template literal that reads each parameter off the
245
- * grouped `path` request option, e.g. `/pet/{petId}` becomes `` `/pet/${path.petId}` ``. Parameter
246
- * names match the generated `path` type, and `prefix` is prepended inside the literal. Shared by
247
- * the client and cypress generators that pass a grouped `path` object.
248
- *
249
- * @example
250
- * Url.toGroupedTemplateString('/pet/{petId}') // '`/pet/${path.petId}`'
251
- */
252
- static toGroupedTemplateString(path, { prefix } = {}) {
253
- return Url.toTemplateString(path, {
254
- prefix,
255
- replacer: (name) => `path.${name}`
256
- });
257
- }
258
- };
259
- //#endregion
260
37
  //#region ../../internals/shared/src/params.ts
261
38
  /**
262
39
  * Drops parameters that share the same name, keeping the first.
@@ -295,11 +72,30 @@ function operationFileEntry(node, name, extname = ".ts") {
295
72
  path: node.path
296
73
  };
297
74
  }
75
+ /**
76
+ * Resolves a dependency plugin's generated file for `node.operationId`, cached in `cache` (the
77
+ * current node's `ctx.cache`) under the resolver's own plugin name. Several dependents reading the
78
+ * same dependency for the same operation in one pass (a query plugin's several hook generators, the
79
+ * MCP handler, ...) share one computed name and path instead of each calling `resolver.file` again.
80
+ *
81
+ * @example Cache `plugin-ts`'s file for the current operation
82
+ * ```ts
83
+ * const fileTs = resolveDependencyOperationFile({ cache: ctx.cache, node, resolver: tsResolver, root, output })
84
+ * ```
85
+ */
86
+ function resolveDependencyOperationFile(options) {
87
+ const { cache, node, resolver, root, output, group } = options;
88
+ return cache.ensureItem(`${resolver.pluginName}:operationFile`, () => resolver.file({
89
+ ...operationFileEntry(node, node.operationId),
90
+ root,
91
+ output,
92
+ group: group ?? void 0
93
+ }));
94
+ }
298
95
  function getOperationLink(node, link) {
299
96
  if (!link) return null;
300
97
  if (typeof link === "function") return link(node) ?? null;
301
- if (link === "urlPath") return node.path ? `{@link ${Url.toPath(node.path)}}` : null;
302
- return node.path ? `{@link ${node.path.replaceAll("{", ":").replaceAll("}", "")}}` : null;
98
+ return node.path ? `{@link ${kubb_kit.Url.toPath(node.path)}}` : null;
303
99
  }
304
100
  /**
305
101
  * Derives the shared `ContentTypeInfo` shape from a list of content types, tracking whether several
@@ -389,16 +185,24 @@ function buildOperationComments(node, options = {}) {
389
185
  if (!splitLines) return filteredComments;
390
186
  return filteredComments.flatMap((text) => text.split(/\r?\n/).map((line) => line.trim())).filter((comment) => Boolean(comment));
391
187
  }
188
+ const operationParameterGroupsByNode = /* @__PURE__ */ new WeakMap();
189
+ /**
190
+ * Groups an operation's parameters by location (`path`/`query`/`header`/`cookie`), deduping each
191
+ * group by name. Every plugin generator visiting the same `OperationNode` shares one AST instance
192
+ * (see `KubbDriver`), so the result is cached per node to avoid re-filtering and re-deduping the
193
+ * same parameters once per plugin.
194
+ */
392
195
  function getOperationParameters(node) {
393
- return {
394
- path: dedupeParams(node.parameters.filter((param) => param.in === "path").map((param) => isValidVarName(param.name) ? param : {
395
- ...param,
396
- name: camelCase(param.name)
397
- })),
196
+ const cached = operationParameterGroupsByNode.get(node);
197
+ if (cached) return cached;
198
+ const groups = {
199
+ path: dedupeParams(node.parameters.filter((param) => param.in === "path")),
398
200
  query: dedupeParams(node.parameters.filter((param) => param.in === "query")),
399
201
  header: dedupeParams(node.parameters.filter((param) => param.in === "header")),
400
202
  cookie: dedupeParams(node.parameters.filter((param) => param.in === "cookie"))
401
203
  };
204
+ operationParameterGroupsByNode.set(node, groups);
205
+ return groups;
402
206
  }
403
207
  function getStatusCodeNumber(statusCode) {
404
208
  const code = Number(statusCode);
@@ -460,6 +264,43 @@ function resolveOperationTypeNames(node, resolver, options = {}) {
460
264
  return result;
461
265
  }
462
266
  //#endregion
267
+ //#region ../../internals/utils/src/casing.ts
268
+ /**
269
+ * Shared implementation for camelCase and PascalCase conversion.
270
+ * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)
271
+ * and capitalizes each word according to `pascal`.
272
+ *
273
+ * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
274
+ */
275
+ function toCamelOrPascal(text, pascal) {
276
+ 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) => {
277
+ if (word.length > 1 && word === word.toUpperCase()) return word;
278
+ return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
279
+ }).join("").replace(/[^a-zA-Z0-9]/g, "");
280
+ }
281
+ /**
282
+ * Converts `text` to camelCase.
283
+ *
284
+ * @example Word boundaries
285
+ * `camelCase('hello-world') // 'helloWorld'`
286
+ *
287
+ * @example With a prefix
288
+ * `camelCase('tag', { prefix: 'create' }) // 'createTag'`
289
+ */
290
+ function camelCase(text, { prefix = "", suffix = "" } = {}) {
291
+ return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
292
+ }
293
+ /**
294
+ * Uppercases only the first character of `text`, leaving the rest untouched.
295
+ * Unlike {@link pascalCase} it never re-splits word boundaries or strips characters.
296
+ *
297
+ * @example
298
+ * `capitalize('getPetById') // 'GetPetById'`
299
+ */
300
+ function capitalize(text) {
301
+ return `${text.charAt(0).toUpperCase()}${text.slice(1)}`;
302
+ }
303
+ //#endregion
463
304
  //#region ../../internals/shared/src/group.ts
464
305
  /**
465
306
  * Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the
@@ -579,23 +420,30 @@ function resolveContractClient(options) {
579
420
  * (plugin-fetch or plugin-axios). Returns `null` when no contract plugin is in play (the inline
580
421
  * path). The plugin injects `.kubb/client.ts` at the global output root, the same path consumers
581
422
  * read `RequestConfig` / `ResponseErrorConfig` from.
423
+ *
424
+ * The result is cached in the current node's `cache` (`ctx.cache`) under the client plugin's name,
425
+ * so several dependents reading the same client plugin for one operation in a single pass
426
+ * (react-query's query/mutation/infinite generators, vue-query, swr, the MCP handler, ...) share
427
+ * one computed result instead of each re-deriving the name and path.
582
428
  */
583
429
  function resolveClientOperation(options) {
584
- const { clientPlugin, driver, node, root, output } = options;
430
+ const { clientPlugin, driver, node, root, output, cache } = options;
585
431
  if (!clientPlugin) return null;
586
- const resolver = driver.getResolver(clientPlugin.pluginName);
587
- const plugin = driver.getPlugin(clientPlugin.pluginName);
588
- const file = resolver.file({
589
- ...operationFileEntry(node, node.operationId),
590
- root,
591
- output: plugin?.options?.output ?? output,
592
- group: plugin?.options?.group ?? void 0
432
+ return cache.ensureItem(`${clientPlugin.pluginName}:clientOperation`, () => {
433
+ const resolver = driver.getResolver(clientPlugin.pluginName);
434
+ const plugin = driver.getPlugin(clientPlugin.pluginName);
435
+ const file = resolver.file({
436
+ ...operationFileEntry(node, node.operationId),
437
+ root,
438
+ output: plugin?.options?.output ?? output,
439
+ group: plugin?.options?.group ?? void 0
440
+ });
441
+ return {
442
+ name: resolver.name(node.operationId),
443
+ path: file.path,
444
+ clientPath: node_path.default.resolve(root, ".kubb/client.ts")
445
+ };
593
446
  });
594
- return {
595
- name: resolver.name(node.operationId),
596
- path: file.path,
597
- clientPath: node_path.default.resolve(root, ".kubb/client.ts")
598
- };
599
447
  }
600
448
  //#endregion
601
449
  //#region ../../internals/tanstack-query/src/utils.ts
@@ -663,14 +511,16 @@ function buildGroupedRequestParam(node, options) {
663
511
  */
664
512
  function buildQueryOptionsParams(node, options) {
665
513
  const { resolver, memberTypeWrapper } = options;
666
- return (0, _kubb_plugin_ts.createFunctionParameters)({ params: [buildGroupedRequestParam(node, {
514
+ const groupedParam = buildGroupedRequestParam(node, {
667
515
  resolver,
668
516
  memberTypeWrapper
669
- }), (0, _kubb_plugin_ts.createFunctionParameter)({
517
+ });
518
+ const configParam = (0, _kubb_plugin_ts.createFunctionParameter)({
670
519
  name: "config",
671
520
  type: `Partial<Omit<RequestConfig, 'path' | 'query' | 'body' | 'headers' | 'url'>>`,
672
521
  default: "{}"
673
- })].filter((param) => param !== null) });
522
+ });
523
+ return (0, _kubb_plugin_ts.createFunctionParameters)({ params: [groupedParam, configParam].filter((param) => param !== null) });
674
524
  }
675
525
  /**
676
526
  * Builds the call to a client `<op>` function inside a query/mutation hook body. The function takes
@@ -728,6 +578,29 @@ function resolveMutationConfig(mutation, options) {
728
578
  };
729
579
  }
730
580
  /**
581
+ * Classifies an operation as a query or a mutation from the resolved `query` / `mutation` method lists.
582
+ * `query: false` still marks the operation as a query so the query-family generators keep matching it,
583
+ * and a method already claimed by `query` never counts as a mutation.
584
+ */
585
+ function classifyOperation(node, { query, mutation }) {
586
+ const isQuery = query === false || !!query && query.methods.some((method) => node.method.toLowerCase() === method.toLowerCase());
587
+ const queryMethods = new Set(query ? query.methods : []);
588
+ return {
589
+ isQuery,
590
+ isMutation: mutation !== false && !isQuery && (mutation ? mutation.methods : []).some((method) => !queryMethods.has(method) && node.method.toLowerCase() === method.toLowerCase())
591
+ };
592
+ }
593
+ /**
594
+ * The request groups a query key is built from, matching `buildQueryKeyParams`. Headers are
595
+ * deliberately absent: they do not identify a cache entry, so the key factory takes no parameter
596
+ * for an operation that only carries headers.
597
+ */
598
+ const queryKeyGroupOrder = [
599
+ "path",
600
+ "query",
601
+ "body"
602
+ ];
603
+ /**
731
604
  * Build QueryKey params as the grouped `{ path, query, body }` object (NO headers, NO config),
732
605
  * typed from the operation's `Options` minus `url`. The query key transformer reads the
733
606
  * grouped `path`/`query`/`body` bindings.
@@ -736,11 +609,7 @@ function buildQueryKeyParams(node, options) {
736
609
  const { resolver } = options;
737
610
  const groupedParam = buildGroupedRequestParam(node, {
738
611
  resolver,
739
- keys: [
740
- "path",
741
- "query",
742
- "body"
743
- ]
612
+ keys: queryKeyGroupOrder
744
613
  });
745
614
  return (0, _kubb_plugin_ts.createFunctionParameters)({ params: groupedParam ? [groupedParam] : [] });
746
615
  }
@@ -749,7 +618,7 @@ function buildQueryKeyParams(node, options) {
749
618
  const declarationPrinter$4 = (0, _kubb_plugin_ts.functionPrinter)({ mode: "declaration" });
750
619
  const mutationKeyTransformer = ({ node }) => {
751
620
  if (!node.path) return [];
752
- return [`{ url: '${Url.toPath(node.path)}' }`];
621
+ return [`{ url: '${kubb_kit.Url.toPath(node.path)}' }`];
753
622
  };
754
623
  function MutationKey$1({ name, node, transformer }) {
755
624
  const paramsNode = (0, _kubb_plugin_ts.createFunctionParameters)({ params: [] });
@@ -834,7 +703,7 @@ const queryKeyTransformer = ({ node }) => {
834
703
  const hasQueryParams = getOperationParameters(node).query.length > 0;
835
704
  const hasRequestBody = !!node.requestBody?.content?.[0]?.schema;
836
705
  return [
837
- hasPathParams ? `{ url: '${Url.toPath(node.path)}', params: path }` : `{ url: '${Url.toPath(node.path)}' }`,
706
+ hasPathParams ? `{ url: '${kubb_kit.Url.toPath(node.path)}', params: path }` : `{ url: '${kubb_kit.Url.toPath(node.path)}' }`,
838
707
  hasQueryParams ? "...(query ? [query] : [])" : null,
839
708
  hasRequestBody ? "...(body ? [body] : [])" : null
840
709
  ].filter(Boolean);
@@ -874,10 +743,12 @@ function buildMutationParamsNode(node, options) {
874
743
  const { mutationKeyTypeName, mutationArgTypeName, resolver } = options;
875
744
  const responseName = resolver.response.response(node);
876
745
  const errorNames = resolveErrorNames(node, resolver);
746
+ const TData = responseName;
747
+ const TError = `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(" | ") : "Error"}>`;
877
748
  return (0, _kubb_plugin_ts.createFunctionParameters)({ params: [(0, _kubb_plugin_ts.createFunctionParameter)({
878
749
  name: "options",
879
750
  type: `{
880
- mutation?: SWRMutationConfiguration<${responseName}, ${`ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(" | ") : "Error"}>`}, ${mutationKeyTypeName} | null, ${mutationArgTypeName}> & { throwOnError?: boolean },
751
+ mutation?: SWRMutationConfiguration<${TData}, ${TError}, ${mutationKeyTypeName} | null, ${mutationArgTypeName}> & { throwOnError?: boolean },
881
752
  client?: ${buildRequestConfigType(node)},
882
753
  shouldFetch?: boolean,
883
754
  }`,
@@ -894,11 +765,10 @@ function Mutation({ name, clientName, mutationKeyName, mutationKeyTypeName, muta
894
765
  const groupedParamsNode = (0, _kubb_plugin_ts.createFunctionParameters)({ params: groupedParam ? [groupedParam] : [] });
895
766
  const argTypeBody = hasMutationParams ? tsResolver.response.options(node) : "";
896
767
  const argBindingStr = hasMutationParams ? callPrinter$1.print(groupedParamsNode) ?? "" : "";
897
- const mutationFnBody = `const { data } = await ${buildClientCall(node, {
768
+ const mutationFnBody = `return ${buildClientCall(node, {
898
769
  clientName,
899
770
  signal: false
900
- })}
901
- return data`;
771
+ })}.unwrap()`;
902
772
  const generics = [
903
773
  TData,
904
774
  TError,
@@ -972,17 +842,20 @@ function buildQueryParamsNode(node, options) {
972
842
  const { resolver } = options;
973
843
  const responseName = resolver.response.response(node);
974
844
  const errorNames = resolveErrorNames(node, resolver);
845
+ const TData = responseName;
846
+ const TError = `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(" | ") : "Error"}>`;
975
847
  const optionsParam = (0, _kubb_plugin_ts.createFunctionParameter)({
976
848
  name: "options",
977
849
  type: `{
978
- query?: SWRConfiguration<${[responseName, `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(" | ") : "Error"}>`].join(", ")}>,
850
+ query?: SWRConfiguration<${[TData, TError].join(", ")}>,
979
851
  client?: ${buildClientOptionType()},
980
852
  shouldFetch?: boolean,
981
853
  immutable?: boolean
982
854
  }`,
983
855
  default: "{}"
984
856
  });
985
- return (0, _kubb_plugin_ts.createFunctionParameters)({ params: [buildGroupedRequestParam(node, { resolver }), optionsParam].filter((param) => param !== null) });
857
+ const groupedParam = buildGroupedRequestParam(node, { resolver });
858
+ return (0, _kubb_plugin_ts.createFunctionParameters)({ params: [groupedParam, optionsParam].filter((param) => param !== null) });
986
859
  }
987
860
  function Query({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, tsResolver }) {
988
861
  const responseName = tsResolver.response.response(node);
@@ -1034,11 +907,10 @@ const declarationPrinter = (0, _kubb_plugin_ts.functionPrinter)({ mode: "declara
1034
907
  function QueryOptions({ name, clientName, node, tsResolver }) {
1035
908
  const paramsNode = buildQueryOptionsParams(node, { resolver: tsResolver });
1036
909
  const paramsSignature = declarationPrinter.print(paramsNode) ?? "";
1037
- const fetcherBody = `const { data } = await ${buildClientCall(node, {
910
+ const fetcherBody = `return ${buildClientCall(node, {
1038
911
  clientName,
1039
912
  signal: false
1040
- })}
1041
- return data`;
913
+ })}.unwrap()`;
1042
914
  return /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Source, {
1043
915
  name,
1044
916
  isExportable: true,
@@ -1074,16 +946,19 @@ const mutationGenerator = (0, kubb_kit.defineGenerator)({
1074
946
  const pluginTs = driver.getPlugin(_kubb_plugin_ts.pluginTsName);
1075
947
  if (!pluginTs) return null;
1076
948
  const tsResolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
1077
- const isQuery = query === false || !!query && query.methods.some((method) => node.method.toLowerCase() === method.toLowerCase());
1078
- const queryMethods = new Set(query ? query.methods : []);
1079
- if (!(mutation !== false && !isQuery && (mutation ? mutation.methods : []).some((method) => !queryMethods.has(method) && node.method.toLowerCase() === method.toLowerCase()))) return null;
949
+ const { isMutation } = classifyOperation(node, {
950
+ query,
951
+ mutation
952
+ });
953
+ if (!isMutation) return null;
1080
954
  const importPath = mutation ? mutation.importPath : "swr/mutation";
1081
955
  const contractOp = resolveClientOperation({
1082
956
  clientPlugin: { pluginName: client.pluginName },
1083
957
  driver,
1084
958
  node,
1085
959
  root,
1086
- output
960
+ output,
961
+ cache: ctx.cache
1087
962
  });
1088
963
  if (!contractOp) return null;
1089
964
  const mutationHookName = resolver.mutation.name(node);
@@ -1100,11 +975,10 @@ const mutationGenerator = (0, kubb_kit.defineGenerator)({
1100
975
  output,
1101
976
  group
1102
977
  }),
1103
- fileTs: tsResolver.file({
1104
- name: node.operationId,
1105
- extname: ".ts",
1106
- tag: node.tags[0] ?? "default",
1107
- path: node.path,
978
+ fileTs: resolveDependencyOperationFile({
979
+ cache: ctx.cache,
980
+ node,
981
+ resolver: tsResolver,
1108
982
  root,
1109
983
  output: pluginTs.options?.output ?? output,
1110
984
  group: pluginTs.options?.group
@@ -1195,18 +1069,23 @@ const queryGenerator = (0, kubb_kit.defineGenerator)({
1195
1069
  operation(node, ctx) {
1196
1070
  if (!kubb_kit.ast.isHttpOperationNode(node)) return null;
1197
1071
  const { config, driver, resolver, root } = ctx;
1198
- const { output, query, client, group } = ctx.options;
1072
+ const { output, query, mutation, client, group } = ctx.options;
1199
1073
  const pluginTs = driver.getPlugin(_kubb_plugin_ts.pluginTsName);
1200
1074
  if (!pluginTs) return null;
1201
1075
  const tsResolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
1202
- if (!(query === false || !!query && query.methods.some((method) => node.method.toLowerCase() === method.toLowerCase()))) return null;
1076
+ const { isQuery } = classifyOperation(node, {
1077
+ query,
1078
+ mutation
1079
+ });
1080
+ if (!isQuery) return null;
1203
1081
  const importPath = query ? query.importPath : "swr";
1204
1082
  const contractOp = resolveClientOperation({
1205
1083
  clientPlugin: { pluginName: client.pluginName },
1206
1084
  driver,
1207
1085
  node,
1208
1086
  root,
1209
- output
1087
+ output,
1088
+ cache: ctx.cache
1210
1089
  });
1211
1090
  if (!contractOp) return null;
1212
1091
  const queryName = resolver.query.name(node);
@@ -1223,11 +1102,10 @@ const queryGenerator = (0, kubb_kit.defineGenerator)({
1223
1102
  output,
1224
1103
  group
1225
1104
  }),
1226
- fileTs: tsResolver.file({
1227
- name: node.operationId,
1228
- extname: ".ts",
1229
- tag: node.tags[0] ?? "default",
1230
- path: node.path,
1105
+ fileTs: resolveDependencyOperationFile({
1106
+ cache: ctx.cache,
1107
+ node,
1108
+ resolver: tsResolver,
1231
1109
  root,
1232
1110
  output: pluginTs.options?.output ?? output,
1233
1111
  group: pluginTs.options?.group