@kubb/plugin-vue-query 5.0.0-beta.99 → 5.1.0-canary.20260819T202658

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,257 +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/strings.ts
194
- /**
195
- * Renders a dotted path or string array as an optional-chaining accessor expression rooted at
196
- * `accessor`. Returns `null` for an empty path.
197
- *
198
- * @example
199
- * ```ts
200
- * getNestedAccessor('pagination.next.id', 'lastPage')
201
- * // "lastPage?.['pagination']?.['next']?.['id']"
202
- * ```
203
- */
204
- function getNestedAccessor(param, accessor) {
205
- const parts = Array.isArray(param) ? param : param.split(".");
206
- if (parts.length === 0 || parts.length === 1 && parts[0] === "") return null;
207
- return `${accessor}?.['${`${parts.join("']?.['")}']`}`;
208
- }
209
- //#endregion
210
- //#region ../../internals/utils/src/url.ts
211
- /**
212
- * Keeps the OpenAPI parameter name as-is when it is already a valid JS identifier, and
213
- * camelCases it only enough to become one otherwise (for example a hyphenated path segment).
214
- */
215
- function transformParam(raw) {
216
- return isValidVarName(raw) ? raw : camelCase(raw);
217
- }
218
- /**
219
- * Helpers for OpenAPI/Swagger paths.
220
- */
221
- var Url = class Url {
222
- /**
223
- * Converts an OpenAPI/Swagger path to Express-style colon syntax.
224
- *
225
- * @example
226
- * Url.toPath('/pet/{petId}') // '/pet/:petId'
227
- */
228
- static toPath(path) {
229
- return path.replace(/\{([^}]+)\}/g, ":$1");
230
- }
231
- /**
232
- * Rewrites OpenAPI placeholder names while keeping the `{...}` braces, so the generated `url`
233
- * literal aligns with the grouped `path` request option that the runtime client interpolates by
234
- * key.
235
- *
236
- * @example
237
- * Url.toSafeTemplate('/user/{monetary-account-id}') // '/user/{monetaryAccountId}'
238
- */
239
- static toSafeTemplate(path) {
240
- return path.replace(/\{([^}]+)\}/g, (_, name) => `{${transformParam(name)}}`);
241
- }
242
- /**
243
- * Converts an OpenAPI/Swagger path to a TypeScript template literal string.
244
- * `prefix` is prepended inside the literal, and `replacer` transforms each parameter name.
245
- *
246
- * @example
247
- * Url.toTemplateString('/pet/{petId}') // '`/pet/${petId}`'
248
- *
249
- * @example
250
- * Url.toTemplateString('/pet/{petId}', { prefix: 'https://api' }) // '`https://api/pet/${petId}`'
251
- */
252
- static toTemplateString(path, { prefix, replacer } = {}) {
253
- const result = path.split(/\{([^}]+)\}/).map((part, i) => {
254
- if (i % 2 === 0) return part;
255
- const param = transformParam(part);
256
- return `\${${replacer ? replacer(param) : param}}`;
257
- }).join("");
258
- return `\`${prefix ?? ""}${result}\``;
259
- }
260
- /**
261
- * Converts an OpenAPI/Swagger path to a template literal that reads each parameter off the
262
- * grouped `path` request option, e.g. `/pet/{petId}` becomes `` `/pet/${path.petId}` ``. Parameter
263
- * names match the generated `path` type, and `prefix` is prepended inside the literal. Shared by
264
- * the client and cypress generators that pass a grouped `path` object.
265
- *
266
- * @example
267
- * Url.toGroupedTemplateString('/pet/{petId}') // '`/pet/${path.petId}`'
268
- */
269
- static toGroupedTemplateString(path, { prefix } = {}) {
270
- return Url.toTemplateString(path, {
271
- prefix,
272
- replacer: (name) => `path.${name}`
273
- });
274
- }
275
- };
276
- //#endregion
277
37
  //#region ../../internals/shared/src/params.ts
