@kubb/plugin-react-query 5.0.0-beta.56 → 5.0.0-beta.73

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +2 -2
  2. package/dist/index.cjs +2521 -59
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.ts +521 -3
  5. package/dist/index.js +2488 -49
  6. package/dist/index.js.map +1 -1
  7. package/package.json +10 -20
  8. package/dist/components-DL0Cai7l.js +0 -1507
  9. package/dist/components-DL0Cai7l.js.map +0 -1
  10. package/dist/components-yMQOuFmI.cjs +0 -1657
  11. package/dist/components-yMQOuFmI.cjs.map +0 -1
  12. package/dist/components.cjs +0 -13
  13. package/dist/components.d.ts +0 -270
  14. package/dist/components.js +0 -2
  15. package/dist/generators-BG-Vcvfg.js +0 -1307
  16. package/dist/generators-BG-Vcvfg.js.map +0 -1
  17. package/dist/generators-zGKP8yII.cjs +0 -1349
  18. package/dist/generators-zGKP8yII.cjs.map +0 -1
  19. package/dist/generators.cjs +0 -9
  20. package/dist/generators.d.ts +0 -66
  21. package/dist/generators.js +0 -2
  22. package/dist/types-X7D0NSvJ.d.ts +0 -396
  23. package/src/components/InfiniteQuery.tsx +0 -166
  24. package/src/components/InfiniteQueryOptions.tsx +0 -166
  25. package/src/components/Mutation.tsx +0 -122
  26. package/src/components/MutationKey.tsx +0 -1
  27. package/src/components/MutationOptions.tsx +0 -104
  28. package/src/components/Query.tsx +0 -124
  29. package/src/components/QueryKey.tsx +0 -1
  30. package/src/components/QueryOptions.tsx +0 -85
  31. package/src/components/SuspenseInfiniteQuery.tsx +0 -161
  32. package/src/components/SuspenseInfiniteQueryOptions.tsx +0 -162
  33. package/src/components/SuspenseQuery.tsx +0 -119
  34. package/src/components/index.ts +0 -11
  35. package/src/generators/customHookOptionsFileGenerator.tsx +0 -90
  36. package/src/generators/hookOptionsGenerator.tsx +0 -129
  37. package/src/generators/index.ts +0 -7
  38. package/src/generators/infiniteQueryGenerator.tsx +0 -196
  39. package/src/generators/mutationGenerator.tsx +0 -172
  40. package/src/generators/queryGenerator.tsx +0 -181
  41. package/src/generators/suspenseInfiniteQueryGenerator.tsx +0 -205
  42. package/src/generators/suspenseQueryGenerator.tsx +0 -184
  43. package/src/index.ts +0 -2
  44. package/src/plugin.ts +0 -203
  45. package/src/resolvers/resolverReactQuery.ts +0 -118
  46. package/src/types.ts +0 -361
  47. package/src/utils.ts +0 -18
  48. /package/dist/{chunk-C0LytTxp.js → rolldown-runtime-C0LytTxp.js} +0 -0
package/dist/index.js CHANGED
@@ -1,14 +1,39 @@
1
- import "./chunk-C0LytTxp.js";
2
- import { d as queryKeyTransformer, h as mutationKeyTransformer, y as camelCase } from "./components-DL0Cai7l.js";
3
- import { a as infiniteQueryGenerator, i as mutationGenerator, n as suspenseInfiniteQueryGenerator, o as hookOptionsGenerator, r as queryGenerator, s as customHookOptionsFileGenerator, t as suspenseQueryGenerator } from "./generators-BG-Vcvfg.js";
1
+ import "./rolldown-runtime-C0LytTxp.js";
4
2
  import path from "node:path";
5
- import { ast, definePlugin, defineResolver } from "@kubb/core";
6
- import { isParserEnabled, pluginClientName } from "@kubb/plugin-client";
7
- import { source } from "@kubb/plugin-client/templates/clients/axios.source";
8
- import { source as source$1 } from "@kubb/plugin-client/templates/clients/fetch.source";
9
- import { source as source$2 } from "@kubb/plugin-client/templates/config.source";
10
- import { pluginTsName } from "@kubb/plugin-ts";
3
+ import { ast, defineGenerator, definePlugin, defineResolver } from "@kubb/core";
4
+ import { createFunctionParameter, createFunctionParameters, createObjectBindingPattern, createTypeLiteral, functionPrinter, pluginTsName } from "@kubb/plugin-ts";
11
5
  import { pluginZodName } from "@kubb/plugin-zod";
6
+ import { File, Function, Type, jsxRenderer } from "@kubb/renderer-jsx";
7
+ import { Fragment, jsx, jsxs } from "@kubb/renderer-jsx/jsx-runtime";
8
+ import fs from "node:fs";
9
+ import { getNestedAccessor } from "@kubb/ast/utils";
10
+ //#region ../../internals/utils/src/casing.ts
11
+ /**
12
+ * Shared implementation for camelCase and PascalCase conversion.
13
+ * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)
14
+ * and capitalizes each word according to `pascal`.
15
+ *
16
+ * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
17
+ */
18
+ function toCamelOrPascal(text, pascal) {
19
+ 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) => {
20
+ if (word.length > 1 && word === word.toUpperCase()) return word;
21
+ return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
22
+ }).join("").replace(/[^a-zA-Z0-9]/g, "");
23
+ }
24
+ /**
25
+ * Converts `text` to camelCase.
26
+ *
27
+ * @example Word boundaries
28
+ * `camelCase('hello-world') // 'helloWorld'`
29
+ *
30
+ * @example With a prefix
31
+ * `camelCase('tag', { prefix: 'create' }) // 'createTag'`
32
+ */
33
+ function camelCase(text, { prefix = "", suffix = "" } = {}) {
34
+ return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
35
+ }
36
+ //#endregion
12
37
  //#region ../../internals/utils/src/fs.ts
13
38
  /**
14
39
  * Builds a nested file path from a dotted name. Splits on dots that precede a letter
@@ -34,6 +59,393 @@ function toFilePath(name, caseLast = camelCase) {
34
59
  return parts.map((part, i) => i === parts.length - 1 ? caseLast(part) : camelCase(part)).filter(Boolean).join("/");
35
60
  }
36
61
  //#endregion
62
+ //#region ../../internals/utils/src/reserved.ts
63
+ /**
64
+ * JavaScript and Java reserved words.
65
+ * @link https://github.com/jonschlinkert/reserved/blob/master/index.js
66
+ */
67
+ const reservedWords = new Set([
68
+ "abstract",
69
+ "arguments",
70
+ "boolean",
71
+ "break",
72
+ "byte",
73
+ "case",
74
+ "catch",
75
+ "char",
76
+ "class",
77
+ "const",
78
+ "continue",
79
+ "debugger",
80
+ "default",
81
+ "delete",
82
+ "do",
83
+ "double",
84
+ "else",
85
+ "enum",
86
+ "eval",
87
+ "export",
88
+ "extends",
89
+ "false",
90
+ "final",
91
+ "finally",
92
+ "float",
93
+ "for",
94
+ "function",
95
+ "goto",
96
+ "if",
97
+ "implements",
98
+ "import",
99
+ "in",
100
+ "instanceof",
101
+ "int",
102
+ "interface",
103
+ "let",
104
+ "long",
105
+ "native",
106
+ "new",
107
+ "null",
108
+ "package",
109
+ "private",
110
+ "protected",
111
+ "public",
112
+ "return",
113
+ "short",
114
+ "static",
115
+ "super",
116
+ "switch",
117
+ "synchronized",
118
+ "this",
119
+ "throw",
120
+ "throws",
121
+ "transient",
122
+ "true",
123
+ "try",
124
+ "typeof",
125
+ "var",
126
+ "void",
127
+ "volatile",
128
+ "while",
129
+ "with",
130
+ "yield",
131
+ "Array",
132
+ "Date",
133
+ "hasOwnProperty",
134
+ "Infinity",
135
+ "isFinite",
136
+ "isNaN",
137
+ "isPrototypeOf",
138
+ "length",
139
+ "Math",
140
+ "name",
141
+ "NaN",
142
+ "Number",
143
+ "Object",
144
+ "prototype",
145
+ "String",
146
+ "toString",
147
+ "undefined",
148
+ "valueOf"
149
+ ]);
150
+ /**
151
+ * Returns `true` when `name` is a syntactically valid JavaScript variable name.
152
+ *
153
+ * @example
154
+ * ```ts
155
+ * isValidVarName('status') // true
156
+ * isValidVarName('class') // false (reserved word)
157
+ * isValidVarName('42foo') // false (starts with digit)
158
+ * ```
159
+ */
160
+ function isValidVarName(name) {
161
+ if (!name || reservedWords.has(name)) return false;
162
+ return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
163
+ }
164
+ //#endregion
165
+ //#region ../../internals/utils/src/url.ts
166
+ function transformParam(raw, casing) {
167
+ const param = isValidVarName(raw) ? raw : camelCase(raw);
168
+ return casing === "camelcase" ? camelCase(param) : param;
169
+ }
170
+ function toParamsObject(path, { replacer, casing } = {}) {
171
+ const params = {};
172
+ for (const match of path.matchAll(/\{([^}]+)\}/g)) {
173
+ const param = transformParam(match[1], casing);
174
+ const key = replacer ? replacer(param) : param;
175
+ params[key] = key;
176
+ }
177
+ return Object.keys(params).length > 0 ? params : null;
178
+ }
179
+ /**
180
+ * Helpers for OpenAPI/Swagger paths, plus a thin wrapper over the native `URL`.
181
+ */
182
+ var Url = class Url {
183
+ /**
184
+ * Reports whether `url` is a parseable absolute URL. Delegates to the native `URL.canParse`.
185
+ *
186
+ * @example
187
+ * Url.canParse('https://petstore.swagger.io/v2') // true
188
+ * Url.canParse('/pet/{petId}') // false
189
+ */
190
+ static canParse(url, base) {
191
+ return URL.canParse(url, base);
192
+ }
193
+ /**
194
+ * Converts an OpenAPI/Swagger path to Express-style colon syntax.
195
+ *
196
+ * @example
197
+ * Url.toPath('/pet/{petId}') // '/pet/:petId'
198
+ */
199
+ static toPath(path) {
200
+ return path.replace(/\{([^}]+)\}/g, ":$1");
201
+ }
202
+ /**
203
+ * Converts an OpenAPI/Swagger path to a TypeScript template literal string.
204
+ * `prefix` is prepended inside the literal, `replacer` transforms each parameter name,
205
+ * and `casing` controls parameter identifier casing.
206
+ *
207
+ * @example
208
+ * Url.toTemplateString('/pet/{petId}') // '`/pet/${petId}`'
209
+ *
210
+ * @example
211
+ * Url.toTemplateString('/pet/{petId}', { prefix: 'https://api' }) // '`https://api/pet/${petId}`'
212
+ */
213
+ static toTemplateString(path, { prefix, replacer, casing } = {}) {
214
+ const result = path.split(/\{([^}]+)\}/).map((part, i) => {
215
+ if (i % 2 === 0) return part;
216
+ const param = transformParam(part, casing);
217
+ return `\${${replacer ? replacer(param) : param}}`;
218
+ }).join("");
219
+ return `\`${prefix ?? ""}${result}\``;
220
+ }
221
+ /**
222
+ * Converts an OpenAPI/Swagger path to a template literal that reads each parameter off the
223
+ * grouped `path` request option, e.g. `/pet/{petId}` becomes `` `/pet/${path.petId}` ``. Parameter
224
+ * names are camelCased to match the generated `path` type, and `prefix` is prepended inside the
225
+ * literal. Shared by the client and cypress generators that pass a grouped `path` object.
226
+ *
227
+ * @example
228
+ * Url.toGroupedTemplateString('/pet/{petId}') // '`/pet/${path.petId}`'
229
+ */
230
+ static toGroupedTemplateString(path, { prefix } = {}) {
231
+ return Url.toTemplateString(path, {
232
+ prefix,
233
+ casing: "camelcase",
234
+ replacer: (name) => `path.${name}`
235
+ });
236
+ }
237
+ /**
238
+ * Returns the path and its extracted params as a structured `URLObject`, or as a stringified
239
+ * expression when `stringify` is set.
240
+ *
241
+ * @example
242
+ * Url.toObject('/pet/{petId}')
243
+ * // { url: '/pet/:petId', params: { petId: 'petId' } }
244
+ */
245
+ static toObject(path, { type = "path", replacer, stringify, casing } = {}) {
246
+ const object = {
247
+ url: type === "path" ? Url.toPath(path) : Url.toTemplateString(path, {
248
+ replacer,
249
+ casing
250
+ }),
251
+ params: toParamsObject(path, {
252
+ replacer,
253
+ casing
254
+ })
255
+ };
256
+ if (stringify) {
257
+ if (type === "template") return JSON.stringify(object).replaceAll("'", "").replaceAll(`"`, "");
258
+ if (object.params) return `{ url: '${object.url}', params: ${JSON.stringify(object.params).replaceAll("'", "").replaceAll(`"`, "")} }`;
259
+ return `{ url: '${object.url}' }`;
260
+ }
261
+ return object;
262
+ }
263
+ };
264
+ //#endregion
265
+ //#region ../../internals/shared/src/params.ts
266
+ const caseParamsCache = /* @__PURE__ */ new WeakMap();
267
+ /**
268
+ * Applies camelCase to parameter names and returns a new array without mutating the input.
269
+ *
270
+ * Run it before handing parameters to schema builders so output property keys get the right casing
271
+ * while `OperationNode.parameters` stays intact for other consumers. When `casing` is unset, the
272
+ * original array is returned unchanged. Results are cached per input array.
273
+ */
274
+ function caseParams(params, casing) {
275
+ if (!casing) return params;
276
+ const cached = caseParamsCache.get(params);
277
+ if (cached) return cached;
278
+ const result = params.map((param) => ({
279
+ ...param,
280
+ name: camelCase(param.name)
281
+ }));
282
+ caseParamsCache.set(params, result);
283
+ return result;
284
+ }
285
+ //#endregion
286
+ //#region ../../internals/shared/src/operation.ts
287
+ /**
288
+ * Builds the `ResolverFileParams` every operation generator passes to
289
+ * `resolver.resolveFile`: a file named `name`, tagged by the operation's first
290
+ * tag (or `'default'`), at the operation's path. Centralizes the entry object
291
+ * that was repeated at dozens of call sites across the client and query plugins.
292
+ *
293
+ * @example
294
+ * ```ts
295
+ * resolver.resolveFile(operationFileEntry(node, node.operationId), { root, output, group })
296
+ * ```
297
+ */
298
+ function operationFileEntry(node, name, extname = ".ts") {
299
+ return {
300
+ name,
301
+ extname,
302
+ tag: node.tags[0] ?? "default",
303
+ path: node.path
304
+ };
305
+ }
306
+ function getOperationLink(node, link) {
307
+ if (!link) return null;
308
+ if (typeof link === "function") return link(node) ?? null;
309
+ if (link === "urlPath") return node.path ? `{@link ${Url.toPath(node.path)}}` : null;
310
+ return node.path ? `{@link ${node.path.replaceAll("{", ":").replaceAll("}", "")}}` : null;
311
+ }
312
+ function getContentTypeInfo(node) {
313
+ const contentTypes = node.requestBody?.content?.map((e) => e.contentType) ?? [];
314
+ const isMultipleContentTypes = contentTypes.length > 1;
315
+ return {
316
+ contentTypes,
317
+ isMultipleContentTypes,
318
+ contentTypeUnion: isMultipleContentTypes ? contentTypes.map((ct) => JSON.stringify(ct)).join(" | ") : "",
319
+ defaultContentType: contentTypes[0] ?? "application/json",
320
+ hasFormData: contentTypes.some((ct) => ct === "multipart/form-data")
321
+ };
322
+ }
323
+ function buildRequestConfigType(node) {
324
+ const { isMultipleContentTypes, contentTypeUnion } = getContentTypeInfo(node);
325
+ const configType = `Partial<Omit<RequestConfig, 'path' | 'query' | 'body' | 'headers' | 'url'>>`;
326
+ const contentTypeProp = isMultipleContentTypes ? `contentType?: ${contentTypeUnion}` : null;
327
+ return contentTypeProp ? `${configType} & { ${contentTypeProp} }` : configType;
328
+ }
329
+ /**
330
+ * Builds the `client?:` option type shared by the generated query hooks (`useQuery`,
331
+ * `useInfiniteQuery`, `useSWR`, ...). Unlike {@link buildRequestConfigType}, it never adds a
332
+ * `contentType?:` member: query hooks wrap GET operations, which carry no request body to select a
333
+ * content type for.
334
+ */
335
+ function buildClientOptionType() {
336
+ return `Partial<Omit<RequestConfig, 'path' | 'query' | 'body' | 'headers' | 'url'>>`;
337
+ }
338
+ /**
339
+ * Which of the grouped request options an operation carries.
340
+ */
341
+ function getRequestGroups(node) {
342
+ const { path, query, header } = getOperationParameters(node);
343
+ return {
344
+ path: path.length > 0,
345
+ query: query.length > 0,
346
+ body: Boolean(node.requestBody?.content?.[0]?.schema),
347
+ headers: header.length > 0
348
+ };
349
+ }
350
+ /**
351
+ * Resolves which grouped request options an operation carries together with whether each group
352
+ * holds a required member. The grouped parameter stays optional only when nothing inside it is
353
+ * required, matching the generated `RequestConfig` type.
354
+ */
355
+ function getRequestGroupOptionality(node) {
356
+ const groups = getRequestGroups(node);
357
+ const { path, query, header } = getOperationParameters(node);
358
+ const hasRequiredPath = path.some((param) => param.required);
359
+ const hasRequiredQuery = query.some((param) => param.required);
360
+ const hasRequiredHeader = header.some((param) => param.required);
361
+ return {
362
+ groups,
363
+ hasRequiredPath,
364
+ hasRequiredQuery,
365
+ hasRequiredHeader,
366
+ isOptional: !hasRequiredPath && !hasRequiredQuery && !hasRequiredHeader && !groups.body
367
+ };
368
+ }
369
+ function buildOperationComments(node, options = {}) {
370
+ const { link = "pathTemplate", linkPosition = "afterDeprecated", splitLines = false } = options;
371
+ const linkComment = getOperationLink(node, link);
372
+ const filteredComments = (linkPosition === "beforeDeprecated" ? [
373
+ node.description && `@description ${node.description}`,
374
+ node.summary && `@summary ${node.summary}`,
375
+ linkComment,
376
+ node.deprecated && "@deprecated"
377
+ ] : [
378
+ node.description && `@description ${node.description}`,
379
+ node.summary && `@summary ${node.summary}`,
380
+ node.deprecated && "@deprecated",
381
+ linkComment
382
+ ]).filter((comment) => Boolean(comment));
383
+ if (!splitLines) return filteredComments;
384
+ return filteredComments.flatMap((text) => text.split(/\r?\n/).map((line) => line.trim())).filter((comment) => Boolean(comment));
385
+ }
386
+ function getOperationParameters(node, options = {}) {
387
+ const params = caseParams(node.parameters, options.paramsCasing === "original" ? void 0 : "camelcase");
388
+ return {
389
+ path: params.filter((param) => param.in === "path"),
390
+ query: params.filter((param) => param.in === "query"),
391
+ header: params.filter((param) => param.in === "header"),
392
+ cookie: params.filter((param) => param.in === "cookie")
393
+ };
394
+ }
395
+ function getStatusCodeNumber(statusCode) {
396
+ const code = Number(statusCode);
397
+ return Number.isNaN(code) ? null : code;
398
+ }
399
+ function isSuccessStatusCode(statusCode) {
400
+ const code = getStatusCodeNumber(statusCode);
401
+ return code !== null && code >= 200 && code < 300;
402
+ }
403
+ function isErrorStatusCode(statusCode) {
404
+ const code = getStatusCodeNumber(statusCode);
405
+ return code !== null && code >= 400;
406
+ }
407
+ function resolveErrorNames(node, resolver) {
408
+ return node.responses.filter((response) => isErrorStatusCode(response.statusCode)).map((response) => resolver.resolveResponseStatusName(node, response.statusCode));
409
+ }
410
+ function resolveSuccessNames(node, resolver) {
411
+ return node.responses.filter((response) => isSuccessStatusCode(response.statusCode)).map((response) => resolver.resolveResponseStatusName(node, response.statusCode));
412
+ }
413
+ function resolveStatusCodeNames(node, resolver) {
414
+ return node.responses.map((response) => resolver.resolveResponseStatusName(node, response.statusCode));
415
+ }
416
+ const typeNamesByResolver = /* @__PURE__ */ new WeakMap();
417
+ function resolveOperationTypeNames(node, resolver, options = {}) {
418
+ const cacheKey = `${node.operationId}\0${options.paramsCasing ?? ""}\0${options.order ?? ""}\0${options.responseStatusNames ?? ""}\0${options.includeParams === false ? "noparams" : ""}\0${(options.exclude ?? []).join(",")}`;
419
+ let byResolver = typeNamesByResolver.get(resolver);
420
+ if (byResolver) {
421
+ const cached = byResolver.get(cacheKey);
422
+ if (cached) return cached;
423
+ } else {
424
+ byResolver = /* @__PURE__ */ new Map();
425
+ typeNamesByResolver.set(resolver, byResolver);
426
+ }
427
+ const { path, query, header } = getOperationParameters(node, { paramsCasing: options.paramsCasing });
428
+ const responseStatusNames = options.responseStatusNames === "error" ? resolveErrorNames(node, resolver) : options.responseStatusNames === false ? [] : resolveStatusCodeNames(node, resolver);
429
+ const exclude = new Set(options.exclude ?? []);
430
+ const paramNames = options.includeParams === false ? [] : [
431
+ ...path.map((param) => resolver.resolvePathParamsName(node, param)),
432
+ ...query.map((param) => resolver.resolveQueryParamsName(node, param)),
433
+ ...header.map((param) => resolver.resolveHeaderParamsName(node, param))
434
+ ];
435
+ const bodyAndResponseNames = [node.requestBody?.content?.[0]?.schema ? resolver.resolveDataName(node) : null, resolver.resolveResponseName(node)];
436
+ const result = (options.order === "body-response-first" ? [
437
+ ...bodyAndResponseNames,
438
+ ...paramNames,
439
+ ...responseStatusNames
440
+ ] : [
441
+ ...paramNames,
442
+ ...bodyAndResponseNames,
443
+ ...responseStatusNames
444
+ ]).filter((name) => Boolean(name) && !exclude.has(name));
445
+ byResolver.set(cacheKey, result);
446
+ return result;
447
+ }
448
+ //#endregion
37
449
  //#region ../../internals/shared/src/group.ts
