@kubb/plugin-react-query 5.0.0-beta.99 → 5.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +356 -457
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +353 -454
- package/dist/index.js.map +1 -1
- package/package.json +16 -8
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.
|
|
@@ -800,6 +663,24 @@ function resolveOperationOverrides(node, override) {
|
|
|
800
663
|
return override.find((ov) => matchesPattern(node, ov))?.options ?? {};
|
|
801
664
|
}
|
|
802
665
|
/**
|
|
666
|
+
* The request groups a query key is built from, matching `buildQueryKeyParams`. Headers are
|
|
667
|
+
* deliberately absent: they do not identify a cache entry, so the key factory takes no parameter
|
|
668
|
+
* for an operation that only carries headers.
|
|
669
|
+
*/
|
|
670
|
+
const queryKeyGroupOrder = [
|
|
671
|
+
"path",
|
|
672
|
+
"query",
|
|
673
|
+
"body"
|
|
674
|
+
];
|
|
675
|
+
/**
|
|
676
|
+
* Whether the generated query key factory declares a parameter, so a call site passes an argument
|
|
677
|
+
* only when one is accepted.
|
|
678
|
+
*/
|
|
679
|
+
function hasQueryKeyParams(node) {
|
|
680
|
+
const groups = getRequestGroups(node);
|
|
681
|
+
return queryKeyGroupOrder.some((key) => groups[key]);
|
|
682
|
+
}
|
|
683
|
+
/**
|
|
803
684
|
* Build QueryKey params as the grouped `{ path, query, body }` object (NO headers, NO config),
|
|
804
685
|
* typed from the operation's `Options` minus `url`. The query key transformer reads the
|
|
805
686
|
* grouped `path`/`query`/`body` bindings.
|
|
@@ -808,11 +689,7 @@ function buildQueryKeyParams(node, options) {
|
|
|
808
689
|
const { resolver } = options;
|
|
809
690
|
const groupedParam = buildGroupedRequestParam(node, {
|
|
810
691
|
resolver,
|
|
811
|
-
keys:
|
|
812
|
-
"path",
|
|
813
|
-
"query",
|
|
814
|
-
"body"
|
|
815
|
-
]
|
|
692
|
+
keys: queryKeyGroupOrder
|
|
816
693
|
});
|
|
817
694
|
return createFunctionParameters({ params: groupedParam ? [groupedParam] : [] });
|
|
818
695
|
}
|
|
@@ -829,11 +706,7 @@ function InfiniteQueryOptions({ name, clientName, initialPageParam, cursorParam,
|
|
|
829
706
|
});
|
|
830
707
|
const groupedKeyParam = buildGroupedRequestParam(node, {
|
|
831
708
|
resolver: tsResolver,
|
|
832
|
-
keys:
|
|
833
|
-
"path",
|
|
834
|
-
"query",
|
|
835
|
-
"body"
|
|
836
|
-
],
|
|
709
|
+
keys: queryKeyGroupOrder,
|
|
837
710
|
memberTypeWrapper
|
|
838
711
|
});
|
|
839
712
|
const queryKeyParamsNode = createFunctionParameters({ params: groupedKeyParam ? [groupedKeyParam] : [] });
|
|
@@ -1131,19 +1004,6 @@ function buildResolvedRequestParams(node) {
|
|
|
1131
1004
|
if (names.length === 0) return null;
|
|
1132
1005
|
return `{ ${names.map((name) => `${name}: typeof ${name} === 'function' ? ${name}() : ${name}`).join(", ")} }`;
|
|
1133
1006
|
}
|
|
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
1007
|
//#endregion
|
|
1148
1008
|
//#region src/generators/hookOptionsGenerator.tsx
|
|
1149
1009
|
/**
|
|
@@ -1318,10 +1178,11 @@ function buildInfiniteQueryParamsNode(node, options) {
|
|
|
1318
1178
|
}`,
|
|
1319
1179
|
default: "{}"
|
|
1320
1180
|
});
|
|
1321
|
-
|
|
1181
|
+
const groupedParam = buildGroupedRequestParam(node, {
|
|
1322
1182
|
resolver,
|
|
1323
1183
|
memberTypeWrapper: maybeValueOrGetter
|
|
1324
|
-
})
|
|
1184
|
+
});
|
|
1185
|
+
return createFunctionParameters({ params: [groupedParam, optionsParam].filter((param) => param !== null) });
|
|
1325
1186
|
}
|
|
1326
1187
|
function InfiniteQuery({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, tsResolver, initialPageParam, queryParam, customOptions, suspense }) {
|
|
1327
1188
|
const { TData: responseType, TError: errorType } = buildResponseTypes(node, tsResolver);
|
|
@@ -1341,7 +1202,7 @@ function InfiniteQuery({ name, queryKeyTypeName, queryOptionsName, queryKeyName,
|
|
|
1341
1202
|
`TPageParam = ${pageParamType}`
|
|
1342
1203
|
];
|
|
1343
1204
|
const resolvedParams = buildResolvedRequestParams(node);
|
|
1344
|
-
const queryKeyArgs = resolvedParams ? "resolvedParams" : "";
|
|
1205
|
+
const queryKeyArgs = resolvedParams && hasQueryKeyParams(node) ? "resolvedParams" : "";
|
|
1345
1206
|
const queryOptionsArgs = resolvedParams ? "resolvedParams, config" : "config";
|
|
1346
1207
|
const paramsNode = buildInfiniteQueryParamsNode(node, {
|
|
1347
1208
|
resolver: tsResolver,
|
|
@@ -1434,15 +1295,16 @@ function resolveMutationRequestType(node, resolver) {
|
|
|
1434
1295
|
function buildMutationParamsNode(node, options) {
|
|
1435
1296
|
const { resolver } = options;
|
|
1436
1297
|
const { TData, TError } = buildResponseTypes(node, resolver);
|
|
1298
|
+
const generics = [
|
|
1299
|
+
TData,
|
|
1300
|
+
TError,
|
|
1301
|
+
resolveMutationRequestType(node, resolver),
|
|
1302
|
+
"TContext"
|
|
1303
|
+
].join(", ");
|
|
1437
1304
|
return createFunctionParameters({ params: [createFunctionParameter({
|
|
1438
1305
|
name: "options",
|
|
1439
1306
|
type: `{
|
|
1440
|
-
mutation?: UseMutationOptions<${
|
|
1441
|
-
TData,
|
|
1442
|
-
TError,
|
|
1443
|
-
resolveMutationRequestType(node, resolver),
|
|
1444
|
-
"TContext"
|
|
1445
|
-
].join(", ")}> & { client?: QueryClient },
|
|
1307
|
+
mutation?: UseMutationOptions<${generics}> & { client?: QueryClient },
|
|
1446
1308
|
client?: ${buildRequestConfigType(node)},
|
|
1447
1309
|
}`,
|
|
1448
1310
|
default: "{}"
|
|
@@ -1500,10 +1362,11 @@ function buildQueryParamsNode(node, options) {
|
|
|
1500
1362
|
}`,
|
|
1501
1363
|
default: "{}"
|
|
1502
1364
|
});
|
|
1503
|
-
|
|
1365
|
+
const groupedParam = buildGroupedRequestParam(node, {
|
|
1504
1366
|
resolver,
|
|
1505
1367
|
memberTypeWrapper: maybeValueOrGetter
|
|
1506
|
-
})
|
|
1368
|
+
});
|
|
1369
|
+
return createFunctionParameters({ params: [groupedParam, optionsParam].filter((param) => param !== null) });
|
|
1507
1370
|
}
|
|
1508
1371
|
function Query({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, tsResolver, customOptions, suspense }) {
|
|
1509
1372
|
const { TData, TError } = buildResponseTypes(node, tsResolver);
|
|
@@ -1528,7 +1391,7 @@ function Query({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, t
|
|
|
1528
1391
|
`TQueryKey extends QueryKey = ${queryKeyTypeName}`
|
|
1529
1392
|
];
|
|
1530
1393
|
const resolvedParams = buildResolvedRequestParams(node);
|
|
1531
|
-
const queryKeyArgs = resolvedParams ? "resolvedParams" : "";
|
|
1394
|
+
const queryKeyArgs = resolvedParams && hasQueryKeyParams(node) ? "resolvedParams" : "";
|
|
1532
1395
|
const queryOptionsArgs = resolvedParams ? "resolvedParams, config" : "config";
|
|
1533
1396
|
const paramsNode = buildQueryParamsNode(node, {
|
|
1534
1397
|
resolver: tsResolver,
|
|
@@ -1568,14 +1431,11 @@ function Query({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, t
|
|
|
1568
1431
|
//#region src/components/QueryOptions.tsx
|
|
1569
1432
|
const declarationPrinter = functionPrinter({ mode: "declaration" });
|
|
1570
1433
|
const callPrinter = functionPrinter({ mode: "call" });
|
|
1571
|
-
function getQueryOptionsParams(node, options) {
|
|
1572
|
-
return buildQueryOptionsParams(node, options);
|
|
1573
|
-
}
|
|
1574
1434
|
function QueryOptions({ name, clientName, node, tsResolver, queryKeyName }) {
|
|
1575
1435
|
const { TData, TError } = buildResponseTypes(node, tsResolver);
|
|
1576
1436
|
const queryKeyParamsNode = buildQueryKeyParams(node, { resolver: tsResolver });
|
|
1577
1437
|
const queryKeyParamsCall = callPrinter.print(queryKeyParamsNode) ?? "";
|
|
1578
|
-
const paramsNode =
|
|
1438
|
+
const paramsNode = buildQueryOptionsParams(node, { resolver: tsResolver });
|
|
1579
1439
|
const paramsSignature = declarationPrinter.print(paramsNode) ?? "";
|
|
1580
1440
|
const queryFnBody = `const { data } = await ${buildClientCall(node, {
|
|
1581
1441
|
clientName,
|
|
@@ -1606,36 +1466,44 @@ function QueryOptions({ name, clientName, node, tsResolver, queryKeyName }) {
|
|
|
1606
1466
|
//#region src/generators/infiniteQueryGenerator.tsx
|
|
1607
1467
|
/**
|
|
1608
1468
|
* 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
|
|
1469
|
+
* `pluginReactQuery({ infinite: { ... }, hooks: true })`. Emits one
|
|
1470
|
+
* `useFooInfiniteQuery` hook per query operation, wiring the configured
|
|
1471
|
+
* `nextParam` / `previousParam` paths into TanStack Query's cursor-based
|
|
1472
|
+
* pagination.
|
|
1612
1473
|
*/
|
|
1613
1474
|
const infiniteQueryGenerator = defineGenerator({
|
|
1614
1475
|
name: "react-infinite-query",
|
|
1615
1476
|
renderer: jsxRenderer,
|
|
1477
|
+
match(node, ctx) {
|
|
1478
|
+
const operationNode = node;
|
|
1479
|
+
if (!ast.isHttpOperationNode(operationNode)) return false;
|
|
1480
|
+
const { query, mutation, infinite, hooks } = ctx.options;
|
|
1481
|
+
const { isQuery, isMutation } = classifyOperation(operationNode, {
|
|
1482
|
+
query,
|
|
1483
|
+
mutation
|
|
1484
|
+
});
|
|
1485
|
+
const infiniteOptions = infinite && typeof infinite === "object" ? infinite : null;
|
|
1486
|
+
if (!isQuery || isMutation || !infiniteOptions || !hooks) return false;
|
|
1487
|
+
const queryParamKeys = getOperationParameters(operationNode).query.map((p) => p.name);
|
|
1488
|
+
return infiniteOptions.queryParam ? queryParamKeys.includes(infiniteOptions.queryParam) || queryParamKeys.includes(`${infiniteOptions.queryParam}?`) : false;
|
|
1489
|
+
},
|
|
1616
1490
|
operation(node, ctx) {
|
|
1617
1491
|
if (!ast.isHttpOperationNode(node)) return null;
|
|
1618
1492
|
const { config, driver, resolver, root } = ctx;
|
|
1619
|
-
const { output, query,
|
|
1493
|
+
const { output, query, infinite, client, group, customOptions } = ctx.options;
|
|
1620
1494
|
const pluginTs = driver.getPlugin(pluginTsName);
|
|
1621
1495
|
if (!pluginTs) return null;
|
|
1622
1496
|
const tsResolver = driver.getResolver(pluginTsName);
|
|
1623
|
-
const { isQuery, isMutation } = classifyOperation(node, {
|
|
1624
|
-
query,
|
|
1625
|
-
mutation
|
|
1626
|
-
});
|
|
1627
1497
|
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;
|
|
1498
|
+
if (!infiniteOptions) return null;
|
|
1632
1499
|
const importPath = query ? query.importPath : "@tanstack/react-query";
|
|
1633
1500
|
const contractOp = resolveClientOperation({
|
|
1634
1501
|
clientPlugin: { pluginName: client.pluginName },
|
|
1635
1502
|
driver,
|
|
1636
1503
|
node,
|
|
1637
1504
|
root,
|
|
1638
|
-
output
|
|
1505
|
+
output,
|
|
1506
|
+
cache: ctx.cache
|
|
1639
1507
|
});
|
|
1640
1508
|
if (!contractOp) return null;
|
|
1641
1509
|
const queryName = resolver.infiniteQuery.name(node);
|
|
@@ -1649,15 +1517,20 @@ const infiniteQueryGenerator = defineGenerator({
|
|
|
1649
1517
|
output,
|
|
1650
1518
|
group: group ?? void 0
|
|
1651
1519
|
}),
|
|
1652
|
-
fileTs:
|
|
1653
|
-
|
|
1520
|
+
fileTs: resolveDependencyOperationFile({
|
|
1521
|
+
cache: ctx.cache,
|
|
1522
|
+
node,
|
|
1523
|
+
resolver: tsResolver,
|
|
1654
1524
|
root,
|
|
1655
1525
|
output: pluginTs.options?.output ?? output,
|
|
1656
|
-
group: pluginTs.options?.group
|
|
1526
|
+
group: pluginTs.options?.group
|
|
1657
1527
|
})
|
|
1658
1528
|
};
|
|
1659
|
-
const
|
|
1660
|
-
|
|
1529
|
+
const { queryParamsTypeName } = resolvePageParamType(node, {
|
|
1530
|
+
resolver: tsResolver,
|
|
1531
|
+
initialPageParam: infiniteOptions.initialPageParam,
|
|
1532
|
+
queryParam: infiniteOptions.queryParam
|
|
1533
|
+
});
|
|
1661
1534
|
const importedTypeNames = [
|
|
1662
1535
|
tsResolver.response.options(node),
|
|
1663
1536
|
queryParamsTypeName,
|
|
@@ -1738,33 +1611,31 @@ const infiniteQueryGenerator = defineGenerator({
|
|
|
1738
1611
|
initialPageParam: infiniteOptions.initialPageParam,
|
|
1739
1612
|
queryParam: infiniteOptions.queryParam
|
|
1740
1613
|
}),
|
|
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
|
-
] })
|
|
1614
|
+
/* @__PURE__ */ jsx(File.Import, {
|
|
1615
|
+
name: ["useInfiniteQuery"],
|
|
1616
|
+
path: importPath
|
|
1617
|
+
}),
|
|
1618
|
+
/* @__PURE__ */ jsx(File.Import, {
|
|
1619
|
+
name: [
|
|
1620
|
+
"QueryKey",
|
|
1621
|
+
"QueryClient",
|
|
1622
|
+
"InfiniteQueryObserverOptions",
|
|
1623
|
+
"UseInfiniteQueryResult"
|
|
1624
|
+
],
|
|
1625
|
+
path: importPath,
|
|
1626
|
+
isTypeOnly: true
|
|
1627
|
+
}),
|
|
1628
|
+
/* @__PURE__ */ jsx(InfiniteQuery, {
|
|
1629
|
+
name: queryName,
|
|
1630
|
+
queryOptionsName,
|
|
1631
|
+
queryKeyName,
|
|
1632
|
+
queryKeyTypeName,
|
|
1633
|
+
node,
|
|
1634
|
+
tsResolver,
|
|
1635
|
+
initialPageParam: infiniteOptions.initialPageParam,
|
|
1636
|
+
queryParam: infiniteOptions.queryParam,
|
|
1637
|
+
customOptions
|
|
1638
|
+
})
|
|
1768
1639
|
]
|
|
1769
1640
|
});
|
|
1770
1641
|
}
|
|
@@ -1779,25 +1650,30 @@ const infiniteQueryGenerator = defineGenerator({
|
|
|
1779
1650
|
const mutationGenerator = defineGenerator({
|
|
1780
1651
|
name: "react-query-mutation",
|
|
1781
1652
|
renderer: jsxRenderer,
|
|
1653
|
+
match(node, ctx) {
|
|
1654
|
+
const operationNode = node;
|
|
1655
|
+
if (!ast.isHttpOperationNode(operationNode)) return false;
|
|
1656
|
+
const { query, mutation } = ctx.options;
|
|
1657
|
+
return classifyOperation(operationNode, {
|
|
1658
|
+
query,
|
|
1659
|
+
mutation
|
|
1660
|
+
}).isMutation;
|
|
1661
|
+
},
|
|
1782
1662
|
operation(node, ctx) {
|
|
1783
1663
|
if (!ast.isHttpOperationNode(node)) return null;
|
|
1784
1664
|
const { config, driver, resolver, root } = ctx;
|
|
1785
|
-
const { output,
|
|
1665
|
+
const { output, mutation, client, group, customOptions, hooks } = ctx.options;
|
|
1786
1666
|
const pluginTs = driver.getPlugin(pluginTsName);
|
|
1787
1667
|
if (!pluginTs) return null;
|
|
1788
1668
|
const tsResolver = driver.getResolver(pluginTsName);
|
|
1789
|
-
const { isMutation } = classifyOperation(node, {
|
|
1790
|
-
query,
|
|
1791
|
-
mutation
|
|
1792
|
-
});
|
|
1793
|
-
if (!isMutation) return null;
|
|
1794
1669
|
const importPath = mutation ? mutation.importPath : "@tanstack/react-query";
|
|
1795
1670
|
const contractOp = resolveClientOperation({
|
|
1796
1671
|
clientPlugin: { pluginName: client.pluginName },
|
|
1797
1672
|
driver,
|
|
1798
1673
|
node,
|
|
1799
1674
|
root,
|
|
1800
|
-
output
|
|
1675
|
+
output,
|
|
1676
|
+
cache: ctx.cache
|
|
1801
1677
|
});
|
|
1802
1678
|
if (!contractOp) return null;
|
|
1803
1679
|
const mutationHookName = resolver.mutation.name(node);
|
|
@@ -1811,11 +1687,13 @@ const mutationGenerator = defineGenerator({
|
|
|
1811
1687
|
output,
|
|
1812
1688
|
group: group ?? void 0
|
|
1813
1689
|
}),
|
|
1814
|
-
fileTs:
|
|
1815
|
-
|
|
1690
|
+
fileTs: resolveDependencyOperationFile({
|
|
1691
|
+
cache: ctx.cache,
|
|
1692
|
+
node,
|
|
1693
|
+
resolver: tsResolver,
|
|
1816
1694
|
root,
|
|
1817
1695
|
output: pluginTs.options?.output ?? output,
|
|
1818
|
-
group: pluginTs.options?.group
|
|
1696
|
+
group: pluginTs.options?.group
|
|
1819
1697
|
})
|
|
1820
1698
|
};
|
|
1821
1699
|
const importedTypeNames = [tsResolver.response.options(node), ...resolveOperationTypeNames(node, tsResolver, {
|
|
@@ -1919,25 +1797,31 @@ const mutationGenerator = defineGenerator({
|
|
|
1919
1797
|
const queryGenerator = defineGenerator({
|
|
1920
1798
|
name: "react-query",
|
|
1921
1799
|
renderer: jsxRenderer,
|
|
1800
|
+
match(node, ctx) {
|
|
1801
|
+
const operationNode = node;
|
|
1802
|
+
if (!ast.isHttpOperationNode(operationNode)) return false;
|
|
1803
|
+
const { query, mutation } = ctx.options;
|
|
1804
|
+
const { isQuery, isMutation } = classifyOperation(operationNode, {
|
|
1805
|
+
query,
|
|
1806
|
+
mutation
|
|
1807
|
+
});
|
|
1808
|
+
return isQuery && !isMutation;
|
|
1809
|
+
},
|
|
1922
1810
|
operation(node, ctx) {
|
|
1923
1811
|
if (!ast.isHttpOperationNode(node)) return null;
|
|
1924
1812
|
const { config, driver, resolver, root } = ctx;
|
|
1925
|
-
const { output, query,
|
|
1813
|
+
const { output, query, client, group, customOptions, hooks } = ctx.options;
|
|
1926
1814
|
const pluginTs = driver.getPlugin(pluginTsName);
|
|
1927
1815
|
if (!pluginTs) return null;
|
|
1928
1816
|
const tsResolver = driver.getResolver(pluginTsName);
|
|
1929
|
-
const { isQuery, isMutation } = classifyOperation(node, {
|
|
1930
|
-
query,
|
|
1931
|
-
mutation
|
|
1932
|
-
});
|
|
1933
|
-
if (!isQuery || isMutation) return null;
|
|
1934
1817
|
const importPath = query ? query.importPath : "@tanstack/react-query";
|
|
1935
1818
|
const contractOp = resolveClientOperation({
|
|
1936
1819
|
clientPlugin: { pluginName: client.pluginName },
|
|
1937
1820
|
driver,
|
|
1938
1821
|
node,
|
|
1939
1822
|
root,
|
|
1940
|
-
output
|
|
1823
|
+
output,
|
|
1824
|
+
cache: ctx.cache
|
|
1941
1825
|
});
|
|
1942
1826
|
if (!contractOp) return null;
|
|
1943
1827
|
const queryName = resolver.query.name(node);
|
|
@@ -1951,11 +1835,13 @@ const queryGenerator = defineGenerator({
|
|
|
1951
1835
|
output,
|
|
1952
1836
|
group: group ?? void 0
|
|
1953
1837
|
}),
|
|
1954
|
-
fileTs:
|
|
1955
|
-
|
|
1838
|
+
fileTs: resolveDependencyOperationFile({
|
|
1839
|
+
cache: ctx.cache,
|
|
1840
|
+
node,
|
|
1841
|
+
resolver: tsResolver,
|
|
1956
1842
|
root,
|
|
1957
1843
|
output: pluginTs.options?.output ?? output,
|
|
1958
|
-
group: pluginTs.options?.group
|
|
1844
|
+
group: pluginTs.options?.group
|
|
1959
1845
|
})
|
|
1960
1846
|
};
|
|
1961
1847
|
const importedTypeNames = [tsResolver.response.options(node), ...resolveOperationTypeNames(node, tsResolver, {
|
|
@@ -2056,38 +1942,44 @@ const queryGenerator = defineGenerator({
|
|
|
2056
1942
|
//#endregion
|
|
2057
1943
|
//#region src/generators/suspenseInfiniteQueryGenerator.tsx
|
|
2058
1944
|
/**
|
|
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.
|
|
1945
|
+
* Built-in generator for `useSuspenseInfiniteQuery` hooks. Enabled when
|
|
1946
|
+
* `suspense`, `infinite`, and `hooks` are all configured. Combines suspense
|
|
1947
|
+
* semantics with cursor-based pagination. Handlers throw promises while
|
|
1948
|
+
* loading and pull additional pages on demand.
|
|
2063
1949
|
*/
|
|
2064
1950
|
const suspenseInfiniteQueryGenerator = defineGenerator({
|
|
2065
1951
|
name: "react-suspense-infinite-query",
|
|
2066
1952
|
renderer: jsxRenderer,
|
|
1953
|
+
match(node, ctx) {
|
|
1954
|
+
const operationNode = node;
|
|
1955
|
+
if (!ast.isHttpOperationNode(operationNode)) return false;
|
|
1956
|
+
const { query, mutation, infinite, suspense, hooks } = ctx.options;
|
|
1957
|
+
const { isQuery, isMutation } = classifyOperation(operationNode, {
|
|
1958
|
+
query,
|
|
1959
|
+
mutation
|
|
1960
|
+
});
|
|
1961
|
+
const infiniteOptions = infinite && typeof infinite === "object" ? infinite : null;
|
|
1962
|
+
if (!isQuery || isMutation || !suspense || !infiniteOptions || !hooks) return false;
|
|
1963
|
+
const queryParamKeys = getOperationParameters(operationNode).query.map((p) => p.name);
|
|
1964
|
+
return infiniteOptions.queryParam ? queryParamKeys.includes(infiniteOptions.queryParam) || queryParamKeys.includes(`${infiniteOptions.queryParam}?`) : false;
|
|
1965
|
+
},
|
|
2067
1966
|
operation(node, ctx) {
|
|
2068
1967
|
if (!ast.isHttpOperationNode(node)) return null;
|
|
2069
1968
|
const { config, driver, resolver, root } = ctx;
|
|
2070
|
-
const { output, query,
|
|
1969
|
+
const { output, query, infinite, client, group, customOptions } = ctx.options;
|
|
2071
1970
|
const pluginTs = driver.getPlugin(pluginTsName);
|
|
2072
1971
|
if (!pluginTs) return null;
|
|
2073
1972
|
const tsResolver = driver.getResolver(pluginTsName);
|
|
2074
|
-
const { isQuery, isMutation } = classifyOperation(node, {
|
|
2075
|
-
query,
|
|
2076
|
-
mutation
|
|
2077
|
-
});
|
|
2078
|
-
const isSuspense = !!suspense;
|
|
2079
1973
|
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;
|
|
1974
|
+
if (!infiniteOptions) return null;
|
|
2084
1975
|
const importPath = query ? query.importPath : "@tanstack/react-query";
|
|
2085
1976
|
const contractOp = resolveClientOperation({
|
|
2086
1977
|
clientPlugin: { pluginName: client.pluginName },
|
|
2087
1978
|
driver,
|
|
2088
1979
|
node,
|
|
2089
1980
|
root,
|
|
2090
|
-
output
|
|
1981
|
+
output,
|
|
1982
|
+
cache: ctx.cache
|
|
2091
1983
|
});
|
|
2092
1984
|
if (!contractOp) return null;
|
|
2093
1985
|
const queryName = resolver.suspenseInfiniteQuery.name(node);
|
|
@@ -2101,11 +1993,13 @@ const suspenseInfiniteQueryGenerator = defineGenerator({
|
|
|
2101
1993
|
output,
|
|
2102
1994
|
group: group ?? void 0
|
|
2103
1995
|
}),
|
|
2104
|
-
fileTs:
|
|
2105
|
-
|
|
1996
|
+
fileTs: resolveDependencyOperationFile({
|
|
1997
|
+
cache: ctx.cache,
|
|
1998
|
+
node,
|
|
1999
|
+
resolver: tsResolver,
|
|
2106
2000
|
root,
|
|
2107
2001
|
output: pluginTs.options?.output ?? output,
|
|
2108
|
-
group: pluginTs.options?.group
|
|
2002
|
+
group: pluginTs.options?.group
|
|
2109
2003
|
})
|
|
2110
2004
|
};
|
|
2111
2005
|
const rawQueryParams = getOperationParameters(node).query;
|
|
@@ -2189,34 +2083,32 @@ const suspenseInfiniteQueryGenerator = defineGenerator({
|
|
|
2189
2083
|
initialPageParam: infiniteOptions.initialPageParam,
|
|
2190
2084
|
queryParam: infiniteOptions.queryParam
|
|
2191
2085
|
}),
|
|
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
|
-
] })
|
|
2086
|
+
/* @__PURE__ */ jsx(File.Import, {
|
|
2087
|
+
name: ["useSuspenseInfiniteQuery"],
|
|
2088
|
+
path: importPath
|
|
2089
|
+
}),
|
|
2090
|
+
/* @__PURE__ */ jsx(File.Import, {
|
|
2091
|
+
name: [
|
|
2092
|
+
"QueryKey",
|
|
2093
|
+
"QueryClient",
|
|
2094
|
+
"UseSuspenseInfiniteQueryOptions",
|
|
2095
|
+
"UseSuspenseInfiniteQueryResult"
|
|
2096
|
+
],
|
|
2097
|
+
path: importPath,
|
|
2098
|
+
isTypeOnly: true
|
|
2099
|
+
}),
|
|
2100
|
+
/* @__PURE__ */ jsx(InfiniteQuery, {
|
|
2101
|
+
name: queryName,
|
|
2102
|
+
queryOptionsName,
|
|
2103
|
+
queryKeyName,
|
|
2104
|
+
queryKeyTypeName,
|
|
2105
|
+
node,
|
|
2106
|
+
tsResolver,
|
|
2107
|
+
initialPageParam: infiniteOptions.initialPageParam,
|
|
2108
|
+
queryParam: infiniteOptions.queryParam,
|
|
2109
|
+
customOptions,
|
|
2110
|
+
suspense: true
|
|
2111
|
+
})
|
|
2220
2112
|
]
|
|
2221
2113
|
});
|
|
2222
2114
|
}
|
|
@@ -2225,32 +2117,39 @@ const suspenseInfiniteQueryGenerator = defineGenerator({
|
|
|
2225
2117
|
//#region src/generators/suspenseQueryGenerator.tsx
|
|
2226
2118
|
/**
|
|
2227
2119
|
* 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
|
|
2120
|
+
* `pluginReactQuery({ suspense: {}, hooks: true })`. Emits one
|
|
2121
|
+
* `useFooSuspenseQuery` hook per query operation. Suspense queries throw
|
|
2122
|
+
* promises while loading and require a `<Suspense>` boundary in the React
|
|
2123
|
+
* tree. TanStack Query v5+ only.
|
|
2231
2124
|
*/
|
|
2232
2125
|
const suspenseQueryGenerator = defineGenerator({
|
|
2233
2126
|
name: "react-suspense-query",
|
|
2234
2127
|
renderer: jsxRenderer,
|
|
2128
|
+
match(node, ctx) {
|
|
2129
|
+
const operationNode = node;
|
|
2130
|
+
if (!ast.isHttpOperationNode(operationNode)) return false;
|
|
2131
|
+
const { query, mutation, suspense, hooks } = ctx.options;
|
|
2132
|
+
const { isQuery, isMutation } = classifyOperation(operationNode, {
|
|
2133
|
+
query,
|
|
2134
|
+
mutation
|
|
2135
|
+
});
|
|
2136
|
+
return isQuery && !isMutation && !!suspense && hooks;
|
|
2137
|
+
},
|
|
2235
2138
|
operation(node, ctx) {
|
|
2236
2139
|
if (!ast.isHttpOperationNode(node)) return null;
|
|
2237
2140
|
const { config, driver, resolver, root } = ctx;
|
|
2238
|
-
const { output, query,
|
|
2141
|
+
const { output, query, client, group, customOptions } = ctx.options;
|
|
2239
2142
|
const pluginTs = driver.getPlugin(pluginTsName);
|
|
2240
2143
|
if (!pluginTs) return null;
|
|
2241
2144
|
const tsResolver = driver.getResolver(pluginTsName);
|
|
2242
|
-
const { isQuery, isMutation } = classifyOperation(node, {
|
|
2243
|
-
query,
|
|
2244
|
-
mutation
|
|
2245
|
-
});
|
|
2246
|
-
if (!isQuery || isMutation || !!!suspense) return null;
|
|
2247
2145
|
const importPath = query ? query.importPath : "@tanstack/react-query";
|
|
2248
2146
|
const contractOp = resolveClientOperation({
|
|
2249
2147
|
clientPlugin: { pluginName: client.pluginName },
|
|
2250
2148
|
driver,
|
|
2251
2149
|
node,
|
|
2252
2150
|
root,
|
|
2253
|
-
output
|
|
2151
|
+
output,
|
|
2152
|
+
cache: ctx.cache
|
|
2254
2153
|
});
|
|
2255
2154
|
if (!contractOp) return null;
|
|
2256
2155
|
const queryName = resolver.suspenseQuery.name(node);
|
|
@@ -2264,11 +2163,13 @@ const suspenseQueryGenerator = defineGenerator({
|
|
|
2264
2163
|
output,
|
|
2265
2164
|
group: group ?? void 0
|
|
2266
2165
|
}),
|
|
2267
|
-
fileTs:
|
|
2268
|
-
|
|
2166
|
+
fileTs: resolveDependencyOperationFile({
|
|
2167
|
+
cache: ctx.cache,
|
|
2168
|
+
node,
|
|
2169
|
+
resolver: tsResolver,
|
|
2269
2170
|
root,
|
|
2270
2171
|
output: pluginTs.options?.output ?? output,
|
|
2271
|
-
group: pluginTs.options?.group
|
|
2172
|
+
group: pluginTs.options?.group
|
|
2272
2173
|
})
|
|
2273
2174
|
};
|
|
2274
2175
|
const importedTypeNames = [tsResolver.response.options(node), ...resolveOperationTypeNames(node, tsResolver, {
|
|
@@ -2337,32 +2238,30 @@ const suspenseQueryGenerator = defineGenerator({
|
|
|
2337
2238
|
node,
|
|
2338
2239
|
tsResolver
|
|
2339
2240
|
}),
|
|
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
|
-
] })
|
|
2241
|
+
/* @__PURE__ */ jsx(File.Import, {
|
|
2242
|
+
name: ["useSuspenseQuery"],
|
|
2243
|
+
path: importPath
|
|
2244
|
+
}),
|
|
2245
|
+
/* @__PURE__ */ jsx(File.Import, {
|
|
2246
|
+
name: [
|
|
2247
|
+
"QueryKey",
|
|
2248
|
+
"QueryClient",
|
|
2249
|
+
"UseSuspenseQueryOptions",
|
|
2250
|
+
"UseSuspenseQueryResult"
|
|
2251
|
+
],
|
|
2252
|
+
path: importPath,
|
|
2253
|
+
isTypeOnly: true
|
|
2254
|
+
}),
|
|
2255
|
+
/* @__PURE__ */ jsx(Query, {
|
|
2256
|
+
name: queryName,
|
|
2257
|
+
queryOptionsName,
|
|
2258
|
+
queryKeyName,
|
|
2259
|
+
queryKeyTypeName,
|
|
2260
|
+
node,
|
|
2261
|
+
tsResolver,
|
|
2262
|
+
customOptions,
|
|
2263
|
+
suspense: true
|
|
2264
|
+
})
|
|
2366
2265
|
]
|
|
2367
2266
|
});
|
|
2368
2267
|
}
|
|
@@ -2448,7 +2347,7 @@ const pluginReactQuery = definePlugin((options) => {
|
|
|
2448
2347
|
const { output = {
|
|
2449
2348
|
path: "hooks",
|
|
2450
2349
|
barrel: { type: "named" }
|
|
2451
|
-
}, group, exclude = [], include, override = [], suspense =
|
|
2350
|
+
}, group, exclude = [], include, override = [], suspense = false, infinite = false, mutation = {}, query = {}, mutationKey = mutationKeyTransformer, queryKey = queryKeyTransformer, customOptions, hooks = false, client, resolver: userResolver, macros: userMacros } = options;
|
|
2452
2351
|
const selectedGenerators = [
|
|
2453
2352
|
queryGenerator,
|
|
2454
2353
|
suspenseQueryGenerator,
|