278
38
  /**
279
39
  * Drops parameters that share the same name, keeping the first.
@@ -312,11 +72,30 @@ function operationFileEntry(node, name, extname = ".ts") {
312
72
  path: node.path
313
73
  };
314
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
+ }
315
95
  function getOperationLink(node, link) {
316
96
  if (!link) return null;
317
97
  if (typeof link === "function") return link(node) ?? null;
318
- if (link === "urlPath") return node.path ? `{@link ${Url.toPath(node.path)}}` : null;
319
- return node.path ? `{@link ${node.path.replaceAll("{", ":").replaceAll("}", "")}}` : null;
98
+ return node.path ? `{@link ${kubb_kit.Url.toPath(node.path)}}` : null;
320
99
  }
321
100
  /**
322
101
  * Derives the shared `ContentTypeInfo` shape from a list of content types, tracking whether several
@@ -406,16 +185,24 @@ function buildOperationComments(node, options = {}) {
406
185
  if (!splitLines) return filteredComments;
407
186
  return filteredComments.flatMap((text) => text.split(/\r?\n/).map((line) => line.trim())).filter((comment) => Boolean(comment));
408
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
+ */
409
195
  function getOperationParameters(node) {
410
- return {
411
- path: dedupeParams(node.parameters.filter((param) => param.in === "path").map((param) => isValidVarName(param.name) ? param : {
412
- ...param,
413
- name: camelCase(param.name)
414
- })),
196
+ const cached = operationParameterGroupsByNode.get(node);
197
+ if (cached) return cached;
198
+ const groups = {
199
+ path: dedupeParams(node.parameters.filter((param) => param.in === "path")),
415
200
  query: dedupeParams(node.parameters.filter((param) => param.in === "query")),
416
201
  header: dedupeParams(node.parameters.filter((param) => param.in === "header")),
417
202
  cookie: dedupeParams(node.parameters.filter((param) => param.in === "cookie"))
418
203
  };
204
+ operationParameterGroupsByNode.set(node, groups);
205
+ return groups;
419
206
  }
420
207
  function getStatusCodeNumber(statusCode) {
421
208
  const code = Number(statusCode);
@@ -480,6 +267,60 @@ function resolveOperationTypeNames(node, resolver, options = {}) {
480
267
  return result;
481
268
  }
482
269
  //#endregion
270
+ //#region ../../internals/utils/src/casing.ts
271
+ /**
272
+ * Shared implementation for camelCase and PascalCase conversion.
273
+ * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)
274
+ * and capitalizes each word according to `pascal`.
275
+ *
276
+ * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
277
+ */
278
+ function toCamelOrPascal(text, pascal) {
279
+ 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) => {
280
+ if (word.length > 1 && word === word.toUpperCase()) return word;
281
+ return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
282
+ }).join("").replace(/[^a-zA-Z0-9]/g, "");
283
+ }
284
+ /**
285
+ * Converts `text` to camelCase.
286
+ *
287
+ * @example Word boundaries
288
+ * `camelCase('hello-world') // 'helloWorld'`
289
+ *
290
+ * @example With a prefix
291
+ * `camelCase('tag', { prefix: 'create' }) // 'createTag'`
292
+ */
293
+ function camelCase(text, { prefix = "", suffix = "" } = {}) {
294
+ return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
295
+ }
296
+ /**
297
+ * Uppercases only the first character of `text`, leaving the rest untouched.
298
+ * Unlike {@link pascalCase} it never re-splits word boundaries or strips characters.
299
+ *
300
+ * @example
301
+ * `capitalize('getPetById') // 'GetPetById'`
302
+ */
303
+ function capitalize(text) {
304
+ return `${text.charAt(0).toUpperCase()}${text.slice(1)}`;
305
+ }
306
+ //#endregion
307
+ //#region ../../internals/utils/src/strings.ts
308
+ /**
309
+ * Renders a dotted path or string array as an optional-chaining accessor expression rooted at
310
+ * `accessor`. Returns `null` for an empty path.
311
+ *
312
+ * @example
313
+ * ```ts
314
+ * getNestedAccessor('pagination.next.id', 'lastPage')
315
+ * // "lastPage?.['pagination']?.['next']?.['id']"
316
+ * ```
317
+ */
318
+ function getNestedAccessor(param, accessor) {
319
+ const parts = Array.isArray(param) ? param : param.split(".");
320
+ if (parts.length === 0 || parts.length === 1 && parts[0] === "") return null;
321
+ return `${accessor}?.['${`${parts.join("']?.['")}']`}`;
322
+ }
323
+ //#endregion
483
324
  //#region ../../internals/shared/src/group.ts
