@kubb/plugin-react-query 5.0.0-beta.98 → 5.0.0
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 +351 -524
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +348 -521
- package/dist/index.js.map +1 -1
- package/package.json +4 -7
package/dist/index.js
CHANGED
|
@@ -1,328 +1,24 @@
|
|
|
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
|
-
function transformParam(raw, casing) {
|
|
183
|
-
const param = isValidVarName(raw) ? raw : camelCase(raw);
|
|
184
|
-
return casing === "camelcase" ? camelCase(param) : param;
|
|
185
|
-
}
|
|
186
|
-
function toParamsObject(path, { replacer, casing } = {}) {
|
|
187
|
-
const params = {};
|
|
188
|
-
for (const match of path.matchAll(/\{([^}]+)\}/g)) {
|
|
189
|
-
const param = transformParam(match[1], casing);
|
|
190
|
-
const key = replacer ? replacer(param) : param;
|
|
191
|
-
params[key] = key;
|
|
192
|
-
}
|
|
193
|
-
return Object.keys(params).length > 0 ? params : null;
|
|
194
|
-
}
|
|
195
|
-
/**
|
|
196
|
-
* Helpers for OpenAPI/Swagger paths, plus a thin wrapper over the native `URL`.
|
|
197
|
-
*/
|
|
198
|
-
var Url = class Url {
|
|
199
|
-
/**
|
|
200
|
-
* Reports whether `url` is a parseable absolute URL. Delegates to the native `URL.canParse`.
|
|
201
|
-
*
|
|
202
|
-
* @example
|
|
203
|
-
* Url.canParse('https://petstore.swagger.io/v2') // true
|
|
204
|
-
* Url.canParse('/pet/{petId}') // false
|
|
205
|
-
*/
|
|
206
|
-
static canParse(url, base) {
|
|
207
|
-
return URL.canParse(url, base);
|
|
208
|
-
}
|
|
209
|
-
/**
|
|
210
|
-
* Converts an OpenAPI/Swagger path to Express-style colon syntax.
|
|
211
|
-
*
|
|
212
|
-
* @example
|
|
213
|
-
* Url.toPath('/pet/{petId}') // '/pet/:petId'
|
|
214
|
-
*/
|
|
215
|
-
static toPath(path) {
|
|
216
|
-
return path.replace(/\{([^}]+)\}/g, ":$1");
|
|
217
|
-
}
|
|
218
|
-
/**
|
|
219
|
-
* Rewrites OpenAPI placeholder names while keeping the `{...}` braces, so the generated `url`
|
|
220
|
-
* literal aligns with the grouped `path` request option that the runtime client interpolates by
|
|
221
|
-
* key.
|
|
222
|
-
*
|
|
223
|
-
* @example
|
|
224
|
-
* Url.toCasedTemplate('/projects/{project_id}', { casing: 'camelcase' }) // '/projects/{projectId}'
|
|
225
|
-
*/
|
|
226
|
-
static toCasedTemplate(path, { casing } = {}) {
|
|
227
|
-
return path.replace(/\{([^}]+)\}/g, (_, name) => `{${transformParam(name, casing)}}`);
|
|
228
|
-
}
|
|
229
|
-
/**
|
|
230
|
-
* Converts an OpenAPI/Swagger path to a TypeScript template literal string.
|
|
231
|
-
* `prefix` is prepended inside the literal, `replacer` transforms each parameter name,
|
|
232
|
-
* and `casing` controls parameter identifier casing.
|
|
233
|
-
*
|
|
234
|
-
* @example
|
|
235
|
-
* Url.toTemplateString('/pet/{petId}') // '`/pet/${petId}`'
|
|
236
|
-
*
|
|
237
|
-
* @example
|
|
238
|
-
* Url.toTemplateString('/pet/{petId}', { prefix: 'https://api' }) // '`https://api/pet/${petId}`'
|
|
239
|
-
*/
|
|
240
|
-
static toTemplateString(path, { prefix, replacer, casing } = {}) {
|
|
241
|
-
const result = path.split(/\{([^}]+)\}/).map((part, i) => {
|
|
242
|
-
if (i % 2 === 0) return part;
|
|
243
|
-
const param = transformParam(part, casing);
|
|
244
|
-
return `\${${replacer ? replacer(param) : param}}`;
|
|
245
|
-
}).join("");
|
|
246
|
-
return `\`${prefix ?? ""}${result}\``;
|
|
247
|
-
}
|
|
248
|
-
/**
|
|
249
|
-
* Converts an OpenAPI/Swagger path to a template literal that reads each parameter off the
|
|
250
|
-
* grouped `path` request option, e.g. `/pet/{petId}` becomes `` `/pet/${path.petId}` ``. Parameter
|
|
251
|
-
* names are camelCased to match the generated `path` type, and `prefix` is prepended inside the
|
|
252
|
-
* literal. Shared by the client and cypress generators that pass a grouped `path` object.
|
|
253
|
-
*
|
|
254
|
-
* @example
|
|
255
|
-
* Url.toGroupedTemplateString('/pet/{petId}') // '`/pet/${path.petId}`'
|
|
256
|
-
*/
|
|
257
|
-
static toGroupedTemplateString(path, { prefix } = {}) {
|
|
258
|
-
return Url.toTemplateString(path, {
|
|
259
|
-
prefix,
|
|
260
|
-
casing: "camelcase",
|
|
261
|
-
replacer: (name) => `path.${name}`
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
/**
|
|
265
|
-
* Returns the path and its extracted params as a structured `URLObject`, or as a stringified
|
|
266
|
-
* expression when `stringify` is set.
|
|
267
|
-
*
|
|
268
|
-
* @example
|
|
269
|
-
* Url.toObject('/pet/{petId}')
|
|
270
|
-
* // { url: '/pet/:petId', params: { petId: 'petId' } }
|
|
271
|
-
*/
|
|
272
|
-
static toObject(path, { type = "path", replacer, stringify, casing } = {}) {
|
|
273
|
-
const object = {
|
|
274
|
-
url: type === "path" ? Url.toPath(path) : Url.toTemplateString(path, {
|
|
275
|
-
replacer,
|
|
276
|
-
casing
|
|
277
|
-
}),
|
|
278
|
-
params: toParamsObject(path, {
|
|
279
|
-
replacer,
|
|
280
|
-
casing
|
|
281
|
-
})
|
|
282
|
-
};
|
|
283
|
-
if (stringify) {
|
|
284
|
-
if (type === "template") return JSON.stringify(object).replaceAll("'", "").replaceAll(`"`, "");
|
|
285
|
-
if (object.params) return `{ url: '${object.url}', params: ${JSON.stringify(object.params).replaceAll("'", "").replaceAll(`"`, "")} }`;
|
|
286
|
-
return `{ url: '${object.url}' }`;
|
|
287
|
-
}
|
|
288
|
-
return object;
|
|
289
|
-
}
|
|
290
|
-
};
|
|
291
|
-
//#endregion
|
|
292
8
|
//#region ../../internals/shared/src/params.ts
|
|
293
|
-
const caseParamsCache = /* @__PURE__ */ new WeakMap();
|
|
294
9
|
/**
|
|
295
|
-
*
|
|
10
|
+
* Drops parameters that share the same name, keeping the first.
|
|
296
11
|
*
|
|
297
|
-
*
|
|
298
|
-
*
|
|
299
|
-
*
|
|
12
|
+
* A malformed spec can declare the same parameter name twice within one `in` location. Both would
|
|
13
|
+
* resolve to the same output property, so emitting both would yield an object type with a duplicate
|
|
14
|
+
* member, which TypeScript rejects. This is a defensive guard against that case, not a casing guard:
|
|
15
|
+
* parameter names flow through unchanged, so no two distinct names ever collide here anymore.
|
|
300
16
|
*/
|
|
301
|
-
function
|
|
302
|
-
if (!casing) return params;
|
|
303
|
-
const cached = caseParamsCache.get(params);
|
|
304
|
-
if (cached) return cached;
|
|
305
|
-
const result = params.map((param) => ({
|
|
306
|
-
...param,
|
|
307
|
-
name: camelCase(param.name)
|
|
308
|
-
}));
|
|
309
|
-
caseParamsCache.set(params, result);
|
|
310
|
-
return result;
|
|
311
|
-
}
|
|
312
|
-
/**
|
|
313
|
-
* Drops parameters that collapse to the same property identity once camelCased, keeping the first.
|
|
314
|
-
*
|
|
315
|
-
* Some specs declare the same parameter twice under different casings (for example AWS S3 lists both
|
|
316
|
-
* `max-uploads` and `MaxUploads`). Both resolve to one output property, so emitting both would yield
|
|
317
|
-
* an object type with a duplicate member, which TypeScript rejects. De-duplicate by the camelCased
|
|
318
|
-
* identity so the resulting group is collision-free regardless of the names each caller carries.
|
|
319
|
-
*/
|
|
320
|
-
function dedupeByCasedName(params) {
|
|
17
|
+
function dedupeParams(params) {
|
|
321
18
|
const seen = /* @__PURE__ */ new Set();
|
|
322
19
|
return params.filter((param) => {
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
seen.add(key);
|
|
20
|
+
if (seen.has(param.name)) return false;
|
|
21
|
+
seen.add(param.name);
|
|
326
22
|
return true;
|
|
327
23
|
});
|
|
328
24
|
}
|
|
@@ -347,11 +43,30 @@ function operationFileEntry(node, name, extname = ".ts") {
|
|
|
347
43
|
path: node.path
|
|
348
44
|
};
|
|
349
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
|
+
}
|
|
350
66
|
function getOperationLink(node, link) {
|
|
351
67
|
if (!link) return null;
|
|
352
68
|
if (typeof link === "function") return link(node) ?? null;
|
|
353
|
-
|
|
354
|
-
return node.path ? `{@link ${node.path.replaceAll("{", ":").replaceAll("}", "")}}` : null;
|
|
69
|
+
return node.path ? `{@link ${Url.toPath(node.path)}}` : null;
|
|
355
70
|
}
|
|
356
71
|
/**
|
|
357
72
|
* Derives the shared `ContentTypeInfo` shape from a list of content types, tracking whether several
|
|
@@ -441,14 +156,24 @@ function buildOperationComments(node, options = {}) {
|
|
|
441
156
|
if (!splitLines) return filteredComments;
|
|
442
157
|
return filteredComments.flatMap((text) => text.split(/\r?\n/).map((line) => line.trim())).filter((comment) => Boolean(comment));
|
|
443
158
|
}
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
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
|
+
*/
|
|
166
|
+
function getOperationParameters(node) {
|
|
167
|
+
const cached = operationParameterGroupsByNode.get(node);
|
|
168
|
+
if (cached) return cached;
|
|
169
|
+
const groups = {
|
|
170
|
+
path: dedupeParams(node.parameters.filter((param) => param.in === "path")),
|
|
171
|
+
query: dedupeParams(node.parameters.filter((param) => param.in === "query")),
|
|
172
|
+
header: dedupeParams(node.parameters.filter((param) => param.in === "header")),
|
|
173
|
+
cookie: dedupeParams(node.parameters.filter((param) => param.in === "cookie"))
|
|
451
174
|
};
|
|
175
|
+
operationParameterGroupsByNode.set(node, groups);
|
|
176
|
+
return groups;
|
|
452
177
|
}
|
|
453
178
|
function getStatusCodeNumber(statusCode) {
|
|
454
179
|
const code = Number(statusCode);
|
|
@@ -482,7 +207,7 @@ function resolveStatusCodeNames(node, resolver) {
|
|
|
482
207
|
}
|
|
483
208
|
const typeNamesByResolver = /* @__PURE__ */ new WeakMap();
|
|
484
209
|
function resolveOperationTypeNames(node, resolver, options = {}) {
|
|
485
|
-
const cacheKey = `${node.operationId}\0${options.
|
|
210
|
+
const cacheKey = `${node.operationId}\0${options.order ?? ""}\0${options.responseStatusNames ?? ""}\0${options.includeParams === false ? "noparams" : ""}\0${(options.exclude ?? []).join(",")}`;
|
|
486
211
|
let byResolver = typeNamesByResolver.get(resolver);
|
|
487
212
|
if (byResolver) {
|
|
488
213
|
const cached = byResolver.get(cacheKey);
|
|
@@ -491,7 +216,7 @@ function resolveOperationTypeNames(node, resolver, options = {}) {
|
|
|
491
216
|
byResolver = /* @__PURE__ */ new Map();
|
|
492
217
|
typeNamesByResolver.set(resolver, byResolver);
|
|
493
218
|
}
|
|
494
|
-
const { path, query, header } = getOperationParameters(node
|
|
219
|
+
const { path, query, header } = getOperationParameters(node);
|
|
495
220
|
const responseStatusNames = options.responseStatusNames === "error" ? resolveErrorNames(node, resolver) : options.responseStatusNames === false ? [] : resolveStatusCodeNames(node, resolver);
|
|
496
221
|
const exclude = new Set(options.exclude ?? []);
|
|
497
222
|
const paramNames = options.includeParams === false ? [] : [
|
|
@@ -513,6 +238,60 @@ function resolveOperationTypeNames(node, resolver, options = {}) {
|
|
|
513
238
|
return result;
|
|
514
239
|
}
|
|
515
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
|
|
516
295
|
//#region ../../internals/shared/src/group.ts
|
|
517
296
|
/**
|
|
518
297
|
* Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the
|
|
@@ -632,23 +411,30 @@ function resolveContractClient(options) {
|
|
|
632
411
|
* (plugin-fetch or plugin-axios). Returns `null` when no contract plugin is in play (the inline
|
|
633
412
|
* path). The plugin injects `.kubb/client.ts` at the global output root, the same path consumers
|
|
634
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.
|
|
635
419
|
*/
|
|
636
420
|
function resolveClientOperation(options) {
|
|
637
|
-
const { clientPlugin, driver, node, root, output } = options;
|
|
421
|
+
const { clientPlugin, driver, node, root, output, cache } = options;
|
|
638
422
|
if (!clientPlugin) return null;
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
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
|
+
};
|
|
646
437
|
});
|
|
647
|
-
return {
|
|
648
|
-
name: resolver.name(node.operationId),
|
|
649
|
-
path: file.path,
|
|
650
|
-
clientPath: path.resolve(root, ".kubb/client.ts")
|
|
651
|
-
};
|
|
652
438
|
}
|
|
653
439
|
//#endregion
|
|
654
440
|
//#region ../../internals/tanstack-query/src/utils.ts
|
|
@@ -719,14 +505,16 @@ function buildGroupedRequestParam(node, options) {
|
|
|
719
505
|
*/
|
|
720
506
|
function buildQueryOptionsParams(node, options) {
|
|
721
507
|
const { resolver, memberTypeWrapper } = options;
|
|
722
|
-
|
|
508
|
+
const groupedParam = buildGroupedRequestParam(node, {
|
|
723
509
|
resolver,
|
|
724
510
|
memberTypeWrapper
|
|
725
|
-
})
|
|
511
|
+
});
|
|
512
|
+
const configParam = createFunctionParameter({
|
|
726
513
|
name: "config",
|
|
727
514
|
type: `Partial<Omit<RequestConfig, 'path' | 'query' | 'body' | 'headers' | 'url'>>`,
|
|
728
515
|
default: "{}"
|
|
729
|
-
})
|
|
516
|
+
});
|
|
517
|
+
return createFunctionParameters({ params: [groupedParam, configParam].filter((param) => param !== null) });
|
|
730
518
|
}
|
|
731
519
|
/**
|
|
732
520
|
* Builds the call to a client `<op>` function inside a query/mutation hook body. The function takes
|
|
@@ -780,7 +568,7 @@ function resolveFallbackPageParamType(initialPageParam) {
|
|
|
780
568
|
* so callers can reuse it when rewriting the paginated request.
|
|
781
569
|
*/
|
|
782
570
|
function resolvePageParamType(node, { resolver, initialPageParam, queryParam }) {
|
|
783
|
-
const firstQueryParam = getOperationParameters(node
|
|
571
|
+
const firstQueryParam = getOperationParameters(node).query[0];
|
|
784
572
|
const groupName = firstQueryParam ? resolver.param.query(node, firstQueryParam) : null;
|
|
785
573
|
const queryParamsTypeName = groupName !== (firstQueryParam ? resolver.param.name(node, firstQueryParam) : null) ? groupName : null;
|
|
786
574
|
const queryParamType = queryParam && queryParamsTypeName ? `${queryParamsTypeName}['${queryParam}']` : null;
|
|
@@ -824,6 +612,19 @@ function resolveMutationConfig(mutation, options) {
|
|
|
824
612
|
};
|
|
825
613
|
}
|
|
826
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
|
+
/**
|
|
827
628
|
* Applies the shared infinite-query defaults during plugin setup: a falsy value disables infinite
|
|
828
629
|
* queries, and an object merges over `queryParam: 'id'` and `initialPageParam: 0` with the cursor
|
|
829
630
|
* paths cleared.
|
|
@@ -1193,19 +994,6 @@ function buildResolvedRequestParams(node) {
|
|
|
1193
994
|
if (names.length === 0) return null;
|
|
1194
995
|
return `{ ${names.map((name) => `${name}: typeof ${name} === 'function' ? ${name}() : ${name}`).join(", ")} }`;
|
|
1195
996
|
}
|
|
1196
|
-
/**
|
|
1197
|
-
* Classifies an operation as a query or a mutation from the resolved `query` / `mutation` method lists.
|
|
1198
|
-
* `query: false` still marks the operation as a query so the query-family generators keep matching it,
|
|
1199
|
-
* and a method already claimed by `query` never counts as a mutation.
|
|
1200
|
-
*/
|
|
1201
|
-
function classifyOperation(node, { query, mutation }) {
|
|
1202
|
-
const isQuery = query === false || !!query && query.methods.some((method) => node.method.toLowerCase() === method.toLowerCase());
|
|
1203
|
-
const queryMethods = new Set(query ? query.methods : []);
|
|
1204
|
-
return {
|
|
1205
|
-
isQuery,
|
|
1206
|
-
isMutation: mutation !== false && !isQuery && (mutation ? mutation.methods : []).some((method) => !queryMethods.has(method) && node.method.toLowerCase() === method.toLowerCase())
|
|
1207
|
-
};
|
|
1208
|
-
}
|
|
1209
997
|
//#endregion
|
|
1210
998
|
//#region src/generators/hookOptionsGenerator.tsx
|
|
1211
999
|
/**
|
|
@@ -1281,7 +1069,7 @@ const hookOptionsGenerator = defineGenerator({
|
|
|
1281
1069
|
}
|
|
1282
1070
|
if (isInfiniteOp) {
|
|
1283
1071
|
const normalizeKey = (key) => key.replace(/\?$/, "");
|
|
1284
|
-
const queryParamKeys = getOperationParameters(node
|
|
1072
|
+
const queryParamKeys = getOperationParameters(node).query.map((p) => p.name);
|
|
1285
1073
|
if (nodeInfiniteOptions.queryParam ? queryParamKeys.some((k) => normalizeKey(k) === nodeInfiniteOptions.queryParam) : false) {
|
|
1286
1074
|
const infiniteOptionsName = resolver.infiniteQuery.optionsName(node);
|
|
1287
1075
|
const infiniteHookName = resolver.infiniteQuery.name(node);
|
|
@@ -1380,10 +1168,11 @@ function buildInfiniteQueryParamsNode(node, options) {
|
|
|
1380
1168
|
}`,
|
|
1381
1169
|
default: "{}"
|
|
1382
1170
|
});
|
|
1383
|
-
|
|
1171
|
+
const groupedParam = buildGroupedRequestParam(node, {
|
|
1384
1172
|
resolver,
|
|
1385
1173
|
memberTypeWrapper: maybeValueOrGetter
|
|
1386
|
-
})
|
|
1174
|
+
});
|
|
1175
|
+
return createFunctionParameters({ params: [groupedParam, optionsParam].filter((param) => param !== null) });
|
|
1387
1176
|
}
|
|
1388
1177
|
function InfiniteQuery({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, tsResolver, initialPageParam, queryParam, customOptions, suspense }) {
|
|
1389
1178
|
const { TData: responseType, TError: errorType } = buildResponseTypes(node, tsResolver);
|
|
@@ -1496,15 +1285,16 @@ function resolveMutationRequestType(node, resolver) {
|
|
|
1496
1285
|
function buildMutationParamsNode(node, options) {
|
|
1497
1286
|
const { resolver } = options;
|
|
1498
1287
|
const { TData, TError } = buildResponseTypes(node, resolver);
|
|
1288
|
+
const generics = [
|
|
1289
|
+
TData,
|
|
1290
|
+
TError,
|
|
1291
|
+
resolveMutationRequestType(node, resolver),
|
|
1292
|
+
"TContext"
|
|
1293
|
+
].join(", ");
|
|
1499
1294
|
return createFunctionParameters({ params: [createFunctionParameter({
|
|
1500
1295
|
name: "options",
|
|
1501
1296
|
type: `{
|
|
1502
|
-
mutation?: UseMutationOptions<${
|
|
1503
|
-
TData,
|
|
1504
|
-
TError,
|
|
1505
|
-
resolveMutationRequestType(node, resolver),
|
|
1506
|
-
"TContext"
|
|
1507
|
-
].join(", ")}> & { client?: QueryClient },
|
|
1297
|
+
mutation?: UseMutationOptions<${generics}> & { client?: QueryClient },
|
|
1508
1298
|
client?: ${buildRequestConfigType(node)},
|
|
1509
1299
|
}`,
|
|
1510
1300
|
default: "{}"
|
|
@@ -1562,10 +1352,11 @@ function buildQueryParamsNode(node, options) {
|
|
|
1562
1352
|
}`,
|
|
1563
1353
|
default: "{}"
|
|
1564
1354
|
});
|
|
1565
|
-
|
|
1355
|
+
const groupedParam = buildGroupedRequestParam(node, {
|
|
1566
1356
|
resolver,
|
|
1567
1357
|
memberTypeWrapper: maybeValueOrGetter
|
|
1568
|
-
})
|
|
1358
|
+
});
|
|
1359
|
+
return createFunctionParameters({ params: [groupedParam, optionsParam].filter((param) => param !== null) });
|
|
1569
1360
|
}
|
|
1570
1361
|
function Query({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, tsResolver, customOptions, suspense }) {
|
|
1571
1362
|
const { TData, TError } = buildResponseTypes(node, tsResolver);
|
|
@@ -1630,14 +1421,11 @@ function Query({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, t
|
|
|
1630
1421
|
//#region src/components/QueryOptions.tsx
|
|
1631
1422
|
const declarationPrinter = functionPrinter({ mode: "declaration" });
|
|
1632
1423
|
const callPrinter = functionPrinter({ mode: "call" });
|
|
1633
|
-
function getQueryOptionsParams(node, options) {
|
|
1634
|
-
return buildQueryOptionsParams(node, options);
|
|
1635
|
-
}
|
|
1636
1424
|
function QueryOptions({ name, clientName, node, tsResolver, queryKeyName }) {
|
|
1637
1425
|
const { TData, TError } = buildResponseTypes(node, tsResolver);
|
|
1638
1426
|
const queryKeyParamsNode = buildQueryKeyParams(node, { resolver: tsResolver });
|
|
1639
1427
|
const queryKeyParamsCall = callPrinter.print(queryKeyParamsNode) ?? "";
|
|
1640
|
-
const paramsNode =
|
|
1428
|
+
const paramsNode = buildQueryOptionsParams(node, { resolver: tsResolver });
|
|
1641
1429
|
const paramsSignature = declarationPrinter.print(paramsNode) ?? "";
|
|
1642
1430
|
const queryFnBody = `const { data } = await ${buildClientCall(node, {
|
|
1643
1431
|
clientName,
|
|
@@ -1668,36 +1456,44 @@ function QueryOptions({ name, clientName, node, tsResolver, queryKeyName }) {
|
|
|
1668
1456
|
//#region src/generators/infiniteQueryGenerator.tsx
|
|
1669
1457
|
/**
|
|
1670
1458
|
* Built-in generator for `useInfiniteQuery` hooks. Enabled when
|
|
1671
|
-
* `pluginReactQuery({ infinite: { ... } })`. Emits one
|
|
1672
|
-
* hook per query operation, wiring the configured
|
|
1673
|
-
* `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.
|
|
1674
1463
|
*/
|
|
1675
1464
|
const infiniteQueryGenerator = defineGenerator({
|
|
1676
1465
|
name: "react-infinite-query",
|
|
1677
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
|
+
},
|
|
1678
1480
|
operation(node, ctx) {
|
|
1679
1481
|
if (!ast.isHttpOperationNode(node)) return null;
|
|
1680
1482
|
const { config, driver, resolver, root } = ctx;
|
|
1681
|
-
const { output, query,
|
|
1483
|
+
const { output, query, infinite, client, group, customOptions } = ctx.options;
|
|
1682
1484
|
const pluginTs = driver.getPlugin(pluginTsName);
|
|
1683
1485
|
if (!pluginTs) return null;
|
|
1684
1486
|
const tsResolver = driver.getResolver(pluginTsName);
|
|
1685
|
-
const { isQuery, isMutation } = classifyOperation(node, {
|
|
1686
|
-
query,
|
|
1687
|
-
mutation
|
|
1688
|
-
});
|
|
1689
1487
|
const infiniteOptions = infinite && typeof infinite === "object" ? infinite : null;
|
|
1690
|
-
if (!
|
|
1691
|
-
const normalizeKey = (key) => key.replace(/\?$/, "");
|
|
1692
|
-
const queryParamKeys = getOperationParameters(node, { paramsCasing: "original" }).query.map((p) => p.name);
|
|
1693
|
-
if (!(infiniteOptions.queryParam ? queryParamKeys.some((k) => normalizeKey(k) === infiniteOptions.queryParam) : false)) return null;
|
|
1488
|
+
if (!infiniteOptions) return null;
|
|
1694
1489
|
const importPath = query ? query.importPath : "@tanstack/react-query";
|
|
1695
1490
|
const contractOp = resolveClientOperation({
|
|
1696
1491
|
clientPlugin: { pluginName: client.pluginName },
|
|
1697
1492
|
driver,
|
|
1698
1493
|
node,
|
|
1699
1494
|
root,
|
|
1700
|
-
output
|
|
1495
|
+
output,
|
|
1496
|
+
cache: ctx.cache
|
|
1701
1497
|
});
|
|
1702
1498
|
if (!contractOp) return null;
|
|
1703
1499
|
const queryName = resolver.infiniteQuery.name(node);
|
|
@@ -1711,15 +1507,20 @@ const infiniteQueryGenerator = defineGenerator({
|
|
|
1711
1507
|
output,
|
|
1712
1508
|
group: group ?? void 0
|
|
1713
1509
|
}),
|
|
1714
|
-
fileTs:
|
|
1715
|
-
|
|
1510
|
+
fileTs: resolveDependencyOperationFile({
|
|
1511
|
+
cache: ctx.cache,
|
|
1512
|
+
node,
|
|
1513
|
+
resolver: tsResolver,
|
|
1716
1514
|
root,
|
|
1717
1515
|
output: pluginTs.options?.output ?? output,
|
|
1718
|
-
group: pluginTs.options?.group
|
|
1516
|
+
group: pluginTs.options?.group
|
|
1719
1517
|
})
|
|
1720
1518
|
};
|
|
1721
|
-
const
|
|
1722
|
-
|
|
1519
|
+
const { queryParamsTypeName } = resolvePageParamType(node, {
|
|
1520
|
+
resolver: tsResolver,
|
|
1521
|
+
initialPageParam: infiniteOptions.initialPageParam,
|
|
1522
|
+
queryParam: infiniteOptions.queryParam
|
|
1523
|
+
});
|
|
1723
1524
|
const importedTypeNames = [
|
|
1724
1525
|
tsResolver.response.options(node),
|
|
1725
1526
|
queryParamsTypeName,
|
|
@@ -1800,33 +1601,31 @@ const infiniteQueryGenerator = defineGenerator({
|
|
|
1800
1601
|
initialPageParam: infiniteOptions.initialPageParam,
|
|
1801
1602
|
queryParam: infiniteOptions.queryParam
|
|
1802
1603
|
}),
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
})
|
|
1829
|
-
] })
|
|
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
|
+
})
|
|
1830
1629
|
]
|
|
1831
1630
|
});
|
|
1832
1631
|
}
|
|
@@ -1841,25 +1640,30 @@ const infiniteQueryGenerator = defineGenerator({
|
|
|
1841
1640
|
const mutationGenerator = defineGenerator({
|
|
1842
1641
|
name: "react-query-mutation",
|
|
1843
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
|
+
},
|
|
1844
1652
|
operation(node, ctx) {
|
|
1845
1653
|
if (!ast.isHttpOperationNode(node)) return null;
|
|
1846
1654
|
const { config, driver, resolver, root } = ctx;
|
|
1847
|
-
const { output,
|
|
1655
|
+
const { output, mutation, client, group, customOptions, hooks } = ctx.options;
|
|
1848
1656
|
const pluginTs = driver.getPlugin(pluginTsName);
|
|
1849
1657
|
if (!pluginTs) return null;
|
|
1850
1658
|
const tsResolver = driver.getResolver(pluginTsName);
|
|
1851
|
-
const { isMutation } = classifyOperation(node, {
|
|
1852
|
-
query,
|
|
1853
|
-
mutation
|
|
1854
|
-
});
|
|
1855
|
-
if (!isMutation) return null;
|
|
1856
1659
|
const importPath = mutation ? mutation.importPath : "@tanstack/react-query";
|
|
1857
1660
|
const contractOp = resolveClientOperation({
|
|
1858
1661
|
clientPlugin: { pluginName: client.pluginName },
|
|
1859
1662
|
driver,
|
|
1860
1663
|
node,
|
|
1861
1664
|
root,
|
|
1862
|
-
output
|
|
1665
|
+
output,
|
|
1666
|
+
cache: ctx.cache
|
|
1863
1667
|
});
|
|
1864
1668
|
if (!contractOp) return null;
|
|
1865
1669
|
const mutationHookName = resolver.mutation.name(node);
|
|
@@ -1873,11 +1677,13 @@ const mutationGenerator = defineGenerator({
|
|
|
1873
1677
|
output,
|
|
1874
1678
|
group: group ?? void 0
|
|
1875
1679
|
}),
|
|
1876
|
-
fileTs:
|
|
1877
|
-
|
|
1680
|
+
fileTs: resolveDependencyOperationFile({
|
|
1681
|
+
cache: ctx.cache,
|
|
1682
|
+
node,
|
|
1683
|
+
resolver: tsResolver,
|
|
1878
1684
|
root,
|
|
1879
1685
|
output: pluginTs.options?.output ?? output,
|
|
1880
|
-
group: pluginTs.options?.group
|
|
1686
|
+
group: pluginTs.options?.group
|
|
1881
1687
|
})
|
|
1882
1688
|
};
|
|
1883
1689
|
const importedTypeNames = [tsResolver.response.options(node), ...resolveOperationTypeNames(node, tsResolver, {
|
|
@@ -1981,25 +1787,31 @@ const mutationGenerator = defineGenerator({
|
|
|
1981
1787
|
const queryGenerator = defineGenerator({
|
|
1982
1788
|
name: "react-query",
|
|
1983
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
|
+
},
|
|
1984
1800
|
operation(node, ctx) {
|
|
1985
1801
|
if (!ast.isHttpOperationNode(node)) return null;
|
|
1986
1802
|
const { config, driver, resolver, root } = ctx;
|
|
1987
|
-
const { output, query,
|
|
1803
|
+
const { output, query, client, group, customOptions, hooks } = ctx.options;
|
|
1988
1804
|
const pluginTs = driver.getPlugin(pluginTsName);
|
|
1989
1805
|
if (!pluginTs) return null;
|
|
1990
1806
|
const tsResolver = driver.getResolver(pluginTsName);
|
|
1991
|
-
const { isQuery, isMutation } = classifyOperation(node, {
|
|
1992
|
-
query,
|
|
1993
|
-
mutation
|
|
1994
|
-
});
|
|
1995
|
-
if (!isQuery || isMutation) return null;
|
|
1996
1807
|
const importPath = query ? query.importPath : "@tanstack/react-query";
|
|
1997
1808
|
const contractOp = resolveClientOperation({
|
|
1998
1809
|
clientPlugin: { pluginName: client.pluginName },
|
|
1999
1810
|
driver,
|
|
2000
1811
|
node,
|
|
2001
1812
|
root,
|
|
2002
|
-
output
|
|
1813
|
+
output,
|
|
1814
|
+
cache: ctx.cache
|
|
2003
1815
|
});
|
|
2004
1816
|
if (!contractOp) return null;
|
|
2005
1817
|
const queryName = resolver.query.name(node);
|
|
@@ -2013,11 +1825,13 @@ const queryGenerator = defineGenerator({
|
|
|
2013
1825
|
output,
|
|
2014
1826
|
group: group ?? void 0
|
|
2015
1827
|
}),
|
|
2016
|
-
fileTs:
|
|
2017
|
-
|
|
1828
|
+
fileTs: resolveDependencyOperationFile({
|
|
1829
|
+
cache: ctx.cache,
|
|
1830
|
+
node,
|
|
1831
|
+
resolver: tsResolver,
|
|
2018
1832
|
root,
|
|
2019
1833
|
output: pluginTs.options?.output ?? output,
|
|
2020
|
-
group: pluginTs.options?.group
|
|
1834
|
+
group: pluginTs.options?.group
|
|
2021
1835
|
})
|
|
2022
1836
|
};
|
|
2023
1837
|
const importedTypeNames = [tsResolver.response.options(node), ...resolveOperationTypeNames(node, tsResolver, {
|
|
@@ -2118,38 +1932,44 @@ const queryGenerator = defineGenerator({
|
|
|
2118
1932
|
//#endregion
|
|
2119
1933
|
//#region src/generators/suspenseInfiniteQueryGenerator.tsx
|
|
2120
1934
|
/**
|
|
2121
|
-
* Built-in generator for `useSuspenseInfiniteQuery` hooks. Enabled when
|
|
2122
|
-
* `suspense` and `
|
|
2123
|
-
* cursor-based pagination. Handlers throw promises while
|
|
2124
|
-
* 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.
|
|
2125
1939
|
*/
|
|
2126
1940
|
const suspenseInfiniteQueryGenerator = defineGenerator({
|
|
2127
1941
|
name: "react-suspense-infinite-query",
|
|
2128
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
|
+
},
|
|
2129
1956
|
operation(node, ctx) {
|
|
2130
1957
|
if (!ast.isHttpOperationNode(node)) return null;
|
|
2131
1958
|
const { config, driver, resolver, root } = ctx;
|
|
2132
|
-
const { output, query,
|
|
1959
|
+
const { output, query, infinite, client, group, customOptions } = ctx.options;
|
|
2133
1960
|
const pluginTs = driver.getPlugin(pluginTsName);
|
|
2134
1961
|
if (!pluginTs) return null;
|
|
2135
1962
|
const tsResolver = driver.getResolver(pluginTsName);
|
|
2136
|
-
const { isQuery, isMutation } = classifyOperation(node, {
|
|
2137
|
-
query,
|
|
2138
|
-
mutation
|
|
2139
|
-
});
|
|
2140
|
-
const isSuspense = !!suspense;
|
|
2141
1963
|
const infiniteOptions = infinite && typeof infinite === "object" ? infinite : null;
|
|
2142
|
-
if (!
|
|
2143
|
-
const normalizeKey = (key) => key.replace(/\?$/, "");
|
|
2144
|
-
const queryParamKeys = getOperationParameters(node, { paramsCasing: "original" }).query.map((p) => p.name);
|
|
2145
|
-
if (!(infiniteOptions.queryParam ? queryParamKeys.some((k) => normalizeKey(k) === infiniteOptions.queryParam) : false)) return null;
|
|
1964
|
+
if (!infiniteOptions) return null;
|
|
2146
1965
|
const importPath = query ? query.importPath : "@tanstack/react-query";
|
|
2147
1966
|
const contractOp = resolveClientOperation({
|
|
2148
1967
|
clientPlugin: { pluginName: client.pluginName },
|
|
2149
1968
|
driver,
|
|
2150
1969
|
node,
|
|
2151
1970
|
root,
|
|
2152
|
-
output
|
|
1971
|
+
output,
|
|
1972
|
+
cache: ctx.cache
|
|
2153
1973
|
});
|
|
2154
1974
|
if (!contractOp) return null;
|
|
2155
1975
|
const queryName = resolver.suspenseInfiniteQuery.name(node);
|
|
@@ -2163,14 +1983,16 @@ const suspenseInfiniteQueryGenerator = defineGenerator({
|
|
|
2163
1983
|
output,
|
|
2164
1984
|
group: group ?? void 0
|
|
2165
1985
|
}),
|
|
2166
|
-
fileTs:
|
|
2167
|
-
|
|
1986
|
+
fileTs: resolveDependencyOperationFile({
|
|
1987
|
+
cache: ctx.cache,
|
|
1988
|
+
node,
|
|
1989
|
+
resolver: tsResolver,
|
|
2168
1990
|
root,
|
|
2169
1991
|
output: pluginTs.options?.output ?? output,
|
|
2170
|
-
group: pluginTs.options?.group
|
|
1992
|
+
group: pluginTs.options?.group
|
|
2171
1993
|
})
|
|
2172
1994
|
};
|
|
2173
|
-
const rawQueryParams = getOperationParameters(node
|
|
1995
|
+
const rawQueryParams = getOperationParameters(node).query;
|
|
2174
1996
|
const queryParamsTypeName = rawQueryParams.length > 0 && tsResolver.param.query(node, rawQueryParams[0]) !== tsResolver.param.name(node, rawQueryParams[0]) ? tsResolver.param.query(node, rawQueryParams[0]) : null;
|
|
2175
1997
|
const importedTypeNames = [
|
|
2176
1998
|
tsResolver.response.options(node),
|
|
@@ -2251,34 +2073,32 @@ const suspenseInfiniteQueryGenerator = defineGenerator({
|
|
|
2251
2073
|
initialPageParam: infiniteOptions.initialPageParam,
|
|
2252
2074
|
queryParam: infiniteOptions.queryParam
|
|
2253
2075
|
}),
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
})
|
|
2281
|
-
] })
|
|
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
|
+
})
|
|
2282
2102
|
]
|
|
2283
2103
|
});
|
|
2284
2104
|
}
|
|
@@ -2287,32 +2107,39 @@ const suspenseInfiniteQueryGenerator = defineGenerator({
|
|
|
2287
2107
|
//#region src/generators/suspenseQueryGenerator.tsx
|
|
2288
2108
|
/**
|
|
2289
2109
|
* Built-in generator for `useSuspenseQuery` hooks. Enabled when
|
|
2290
|
-
* `pluginReactQuery({ suspense: {} })`. Emits one
|
|
2291
|
-
* per query operation. Suspense queries throw
|
|
2292
|
-
* 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.
|
|
2293
2114
|
*/
|
|
2294
2115
|
const suspenseQueryGenerator = defineGenerator({
|
|
2295
2116
|
name: "react-suspense-query",
|
|
2296
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
|
+
},
|
|
2297
2128
|
operation(node, ctx) {
|
|
2298
2129
|
if (!ast.isHttpOperationNode(node)) return null;
|
|
2299
2130
|
const { config, driver, resolver, root } = ctx;
|
|
2300
|
-
const { output, query,
|
|
2131
|
+
const { output, query, client, group, customOptions } = ctx.options;
|
|
2301
2132
|
const pluginTs = driver.getPlugin(pluginTsName);
|
|
2302
2133
|
if (!pluginTs) return null;
|
|
2303
2134
|
const tsResolver = driver.getResolver(pluginTsName);
|
|
2304
|
-
const { isQuery, isMutation } = classifyOperation(node, {
|
|
2305
|
-
query,
|
|
2306
|
-
mutation
|
|
2307
|
-
});
|
|
2308
|
-
if (!isQuery || isMutation || !!!suspense) return null;
|
|
2309
2135
|
const importPath = query ? query.importPath : "@tanstack/react-query";
|
|
2310
2136
|
const contractOp = resolveClientOperation({
|
|
2311
2137
|
clientPlugin: { pluginName: client.pluginName },
|
|
2312
2138
|
driver,
|
|
2313
2139
|
node,
|
|
2314
2140
|
root,
|
|
2315
|
-
output
|
|
2141
|
+
output,
|
|
2142
|
+
cache: ctx.cache
|
|
2316
2143
|
});
|
|
2317
2144
|
if (!contractOp) return null;
|
|
2318
2145
|
const queryName = resolver.suspenseQuery.name(node);
|
|
@@ -2326,11 +2153,13 @@ const suspenseQueryGenerator = defineGenerator({
|
|
|
2326
2153
|
output,
|
|
2327
2154
|
group: group ?? void 0
|
|
2328
2155
|
}),
|
|
2329
|
-
fileTs:
|
|
2330
|
-
|
|
2156
|
+
fileTs: resolveDependencyOperationFile({
|
|
2157
|
+
cache: ctx.cache,
|
|
2158
|
+
node,
|
|
2159
|
+
resolver: tsResolver,
|
|
2331
2160
|
root,
|
|
2332
2161
|
output: pluginTs.options?.output ?? output,
|
|
2333
|
-
group: pluginTs.options?.group
|
|
2162
|
+
group: pluginTs.options?.group
|
|
2334
2163
|
})
|
|
2335
2164
|
};
|
|
2336
2165
|
const importedTypeNames = [tsResolver.response.options(node), ...resolveOperationTypeNames(node, tsResolver, {
|
|
@@ -2399,32 +2228,30 @@ const suspenseQueryGenerator = defineGenerator({
|
|
|
2399
2228
|
node,
|
|
2400
2229
|
tsResolver
|
|
2401
2230
|
}),
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
})
|
|
2427
|
-
] })
|
|
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
|
+
})
|
|
2428
2255
|
]
|
|
2429
2256
|
});
|
|
2430
2257
|
}
|
|
@@ -2510,7 +2337,7 @@ const pluginReactQuery = definePlugin((options) => {
|
|
|
2510
2337
|
const { output = {
|
|
2511
2338
|
path: "hooks",
|
|
2512
2339
|
barrel: { type: "named" }
|
|
2513
|
-
}, 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;
|
|
2514
2341
|
const selectedGenerators = [
|
|
2515
2342
|
queryGenerator,
|
|
2516
2343
|
suspenseQueryGenerator,
|