@kubb/plugin-react-query 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
@@ -19,259 +19,19 @@ var __copyProps = (to, from, except, desc) => {
19
19
  }
20
20
  return to;
21
21
  };
22
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
22
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
23
23
  value: mod,
24
24
  enumerable: true
25
25
  }) : target, mod));
26
26
  //#endregion
27
+ let kubb_kit = require("kubb/kit");
27
28
  let node_path = require("node:path");
28
29
  node_path = __toESM(node_path, 1);
29
- let kubb_kit = require("kubb/kit");
30
30
  let _kubb_plugin_ts = require("@kubb/plugin-ts");
31
31
  let kubb_jsx = require("kubb/jsx");
32
32
  let kubb_jsx_jsx_runtime = require("kubb/jsx/jsx-runtime");
33
33
  let node_fs = require("node:fs");
34
34
  node_fs = __toESM(node_fs, 1);
35
- //#region ../../internals/utils/src/casing.ts
36
- /**
37
- * Shared implementation for camelCase and PascalCase conversion.
38
- * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)
39
- * and capitalizes each word according to `pascal`.
40
- *
41
- * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
42
- */
43
- function toCamelOrPascal(text, pascal) {
44
- 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) => {
45
- if (word.length > 1 && word === word.toUpperCase()) return word;
46
- return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
47
- }).join("").replace(/[^a-zA-Z0-9]/g, "");
48
- }
49
- /**
50
- * Converts `text` to camelCase.
51
- *
52
- * @example Word boundaries
53
- * `camelCase('hello-world') // 'helloWorld'`
54
- *
55
- * @example With a prefix
56
- * `camelCase('tag', { prefix: 'create' }) // 'createTag'`
57
- */
58
- function camelCase(text, { prefix = "", suffix = "" } = {}) {
59
- return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
60
- }
61
- /**
62
- * Uppercases only the first character of `text`, leaving the rest untouched.
63
- * Unlike {@link pascalCase} it never re-splits word boundaries or strips characters.
64
- *
65
- * @example
66
- * `capitalize('getPetById') // 'GetPetById'`
67
- */
68
- function capitalize(text) {
69
- return `${text.charAt(0).toUpperCase()}${text.slice(1)}`;
70
- }
71
- //#endregion
72
- //#region ../../internals/utils/src/reserved.ts
73
- /**
74
- * JavaScript and Java reserved words.
75
- * @link https://github.com/jonschlinkert/reserved/blob/master/index.js
76
- */
77
- const reservedWords = /* @__PURE__ */ new Set([
78
- "abstract",
79
- "arguments",
80
- "boolean",
81
- "break",
82
- "byte",
83
- "case",
84
- "catch",
85
- "char",
86
- "class",
87
- "const",
88
- "continue",
89
- "debugger",
90
- "default",
91
- "delete",
92
- "do",
93
- "double",
94
- "else",
95
- "enum",
96
- "eval",
97
- "export",
98
- "extends",
99
- "false",
100
- "final",
101
- "finally",
102
- "float",
103
- "for",
104
- "function",
105
- "goto",
106
- "if",
107
- "implements",
108
- "import",
109
- "in",
110
- "instanceof",
111
- "int",
112
- "interface",
113
- "let",
114
- "long",
115
- "native",
116
- "new",
117
- "null",
118
- "package",
119
- "private",
120
- "protected",
121
- "public",
122
- "return",
123
- "short",
124
- "static",
125
- "super",
126
- "switch",
127
- "synchronized",
128
- "this",
129
- "throw",
130
- "throws",
131
- "transient",
132
- "true",
133
- "try",
134
- "typeof",
135
- "var",
136
- "void",
137
- "volatile",
138
- "while",
139
- "with",
140
- "yield",
141
- "Array",
142
- "Date",
143
- "hasOwnProperty",
144
- "Infinity",
145
- "isFinite",
146
- "isNaN",
147
- "isPrototypeOf",
148
- "length",
149
- "Math",
150
- "name",
151
- "NaN",
152
- "Number",
153
- "Object",
154
- "prototype",
155
- "String",
156
- "toString",
157
- "undefined",
158
- "valueOf"
159
- ]);
160
- /**
161
- * Returns `true` when `name` is a syntactically valid JavaScript variable name.
162
- *
163
- * @example
164
- * ```ts
165
- * isValidVarName('status') // true
166
- * isValidVarName('class') // false (reserved word)
167
- * isValidVarName('42foo') // false (starts with digit)
168
- * ```
169
- */
170
- function isValidVarName(name) {
171
- if (!name || reservedWords.has(name)) return false;
172
- return isIdentifier(name);
173
- }
174
- /**
175
- * Returns `true` when `name` is syntactically a valid identifier, ignoring reserved words.
176
- *
177
- * Reserved words and globals (`class`, `name`, `Date`, …) are valid as bare object-literal keys
178
- * even though they are not valid variable names, so use this (not {@link isValidVarName}) when
179
- * deciding whether an object key needs quoting.
180
- *
181
- * @example
182
- * ```ts
183
- * isIdentifier('name') // true
184
- * isIdentifier('x-total')// false
185
- * ```
186
- */
187
- function isIdentifier(name) {
188
- return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
189
- }
190
- //#endregion
191
- //#region ../../internals/utils/src/strings.ts
192
- /**
193
- * Renders a dotted path or string array as an optional-chaining accessor expression rooted at
194
- * `accessor`. Returns `null` for an empty path.
195
- *
196
- * @example
197
- * ```ts
198
- * getNestedAccessor('pagination.next.id', 'lastPage')
199
- * // "lastPage?.['pagination']?.['next']?.['id']"
200
- * ```
201
- */
202
- function getNestedAccessor(param, accessor) {
203
- const parts = Array.isArray(param) ? param : param.split(".");
204
- if (parts.length === 0 || parts.length === 1 && parts[0] === "") return null;
205
- return `${accessor}?.['${`${parts.join("']?.['")}']`}`;
206
- }
207
- //#endregion
208
- //#region ../../internals/utils/src/url.ts
209
- /**
210
- * Keeps the OpenAPI parameter name as-is when it is already a valid JS identifier, and
211
- * camelCases it only enough to become one otherwise (for example a hyphenated path segment).
212
- */
213
- function transformParam(raw) {
214
- return isValidVarName(raw) ? raw : camelCase(raw);
215
- }
216
- /**
217
- * Helpers for OpenAPI/Swagger paths.
218
- */
219
- var Url = class Url {
220
- /**
221
- * Converts an OpenAPI/Swagger path to Express-style colon syntax.
222
- *
223
- * @example
224
- * Url.toPath('/pet/{petId}') // '/pet/:petId'
225
- */
226
- static toPath(path) {
227
- return path.replace(/\{([^}]+)\}/g, ":$1");
228
- }
229
- /**
230
- * Rewrites OpenAPI placeholder names while keeping the `{...}` braces, so the generated `url`
231
- * literal aligns with the grouped `path` request option that the runtime client interpolates by
232
- * key.
233
- *
234
- * @example
235
- * Url.toSafeTemplate('/user/{monetary-account-id}') // '/user/{monetaryAccountId}'
236
- */
237
- static toSafeTemplate(path) {
238
- return path.replace(/\{([^}]+)\}/g, (_, name) => `{${transformParam(name)}}`);
239
- }
240
- /**
241
- * Converts an OpenAPI/Swagger path to a TypeScript template literal string.
242
- * `prefix` is prepended inside the literal, and `replacer` transforms each parameter name.
243
- *
244
- * @example
245
- * Url.toTemplateString('/pet/{petId}') // '`/pet/${petId}`'
246
- *
247
- * @example
248
- * Url.toTemplateString('/pet/{petId}', { prefix: 'https://api' }) // '`https://api/pet/${petId}`'
249
- */
250
- static toTemplateString(path, { prefix, replacer } = {}) {
251
- const result = path.split(/\{([^}]+)\}/).map((part, i) => {
252
- if (i % 2 === 0) return part;
253
- const param = transformParam(part);
254
- return `\${${replacer ? replacer(param) : param}}`;
255
- }).join("");
256
- return `\`${prefix ?? ""}${result}\``;
257
- }
258
- /**
259
- * Converts an OpenAPI/Swagger path to a template literal that reads each parameter off the
260
- * grouped `path` request option, e.g. `/pet/{petId}` becomes `` `/pet/${path.petId}` ``. Parameter
261
- * names match the generated `path` type, and `prefix` is prepended inside the literal. Shared by
262
- * the client and cypress generators that pass a grouped `path` object.
263
- *
264
- * @example
265
- * Url.toGroupedTemplateString('/pet/{petId}') // '`/pet/${path.petId}`'
266
- */
267
- static toGroupedTemplateString(path, { prefix } = {}) {
268
- return Url.toTemplateString(path, {
269
- prefix,
270
- replacer: (name) => `path.${name}`
271
- });
272
- }
273
- };
274
- //#endregion
275
35
  //#region ../../internals/shared/src/params.ts