484
325
  /**
485
326
  * Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the
@@ -589,14 +430,16 @@ function buildGroupedRequestParam(node, options) {
589
430
  */
590
431
  function buildQueryOptionsParams(node, options) {
591
432
  const { resolver, memberTypeWrapper } = options;
592
- return (0, _kubb_plugin_ts.createFunctionParameters)({ params: [buildGroupedRequestParam(node, {
433
+ const groupedParam = buildGroupedRequestParam(node, {
593
434
  resolver,
594
435
  memberTypeWrapper
595
- }), (0, _kubb_plugin_ts.createFunctionParameter)({
436
+ });
437
+ const configParam = (0, _kubb_plugin_ts.createFunctionParameter)({
596
438
  name: "config",
597
439
  type: `Partial<Omit<RequestConfig, 'path' | 'query' | 'body' | 'headers' | 'url'>>`,
598
440
  default: "{}"
599
- })].filter((param) => param !== null) });
441
+ });
442
+ return (0, _kubb_plugin_ts.createFunctionParameters)({ params: [groupedParam, configParam].filter((param) => param !== null) });
600
443
  }
601
444
  /**
602
445
  * Builds the call to a client `<op>` function inside a query/mutation hook body. The function takes
@@ -694,6 +537,19 @@ function resolveMutationConfig(mutation, options) {
694
537
  };
695
538
  }
696
539
  /**
540
+ * Classifies an operation as a query or a mutation from the resolved `query` / `mutation` method lists.
541
+ * `query: false` still marks the operation as a query so the query-family generators keep matching it,
542
+ * and a method already claimed by `query` never counts as a mutation.
543
+ */
544
+ function classifyOperation(node, { query, mutation }) {
545
+ const isQuery = query === false || !!query && query.methods.some((method) => node.method.toLowerCase() === method.toLowerCase());
546
+ const queryMethods = new Set(query ? query.methods : []);
547
+ return {
548
+ isQuery,
549
+ isMutation: mutation !== false && !isQuery && (mutation ? mutation.methods : []).some((method) => !queryMethods.has(method) && node.method.toLowerCase() === method.toLowerCase())
550
+ };
551
+ }
552
+ /**
697
553
  * Applies the shared infinite-query defaults during plugin setup: a falsy value disables infinite
698
554
  * queries, and an object merges over `queryParam: 'id'` and `initialPageParam: 0` with the cursor
699
555
  * paths cleared.
@@ -790,7 +646,7 @@ __name(InfiniteQueryOptions$1, "InfiniteQueryOptions");
790
646
  const declarationPrinter$6 = (0, _kubb_plugin_ts.functionPrinter)({ mode: "declaration" });
791
647
  const mutationKeyTransformer = ({ node }) => {
792
648
  if (!node.path) return [];
793
- return [`{ url: '${Url.toPath(node.path)}' }`];
649
+ return [`{ url: '${kubb_kit.Url.toPath(node.path)}' }`];
794
650
  };
795
651
  function MutationKey({ name, node, transformer }) {
796
652
  const paramsNode = (0, _kubb_plugin_ts.createFunctionParameters)({ params: [] });
@@ -872,7 +728,7 @@ const queryKeyTransformer = ({ node }) => {
872
728
  const hasQueryParams = getOperationParameters(node).query.length > 0;
873
729
  const hasRequestBody = !!node.requestBody?.content?.[0]?.schema;
874
730
  return [
875
- hasPathParams ? `{ url: '${Url.toPath(node.path)}', params: path }` : `{ url: '${Url.toPath(node.path)}' }`,
731
+ hasPathParams ? `{ url: '${kubb_kit.Url.toPath(node.path)}', params: path }` : `{ url: '${kubb_kit.Url.toPath(node.path)}' }`,
876
732
  hasQueryParams ? "...(query ? [query] : [])" : null,
877
733
  hasRequestBody ? "...(body ? [body] : [])" : null
878
734
  ].filter(Boolean);
@@ -966,23 +822,30 @@ function resolveContractClient(options) {
966
822
  * (plugin-fetch or plugin-axios). Returns `null` when no contract plugin is in play (the inline
967
823
  * path). The plugin injects `.kubb/client.ts` at the global output root, the same path consumers
968
824
  * read `RequestConfig` / `ResponseErrorConfig` from.
825
+ *
826
+ * The result is cached in the current node's `cache` (`ctx.cache`) under the client plugin's name,
827
+ * so several dependents reading the same client plugin for one operation in a single pass
828
+ * (react-query's query/mutation/infinite generators, vue-query, swr, the MCP handler, ...) share
829
+ * one computed result instead of each re-deriving the name and path.
969
830
  */