38
450
  /**
39
451
  * Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the
@@ -65,6 +477,2060 @@ function createGroupConfig(group) {
65
477
  };
66
478
  }
67
479
  //#endregion
480
+ //#region ../../internals/client/src/builders/parser.ts
481
+ /**
482
+ * Returns `true` when any direction of the parser uses zod (used for dependency checks).
483
+ */
484
+ function isParserEnabled(parser) {
485
+ if (!parser) return false;
486
+ if (parser === "zod") return true;
487
+ return Boolean(parser.request || parser.response);
488
+ }
489
+ //#endregion
490
+ //#region ../../internals/client/src/resolveClient.ts
491
+ /**
492
+ * Resolves which client plugin a consumer (react-query, vue-query, swr, mcp) should call for an
493
+ * operation, shared so the selection rules and diagnostics stay in one place.
494
+ *
495
+ * Every client runtime lives in a dedicated client plugin, so a consumer always calls a registered
496
+ * contract client plugin (plugin-fetch or plugin-axios) and never emits its own inline client:
497
+ *
498
+ * - `contract` — a registered contract client plugin owns the `<op>` functions and the consumer
499
+ * imports and calls them.
500
+ * - `error` — no client plugin is registered, several are registered without a selector, or the
501
+ * requested one is missing.
502
+ *
503
+ * The `client` string selects explicitly (`'fetch'` / `'axios'`); when it is unset a lone registered
504
+ * contract client plugin is picked up automatically.
505
+ */
506
+ const pluginFetchName = "plugin-fetch";
507
+ const pluginAxiosName = "plugin-axios";
508
+ const selectorToPlugin = {
509
+ fetch: pluginFetchName,
510
+ axios: pluginAxiosName
511
+ };
512
+ const contractPlugins = [pluginFetchName, pluginAxiosName];
513
+ /**
514
+ * Applies the `client` resolution rules. See the module comment for the strategy shape.
515
+ *
516
+ * @example
517
+ * ```ts
518
+ * resolveClient({ client: 'fetch', pluginNames: ['plugin-ts', 'plugin-fetch'] })
519
+ * // { kind: 'contract', pluginName: 'plugin-fetch' }
520
+ * ```
521
+ *
522
+ * @example
523
+ * ```ts
524
+ * resolveClient({ client: undefined, pluginNames: ['plugin-ts'] })
525
+ * // { kind: 'error', message: 'No client plugin is registered…' }
526
+ * ```
527
+ */
528
+ function resolveClient(options) {
529
+ const { client, pluginNames } = options;
530
+ const has = (name) => pluginNames.includes(name);
531
+ if (client === "fetch" || client === "axios") {
532
+ const pluginName = selectorToPlugin[client];
533
+ if (!has(pluginName)) return {
534
+ kind: "error",
535
+ message: `\`client: '${client}'\` is set but \`@kubb/plugin-${client}\` is not registered in \`plugins\`. Add it, or drop \`client\` to use a different client plugin.`
536
+ };
537
+ return {
538
+ kind: "contract",
539
+ pluginName
540
+ };
541
+ }
542
+ const registered = contractPlugins.filter(has);
543
+ if (registered.length === 1) return {
544
+ kind: "contract",
545
+ pluginName: registered[0]
546
+ };
547
+ if (registered.length > 1) return {
548
+ kind: "error",
549
+ message: `Multiple client plugins are registered (${registered.map((name) => `\`@kubb/${name}\``).join(", ")}). Set \`client: 'fetch' | 'axios'\` to choose which client the hooks call, or register a single client plugin.`
550
+ };
551
+ return {
552
+ kind: "error",
553
+ message: "No client plugin is registered. Add `@kubb/plugin-axios` or `@kubb/plugin-fetch` to `plugins` so the generated code has an HTTP client to call."
554
+ };
555
+ }
556
+ //#endregion
557
+ //#region ../../internals/client/src/resolveClientOperation.ts
558
+ /**
559
+ * Resolves the contract client `<op>` a consumer (query hook, MCP handler) imports, by looking up
560
+ * the registered contract client plugin's resolver and output. Works for any contract client plugin
561
+ * (plugin-fetch or plugin-axios). Returns `null` when no contract plugin is in play (the inline
562
+ * path). The plugin injects `.kubb/client.ts` at the global output root, the same path consumers
563
+ * read `RequestConfig` / `ResponseErrorConfig` from.
564
+ */
565
+ function resolveClientOperation(options) {
566
+ const { clientPlugin, driver, node, root, output } = options;
567
+ if (!clientPlugin) return null;
568
+ const resolver = driver.getResolver(clientPlugin.pluginName);
569
+ if (!resolver) return null;
570
+ const plugin = driver.getPlugin(clientPlugin.pluginName);
571
+ const file = resolver.resolveFile(operationFileEntry(node, node.operationId), {
572
+ root,
573
+ output: plugin?.options?.output ?? output,
574
+ group: plugin?.options?.group ?? void 0
575
+ });
576
+ return {
577
+ name: resolver.resolveName(node.operationId),
578
+ path: file.path,
579
+ clientPath: path.resolve(root, ".kubb/client.ts")
580
+ };
581
+ }
582
+ //#endregion
583
+ //#region ../../internals/tanstack-query/src/components/MutationKey.tsx
584
+ const declarationPrinter$10 = functionPrinter({ mode: "declaration" });
585
+ const mutationKeyTransformer = ({ node }) => {
586
+ if (!node.path) return [];
587
+ return [`{ url: '${Url.toPath(node.path)}' }`];
588
+ };
589
+ function MutationKey({ name, node, transformer }) {
590
+ const paramsNode = createFunctionParameters({ params: [] });
591
+ const paramsSignature = declarationPrinter$10.print(paramsNode) ?? "";
592
+ const keys = (transformer ?? mutationKeyTransformer)({
593
+ node,
594
+ casing: "camelcase"
595
+ });
596
+ return /* @__PURE__ */ jsx(File.Source, {
597
+ name,
598
+ isExportable: true,
599
+ isIndexable: true,
600
+ children: /* @__PURE__ */ jsx(Function.Arrow, {
601
+ name,
602
+ export: true,
603
+ params: paramsSignature,
604
+ singleLine: true,
605
+ children: `[${keys.join(", ")}] as const`
606
+ })
607
+ });
608
+ }
609
+ //#endregion
610
+ //#region ../../internals/tanstack-query/src/utils.ts
611
+ /**
612
+ * The grouped request options, ordered for both the destructured signature and the
613
+ * call passed to the underlying client.
614
+ */
615
+ const requestGroupOrder = [
616
+ "path",
617
+ "query",
618
+ "body",
619
+ "headers"
620
+ ];
621
+ /**
622
+ * Builds the grouped `{ path, query, body, headers }` parameter that mirrors the client
623
+ * function signature. Only the groups the operation carries are emitted, typed from the
624
+ * operation's `RequestConfig`. `keys` narrows the emitted groups, used by the query key which
625
+ * never carries `headers`.
626
+ *
627
+ * By default the whole group is typed as the single `RequestConfig` reference. When
628
+ * `memberTypeWrapper` is set, each group is emitted as its own member typed from the matching
629
+ * `RequestConfig['<group>']` slice and wrapped, used by vue-query to apply
630
+ * `MaybeRefOrGetter` per group.
631
+ */
632
+ function buildGroupedRequestParam(node, options) {
633
+ const { resolver, keys = requestGroupOrder, memberTypeWrapper } = options;
634
+ const { groups, hasRequiredPath, hasRequiredQuery, hasRequiredHeader } = getRequestGroupOptionality(node);
635
+ const names = keys.filter((key) => groups[key]);
636
+ if (names.length === 0) return null;
637
+ const requiredByGroup = {
638
+ path: hasRequiredPath,
639
+ query: hasRequiredQuery,
640
+ body: groups.body,
641
+ headers: hasRequiredHeader
642
+ };
643
+ const isOptional = names.every((name) => !requiredByGroup[name]);
644
+ const requestConfigName = resolver.resolveRequestConfigName(node);
645
+ const omittedKeys = requestGroupOrder.filter((key) => !keys.includes(key));
646
+ const requestConfigType = omittedKeys.length > 0 ? `Omit<${requestConfigName}, ${omittedKeys.map((key) => `'${key}'`).join(" | ")}>` : requestConfigName;
647
+ if (memberTypeWrapper) {
648
+ const members = names.map((name) => ({
649
+ name,
650
+ type: memberTypeWrapper(`${requestConfigType}['${name}']`),
651
+ optional: !requiredByGroup[name]
652
+ }));
653
+ return createFunctionParameter({
654
+ name: createObjectBindingPattern({ elements: names.map((name) => ({ name })) }),
655
+ type: createTypeLiteral({ members }),
656
+ optional: false,
657
+ ...isOptional ? { default: "{}" } : {}
658
+ });
659
+ }
660
+ return createFunctionParameter({
661
+ name: createObjectBindingPattern({ elements: names.map((name) => ({ name })) }),
662
+ type: requestConfigType,
663
+ optional: false,
664
+ ...isOptional ? { default: "{}" } : {}
665
+ });
666
+ }
667
+ /**
668
+ * Builds the shared `({ path, query, body, headers }, config = {})` parameter list for a
669
+ * TanStack query-options function. The leading parameter mirrors the client signature, and the
670
+ * trailing `config` is a partial `RequestConfig` minus the grouped data-shape keys, which are passed
671
+ * explicitly. Framework plugins wrap the result when needed, for example vue-query applies `MaybeRefOrGetter`.
672
+ */
673
+ function buildQueryOptionsParams(node, options) {
674
+ const { resolver, memberTypeWrapper } = options;
675
+ return createFunctionParameters({ params: [buildGroupedRequestParam(node, {
676
+ resolver,
677
+ memberTypeWrapper
678
+ }), createFunctionParameter({
679
+ name: "config",
680
+ type: `Partial<Omit<RequestConfig, 'path' | 'query' | 'body' | 'headers' | 'url'>>`,
681
+ default: "{}"
682
+ })].filter((param) => param !== null) });
683
+ }
684
+ /**
685
+ * Builds the call to a client `<op>` function inside a query/mutation hook body. The function takes
686
+ * a single grouped options object, so the operation's request groups are passed as
687
+ * shorthand alongside the spread `config`, with `throwOnError: true` pinned last so a caller's config
688
+ * can't flip the query's error semantics. Queries thread the TanStack `signal`; mutations omit it.
689
+ *
690
+ * @example
691
+ * ```ts
692
+ * buildClientCall(node, { clientName: 'getPetById', signal: true })
693
+ * // getPetById({ path, ...config, signal: config.signal ?? signal, throwOnError: true })
694
+ * ```
695
+ */
696
+ function buildClientCall(node, options) {
697
+ const { clientName, signal = false } = options;
698
+ const { groups } = getRequestGroupOptionality(node);
699
+ return `${clientName}({ ${[
700
+ "...config",
701
+ ...requestGroupOrder.filter((key) => groups[key]),
702
+ signal ? "signal: config.signal ?? signal" : null,
703
+ "throwOnError: true"
704
+ ].filter((part) => part !== null).join(", ")} })`;
705
+ }
706
+ function matchesPattern(node, ov) {
707
+ const { type, pattern } = ov;
708
+ const matches = (value) => typeof pattern === "string" ? value === pattern : pattern.test(value);
709
+ if (type === "operationId") return matches(node.operationId);
710
+ if (type === "tag") return node.tags.some((t) => matches(t));
711
+ if (type === "path") return node.path !== void 0 && matches(node.path);
712
+ if (type === "method") return node.method !== void 0 && matches(node.method);
713
+ return false;
714
+ }
715
+ /**
716
+ * Resolves per-operation overrides (first matching override wins).
717
+ *
718
+ * @example
719
+ * ```ts
720
+ * const opts = resolveOperationOverrides(node, override)
721
+ * const queryOpts = 'query' in opts ? opts.query : defaultQuery
722
+ * ```
723
+ */
724
+ function resolveOperationOverrides(node, override) {
725
+ if (!override) return {};
726
+ return override.find((ov) => matchesPattern(node, ov))?.options ?? {};
727
+ }
728
+ /**
729
+ * Returns `'zod'` when response-direction parsing is enabled.
730
+ * The string shorthand `'zod'` also enables response parsing.
731
+ */
732
+ function resolveResponseParser(parser) {
733
+ if (!parser) return null;
734
+ if (parser === "zod") return "zod";
735
+ return parser.response ?? null;
736
+ }
737
+ /**
738
+ * Returns `'zod'` when request body parsing is enabled.
739
+ * The string shorthand `'zod'` also enables request body parsing (existing behavior).
740
+ */
741
+ function resolveRequestParser(parser) {
742
+ if (!parser) return null;
743
+ if (parser === "zod") return "zod";
744
+ return parser.request ?? null;
745
+ }
746
+ /**
747
+ * Returns `'zod'` when query-params parsing is enabled.
748
+ * Only the object form `{ request: 'zod' }` enables this. `parser: 'zod'` does not.
749
+ */
750
+ function resolveQueryParamsParser(parser) {
751
+ if (!parser || parser === "zod") return null;
752
+ return parser.request ?? null;
753
+ }
754
+ /**
755
+ * Collects the Zod schema import names for an operation based on the active parser directions.
756
+ *
757
+ * - `parser: 'zod'`: response and request body names (backward-compatible behavior).
758
+ * - `parser: { request: 'zod' }`: request body and query params names.
759
+ * - `parser: { response: 'zod' }`: response name only.
760
+ * - `parser: { request: 'zod', response: 'zod' }`: all three.
761
+ *
762
+ * Returns an empty array when no resolver is provided or `parser` is falsy.
763
+ */
764
+ function resolveZodSchemaNames(node, zodResolver, parser) {
765
+ if (!zodResolver || !parser) return [];
766
+ const { query: queryParams } = getOperationParameters(node, { paramsCasing: "original" });
767
+ return [
768
+ resolveResponseParser(parser) === "zod" ? zodResolver.resolveResponseName?.(node) : null,
769
+ resolveRequestParser(parser) === "zod" && node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : null,
770
+ resolveQueryParamsParser(parser) === "zod" && queryParams.length > 0 ? zodResolver.resolveQueryParamsName?.(node, queryParams[0]) : null
771
+ ].filter((n) => Boolean(n));
772
+ }
773
+ /**
774
+ * Build QueryKey params as the grouped `{ path, query, body }` object (NO headers, NO config),
775
+ * typed from the operation's `RequestConfig` minus `url`. The query key transformer reads the
776
+ * grouped `path`/`query`/`body` bindings.
777
+ */
778
+ function buildQueryKeyParams(node, options) {
779
+ const { resolver } = options;
780
+ const groupedParam = buildGroupedRequestParam(node, {
781
+ resolver,
782
+ keys: [
783
+ "path",
784
+ "query",
785
+ "body"
786
+ ]
787
+ });
788
+ return createFunctionParameters({ params: groupedParam ? [groupedParam] : [] });
789
+ }
790
+ //#endregion
791
+ //#region ../../internals/tanstack-query/src/components/QueryKey.tsx
792
+ const declarationPrinter$9 = functionPrinter({ mode: "declaration" });
793
+ const queryKeyTransformer = ({ node }) => {
794
+ if (!node.path) return [];
795
+ const hasPathParams = getOperationParameters(node).path.length > 0;
796
+ const hasQueryParams = getOperationParameters(node).query.length > 0;
797
+ const hasRequestBody = !!node.requestBody?.content?.[0]?.schema;
798
+ return [
799
+ hasPathParams ? `{ url: '${Url.toPath(node.path)}', params: path }` : `{ url: '${Url.toPath(node.path)}' }`,
800
+ hasQueryParams ? "...(query ? [query] : [])" : null,
801
+ hasRequestBody ? "...(body ? [body] : [])" : null
802
+ ].filter(Boolean);
803
+ };
804
+ function QueryKey({ name, node, tsResolver, typeName, transformer }) {
805
+ const paramsNode = buildQueryKeyParams(node, { resolver: tsResolver });
806
+ const paramsSignature = declarationPrinter$9.print(paramsNode) ?? "";
807
+ const keys = (transformer ?? queryKeyTransformer)({
808
+ node,
809
+ casing: "camelcase"
810
+ });
811
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(File.Source, {
812
+ name,
813
+ isExportable: true,
814
+ isIndexable: true,
815
+ children: /* @__PURE__ */ jsx(Function.Arrow, {
816
+ name,
817
+ export: true,
818
+ params: paramsSignature,
819
+ singleLine: true,
820
+ children: `[${keys.join(", ")}] as const`
821
+ })
822
+ }), /* @__PURE__ */ jsx(File.Source, {
823
+ name: typeName,
824
+ isTypeOnly: true,
825
+ children: /* @__PURE__ */ jsx(Type, {
826
+ name: typeName,
827
+ children: `ReturnType<typeof ${name}>`
828
+ })
829
+ })] });
830
+ }
831
+ //#endregion
832
+ //#region src/generators/customHookOptionsFileGenerator.tsx
833
+ /**
834
+ * Scaffolds the user-editable `useCustomHookOptions` file when
835
+ * `pluginReactQuery({ customOptions: { ... } })` is configured. The file is
836
+ * only created when it does not already exist, so user edits persist across
837
+ * regeneration.
838
+ */
839
+ const customHookOptionsFileGenerator = defineGenerator({
840
+ name: "react-query-custom-hook-options-file",
841
+ renderer: jsxRenderer,
842
+ operations(nodes, ctx) {
843
+ const { resolver, root } = ctx;
844
+ const { output, customOptions, query, group } = ctx.options;
845
+ if (!customOptions) return null;
846
+ const { importPath, name } = customOptions;
847
+ const hookOptionsName = resolver.resolveHookOptionsName();
848
+ const customHookOptionsName = resolver.resolveCustomHookOptionsName();
849
+ const reactQueryImportPath = query ? query.importPath : "@tanstack/react-query";
850
+ let hookFilePath;
851
+ const firstNode = nodes[0];
852
+ if (firstNode) {
853
+ const hookName = resolver.resolveQueryName(firstNode);
854
+ hookFilePath = resolver.resolveFile({
855
+ name: hookName,
856
+ extname: ".ts",
857
+ tag: firstNode.tags[0] ?? "default",
858
+ path: firstNode.path
859
+ }, {
860
+ root,
861
+ output,
862
+ group: group ?? void 0
863
+ }).path;
864
+ } else hookFilePath = path.resolve(root, "index.ts");
865
+ const ensureExtension = (filePath, extname) => {
866
+ if (path.extname(filePath) === "") return filePath + extname;
867
+ return filePath;
868
+ };
869
+ const basePath = path.dirname(hookFilePath);
870
+ const actualFilePath = ensureExtension(importPath, ".ts");
871
+ const file = {
872
+ baseName: path.basename(actualFilePath),
873
+ name: path.basename(actualFilePath, path.extname(actualFilePath)),
874
+ path: path.resolve(basePath, actualFilePath)
875
+ };
876
+ if (fs.existsSync(file.path)) return null;
877
+ return /* @__PURE__ */ jsxs(File, {
878
+ baseName: file.baseName,
879
+ path: file.path,
880
+ children: [
881
+ /* @__PURE__ */ jsx(File.Import, {
882
+ name: ["QueryClient"],
883
+ path: reactQueryImportPath,
884
+ isTypeOnly: true
885
+ }),
886
+ /* @__PURE__ */ jsx(File.Import, {
887
+ name: ["useQueryClient"],
888
+ path: reactQueryImportPath
889
+ }),
890
+ /* @__PURE__ */ jsx(File.Import, {
891
+ name: [hookOptionsName],
892
+ root: file.path,
893
+ path: path.resolve(root, "./index.ts")
894
+ }),
895
+ /* @__PURE__ */ jsxs(File.Source, {
896
+ name: file.name,
897
+ isExportable: true,
898
+ isIndexable: true,
899
+ children: [/* @__PURE__ */ jsx(Function, {
900
+ name: customHookOptionsName,
901
+ params: "{ queryClient }: { queryClient: QueryClient }",
902
+ returnType: `Partial<${hookOptionsName}>`,
903
+ children: `return {
904
+ // TODO: Define custom hook options here
905
+ // Example:
906
+ // useUpdatePetHook: {
907
+ // onSuccess: () => {
908
+ // void queryClient.invalidateQueries({ queryKey: ['pet'] })
909
+ // }
910
+ // }
911
+ }`
912
+ }), /* @__PURE__ */ jsx(Function, {
913
+ name,
914
+ generics: `T extends keyof ${hookOptionsName}`,
915
+ params: "{ hookName, operationId }: { hookName: T, operationId: string }",
916
+ returnType: `${hookOptionsName}[T]`,
917
+ export: true,
918
+ children: `const queryClient = useQueryClient()
919
+ const customOptions = ${customHookOptionsName}({ queryClient })
920
+ return customOptions[hookName] ?? {}`
921
+ })]
922
+ })
923
+ ]
924
+ });
925
+ }
926
+ });
927
+ //#endregion
928
+ //#region src/generators/hookOptionsGenerator.tsx
929
+ /**
930
+ * Emits the `HookOptions` type used by `customOptions`. Enabled when
931
+ * `pluginReactQuery({ customOptions: { ... } })`. The generated type lists
932
+ * every hook keyed by name so user-supplied options stay in sync with the
933
+ * generated hooks at compile time.
934
+ */
935
+ const hookOptionsGenerator = defineGenerator({
936
+ name: "react-query-hook-options",
937
+ renderer: jsxRenderer,
938
+ operations(nodes, ctx) {
939
+ const { resolver, config, root } = ctx;
940
+ const { output, customOptions, query, mutation, suspense, infinite, group, override } = ctx.options;
941
+ if (!customOptions) return null;
942
+ const name = resolver.resolveHookOptionsName();
943
+ const resolvedFile = resolver.resolveFile({
944
+ name,
945
+ extname: ".ts"
946
+ }, {
947
+ root,
948
+ output,
949
+ group: group ?? void 0
950
+ });
951
+ const hookOptionsFile = {
952
+ ...resolvedFile,
953
+ baseName: `${name}.ts`,
954
+ path: resolvedFile.path.replace(/[^/\\]+\.ts$/, `${name}.ts`)
955
+ };
956
+ const imports = [];
957
+ const hookOptions = {};
958
+ for (const node of nodes) {
959
+ if (!ast.isHttpOperationNode(node)) continue;
960
+ const opOverrides = resolveOperationOverrides(node, override);
961
+ const nodeQuery = "query" in opOverrides ? opOverrides.query : query;
962
+ const nodeMutation = "mutation" in opOverrides ? opOverrides.mutation : mutation;
963
+ const nodeInfinite = "infinite" in opOverrides ? opOverrides.infinite : infinite;
964
+ const nodeInfiniteOptions = nodeInfinite && typeof nodeInfinite === "object" ? nodeInfinite : null;
965
+ const isQueryOp = nodeQuery === false ? !!query && query.methods.some((m) => node.method.toLowerCase() === m.toLowerCase()) : !!nodeQuery && nodeQuery.methods.some((m) => node.method.toLowerCase() === m.toLowerCase());
966
+ const nodeQueryMethods = new Set(nodeQuery ? nodeQuery.methods : []);
967
+ const isMutationOp = nodeMutation !== false && !isQueryOp && (nodeMutation ? nodeMutation.methods : []).some((m) => !nodeQueryMethods.has(m) && node.method.toLowerCase() === m.toLowerCase());
968
+ const isSuspenseOp = !!suspense;
969
+ const isInfiniteOp = !!nodeInfiniteOptions;
970
+ if (isQueryOp) {
971
+ const queryOptionsName = resolver.resolveQueryOptionsName(node);
972
+ const queryHookName = resolver.resolveQueryName(node);
973
+ const queryHookFile = resolver.resolveFile(operationFileEntry(node, queryHookName), {
974
+ root,
975
+ output,
976
+ group: group ?? void 0
977
+ });
978
+ imports.push(/* @__PURE__ */ jsx(File.Import, {
979
+ name: [queryOptionsName],
980
+ root: hookOptionsFile.path,
981
+ path: queryHookFile.path
982
+ }));
983
+ hookOptions[queryHookName] = `Partial<ReturnType<typeof ${queryOptionsName}>>`;
984
+ if (isSuspenseOp) {
985
+ const suspenseOptionsName = resolver.resolveSuspenseQueryOptionsName(node);
986
+ const suspenseHookName = resolver.resolveSuspenseQueryName(node);
987
+ const suspenseHookFile = resolver.resolveFile(operationFileEntry(node, suspenseHookName), {
988
+ root,
989
+ output,
990
+ group: group ?? void 0
991
+ });
992
+ imports.push(/* @__PURE__ */ jsx(File.Import, {
993
+ name: [suspenseOptionsName],
994
+ root: hookOptionsFile.path,
995
+ path: suspenseHookFile.path
996
+ }));
997
+ hookOptions[suspenseHookName] = `Partial<ReturnType<typeof ${suspenseOptionsName}>>`;
998
+ }
999
+ if (isInfiniteOp) {
1000
+ const normalizeKey = (key) => key.replace(/\?$/, "");
1001
+ const queryParamKeys = getOperationParameters(node, { paramsCasing: "original" }).query.map((p) => p.name);
1002
+ if (nodeInfiniteOptions.queryParam ? queryParamKeys.some((k) => normalizeKey(k) === nodeInfiniteOptions.queryParam) : false) {
1003
+ const infiniteOptionsName = resolver.resolveInfiniteQueryOptionsName(node);
1004
+ const infiniteHookName = resolver.resolveInfiniteQueryName(node);
1005
+ const infiniteHookFile = resolver.resolveFile(operationFileEntry(node, infiniteHookName), {
1006
+ root,
1007
+ output,
1008
+ group: group ?? void 0
1009
+ });
1010
+ imports.push(/* @__PURE__ */ jsx(File.Import, {
1011
+ name: [infiniteOptionsName],
1012
+ root: hookOptionsFile.path,
1013
+ path: infiniteHookFile.path
1014
+ }));
1015
+ hookOptions[infiniteHookName] = `Partial<ReturnType<typeof ${infiniteOptionsName}>>`;
1016
+ if (isSuspenseOp) {
1017
+ const suspenseInfiniteOptionsName = resolver.resolveSuspenseInfiniteQueryOptionsName(node);
1018
+ const suspenseInfiniteHookName = resolver.resolveSuspenseInfiniteQueryName(node);
1019
+ const suspenseInfiniteHookFile = resolver.resolveFile(operationFileEntry(node, suspenseInfiniteHookName), {
1020
+ root,
1021
+ output,
1022
+ group: group ?? void 0
1023
+ });
1024
+ imports.push(/* @__PURE__ */ jsx(File.Import, {
1025
+ name: [suspenseInfiniteOptionsName],
1026
+ root: hookOptionsFile.path,
1027
+ path: suspenseInfiniteHookFile.path
1028
+ }));
1029
+ hookOptions[suspenseInfiniteHookName] = `Partial<ReturnType<typeof ${suspenseInfiniteOptionsName}>>`;
1030
+ }
1031
+ }
1032
+ }
1033
+ }
1034
+ if (isMutationOp) {
1035
+ const mutationOptionsName = resolver.resolveMutationOptionsName(node);
1036
+ const mutationHookName = resolver.resolveMutationName(node);
1037
+ const mutationHookFile = resolver.resolveFile(operationFileEntry(node, mutationHookName), {
1038
+ root,
1039
+ output,
1040
+ group: group ?? void 0
1041
+ });
1042
+ imports.push(/* @__PURE__ */ jsx(File.Import, {
1043
+ name: [mutationOptionsName],
1044
+ root: hookOptionsFile.path,
1045
+ path: mutationHookFile.path
1046
+ }));
1047
+ hookOptions[mutationHookName] = `Partial<ReturnType<typeof ${mutationOptionsName}>>`;
1048
+ }
1049
+ }
1050
+ return /* @__PURE__ */ jsxs(File, {
1051
+ baseName: hookOptionsFile.baseName,
1052
+ path: hookOptionsFile.path,
1053
+ meta: hookOptionsFile.meta,
1054
+ banner: resolver.resolveBanner(ctx.meta, {
1055
+ output,
1056
+ config,
1057
+ file: {
1058
+ path: hookOptionsFile.path,
1059
+ baseName: hookOptionsFile.baseName
1060
+ }
1061
+ }),
1062
+ footer: resolver.resolveFooter(ctx.meta, {
1063
+ output,
1064
+ config,
1065
+ file: {
1066
+ path: hookOptionsFile.path,
1067
+ baseName: hookOptionsFile.baseName
1068
+ }
1069
+ }),
1070
+ children: [imports, /* @__PURE__ */ jsx(File.Source, {
1071
+ name,
1072
+ isExportable: true,
1073
+ isIndexable: true,
1074
+ isTypeOnly: true,
1075
+ children: /* @__PURE__ */ jsx(Type, {
1076
+ export: true,
1077
+ name,
1078
+ children: `{ ${Object.keys(hookOptions).map((key) => `${JSON.stringify(key)}: ${hookOptions[key]}`).join(", ")} }`
1079
+ })
1080
+ })]
1081
+ });
1082
+ }
1083
+ });
1084
+ //#endregion
1085
+ //#region src/components/QueryOptions.tsx
1086
+ const declarationPrinter$8 = functionPrinter({ mode: "declaration" });
1087
+ const callPrinter$8 = functionPrinter({ mode: "call" });
1088
+ function getQueryOptionsParams(node, options) {
1089
+ return buildQueryOptionsParams(node, options);
1090
+ }
1091
+ function QueryOptions({ name, clientName, node, tsResolver, queryKeyName }) {
1092
+ const successNames = resolveSuccessNames(node, tsResolver);
1093
+ const responseName = successNames.length > 0 ? successNames.join(" | ") : tsResolver.resolveResponseName(node);
1094
+ const errorNames = resolveErrorNames(node, tsResolver);
1095
+ const TData = responseName;
1096
+ const TError = `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(" | ") : "Error"}>`;
1097
+ const queryKeyParamsNode = buildQueryKeyParams(node, { resolver: tsResolver });
1098
+ const queryKeyParamsCall = callPrinter$8.print(queryKeyParamsNode) ?? "";
1099
+ const paramsNode = getQueryOptionsParams(node, { resolver: tsResolver });
1100
+ const paramsSignature = declarationPrinter$8.print(paramsNode) ?? "";
1101
+ const queryFnBody = `const { data } = await ${buildClientCall(node, {
1102
+ clientName,
1103
+ signal: true
1104
+ })}
1105
+ return data`;
1106
+ return /* @__PURE__ */ jsx(File.Source, {
1107
+ name,
1108
+ isExportable: true,
1109
+ isIndexable: true,
1110
+ children: /* @__PURE__ */ jsx(Function, {
1111
+ name,
1112
+ export: true,
1113
+ params: paramsSignature,
1114
+ children: `
1115
+ const queryKey = ${queryKeyName}(${queryKeyParamsCall})
1116
+ return queryOptions<${TData}, ${TError}, ${TData}, typeof queryKey>({
1117
+ queryKey,
1118
+ queryFn: async ({ signal }) => {
1119
+ ${queryFnBody}
1120
+ },
1121
+ })
1122
+ `
1123
+ })
1124
+ });
1125
+ }
1126
+ //#endregion
1127
+ //#region src/components/InfiniteQuery.tsx
1128
+ const declarationPrinter$7 = functionPrinter({ mode: "declaration" });
1129
+ const callPrinter$7 = functionPrinter({ mode: "call" });
1130
+ function buildInfiniteQueryParamsNode(node, options) {
1131
+ const { resolver, pageParamGeneric } = options;
1132
+ const optionsParam = createFunctionParameter({
1133
+ name: "options",
1134
+ type: `{
1135
+ query?: Partial<InfiniteQueryObserverOptions<TQueryFnData, TError, TData, TQueryKey, ${pageParamGeneric}>> & { client?: QueryClient },
1136
+ client?: ${buildClientOptionType()}
1137
+ }`,
1138
+ default: "{}"
1139
+ });
1140
+ return createFunctionParameters({ params: [buildGroupedRequestParam(node, { resolver }), optionsParam].filter((param) => param !== null) });
1141
+ }
1142
+ function InfiniteQuery({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, tsResolver, initialPageParam, queryParam, customOptions }) {
1143
+ const successNames = resolveSuccessNames(node, tsResolver);
1144
+ const responseName = successNames.length > 0 ? successNames.join(" | ") : tsResolver.resolveResponseName(node);
1145
+ const errorNames = resolveErrorNames(node, tsResolver);
1146
+ const responseType = responseName;
1147
+ const errorType = `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(" | ") : "Error"}>`;
1148
+ const isInitialPageParamDefined = initialPageParam !== void 0 && initialPageParam !== null;
1149
+ const fallbackPageParamType = typeof initialPageParam === "number" ? "number" : typeof initialPageParam === "string" ? initialPageParam.includes(" as ") ? (() => {
1150
+ const parts = initialPageParam.split(" as ");
1151
+ return parts[parts.length - 1] ?? "unknown";
1152
+ })() : "string" : typeof initialPageParam === "boolean" ? "boolean" : "unknown";
1153
+ const rawQueryParams = getOperationParameters(node, { paramsCasing: "original" }).query;
1154
+ const queryParamsTypeName = rawQueryParams.length > 0 ? (() => {
1155
+ const groupName = tsResolver.resolveQueryParamsName(node, rawQueryParams[0]);
1156
+ return groupName !== tsResolver.resolveParamName(node, rawQueryParams[0]) ? groupName : null;
1157
+ })() : null;
1158
+ const queryParamType = queryParam && queryParamsTypeName ? `${queryParamsTypeName}['${queryParam}']` : null;
1159
+ const pageParamType = queryParamType ? isInitialPageParamDefined ? `NonNullable<${queryParamType}>` : queryParamType : fallbackPageParamType;
1160
+ const returnType = "UseInfiniteQueryResult<TData, TError> & { queryKey: TQueryKey }";
1161
+ const generics = [
1162
+ `TQueryFnData = ${responseType}`,
1163
+ `TError = ${errorType}`,
1164
+ "TData = InfiniteData<TQueryFnData>",
1165
+ `TQueryKey extends QueryKey = ${queryKeyTypeName}`,
1166
+ `TPageParam = ${pageParamType}`
1167
+ ];
1168
+ const queryKeyParamsNode = buildQueryKeyParams(node, { resolver: tsResolver });
1169
+ const queryKeyParamsCall = callPrinter$7.print(queryKeyParamsNode) ?? "";
1170
+ const queryOptionsParamsNode = getQueryOptionsParams(node, { resolver: tsResolver });
1171
+ const queryOptionsParamsCall = callPrinter$7.print(queryOptionsParamsNode) ?? "";
1172
+ const paramsNode = buildInfiniteQueryParamsNode(node, {
1173
+ resolver: tsResolver,
1174
+ pageParamGeneric: "TPageParam"
1175
+ });
1176
+ const paramsSignature = declarationPrinter$7.print(paramsNode) ?? "";
1177
+ return /* @__PURE__ */ jsx(File.Source, {
1178
+ name,
1179
+ isExportable: true,
1180
+ isIndexable: true,
1181
+ children: /* @__PURE__ */ jsx(Function, {
1182
+ name,
1183
+ export: true,
1184
+ generics: generics.join(", "),
1185
+ params: paramsSignature,
1186
+ returnType: void 0,
1187
+ JSDoc: { comments: buildOperationComments(node) },
1188
+ children: `
1189
+ const { query: queryConfig = {}, client: config = {} } = options ?? {}
1190
+ const { client: queryClient, ...resolvedOptions } = queryConfig
1191
+ const queryKey = resolvedOptions?.queryKey ?? ${queryKeyName}(${queryKeyParamsCall})${customOptions ? `\n const customOptions = ${customOptions.name}({ hookName: '${name}', operationId: '${node.operationId}' })` : ""}
1192
+
1193
+ const queryResult = useInfiniteQuery({
1194
+ ...${queryOptionsName}(${queryOptionsParamsCall}),${customOptions ? "\n ...customOptions," : ""}
1195
+ ...resolvedOptions,
1196
+ queryKey,
1197
+ } as unknown as InfiniteQueryObserverOptions<TQueryFnData, TError, TData, TQueryKey, TPageParam>, queryClient) as ${returnType}
1198
+
1199
+ queryResult.queryKey = queryKey as TQueryKey
1200
+
1201
+ return queryResult
1202
+ `
1203
+ })
1204
+ });
1205
+ }
1206
+ //#endregion
1207
+ //#region src/components/InfiniteQueryOptions.tsx
1208
+ const declarationPrinter$6 = functionPrinter({ mode: "declaration" });
1209
+ const callPrinter$6 = functionPrinter({ mode: "call" });
1210
+ function InfiniteQueryOptions({ name, clientName, initialPageParam, cursorParam, nextParam, previousParam, node, tsResolver, queryParam, queryKeyName }) {
1211
+ const successNames = resolveSuccessNames(node, tsResolver);
1212
+ const queryFnDataType = successNames.length > 0 ? successNames.join(" | ") : tsResolver.resolveResponseName(node);
1213
+ const errorNames = resolveErrorNames(node, tsResolver);
1214
+ const errorType = `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(" | ") : "Error"}>`;
1215
+ const isInitialPageParamDefined = initialPageParam !== void 0 && initialPageParam !== null;
1216
+ const fallbackPageParamType = typeof initialPageParam === "number" ? "number" : typeof initialPageParam === "string" ? initialPageParam.includes(" as ") ? (() => {
1217
+ const parts = initialPageParam.split(" as ");
1218
+ return parts[parts.length - 1] ?? "unknown";
1219
+ })() : "string" : typeof initialPageParam === "boolean" ? "boolean" : "unknown";
1220
+ const rawQueryParams = getOperationParameters(node, { paramsCasing: "original" }).query;
1221
+ const queryParamsTypeName = rawQueryParams.length > 0 ? (() => {
1222
+ const groupName = tsResolver.resolveQueryParamsName(node, rawQueryParams[0]);
1223
+ return groupName !== tsResolver.resolveParamName(node, rawQueryParams[0]) ? groupName : null;
1224
+ })() : null;
1225
+ const queryParamType = queryParam && queryParamsTypeName ? `${queryParamsTypeName}['${queryParam}']` : null;
1226
+ const pageParamType = queryParamType ? isInitialPageParamDefined ? `NonNullable<${queryParamType}>` : queryParamType : fallbackPageParamType;
1227
+ const queryKeyParamsNode = buildQueryKeyParams(node, { resolver: tsResolver });
1228
+ const queryKeyParamsCall = callPrinter$6.print(queryKeyParamsNode) ?? "";
1229
+ const paramsNode = getQueryOptionsParams(node, { resolver: tsResolver });
1230
+ const paramsSignature = declarationPrinter$6.print(paramsNode) ?? "";
1231
+ const queryFnBody = `const { data } = await ${buildClientCall(node, {
1232
+ clientName,
1233
+ signal: true
1234
+ })}
1235
+ return data`;
1236
+ const hasNewParams = nextParam != null || previousParam != null;
1237
+ const [getNextPageParamExpr, getPreviousPageParamExpr] = (() => {
1238
+ if (hasNewParams) {
1239
+ const nextAccessor = nextParam ? getNestedAccessor(nextParam, "lastPage") : null;
1240
+ const prevAccessor = previousParam ? getNestedAccessor(previousParam, "firstPage") : null;
1241
+ return [nextAccessor ? `getNextPageParam: (lastPage) => ${nextAccessor}` : null, prevAccessor ? `getPreviousPageParam: (firstPage) => ${prevAccessor}` : null];
1242
+ }
1243
+ if (cursorParam) return [`getNextPageParam: (lastPage) => lastPage['${cursorParam}']`, `getPreviousPageParam: (firstPage) => firstPage['${cursorParam}']`];
1244
+ return ["getNextPageParam: (lastPage, _allPages, lastPageParam) => Array.isArray(lastPage) && lastPage.length === 0 ? undefined : lastPageParam + 1", "getPreviousPageParam: (_firstPage, _allPages, firstPageParam) => firstPageParam <= 1 ? undefined : firstPageParam - 1"];
1245
+ })();
1246
+ const queryOptionsArr = [
1247
+ `initialPageParam: ${typeof initialPageParam === "string" ? JSON.stringify(initialPageParam) : initialPageParam}`,
1248
+ getNextPageParamExpr,
1249
+ getPreviousPageParamExpr
1250
+ ].filter(Boolean);
1251
+ const infiniteOverrideParams = queryParam && queryParamsTypeName ? `query = {
1252
+ ...(query ?? {}),
1253
+ ['${queryParam}']: pageParam as unknown as ${queryParamsTypeName}['${queryParam}'],
1254
+ } as ${queryParamsTypeName}` : "";
1255
+ if (infiniteOverrideParams) return /* @__PURE__ */ jsx(File.Source, {
1256
+ name,
1257
+ isExportable: true,
1258
+ isIndexable: true,
1259
+ children: /* @__PURE__ */ jsx(Function, {
1260
+ name,
1261
+ export: true,
1262
+ params: paramsSignature,
1263
+ children: `
1264
+ const queryKey = ${queryKeyName}(${queryKeyParamsCall})
1265
+ return infiniteQueryOptions<${queryFnDataType}, ${errorType}, InfiniteData<${queryFnDataType}>, typeof queryKey, ${pageParamType}>({
1266
+ queryKey,
1267
+ queryFn: async ({ signal, pageParam }) => {
1268
+ ${infiniteOverrideParams}
1269
+ ${queryFnBody}
1270
+ },
1271
+ ${queryOptionsArr.join(",\n ")}
1272
+ })
1273
+ `
1274
+ })
1275
+ });
1276
+ return /* @__PURE__ */ jsx(File.Source, {
1277
+ name,
1278
+ isExportable: true,
1279
+ isIndexable: true,
1280
+ children: /* @__PURE__ */ jsx(Function, {
1281
+ name,
1282
+ export: true,
1283
+ params: paramsSignature,
1284
+ children: `
1285
+ const queryKey = ${queryKeyName}(${queryKeyParamsCall})
1286
+ return infiniteQueryOptions<${queryFnDataType}, ${errorType}, InfiniteData<${queryFnDataType}>, typeof queryKey, ${pageParamType}>({
1287
+ queryKey,
1288
+ queryFn: async ({ signal }) => {
1289
+ ${queryFnBody}
1290
+ },
1291
+ ${queryOptionsArr.join(",\n ")}
1292
+ })
1293
+ `
1294
+ })
1295
+ });
1296
+ }
1297
+ //#endregion
1298
+ //#region src/components/MutationOptions.tsx
1299
+ const declarationPrinter$5 = functionPrinter({ mode: "declaration" });
1300
+ const callPrinter$5 = functionPrinter({ mode: "call" });
1301
+ function buildMutationConfigParamsNode(node) {
1302
+ return createFunctionParameters({ params: [createFunctionParameter({
1303
+ name: "config",
1304
+ type: buildRequestConfigType(node),
1305
+ default: "{}"
1306
+ })] });
1307
+ }
1308
+ function MutationOptions({ name, clientName, node, tsResolver, mutationKeyName }) {
1309
+ const successNames = resolveSuccessNames(node, tsResolver);
1310
+ const TData = successNames.length > 0 ? successNames.join(" | ") : tsResolver.resolveResponseName(node);
1311
+ const errorNames = resolveErrorNames(node, tsResolver);
1312
+ const TError = `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(" | ") : "Error"}>`;
1313
+ const configParamsNode = buildMutationConfigParamsNode(node);
1314
+ const paramsSignature = declarationPrinter$5.print(configParamsNode) ?? "";
1315
+ const groupedParam = buildGroupedRequestParam(node, { resolver: tsResolver });
1316
+ const hasMutationParams = groupedParam !== null;
1317
+ const groupedParamsNode = createFunctionParameters({ params: groupedParam ? [groupedParam] : [] });
1318
+ const TRequest = hasMutationParams ? tsResolver.resolveRequestConfigName(node) : "undefined";
1319
+ const argBindingStr = hasMutationParams ? callPrinter$5.print(groupedParamsNode) ?? "" : "_";
1320
+ const mutationFnBody = `const { data } = await ${buildClientCall(node, {
1321
+ clientName,
1322
+ signal: false
1323
+ })}
1324
+ return data`;
1325
+ return /* @__PURE__ */ jsx(File.Source, {
1326
+ name,
1327
+ isExportable: true,
1328
+ isIndexable: true,
1329
+ children: /* @__PURE__ */ jsx(Function, {
1330
+ name,
1331
+ export: true,
1332
+ params: paramsSignature,
1333
+ generics: ["TContext = unknown"],
1334
+ children: `
1335
+ const mutationKey = ${mutationKeyName}()
1336
+ return mutationOptions<${TData}, ${TError}, ${TRequest}, TContext>({
1337
+ mutationKey,
1338
+ mutationFn: async(${argBindingStr}) => {
1339
+ ${mutationFnBody}
1340
+ },
1341
+ })
1342
+ `
1343
+ })
1344
+ });
1345
+ }
1346
+ //#endregion
1347
+ //#region src/components/Mutation.tsx
1348
+ const declarationPrinter$4 = functionPrinter({ mode: "declaration" });
1349
+ const callPrinter$4 = functionPrinter({ mode: "call" });
1350
+ function resolveMutationRequestType(node, resolver) {
1351
+ return buildGroupedRequestParam(node, { resolver }) ? resolver.resolveRequestConfigName(node) : "undefined";
1352
+ }
1353
+ function buildMutationParamsNode(node, options) {
1354
+ const { resolver } = options;
1355
+ const successNames = resolveSuccessNames(node, resolver);
1356
+ const responseName = successNames.length > 0 ? successNames.join(" | ") : resolver.resolveResponseName(node);
1357
+ const errorNames = resolveErrorNames(node, resolver);
1358
+ return createFunctionParameters({ params: [createFunctionParameter({
1359
+ name: "options",
1360
+ type: `{
1361
+ mutation?: UseMutationOptions<${[
1362
+ responseName,
1363
+ `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(" | ") : "Error"}>`,
1364
+ resolveMutationRequestType(node, resolver),
1365
+ "TContext"
1366
+ ].join(", ")}> & { client?: QueryClient },
1367
+ client?: ${buildRequestConfigType(node)},
1368
+ }`,
1369
+ default: "{}"
1370
+ })] });
1371
+ }
1372
+ function Mutation({ name, mutationOptionsName, node, tsResolver, mutationKeyName, customOptions }) {
1373
+ const successNames = resolveSuccessNames(node, tsResolver);
1374
+ const responseName = successNames.length > 0 ? successNames.join(" | ") : tsResolver.resolveResponseName(node);
1375
+ const errorNames = resolveErrorNames(node, tsResolver);
1376
+ const generics = [
1377
+ responseName,
1378
+ `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(" | ") : "Error"}>`,
1379
+ resolveMutationRequestType(node, tsResolver),
1380
+ "TContext"
1381
+ ].join(", ");
1382
+ const returnType = `UseMutationResult<${generics}>`;
1383
+ const mutationOptionsConfigNode = buildMutationConfigParamsNode(node);
1384
+ const mutationOptionsParamsCall = callPrinter$4.print(mutationOptionsConfigNode) ?? "";
1385
+ const paramsNode = buildMutationParamsNode(node, { resolver: tsResolver });
1386
+ const paramsSignature = declarationPrinter$4.print(paramsNode) ?? "";
1387
+ return /* @__PURE__ */ jsx(File.Source, {
1388
+ name,
1389
+ isExportable: true,
1390
+ isIndexable: true,
1391
+ children: /* @__PURE__ */ jsx(Function, {
1392
+ name,
1393
+ export: true,
1394
+ params: paramsSignature,
1395
+ JSDoc: { comments: buildOperationComments(node) },
1396
+ generics: ["TContext"],
1397
+ children: `
1398
+ const { mutation = {}, client: config = {} } = options ?? {}
1399
+ const { client: queryClient, ...mutationOptions } = mutation;
1400
+ const mutationKey = mutationOptions.mutationKey ?? ${mutationKeyName}()
1401
+
1402
+ const baseOptions = ${mutationOptionsName}(${mutationOptionsParamsCall}) as UseMutationOptions<${generics}>${customOptions ? `\n const customOptions = ${customOptions.name}({ hookName: '${name}', operationId: '${node.operationId}' }) as UseMutationOptions<${generics}>` : ""}
1403
+
1404
+ return useMutation<${generics}>({
1405
+ ...baseOptions,${customOptions ? "\n ...customOptions," : ""}
1406
+ mutationKey,
1407
+ ...mutationOptions,
1408
+ }, queryClient) as ${returnType}
1409
+ `
1410
+ })
1411
+ });
1412
+ }
1413
+ //#endregion
1414
+ //#region src/components/Query.tsx
1415
+ const declarationPrinter$3 = functionPrinter({ mode: "declaration" });
1416
+ const callPrinter$3 = functionPrinter({ mode: "call" });
1417
+ function buildQueryParamsNode(node, options) {
1418
+ const { resolver } = options;
1419
+ const successNames = resolveSuccessNames(node, resolver);
1420
+ const responseName = successNames.length > 0 ? successNames.join(" | ") : resolver.resolveResponseName(node);
1421
+ const errorNames = resolveErrorNames(node, resolver);
1422
+ const optionsParam = createFunctionParameter({
1423
+ name: "options",
1424
+ type: `{
1425
+ query?: Partial<QueryObserverOptions<${[
1426
+ responseName,
1427
+ `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(" | ") : "Error"}>`,
1428
+ "TData",
1429
+ "TQueryData",
1430
+ "TQueryKey"
1431
+ ].join(", ")}>> & { client?: QueryClient },
1432
+ client?: ${buildClientOptionType()}
1433
+ }`,
1434
+ default: "{}"
1435
+ });
1436
+ return createFunctionParameters({ params: [buildGroupedRequestParam(node, { resolver }), optionsParam].filter((param) => param !== null) });
1437
+ }
1438
+ function Query({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, tsResolver, customOptions }) {
1439
+ const successNames = resolveSuccessNames(node, tsResolver);
1440
+ const responseName = successNames.length > 0 ? successNames.join(" | ") : tsResolver.resolveResponseName(node);
1441
+ const errorNames = resolveErrorNames(node, tsResolver);
1442
+ const TData = responseName;
1443
+ const returnType = `UseQueryResult<TData, ${`ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(" | ") : "Error"}>`}> & { queryKey: TQueryKey }`;
1444
+ const generics = [
1445
+ `TData = ${TData}`,
1446
+ `TQueryData = ${TData}`,
1447
+ `TQueryKey extends QueryKey = ${queryKeyTypeName}`
1448
+ ];
1449
+ const queryKeyParamsNode = buildQueryKeyParams(node, { resolver: tsResolver });
1450
+ const queryKeyParamsCall = callPrinter$3.print(queryKeyParamsNode) ?? "";
1451
+ const queryOptionsParamsNode = getQueryOptionsParams(node, { resolver: tsResolver });
1452
+ const queryOptionsParamsCall = callPrinter$3.print(queryOptionsParamsNode) ?? "";
1453
+ const paramsNode = buildQueryParamsNode(node, { resolver: tsResolver });
1454
+ const paramsSignature = declarationPrinter$3.print(paramsNode) ?? "";
1455
+ return /* @__PURE__ */ jsx(File.Source, {
1456
+ name,
1457
+ isExportable: true,
1458
+ isIndexable: true,
1459
+ children: /* @__PURE__ */ jsx(Function, {
1460
+ name,
1461
+ export: true,
1462
+ generics: generics.join(", "),
1463
+ params: paramsSignature,
1464
+ returnType: void 0,
1465
+ JSDoc: { comments: buildOperationComments(node) },
1466
+ children: `
1467
+ const { query: queryConfig = {}, client: config = {} } = options ?? {}
1468
+ const { client: queryClient, ...resolvedOptions } = queryConfig
1469
+ const queryKey = resolvedOptions?.queryKey ?? ${queryKeyName}(${queryKeyParamsCall})${customOptions ? `\n const customOptions = ${customOptions.name}({ hookName: '${name}', operationId: '${node.operationId}' })` : ""}
1470
+
1471
+ const queryResult = useQuery({
1472
+ ...${queryOptionsName}(${queryOptionsParamsCall}),${customOptions ? "\n ...customOptions," : ""}
1473
+ ...resolvedOptions,
1474
+ queryKey,
1475
+ } as unknown as QueryObserverOptions, queryClient) as ${returnType}
1476
+
1477
+ queryResult.queryKey = queryKey as TQueryKey
1478
+
1479
+ return queryResult
1480
+ `
1481
+ })
1482
+ });
1483
+ }
1484
+ //#endregion
1485
+ //#region src/components/SuspenseInfiniteQuery.tsx
1486
+ const declarationPrinter$2 = functionPrinter({ mode: "declaration" });
1487
+ const callPrinter$2 = functionPrinter({ mode: "call" });
1488
+ function buildSuspenseInfiniteQueryParamsNode(node, options) {
1489
+ const { resolver, pageParamGeneric } = options;
1490
+ const optionsParam = createFunctionParameter({
1491
+ name: "options",
1492
+ type: `{
1493
+ query?: Partial<UseSuspenseInfiniteQueryOptions<TQueryFnData, TError, TData, TQueryKey, ${pageParamGeneric}>> & { client?: QueryClient },
1494
+ client?: ${buildClientOptionType()}
1495
+ }`,
1496
+ default: "{}"
1497
+ });
1498
+ return createFunctionParameters({ params: [buildGroupedRequestParam(node, { resolver }), optionsParam].filter((param) => param !== null) });
1499
+ }
1500
+ function SuspenseInfiniteQuery({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, tsResolver, customOptions, initialPageParam, queryParam }) {
1501
+ const successNames = resolveSuccessNames(node, tsResolver);
1502
+ const responseName = successNames.length > 0 ? successNames.join(" | ") : tsResolver.resolveResponseName(node);
1503
+ const errorNames = resolveErrorNames(node, tsResolver);
1504
+ const responseType = responseName;
1505
+ const errorType = `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(" | ") : "Error"}>`;
1506
+ const isInitialPageParamDefined = initialPageParam !== void 0 && initialPageParam !== null;
1507
+ const fallbackPageParamType = typeof initialPageParam === "number" ? "number" : typeof initialPageParam === "string" ? initialPageParam.includes(" as ") ? (() => {
1508
+ const parts = initialPageParam.split(" as ");
1509
+ return parts[parts.length - 1] ?? "unknown";
1510
+ })() : "string" : typeof initialPageParam === "boolean" ? "boolean" : "unknown";
1511
+ const rawQueryParams = getOperationParameters(node, { paramsCasing: "original" }).query;
1512
+ const queryParamsTypeName = rawQueryParams.length > 0 ? (() => {
1513
+ const groupName = tsResolver.resolveQueryParamsName(node, rawQueryParams[0]);
1514
+ return groupName !== tsResolver.resolveParamName(node, rawQueryParams[0]) ? groupName : null;
1515
+ })() : null;
1516
+ const queryParamType = queryParam && queryParamsTypeName ? `${queryParamsTypeName}['${queryParam}']` : null;
1517
+ const pageParamType = queryParamType ? isInitialPageParamDefined ? `NonNullable<${queryParamType}>` : queryParamType : fallbackPageParamType;
1518
+ const returnType = "UseSuspenseInfiniteQueryResult<TData, TError> & { queryKey: TQueryKey }";
1519
+ const generics = [
1520
+ `TQueryFnData = ${responseType}`,
1521
+ `TError = ${errorType}`,
1522
+ "TData = InfiniteData<TQueryFnData>",
1523
+ `TQueryKey extends QueryKey = ${queryKeyTypeName}`,
1524
+ `TPageParam = ${pageParamType}`
1525
+ ];
1526
+ const queryKeyParamsNode = buildQueryKeyParams(node, { resolver: tsResolver });
1527
+ const queryKeyParamsCall = callPrinter$2.print(queryKeyParamsNode) ?? "";
1528
+ const queryOptionsParamsNode = getQueryOptionsParams(node, { resolver: tsResolver });
1529
+ const queryOptionsParamsCall = callPrinter$2.print(queryOptionsParamsNode) ?? "";
1530
+ const paramsNode = buildSuspenseInfiniteQueryParamsNode(node, {
1531
+ resolver: tsResolver,
1532
+ pageParamGeneric: "TPageParam"
1533
+ });
1534
+ const paramsSignature = declarationPrinter$2.print(paramsNode) ?? "";
1535
+ return /* @__PURE__ */ jsx(File.Source, {
1536
+ name,
1537
+ isExportable: true,
1538
+ isIndexable: true,
1539
+ children: /* @__PURE__ */ jsx(Function, {
1540
+ name,
1541
+ export: true,
1542
+ generics: generics.join(", "),
1543
+ params: paramsSignature,
1544
+ returnType: void 0,
1545
+ JSDoc: { comments: buildOperationComments(node) },
1546
+ children: `
1547
+ const { query: queryConfig = {}, client: config = {} } = options ?? {}
1548
+ const { client: queryClient, ...resolvedOptions } = queryConfig
1549
+ const queryKey = resolvedOptions?.queryKey ?? ${queryKeyName}(${queryKeyParamsCall})${customOptions ? `\n const customOptions = ${customOptions.name}({ hookName: '${name}', operationId: '${node.operationId}' })` : ""}
1550
+
1551
+ const queryResult = useSuspenseInfiniteQuery({
1552
+ ...${queryOptionsName}(${queryOptionsParamsCall}),${customOptions ? "\n ...customOptions," : ""}
1553
+ ...resolvedOptions,
1554
+ queryKey,
1555
+ } as unknown as UseSuspenseInfiniteQueryOptions<TQueryFnData, TError, TData, TQueryKey, TPageParam>, queryClient) as ${returnType}
1556
+
1557
+ queryResult.queryKey = queryKey as TQueryKey
1558
+
1559
+ return queryResult
1560
+ `
1561
+ })
1562
+ });
1563
+ }
1564
+ //#endregion
1565
+ //#region src/components/SuspenseInfiniteQueryOptions.tsx
1566
+ const declarationPrinter$1 = functionPrinter({ mode: "declaration" });
1567
+ const callPrinter$1 = functionPrinter({ mode: "call" });
1568
+ function SuspenseInfiniteQueryOptions({ name, clientName, initialPageParam, cursorParam, nextParam, previousParam, node, tsResolver, queryParam, queryKeyName }) {
1569
+ const successNames = resolveSuccessNames(node, tsResolver);
1570
+ const queryFnDataType = successNames.length > 0 ? successNames.join(" | ") : tsResolver.resolveResponseName(node);
1571
+ const errorNames = resolveErrorNames(node, tsResolver);
1572
+ const errorType = `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(" | ") : "Error"}>`;
1573
+ const isInitialPageParamDefined = initialPageParam !== void 0 && initialPageParam !== null;
1574
+ const fallbackPageParamType = typeof initialPageParam === "number" ? "number" : typeof initialPageParam === "string" ? initialPageParam.includes(" as ") ? (() => {
1575
+ const parts = initialPageParam.split(" as ");
1576
+ return parts[parts.length - 1] ?? "unknown";
1577
+ })() : "string" : typeof initialPageParam === "boolean" ? "boolean" : "unknown";
1578
+ const rawQueryParams = getOperationParameters(node, { paramsCasing: "original" }).query;
1579
+ const queryParamsTypeName = rawQueryParams.length > 0 ? (() => {
1580
+ const groupName = tsResolver.resolveQueryParamsName(node, rawQueryParams[0]);
1581
+ return groupName !== tsResolver.resolveParamName(node, rawQueryParams[0]) ? groupName : null;
1582
+ })() : null;
1583
+ const queryParamType = queryParam && queryParamsTypeName ? `${queryParamsTypeName}['${queryParam}']` : null;
1584
+ const pageParamType = queryParamType ? isInitialPageParamDefined ? `NonNullable<${queryParamType}>` : queryParamType : fallbackPageParamType;
1585
+ const paramsNode = getQueryOptionsParams(node, { resolver: tsResolver });
1586
+ const paramsSignature = declarationPrinter$1.print(paramsNode) ?? "";
1587
+ const queryFnBody = `const { data } = await ${buildClientCall(node, {
1588
+ clientName,
1589
+ signal: true
1590
+ })}
1591
+ return data`;
1592
+ const queryKeyParamsNode = buildQueryKeyParams(node, { resolver: tsResolver });
1593
+ const queryKeyParamsCall = callPrinter$1.print(queryKeyParamsNode) ?? "";
1594
+ const hasNewParams = nextParam != null || previousParam != null;
1595
+ const [getNextPageParamExpr, getPreviousPageParamExpr] = (() => {
1596
+ if (hasNewParams) {
1597
+ const nextAccessor = nextParam ? getNestedAccessor(nextParam, "lastPage") : null;
1598
+ const prevAccessor = previousParam ? getNestedAccessor(previousParam, "firstPage") : null;
1599
+ return [nextAccessor ? `getNextPageParam: (lastPage) => ${nextAccessor}` : null, prevAccessor ? `getPreviousPageParam: (firstPage) => ${prevAccessor}` : null];
1600
+ }
1601
+ if (cursorParam) return [`getNextPageParam: (lastPage) => lastPage['${cursorParam}']`, `getPreviousPageParam: (firstPage) => firstPage['${cursorParam}']`];
1602
+ return ["getNextPageParam: (lastPage, _allPages, lastPageParam) => Array.isArray(lastPage) && lastPage.length === 0 ? undefined : lastPageParam + 1", "getPreviousPageParam: (_firstPage, _allPages, firstPageParam) => firstPageParam <= 1 ? undefined : firstPageParam - 1"];
1603
+ })();
1604
+ const queryOptionsArr = [
1605
+ `initialPageParam: ${typeof initialPageParam === "string" ? JSON.stringify(initialPageParam) : initialPageParam}`,
1606
+ getNextPageParamExpr,
1607
+ getPreviousPageParamExpr
1608
+ ].filter(Boolean);
1609
+ const infiniteOverrideParams = queryParam && queryParamsTypeName ? `query = {
1610
+ ...(query ?? {}),
1611
+ ['${queryParam}']: pageParam as unknown as ${queryParamsTypeName}['${queryParam}'],
1612
+ } as ${queryParamsTypeName}` : "";
1613
+ if (infiniteOverrideParams) return /* @__PURE__ */ jsx(File.Source, {
1614
+ name,
1615
+ isExportable: true,
1616
+ isIndexable: true,
1617
+ children: /* @__PURE__ */ jsx(Function, {
1618
+ name,
1619
+ export: true,
1620
+ params: paramsSignature,
1621
+ children: `
1622
+ const queryKey = ${queryKeyName}(${queryKeyParamsCall})
1623
+ return infiniteQueryOptions<${queryFnDataType}, ${errorType}, InfiniteData<${queryFnDataType}>, typeof queryKey, ${pageParamType}>({
1624
+ queryKey,
1625
+ queryFn: async ({ signal, pageParam }) => {
1626
+ ${infiniteOverrideParams}
1627
+ ${queryFnBody}
1628
+ },
1629
+ ${queryOptionsArr.join(",\n ")}
1630
+ })
1631
+ `
1632
+ })
1633
+ });
1634
+ return /* @__PURE__ */ jsx(File.Source, {
1635
+ name,
1636
+ isExportable: true,
1637
+ isIndexable: true,
1638
+ children: /* @__PURE__ */ jsx(Function, {
1639
+ name,
1640
+ export: true,
1641
+ params: paramsSignature,
1642
+ children: `
1643
+ const queryKey = ${queryKeyName}(${queryKeyParamsCall})
1644
+ return infiniteQueryOptions<${queryFnDataType}, ${errorType}, InfiniteData<${queryFnDataType}>, typeof queryKey, ${pageParamType}>({
1645
+ queryKey,
1646
+ queryFn: async ({ signal }) => {
1647
+ ${queryFnBody}
1648
+ },
1649
+ ${queryOptionsArr.join(",\n ")}
1650
+ })
1651
+ `
1652
+ })
1653
+ });
1654
+ }
1655
+ //#endregion
1656
+ //#region src/components/SuspenseQuery.tsx
1657
+ const declarationPrinter = functionPrinter({ mode: "declaration" });
1658
+ const callPrinter = functionPrinter({ mode: "call" });
1659
+ function buildSuspenseQueryParamsNode(node, options) {
1660
+ const { resolver } = options;
1661
+ const successNames = resolveSuccessNames(node, resolver);
1662
+ const responseName = successNames.length > 0 ? successNames.join(" | ") : resolver.resolveResponseName(node);
1663
+ const errorNames = resolveErrorNames(node, resolver);
1664
+ const optionsParam = createFunctionParameter({
1665
+ name: "options",
1666
+ type: `{
1667
+ query?: Partial<UseSuspenseQueryOptions<${[
1668
+ responseName,
1669
+ `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(" | ") : "Error"}>`,
1670
+ "TData",
1671
+ "TQueryKey"
1672
+ ].join(", ")}>> & { client?: QueryClient },
1673
+ client?: ${buildClientOptionType()}
1674
+ }`,
1675
+ default: "{}"
1676
+ });
1677
+ return createFunctionParameters({ params: [buildGroupedRequestParam(node, { resolver }), optionsParam].filter((param) => param !== null) });
1678
+ }
1679
+ function SuspenseQuery({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, tsResolver, customOptions }) {
1680
+ const successNames = resolveSuccessNames(node, tsResolver);
1681
+ const responseName = successNames.length > 0 ? successNames.join(" | ") : tsResolver.resolveResponseName(node);
1682
+ const errorNames = resolveErrorNames(node, tsResolver);
1683
+ const TData = responseName;
1684
+ const returnType = `UseSuspenseQueryResult<TData, ${`ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(" | ") : "Error"}>`}> & { queryKey: TQueryKey }`;
1685
+ const generics = [`TData = ${TData}`, `TQueryKey extends QueryKey = ${queryKeyTypeName}`];
1686
+ const queryKeyParamsNode = buildQueryKeyParams(node, { resolver: tsResolver });
1687
+ const queryKeyParamsCall = callPrinter.print(queryKeyParamsNode) ?? "";
1688
+ const queryOptionsParamsNode = getQueryOptionsParams(node, { resolver: tsResolver });
1689
+ const queryOptionsParamsCall = callPrinter.print(queryOptionsParamsNode) ?? "";
1690
+ const paramsNode = buildSuspenseQueryParamsNode(node, { resolver: tsResolver });
1691
+ const paramsSignature = declarationPrinter.print(paramsNode) ?? "";
1692
+ return /* @__PURE__ */ jsx(File.Source, {
1693
+ name,
1694
+ isExportable: true,
1695
+ isIndexable: true,
1696
+ children: /* @__PURE__ */ jsx(Function, {
1697
+ name,
1698
+ export: true,
1699
+ generics: generics.join(", "),
1700
+ params: paramsSignature,
1701
+ returnType: void 0,
1702
+ JSDoc: { comments: buildOperationComments(node) },
1703
+ children: `
1704
+ const { query: queryConfig = {}, client: config = {} } = options ?? {}
1705
+ const { client: queryClient, ...resolvedOptions } = queryConfig
1706
+ const queryKey = resolvedOptions?.queryKey ?? ${queryKeyName}(${queryKeyParamsCall})${customOptions ? `\n const customOptions = ${customOptions.name}({ hookName: '${name}', operationId: '${node.operationId}' })` : ""}
1707
+
1708
+ const queryResult = useSuspenseQuery({
1709
+ ...${queryOptionsName}(${queryOptionsParamsCall}),${customOptions ? "\n ...customOptions," : ""}
1710
+ ...resolvedOptions,
1711
+ queryKey,
1712
+ } as unknown as UseSuspenseQueryOptions, queryClient) as ${returnType}
1713
+
1714
+ queryResult.queryKey = queryKey as TQueryKey
1715
+
1716
+ return queryResult
1717
+ `
1718
+ })
1719
+ });
1720
+ }
1721
+ //#endregion
1722
+ //#region src/generators/infiniteQueryGenerator.tsx
1723
+ /**
1724
+ * Built-in generator for `useInfiniteQuery` hooks. Enabled when
1725
+ * `pluginReactQuery({ infinite: { ... } })`. Emits one `useFooInfiniteQuery`
1726
+ * hook per query operation, wiring the configured `nextParam` /
1727
+ * `previousParam` paths into TanStack Query's cursor-based pagination.
1728
+ */
1729
+ const infiniteQueryGenerator = defineGenerator({
1730
+ name: "react-infinite-query",
1731
+ renderer: jsxRenderer,
1732
+ operation(node, ctx) {
1733
+ if (!ast.isHttpOperationNode(node)) return null;
1734
+ const { config, driver, resolver, root } = ctx;
1735
+ const { output, query, mutation, infinite, parser, client, group, customOptions } = ctx.options;
1736
+ const pluginTs = driver.getPlugin(pluginTsName);
1737
+ if (!pluginTs) return null;
1738
+ const tsResolver = driver.getResolver(pluginTsName);
1739
+ const isQuery = query === false || !!query && query.methods.some((method) => node.method.toLowerCase() === method.toLowerCase());
1740
+ const queryMethods = new Set(query ? query.methods : []);
1741
+ const isMutation = mutation !== false && !isQuery && (mutation ? mutation.methods : []).some((method) => !queryMethods.has(method) && node.method.toLowerCase() === method.toLowerCase());
1742
+ const infiniteOptions = infinite && typeof infinite === "object" ? infinite : null;
1743
+ if (!isQuery || isMutation || !infiniteOptions) return null;
1744
+ const normalizeKey = (key) => key.replace(/\?$/, "");
1745
+ const queryParamKeys = getOperationParameters(node, { paramsCasing: "original" }).query.map((p) => p.name);
1746
+ const hasQueryParam = infiniteOptions.queryParam ? queryParamKeys.some((k) => normalizeKey(k) === infiniteOptions.queryParam) : false;
1747
+ const hasCursorParam = !infiniteOptions.cursorParam || true;
1748
+ if (!hasQueryParam || !hasCursorParam) return null;
1749
+ const importPath = query ? query.importPath : "@tanstack/react-query";
1750
+ const contractOp = resolveClientOperation({
1751
+ clientPlugin: { pluginName: client.pluginName },
1752
+ driver,
1753
+ node,
1754
+ root,
1755
+ output
1756
+ });
1757
+ if (!contractOp) return null;
1758
+ const queryName = resolver.resolveInfiniteQueryName(node);
1759
+ const queryOptionsName = resolver.resolveInfiniteQueryOptionsName(node);
1760
+ const queryKeyName = resolver.resolveInfiniteQueryKeyName(node);
1761
+ const queryKeyTypeName = resolver.resolveInfiniteQueryKeyTypeName(node);
1762
+ const meta = {
1763
+ file: resolver.resolveFile(operationFileEntry(node, queryName), {
1764
+ root,
1765
+ output,
1766
+ group: group ?? void 0
1767
+ }),
1768
+ fileTs: tsResolver.resolveFile(operationFileEntry(node, node.operationId), {
1769
+ root,
1770
+ output: pluginTs.options?.output ?? output,
1771
+ group: pluginTs.options?.group ?? void 0
1772
+ })
1773
+ };
1774
+ const rawQueryParams = getOperationParameters(node, { paramsCasing: "original" }).query;
1775
+ const queryParamsTypeName = rawQueryParams.length > 0 && tsResolver.resolveQueryParamsName(node, rawQueryParams[0]) !== tsResolver.resolveParamName(node, rawQueryParams[0]) ? tsResolver.resolveQueryParamsName(node, rawQueryParams[0]) : null;
1776
+ const importedTypeNames = [
1777
+ tsResolver.resolveRequestConfigName(node),
1778
+ queryParamsTypeName,
1779
+ ...resolveOperationTypeNames(node, tsResolver, {
1780
+ exclude: [queryKeyTypeName],
1781
+ order: "body-response-first",
1782
+ includeParams: false
1783
+ })
1784
+ ].filter((name) => Boolean(name));
1785
+ const pluginZod = isParserEnabled(parser) ? driver.getPlugin(pluginZodName) : null;
1786
+ const zodResolver = pluginZod ? driver.getResolver(pluginZodName) : null;
1787
+ const fileZod = zodResolver ? zodResolver.resolveFile(operationFileEntry(node, node.operationId), {
1788
+ root,
1789
+ output: pluginZod?.options?.output ?? output,
1790
+ group: pluginZod?.options?.group ?? void 0
1791
+ }) : null;
1792
+ const zodSchemaNames = resolveZodSchemaNames(node, zodResolver, parser);
1793
+ const calledClientName = contractOp.name;
1794
+ return /* @__PURE__ */ jsxs(File, {
1795
+ baseName: meta.file.baseName,
1796
+ path: meta.file.path,
1797
+ meta: meta.file.meta,
1798
+ banner: resolver.resolveBanner(ctx.meta, {
1799
+ output,
1800
+ config,
1801
+ file: {
1802
+ path: meta.file.path,
1803
+ baseName: meta.file.baseName
1804
+ }
1805
+ }),
1806
+ footer: resolver.resolveFooter(ctx.meta, {
1807
+ output,
1808
+ config,
1809
+ file: {
1810
+ path: meta.file.path,
1811
+ baseName: meta.file.baseName
1812
+ }
1813
+ }),
1814
+ children: [
1815
+ fileZod && zodSchemaNames.length > 0 && /* @__PURE__ */ jsx(File.Import, {
1816
+ name: zodSchemaNames,
1817
+ root: meta.file.path,
1818
+ path: fileZod.path
1819
+ }),
1820
+ /* @__PURE__ */ jsx(File.Import, {
1821
+ name: [contractOp.name],
1822
+ root: meta.file.path,
1823
+ path: contractOp.path
1824
+ }),
1825
+ /* @__PURE__ */ jsx(File.Import, {
1826
+ name: ["RequestConfig", "ResponseErrorConfig"],
1827
+ root: meta.file.path,
1828
+ path: contractOp.clientPath,
1829
+ isTypeOnly: true
1830
+ }),
1831
+ customOptions && /* @__PURE__ */ jsx(File.Import, {
1832
+ name: [customOptions.name],
1833
+ path: customOptions.importPath
1834
+ }),
1835
+ meta.fileTs && importedTypeNames.length > 0 && /* @__PURE__ */ jsx(File.Import, {
1836
+ name: Array.from(new Set(importedTypeNames)),
1837
+ root: meta.file.path,
1838
+ path: meta.fileTs.path,
1839
+ isTypeOnly: true
1840
+ }),
1841
+ /* @__PURE__ */ jsx(QueryKey, {
1842
+ name: queryKeyName,
1843
+ typeName: queryKeyTypeName,
1844
+ node,
1845
+ tsResolver,
1846
+ transformer: ctx.options.queryKey
1847
+ }),
1848
+ /* @__PURE__ */ jsx(File.Import, {
1849
+ name: ["InfiniteData"],
1850
+ isTypeOnly: true,
1851
+ path: importPath
1852
+ }),
1853
+ /* @__PURE__ */ jsx(File.Import, {
1854
+ name: ["infiniteQueryOptions"],
1855
+ path: importPath
1856
+ }),
1857
+ /* @__PURE__ */ jsx(InfiniteQueryOptions, {
1858
+ name: queryOptionsName,
1859
+ clientName: calledClientName,
1860
+ queryKeyName,
1861
+ node,
1862
+ tsResolver,
1863
+ cursorParam: infiniteOptions.cursorParam,
1864
+ nextParam: infiniteOptions.nextParam,
1865
+ previousParam: infiniteOptions.previousParam,
1866
+ initialPageParam: infiniteOptions.initialPageParam,
1867
+ queryParam: infiniteOptions.queryParam
1868
+ }),
1869
+ /* @__PURE__ */ jsx(File.Import, {
1870
+ name: ["useInfiniteQuery"],
1871
+ path: importPath
1872
+ }),
1873
+ /* @__PURE__ */ jsx(File.Import, {
1874
+ name: [
1875
+ "QueryKey",
1876
+ "QueryClient",
1877
+ "InfiniteQueryObserverOptions",
1878
+ "UseInfiniteQueryResult"
1879
+ ],
1880
+ path: importPath,
1881
+ isTypeOnly: true
1882
+ }),
1883
+ /* @__PURE__ */ jsx(InfiniteQuery, {
1884
+ name: queryName,
1885
+ queryOptionsName,
1886
+ queryKeyName,
1887
+ queryKeyTypeName,
1888
+ node,
1889
+ tsResolver,
1890
+ initialPageParam: infiniteOptions.initialPageParam,
1891
+ queryParam: infiniteOptions.queryParam,
1892
+ customOptions
1893
+ })
1894
+ ]
1895
+ });
1896
+ }
1897
+ });
1898
+ //#endregion
1899
+ //#region src/generators/mutationGenerator.tsx
1900
+ /**
1901
+ * Built-in generator for `useMutation` hooks. Emits one `useFooMutation` hook
1902
+ * per POST/PUT/DELETE operation (configurable via `mutation.methods`) plus
1903
+ * the matching `fooMutationKey` / `fooMutationOptions` helpers.
1904
+ */
1905
+ const mutationGenerator = defineGenerator({
1906
+ name: "react-query-mutation",
1907
+ renderer: jsxRenderer,
1908
+ operation(node, ctx) {
1909
+ if (!ast.isHttpOperationNode(node)) return null;
1910
+ const { config, driver, resolver, root } = ctx;
1911
+ const { output, query, mutation, parser, client, group, customOptions } = ctx.options;
1912
+ const pluginTs = driver.getPlugin(pluginTsName);
1913
+ if (!pluginTs) return null;
1914
+ const tsResolver = driver.getResolver(pluginTsName);
1915
+ const isQuery = query === false || !!query && query.methods.some((method) => node.method.toLowerCase() === method.toLowerCase());
1916
+ const queryMethods = new Set(query ? query.methods : []);
1917
+ if (!(mutation !== false && !isQuery && (mutation ? mutation.methods : []).some((method) => !queryMethods.has(method) && node.method.toLowerCase() === method.toLowerCase()))) return null;
1918
+ const importPath = mutation ? mutation.importPath : "@tanstack/react-query";
1919
+ const contractOp = resolveClientOperation({
1920
+ clientPlugin: { pluginName: client.pluginName },
1921
+ driver,
1922
+ node,
1923
+ root,
1924
+ output
1925
+ });
1926
+ if (!contractOp) return null;
1927
+ const mutationHookName = resolver.resolveMutationName(node);
1928
+ const mutationTypeName = resolver.resolveMutationTypeName(node);
1929
+ const mutationOptionsName = resolver.resolveMutationOptionsName(node);
1930
+ const mutationKeyName = resolver.resolveMutationKeyName(node);
1931
+ const meta = {
1932
+ file: resolver.resolveFile(operationFileEntry(node, mutationHookName), {
1933
+ root,
1934
+ output,
1935
+ group: group ?? void 0
1936
+ }),
1937
+ fileTs: tsResolver.resolveFile(operationFileEntry(node, node.operationId), {
1938
+ root,
1939
+ output: pluginTs.options?.output ?? output,
1940
+ group: pluginTs.options?.group ?? void 0
1941
+ })
1942
+ };
1943
+ const importedTypeNames = [tsResolver.resolveRequestConfigName(node), ...resolveOperationTypeNames(node, tsResolver, {
1944
+ order: "body-response-first",
1945
+ includeParams: false
1946
+ })].filter((name) => Boolean(name));
1947
+ const pluginZod = isParserEnabled(parser) ? driver.getPlugin(pluginZodName) : null;
1948
+ const zodResolver = pluginZod ? driver.getResolver(pluginZodName) : null;
1949
+ const fileZod = zodResolver ? zodResolver.resolveFile(operationFileEntry(node, node.operationId), {
1950
+ root,
1951
+ output: pluginZod?.options?.output ?? output,
1952
+ group: pluginZod?.options?.group ?? void 0
1953
+ }) : null;
1954
+ const zodSchemaNames = resolveZodSchemaNames(node, zodResolver, parser);
1955
+ const calledClientName = contractOp.name;
1956
+ return /* @__PURE__ */ jsxs(File, {
1957
+ baseName: meta.file.baseName,
1958
+ path: meta.file.path,
1959
+ meta: meta.file.meta,
1960
+ banner: resolver.resolveBanner(ctx.meta, {
1961
+ output,
1962
+ config,
1963
+ file: {
1964
+ path: meta.file.path,
1965
+ baseName: meta.file.baseName
1966
+ }
1967
+ }),
1968
+ footer: resolver.resolveFooter(ctx.meta, {
1969
+ output,
1970
+ config,
1971
+ file: {
1972
+ path: meta.file.path,
1973
+ baseName: meta.file.baseName
1974
+ }
1975
+ }),
1976
+ children: [
1977
+ fileZod && zodSchemaNames.length > 0 && /* @__PURE__ */ jsx(File.Import, {
1978
+ name: zodSchemaNames,
1979
+ root: meta.file.path,
1980
+ path: fileZod.path
1981
+ }),
1982
+ /* @__PURE__ */ jsx(File.Import, {
1983
+ name: [contractOp.name],
1984
+ root: meta.file.path,
1985
+ path: contractOp.path
1986
+ }),
1987
+ /* @__PURE__ */ jsx(File.Import, {
1988
+ name: ["RequestConfig", "ResponseErrorConfig"],
1989
+ root: meta.file.path,
1990
+ path: contractOp.clientPath,
1991
+ isTypeOnly: true
1992
+ }),
1993
+ customOptions && /* @__PURE__ */ jsx(File.Import, {
1994
+ name: [customOptions.name],
1995
+ path: customOptions.importPath
1996
+ }),
1997
+ meta.fileTs && importedTypeNames.length > 0 && /* @__PURE__ */ jsx(File.Import, {
1998
+ name: Array.from(new Set(importedTypeNames)),
1999
+ root: meta.file.path,
2000
+ path: meta.fileTs.path,
2001
+ isTypeOnly: true
2002
+ }),
2003
+ /* @__PURE__ */ jsx(MutationKey, {
2004
+ name: mutationKeyName,
2005
+ node,
2006
+ transformer: ctx.options.mutationKey
2007
+ }),
2008
+ /* @__PURE__ */ jsx(File.Import, {
2009
+ name: ["mutationOptions"],
2010
+ path: importPath
2011
+ }),
2012
+ /* @__PURE__ */ jsx(MutationOptions, {
2013
+ name: mutationOptionsName,
2014
+ clientName: calledClientName,
2015
+ mutationKeyName,
2016
+ node,
2017
+ tsResolver
2018
+ }),
2019
+ mutation && /* @__PURE__ */ jsxs(Fragment, { children: [
2020
+ /* @__PURE__ */ jsx(File.Import, {
2021
+ name: ["useMutation"],
2022
+ path: importPath
2023
+ }),
2024
+ /* @__PURE__ */ jsx(File.Import, {
2025
+ name: [
2026
+ "UseMutationOptions",
2027
+ "UseMutationResult",
2028
+ "QueryClient"
2029
+ ],
2030
+ path: importPath,
2031
+ isTypeOnly: true
2032
+ }),
2033
+ /* @__PURE__ */ jsx(Mutation, {
2034
+ name: mutationHookName,
2035
+ typeName: mutationTypeName,
2036
+ mutationOptionsName,
2037
+ mutationKeyName,
2038
+ node,
2039
+ tsResolver,
2040
+ customOptions
2041
+ })
2042
+ ] })
2043
+ ]
2044
+ });
2045
+ }
2046
+ });
2047
+ //#endregion
2048
+ //#region src/generators/queryGenerator.tsx
2049
+ /**
2050
+ * Built-in generator for `useQuery` hooks. Emits one `useFooQuery` hook per
2051
+ * GET operation (configurable via `query.methods`) plus the matching
2052
+ * `fooQueryKey` / `fooQueryOptions` helpers.
2053
+ */
2054
+ const queryGenerator = defineGenerator({
2055
+ name: "react-query",
2056
+ renderer: jsxRenderer,
2057
+ operation(node, ctx) {
2058
+ if (!ast.isHttpOperationNode(node)) return null;
2059
+ const { config, driver, resolver, root } = ctx;
2060
+ const { output, query, mutation, parser, client, group, customOptions } = ctx.options;
2061
+ const pluginTs = driver.getPlugin(pluginTsName);
2062
+ if (!pluginTs) return null;
2063
+ const tsResolver = driver.getResolver(pluginTsName);
2064
+ const isQuery = query === false || !!query && query.methods.some((method) => node.method.toLowerCase() === method.toLowerCase());
2065
+ const queryMethods = new Set(query ? query.methods : []);
2066
+ const isMutation = mutation !== false && !isQuery && (mutation ? mutation.methods : []).some((method) => !queryMethods.has(method) && node.method.toLowerCase() === method.toLowerCase());
2067
+ if (!isQuery || isMutation) return null;
2068
+ const importPath = query ? query.importPath : "@tanstack/react-query";
2069
+ const contractOp = resolveClientOperation({
2070
+ clientPlugin: { pluginName: client.pluginName },
2071
+ driver,
2072
+ node,
2073
+ root,
2074
+ output
2075
+ });
2076
+ if (!contractOp) return null;
2077
+ const queryName = resolver.resolveQueryName(node);
2078
+ const queryOptionsName = resolver.resolveQueryOptionsName(node);
2079
+ const queryKeyName = resolver.resolveQueryKeyName(node);
2080
+ const queryKeyTypeName = resolver.resolveQueryKeyTypeName(node);
2081
+ const meta = {
2082
+ file: resolver.resolveFile(operationFileEntry(node, queryName), {
2083
+ root,
2084
+ output,
2085
+ group: group ?? void 0
2086
+ }),
2087
+ fileTs: tsResolver.resolveFile(operationFileEntry(node, node.operationId), {
2088
+ root,
2089
+ output: pluginTs.options?.output ?? output,
2090
+ group: pluginTs.options?.group ?? void 0
2091
+ })
2092
+ };
2093
+ const importedTypeNames = [tsResolver.resolveRequestConfigName(node), ...resolveOperationTypeNames(node, tsResolver, {
2094
+ exclude: [queryKeyTypeName],
2095
+ order: "body-response-first",
2096
+ includeParams: false
2097
+ })].filter((name) => Boolean(name));
2098
+ const pluginZod = isParserEnabled(parser) ? driver.getPlugin(pluginZodName) : null;
2099
+ const zodResolver = pluginZod ? driver.getResolver(pluginZodName) : null;
2100
+ const fileZod = zodResolver ? zodResolver.resolveFile(operationFileEntry(node, node.operationId), {
2101
+ root,
2102
+ output: pluginZod?.options?.output ?? output,
2103
+ group: pluginZod?.options?.group ?? void 0
2104
+ }) : null;
2105
+ const zodSchemaNames = resolveZodSchemaNames(node, zodResolver, parser);
2106
+ const calledClientName = contractOp.name;
2107
+ return /* @__PURE__ */ jsxs(File, {
2108
+ baseName: meta.file.baseName,
2109
+ path: meta.file.path,
2110
+ meta: meta.file.meta,
2111
+ banner: resolver.resolveBanner(ctx.meta, {
2112
+ output,
2113
+ config,
2114
+ file: {
2115
+ path: meta.file.path,
2116
+ baseName: meta.file.baseName
2117
+ }
2118
+ }),
2119
+ footer: resolver.resolveFooter(ctx.meta, {
2120
+ output,
2121
+ config,
2122
+ file: {
2123
+ path: meta.file.path,
2124
+ baseName: meta.file.baseName
2125
+ }
2126
+ }),
2127
+ children: [
2128
+ fileZod && zodSchemaNames.length > 0 && /* @__PURE__ */ jsx(File.Import, {
2129
+ name: zodSchemaNames,
2130
+ root: meta.file.path,
2131
+ path: fileZod.path
2132
+ }),
2133
+ /* @__PURE__ */ jsx(File.Import, {
2134
+ name: [contractOp.name],
2135
+ root: meta.file.path,
2136
+ path: contractOp.path
2137
+ }),
2138
+ /* @__PURE__ */ jsx(File.Import, {
2139
+ name: ["RequestConfig", "ResponseErrorConfig"],
2140
+ root: meta.file.path,
2141
+ path: contractOp.clientPath,
2142
+ isTypeOnly: true
2143
+ }),
2144
+ customOptions && /* @__PURE__ */ jsx(File.Import, {
2145
+ name: [customOptions.name],
2146
+ path: customOptions.importPath
2147
+ }),
2148
+ meta.fileTs && importedTypeNames.length > 0 && /* @__PURE__ */ jsx(File.Import, {
2149
+ name: Array.from(new Set(importedTypeNames)),
2150
+ root: meta.file.path,
2151
+ path: meta.fileTs.path,
2152
+ isTypeOnly: true
2153
+ }),
2154
+ /* @__PURE__ */ jsx(QueryKey, {
2155
+ name: queryKeyName,
2156
+ typeName: queryKeyTypeName,
2157
+ node,
2158
+ tsResolver,
2159
+ transformer: ctx.options.queryKey
2160
+ }),
2161
+ /* @__PURE__ */ jsx(File.Import, {
2162
+ name: ["queryOptions"],
2163
+ path: importPath
2164
+ }),
2165
+ /* @__PURE__ */ jsx(QueryOptions, {
2166
+ name: queryOptionsName,
2167
+ clientName: calledClientName,
2168
+ queryKeyName,
2169
+ node,
2170
+ tsResolver
2171
+ }),
2172
+ query && /* @__PURE__ */ jsxs(Fragment, { children: [
2173
+ /* @__PURE__ */ jsx(File.Import, {
2174
+ name: ["useQuery"],
2175
+ path: importPath
2176
+ }),
2177
+ /* @__PURE__ */ jsx(File.Import, {
2178
+ name: [
2179
+ "QueryKey",
2180
+ "QueryClient",
2181
+ "QueryObserverOptions",
2182
+ "UseQueryResult"
2183
+ ],
2184
+ path: importPath,
2185
+ isTypeOnly: true
2186
+ }),
2187
+ /* @__PURE__ */ jsx(Query, {
2188
+ name: queryName,
2189
+ queryOptionsName,
2190
+ queryKeyName,
2191
+ queryKeyTypeName,
2192
+ node,
2193
+ tsResolver,
2194
+ customOptions
2195
+ })
2196
+ ] })
2197
+ ]
2198
+ });
2199
+ }
2200
+ });
2201
+ //#endregion
2202
+ //#region src/generators/suspenseInfiniteQueryGenerator.tsx
2203
+ /**
2204
+ * Built-in generator for `useSuspenseInfiniteQuery` hooks. Enabled when both
2205
+ * `suspense` and `infinite` are configured. Combines suspense semantics with
2206
+ * cursor-based pagination — handlers throw promises while loading and pull
2207
+ * additional pages on demand.
2208
+ */
2209
+ const suspenseInfiniteQueryGenerator = defineGenerator({
2210
+ name: "react-suspense-infinite-query",
2211
+ renderer: jsxRenderer,
2212
+ operation(node, ctx) {
2213
+ if (!ast.isHttpOperationNode(node)) return null;
2214
+ const { config, driver, resolver, root } = ctx;
2215
+ const { output, query, mutation, infinite, suspense, parser, client, group, customOptions } = ctx.options;
2216
+ const pluginTs = driver.getPlugin(pluginTsName);
2217
+ if (!pluginTs) return null;
2218
+ const tsResolver = driver.getResolver(pluginTsName);
2219
+ const isQuery = query === false || !!query && query.methods.some((method) => node.method.toLowerCase() === method.toLowerCase());
2220
+ const queryMethods = new Set(query ? query.methods : []);
2221
+ const isMutation = mutation !== false && !isQuery && (mutation ? mutation.methods : []).some((method) => !queryMethods.has(method) && node.method.toLowerCase() === method.toLowerCase());
2222
+ const isSuspense = !!suspense;
2223
+ const infiniteOptions = infinite && typeof infinite === "object" ? infinite : null;
2224
+ if (!isQuery || isMutation || !isSuspense || !infiniteOptions) return null;
2225
+ const normalizeKey = (key) => key.replace(/\?$/, "");
2226
+ const queryParamKeys = getOperationParameters(node, { paramsCasing: "original" }).query.map((p) => p.name);
2227
+ const hasQueryParam = infiniteOptions.queryParam ? queryParamKeys.some((k) => normalizeKey(k) === infiniteOptions.queryParam) : false;
2228
+ const hasCursorParam = !infiniteOptions.cursorParam || true;
2229
+ if (!hasQueryParam || !hasCursorParam) return null;
2230
+ const importPath = query ? query.importPath : "@tanstack/react-query";
2231
+ const contractOp = resolveClientOperation({
2232
+ clientPlugin: { pluginName: client.pluginName },
2233
+ driver,
2234
+ node,
2235
+ root,
2236
+ output
2237
+ });
2238
+ if (!contractOp) return null;
2239
+ const queryName = resolver.resolveSuspenseInfiniteQueryName(node);
2240
+ const queryOptionsName = resolver.resolveSuspenseInfiniteQueryOptionsName(node);
2241
+ const queryKeyName = resolver.resolveSuspenseInfiniteQueryKeyName(node);
2242
+ const queryKeyTypeName = resolver.resolveSuspenseInfiniteQueryKeyTypeName(node);
2243
+ const meta = {
2244
+ file: resolver.resolveFile(operationFileEntry(node, queryName), {
2245
+ root,
2246
+ output,
2247
+ group: group ?? void 0
2248
+ }),
2249
+ fileTs: tsResolver.resolveFile(operationFileEntry(node, node.operationId), {
2250
+ root,
2251
+ output: pluginTs.options?.output ?? output,
2252
+ group: pluginTs.options?.group ?? void 0
2253
+ })
2254
+ };
2255
+ const rawQueryParams = getOperationParameters(node, { paramsCasing: "original" }).query;
2256
+ const queryParamsTypeName = rawQueryParams.length > 0 && tsResolver.resolveQueryParamsName(node, rawQueryParams[0]) !== tsResolver.resolveParamName(node, rawQueryParams[0]) ? tsResolver.resolveQueryParamsName(node, rawQueryParams[0]) : null;
2257
+ const importedTypeNames = [
2258
+ tsResolver.resolveRequestConfigName(node),
2259
+ queryParamsTypeName,
2260
+ ...resolveOperationTypeNames(node, tsResolver, {
2261
+ order: "body-response-first",
2262
+ includeParams: false
2263
+ })
2264
+ ].filter((name) => Boolean(name));
2265
+ const pluginZod = isParserEnabled(parser) ? driver.getPlugin(pluginZodName) : null;
2266
+ const zodResolver = pluginZod ? driver.getResolver(pluginZodName) : null;
2267
+ const fileZod = zodResolver ? zodResolver.resolveFile(operationFileEntry(node, node.operationId), {
2268
+ root,
2269
+ output: pluginZod?.options?.output ?? output,
2270
+ group: pluginZod?.options?.group ?? void 0
2271
+ }) : null;
2272
+ const zodSchemaNames = resolveZodSchemaNames(node, zodResolver, parser);
2273
+ const calledClientName = contractOp.name;
2274
+ return /* @__PURE__ */ jsxs(File, {
2275
+ baseName: meta.file.baseName,
2276
+ path: meta.file.path,
2277
+ meta: meta.file.meta,
2278
+ banner: resolver.resolveBanner(ctx.meta, {
2279
+ output,
2280
+ config,
2281
+ file: {
2282
+ path: meta.file.path,
2283
+ baseName: meta.file.baseName
2284
+ }
2285
+ }),
2286
+ footer: resolver.resolveFooter(ctx.meta, {
2287
+ output,
2288
+ config,
2289
+ file: {
2290
+ path: meta.file.path,
2291
+ baseName: meta.file.baseName
2292
+ }
2293
+ }),
2294
+ children: [
2295
+ fileZod && zodSchemaNames.length > 0 && /* @__PURE__ */ jsx(File.Import, {
2296
+ name: zodSchemaNames,
2297
+ root: meta.file.path,
2298
+ path: fileZod.path
2299
+ }),
2300
+ /* @__PURE__ */ jsx(File.Import, {
2301
+ name: [contractOp.name],
2302
+ root: meta.file.path,
2303
+ path: contractOp.path
2304
+ }),
2305
+ /* @__PURE__ */ jsx(File.Import, {
2306
+ name: ["RequestConfig", "ResponseErrorConfig"],
2307
+ root: meta.file.path,
2308
+ path: contractOp.clientPath,
2309
+ isTypeOnly: true
2310
+ }),
2311
+ customOptions && /* @__PURE__ */ jsx(File.Import, {
2312
+ name: [customOptions.name],
2313
+ path: customOptions.importPath
2314
+ }),
2315
+ meta.fileTs && importedTypeNames.length > 0 && /* @__PURE__ */ jsx(File.Import, {
2316
+ name: Array.from(new Set(importedTypeNames)),
2317
+ root: meta.file.path,
2318
+ path: meta.fileTs.path,
2319
+ isTypeOnly: true
2320
+ }),
2321
+ /* @__PURE__ */ jsx(QueryKey, {
2322
+ name: queryKeyName,
2323
+ typeName: queryKeyTypeName,
2324
+ node,
2325
+ tsResolver,
2326
+ transformer: ctx.options.queryKey
2327
+ }),
2328
+ /* @__PURE__ */ jsx(File.Import, {
2329
+ name: ["InfiniteData"],
2330
+ isTypeOnly: true,
2331
+ path: importPath
2332
+ }),
2333
+ /* @__PURE__ */ jsx(File.Import, {
2334
+ name: ["infiniteQueryOptions"],
2335
+ path: importPath
2336
+ }),
2337
+ /* @__PURE__ */ jsx(SuspenseInfiniteQueryOptions, {
2338
+ name: queryOptionsName,
2339
+ clientName: calledClientName,
2340
+ queryKeyName,
2341
+ node,
2342
+ tsResolver,
2343
+ cursorParam: infiniteOptions.cursorParam,
2344
+ nextParam: infiniteOptions.nextParam,
2345
+ previousParam: infiniteOptions.previousParam,
2346
+ initialPageParam: infiniteOptions.initialPageParam,
2347
+ queryParam: infiniteOptions.queryParam
2348
+ }),
2349
+ /* @__PURE__ */ jsx(File.Import, {
2350
+ name: ["useSuspenseInfiniteQuery"],
2351
+ path: importPath
2352
+ }),
2353
+ /* @__PURE__ */ jsx(File.Import, {
2354
+ name: [
2355
+ "QueryKey",
2356
+ "QueryClient",
2357
+ "UseSuspenseInfiniteQueryOptions",
2358
+ "UseSuspenseInfiniteQueryResult"
2359
+ ],
2360
+ path: importPath,
2361
+ isTypeOnly: true
2362
+ }),
2363
+ /* @__PURE__ */ jsx(SuspenseInfiniteQuery, {
2364
+ name: queryName,
2365
+ queryOptionsName,
2366
+ queryKeyName,
2367
+ queryKeyTypeName,
2368
+ node,
2369
+ tsResolver,
2370
+ initialPageParam: infiniteOptions.initialPageParam,
2371
+ queryParam: infiniteOptions.queryParam,
2372
+ customOptions
2373
+ })
2374
+ ]
2375
+ });
2376
+ }
2377
+ });
2378
+ //#endregion
2379
+ //#region src/generators/suspenseQueryGenerator.tsx
2380
+ /**
2381
+ * Built-in generator for `useSuspenseQuery` hooks. Enabled when
2382
+ * `pluginReactQuery({ suspense: {} })`. Emits one `useFooSuspenseQuery` hook
2383
+ * per query operation. Suspense queries throw promises while loading and
2384
+ * require a `<Suspense>` boundary in the React tree. TanStack Query v5+ only.
2385
+ */
2386
+ const suspenseQueryGenerator = defineGenerator({
2387
+ name: "react-suspense-query",
2388
+ renderer: jsxRenderer,
2389
+ operation(node, ctx) {
2390
+ if (!ast.isHttpOperationNode(node)) return null;
2391
+ const { config, driver, resolver, root } = ctx;
2392
+ const { output, query, mutation, suspense, parser, client, group, customOptions } = ctx.options;
2393
+ const pluginTs = driver.getPlugin(pluginTsName);
2394
+ if (!pluginTs) return null;
2395
+ const tsResolver = driver.getResolver(pluginTsName);
2396
+ const isQuery = query === false || !!query && query.methods.some((method) => node.method.toLowerCase() === method.toLowerCase());
2397
+ const queryMethods = new Set(query ? query.methods : []);
2398
+ const isMutation = mutation !== false && !isQuery && (mutation ? mutation.methods : []).some((method) => !queryMethods.has(method) && node.method.toLowerCase() === method.toLowerCase());
2399
+ if (!isQuery || isMutation || !!!suspense) return null;
2400
+ const importPath = query ? query.importPath : "@tanstack/react-query";
2401
+ const contractOp = resolveClientOperation({
2402
+ clientPlugin: { pluginName: client.pluginName },
2403
+ driver,
2404
+ node,
2405
+ root,
2406
+ output
2407
+ });
2408
+ if (!contractOp) return null;
2409
+ const queryName = resolver.resolveSuspenseQueryName(node);
2410
+ const queryOptionsName = resolver.resolveSuspenseQueryOptionsName(node);
2411
+ const queryKeyName = resolver.resolveSuspenseQueryKeyName(node);
2412
+ const queryKeyTypeName = resolver.resolveSuspenseQueryKeyTypeName(node);
2413
+ const meta = {
2414
+ file: resolver.resolveFile(operationFileEntry(node, queryName), {
2415
+ root,
2416
+ output,
2417
+ group: group ?? void 0
2418
+ }),
2419
+ fileTs: tsResolver.resolveFile(operationFileEntry(node, node.operationId), {
2420
+ root,
2421
+ output: pluginTs.options?.output ?? output,
2422
+ group: pluginTs.options?.group ?? void 0
2423
+ })
2424
+ };
2425
+ const importedTypeNames = [tsResolver.resolveRequestConfigName(node), ...resolveOperationTypeNames(node, tsResolver, {
2426
+ exclude: [queryKeyTypeName],
2427
+ order: "body-response-first",
2428
+ includeParams: false
2429
+ })].filter((name) => Boolean(name));
2430
+ const pluginZod = isParserEnabled(parser) ? driver.getPlugin(pluginZodName) : null;
2431
+ const zodResolver = pluginZod ? driver.getResolver(pluginZodName) : null;
2432
+ const fileZod = zodResolver ? zodResolver.resolveFile(operationFileEntry(node, node.operationId), {
2433
+ root,
2434
+ output: pluginZod?.options?.output ?? output,
2435
+ group: pluginZod?.options?.group ?? void 0
2436
+ }) : null;
2437
+ const zodSchemaNames = resolveZodSchemaNames(node, zodResolver, parser);
2438
+ const calledClientName = contractOp.name;
2439
+ return /* @__PURE__ */ jsxs(File, {
2440
+ baseName: meta.file.baseName,
2441
+ path: meta.file.path,
2442
+ meta: meta.file.meta,
2443
+ banner: resolver.resolveBanner(ctx.meta, {
2444
+ output,
2445
+ config,
2446
+ file: {
2447
+ path: meta.file.path,
2448
+ baseName: meta.file.baseName
2449
+ }
2450
+ }),
2451
+ footer: resolver.resolveFooter(ctx.meta, {
2452
+ output,
2453
+ config,
2454
+ file: {
2455
+ path: meta.file.path,
2456
+ baseName: meta.file.baseName
2457
+ }
2458
+ }),
2459
+ children: [
2460
+ fileZod && zodSchemaNames.length > 0 && /* @__PURE__ */ jsx(File.Import, {
2461
+ name: zodSchemaNames,
2462
+ root: meta.file.path,
2463
+ path: fileZod.path
2464
+ }),
2465
+ /* @__PURE__ */ jsx(File.Import, {
2466
+ name: [contractOp.name],
2467
+ root: meta.file.path,
2468
+ path: contractOp.path
2469
+ }),
2470
+ /* @__PURE__ */ jsx(File.Import, {
2471
+ name: ["RequestConfig", "ResponseErrorConfig"],
2472
+ root: meta.file.path,
2473
+ path: contractOp.clientPath,
2474
+ isTypeOnly: true
2475
+ }),
2476
+ customOptions && /* @__PURE__ */ jsx(File.Import, {
2477
+ name: [customOptions.name],
2478
+ path: customOptions.importPath
2479
+ }),
2480
+ meta.fileTs && importedTypeNames.length > 0 && /* @__PURE__ */ jsx(File.Import, {
2481
+ name: Array.from(new Set(importedTypeNames)),
2482
+ root: meta.file.path,
2483
+ path: meta.fileTs.path,
2484
+ isTypeOnly: true
2485
+ }),
2486
+ /* @__PURE__ */ jsx(QueryKey, {
2487
+ name: queryKeyName,
2488
+ typeName: queryKeyTypeName,
2489
+ node,
2490
+ tsResolver,
2491
+ transformer: ctx.options.queryKey
2492
+ }),
2493
+ /* @__PURE__ */ jsx(File.Import, {
2494
+ name: ["queryOptions"],
2495
+ path: importPath
2496
+ }),
2497
+ /* @__PURE__ */ jsx(QueryOptions, {
2498
+ name: queryOptionsName,
2499
+ clientName: calledClientName,
2500
+ queryKeyName,
2501
+ node,
2502
+ tsResolver
2503
+ }),
2504
+ suspense && /* @__PURE__ */ jsxs(Fragment, { children: [
2505
+ /* @__PURE__ */ jsx(File.Import, {
2506
+ name: ["useSuspenseQuery"],
2507
+ path: importPath
2508
+ }),
2509
+ /* @__PURE__ */ jsx(File.Import, {
2510
+ name: [
2511
+ "QueryKey",
2512
+ "QueryClient",
2513
+ "UseSuspenseQueryOptions",
2514
+ "UseSuspenseQueryResult"
2515
+ ],
2516
+ path: importPath,
2517
+ isTypeOnly: true
2518
+ }),
2519
+ /* @__PURE__ */ jsx(SuspenseQuery, {
2520
+ name: queryName,
2521
+ queryOptionsName,
2522
+ queryKeyName,
2523
+ queryKeyTypeName,
2524
+ node,
2525
+ tsResolver,
2526
+ customOptions
2527
+ })
2528
+ ] })
2529
+ ]
2530
+ });
2531
+ }
2532
+ });
2533
+ //#endregion
68
2534
  //#region src/resolvers/resolverReactQuery.ts
