@kubb/plugin-vue-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 +223 -344
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +220 -341
- package/dist/index.js.map +1 -1
- package/package.json +16 -8
package/dist/index.js
CHANGED
|
@@ -1,249 +1,9 @@
|
|
|
1
1
|
import { t as __name } from "./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
|
-
//#region ../../internals/utils/src/casing.ts
|
|
8
|
-
/**
|
|
9
|
-
* Shared implementation for camelCase and PascalCase conversion.
|
|
10
|
-
* Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)
|
|
11
|
-
* and capitalizes each word according to `pascal`.
|
|
12
|
-
*
|
|
13
|
-
* When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
|
|
14
|
-
*/
|
|
15
|
-
function toCamelOrPascal(text, pascal) {
|
|
16
|
-
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) => {
|
|
17
|
-
if (word.length > 1 && word === word.toUpperCase()) return word;
|
|
18
|
-
return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
|
|
19
|
-
}).join("").replace(/[^a-zA-Z0-9]/g, "");
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Converts `text` to camelCase.
|
|
23
|
-
*
|
|
24
|
-
* @example Word boundaries
|
|
25
|
-
* `camelCase('hello-world') // 'helloWorld'`
|
|
26
|
-
*
|
|
27
|
-
* @example With a prefix
|
|
28
|
-
* `camelCase('tag', { prefix: 'create' }) // 'createTag'`
|
|
29
|
-
*/
|
|
30
|
-
function camelCase(text, { prefix = "", suffix = "" } = {}) {
|
|
31
|
-
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Uppercases only the first character of `text`, leaving the rest untouched.
|
|
35
|
-
* Unlike {@link pascalCase} it never re-splits word boundaries or strips characters.
|
|
36
|
-
*
|
|
37
|
-
* @example
|
|
38
|
-
* `capitalize('getPetById') // 'GetPetById'`
|
|
39
|
-
*/
|
|
40
|
-
function capitalize(text) {
|
|
41
|
-
return `${text.charAt(0).toUpperCase()}${text.slice(1)}`;
|
|
42
|
-
}
|
|
43
|
-
//#endregion
|
|
44
|
-
//#region ../../internals/utils/src/reserved.ts
|
|
45
|
-
/**
|
|
46
|
-
* JavaScript and Java reserved words.
|
|
47
|
-
* @link https://github.com/jonschlinkert/reserved/blob/master/index.js
|
|
48
|
-
*/
|
|
49
|
-
const reservedWords = /* @__PURE__ */ new Set([
|
|
50
|
-
"abstract",
|
|
51
|
-
"arguments",
|
|
52
|
-
"boolean",
|
|
53
|
-
"break",
|
|
54
|
-
"byte",
|
|
55
|
-
"case",
|
|
56
|
-
"catch",
|
|
57
|
-
"char",
|
|
58
|
-
"class",
|
|
59
|
-
"const",
|
|
60
|
-
"continue",
|
|
61
|
-
"debugger",
|
|
62
|
-
"default",
|
|
63
|
-
"delete",
|
|
64
|
-
"do",
|
|
65
|
-
"double",
|
|
66
|
-
"else",
|
|
67
|
-
"enum",
|
|
68
|
-
"eval",
|
|
69
|
-
"export",
|
|
70
|
-
"extends",
|
|
71
|
-
"false",
|
|
72
|
-
"final",
|
|
73
|
-
"finally",
|
|
74
|
-
"float",
|
|
75
|
-
"for",
|
|
76
|
-
"function",
|
|
77
|
-
"goto",
|
|
78
|
-
"if",
|
|
79
|
-
"implements",
|
|
80
|
-
"import",
|
|
81
|
-
"in",
|
|
82
|
-
"instanceof",
|
|
83
|
-
"int",
|
|
84
|
-
"interface",
|
|
85
|
-
"let",
|
|
86
|
-
"long",
|
|
87
|
-
"native",
|
|
88
|
-
"new",
|
|
89
|
-
"null",
|
|
90
|
-
"package",
|
|
91
|
-
"private",
|
|
92
|
-
"protected",
|
|
93
|
-
"public",
|
|
94
|
-
"return",
|
|
95
|
-
"short",
|
|
96
|
-
"static",
|
|
97
|
-
"super",
|
|
98
|
-
"switch",
|
|
99
|
-
"synchronized",
|
|
100
|
-
"this",
|
|
101
|
-
"throw",
|
|
102
|
-
"throws",
|
|
103
|
-
"transient",
|
|
104
|
-
"true",
|
|
105
|
-
"try",
|
|
106
|
-
"typeof",
|
|
107
|
-
"var",
|
|
108
|
-
"void",
|
|
109
|
-
"volatile",
|
|
110
|
-
"while",
|
|
111
|
-
"with",
|
|
112
|
-
"yield",
|
|
113
|
-
"Array",
|
|
114
|
-
"Date",
|
|
115
|
-
"hasOwnProperty",
|
|
116
|
-
"Infinity",
|
|
117
|
-
"isFinite",
|
|
118
|
-
"isNaN",
|
|
119
|
-
"isPrototypeOf",
|
|
120
|
-
"length",
|
|
121
|
-
"Math",
|
|
122
|
-
"name",
|
|
123
|
-
"NaN",
|
|
124
|
-
"Number",
|
|
125
|
-
"Object",
|
|
126
|
-
"prototype",
|
|
127
|
-
"String",
|
|
128
|
-
"toString",
|
|
129
|
-
"undefined",
|
|
130
|
-
"valueOf"
|
|
131
|
-
]);
|
|
132
|
-
/**
|
|
133
|
-
* Returns `true` when `name` is a syntactically valid JavaScript variable name.
|
|
134
|
-
*
|
|
135
|
-
* @example
|
|
136
|
-
* ```ts
|
|
137
|
-
* isValidVarName('status') // true
|
|
138
|
-
* isValidVarName('class') // false (reserved word)
|
|
139
|
-
* isValidVarName('42foo') // false (starts with digit)
|
|
140
|
-
* ```
|
|
141
|
-
*/
|
|
142
|
-
function isValidVarName(name) {
|
|
143
|
-
if (!name || reservedWords.has(name)) return false;
|
|
144
|
-
return isIdentifier(name);
|
|
145
|
-
}
|
|
146
|
-
/**
|
|
147
|
-
* Returns `true` when `name` is syntactically a valid identifier, ignoring reserved words.
|
|
148
|
-
*
|
|
149
|
-
* Reserved words and globals (`class`, `name`, `Date`, …) are valid as bare object-literal keys
|
|
150
|
-
* even though they are not valid variable names, so use this (not {@link isValidVarName}) when
|
|
151
|
-
* deciding whether an object key needs quoting.
|
|
152
|
-
*
|
|
153
|
-
* @example
|
|
154
|
-
* ```ts
|
|
155
|
-
* isIdentifier('name') // true
|
|
156
|
-
* isIdentifier('x-total')// false
|
|
157
|
-
* ```
|
|
158
|
-
*/
|
|
159
|
-
function isIdentifier(name) {
|
|
160
|
-
return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
|
|
161
|
-
}
|
|
162
|
-
//#endregion
|
|
163
|
-
//#region ../../internals/utils/src/strings.ts
|
|
164
|
-
/**
|
|
165
|
-
* Renders a dotted path or string array as an optional-chaining accessor expression rooted at
|
|
166
|
-
* `accessor`. Returns `null` for an empty path.
|
|
167
|
-
*
|
|
168
|
-
* @example
|
|
169
|
-
* ```ts
|
|
170
|
-
* getNestedAccessor('pagination.next.id', 'lastPage')
|
|
171
|
-
* // "lastPage?.['pagination']?.['next']?.['id']"
|
|
172
|
-
* ```
|
|
173
|
-
*/
|
|
174
|
-
function getNestedAccessor(param, accessor) {
|
|
175
|
-
const parts = Array.isArray(param) ? param : param.split(".");
|
|
176
|
-
if (parts.length === 0 || parts.length === 1 && parts[0] === "") return null;
|
|
177
|
-
return `${accessor}?.['${`${parts.join("']?.['")}']`}`;
|
|
178
|
-
}
|
|
179
|
-
//#endregion
|
|
180
|
-
//#region ../../internals/utils/src/url.ts
|
|
181
|
-
/**
|
|
182
|
-
* Keeps the OpenAPI parameter name as-is when it is already a valid JS identifier, and
|
|
183
|
-
* camelCases it only enough to become one otherwise (for example a hyphenated path segment).
|
|
184
|
-
*/
|
|
185
|
-
function transformParam(raw) {
|
|
186
|
-
return isValidVarName(raw) ? raw : camelCase(raw);
|
|
187
|
-
}
|
|
188
|
-
/**
|
|
189
|
-
* Helpers for OpenAPI/Swagger paths.
|
|
190
|
-
*/
|
|
191
|
-
var Url = class Url {
|
|
192
|
-
/**
|
|
193
|
-
* Converts an OpenAPI/Swagger path to Express-style colon syntax.
|
|
194
|
-
*
|
|
195
|
-
* @example
|
|
196
|
-
* Url.toPath('/pet/{petId}') // '/pet/:petId'
|
|
197
|
-
*/
|
|
198
|
-
static toPath(path) {
|
|
199
|
-
return path.replace(/\{([^}]+)\}/g, ":$1");
|
|
200
|
-
}
|
|
201
|
-
/**
|
|
202
|
-
* Rewrites OpenAPI placeholder names while keeping the `{...}` braces, so the generated `url`
|
|
203
|
-
* literal aligns with the grouped `path` request option that the runtime client interpolates by
|
|
204
|
-
* key.
|
|
205
|
-
*
|
|
206
|
-
* @example
|
|
207
|
-
* Url.toSafeTemplate('/user/{monetary-account-id}') // '/user/{monetaryAccountId}'
|
|
208
|
-
*/
|
|
209
|
-
static toSafeTemplate(path) {
|
|
210
|
-
return path.replace(/\{([^}]+)\}/g, (_, name) => `{${transformParam(name)}}`);
|
|
211
|
-
}
|
|
212
|
-
/**
|
|
213
|
-
* Converts an OpenAPI/Swagger path to a TypeScript template literal string.
|
|
214
|
-
* `prefix` is prepended inside the literal, and `replacer` transforms each parameter name.
|
|
215
|
-
*
|
|
216
|
-
* @example
|
|
217
|
-
* Url.toTemplateString('/pet/{petId}') // '`/pet/${petId}`'
|
|
218
|
-
*
|
|
219
|
-
* @example
|
|
220
|
-
* Url.toTemplateString('/pet/{petId}', { prefix: 'https://api' }) // '`https://api/pet/${petId}`'
|
|
221
|
-
*/
|
|
222
|
-
static toTemplateString(path, { prefix, replacer } = {}) {
|
|
223
|
-
const result = path.split(/\{([^}]+)\}/).map((part, i) => {
|
|
224
|
-
if (i % 2 === 0) return part;
|
|
225
|
-
const param = transformParam(part);
|
|
226
|
-
return `\${${replacer ? replacer(param) : param}}`;
|
|
227
|
-
}).join("");
|
|
228
|
-
return `\`${prefix ?? ""}${result}\``;
|
|
229
|
-
}
|
|
230
|
-
/**
|
|
231
|
-
* Converts an OpenAPI/Swagger path to a template literal that reads each parameter off the
|
|
232
|
-
* grouped `path` request option, e.g. `/pet/{petId}` becomes `` `/pet/${path.petId}` ``. Parameter
|
|
233
|
-
* names match the generated `path` type, and `prefix` is prepended inside the literal. Shared by
|
|
234
|
-
* the client and cypress generators that pass a grouped `path` object.
|
|
235
|
-
*
|
|
236
|
-
* @example
|
|
237
|
-
* Url.toGroupedTemplateString('/pet/{petId}') // '`/pet/${path.petId}`'
|
|
238
|
-
*/
|
|
239
|
-
static toGroupedTemplateString(path, { prefix } = {}) {
|
|
240
|
-
return Url.toTemplateString(path, {
|
|
241
|
-
prefix,
|
|
242
|
-
replacer: (name) => `path.${name}`
|
|
243
|
-
});
|
|
244
|
-
}
|
|
245
|
-
};
|
|
246
|
-
//#endregion
|
|
247
7
|
//#region ../../internals/shared/src/params.ts
|
|
248
8
|
/**
|
|
249
9
|
* Drops parameters that share the same name, keeping the first.
|
|
@@ -282,11 +42,30 @@ function operationFileEntry(node, name, extname = ".ts") {
|
|
|
282
42
|
path: node.path
|
|
283
43
|
};
|
|
284
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* Resolves a dependency plugin's generated file for `node.operationId`, cached in `cache` (the
|
|
47
|
+
* current node's `ctx.cache`) under the resolver's own plugin name. Several dependents reading the
|
|
48
|
+
* same dependency for the same operation in one pass (a query plugin's several hook generators, the
|
|
49
|
+
* MCP handler, ...) share one computed name and path instead of each calling `resolver.file` again.
|
|
50
|
+
*
|
|
51
|
+
* @example Cache `plugin-ts`'s file for the current operation
|
|
52
|
+
* ```ts
|
|
53
|
+
* const fileTs = resolveDependencyOperationFile({ cache: ctx.cache, node, resolver: tsResolver, root, output })
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
function resolveDependencyOperationFile(options) {
|
|
57
|
+
const { cache, node, resolver, root, output, group } = options;
|
|
58
|
+
return cache.ensureItem(`${resolver.pluginName}:operationFile`, () => resolver.file({
|
|
59
|
+
...operationFileEntry(node, node.operationId),
|
|
60
|
+
root,
|
|
61
|
+
output,
|
|
62
|
+
group: group ?? void 0
|
|
63
|
+
}));
|
|
64
|
+
}
|
|
285
65
|
function getOperationLink(node, link) {
|
|
286
66
|
if (!link) return null;
|
|
287
67
|
if (typeof link === "function") return link(node) ?? null;
|
|
288
|
-
|
|
289
|
-
return node.path ? `{@link ${node.path.replaceAll("{", ":").replaceAll("}", "")}}` : null;
|
|
68
|
+
return node.path ? `{@link ${Url.toPath(node.path)}}` : null;
|
|
290
69
|
}
|
|
291
70
|
/**
|
|
292
71
|
* Derives the shared `ContentTypeInfo` shape from a list of content types, tracking whether several
|
|
@@ -376,16 +155,24 @@ function buildOperationComments(node, options = {}) {
|
|
|
376
155
|
if (!splitLines) return filteredComments;
|
|
377
156
|
return filteredComments.flatMap((text) => text.split(/\r?\n/).map((line) => line.trim())).filter((comment) => Boolean(comment));
|
|
378
157
|
}
|
|
158
|
+
const operationParameterGroupsByNode = /* @__PURE__ */ new WeakMap();
|
|
159
|
+
/**
|
|
160
|
+
* Groups an operation's parameters by location (`path`/`query`/`header`/`cookie`), deduping each
|
|
161
|
+
* group by name. Every plugin generator visiting the same `OperationNode` shares one AST instance
|
|
162
|
+
* (see `KubbDriver`), so the result is cached per node to avoid re-filtering and re-deduping the
|
|
163
|
+
* same parameters once per plugin.
|
|
164
|
+
*/
|
|
379
165
|
function getOperationParameters(node) {
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
})),
|
|
166
|
+
const cached = operationParameterGroupsByNode.get(node);
|
|
167
|
+
if (cached) return cached;
|
|
168
|
+
const groups = {
|
|
169
|
+
path: dedupeParams(node.parameters.filter((param) => param.in === "path")),
|
|
385
170
|
query: dedupeParams(node.parameters.filter((param) => param.in === "query")),
|
|
386
171
|
header: dedupeParams(node.parameters.filter((param) => param.in === "header")),
|
|
387
172
|
cookie: dedupeParams(node.parameters.filter((param) => param.in === "cookie"))
|
|
388
173
|
};
|
|
174
|
+
operationParameterGroupsByNode.set(node, groups);
|
|
175
|
+
return groups;
|
|
389
176
|
}
|
|
390
177
|
function getStatusCodeNumber(statusCode) {
|
|
391
178
|
const code = Number(statusCode);
|
|
@@ -450,6 +237,60 @@ function resolveOperationTypeNames(node, resolver, options = {}) {
|
|
|
450
237
|
return result;
|
|
451
238
|
}
|
|
452
239
|
//#endregion
|
|
240
|
+
//#region ../../internals/utils/src/casing.ts
|
|
241
|
+
/**
|
|
242
|
+
* Shared implementation for camelCase and PascalCase conversion.
|
|
243
|
+
* Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)
|
|
244
|
+
* and capitalizes each word according to `pascal`.
|
|
245
|
+
*
|
|
246
|
+
* When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
|
|
247
|
+
*/
|
|
248
|
+
function toCamelOrPascal(text, pascal) {
|
|
249
|
+
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) => {
|
|
250
|
+
if (word.length > 1 && word === word.toUpperCase()) return word;
|
|
251
|
+
return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
|
|
252
|
+
}).join("").replace(/[^a-zA-Z0-9]/g, "");
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Converts `text` to camelCase.
|
|
256
|
+
*
|
|
257
|
+
* @example Word boundaries
|
|
258
|
+
* `camelCase('hello-world') // 'helloWorld'`
|
|
259
|
+
*
|
|
260
|
+
* @example With a prefix
|
|
261
|
+
* `camelCase('tag', { prefix: 'create' }) // 'createTag'`
|
|
262
|
+
*/
|
|
263
|
+
function camelCase(text, { prefix = "", suffix = "" } = {}) {
|
|
264
|
+
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Uppercases only the first character of `text`, leaving the rest untouched.
|
|
268
|
+
* Unlike {@link pascalCase} it never re-splits word boundaries or strips characters.
|
|
269
|
+
*
|
|
270
|
+
* @example
|
|
271
|
+
* `capitalize('getPetById') // 'GetPetById'`
|
|
272
|
+
*/
|
|
273
|
+
function capitalize(text) {
|
|
274
|
+
return `${text.charAt(0).toUpperCase()}${text.slice(1)}`;
|
|
275
|
+
}
|
|
276
|
+
//#endregion
|
|
277
|
+
//#region ../../internals/utils/src/strings.ts
|
|
278
|
+
/**
|
|
279
|
+
* Renders a dotted path or string array as an optional-chaining accessor expression rooted at
|
|
280
|
+
* `accessor`. Returns `null` for an empty path.
|
|
281
|
+
*
|
|
282
|
+
* @example
|
|
283
|
+
* ```ts
|
|
284
|
+
* getNestedAccessor('pagination.next.id', 'lastPage')
|
|
285
|
+
* // "lastPage?.['pagination']?.['next']?.['id']"
|
|
286
|
+
* ```
|
|
287
|
+
*/
|
|
288
|
+
function getNestedAccessor(param, accessor) {
|
|
289
|
+
const parts = Array.isArray(param) ? param : param.split(".");
|
|
290
|
+
if (parts.length === 0 || parts.length === 1 && parts[0] === "") return null;
|
|
291
|
+
return `${accessor}?.['${`${parts.join("']?.['")}']`}`;
|
|
292
|
+
}
|
|
293
|
+
//#endregion
|
|
453
294
|
//#region ../../internals/shared/src/group.ts
|
|
454
295
|
/**
|
|
455
296
|
* Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the
|
|
@@ -559,14 +400,16 @@ function buildGroupedRequestParam(node, options) {
|
|
|
559
400
|
*/
|
|
560
401
|
function buildQueryOptionsParams(node, options) {
|
|
561
402
|
const { resolver, memberTypeWrapper } = options;
|
|
562
|
-
|
|
403
|
+
const groupedParam = buildGroupedRequestParam(node, {
|
|
563
404
|
resolver,
|
|
564
405
|
memberTypeWrapper
|
|
565
|
-
})
|
|
406
|
+
});
|
|
407
|
+
const configParam = createFunctionParameter({
|
|
566
408
|
name: "config",
|
|
567
409
|
type: `Partial<Omit<RequestConfig, 'path' | 'query' | 'body' | 'headers' | 'url'>>`,
|
|
568
410
|
default: "{}"
|
|
569
|
-
})
|
|
411
|
+
});
|
|
412
|
+
return createFunctionParameters({ params: [groupedParam, configParam].filter((param) => param !== null) });
|
|
570
413
|
}
|
|
571
414
|
/**
|
|
572
415
|
* Builds the call to a client `<op>` function inside a query/mutation hook body. The function takes
|
|
@@ -664,6 +507,19 @@ function resolveMutationConfig(mutation, options) {
|
|
|
664
507
|
};
|
|
665
508
|
}
|
|
666
509
|
/**
|
|
510
|
+
* Classifies an operation as a query or a mutation from the resolved `query` / `mutation` method lists.
|
|
511
|
+
* `query: false` still marks the operation as a query so the query-family generators keep matching it,
|
|
512
|
+
* and a method already claimed by `query` never counts as a mutation.
|
|
513
|
+
*/
|
|
514
|
+
function classifyOperation(node, { query, mutation }) {
|
|
515
|
+
const isQuery = query === false || !!query && query.methods.some((method) => node.method.toLowerCase() === method.toLowerCase());
|
|
516
|
+
const queryMethods = new Set(query ? query.methods : []);
|
|
517
|
+
return {
|
|
518
|
+
isQuery,
|
|
519
|
+
isMutation: mutation !== false && !isQuery && (mutation ? mutation.methods : []).some((method) => !queryMethods.has(method) && node.method.toLowerCase() === method.toLowerCase())
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
667
523
|
* Applies the shared infinite-query defaults during plugin setup: a falsy value disables infinite
|
|
668
524
|
* queries, and an object merges over `queryParam: 'id'` and `initialPageParam: 0` with the cursor
|
|
669
525
|
* paths cleared.
|
|
@@ -679,6 +535,16 @@ function resolveInfiniteConfig(infinite) {
|
|
|
679
535
|
...infinite
|
|
680
536
|
};
|
|
681
537
|
}
|
|
538
|
+
/**
|
|
539
|
+
* The request groups a query key is built from, matching `buildQueryKeyParams`. Headers are
|
|
540
|
+
* deliberately absent: they do not identify a cache entry, so the key factory takes no parameter
|
|
541
|
+
* for an operation that only carries headers.
|
|
542
|
+
*/
|
|
543
|
+
const queryKeyGroupOrder = [
|
|
544
|
+
"path",
|
|
545
|
+
"query",
|
|
546
|
+
"body"
|
|
547
|
+
];
|
|
682
548
|
//#endregion
|
|
683
549
|
//#region ../../internals/tanstack-query/src/components/InfiniteQueryOptions.tsx
|
|
684
550
|
const declarationPrinter$7 = functionPrinter({ mode: "declaration" });
|
|
@@ -692,11 +558,7 @@ function InfiniteQueryOptions$1({ name, clientName, initialPageParam, cursorPara
|
|
|
692
558
|
});
|
|
693
559
|
const groupedKeyParam = buildGroupedRequestParam(node, {
|
|
694
560
|
resolver: tsResolver,
|
|
695
|
-
keys:
|
|
696
|
-
"path",
|
|
697
|
-
"query",
|
|
698
|
-
"body"
|
|
699
|
-
],
|
|
561
|
+
keys: queryKeyGroupOrder,
|
|
700
562
|
memberTypeWrapper
|
|
701
563
|
});
|
|
702
564
|
const queryKeyParamsNode = createFunctionParameters({ params: groupedKeyParam ? [groupedKeyParam] : [] });
|
|
@@ -706,12 +568,11 @@ function InfiniteQueryOptions$1({ name, clientName, initialPageParam, cursorPara
|
|
|
706
568
|
memberTypeWrapper
|
|
707
569
|
});
|
|
708
570
|
const paramsSignature = declarationPrinter$7.print(paramsNode) ?? "";
|
|
709
|
-
const queryFnBody = `
|
|
571
|
+
const queryFnBody = `return ${buildClientCall(node, {
|
|
710
572
|
clientName,
|
|
711
573
|
signal: true,
|
|
712
574
|
unwrapName
|
|
713
|
-
})}
|
|
714
|
-
return data`;
|
|
575
|
+
})}.unwrap()`;
|
|
715
576
|
const hasNewParams = nextParam != null || previousParam != null;
|
|
716
577
|
const [getNextPageParamExpr, getPreviousPageParamExpr] = (() => {
|
|
717
578
|
if (hasNewParams) {
|
|
@@ -936,23 +797,30 @@ function resolveContractClient(options) {
|
|
|
936
797
|
* (plugin-fetch or plugin-axios). Returns `null` when no contract plugin is in play (the inline
|
|
937
798
|
* path). The plugin injects `.kubb/client.ts` at the global output root, the same path consumers
|
|
938
799
|
* read `RequestConfig` / `ResponseErrorConfig` from.
|
|
800
|
+
*
|
|
801
|
+
* The result is cached in the current node's `cache` (`ctx.cache`) under the client plugin's name,
|
|
802
|
+
* so several dependents reading the same client plugin for one operation in a single pass
|
|
803
|
+
* (react-query's query/mutation/infinite generators, vue-query, swr, the MCP handler, ...) share
|
|
804
|
+
* one computed result instead of each re-deriving the name and path.
|
|
939
805
|
*/
|
|
940
806
|
function resolveClientOperation(options) {
|
|
941
|
-
const { clientPlugin, driver, node, root, output } = options;
|
|
807
|
+
const { clientPlugin, driver, node, root, output, cache } = options;
|
|
942
808
|
if (!clientPlugin) return null;
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
809
|
+
return cache.ensureItem(`${clientPlugin.pluginName}:clientOperation`, () => {
|
|
810
|
+
const resolver = driver.getResolver(clientPlugin.pluginName);
|
|
811
|
+
const plugin = driver.getPlugin(clientPlugin.pluginName);
|
|
812
|
+
const file = resolver.file({
|
|
813
|
+
...operationFileEntry(node, node.operationId),
|
|
814
|
+
root,
|
|
815
|
+
output: plugin?.options?.output ?? output,
|
|
816
|
+
group: plugin?.options?.group ?? void 0
|
|
817
|
+
});
|
|
818
|
+
return {
|
|
819
|
+
name: resolver.name(node.operationId),
|
|
820
|
+
path: file.path,
|
|
821
|
+
clientPath: path.resolve(root, ".kubb/client.ts")
|
|
822
|
+
};
|
|
950
823
|
});
|
|
951
|
-
return {
|
|
952
|
-
name: resolver.name(node.operationId),
|
|
953
|
-
path: file.path,
|
|
954
|
-
clientPath: path.resolve(root, ".kubb/client.ts")
|
|
955
|
-
};
|
|
956
824
|
}
|
|
957
825
|
//#endregion
|
|
958
826
|
//#region src/utils.ts
|
|
@@ -975,11 +843,7 @@ const declarationPrinter$4 = functionPrinter({ mode: "declaration" });
|
|
|
975
843
|
function buildQueryKeyParamsNode(node, options) {
|
|
976
844
|
const groupedParam = buildGroupedRequestParam(node, {
|
|
977
845
|
resolver: options.resolver,
|
|
978
|
-
keys:
|
|
979
|
-
"path",
|
|
980
|
-
"query",
|
|
981
|
-
"body"
|
|
982
|
-
],
|
|
846
|
+
keys: queryKeyGroupOrder,
|
|
983
847
|
memberTypeWrapper: maybeRefOrGetter
|
|
984
848
|
});
|
|
985
849
|
return createFunctionParameters({ params: groupedParam ? [groupedParam] : [] });
|
|
@@ -1030,11 +894,10 @@ function QueryOptions({ name, clientName, node, tsResolver, queryKeyName }) {
|
|
|
1030
894
|
const queryKeyParamsCall = callPrinter$3.print(queryKeyParamsNode) ?? "";
|
|
1031
895
|
const paramsNode = getQueryOptionsParams(node, { resolver: tsResolver });
|
|
1032
896
|
const paramsSignature = declarationPrinter$3.print(paramsNode) ?? "";
|
|
1033
|
-
const queryFnBody = `
|
|
897
|
+
const queryFnBody = `return ${buildVueClientCall(node, {
|
|
1034
898
|
clientName,
|
|
1035
899
|
signal: true
|
|
1036
|
-
})}
|
|
1037
|
-
return data`;
|
|
900
|
+
})}.unwrap()`;
|
|
1038
901
|
return /* @__PURE__ */ jsx(File.Source, {
|
|
1039
902
|
name,
|
|
1040
903
|
isExportable: true,
|
|
@@ -1076,10 +939,11 @@ function buildInfiniteQueryParamsNode(node, options) {
|
|
|
1076
939
|
}`,
|
|
1077
940
|
default: "{}"
|
|
1078
941
|
});
|
|
1079
|
-
|
|
942
|
+
const groupedParam = buildGroupedRequestParam(node, {
|
|
1080
943
|
resolver,
|
|
1081
944
|
memberTypeWrapper: maybeRefOrGetter
|
|
1082
|
-
})
|
|
945
|
+
});
|
|
946
|
+
return createFunctionParameters({ params: [groupedParam, optionsParam].filter((param) => param !== null) });
|
|
1083
947
|
}
|
|
1084
948
|
function InfiniteQuery({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, tsResolver }) {
|
|
1085
949
|
const { TData, TError } = buildResponseTypes(node, tsResolver);
|
|
@@ -1148,13 +1012,14 @@ function resolveMutationRequestType(node, resolver) {
|
|
|
1148
1012
|
function buildMutationParamsNode(node, options) {
|
|
1149
1013
|
const { resolver } = options;
|
|
1150
1014
|
const { TData, TError } = buildResponseTypes(node, resolver);
|
|
1015
|
+
const TRequest = resolveMutationRequestType(node, resolver);
|
|
1151
1016
|
return createFunctionParameters({ params: [createFunctionParameter({
|
|
1152
1017
|
name: "options",
|
|
1153
1018
|
type: `{
|
|
1154
1019
|
mutation?: MutationObserverOptions<${[
|
|
1155
1020
|
TData,
|
|
1156
1021
|
TError,
|
|
1157
|
-
|
|
1022
|
+
TRequest,
|
|
1158
1023
|
"TContext"
|
|
1159
1024
|
].join(", ")}> & { client?: QueryClient },
|
|
1160
1025
|
client?: ${buildRequestConfigType(node)},
|
|
@@ -1168,11 +1033,10 @@ function Mutation({ name, clientName, node, tsResolver, mutationKeyName }) {
|
|
|
1168
1033
|
const hasMutationParams = groupedParam !== null;
|
|
1169
1034
|
const groupedParamsNode = createFunctionParameters({ params: groupedParam ? [groupedParam] : [] });
|
|
1170
1035
|
const argBindingStr = hasMutationParams ? callPrinter$1.print(groupedParamsNode) ?? "" : "";
|
|
1171
|
-
const mutationFnBody = `
|
|
1036
|
+
const mutationFnBody = `return ${buildVueClientCall(node, {
|
|
1172
1037
|
clientName,
|
|
1173
1038
|
signal: false
|
|
1174
|
-
})}
|
|
1175
|
-
return data`;
|
|
1039
|
+
})}.unwrap()`;
|
|
1176
1040
|
const generics = [
|
|
1177
1041
|
TData,
|
|
1178
1042
|
TError,
|
|
@@ -1228,10 +1092,11 @@ function buildQueryParamsNode(node, options) {
|
|
|
1228
1092
|
}`,
|
|
1229
1093
|
default: "{}"
|
|
1230
1094
|
});
|
|
1231
|
-
|
|
1095
|
+
const groupedParam = buildGroupedRequestParam(node, {
|
|
1232
1096
|
resolver,
|
|
1233
1097
|
memberTypeWrapper: maybeRefOrGetter
|
|
1234
|
-
})
|
|
1098
|
+
});
|
|
1099
|
+
return createFunctionParameters({ params: [groupedParam, optionsParam].filter((param) => param !== null) });
|
|
1235
1100
|
}
|
|
1236
1101
|
function Query({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, tsResolver }) {
|
|
1237
1102
|
const { TData, TError } = buildResponseTypes(node, tsResolver);
|
|
@@ -1279,9 +1144,9 @@ function Query({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, t
|
|
|
1279
1144
|
//#region src/generators/infiniteQueryGenerator.tsx
|
|
1280
1145
|
/**
|
|
1281
1146
|
* Built-in generator for `useInfiniteQuery` composables. Enabled when
|
|
1282
|
-
* `pluginVueQuery({ infinite: { ... } })`. Emits one
|
|
1283
|
-
* composable per query operation, wiring the
|
|
1284
|
-
* TanStack Query's cursor-based pagination.
|
|
1147
|
+
* `pluginVueQuery({ infinite: { ... }, hooks: true })`. Emits one
|
|
1148
|
+
* `useFooInfiniteQuery` composable per query operation, wiring the
|
|
1149
|
+
* configured cursor path into TanStack Query's cursor-based pagination.
|
|
1285
1150
|
*/
|
|
1286
1151
|
const infiniteQueryGenerator = defineGenerator({
|
|
1287
1152
|
name: "vue-query-infinite",
|
|
@@ -1293,11 +1158,12 @@ const infiniteQueryGenerator = defineGenerator({
|
|
|
1293
1158
|
const pluginTs = driver.getPlugin(pluginTsName);
|
|
1294
1159
|
if (!pluginTs) return null;
|
|
1295
1160
|
const tsResolver = driver.getResolver(pluginTsName);
|
|
1296
|
-
const isQuery
|
|
1297
|
-
|
|
1298
|
-
|
|
1161
|
+
const { isQuery, isMutation } = classifyOperation(node, {
|
|
1162
|
+
query,
|
|
1163
|
+
mutation
|
|
1164
|
+
});
|
|
1299
1165
|
const infiniteOptions = infinite && typeof infinite === "object" ? infinite : null;
|
|
1300
|
-
if (!isQuery || isMutation || !infiniteOptions) return null;
|
|
1166
|
+
if (!isQuery || isMutation || !infiniteOptions || !hooks) return null;
|
|
1301
1167
|
const normalizeKey = (key) => key.replace(/\?$/, "");
|
|
1302
1168
|
const queryParamKeys = getOperationParameters(node).query.map((p) => p.name);
|
|
1303
1169
|
if (!(infiniteOptions.queryParam ? queryParamKeys.some((k) => normalizeKey(k) === infiniteOptions.queryParam) : false)) return null;
|
|
@@ -1307,7 +1173,8 @@ const infiniteQueryGenerator = defineGenerator({
|
|
|
1307
1173
|
driver,
|
|
1308
1174
|
node,
|
|
1309
1175
|
root,
|
|
1310
|
-
output
|
|
1176
|
+
output,
|
|
1177
|
+
cache: ctx.cache
|
|
1311
1178
|
});
|
|
1312
1179
|
if (!contractOp) return null;
|
|
1313
1180
|
const queryName = resolver.infiniteQuery.name(node);
|
|
@@ -1321,15 +1188,20 @@ const infiniteQueryGenerator = defineGenerator({
|
|
|
1321
1188
|
output,
|
|
1322
1189
|
group: group ?? void 0
|
|
1323
1190
|
}),
|
|
1324
|
-
fileTs:
|
|
1325
|
-
|
|
1191
|
+
fileTs: resolveDependencyOperationFile({
|
|
1192
|
+
cache: ctx.cache,
|
|
1193
|
+
node,
|
|
1194
|
+
resolver: tsResolver,
|
|
1326
1195
|
root,
|
|
1327
1196
|
output: pluginTs.options?.output ?? output,
|
|
1328
|
-
group: pluginTs.options?.group
|
|
1197
|
+
group: pluginTs.options?.group
|
|
1329
1198
|
})
|
|
1330
1199
|
};
|
|
1331
|
-
const
|
|
1332
|
-
|
|
1200
|
+
const { queryParamsTypeName } = resolvePageParamType(node, {
|
|
1201
|
+
resolver: tsResolver,
|
|
1202
|
+
initialPageParam: infiniteOptions.initialPageParam,
|
|
1203
|
+
queryParam: infiniteOptions.queryParam
|
|
1204
|
+
});
|
|
1333
1205
|
const importedTypeNames = [
|
|
1334
1206
|
tsResolver.response.options(node),
|
|
1335
1207
|
queryParamsTypeName,
|
|
@@ -1415,32 +1287,30 @@ const infiniteQueryGenerator = defineGenerator({
|
|
|
1415
1287
|
initialPageParam: infiniteOptions.initialPageParam,
|
|
1416
1288
|
queryParam: infiniteOptions.queryParam
|
|
1417
1289
|
}),
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
})
|
|
1443
|
-
] })
|
|
1290
|
+
/* @__PURE__ */ jsx(File.Import, {
|
|
1291
|
+
name: ["useInfiniteQuery"],
|
|
1292
|
+
path: importPath
|
|
1293
|
+
}),
|
|
1294
|
+
/* @__PURE__ */ jsx(File.Import, {
|
|
1295
|
+
name: [
|
|
1296
|
+
"QueryKey",
|
|
1297
|
+
"QueryClient",
|
|
1298
|
+
"UseInfiniteQueryOptions",
|
|
1299
|
+
"UseInfiniteQueryReturnType"
|
|
1300
|
+
],
|
|
1301
|
+
path: importPath,
|
|
1302
|
+
isTypeOnly: true
|
|
1303
|
+
}),
|
|
1304
|
+
/* @__PURE__ */ jsx(InfiniteQuery, {
|
|
1305
|
+
name: queryName,
|
|
1306
|
+
queryOptionsName,
|
|
1307
|
+
queryKeyName,
|
|
1308
|
+
queryKeyTypeName,
|
|
1309
|
+
node,
|
|
1310
|
+
tsResolver,
|
|
1311
|
+
initialPageParam: infiniteOptions.initialPageParam,
|
|
1312
|
+
queryParam: infiniteOptions.queryParam
|
|
1313
|
+
})
|
|
1444
1314
|
]
|
|
1445
1315
|
});
|
|
1446
1316
|
}
|
|
@@ -1462,16 +1332,19 @@ const mutationGenerator = defineGenerator({
|
|
|
1462
1332
|
const pluginTs = driver.getPlugin(pluginTsName);
|
|
1463
1333
|
if (!pluginTs) return null;
|
|
1464
1334
|
const tsResolver = driver.getResolver(pluginTsName);
|
|
1465
|
-
const
|
|
1466
|
-
|
|
1467
|
-
|
|
1335
|
+
const { isMutation } = classifyOperation(node, {
|
|
1336
|
+
query,
|
|
1337
|
+
mutation
|
|
1338
|
+
});
|
|
1339
|
+
if (!isMutation) return null;
|
|
1468
1340
|
const importPath = mutation ? mutation.importPath : "@tanstack/vue-query";
|
|
1469
1341
|
const contractOp = resolveClientOperation({
|
|
1470
1342
|
clientPlugin: { pluginName: client.pluginName },
|
|
1471
1343
|
driver,
|
|
1472
1344
|
node,
|
|
1473
1345
|
root,
|
|
1474
|
-
output
|
|
1346
|
+
output,
|
|
1347
|
+
cache: ctx.cache
|
|
1475
1348
|
});
|
|
1476
1349
|
if (!contractOp) return null;
|
|
1477
1350
|
const mutationHookName = resolver.mutation.name(node);
|
|
@@ -1484,11 +1357,13 @@ const mutationGenerator = defineGenerator({
|
|
|
1484
1357
|
output,
|
|
1485
1358
|
group: group ?? void 0
|
|
1486
1359
|
}),
|
|
1487
|
-
fileTs:
|
|
1488
|
-
|
|
1360
|
+
fileTs: resolveDependencyOperationFile({
|
|
1361
|
+
cache: ctx.cache,
|
|
1362
|
+
node,
|
|
1363
|
+
resolver: tsResolver,
|
|
1489
1364
|
root,
|
|
1490
1365
|
output: pluginTs.options?.output ?? output,
|
|
1491
|
-
group: pluginTs.options?.group
|
|
1366
|
+
group: pluginTs.options?.group
|
|
1492
1367
|
})
|
|
1493
1368
|
};
|
|
1494
1369
|
const importedTypeNames = [tsResolver.response.options(node), ...resolveOperationTypeNames(node, tsResolver, {
|
|
@@ -1590,9 +1465,10 @@ const queryGenerator = defineGenerator({
|
|
|
1590
1465
|
const pluginTs = driver.getPlugin(pluginTsName);
|
|
1591
1466
|
if (!pluginTs) return null;
|
|
1592
1467
|
const tsResolver = driver.getResolver(pluginTsName);
|
|
1593
|
-
const isQuery
|
|
1594
|
-
|
|
1595
|
-
|
|
1468
|
+
const { isQuery, isMutation } = classifyOperation(node, {
|
|
1469
|
+
query,
|
|
1470
|
+
mutation
|
|
1471
|
+
});
|
|
1596
1472
|
if (!isQuery || isMutation) return null;
|
|
1597
1473
|
const importPath = query ? query.importPath : "@tanstack/vue-query";
|
|
1598
1474
|
const contractOp = resolveClientOperation({
|
|
@@ -1600,7 +1476,8 @@ const queryGenerator = defineGenerator({
|
|
|
1600
1476
|
driver,
|
|
1601
1477
|
node,
|
|
1602
1478
|
root,
|
|
1603
|
-
output
|
|
1479
|
+
output,
|
|
1480
|
+
cache: ctx.cache
|
|
1604
1481
|
});
|
|
1605
1482
|
if (!contractOp) return null;
|
|
1606
1483
|
const queryName = resolver.query.name(node);
|
|
@@ -1614,11 +1491,13 @@ const queryGenerator = defineGenerator({
|
|
|
1614
1491
|
output,
|
|
1615
1492
|
group: group ?? void 0
|
|
1616
1493
|
}),
|
|
1617
|
-
fileTs:
|
|
1618
|
-
|
|
1494
|
+
fileTs: resolveDependencyOperationFile({
|
|
1495
|
+
cache: ctx.cache,
|
|
1496
|
+
node,
|
|
1497
|
+
resolver: tsResolver,
|
|
1619
1498
|
root,
|
|
1620
1499
|
output: pluginTs.options?.output ?? output,
|
|
1621
|
-
group: pluginTs.options?.group
|
|
1500
|
+
group: pluginTs.options?.group
|
|
1622
1501
|
})
|
|
1623
1502
|
};
|
|
1624
1503
|
const importedTypeNames = [tsResolver.response.options(node), ...resolveOperationTypeNames(node, tsResolver, {
|