970
831
  function resolveClientOperation(options) {
971
- const { clientPlugin, driver, node, root, output } = options;
832
+ const { clientPlugin, driver, node, root, output, cache } = options;
972
833
  if (!clientPlugin) return null;
973
- const resolver = driver.getResolver(clientPlugin.pluginName);
974
- const plugin = driver.getPlugin(clientPlugin.pluginName);
975
- const file = resolver.file({
976
- ...operationFileEntry(node, node.operationId),
977
- root,
978
- output: plugin?.options?.output ?? output,
979
- group: plugin?.options?.group ?? void 0
834
+ return cache.ensureItem(`${clientPlugin.pluginName}:clientOperation`, () => {
835
+ const resolver = driver.getResolver(clientPlugin.pluginName);
836
+ const plugin = driver.getPlugin(clientPlugin.pluginName);
837
+ const file = resolver.file({
838
+ ...operationFileEntry(node, node.operationId),
839
+ root,
840
+ output: plugin?.options?.output ?? output,
841
+ group: plugin?.options?.group ?? void 0
842
+ });
843
+ return {
844
+ name: resolver.name(node.operationId),
845
+ path: file.path,
846
+ clientPath: node_path.default.resolve(root, ".kubb/client.ts")
847
+ };
980
848
  });
981
- return {
982
- name: resolver.name(node.operationId),
983
- path: file.path,
984
- clientPath: node_path.default.resolve(root, ".kubb/client.ts")
985
- };
986
849
  }
987
850
  //#endregion
988
851
  //#region src/utils.ts
@@ -1106,10 +969,11 @@ function buildInfiniteQueryParamsNode(node, options) {
1106
969
  }`,
1107
970
  default: "{}"
1108
971
  });
1109
- return (0, _kubb_plugin_ts.createFunctionParameters)({ params: [buildGroupedRequestParam(node, {
972
+ const groupedParam = buildGroupedRequestParam(node, {
1110
973
  resolver,
1111
974
  memberTypeWrapper: maybeRefOrGetter
1112
- }), optionsParam].filter((param) => param !== null) });
975
+ });
976
+ return (0, _kubb_plugin_ts.createFunctionParameters)({ params: [groupedParam, optionsParam].filter((param) => param !== null) });
1113
977
  }
1114
978
  function InfiniteQuery({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, tsResolver }) {
1115
979
  const { TData, TError } = buildResponseTypes(node, tsResolver);
@@ -1178,13 +1042,14 @@ function resolveMutationRequestType(node, resolver) {
1178
1042
  function buildMutationParamsNode(node, options) {
1179
1043
  const { resolver } = options;
1180
1044
  const { TData, TError } = buildResponseTypes(node, resolver);
1045
+ const TRequest = resolveMutationRequestType(node, resolver);
1181
1046
  return (0, _kubb_plugin_ts.createFunctionParameters)({ params: [(0, _kubb_plugin_ts.createFunctionParameter)({
1182
1047
  name: "options",
1183
1048
  type: `{
1184
1049
  mutation?: MutationObserverOptions<${[
1185
1050
  TData,
1186
1051
  TError,
1187
- resolveMutationRequestType(node, resolver),
1052
+ TRequest,
1188
1053
  "TContext"
1189
1054
  ].join(", ")}> & { client?: QueryClient },
1190
1055
  client?: ${buildRequestConfigType(node)},
@@ -1258,10 +1123,11 @@ function buildQueryParamsNode(node, options) {
1258
1123
  }`,
1259
1124
  default: "{}"
1260
1125
  });
1261
- return (0, _kubb_plugin_ts.createFunctionParameters)({ params: [buildGroupedRequestParam(node, {
1126
+ const groupedParam = buildGroupedRequestParam(node, {
1262
1127
  resolver,
1263
1128
  memberTypeWrapper: maybeRefOrGetter
1264
- }), optionsParam].filter((param) => param !== null) });
1129
+ });
1130
+ return (0, _kubb_plugin_ts.createFunctionParameters)({ params: [groupedParam, optionsParam].filter((param) => param !== null) });
1265
1131
  }
1266
1132
  function Query({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, tsResolver }) {
1267
1133
  const { TData, TError } = buildResponseTypes(node, tsResolver);
@@ -1309,9 +1175,9 @@ function Query({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, t
1309
1175
  //#region src/generators/infiniteQueryGenerator.tsx
1310
1176
  /**
1311
1177
  * Built-in generator for `useInfiniteQuery` composables. Enabled when
1312
- * `pluginVueQuery({ infinite: { ... } })`. Emits one `useFooInfiniteQuery`
1313
- * composable per query operation, wiring the configured cursor path into
1314
- * TanStack Query's cursor-based pagination.
1178
+ * `pluginVueQuery({ infinite: { ... }, hooks: true })`. Emits one
1179
+ * `useFooInfiniteQuery` composable per query operation, wiring the
1180
+ * configured cursor path into TanStack Query's cursor-based pagination.
1315
1181
  */
1316
1182
  const infiniteQueryGenerator = (0, kubb_kit.defineGenerator)({
1317
1183
  name: "vue-query-infinite",
@@ -1323,11 +1189,12 @@ const infiniteQueryGenerator = (0, kubb_kit.defineGenerator)({
1323
1189
  const pluginTs = driver.getPlugin(_kubb_plugin_ts.pluginTsName);
1324
1190
  if (!pluginTs) return null;
1325
1191
  const tsResolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
1326
- const isQuery = query === false || !!query && query.methods.some((method) => node.method.toLowerCase() === method.toLowerCase());
1327
- const queryMethods = new Set(query ? query.methods : []);
1328
- const isMutation = mutation !== false && !isQuery && (mutation ? mutation.methods : []).some((method) => !queryMethods.has(method) && node.method.toLowerCase() === method.toLowerCase());
1192
+ const { isQuery, isMutation } = classifyOperation(node, {
1193
+ query,
1194
+ mutation
1195
+ });
1329
1196
  const infiniteOptions = infinite && typeof infinite === "object" ? infinite : null;
1330
- if (!isQuery || isMutation || !infiniteOptions) return null;
1197
+ if (!isQuery || isMutation || !infiniteOptions || !hooks) return null;
1331
1198
  const normalizeKey = (key) => key.replace(/\?$/, "");
1332
1199
  const queryParamKeys = getOperationParameters(node).query.map((p) => p.name);
1333
1200
  if (!(infiniteOptions.queryParam ? queryParamKeys.some((k) => normalizeKey(k) === infiniteOptions.queryParam) : false)) return null;
@@ -1337,7 +1204,8 @@ const infiniteQueryGenerator = (0, kubb_kit.defineGenerator)({
1337
1204
  driver,
1338
1205
  node,
1339
1206
  root,
1340
- output
1207
+ output,
1208
+ cache: ctx.cache
1341
1209
  });
1342
1210
  if (!contractOp) return null;
1343
1211
  const queryName = resolver.infiniteQuery.name(node);
@@ -1351,15 +1219,20 @@ const infiniteQueryGenerator = (0, kubb_kit.defineGenerator)({
1351
1219
  output,
1352
1220
  group: group ?? void 0
1353
1221
  }),
1354
- fileTs: tsResolver.file({
1355
- ...operationFileEntry(node, node.operationId),
1222
+ fileTs: resolveDependencyOperationFile({
1223
+ cache: ctx.cache,
1224
+ node,
1225
+ resolver: tsResolver,
1356
1226
  root,
1357
1227
  output: pluginTs.options?.output ?? output,
1358
- group: pluginTs.options?.group ?? void 0
1228
+ group: pluginTs.options?.group
1359
1229
  })
1360
1230
  };
1361
- const rawQueryParams = getOperationParameters(node).query;
1362
- const queryParamsTypeName = rawQueryParams.length > 0 && tsResolver.param.query(node, rawQueryParams[0]) !== tsResolver.param.name(node, rawQueryParams[0]) ? tsResolver.param.query(node, rawQueryParams[0]) : null;
1231
+ const { queryParamsTypeName } = resolvePageParamType(node, {
1232
+ resolver: tsResolver,
1233
+ initialPageParam: infiniteOptions.initialPageParam,
1234
+ queryParam: infiniteOptions.queryParam
1235
+ });
1363
1236
  const importedTypeNames = [
1364
1237
  tsResolver.response.options(node),
1365
1238
  queryParamsTypeName,
@@ -1445,32 +1318,30 @@ const infiniteQueryGenerator = (0, kubb_kit.defineGenerator)({
1445
1318
  initialPageParam: infiniteOptions.initialPageParam,
1446
1319
  queryParam: infiniteOptions.queryParam
1447
1320
  }),
1448
- hooks && /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsxs)(kubb_jsx_jsx_runtime.Fragment, { children: [
1449
- /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
1450
- name: ["useInfiniteQuery"],
1451
- path: importPath
1452
- }),
1453
- /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
1454
- name: [
1455
- "QueryKey",
1456
- "QueryClient",
1457
- "UseInfiniteQueryOptions",
1458
- "UseInfiniteQueryReturnType"
1459
- ],
1460
- path: importPath,
1461
- isTypeOnly: true
1462
- }),
1463
- /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(InfiniteQuery, {
1464
- name: queryName,
1465
- queryOptionsName,
1466
- queryKeyName,
1467
- queryKeyTypeName,
1468
- node,
1469
- tsResolver,
1470
- initialPageParam: infiniteOptions.initialPageParam,
1471
- queryParam: infiniteOptions.queryParam
1472
- })
1473
- ] })
1321
+ /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
1322
+ name: ["useInfiniteQuery"],
1323
+ path: importPath
1324
+ }),
1325
+ /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
1326
+ name: [
1327
+ "QueryKey",
1328
+ "QueryClient",
1329
+ "UseInfiniteQueryOptions",
1330
+ "UseInfiniteQueryReturnType"
1331
+ ],
1332
+ path: importPath,
1333
+ isTypeOnly: true
1334
+ }),
1335
+ /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(InfiniteQuery, {
1336
+ name: queryName,
1337
+ queryOptionsName,
1338
+ queryKeyName,
1339
+ queryKeyTypeName,
1340
+ node,
1341
+ tsResolver,
1342
+ initialPageParam: infiniteOptions.initialPageParam,
1343
+ queryParam: infiniteOptions.queryParam
1344
+ })
1474
1345
  ]
1475
1346
  });
1476
1347
  }
@@ -1492,16 +1363,19 @@ const mutationGenerator = (0, kubb_kit.defineGenerator)({
1492
1363
  const pluginTs = driver.getPlugin(_kubb_plugin_ts.pluginTsName);
1493
1364
  if (!pluginTs) return null;
1494
1365
  const tsResolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
1495
- const isQuery = query === false || !!query && query.methods.some((method) => node.method.toLowerCase() === method.toLowerCase());
1496
- const queryMethods = new Set(query ? query.methods : []);
1497
- if (!(mutation !== false && !isQuery && (mutation ? mutation.methods : []).some((method) => !queryMethods.has(method) && node.method.toLowerCase() === method.toLowerCase()))) return null;
1366
+ const { isMutation } = classifyOperation(node, {
1367
+ query,
1368
+ mutation
1369
+ });
1370
+ if (!isMutation) return null;
1498
1371
  const importPath = mutation ? mutation.importPath : "@tanstack/vue-query";
1499
1372
  const contractOp = resolveClientOperation({
1500
1373
  clientPlugin: { pluginName: client.pluginName },
1501
1374
  driver,
1502
1375
  node,
1503
1376
  root,
1504
- output
1377
+ output,
1378
+ cache: ctx.cache
1505
1379
  });
1506
1380
  if (!contractOp) return null;
1507
1381
  const mutationHookName = resolver.mutation.name(node);
@@ -1514,11 +1388,13 @@ const mutationGenerator = (0, kubb_kit.defineGenerator)({
1514
1388
  output,
1515
1389
  group: group ?? void 0
1516
1390
  }),
1517
- fileTs: tsResolver.file({
1518
- ...operationFileEntry(node, node.operationId),
1391
+ fileTs: resolveDependencyOperationFile({
1392
+ cache: ctx.cache,
1393
+ node,
1394
+ resolver: tsResolver,
1519
1395
  root,
1520
1396
  output: pluginTs.options?.output ?? output,
1521
- group: pluginTs.options?.group ?? void 0
1397
+ group: pluginTs.options?.group
1522
1398
  })
1523
1399
  };
1524
1400
  const importedTypeNames = [tsResolver.response.options(node), ...resolveOperationTypeNames(node, tsResolver, {
@@ -1620,9 +1496,10 @@ const queryGenerator = (0, kubb_kit.defineGenerator)({
1620
1496
  const pluginTs = driver.getPlugin(_kubb_plugin_ts.pluginTsName);
1621
1497
  if (!pluginTs) return null;
1622
1498
  const tsResolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
1623
- const isQuery = query === false || !!query && query.methods.some((method) => node.method.toLowerCase() === method.toLowerCase());
1624
- const queryMethods = new Set(query ? query.methods : []);
1625
- const isMutation = mutation !== false && !isQuery && (mutation ? mutation.methods : []).some((method) => !queryMethods.has(method) && node.method.toLowerCase() === method.toLowerCase());
1499
+ const { isQuery, isMutation } = classifyOperation(node, {
1500
+ query,
1501
+ mutation
1502
+ });
1626
1503
  if (!isQuery || isMutation) return null;
1627
1504
  const importPath = query ? query.importPath : "@tanstack/vue-query";
1628
1505
  const contractOp = resolveClientOperation({
@@ -1630,7 +1507,8 @@ const queryGenerator = (0, kubb_kit.defineGenerator)({
1630
1507
  driver,
1631
1508
  node,
1632
1509
  root,
1633
- output
1510
+ output,
1511
+ cache: ctx.cache
1634
1512
  });
1635
1513
  if (!contractOp) return null;
1636
1514
  const queryName = resolver.query.name(node);
@@ -1644,11 +1522,13 @@ const queryGenerator = (0, kubb_kit.defineGenerator)({
1644
1522
  output,
1645
1523
  group: group ?? void 0
1646
1524
  }),
1647
- fileTs: tsResolver.file({
1648
- ...operationFileEntry(node, node.operationId),
1525
+ fileTs: resolveDependencyOperationFile({
1526
+ cache: ctx.cache,
1527
+ node,
1528
+ resolver: tsResolver,
1649
1529
  root,
1650
1530
  output: pluginTs.options?.output ?? output,
1651
- group: pluginTs.options?.group ?? void 0
1531
+ group: pluginTs.options?.group
1652
1532
  })
1653
1533
  };
1654
1534
  const importedTypeNames = [tsResolver.response.options(node), ...resolveOperationTypeNames(node, tsResolver, {