276
36
  /**
277
37
  * Drops parameters that share the same name, keeping the first.
@@ -310,11 +70,30 @@ function operationFileEntry(node, name, extname = ".ts") {
310
70
  path: node.path
311
71
  };
312
72
  }
73
+ /**
74
+ * Resolves a dependency plugin's generated file for `node.operationId`, cached in `cache` (the
75
+ * current node's `ctx.cache`) under the resolver's own plugin name. Several dependents reading the
76
+ * same dependency for the same operation in one pass (a query plugin's several hook generators, the
77
+ * MCP handler, ...) share one computed name and path instead of each calling `resolver.file` again.
78
+ *
79
+ * @example Cache `plugin-ts`'s file for the current operation
80
+ * ```ts
81
+ * const fileTs = resolveDependencyOperationFile({ cache: ctx.cache, node, resolver: tsResolver, root, output })
82
+ * ```
83
+ */
84
+ function resolveDependencyOperationFile(options) {
85
+ const { cache, node, resolver, root, output, group } = options;
86
+ return cache.ensureItem(`${resolver.pluginName}:operationFile`, () => resolver.file({
87
+ ...operationFileEntry(node, node.operationId),
88
+ root,
89
+ output,
90
+ group: group ?? void 0
91
+ }));
92
+ }
313
93
  function getOperationLink(node, link) {
314
94
  if (!link) return null;
315
95
  if (typeof link === "function") return link(node) ?? null;
316
- if (link === "urlPath") return node.path ? `{@link ${Url.toPath(node.path)}}` : null;
317
- return node.path ? `{@link ${node.path.replaceAll("{", ":").replaceAll("}", "")}}` : null;
96
+ return node.path ? `{@link ${kubb_kit.Url.toPath(node.path)}}` : null;
318
97
  }
319
98
  /**
320
99
  * Derives the shared `ContentTypeInfo` shape from a list of content types, tracking whether several
@@ -404,16 +183,24 @@ function buildOperationComments(node, options = {}) {
404
183
  if (!splitLines) return filteredComments;
405
184
  return filteredComments.flatMap((text) => text.split(/\r?\n/).map((line) => line.trim())).filter((comment) => Boolean(comment));
406
185
  }
186
+ const operationParameterGroupsByNode = /* @__PURE__ */ new WeakMap();
187
+ /**
188
+ * Groups an operation's parameters by location (`path`/`query`/`header`/`cookie`), deduping each
189
+ * group by name. Every plugin generator visiting the same `OperationNode` shares one AST instance
190
+ * (see `KubbDriver`), so the result is cached per node to avoid re-filtering and re-deduping the
191
+ * same parameters once per plugin.
192
+ */
407
193
  function getOperationParameters(node) {
408
- return {
409
- path: dedupeParams(node.parameters.filter((param) => param.in === "path").map((param) => isValidVarName(param.name) ? param : {
410
- ...param,
411
- name: camelCase(param.name)
412
- })),
194
+ const cached = operationParameterGroupsByNode.get(node);
195
+ if (cached) return cached;
196
+ const groups = {
197
+ path: dedupeParams(node.parameters.filter((param) => param.in === "path")),
413
198
  query: dedupeParams(node.parameters.filter((param) => param.in === "query")),
414
199
  header: dedupeParams(node.parameters.filter((param) => param.in === "header")),
415
200
  cookie: dedupeParams(node.parameters.filter((param) => param.in === "cookie"))
416
201
  };
202
+ operationParameterGroupsByNode.set(node, groups);
203
+ return groups;
417
204
  }
418
205
  function getStatusCodeNumber(statusCode) {
419
206
  const code = Number(statusCode);
@@ -478,6 +265,60 @@ function resolveOperationTypeNames(node, resolver, options = {}) {
478
265
  return result;
479
266
  }
480
267
  //#endregion
268
+ //#region ../../internals/utils/src/casing.ts
269
+ /**
270
+ * Shared implementation for camelCase and PascalCase conversion.
271
+ * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)
272
+ * and capitalizes each word according to `pascal`.
273
+ *
274
+ * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
275
+ */
276
+ function toCamelOrPascal(text, pascal) {
277
+ 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) => {
278
+ if (word.length > 1 && word === word.toUpperCase()) return word;
279
+ return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
280
+ }).join("").replace(/[^a-zA-Z0-9]/g, "");
281
+ }
282
+ /**
283
+ * Converts `text` to camelCase.
284
+ *
285
+ * @example Word boundaries
286
+ * `camelCase('hello-world') // 'helloWorld'`
287
+ *
288
+ * @example With a prefix
289
+ * `camelCase('tag', { prefix: 'create' }) // 'createTag'`
290
+ */
291
+ function camelCase(text, { prefix = "", suffix = "" } = {}) {
292
+ return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
293
+ }
294
+ /**
295
+ * Uppercases only the first character of `text`, leaving the rest untouched.
296
+ * Unlike {@link pascalCase} it never re-splits word boundaries or strips characters.
297
+ *
298
+ * @example
299
+ * `capitalize('getPetById') // 'GetPetById'`
300
+ */
301
+ function capitalize(text) {
302
+ return `${text.charAt(0).toUpperCase()}${text.slice(1)}`;
303
+ }
304
+ //#endregion
305
+ //#region ../../internals/utils/src/strings.ts
306
+ /**
307
+ * Renders a dotted path or string array as an optional-chaining accessor expression rooted at
308
+ * `accessor`. Returns `null` for an empty path.
309
+ *
310
+ * @example
311
+ * ```ts
312
+ * getNestedAccessor('pagination.next.id', 'lastPage')
313
+ * // "lastPage?.['pagination']?.['next']?.['id']"
314
+ * ```
315
+ */
316
+ function getNestedAccessor(param, accessor) {
317
+ const parts = Array.isArray(param) ? param : param.split(".");
318
+ if (parts.length === 0 || parts.length === 1 && parts[0] === "") return null;
319
+ return `${accessor}?.['${`${parts.join("']?.['")}']`}`;
320
+ }
321
+ //#endregion
481
322
  //#region ../../internals/shared/src/group.ts