69
2535
  function capitalize(name) {
70
2536
  return `${name.charAt(0).toUpperCase()}${name.slice(1)}`;
@@ -215,10 +2681,8 @@ const pluginReactQuery = definePlugin((options) => {
215
2681
  const { output = {
216
2682
  path: "hooks",
217
2683
  barrel: { type: "named" }
218
- }, group, exclude = [], include, override = [], parser = false, suspense = {}, infinite = false, paramsType = "inline", pathParamsType = paramsType === "object" ? "object" : options.pathParamsType || "inline", mutation = {}, query = {}, mutationKey = mutationKeyTransformer, queryKey = queryKeyTransformer, customOptions, paramsCasing, client, resolver: userResolver, transformer: userTransformer, generators: userGenerators = [] } = options;
219
- const clientName = client?.client ?? "axios";
220
- const clientImportPath = client?.importPath ?? (!client?.bundle ? `@kubb/plugin-client/clients/${clientName}` : void 0);
221
- const selectedGenerators = options.generators ?? [
2684
+ }, group, exclude = [], include, override = [], parser = false, suspense = {}, infinite = false, mutation = {}, query = {}, mutationKey = mutationKeyTransformer, queryKey = queryKeyTransformer, customOptions, client, resolver: userResolver, macros: userMacros } = options;
2685
+ const selectedGenerators = [
222
2686
  queryGenerator,
223
2687
  suspenseQueryGenerator,
224
2688
  infiniteQueryGenerator,
@@ -237,17 +2701,18 @@ const pluginReactQuery = definePlugin((options) => {
237
2701
  ...resolverReactQuery,
238
2702
  ...userResolver
239
2703
  } : resolverReactQuery;
2704
+ const resolvedClient = resolveClient({
2705
+ client,
2706
+ pluginNames: (ctx.config.plugins ?? []).map((p) => p.name).filter((name) => Boolean(name))
2707
+ });
2708
+ if (resolvedClient.kind === "error") throw new Error(resolvedClient.message);
2709
+ const resolvedClientDescriptor = {
2710
+ kind: "contract",
2711
+ pluginName: resolvedClient.pluginName
2712
+ };
240
2713
  ctx.setOptions({
241
2714
  output,
242
- client: {
243
- bundle: client?.bundle,
244
- baseURL: client?.baseURL,
245
- client: clientName,
246
- clientType: client?.clientType ?? "function",
247
- importPath: clientImportPath,
248
- dataReturnType: client?.dataReturnType ?? "data",
249
- paramsCasing
250
- },
2715
+ client: resolvedClientDescriptor,
251
2716
  queryKey,
252
2717
  query: query === false ? false : {
253
2718
  importPath: "@tanstack/react-query",
@@ -279,9 +2744,6 @@ const pluginReactQuery = definePlugin((options) => {
279
2744
  ...customOptions
280
2745
  } : null,
281
2746
  parser,
282
- paramsType,
283
- pathParamsType,
284
- paramsCasing,
285
2747
  group: groupConfig,
286
2748
  exclude,
287
2749
  include,
@@ -289,31 +2751,8 @@ const pluginReactQuery = definePlugin((options) => {
289
2751
  resolver
290
2752
  });
291
2753
  ctx.setResolver(resolver);
292
- if (userTransformer) ctx.setTransformer(userTransformer);
2754
+ if (userMacros?.length) ctx.setMacros(userMacros);
293
2755
  for (const gen of selectedGenerators) ctx.addGenerator(gen);
294
- for (const gen of userGenerators) ctx.addGenerator(gen);
295
- const root = path.resolve(ctx.config.root, ctx.config.output.path);
296
- const hasClientPlugin = !!ctx.config.plugins?.some((p) => p.name === pluginClientName);
297
- if (client?.bundle && !hasClientPlugin && !clientImportPath) ctx.injectFile({
298
- baseName: "client.ts",
299
- path: path.resolve(root, ".kubb/client.ts"),
300
- sources: [ast.createSource({
301
- name: "client",
302
- nodes: [ast.createText(clientName === "fetch" ? source$1 : source)],
303
- isExportable: true,
304
- isIndexable: true
305
- })]
306
- });
307
- if (!hasClientPlugin) ctx.injectFile({
308
- baseName: "config.ts",
309
- path: path.resolve(root, ".kubb/config.ts"),
310
- sources: [ast.createSource({
311
- name: "config",
312
- nodes: [ast.createText(source$2)],
313
- isExportable: false,
314
- isIndexable: false
315
- })]
316
- });
317
2756
  } }
318
2757
  };
319
2758
  });