@kubb/plugin-react-query 5.0.0-beta.99 → 5.1.0-canary.20260819T202657
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +334 -445
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +331 -442
- package/dist/index.js.map +1 -1
- package/package.json +8 -11
package/dist/index.js
CHANGED
|
@@ -1,250 +1,10 @@
|
|
|
1
1
|
import "./rolldown-runtime-C0LytTxp.js";
|
|
2
|
+
import { Resolver, Url, ast, createResolver, defineGenerator, definePlugin } from "kubb/kit";
|
|
2
3
|
import path from "node:path";
|
|
3
|
-
import { Resolver, ast, createResolver, defineGenerator, definePlugin } from "kubb/kit";
|
|
4
4
|
import { createFunctionParameter, createFunctionParameters, createObjectBindingPattern, createTypeLiteral, functionPrinter, pluginTsName } from "@kubb/plugin-ts";
|
|
5
5
|
import { File, Function, Type, jsxRenderer } from "kubb/jsx";
|
|
6
6
|
import { Fragment, jsx, jsxs } from "kubb/jsx/jsx-runtime";
|
|
7
7
|
import fs from "node:fs";
|
|
8
|
-
//#region ../../internals/utils/src/casing.ts
|
|
9
|
-
/**
|
|
10
|
-
* Shared implementation for camelCase and PascalCase conversion.
|
|
11
|
-
* Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)
|
|
12
|
-
* and capitalizes each word according to `pascal`.
|
|
13
|
-
*
|
|
14
|
-
* When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
|
|
15
|
-
*/
|
|
16
|
-
function toCamelOrPascal(text, pascal) {
|
|
17
|
-
return text.trim().replace(/([a-z\d])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/(\d)([a-z])/g, "$1 $2").split(/[\s\-_./\\:]+/).filter(Boolean).map((word, i) => {
|
|
18
|
-
if (word.length > 1 && word === word.toUpperCase()) return word;
|
|
19
|
-
return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
|
|
20
|
-
}).join("").replace(/[^a-zA-Z0-9]/g, "");
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Converts `text` to camelCase.
|
|
24
|
-
*
|
|
25
|
-
* @example Word boundaries
|
|
26
|
-
* `camelCase('hello-world') // 'helloWorld'`
|
|
27
|
-
*
|
|
28
|
-
* @example With a prefix
|
|
29
|
-
* `camelCase('tag', { prefix: 'create' }) // 'createTag'`
|
|
30
|
-
*/
|
|
31
|
-
function camelCase(text, { prefix = "", suffix = "" } = {}) {
|
|
32
|
-
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Uppercases only the first character of `text`, leaving the rest untouched.
|
|
36
|
-
* Unlike {@link pascalCase} it never re-splits word boundaries or strips characters.
|
|
37
|
-
*
|
|
38
|
-
* @example
|
|
39
|
-
* `capitalize('getPetById') // 'GetPetById'`
|
|
40
|
-
*/
|
|
41
|
-
function capitalize(text) {
|
|
42
|
-
return `${text.charAt(0).toUpperCase()}${text.slice(1)}`;
|
|
43
|
-
}
|
|
44
|
-
//#endregion
|
|
45
|
-
//#region ../../internals/utils/src/reserved.ts
|
|
46
|
-
/**
|
|
47
|
-
* JavaScript and Java reserved words.
|
|
48
|
-
* @link https://github.com/jonschlinkert/reserved/blob/master/index.js
|
|
49
|
-
*/
|
|
50
|
-
const reservedWords = /* @__PURE__ */ new Set([
|
|
51
|
-
"abstract",
|
|
52
|
-
"arguments",
|
|
53
|
-
"boolean",
|
|
54
|
-
"break",
|
|
55
|
-
"byte",
|
|
56
|
-
"case",
|
|
57
|
-
"catch",
|
|
58
|
-
"char",
|
|
59
|
-
"class",
|
|
60
|
-
"const",
|
|
61
|
-
"continue",
|
|
62
|
-
"debugger",
|
|
63
|
-
"default",
|
|
64
|
-
"delete",
|
|
65
|
-
"do",
|
|
66
|
-
"double",
|
|
67
|
-
"else",
|
|
68
|
-
"enum",
|
|
69
|
-
"eval",
|
|
70
|
-
"export",
|
|
71
|
-
"extends",
|
|
72
|
-
"false",
|
|
73
|
-
"final",
|
|
74
|
-
"finally",
|
|
75
|
-
"float",
|
|
76
|
-
"for",
|
|
77
|
-
"function",
|
|
78
|
-
"goto",
|
|
79
|
-
"if",
|
|
80
|
-
"implements",
|
|
81
|
-
"import",
|
|
82
|
-
"in",
|
|
83
|
-
"instanceof",
|
|
84
|
-
"int",
|
|
85
|
-
"interface",
|
|
86
|
-
"let",
|
|
87
|
-
"long",
|
|
88
|
-
"native",
|
|
89
|
-
"new",
|
|
90
|
-
"null",
|
|
91
|
-
"package",
|
|
92
|
-
"private",
|
|
93
|
-
"protected",
|
|
94
|
-
"public",
|
|
95
|
-
"return",
|
|
96
|
-
"short",
|
|
97
|
-
"static",
|
|
98
|
-
"super",
|
|
99
|
-
"switch",
|
|
100
|
-
"synchronized",
|
|
101
|
-
"this",
|
|
102
|
-
"throw",
|
|
103
|
-
"throws",
|
|
104
|
-
"transient",
|
|
105
|
-
"true",
|
|
106
|
-
"try",
|
|
107
|
-
"typeof",
|
|
108
|
-
"var",
|
|
109
|
-
"void",
|
|
110
|
-
"volatile",
|
|
111
|
-
"while",
|
|
112
|
-
"with",
|
|
113
|
-
"yield",
|
|
114
|
-
"Array",
|
|
115
|
-
"Date",
|
|
116
|
-
"hasOwnProperty",
|
|
117
|
-
"Infinity",
|
|
118
|
-
"isFinite",
|
|
119
|
-
"isNaN",
|
|
120
|
-
"isPrototypeOf",
|
|
121
|
-
"length",
|
|
122
|
-
"Math",
|
|
123
|
-
"name",
|
|
124
|
-
"NaN",
|
|
125
|
-
"Number",
|
|
126
|
-
"Object",
|
|
127
|
-
"prototype",
|
|
128
|
-
"String",
|
|
129
|
-
"toString",
|
|
130
|
-
"undefined",
|
|
131
|
-
"valueOf"
|
|
132
|
-
]);
|
|
133
|
-
/**
|
|
134
|
-
* Returns `true` when `name` is a syntactically valid JavaScript variable name.
|
|
135
|
-
*
|
|
136
|
-
* @example
|
|
137
|
-
* ```ts
|
|
138
|
-
* isValidVarName('status') // true
|
|
139
|
-
* isValidVarName('class') // false (reserved word)
|
|
140
|
-
* isValidVarName('42foo') // false (starts with digit)
|
|
141
|
-
* ```
|
|
142
|
-
*/
|
|
143
|
-
function isValidVarName(name) {
|
|
144
|
-
if (!name || reservedWords.has(name)) return false;
|
|
145
|
-
return isIdentifier(name);
|
|
146
|
-
}
|
|
147
|
-
/**
|
|
148
|
-
* Returns `true` when `name` is syntactically a valid identifier, ignoring reserved words.
|
|
149
|
-
*
|
|
150
|
-
* Reserved words and globals (`class`, `name`, `Date`, …) are valid as bare object-literal keys
|
|
151
|
-
* even though they are not valid variable names, so use this (not {@link isValidVarName}) when
|
|
152
|
-
* deciding whether an object key needs quoting.
|
|
153
|
-
*
|
|
154
|
-
* @example
|
|
155
|
-
* ```ts
|
|
156
|
-
* isIdentifier('name') // true
|
|
157
|
-
* isIdentifier('x-total')// false
|
|
158
|
-
* ```
|
|
159
|
-
*/
|
|
160
|
-
function isIdentifier(name) {
|
|
161
|
-
return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
|
|
162
|
-
}
|
|
163
|
-
//#endregion
|
|
164
|
-
//#region ../../internals/utils/src/strings.ts
|
|
165
|
-
/**
|
|
166
|
-
* Renders a dotted path or string array as an optional-chaining accessor expression rooted at
|
|
167
|
-
* `accessor`. Returns `null` for an empty path.
|
|
168
|
-
*
|
|
169
|
-
* @example
|
|
170
|
-
* ```ts
|
|
171
|
-
* getNestedAccessor('pagination.next.id', 'lastPage')
|
|
172
|
-
* // "lastPage?.['pagination']?.['next']?.['id']"
|
|
173
|
-
* ```
|
|
174
|
-
*/
|
|
175
|
-
function getNestedAccessor(param, accessor) {
|
|
176
|
-
const parts = Array.isArray(param) ? param : param.split(".");
|
|
177
|
-
if (parts.length === 0 || parts.length === 1 && parts[0] === "") return null;
|
|
178
|
-
return `${accessor}?.['${`${parts.join("']?.['")}']`}`;
|
|
179
|
-
}
|
|
180
|
-
//#endregion
|
|
181
|
-
//#region ../../internals/utils/src/url.ts
|
|
182
|
-
/**
|
|
183
|
-
* Keeps the OpenAPI parameter name as-is when it is already a valid JS identifier, and
|
|
184
|
-
* camelCases it only enough to become one otherwise (for example a hyphenated path segment).
|
|
185
|
-
*/
|
|
186
|
-
function transformParam(raw) {
|
|
187
|
-
return isValidVarName(raw) ? raw : camelCase(raw);
|
|
188
|
-
}
|
|
189
|
-
/**
|
|
190
|
-
* Helpers for OpenAPI/Swagger paths.
|
|
191
|
-
*/
|
|
192
|
-
var Url = class Url {
|
|
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
|
-
* Rewrites OpenAPI placeholder names while keeping the `{...}` braces, so the generated `url`
|
|
204
|
-
* literal aligns with the grouped `path` request option that the runtime client interpolates by
|
|
205
|
-
* key.
|
|
206
|
-
*
|
|
207
|
-
* @example
|
|
208
|
-
* Url.toSafeTemplate('/user/{monetary-account-id}') // '/user/{monetaryAccountId}'
|
|
209
|
-
*/
|
|
210
|
-
static toSafeTemplate(path) {
|
|
211
|
-
return path.replace(/\{([^}]+)\}/g, (_, name) => `{${transformParam(name)}}`);
|
|
212
|
-
}
|
|
213
|
-
/**
|
|
214
|
-
* Converts an OpenAPI/Swagger path to a TypeScript template literal string.
|
|
215
|
-
* `prefix` is prepended inside the literal, and `replacer` transforms each parameter name.
|
|
216
|
-
*
|
|
217
|
-
* @example
|
|
218
|
-
* Url.toTemplateString('/pet/{petId}') // '`/pet/${petId}`'
|
|
219
|
-
*
|
|
220
|
-
* @example
|
|
221
|
-
* Url.toTemplateString('/pet/{petId}', { prefix: 'https://api' }) // '`https://api/pet/${petId}`'
|
|
222
|
-
*/
|
|
223
|
-
static toTemplateString(path, { prefix, replacer } = {}) {
|
|
224
|
-
const result = path.split(/\{([^}]+)\}/).map((part, i) => {
|
|
225
|
-
if (i % 2 === 0) return part;
|
|
226
|
-
const param = transformParam(part);
|
|
227
|
-
return `\${${replacer ? replacer(param) : param}}`;
|
|
228
|
-
}).join("");
|
|
229
|
-
return `\`${prefix ?? ""}${result}\``;
|
|
230
|
-
}
|
|
231
|
-
/**
|
|
232
|
-
* Converts an OpenAPI/Swagger path to a template literal that reads each parameter off the
|
|
233
|
-
* grouped `path` request option, e.g. `/pet/{petId}` becomes `` `/pet/${path.petId}` ``. Parameter
|
|
234
|
-
* names match the generated `path` type, and `prefix` is prepended inside the literal. Shared by
|
|
235
|
-
* the client and cypress generators that pass a grouped `path` object.
|
|
236
|
-
*
|
|
237
|
-
* @example
|
|
238
|
-
* Url.toGroupedTemplateString('/pet/{petId}') // '`/pet/${path.petId}`'
|
|
239
|
-
*/
|
|
240
|
-
static toGroupedTemplateString(path, { prefix } = {}) {
|
|
241
|
-
return Url.toTemplateString(path, {
|
|
242
|
-
prefix,
|
|
243
|
-
replacer: (name) => `path.${name}`
|
|
244
|
-
});
|
|
245
|
-
}
|
|
246
|
-
};
|
|
247
|
-
//#endregion
|
|
248
8
|
//#region ../../internals/shared/src/params.ts
|
|
249
9
|
/**
|
|
250
10
|
* Drops parameters that share the same name, keeping the first.
|
|
@@ -283,11 +43,30 @@ function operationFileEntry(node, name, extname = ".ts") {
|
|
|
283
43
|
path: node.path
|
|
284
44
|
};
|
|
285
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* Resolves a dependency plugin's generated file for `node.operationId`, cached in `cache` (the
|
|
48
|
+
* current node's `ctx.cache`) under the resolver's own plugin name. Several dependents reading the
|
|
49
|
+
* same dependency for the same operation in one pass (a query plugin's several hook generators, the
|
|
50
|
+
* MCP handler, ...) share one computed name and path instead of each calling `resolver.file` again.
|
|
51
|
+
*
|
|
52
|
+
* @example Cache `plugin-ts`'s file for the current operation
|
|
53
|
+
* ```ts
|
|
54
|
+
* const fileTs = resolveDependencyOperationFile({ cache: ctx.cache, node, resolver: tsResolver, root, output })
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
function resolveDependencyOperationFile(options) {
|
|
58
|
+
const { cache, node, resolver, root, output, group } = options;
|
|
59
|
+
return cache.ensureItem(`${resolver.pluginName}:operationFile`, () => resolver.file({
|
|
60
|
+
...operationFileEntry(node, node.operationId),
|
|
61
|
+
root,
|
|
62
|
+
output,
|
|
63
|
+
group: group ?? void 0
|
|
64
|
+
}));
|
|
65
|
+
}
|
|
286
66
|
function getOperationLink(node, link) {
|
|
287
67
|
if (!link) return null;
|
|
288
68
|
if (typeof link === "function") return link(node) ?? null;
|
|
289
|
-
|
|
290
|
-
return node.path ? `{@link ${node.path.replaceAll("{", ":").replaceAll("}", "")}}` : null;
|
|
69
|
+
return node.path ? `{@link ${Url.toPath(node.path)}}` : null;
|
|
291
70
|
}
|
|
292
71
|
/**
|
|
293
72
|
* Derives the shared `ContentTypeInfo` shape from a list of content types, tracking whether several
|
|
@@ -377,16 +156,24 @@ function buildOperationComments(node, options = {}) {
|
|
|
377
156
|
if (!splitLines) return filteredComments;
|
|
378
157
|
return filteredComments.flatMap((text) => text.split(/\r?\n/).map((line) => line.trim())).filter((comment) => Boolean(comment));
|
|
379
158
|
}
|
|
159
|
+
const operationParameterGroupsByNode = /* @__PURE__ */ new WeakMap();
|
|
160
|
+
/**
|
|
161
|
+
* Groups an operation's parameters by location (`path`/`query`/`header`/`cookie`), deduping each
|
|
162
|
+
* group by name. Every plugin generator visiting the same `OperationNode` shares one AST instance
|
|
163
|
+
* (see `KubbDriver`), so the result is cached per node to avoid re-filtering and re-deduping the
|
|
164
|
+
* same parameters once per plugin.
|
|
165
|
+
*/
|
|
380
166
|
function getOperationParameters(node) {
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
})),
|
|
167
|
+
const cached = operationParameterGroupsByNode.get(node);
|
|
168
|
+
if (cached) return cached;
|
|
169
|
+
const groups = {
|
|
170
|
+
path: dedupeParams(node.parameters.filter((param) => param.in === "path")),
|
|
386
171
|
query: dedupeParams(node.parameters.filter((param) => param.in === "query")),
|
|
387
172
|
header: dedupeParams(node.parameters.filter((param) => param.in === "header")),
|
|
388
173
|
cookie: dedupeParams(node.parameters.filter((param) => param.in === "cookie"))
|
|
389
174
|
};
|
|
175
|
+
operationParameterGroupsByNode.set(node, groups);
|
|
176
|
+
return groups;
|
|
390
177
|
}
|
|
391
178
|
function getStatusCodeNumber(statusCode) {
|
|
392
179
|
const code = Number(statusCode);
|
|
@@ -451,6 +238,60 @@ function resolveOperationTypeNames(node, resolver, options = {}) {
|
|
|
451
238
|
return result;
|
|
452
239
|
}
|
|
453
240
|
//#endregion
|
|
241
|
+
//#region ../../internals/utils/src/casing.ts
|
|
242
|
+
/**
|
|
243
|
+
* Shared implementation for camelCase and PascalCase conversion.
|
|
244
|
+
* Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)
|
|
245
|
+
* and capitalizes each word according to `pascal`.
|
|
246
|
+
*
|
|
247
|
+
* When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
|
|
248
|
+
*/
|
|
249
|
+
function toCamelOrPascal(text, pascal) {
|
|
250
|
+
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) => {
|
|
251
|
+
if (word.length > 1 && word === word.toUpperCase()) return word;
|
|
252
|
+
return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
|
|
253
|
+
}).join("").replace(/[^a-zA-Z0-9]/g, "");
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Converts `text` to camelCase.
|
|
257
|
+
*
|
|
258
|
+
* @example Word boundaries
|
|
259
|
+
* `camelCase('hello-world') // 'helloWorld'`
|
|
260
|
+
*
|
|
261
|
+
* @example With a prefix
|
|
262
|
+
* `camelCase('tag', { prefix: 'create' }) // 'createTag'`
|
|
263
|
+
*/
|
|
264
|
+
function camelCase(text, { prefix = "", suffix = "" } = {}) {
|
|
265
|
+
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Uppercases only the first character of `text`, leaving the rest untouched.
|
|
269
|
+
* Unlike {@link pascalCase} it never re-splits word boundaries or strips characters.
|
|
270
|
+
*
|
|
271
|
+
* @example
|
|
272
|
+
* `capitalize('getPetById') // 'GetPetById'`
|
|
273
|
+
*/
|
|
274
|
+
function capitalize(text) {
|
|
275
|
+
return `${text.charAt(0).toUpperCase()}${text.slice(1)}`;
|
|
276
|
+
}
|
|
277
|
+
//#endregion
|
|
278
|
+
//#region ../../internals/utils/src/strings.ts
|
|
279
|
+
/**
|
|
280
|
+
* Renders a dotted path or string array as an optional-chaining accessor expression rooted at
|
|
281
|
+
* `accessor`. Returns `null` for an empty path.
|
|
282
|
+
*
|
|
283
|
+
* @example
|
|
284
|
+
* ```ts
|
|
285
|
+
* getNestedAccessor('pagination.next.id', 'lastPage')
|
|
286
|
+
* // "lastPage?.['pagination']?.['next']?.['id']"
|
|
287
|
+
* ```
|
|
288
|
+
*/
|
|
289
|
+
function getNestedAccessor(param, accessor) {
|
|
290
|
+
const parts = Array.isArray(param) ? param : param.split(".");
|
|
291
|
+
if (parts.length === 0 || parts.length === 1 && parts[0] === "") return null;
|
|
292
|
+
return `${accessor}?.['${`${parts.join("']?.['")}']`}`;
|
|
293
|
+
}
|
|
294
|
+
//#endregion
|
|
454
295
|
//#region ../../internals/shared/src/group.ts
|
|
455
296
|
/**
|
|
456
297
|
* Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the
|
|
@@ -570,23 +411,30 @@ function resolveContractClient(options) {
|
|
|
570
411
|
* (plugin-fetch or plugin-axios). Returns `null` when no contract plugin is in play (the inline
|
|
571
412
|
* path). The plugin injects `.kubb/client.ts` at the global output root, the same path consumers
|
|
572
413
|
* read `RequestConfig` / `ResponseErrorConfig` from.
|
|
414
|
+
*
|
|
415
|
+
* The result is cached in the current node's `cache` (`ctx.cache`) under the client plugin's name,
|
|
416
|
+
* so several dependents reading the same client plugin for one operation in a single pass
|
|
417
|
+
* (react-query's query/mutation/infinite generators, vue-query, swr, the MCP handler, ...) share
|
|
418
|
+
* one computed result instead of each re-deriving the name and path.
|
|
573
419
|
*/
|
|
574
420
|
function resolveClientOperation(options) {
|
|
575
|
-
const { clientPlugin, driver, node, root, output } = options;
|
|
421
|
+
const { clientPlugin, driver, node, root, output, cache } = options;
|
|
576
422
|
if (!clientPlugin) return null;
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
423
|
+
return cache.ensureItem(`${clientPlugin.pluginName}:clientOperation`, () => {
|
|
424
|
+
const resolver = driver.getResolver(clientPlugin.pluginName);
|
|
425
|
+
const plugin = driver.getPlugin(clientPlugin.pluginName);
|
|
426
|
+
const file = resolver.file({
|
|
427
|
+
...operationFileEntry(node, node.operationId),
|
|
428
|
+
root,
|
|
429
|
+
output: plugin?.options?.output ?? output,
|
|
430
|
+
group: plugin?.options?.group ?? void 0
|
|
431
|
+
});
|
|
432
|
+
return {
|
|
433
|
+
name: resolver.name(node.operationId),
|
|
434
|
+
path: file.path,
|
|
435
|
+
clientPath: path.resolve(root, ".kubb/client.ts")
|
|
436
|
+
};
|
|
584
437
|
});
|
|
585
|
-
return {
|
|
586
|
-
name: resolver.name(node.operationId),
|
|
587
|
-
path: file.path,
|
|
588
|
-
clientPath: path.resolve(root, ".kubb/client.ts")
|
|
589
|
-
};
|
|
590
438
|
}
|
|
591
439
|
//#endregion
|
|
592
440
|
//#region ../../internals/tanstack-query/src/utils.ts
|
|
@@ -657,14 +505,16 @@ function buildGroupedRequestParam(node, options) {
|
|
|
657
505
|
*/
|
|
658
506
|
function buildQueryOptionsParams(node, options) {
|
|
659
507
|
const { resolver, memberTypeWrapper } = options;
|
|
660
|
-
|
|
508
|
+
const groupedParam = buildGroupedRequestParam(node, {
|
|
661
509
|
resolver,
|
|
662
510
|
memberTypeWrapper
|
|
663
|
-
})
|
|
511
|
+
});
|
|
512
|
+
const configParam = createFunctionParameter({
|
|
664
513
|
name: "config",
|
|
665
514
|
type: `Partial<Omit<RequestConfig, 'path' | 'query' | 'body' | 'headers' | 'url'>>`,
|
|
666
515
|
default: "{}"
|
|
667
|
-
})
|
|
516
|
+
});
|
|
517
|
+
return createFunctionParameters({ params: [groupedParam, configParam].filter((param) => param !== null) });
|
|
668
518
|
}
|
|
669
519
|
/**
|
|
670
520
|
* Builds the call to a client `<op>` function inside a query/mutation hook body. The function takes
|
|
@@ -762,6 +612,19 @@ function resolveMutationConfig(mutation, options) {
|
|
|
762
612
|
};
|
|
763
613
|
}
|
|
764
614
|
/**
|
|
615
|
+
* Classifies an operation as a query or a mutation from the resolved `query` / `mutation` method lists.
|
|
616
|
+
* `query: false` still marks the operation as a query so the query-family generators keep matching it,
|
|
617
|
+
* and a method already claimed by `query` never counts as a mutation.
|
|
618
|
+
*/
|
|
619
|
+
function classifyOperation(node, { query, mutation }) {
|
|
620
|
+
const isQuery = query === false || !!query && query.methods.some((method) => node.method.toLowerCase() === method.toLowerCase());
|
|
621
|
+
const queryMethods = new Set(query ? query.methods : []);
|
|
622
|
+
return {
|
|
623
|
+
isQuery,
|
|
624
|
+
isMutation: mutation !== false && !isQuery && (mutation ? mutation.methods : []).some((method) => !queryMethods.has(method) && node.method.toLowerCase() === method.toLowerCase())
|
|
625
|
+
};
|
|
626
|
+
}
|
|
627
|
+
/**
|
|
765
628
|
* Applies the shared infinite-query defaults during plugin setup: a falsy value disables infinite
|
|
766
629
|
* queries, and an object merges over `queryParam: 'id'` and `initialPageParam: 0` with the cursor
|
|
767
630
|
* paths cleared.
|
|
@@ -1131,19 +994,6 @@ function buildResolvedRequestParams(node) {
|
|
|
1131
994
|
if (names.length === 0) return null;
|
|
1132
995
|
return `{ ${names.map((name) => `${name}: typeof ${name} === 'function' ? ${name}() : ${name}`).join(", ")} }`;
|
|
1133
996
|
}
|
|
1134
|
-
/**
|
|
1135
|
-
* Classifies an operation as a query or a mutation from the resolved `query` / `mutation` method lists.
|
|
1136
|
-
* `query: false` still marks the operation as a query so the query-family generators keep matching it,
|
|
1137
|
-
* and a method already claimed by `query` never counts as a mutation.
|
|
1138
|
-
*/
|
|
1139
|
-
function classifyOperation(node, { query, mutation }) {
|
|
1140
|
-
const isQuery = query === false || !!query && query.methods.some((method) => node.method.toLowerCase() === method.toLowerCase());
|
|
1141
|
-
const queryMethods = new Set(query ? query.methods : []);
|
|
1142
|
-
return {
|
|
1143
|
-
isQuery,
|
|
1144
|
-
isMutation: mutation !== false && !isQuery && (mutation ? mutation.methods : []).some((method) => !queryMethods.has(method) && node.method.toLowerCase() === method.toLowerCase())
|
|
1145
|
-
};
|
|
1146
|
-
}
|
|
1147
997
|
//#endregion
|
|
1148
998
|
//#region src/generators/hookOptionsGenerator.tsx
|
|
1149
999
|
/**
|
|
@@ -1318,10 +1168,11 @@ function buildInfiniteQueryParamsNode(node, options) {
|
|
|
1318
1168
|
}`,
|
|
1319
1169
|
default: "{}"
|
|
1320
1170
|
});
|
|
1321
|
-
|
|
1171
|
+
const groupedParam = buildGroupedRequestParam(node, {
|
|
1322
1172
|
resolver,
|
|
1323
1173
|
memberTypeWrapper: maybeValueOrGetter
|
|
1324
|
-
})
|
|
1174
|
+
});
|
|
1175
|
+
return createFunctionParameters({ params: [groupedParam, optionsParam].filter((param) => param !== null) });
|
|
1325
1176
|
}
|
|
1326
1177
|
function InfiniteQuery({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, tsResolver, initialPageParam, queryParam, customOptions, suspense }) {
|
|
1327
1178
|
const { TData: responseType, TError: errorType } = buildResponseTypes(node, tsResolver);
|
|
@@ -1434,15 +1285,16 @@ function resolveMutationRequestType(node, resolver) {
|
|
|
1434
1285
|
function buildMutationParamsNode(node, options) {
|
|
1435
1286
|
const { resolver } = options;
|
|
1436
1287
|
const { TData, TError } = buildResponseTypes(node, resolver);
|
|
1288
|
+
const generics = [
|
|
1289
|
+
TData,
|
|
1290
|
+
TError,
|
|
1291
|
+
resolveMutationRequestType(node, resolver),
|
|
1292
|
+
"TContext"
|
|
1293
|
+
].join(", ");
|
|
1437
1294
|
return createFunctionParameters({ params: [createFunctionParameter({
|
|
1438
1295
|
name: "options",
|
|
1439
1296
|
type: `{
|
|
1440
|
-
mutation?: UseMutationOptions<${
|
|
1441
|
-
TData,
|
|
1442
|
-
TError,
|
|
1443
|
-
resolveMutationRequestType(node, resolver),
|
|
1444
|
-
"TContext"
|
|
1445
|
-
].join(", ")}> & { client?: QueryClient },
|
|
1297
|
+
mutation?: UseMutationOptions<${generics}> & { client?: QueryClient },
|
|
1446
1298
|
client?: ${buildRequestConfigType(node)},
|
|
1447
1299
|
}`,
|
|
1448
1300
|
default: "{}"
|
|
@@ -1500,10 +1352,11 @@ function buildQueryParamsNode(node, options) {
|
|
|
1500
1352
|
}`,
|
|
1501
1353
|
default: "{}"
|
|
1502
1354
|
});
|
|
1503
|
-
|
|
1355
|
+
const groupedParam = buildGroupedRequestParam(node, {
|
|
1504
1356
|
resolver,
|
|
1505
1357
|
memberTypeWrapper: maybeValueOrGetter
|
|
1506
|
-
})
|
|
1358
|
+
});
|
|
1359
|
+
return createFunctionParameters({ params: [groupedParam, optionsParam].filter((param) => param !== null) });
|
|
1507
1360
|
}
|
|
1508
1361
|
function Query({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, tsResolver, customOptions, suspense }) {
|
|
1509
1362
|
const { TData, TError } = buildResponseTypes(node, tsResolver);
|
|
@@ -1568,14 +1421,11 @@ function Query({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, t
|
|
|
1568
1421
|
//#region src/components/QueryOptions.tsx
|
|
1569
1422
|
const declarationPrinter = functionPrinter({ mode: "declaration" });
|
|
1570
1423
|
const callPrinter = functionPrinter({ mode: "call" });
|
|
1571
|
-
function getQueryOptionsParams(node, options) {
|
|
1572
|
-
return buildQueryOptionsParams(node, options);
|
|
1573
|
-
}
|
|
1574
1424
|
function QueryOptions({ name, clientName, node, tsResolver, queryKeyName }) {
|
|
1575
1425
|
const { TData, TError } = buildResponseTypes(node, tsResolver);
|
|
1576
1426
|
const queryKeyParamsNode = buildQueryKeyParams(node, { resolver: tsResolver });
|
|
1577
1427
|
const queryKeyParamsCall = callPrinter.print(queryKeyParamsNode) ?? "";
|
|
1578
|
-
const paramsNode =
|
|
1428
|
+
const paramsNode = buildQueryOptionsParams(node, { resolver: tsResolver });
|
|
1579
1429
|
const paramsSignature = declarationPrinter.print(paramsNode) ?? "";
|
|
1580
1430
|
const queryFnBody = `const { data } = await ${buildClientCall(node, {
|
|
1581
1431
|
clientName,
|
|
@@ -1606,36 +1456,44 @@ function QueryOptions({ name, clientName, node, tsResolver, queryKeyName }) {
|
|
|
1606
1456
|
//#region src/generators/infiniteQueryGenerator.tsx
|
|
1607
1457
|
/**
|
|
1608
1458
|
* Built-in generator for `useInfiniteQuery` hooks. Enabled when
|
|
1609
|
-
* `pluginReactQuery({ infinite: { ... } })`. Emits one
|
|
1610
|
-
* hook per query operation, wiring the configured
|
|
1611
|
-
* `previousParam` paths into TanStack Query's cursor-based
|
|
1459
|
+
* `pluginReactQuery({ infinite: { ... }, hooks: true })`. Emits one
|
|
1460
|
+
* `useFooInfiniteQuery` hook per query operation, wiring the configured
|
|
1461
|
+
* `nextParam` / `previousParam` paths into TanStack Query's cursor-based
|
|
1462
|
+
* pagination.
|
|
1612
1463
|
*/
|
|
1613
1464
|
const infiniteQueryGenerator = defineGenerator({
|
|
1614
1465
|
name: "react-infinite-query",
|
|
1615
1466
|
renderer: jsxRenderer,
|
|
1467
|
+
match(node, ctx) {
|
|
1468
|
+
const operationNode = node;
|
|
1469
|
+
if (!ast.isHttpOperationNode(operationNode)) return false;
|
|
1470
|
+
const { query, mutation, infinite, hooks } = ctx.options;
|
|
1471
|
+
const { isQuery, isMutation } = classifyOperation(operationNode, {
|
|
1472
|
+
query,
|
|
1473
|
+
mutation
|
|
1474
|
+
});
|
|
1475
|
+
const infiniteOptions = infinite && typeof infinite === "object" ? infinite : null;
|
|
1476
|
+
if (!isQuery || isMutation || !infiniteOptions || !hooks) return false;
|
|
1477
|
+
const queryParamKeys = getOperationParameters(operationNode).query.map((p) => p.name);
|
|
1478
|
+
return infiniteOptions.queryParam ? queryParamKeys.includes(infiniteOptions.queryParam) || queryParamKeys.includes(`${infiniteOptions.queryParam}?`) : false;
|
|
1479
|
+
},
|
|
1616
1480
|
operation(node, ctx) {
|
|
1617
1481
|
if (!ast.isHttpOperationNode(node)) return null;
|
|
1618
1482
|
const { config, driver, resolver, root } = ctx;
|
|
1619
|
-
const { output, query,
|
|
1483
|
+
const { output, query, infinite, client, group, customOptions } = ctx.options;
|
|
1620
1484
|
const pluginTs = driver.getPlugin(pluginTsName);
|
|
1621
1485
|
if (!pluginTs) return null;
|
|
1622
1486
|
const tsResolver = driver.getResolver(pluginTsName);
|
|
1623
|
-
const { isQuery, isMutation } = classifyOperation(node, {
|
|
1624
|
-
query,
|
|
1625
|
-
mutation
|
|
1626
|
-
});
|
|
1627
1487
|
const infiniteOptions = infinite && typeof infinite === "object" ? infinite : null;
|
|
1628
|
-
if (!
|
|
1629
|
-
const normalizeKey = (key) => key.replace(/\?$/, "");
|
|
1630
|
-
const queryParamKeys = getOperationParameters(node).query.map((p) => p.name);
|
|
1631
|
-
if (!(infiniteOptions.queryParam ? queryParamKeys.some((k) => normalizeKey(k) === infiniteOptions.queryParam) : false)) return null;
|
|
1488
|
+
if (!infiniteOptions) return null;
|
|
1632
1489
|
const importPath = query ? query.importPath : "@tanstack/react-query";
|
|
1633
1490
|
const contractOp = resolveClientOperation({
|
|
1634
1491
|
clientPlugin: { pluginName: client.pluginName },
|
|
1635
1492
|
driver,
|
|
1636
1493
|
node,
|
|
1637
1494
|
root,
|
|
1638
|
-
output
|
|
1495
|
+
output,
|
|
1496
|
+
cache: ctx.cache
|
|
1639
1497
|
});
|
|
1640
1498
|
if (!contractOp) return null;
|
|
1641
1499
|
const queryName = resolver.infiniteQuery.name(node);
|
|
@@ -1649,15 +1507,20 @@ const infiniteQueryGenerator = defineGenerator({
|
|
|
1649
1507
|
output,
|
|
1650
1508
|
group: group ?? void 0
|
|
1651
1509
|
}),
|
|
1652
|
-
fileTs:
|
|
1653
|
-
|
|
1510
|
+
fileTs: resolveDependencyOperationFile({
|
|
1511
|
+
cache: ctx.cache,
|
|
1512
|
+
node,
|
|
1513
|
+
resolver: tsResolver,
|
|
1654
1514
|
root,
|
|
1655
1515
|
output: pluginTs.options?.output ?? output,
|
|
1656
|
-
group: pluginTs.options?.group
|
|
1516
|
+
group: pluginTs.options?.group
|
|
1657
1517
|
})
|
|
1658
1518
|
};
|
|
1659
|
-
const
|
|
1660
|
-
|
|
1519
|
+
const { queryParamsTypeName } = resolvePageParamType(node, {
|
|
1520
|
+
resolver: tsResolver,
|
|
1521
|
+
initialPageParam: infiniteOptions.initialPageParam,
|
|
1522
|
+
queryParam: infiniteOptions.queryParam
|
|
1523
|
+
});
|
|
1661
1524
|
const importedTypeNames = [
|
|
1662
1525
|
tsResolver.response.options(node),
|
|
1663
1526
|
queryParamsTypeName,
|
|
@@ -1738,33 +1601,31 @@ const infiniteQueryGenerator = defineGenerator({
|
|
|
1738
1601
|
initialPageParam: infiniteOptions.initialPageParam,
|
|
1739
1602
|
queryParam: infiniteOptions.queryParam
|
|
1740
1603
|
}),
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
})
|
|
1767
|
-
] })
|
|
1604
|
+
/* @__PURE__ */ jsx(File.Import, {
|
|
1605
|
+
name: ["useInfiniteQuery"],
|
|
1606
|
+
path: importPath
|
|
1607
|
+
}),
|
|
1608
|
+
/* @__PURE__ */ jsx(File.Import, {
|
|
1609
|
+
name: [
|
|
1610
|
+
"QueryKey",
|
|
1611
|
+
"QueryClient",
|
|
1612
|
+
"InfiniteQueryObserverOptions",
|
|
1613
|
+
"UseInfiniteQueryResult"
|
|
1614
|
+
],
|
|
1615
|
+
path: importPath,
|
|
1616
|
+
isTypeOnly: true
|
|
1617
|
+
}),
|
|
1618
|
+
/* @__PURE__ */ jsx(InfiniteQuery, {
|
|
1619
|
+
name: queryName,
|
|
1620
|
+
queryOptionsName,
|
|
1621
|
+
queryKeyName,
|
|
1622
|
+
queryKeyTypeName,
|
|
1623
|
+
node,
|
|
1624
|
+
tsResolver,
|
|
1625
|
+
initialPageParam: infiniteOptions.initialPageParam,
|
|
1626
|
+
queryParam: infiniteOptions.queryParam,
|
|
1627
|
+
customOptions
|
|
1628
|
+
})
|
|
1768
1629
|
]
|
|
1769
1630
|
});
|
|
1770
1631
|
}
|
|
@@ -1779,25 +1640,30 @@ const infiniteQueryGenerator = defineGenerator({
|
|
|
1779
1640
|
const mutationGenerator = defineGenerator({
|
|
1780
1641
|
name: "react-query-mutation",
|
|
1781
1642
|
renderer: jsxRenderer,
|
|
1643
|
+
match(node, ctx) {
|
|
1644
|
+
const operationNode = node;
|
|
1645
|
+
if (!ast.isHttpOperationNode(operationNode)) return false;
|
|
1646
|
+
const { query, mutation } = ctx.options;
|
|
1647
|
+
return classifyOperation(operationNode, {
|
|
1648
|
+
query,
|
|
1649
|
+
mutation
|
|
1650
|
+
}).isMutation;
|
|
1651
|
+
},
|
|
1782
1652
|
operation(node, ctx) {
|
|
1783
1653
|
if (!ast.isHttpOperationNode(node)) return null;
|
|
1784
1654
|
const { config, driver, resolver, root } = ctx;
|
|
1785
|
-
const { output,
|
|
1655
|
+
const { output, mutation, client, group, customOptions, hooks } = ctx.options;
|
|
1786
1656
|
const pluginTs = driver.getPlugin(pluginTsName);
|
|
1787
1657
|
if (!pluginTs) return null;
|
|
1788
1658
|
const tsResolver = driver.getResolver(pluginTsName);
|
|
1789
|
-
const { isMutation } = classifyOperation(node, {
|
|
1790
|
-
query,
|
|
1791
|
-
mutation
|
|
1792
|
-
});
|
|
1793
|
-
if (!isMutation) return null;
|
|
1794
1659
|
const importPath = mutation ? mutation.importPath : "@tanstack/react-query";
|
|
1795
1660
|
const contractOp = resolveClientOperation({
|
|
1796
1661
|
clientPlugin: { pluginName: client.pluginName },
|
|
1797
1662
|
driver,
|
|
1798
1663
|
node,
|
|
1799
1664
|
root,
|
|
1800
|
-
output
|
|
1665
|
+
output,
|
|
1666
|
+
cache: ctx.cache
|
|
1801
1667
|
});
|
|
1802
1668
|
if (!contractOp) return null;
|
|
1803
1669
|
const mutationHookName = resolver.mutation.name(node);
|
|
@@ -1811,11 +1677,13 @@ const mutationGenerator = defineGenerator({
|
|
|
1811
1677
|
output,
|
|
1812
1678
|
group: group ?? void 0
|
|
1813
1679
|
}),
|
|
1814
|
-
fileTs:
|
|
1815
|
-
|
|
1680
|
+
fileTs: resolveDependencyOperationFile({
|
|
1681
|
+
cache: ctx.cache,
|
|
1682
|
+
node,
|
|
1683
|
+
resolver: tsResolver,
|
|
1816
1684
|
root,
|
|
1817
1685
|
output: pluginTs.options?.output ?? output,
|
|
1818
|
-
group: pluginTs.options?.group
|
|
1686
|
+
group: pluginTs.options?.group
|
|
1819
1687
|
})
|
|
1820
1688
|
};
|
|
1821
1689
|
const importedTypeNames = [tsResolver.response.options(node), ...resolveOperationTypeNames(node, tsResolver, {
|
|
@@ -1919,25 +1787,31 @@ const mutationGenerator = defineGenerator({
|
|
|
1919
1787
|
const queryGenerator = defineGenerator({
|
|
1920
1788
|
name: "react-query",
|
|
1921
1789
|
renderer: jsxRenderer,
|
|
1790
|
+
match(node, ctx) {
|
|
1791
|
+
const operationNode = node;
|
|
1792
|
+
if (!ast.isHttpOperationNode(operationNode)) return false;
|
|
1793
|
+
const { query, mutation } = ctx.options;
|
|
1794
|
+
const { isQuery, isMutation } = classifyOperation(operationNode, {
|
|
1795
|
+
query,
|
|
1796
|
+
mutation
|
|
1797
|
+
});
|
|
1798
|
+
return isQuery && !isMutation;
|
|
1799
|
+
},
|
|
1922
1800
|
operation(node, ctx) {
|
|
1923
1801
|
if (!ast.isHttpOperationNode(node)) return null;
|
|
1924
1802
|
const { config, driver, resolver, root } = ctx;
|
|
1925
|
-
const { output, query,
|
|
1803
|
+
const { output, query, client, group, customOptions, hooks } = ctx.options;
|
|
1926
1804
|
const pluginTs = driver.getPlugin(pluginTsName);
|
|
1927
1805
|
if (!pluginTs) return null;
|
|
1928
1806
|
const tsResolver = driver.getResolver(pluginTsName);
|
|
1929
|
-
const { isQuery, isMutation } = classifyOperation(node, {
|
|
1930
|
-
query,
|
|
1931
|
-
mutation
|
|
1932
|
-
});
|
|
1933
|
-
if (!isQuery || isMutation) return null;
|
|
1934
1807
|
const importPath = query ? query.importPath : "@tanstack/react-query";
|
|
1935
1808
|
const contractOp = resolveClientOperation({
|
|
1936
1809
|
clientPlugin: { pluginName: client.pluginName },
|
|
1937
1810
|
driver,
|
|
1938
1811
|
node,
|
|
1939
1812
|
root,
|
|
1940
|
-
output
|
|
1813
|
+
output,
|
|
1814
|
+
cache: ctx.cache
|
|
1941
1815
|
});
|
|
1942
1816
|
if (!contractOp) return null;
|
|
1943
1817
|
const queryName = resolver.query.name(node);
|
|
@@ -1951,11 +1825,13 @@ const queryGenerator = defineGenerator({
|
|
|
1951
1825
|
output,
|
|
1952
1826
|
group: group ?? void 0
|
|
1953
1827
|
}),
|
|
1954
|
-
fileTs:
|
|
1955
|
-
|
|
1828
|
+
fileTs: resolveDependencyOperationFile({
|
|
1829
|
+
cache: ctx.cache,
|
|
1830
|
+
node,
|
|
1831
|
+
resolver: tsResolver,
|
|
1956
1832
|
root,
|
|
1957
1833
|
output: pluginTs.options?.output ?? output,
|
|
1958
|
-
group: pluginTs.options?.group
|
|
1834
|
+
group: pluginTs.options?.group
|
|
1959
1835
|
})
|
|
1960
1836
|
};
|
|
1961
1837
|
const importedTypeNames = [tsResolver.response.options(node), ...resolveOperationTypeNames(node, tsResolver, {
|
|
@@ -2056,38 +1932,44 @@ const queryGenerator = defineGenerator({
|
|
|
2056
1932
|
//#endregion
|
|
2057
1933
|
//#region src/generators/suspenseInfiniteQueryGenerator.tsx
|
|
2058
1934
|
/**
|
|
2059
|
-
* Built-in generator for `useSuspenseInfiniteQuery` hooks. Enabled when
|
|
2060
|
-
* `suspense` and `
|
|
2061
|
-
* cursor-based pagination. Handlers throw promises while
|
|
2062
|
-
* additional pages on demand.
|
|
1935
|
+
* Built-in generator for `useSuspenseInfiniteQuery` hooks. Enabled when
|
|
1936
|
+
* `suspense`, `infinite`, and `hooks` are all configured. Combines suspense
|
|
1937
|
+
* semantics with cursor-based pagination. Handlers throw promises while
|
|
1938
|
+
* loading and pull additional pages on demand.
|
|
2063
1939
|
*/
|
|
2064
1940
|
const suspenseInfiniteQueryGenerator = defineGenerator({
|
|
2065
1941
|
name: "react-suspense-infinite-query",
|
|
2066
1942
|
renderer: jsxRenderer,
|
|
1943
|
+
match(node, ctx) {
|
|
1944
|
+
const operationNode = node;
|
|
1945
|
+
if (!ast.isHttpOperationNode(operationNode)) return false;
|
|
1946
|
+
const { query, mutation, infinite, suspense, hooks } = ctx.options;
|
|
1947
|
+
const { isQuery, isMutation } = classifyOperation(operationNode, {
|
|
1948
|
+
query,
|
|
1949
|
+
mutation
|
|
1950
|
+
});
|
|
1951
|
+
const infiniteOptions = infinite && typeof infinite === "object" ? infinite : null;
|
|
1952
|
+
if (!isQuery || isMutation || !suspense || !infiniteOptions || !hooks) return false;
|
|
1953
|
+
const queryParamKeys = getOperationParameters(operationNode).query.map((p) => p.name);
|
|
1954
|
+
return infiniteOptions.queryParam ? queryParamKeys.includes(infiniteOptions.queryParam) || queryParamKeys.includes(`${infiniteOptions.queryParam}?`) : false;
|
|
1955
|
+
},
|
|
2067
1956
|
operation(node, ctx) {
|
|
2068
1957
|
if (!ast.isHttpOperationNode(node)) return null;
|
|
2069
1958
|
const { config, driver, resolver, root } = ctx;
|
|
2070
|
-
const { output, query,
|
|
1959
|
+
const { output, query, infinite, client, group, customOptions } = ctx.options;
|
|
2071
1960
|
const pluginTs = driver.getPlugin(pluginTsName);
|
|
2072
1961
|
if (!pluginTs) return null;
|
|
2073
1962
|
const tsResolver = driver.getResolver(pluginTsName);
|
|
2074
|
-
const { isQuery, isMutation } = classifyOperation(node, {
|
|
2075
|
-
query,
|
|
2076
|
-
mutation
|
|
2077
|
-
});
|
|
2078
|
-
const isSuspense = !!suspense;
|
|
2079
1963
|
const infiniteOptions = infinite && typeof infinite === "object" ? infinite : null;
|
|
2080
|
-
if (!
|
|
2081
|
-
const normalizeKey = (key) => key.replace(/\?$/, "");
|
|
2082
|
-
const queryParamKeys = getOperationParameters(node).query.map((p) => p.name);
|
|
2083
|
-
if (!(infiniteOptions.queryParam ? queryParamKeys.some((k) => normalizeKey(k) === infiniteOptions.queryParam) : false)) return null;
|
|
1964
|
+
if (!infiniteOptions) return null;
|
|
2084
1965
|
const importPath = query ? query.importPath : "@tanstack/react-query";
|
|
2085
1966
|
const contractOp = resolveClientOperation({
|
|
2086
1967
|
clientPlugin: { pluginName: client.pluginName },
|
|
2087
1968
|
driver,
|
|
2088
1969
|
node,
|
|
2089
1970
|
root,
|
|
2090
|
-
output
|
|
1971
|
+
output,
|
|
1972
|
+
cache: ctx.cache
|
|
2091
1973
|
});
|
|
2092
1974
|
if (!contractOp) return null;
|
|
2093
1975
|
const queryName = resolver.suspenseInfiniteQuery.name(node);
|
|
@@ -2101,11 +1983,13 @@ const suspenseInfiniteQueryGenerator = defineGenerator({
|
|
|
2101
1983
|
output,
|
|
2102
1984
|
group: group ?? void 0
|
|
2103
1985
|
}),
|
|
2104
|
-
fileTs:
|
|
2105
|
-
|
|
1986
|
+
fileTs: resolveDependencyOperationFile({
|
|
1987
|
+
cache: ctx.cache,
|
|
1988
|
+
node,
|
|
1989
|
+
resolver: tsResolver,
|
|
2106
1990
|
root,
|
|
2107
1991
|
output: pluginTs.options?.output ?? output,
|
|
2108
|
-
group: pluginTs.options?.group
|
|
1992
|
+
group: pluginTs.options?.group
|
|
2109
1993
|
})
|
|
2110
1994
|
};
|
|
2111
1995
|
const rawQueryParams = getOperationParameters(node).query;
|
|
@@ -2189,34 +2073,32 @@ const suspenseInfiniteQueryGenerator = defineGenerator({
|
|
|
2189
2073
|
initialPageParam: infiniteOptions.initialPageParam,
|
|
2190
2074
|
queryParam: infiniteOptions.queryParam
|
|
2191
2075
|
}),
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
})
|
|
2219
|
-
] })
|
|
2076
|
+
/* @__PURE__ */ jsx(File.Import, {
|
|
2077
|
+
name: ["useSuspenseInfiniteQuery"],
|
|
2078
|
+
path: importPath
|
|
2079
|
+
}),
|
|
2080
|
+
/* @__PURE__ */ jsx(File.Import, {
|
|
2081
|
+
name: [
|
|
2082
|
+
"QueryKey",
|
|
2083
|
+
"QueryClient",
|
|
2084
|
+
"UseSuspenseInfiniteQueryOptions",
|
|
2085
|
+
"UseSuspenseInfiniteQueryResult"
|
|
2086
|
+
],
|
|
2087
|
+
path: importPath,
|
|
2088
|
+
isTypeOnly: true
|
|
2089
|
+
}),
|
|
2090
|
+
/* @__PURE__ */ jsx(InfiniteQuery, {
|
|
2091
|
+
name: queryName,
|
|
2092
|
+
queryOptionsName,
|
|
2093
|
+
queryKeyName,
|
|
2094
|
+
queryKeyTypeName,
|
|
2095
|
+
node,
|
|
2096
|
+
tsResolver,
|
|
2097
|
+
initialPageParam: infiniteOptions.initialPageParam,
|
|
2098
|
+
queryParam: infiniteOptions.queryParam,
|
|
2099
|
+
customOptions,
|
|
2100
|
+
suspense: true
|
|
2101
|
+
})
|
|
2220
2102
|
]
|
|
2221
2103
|
});
|
|
2222
2104
|
}
|
|
@@ -2225,32 +2107,39 @@ const suspenseInfiniteQueryGenerator = defineGenerator({
|
|
|
2225
2107
|
//#region src/generators/suspenseQueryGenerator.tsx
|
|
2226
2108
|
/**
|
|
2227
2109
|
* Built-in generator for `useSuspenseQuery` hooks. Enabled when
|
|
2228
|
-
* `pluginReactQuery({ suspense: {} })`. Emits one
|
|
2229
|
-
* per query operation. Suspense queries throw
|
|
2230
|
-
* require a `<Suspense>` boundary in the React
|
|
2110
|
+
* `pluginReactQuery({ suspense: {}, hooks: true })`. Emits one
|
|
2111
|
+
* `useFooSuspenseQuery` hook per query operation. Suspense queries throw
|
|
2112
|
+
* promises while loading and require a `<Suspense>` boundary in the React
|
|
2113
|
+
* tree. TanStack Query v5+ only.
|
|
2231
2114
|
*/
|
|
2232
2115
|
const suspenseQueryGenerator = defineGenerator({
|
|
2233
2116
|
name: "react-suspense-query",
|
|
2234
2117
|
renderer: jsxRenderer,
|
|
2118
|
+
match(node, ctx) {
|
|
2119
|
+
const operationNode = node;
|
|
2120
|
+
if (!ast.isHttpOperationNode(operationNode)) return false;
|
|
2121
|
+
const { query, mutation, suspense, hooks } = ctx.options;
|
|
2122
|
+
const { isQuery, isMutation } = classifyOperation(operationNode, {
|
|
2123
|
+
query,
|
|
2124
|
+
mutation
|
|
2125
|
+
});
|
|
2126
|
+
return isQuery && !isMutation && !!suspense && hooks;
|
|
2127
|
+
},
|
|
2235
2128
|
operation(node, ctx) {
|
|
2236
2129
|
if (!ast.isHttpOperationNode(node)) return null;
|
|
2237
2130
|
const { config, driver, resolver, root } = ctx;
|
|
2238
|
-
const { output, query,
|
|
2131
|
+
const { output, query, client, group, customOptions } = ctx.options;
|
|
2239
2132
|
const pluginTs = driver.getPlugin(pluginTsName);
|
|
2240
2133
|
if (!pluginTs) return null;
|
|
2241
2134
|
const tsResolver = driver.getResolver(pluginTsName);
|
|
2242
|
-
const { isQuery, isMutation } = classifyOperation(node, {
|
|
2243
|
-
query,
|
|
2244
|
-
mutation
|
|
2245
|
-
});
|
|
2246
|
-
if (!isQuery || isMutation || !!!suspense) return null;
|
|
2247
2135
|
const importPath = query ? query.importPath : "@tanstack/react-query";
|
|
2248
2136
|
const contractOp = resolveClientOperation({
|
|
2249
2137
|
clientPlugin: { pluginName: client.pluginName },
|
|
2250
2138
|
driver,
|
|
2251
2139
|
node,
|
|
2252
2140
|
root,
|
|
2253
|
-
output
|
|
2141
|
+
output,
|
|
2142
|
+
cache: ctx.cache
|
|
2254
2143
|
});
|
|
2255
2144
|
if (!contractOp) return null;
|
|
2256
2145
|
const queryName = resolver.suspenseQuery.name(node);
|
|
@@ -2264,11 +2153,13 @@ const suspenseQueryGenerator = defineGenerator({
|
|
|
2264
2153
|
output,
|
|
2265
2154
|
group: group ?? void 0
|
|
2266
2155
|
}),
|
|
2267
|
-
fileTs:
|
|
2268
|
-
|
|
2156
|
+
fileTs: resolveDependencyOperationFile({
|
|
2157
|
+
cache: ctx.cache,
|
|
2158
|
+
node,
|
|
2159
|
+
resolver: tsResolver,
|
|
2269
2160
|
root,
|
|
2270
2161
|
output: pluginTs.options?.output ?? output,
|
|
2271
|
-
group: pluginTs.options?.group
|
|
2162
|
+
group: pluginTs.options?.group
|
|
2272
2163
|
})
|
|
2273
2164
|
};
|
|
2274
2165
|
const importedTypeNames = [tsResolver.response.options(node), ...resolveOperationTypeNames(node, tsResolver, {
|
|
@@ -2337,32 +2228,30 @@ const suspenseQueryGenerator = defineGenerator({
|
|
|
2337
2228
|
node,
|
|
2338
2229
|
tsResolver
|
|
2339
2230
|
}),
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
})
|
|
2365
|
-
] })
|
|
2231
|
+
/* @__PURE__ */ jsx(File.Import, {
|
|
2232
|
+
name: ["useSuspenseQuery"],
|
|
2233
|
+
path: importPath
|
|
2234
|
+
}),
|
|
2235
|
+
/* @__PURE__ */ jsx(File.Import, {
|
|
2236
|
+
name: [
|
|
2237
|
+
"QueryKey",
|
|
2238
|
+
"QueryClient",
|
|
2239
|
+
"UseSuspenseQueryOptions",
|
|
2240
|
+
"UseSuspenseQueryResult"
|
|
2241
|
+
],
|
|
2242
|
+
path: importPath,
|
|
2243
|
+
isTypeOnly: true
|
|
2244
|
+
}),
|
|
2245
|
+
/* @__PURE__ */ jsx(Query, {
|
|
2246
|
+
name: queryName,
|
|
2247
|
+
queryOptionsName,
|
|
2248
|
+
queryKeyName,
|
|
2249
|
+
queryKeyTypeName,
|
|
2250
|
+
node,
|
|
2251
|
+
tsResolver,
|
|
2252
|
+
customOptions,
|
|
2253
|
+
suspense: true
|
|
2254
|
+
})
|
|
2366
2255
|
]
|
|
2367
2256
|
});
|
|
2368
2257
|
}
|
|
@@ -2448,7 +2337,7 @@ const pluginReactQuery = definePlugin((options) => {
|
|
|
2448
2337
|
const { output = {
|
|
2449
2338
|
path: "hooks",
|
|
2450
2339
|
barrel: { type: "named" }
|
|
2451
|
-
}, group, exclude = [], include, override = [], suspense =
|
|
2340
|
+
}, group, exclude = [], include, override = [], suspense = false, infinite = false, mutation = {}, query = {}, mutationKey = mutationKeyTransformer, queryKey = queryKeyTransformer, customOptions, hooks = false, client, resolver: userResolver, macros: userMacros } = options;
|
|
2452
2341
|
const selectedGenerators = [
|
|
2453
2342
|
queryGenerator,
|
|
2454
2343
|
suspenseQueryGenerator,
|