482
323
  /**
483
324
  * Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the
@@ -597,23 +438,30 @@ function resolveContractClient(options) {
597
438
  * (plugin-fetch or plugin-axios). Returns `null` when no contract plugin is in play (the inline
598
439
  * path). The plugin injects `.kubb/client.ts` at the global output root, the same path consumers
599
440
  * read `RequestConfig` / `ResponseErrorConfig` from.
441
+ *
442
+ * The result is cached in the current node's `cache` (`ctx.cache`) under the client plugin's name,
443
+ * so several dependents reading the same client plugin for one operation in a single pass
444
+ * (react-query's query/mutation/infinite generators, vue-query, swr, the MCP handler, ...) share
445
+ * one computed result instead of each re-deriving the name and path.
600
446
  */
601
447
  function resolveClientOperation(options) {
602
- const { clientPlugin, driver, node, root, output } = options;
448
+ const { clientPlugin, driver, node, root, output, cache } = options;
603
449
  if (!clientPlugin) return null;
604
- const resolver = driver.getResolver(clientPlugin.pluginName);
605
- const plugin = driver.getPlugin(clientPlugin.pluginName);
606
- const file = resolver.file({
607
- ...operationFileEntry(node, node.operationId),
608
- root,
609
- output: plugin?.options?.output ?? output,
610
- group: plugin?.options?.group ?? void 0
450
+ return cache.ensureItem(`${clientPlugin.pluginName}:clientOperation`, () => {
451
+ const resolver = driver.getResolver(clientPlugin.pluginName);
452
+ const plugin = driver.getPlugin(clientPlugin.pluginName);
453
+ const file = resolver.file({
454
+ ...operationFileEntry(node, node.operationId),
455
+ root,
456
+ output: plugin?.options?.output ?? output,
457
+ group: plugin?.options?.group ?? void 0
458
+ });
459
+ return {
460
+ name: resolver.name(node.operationId),
461
+ path: file.path,
462
+ clientPath: node_path.default.resolve(root, ".kubb/client.ts")
463
+ };
611
464
  });
612
- return {
613
- name: resolver.name(node.operationId),
614
- path: file.path,
615
- clientPath: node_path.default.resolve(root, ".kubb/client.ts")
616
- };
617
465
  }
618
466
  //#endregion
619
467
  //#region ../../internals/tanstack-query/src/utils.ts
@@ -684,14 +532,16 @@ function buildGroupedRequestParam(node, options) {
684
532
  */
685
533
  function buildQueryOptionsParams(node, options) {
686
534
  const { resolver, memberTypeWrapper } = options;
687
- return (0, _kubb_plugin_ts.createFunctionParameters)({ params: [buildGroupedRequestParam(node, {
535
+ const groupedParam = buildGroupedRequestParam(node, {
688
536
  resolver,
689
537
  memberTypeWrapper
690
- }), (0, _kubb_plugin_ts.createFunctionParameter)({
538
+ });
539
+ const configParam = (0, _kubb_plugin_ts.createFunctionParameter)({
691
540
  name: "config",
692
541
  type: `Partial<Omit<RequestConfig, 'path' | 'query' | 'body' | 'headers' | 'url'>>`,
693
542
  default: "{}"
694
- })].filter((param) => param !== null) });
543
+ });
544
+ return (0, _kubb_plugin_ts.createFunctionParameters)({ params: [groupedParam, configParam].filter((param) => param !== null) });
695
545
  }
696
546
  /**
697
547
  * Builds the call to a client `<op>` function inside a query/mutation hook body. The function takes
@@ -789,6 +639,19 @@ function resolveMutationConfig(mutation, options) {
789
639
  };
790
640
  }
791
641
  /**
642
+ * Classifies an operation as a query or a mutation from the resolved `query` / `mutation` method lists.
643
+ * `query: false` still marks the operation as a query so the query-family generators keep matching it,
644
+ * and a method already claimed by `query` never counts as a mutation.
645
+ */
646
+ function classifyOperation(node, { query, mutation }) {
647
+ const isQuery = query === false || !!query && query.methods.some((method) => node.method.toLowerCase() === method.toLowerCase());
648
+ const queryMethods = new Set(query ? query.methods : []);
649
+ return {
650
+ isQuery,
651
+ isMutation: mutation !== false && !isQuery && (mutation ? mutation.methods : []).some((method) => !queryMethods.has(method) && node.method.toLowerCase() === method.toLowerCase())
652
+ };
653
+ }
654
+ /**
792
655
  * Applies the shared infinite-query defaults during plugin setup: a falsy value disables infinite
793
656
  * queries, and an object merges over `queryParam: 'id'` and `initialPageParam: 0` with the cursor
794
657
  * paths cleared.
@@ -827,6 +690,24 @@ function resolveOperationOverrides(node, override) {
827
690
  return override.find((ov) => matchesPattern(node, ov))?.options ?? {};
828
691
  }
829
692
  /**
693
+ * The request groups a query key is built from, matching `buildQueryKeyParams`. Headers are
694
+ * deliberately absent: they do not identify a cache entry, so the key factory takes no parameter
695
+ * for an operation that only carries headers.
696
+ */
697
+ const queryKeyGroupOrder = [
698
+ "path",
699
+ "query",
700
+ "body"
701
+ ];
702
+ /**
703
+ * Whether the generated query key factory declares a parameter, so a call site passes an argument
704
+ * only when one is accepted.
705
+ */
706
+ function hasQueryKeyParams(node) {
707
+ const groups = getRequestGroups(node);
708
+ return queryKeyGroupOrder.some((key) => groups[key]);
709
+ }
710
+ /**
830
711
  * Build QueryKey params as the grouped `{ path, query, body }` object (NO headers, NO config),
831
712
  * typed from the operation's `Options` minus `url`. The query key transformer reads the
832
713
  * grouped `path`/`query`/`body` bindings.
@@ -835,11 +716,7 @@ function buildQueryKeyParams(node, options) {
835
716
  const { resolver } = options;
836
717
  const groupedParam = buildGroupedRequestParam(node, {
837
718
  resolver,
838
- keys: [
839
- "path",
840
- "query",
841
- "body"
842
- ]
719
+ keys: queryKeyGroupOrder
843
720
  });
844
721
  return (0, _kubb_plugin_ts.createFunctionParameters)({ params: groupedParam ? [groupedParam] : [] });
845
722
  }
@@ -856,11 +733,7 @@ function InfiniteQueryOptions({ name, clientName, initialPageParam, cursorParam,
856
733
  });
857
734
  const groupedKeyParam = buildGroupedRequestParam(node, {
858
735
  resolver: tsResolver,
859
- keys: [
860
- "path",
861
- "query",
862
- "body"
863
- ],
736
+ keys: queryKeyGroupOrder,
864
737
  memberTypeWrapper
865
738
  });
866
739
  const queryKeyParamsNode = (0, _kubb_plugin_ts.createFunctionParameters)({ params: groupedKeyParam ? [groupedKeyParam] : [] });
@@ -923,7 +796,7 @@ return infiniteQueryOptions<${queryFnDataType}, ${errorType}, InfiniteData<${que
923
796
  const declarationPrinter$6 = (0, _kubb_plugin_ts.functionPrinter)({ mode: "declaration" });
924
797
  const mutationKeyTransformer = ({ node }) => {
925
798
  if (!node.path) return [];
926
- return [`{ url: '${Url.toPath(node.path)}' }`];
799
+ return [`{ url: '${kubb_kit.Url.toPath(node.path)}' }`];
927
800
  };
928
801
  function MutationKey({ name, node, transformer }) {
929
802
  const paramsNode = (0, _kubb_plugin_ts.createFunctionParameters)({ params: [] });
@@ -1007,7 +880,7 @@ const queryKeyTransformer = ({ node }) => {
1007
880
  const hasQueryParams = getOperationParameters(node).query.length > 0;
1008
881
  const hasRequestBody = !!node.requestBody?.content?.[0]?.schema;
1009
882
  return [
1010
- hasPathParams ? `{ url: '${Url.toPath(node.path)}', params: path }` : `{ url: '${Url.toPath(node.path)}' }`,
883
+ hasPathParams ? `{ url: '${kubb_kit.Url.toPath(node.path)}', params: path }` : `{ url: '${kubb_kit.Url.toPath(node.path)}' }`,
1011
884
  hasQueryParams ? "...(query ? [query] : [])" : null,
1012
885
  hasRequestBody ? "...(body ? [body] : [])" : null
1013
886
  ].filter(Boolean);
@@ -1158,19 +1031,6 @@ function buildResolvedRequestParams(node) {
1158
1031
  if (names.length === 0) return null;
1159
1032
  return `{ ${names.map((name) => `${name}: typeof ${name} === 'function' ? ${name}() : ${name}`).join(", ")} }`;
1160
1033
  }
1161
- /**
1162
- * Classifies an operation as a query or a mutation from the resolved `query` / `mutation` method lists.
1163
- * `query: false` still marks the operation as a query so the query-family generators keep matching it,
1164
- * and a method already claimed by `query` never counts as a mutation.
1165
- */
1166
- function classifyOperation(node, { query, mutation }) {
1167
- const isQuery = query === false || !!query && query.methods.some((method) => node.method.toLowerCase() === method.toLowerCase());
1168
- const queryMethods = new Set(query ? query.methods : []);
1169
- return {
1170
- isQuery,
1171
- isMutation: mutation !== false && !isQuery && (mutation ? mutation.methods : []).some((method) => !queryMethods.has(method) && node.method.toLowerCase() === method.toLowerCase())
1172
- };
1173
- }
1174
1034
  //#endregion
1175
1035
  //#region src/generators/hookOptionsGenerator.tsx
1176
1036
  /**
@@ -1345,10 +1205,11 @@ function buildInfiniteQueryParamsNode(node, options) {
1345
1205
  }`,
1346
1206
  default: "{}"
1347
1207
  });
1348
- return (0, _kubb_plugin_ts.createFunctionParameters)({ params: [buildGroupedRequestParam(node, {
1208
+ const groupedParam = buildGroupedRequestParam(node, {
1349
1209
  resolver,
1350
1210
  memberTypeWrapper: maybeValueOrGetter
1351
- }), optionsParam].filter((param) => param !== null) });
1211
+ });
1212
+ return (0, _kubb_plugin_ts.createFunctionParameters)({ params: [groupedParam, optionsParam].filter((param) => param !== null) });
1352
1213
  }
1353
1214
  function InfiniteQuery({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, tsResolver, initialPageParam, queryParam, customOptions, suspense }) {
1354
1215
  const { TData: responseType, TError: errorType } = buildResponseTypes(node, tsResolver);
@@ -1368,7 +1229,7 @@ function InfiniteQuery({ name, queryKeyTypeName, queryOptionsName, queryKeyName,
1368
1229
  `TPageParam = ${pageParamType}`
1369
1230
  ];
1370
1231
  const resolvedParams = buildResolvedRequestParams(node);
1371
- const queryKeyArgs = resolvedParams ? "resolvedParams" : "";
1232
+ const queryKeyArgs = resolvedParams && hasQueryKeyParams(node) ? "resolvedParams" : "";
1372
1233
  const queryOptionsArgs = resolvedParams ? "resolvedParams, config" : "config";
1373
1234
  const paramsNode = buildInfiniteQueryParamsNode(node, {
1374
1235
  resolver: tsResolver,
@@ -1461,15 +1322,16 @@ function resolveMutationRequestType(node, resolver) {
1461
1322
  function buildMutationParamsNode(node, options) {
1462
1323
  const { resolver } = options;
1463
1324
  const { TData, TError } = buildResponseTypes(node, resolver);
1325
+ const generics = [
1326
+ TData,
1327
+ TError,
1328
+ resolveMutationRequestType(node, resolver),
1329
+ "TContext"
1330
+ ].join(", ");
1464
1331
  return (0, _kubb_plugin_ts.createFunctionParameters)({ params: [(0, _kubb_plugin_ts.createFunctionParameter)({
1465
1332
  name: "options",
1466
1333
  type: `{
1467
- mutation?: UseMutationOptions<${[
1468
- TData,
1469
- TError,
1470
- resolveMutationRequestType(node, resolver),
1471
- "TContext"
1472
- ].join(", ")}> & { client?: QueryClient },
1334
+ mutation?: UseMutationOptions<${generics}> & { client?: QueryClient },
1473
1335
  client?: ${buildRequestConfigType(node)},
1474
1336
  }`,
1475
1337
  default: "{}"
@@ -1527,10 +1389,11 @@ function buildQueryParamsNode(node, options) {
1527
1389
  }`,
1528
1390
  default: "{}"
1529
1391
  });
1530
- return (0, _kubb_plugin_ts.createFunctionParameters)({ params: [buildGroupedRequestParam(node, {
1392
+ const groupedParam = buildGroupedRequestParam(node, {
1531
1393
  resolver,
1532
1394
  memberTypeWrapper: maybeValueOrGetter
1533
- }), optionsParam].filter((param) => param !== null) });
1395
+ });
1396
+ return (0, _kubb_plugin_ts.createFunctionParameters)({ params: [groupedParam, optionsParam].filter((param) => param !== null) });
1534
1397
  }
1535
1398
  function Query({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, tsResolver, customOptions, suspense }) {
1536
1399
  const { TData, TError } = buildResponseTypes(node, tsResolver);
@@ -1555,7 +1418,7 @@ function Query({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, t
1555
1418
  `TQueryKey extends QueryKey = ${queryKeyTypeName}`
1556
1419
  ];
1557
1420
  const resolvedParams = buildResolvedRequestParams(node);
1558
- const queryKeyArgs = resolvedParams ? "resolvedParams" : "";
1421
+ const queryKeyArgs = resolvedParams && hasQueryKeyParams(node) ? "resolvedParams" : "";
1559
1422
  const queryOptionsArgs = resolvedParams ? "resolvedParams, config" : "config";
1560
1423
  const paramsNode = buildQueryParamsNode(node, {
1561
1424
  resolver: tsResolver,
@@ -1595,14 +1458,11 @@ function Query({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, t
1595
1458
  //#region src/components/QueryOptions.tsx
1596
1459
  const declarationPrinter = (0, _kubb_plugin_ts.functionPrinter)({ mode: "declaration" });
1597
1460
  const callPrinter = (0, _kubb_plugin_ts.functionPrinter)({ mode: "call" });
1598
- function getQueryOptionsParams(node, options) {
1599
- return buildQueryOptionsParams(node, options);
1600
- }
1601
1461
  function QueryOptions({ name, clientName, node, tsResolver, queryKeyName }) {
1602
1462
  const { TData, TError } = buildResponseTypes(node, tsResolver);
1603
1463
  const queryKeyParamsNode = buildQueryKeyParams(node, { resolver: tsResolver });
1604
1464
  const queryKeyParamsCall = callPrinter.print(queryKeyParamsNode) ?? "";
1605
- const paramsNode = getQueryOptionsParams(node, { resolver: tsResolver });
1465
+ const paramsNode = buildQueryOptionsParams(node, { resolver: tsResolver });
1606
1466
  const paramsSignature = declarationPrinter.print(paramsNode) ?? "";
1607
1467
  const queryFnBody = `const { data } = await ${buildClientCall(node, {
1608
1468
  clientName,
@@ -1633,36 +1493,44 @@ function QueryOptions({ name, clientName, node, tsResolver, queryKeyName }) {
1633
1493
  //#region src/generators/infiniteQueryGenerator.tsx
1634
1494
  /**
1635
1495
  * Built-in generator for `useInfiniteQuery` hooks. Enabled when
1636
- * `pluginReactQuery({ infinite: { ... } })`. Emits one `useFooInfiniteQuery`
1637
- * hook per query operation, wiring the configured `nextParam` /
1638
- * `previousParam` paths into TanStack Query's cursor-based pagination.
1496
+ * `pluginReactQuery({ infinite: { ... }, hooks: true })`. Emits one
1497
+ * `useFooInfiniteQuery` hook per query operation, wiring the configured
1498
+ * `nextParam` / `previousParam` paths into TanStack Query's cursor-based
1499
+ * pagination.
1639
1500
  */
1640
1501
  const infiniteQueryGenerator = (0, kubb_kit.defineGenerator)({
1641
1502
  name: "react-infinite-query",
1642
1503
  renderer: kubb_jsx.jsxRenderer,
1504
+ match(node, ctx) {
1505
+ const operationNode = node;
1506
+ if (!kubb_kit.ast.isHttpOperationNode(operationNode)) return false;
1507
+ const { query, mutation, infinite, hooks } = ctx.options;
1508
+ const { isQuery, isMutation } = classifyOperation(operationNode, {
1509
+ query,
1510
+ mutation
1511
+ });
1512
+ const infiniteOptions = infinite && typeof infinite === "object" ? infinite : null;
1513
+ if (!isQuery || isMutation || !infiniteOptions || !hooks) return false;
1514
+ const queryParamKeys = getOperationParameters(operationNode).query.map((p) => p.name);
1515
+ return infiniteOptions.queryParam ? queryParamKeys.includes(infiniteOptions.queryParam) || queryParamKeys.includes(`${infiniteOptions.queryParam}?`) : false;
1516
+ },
1643
1517
  operation(node, ctx) {
1644
1518
  if (!kubb_kit.ast.isHttpOperationNode(node)) return null;
1645
1519
  const { config, driver, resolver, root } = ctx;
1646
- const { output, query, mutation, infinite, client, group, customOptions, hooks } = ctx.options;
1520
+ const { output, query, infinite, client, group, customOptions } = ctx.options;
1647
1521
  const pluginTs = driver.getPlugin(_kubb_plugin_ts.pluginTsName);
1648
1522
  if (!pluginTs) return null;
1649
1523
  const tsResolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
1650
- const { isQuery, isMutation } = classifyOperation(node, {
1651
- query,
1652
- mutation
1653
- });
1654
1524
  const infiniteOptions = infinite && typeof infinite === "object" ? infinite : null;
1655
- if (!isQuery || isMutation || !infiniteOptions) return null;
1656
- const normalizeKey = (key) => key.replace(/\?$/, "");
1657
- const queryParamKeys = getOperationParameters(node).query.map((p) => p.name);
1658
- if (!(infiniteOptions.queryParam ? queryParamKeys.some((k) => normalizeKey(k) === infiniteOptions.queryParam) : false)) return null;
1525
+ if (!infiniteOptions) return null;
1659
1526
  const importPath = query ? query.importPath : "@tanstack/react-query";
1660
1527
  const contractOp = resolveClientOperation({
1661
1528
  clientPlugin: { pluginName: client.pluginName },
1662
1529
  driver,
1663
1530
  node,
1664
1531
  root,
1665
- output
1532
+ output,
1533
+ cache: ctx.cache
1666
1534
  });
1667
1535
  if (!contractOp) return null;
1668
1536
  const queryName = resolver.infiniteQuery.name(node);
@@ -1676,15 +1544,20 @@ const infiniteQueryGenerator = (0, kubb_kit.defineGenerator)({
1676
1544
  output,
1677
1545
  group: group ?? void 0
1678
1546
  }),
1679
- fileTs: tsResolver.file({
1680
- ...operationFileEntry(node, node.operationId),
1547
+ fileTs: resolveDependencyOperationFile({
1548
+ cache: ctx.cache,
1549
+ node,
1550
+ resolver: tsResolver,
1681
1551
  root,
1682
1552
  output: pluginTs.options?.output ?? output,
1683
- group: pluginTs.options?.group ?? void 0
1553
+ group: pluginTs.options?.group
1684
1554
  })
1685
1555
  };
1686
- const rawQueryParams = getOperationParameters(node).query;
1687
- const queryParamsTypeName = rawQueryParams.length > 0 && tsResolver.param.query(node, rawQueryParams[0]) !== tsResolver.param.name(node, rawQueryParams[0]) ? tsResolver.param.query(node, rawQueryParams[0]) : null;
1556
+ const { queryParamsTypeName } = resolvePageParamType(node, {
1557
+ resolver: tsResolver,
1558
+ initialPageParam: infiniteOptions.initialPageParam,
1559
+ queryParam: infiniteOptions.queryParam
1560
+ });
1688
1561
  const importedTypeNames = [
1689
1562
  tsResolver.response.options(node),
1690
1563
  queryParamsTypeName,
@@ -1765,33 +1638,31 @@ const infiniteQueryGenerator = (0, kubb_kit.defineGenerator)({
1765
1638
  initialPageParam: infiniteOptions.initialPageParam,
1766
1639
  queryParam: infiniteOptions.queryParam
1767
1640
  }),
1768
- hooks && /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsxs)(kubb_jsx_jsx_runtime.Fragment, { children: [
1769
- /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
1770
- name: ["useInfiniteQuery"],
1771
- path: importPath
1772
- }),
1773
- /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
1774
- name: [
1775
- "QueryKey",
1776
- "QueryClient",
1777
- "InfiniteQueryObserverOptions",
1778
- "UseInfiniteQueryResult"
1779
- ],
1780
- path: importPath,
1781
- isTypeOnly: true
1782
- }),
1783
- /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(InfiniteQuery, {
1784
- name: queryName,
1785
- queryOptionsName,
1786
- queryKeyName,
1787
- queryKeyTypeName,
1788
- node,
1789
- tsResolver,
1790
- initialPageParam: infiniteOptions.initialPageParam,
1791
- queryParam: infiniteOptions.queryParam,
1792
- customOptions
1793
- })
1794
- ] })
1641
+ /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
1642
+ name: ["useInfiniteQuery"],
1643
+ path: importPath
1644
+ }),
1645
+ /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
1646
+ name: [
1647
+ "QueryKey",
1648
+ "QueryClient",
1649
+ "InfiniteQueryObserverOptions",
1650
+ "UseInfiniteQueryResult"
1651
+ ],
1652
+ path: importPath,
1653
+ isTypeOnly: true
1654
+ }),
1655
+ /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(InfiniteQuery, {
1656
+ name: queryName,
1657
+ queryOptionsName,
1658
+ queryKeyName,
1659
+ queryKeyTypeName,
1660
+ node,
1661
+ tsResolver,
1662
+ initialPageParam: infiniteOptions.initialPageParam,
1663
+ queryParam: infiniteOptions.queryParam,
1664
+ customOptions
1665
+ })
1795
1666
  ]
1796
1667
  });
1797
1668
  }
@@ -1806,25 +1677,30 @@ const infiniteQueryGenerator = (0, kubb_kit.defineGenerator)({
1806
1677
  const mutationGenerator = (0, kubb_kit.defineGenerator)({
1807
1678
  name: "react-query-mutation",
1808
1679
  renderer: kubb_jsx.jsxRenderer,
1680
+ match(node, ctx) {
1681
+ const operationNode = node;
1682
+ if (!kubb_kit.ast.isHttpOperationNode(operationNode)) return false;
1683
+ const { query, mutation } = ctx.options;
1684
+ return classifyOperation(operationNode, {
1685
+ query,
1686
+ mutation
1687
+ }).isMutation;
1688
+ },
1809
1689
  operation(node, ctx) {
1810
1690
  if (!kubb_kit.ast.isHttpOperationNode(node)) return null;
1811
1691
  const { config, driver, resolver, root } = ctx;
1812
- const { output, query, mutation, client, group, customOptions, hooks } = ctx.options;
1692
+ const { output, mutation, client, group, customOptions, hooks } = ctx.options;
1813
1693
  const pluginTs = driver.getPlugin(_kubb_plugin_ts.pluginTsName);
1814
1694
  if (!pluginTs) return null;
1815
1695
  const tsResolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
1816
- const { isMutation } = classifyOperation(node, {
1817
- query,
1818
- mutation
1819
- });
1820
- if (!isMutation) return null;
1821
1696
  const importPath = mutation ? mutation.importPath : "@tanstack/react-query";
1822
1697
  const contractOp = resolveClientOperation({
1823
1698
  clientPlugin: { pluginName: client.pluginName },
1824
1699
  driver,
1825
1700
  node,
1826
1701
  root,
1827
- output
1702
+ output,
1703
+ cache: ctx.cache
1828
1704
  });
1829
1705
  if (!contractOp) return null;
1830
1706
  const mutationHookName = resolver.mutation.name(node);
@@ -1838,11 +1714,13 @@ const mutationGenerator = (0, kubb_kit.defineGenerator)({
1838
1714
  output,
1839
1715
  group: group ?? void 0
1840
1716
  }),
1841
- fileTs: tsResolver.file({
1842
- ...operationFileEntry(node, node.operationId),
1717
+ fileTs: resolveDependencyOperationFile({
1718
+ cache: ctx.cache,
1719
+ node,
1720
+ resolver: tsResolver,
1843
1721
  root,
1844
1722
  output: pluginTs.options?.output ?? output,
1845
- group: pluginTs.options?.group ?? void 0
1723
+ group: pluginTs.options?.group
1846
1724
  })
1847
1725
  };
1848
1726
  const importedTypeNames = [tsResolver.response.options(node), ...resolveOperationTypeNames(node, tsResolver, {
@@ -1946,25 +1824,31 @@ const mutationGenerator = (0, kubb_kit.defineGenerator)({
1946
1824
  const queryGenerator = (0, kubb_kit.defineGenerator)({
1947
1825
  name: "react-query",
1948
1826
  renderer: kubb_jsx.jsxRenderer,
1827
+ match(node, ctx) {
1828
+ const operationNode = node;
1829
+ if (!kubb_kit.ast.isHttpOperationNode(operationNode)) return false;
1830
+ const { query, mutation } = ctx.options;
1831
+ const { isQuery, isMutation } = classifyOperation(operationNode, {
1832
+ query,
1833
+ mutation
1834
+ });
1835
+ return isQuery && !isMutation;
1836
+ },
1949
1837
  operation(node, ctx) {
1950
1838
  if (!kubb_kit.ast.isHttpOperationNode(node)) return null;
1951
1839
  const { config, driver, resolver, root } = ctx;
1952
- const { output, query, mutation, client, group, customOptions, hooks } = ctx.options;
1840
+ const { output, query, client, group, customOptions, hooks } = ctx.options;
1953
1841
  const pluginTs = driver.getPlugin(_kubb_plugin_ts.pluginTsName);
1954
1842
  if (!pluginTs) return null;
1955
1843
  const tsResolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
1956
- const { isQuery, isMutation } = classifyOperation(node, {
1957
- query,
1958
- mutation
1959
- });
1960
- if (!isQuery || isMutation) return null;
1961
1844
  const importPath = query ? query.importPath : "@tanstack/react-query";
1962
1845
  const contractOp = resolveClientOperation({
1963
1846
  clientPlugin: { pluginName: client.pluginName },
1964
1847
  driver,
1965
1848
  node,
1966
1849
  root,
1967
- output
1850
+ output,
1851
+ cache: ctx.cache
1968
1852
  });
1969
1853
  if (!contractOp) return null;
1970
1854
  const queryName = resolver.query.name(node);
@@ -1978,11 +1862,13 @@ const queryGenerator = (0, kubb_kit.defineGenerator)({
1978
1862
  output,
1979
1863
  group: group ?? void 0
1980
1864
  }),
1981
- fileTs: tsResolver.file({
1982
- ...operationFileEntry(node, node.operationId),
1865
+ fileTs: resolveDependencyOperationFile({
1866
+ cache: ctx.cache,
1867
+ node,
1868
+ resolver: tsResolver,
1983
1869
  root,
1984
1870
  output: pluginTs.options?.output ?? output,
1985
- group: pluginTs.options?.group ?? void 0
1871
+ group: pluginTs.options?.group
1986
1872
  })
1987
1873
  };
1988
1874
  const importedTypeNames = [tsResolver.response.options(node), ...resolveOperationTypeNames(node, tsResolver, {
@@ -2083,38 +1969,44 @@ const queryGenerator = (0, kubb_kit.defineGenerator)({
2083
1969
  //#endregion
2084
1970
  //#region src/generators/suspenseInfiniteQueryGenerator.tsx
2085
1971
  /**
2086
- * Built-in generator for `useSuspenseInfiniteQuery` hooks. Enabled when both
2087
- * `suspense` and `infinite` are configured. Combines suspense semantics with
2088
- * cursor-based pagination. Handlers throw promises while loading and pull
2089
- * additional pages on demand.
1972
+ * Built-in generator for `useSuspenseInfiniteQuery` hooks. Enabled when
1973
+ * `suspense`, `infinite`, and `hooks` are all configured. Combines suspense
1974
+ * semantics with cursor-based pagination. Handlers throw promises while
1975
+ * loading and pull additional pages on demand.
2090
1976
  */
2091
1977
  const suspenseInfiniteQueryGenerator = (0, kubb_kit.defineGenerator)({
2092
1978
  name: "react-suspense-infinite-query",
2093
1979
  renderer: kubb_jsx.jsxRenderer,
1980
+ match(node, ctx) {
1981
+ const operationNode = node;
1982
+ if (!kubb_kit.ast.isHttpOperationNode(operationNode)) return false;
1983
+ const { query, mutation, infinite, suspense, hooks } = ctx.options;
1984
+ const { isQuery, isMutation } = classifyOperation(operationNode, {
1985
+ query,
1986
+ mutation
1987
+ });
1988
+ const infiniteOptions = infinite && typeof infinite === "object" ? infinite : null;
1989
+ if (!isQuery || isMutation || !suspense || !infiniteOptions || !hooks) return false;
1990
+ const queryParamKeys = getOperationParameters(operationNode).query.map((p) => p.name);
1991
+ return infiniteOptions.queryParam ? queryParamKeys.includes(infiniteOptions.queryParam) || queryParamKeys.includes(`${infiniteOptions.queryParam}?`) : false;
1992
+ },
2094
1993
  operation(node, ctx) {
2095
1994
  if (!kubb_kit.ast.isHttpOperationNode(node)) return null;
2096
1995
  const { config, driver, resolver, root } = ctx;
2097
- const { output, query, mutation, infinite, suspense, client, group, customOptions, hooks } = ctx.options;
1996
+ const { output, query, infinite, client, group, customOptions } = ctx.options;
2098
1997
  const pluginTs = driver.getPlugin(_kubb_plugin_ts.pluginTsName);
2099
1998
  if (!pluginTs) return null;
2100
1999
  const tsResolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
2101
- const { isQuery, isMutation } = classifyOperation(node, {
2102
- query,
2103
- mutation
2104
- });
2105
- const isSuspense = !!suspense;
2106
2000
  const infiniteOptions = infinite && typeof infinite === "object" ? infinite : null;
2107
- if (!isQuery || isMutation || !isSuspense || !infiniteOptions) return null;
2108
- const normalizeKey = (key) => key.replace(/\?$/, "");
2109
- const queryParamKeys = getOperationParameters(node).query.map((p) => p.name);
2110
- if (!(infiniteOptions.queryParam ? queryParamKeys.some((k) => normalizeKey(k) === infiniteOptions.queryParam) : false)) return null;
2001
+ if (!infiniteOptions) return null;
2111
2002
  const importPath = query ? query.importPath : "@tanstack/react-query";
2112
2003
  const contractOp = resolveClientOperation({
2113
2004
  clientPlugin: { pluginName: client.pluginName },
2114
2005
  driver,
2115
2006
  node,
2116
2007
  root,
2117
- output
2008
+ output,
2009
+ cache: ctx.cache
2118
2010
  });
2119
2011
  if (!contractOp) return null;
2120
2012
  const queryName = resolver.suspenseInfiniteQuery.name(node);
@@ -2128,11 +2020,13 @@ const suspenseInfiniteQueryGenerator = (0, kubb_kit.defineGenerator)({
2128
2020
  output,
2129
2021
  group: group ?? void 0
2130
2022
  }),
2131
- fileTs: tsResolver.file({
2132
- ...operationFileEntry(node, node.operationId),
2023
+ fileTs: resolveDependencyOperationFile({
2024
+ cache: ctx.cache,
2025
+ node,
2026
+ resolver: tsResolver,
2133
2027
  root,
2134
2028
  output: pluginTs.options?.output ?? output,
2135
- group: pluginTs.options?.group ?? void 0
2029
+ group: pluginTs.options?.group
2136
2030
  })
2137
2031
  };
2138
2032
  const rawQueryParams = getOperationParameters(node).query;
@@ -2216,34 +2110,32 @@ const suspenseInfiniteQueryGenerator = (0, kubb_kit.defineGenerator)({
2216
2110
  initialPageParam: infiniteOptions.initialPageParam,
2217
2111
  queryParam: infiniteOptions.queryParam
2218
2112
  }),
2219
- hooks && /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsxs)(kubb_jsx_jsx_runtime.Fragment, { children: [
2220
- /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
2221
- name: ["useSuspenseInfiniteQuery"],
2222
- path: importPath
2223
- }),
2224
- /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
2225
- name: [
2226
- "QueryKey",
2227
- "QueryClient",
2228
- "UseSuspenseInfiniteQueryOptions",
2229
- "UseSuspenseInfiniteQueryResult"
2230
- ],
2231
- path: importPath,
2232
- isTypeOnly: true
2233
- }),
2234
- /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(InfiniteQuery, {
2235
- name: queryName,
2236
- queryOptionsName,
2237
- queryKeyName,
2238
- queryKeyTypeName,
2239
- node,
2240
- tsResolver,
2241
- initialPageParam: infiniteOptions.initialPageParam,
2242
- queryParam: infiniteOptions.queryParam,
2243
- customOptions,
2244
- suspense: true
2245
- })
2246
- ] })
2113
+ /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
2114
+ name: ["useSuspenseInfiniteQuery"],
2115
+ path: importPath
2116
+ }),
2117
+ /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
2118
+ name: [
2119
+ "QueryKey",
2120
+ "QueryClient",
2121
+ "UseSuspenseInfiniteQueryOptions",
2122
+ "UseSuspenseInfiniteQueryResult"
2123
+ ],
2124
+ path: importPath,
2125
+ isTypeOnly: true
2126
+ }),
2127
+ /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(InfiniteQuery, {
2128
+ name: queryName,
2129
+ queryOptionsName,
2130
+ queryKeyName,
2131
+ queryKeyTypeName,
2132
+ node,
2133
+ tsResolver,
2134
+ initialPageParam: infiniteOptions.initialPageParam,
2135
+ queryParam: infiniteOptions.queryParam,
2136
+ customOptions,
2137
+ suspense: true
2138
+ })
2247
2139
  ]
2248
2140
  });
2249
2141
  }
@@ -2252,32 +2144,39 @@ const suspenseInfiniteQueryGenerator = (0, kubb_kit.defineGenerator)({
2252
2144
  //#region src/generators/suspenseQueryGenerator.tsx
2253
2145
  /**
2254
2146
  * Built-in generator for `useSuspenseQuery` hooks. Enabled when
2255
- * `pluginReactQuery({ suspense: {} })`. Emits one `useFooSuspenseQuery` hook
2256
- * per query operation. Suspense queries throw promises while loading and
2257
- * require a `<Suspense>` boundary in the React tree. TanStack Query v5+ only.
2147
+ * `pluginReactQuery({ suspense: {}, hooks: true })`. Emits one
2148
+ * `useFooSuspenseQuery` hook per query operation. Suspense queries throw
2149
+ * promises while loading and require a `<Suspense>` boundary in the React
2150
+ * tree. TanStack Query v5+ only.
2258
2151
  */
2259
2152
  const suspenseQueryGenerator = (0, kubb_kit.defineGenerator)({
2260
2153
  name: "react-suspense-query",
2261
2154
  renderer: kubb_jsx.jsxRenderer,
2155
+ match(node, ctx) {
2156
+ const operationNode = node;
2157
+ if (!kubb_kit.ast.isHttpOperationNode(operationNode)) return false;
2158
+ const { query, mutation, suspense, hooks } = ctx.options;
2159
+ const { isQuery, isMutation } = classifyOperation(operationNode, {
2160
+ query,
2161
+ mutation
2162
+ });
2163
+ return isQuery && !isMutation && !!suspense && hooks;
2164
+ },
2262
2165
  operation(node, ctx) {
2263
2166
  if (!kubb_kit.ast.isHttpOperationNode(node)) return null;
2264
2167
  const { config, driver, resolver, root } = ctx;
2265
- const { output, query, mutation, suspense, client, group, customOptions, hooks } = ctx.options;
2168
+ const { output, query, client, group, customOptions } = ctx.options;
2266
2169
  const pluginTs = driver.getPlugin(_kubb_plugin_ts.pluginTsName);
2267
2170
  if (!pluginTs) return null;
2268
2171
  const tsResolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
2269
- const { isQuery, isMutation } = classifyOperation(node, {
2270
- query,
2271
- mutation
2272
- });
2273
- if (!isQuery || isMutation || !!!suspense) return null;
2274
2172
  const importPath = query ? query.importPath : "@tanstack/react-query";
2275
2173
  const contractOp = resolveClientOperation({
2276
2174
  clientPlugin: { pluginName: client.pluginName },
2277
2175
  driver,
2278
2176
  node,
2279
2177
  root,
2280
- output
2178
+ output,
2179
+ cache: ctx.cache
2281
2180
  });
2282
2181
  if (!contractOp) return null;
2283
2182
  const queryName = resolver.suspenseQuery.name(node);
@@ -2291,11 +2190,13 @@ const suspenseQueryGenerator = (0, kubb_kit.defineGenerator)({
2291
2190
  output,
2292
2191
  group: group ?? void 0
2293
2192
  }),
2294
- fileTs: tsResolver.file({
2295
- ...operationFileEntry(node, node.operationId),
2193
+ fileTs: resolveDependencyOperationFile({
2194
+ cache: ctx.cache,
2195
+ node,
2196
+ resolver: tsResolver,
2296
2197
  root,
2297
2198
  output: pluginTs.options?.output ?? output,
2298
- group: pluginTs.options?.group ?? void 0
2199
+ group: pluginTs.options?.group
2299
2200
  })
2300
2201
  };
2301
2202
  const importedTypeNames = [tsResolver.response.options(node), ...resolveOperationTypeNames(node, tsResolver, {
@@ -2364,32 +2265,30 @@ const suspenseQueryGenerator = (0, kubb_kit.defineGenerator)({
2364
2265
  node,
2365
2266
  tsResolver
2366
2267
  }),
2367
- suspense && hooks && /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsxs)(kubb_jsx_jsx_runtime.Fragment, { children: [
2368
- /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
2369
- name: ["useSuspenseQuery"],
2370
- path: importPath
2371
- }),
2372
- /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
2373
- name: [
2374
- "QueryKey",
2375
- "QueryClient",
2376
- "UseSuspenseQueryOptions",
2377
- "UseSuspenseQueryResult"
2378
- ],
2379
- path: importPath,
2380
- isTypeOnly: true
2381
- }),
2382
- /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(Query, {
2383
- name: queryName,
2384
- queryOptionsName,
2385
- queryKeyName,
2386
- queryKeyTypeName,
2387
- node,
2388
- tsResolver,
2389
- customOptions,
2390
- suspense: true
2391
- })
2392
- ] })
2268
+ /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
2269
+ name: ["useSuspenseQuery"],
2270
+ path: importPath
2271
+ }),
2272
+ /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
2273
+ name: [
2274
+ "QueryKey",
2275
+ "QueryClient",
2276
+ "UseSuspenseQueryOptions",
2277
+ "UseSuspenseQueryResult"
2278
+ ],
2279
+ path: importPath,
2280
+ isTypeOnly: true
2281
+ }),
2282
+ /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(Query, {
2283
+ name: queryName,
2284
+ queryOptionsName,
2285
+ queryKeyName,
2286
+ queryKeyTypeName,
2287
+ node,
2288
+ tsResolver,
2289
+ customOptions,
2290
+ suspense: true
2291
+ })
2393
2292
  ]
2394
2293
  });
2395
2294
  }
@@ -2475,7 +2374,7 @@ const pluginReactQuery = (0, kubb_kit.definePlugin)((options) => {
2475
2374
  const { output = {
2476
2375
  path: "hooks",
2477
2376
  barrel: { type: "named" }
2478
- }, group, exclude = [], include, override = [], suspense = {}, infinite = false, mutation = {}, query = {}, mutationKey = mutationKeyTransformer, queryKey = queryKeyTransformer, customOptions, hooks = false, client, resolver: userResolver, macros: userMacros } = options;
2377
+ }, group, exclude = [], include, override = [], suspense = false, infinite = false, mutation = {}, query = {}, mutationKey = mutationKeyTransformer, queryKey = queryKeyTransformer, customOptions, hooks = false, client, resolver: userResolver, macros: userMacros } = options;
2479
2378
  const selectedGenerators = [
2480
2379
  queryGenerator,
2481
2380
  suspenseQueryGenerator,