@kubb/plugin-vue-query 5.0.0-beta.10 → 5.0.0-beta.101

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +22 -26
  2. package/dist/index.cjs +1649 -147
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.ts +358 -6
  5. package/dist/index.js +1620 -145
  6. package/dist/index.js.map +1 -1
  7. package/package.json +9 -32
  8. package/dist/components-B6jAb2as.js +0 -1150
  9. package/dist/components-B6jAb2as.js.map +0 -1
  10. package/dist/components-X0P-3W2G.cjs +0 -1264
  11. package/dist/components-X0P-3W2G.cjs.map +0 -1
  12. package/dist/components.cjs +0 -9
  13. package/dist/components.d.ts +0 -187
  14. package/dist/components.js +0 -2
  15. package/dist/generators-B33PbKzu.js +0 -681
  16. package/dist/generators-B33PbKzu.js.map +0 -1
  17. package/dist/generators-BE3KD0IR.cjs +0 -698
  18. package/dist/generators-BE3KD0IR.cjs.map +0 -1
  19. package/dist/generators.cjs +0 -5
  20. package/dist/generators.d.ts +0 -15
  21. package/dist/generators.js +0 -2
  22. package/dist/types-Bkm7bWT3.d.ts +0 -243
  23. package/extension.yaml +0 -732
  24. package/src/components/InfiniteQuery.tsx +0 -120
  25. package/src/components/InfiniteQueryOptions.tsx +0 -201
  26. package/src/components/Mutation.tsx +0 -148
  27. package/src/components/MutationKey.tsx +0 -1
  28. package/src/components/Query.tsx +0 -119
  29. package/src/components/QueryKey.tsx +0 -51
  30. package/src/components/QueryOptions.tsx +0 -134
  31. package/src/components/index.ts +0 -7
  32. package/src/generators/index.ts +0 -3
  33. package/src/generators/infiniteQueryGenerator.tsx +0 -194
  34. package/src/generators/mutationGenerator.tsx +0 -153
  35. package/src/generators/queryGenerator.tsx +0 -179
  36. package/src/index.ts +0 -2
  37. package/src/plugin.ts +0 -167
  38. package/src/resolvers/resolverVueQuery.ts +0 -65
  39. package/src/types.ts +0 -245
  40. package/src/utils.ts +0 -49
  41. /package/dist/{chunk--u3MIqq1.js → rolldown-runtime-C0LytTxp.js} +0 -0
package/dist/index.js CHANGED
@@ -1,146 +1,1644 @@
1
- import "./chunk--u3MIqq1.js";
2
- import { f as mutationKeyTransformer, p as camelCase, s as queryKeyTransformer } from "./components-B6jAb2as.js";
3
- import { n as mutationGenerator, r as infiniteQueryGenerator, t as queryGenerator } from "./generators-B33PbKzu.js";
1
+ import { t as __name } from "./rolldown-runtime-C0LytTxp.js";
2
+ import { Resolver, Url, ast, createResolver, defineGenerator, definePlugin } from "kubb/kit";
4
3
  import path from "node:path";
5
- import { ast, definePlugin, defineResolver } from "@kubb/core";
6
- import { pluginClientName } from "@kubb/plugin-client";
7
- import { source } from "@kubb/plugin-client/templates/clients/axios.source";
8
- import { source as source$1 } from "@kubb/plugin-client/templates/clients/fetch.source";
9
- import { source as source$2 } from "@kubb/plugin-client/templates/config.source";
10
- import { pluginTsName } from "@kubb/plugin-ts";
11
- import { pluginZodName } from "@kubb/plugin-zod";
12
- //#region src/resolvers/resolverVueQuery.ts
13
- function capitalize(name) {
14
- return `${name.charAt(0).toUpperCase()}${name.slice(1)}`;
4
+ import { createFunctionParameter, createFunctionParameters, createObjectBindingPattern, createTypeLiteral, functionPrinter, pluginTsName } from "@kubb/plugin-ts";
5
+ import { File, Function, Type, jsxRenderer } from "kubb/jsx";
6
+ import { Fragment, jsx, jsxs } from "kubb/jsx/jsx-runtime";
7
+ //#region ../../internals/shared/src/params.ts
8
+ /**
9
+ * Drops parameters that share the same name, keeping the first.
10
+ *
11
+ * A malformed spec can declare the same parameter name twice within one `in` location. Both would
12
+ * resolve to the same output property, so emitting both would yield an object type with a duplicate
13
+ * member, which TypeScript rejects. This is a defensive guard against that case, not a casing guard:
14
+ * parameter names flow through unchanged, so no two distinct names ever collide here anymore.
15
+ */
16
+ function dedupeParams(params) {
17
+ const seen = /* @__PURE__ */ new Set();
18
+ return params.filter((param) => {
19
+ if (seen.has(param.name)) return false;
20
+ seen.add(param.name);
21
+ return true;
22
+ });
23
+ }
24
+ //#endregion
25
+ //#region ../../internals/shared/src/operation.ts
26
+ /**
27
+ * Builds the `ResolverFileParams` every operation generator passes to
28
+ * `resolver.file`: a file named `name`, tagged by the operation's first
29
+ * tag (or `'default'`), at the operation's path. Centralizes the entry object
30
+ * that was repeated at dozens of call sites across the client and query plugins.
31
+ *
32
+ * @example
33
+ * ```ts
34
+ * resolver.file(operationFileEntry(node, node.operationId), { root, output, group })
35
+ * ```
36
+ */
37
+ function operationFileEntry(node, name, extname = ".ts") {
38
+ return {
39
+ name,
40
+ extname,
41
+ tag: node.tags[0] ?? "default",
42
+ path: node.path
43
+ };
44
+ }
45
+ function getOperationLink(node, link) {
46
+ if (!link) return null;
47
+ if (typeof link === "function") return link(node) ?? null;
48
+ return node.path ? `{@link ${Url.toPath(node.path)}}` : null;
49
+ }
50
+ /**
51
+ * Derives the shared `ContentTypeInfo` shape from a list of content types, tracking whether several
52
+ * are present and the union, default, and form-data flags the client uses to pick one.
53
+ */
54
+ function buildContentTypeInfo(contentTypes) {
55
+ const isMultipleContentTypes = contentTypes.length > 1;
56
+ return {
57
+ contentTypes,
58
+ isMultipleContentTypes,
59
+ contentTypeUnion: isMultipleContentTypes ? contentTypes.map((ct) => JSON.stringify(ct)).join(" | ") : "",
60
+ defaultContentType: contentTypes[0] ?? "application/json",
61
+ hasFormData: contentTypes.some((ct) => ct === "multipart/form-data")
62
+ };
63
+ }
64
+ function getContentTypeInfo(node) {
65
+ return buildContentTypeInfo(node.requestBody?.content?.map((e) => e.contentType) ?? []);
66
+ }
67
+ /**
68
+ * The request-body counterpart for the primary success response: the content types it documents and
69
+ * whether several are present, so the client can let a caller pick which one to accept.
70
+ */
71
+ function getResponseContentTypeInfo(node) {
72
+ return buildContentTypeInfo(getPrimarySuccessResponse(node)?.content?.map((e) => e.contentType) ?? []);
73
+ }
74
+ function buildRequestConfigType(node) {
75
+ const request = getContentTypeInfo(node);
76
+ const response = getResponseContentTypeInfo(node);
77
+ const configType = `Partial<Omit<RequestConfig, 'path' | 'query' | 'body' | 'headers' | 'url'>>`;
78
+ const members = [request.isMultipleContentTypes ? `request?: ${request.contentTypeUnion}` : null, response.isMultipleContentTypes ? `response?: ${response.contentTypeUnion}` : null].filter(Boolean);
79
+ return members.length ? `${configType} & { contentType?: { ${members.join("; ")} } }` : configType;
80
+ }
81
+ /**
82
+ * Builds the `client?:` option type shared by the generated query hooks (`useQuery`,
83
+ * `useInfiniteQuery`, `useSWR`, ...). Unlike {@link buildRequestConfigType}, it never adds a
84
+ * `contentType?:` member: query hooks wrap GET operations, which carry no request body to select a
85
+ * content type for.
86
+ */
87
+ function buildClientOptionType() {
88
+ return `Partial<Omit<RequestConfig, 'path' | 'query' | 'body' | 'headers' | 'url'>>`;
89
+ }
90
+ /**
91
+ * Which of the grouped request options an operation carries.
92
+ */
93
+ function getRequestGroups(node) {
94
+ const { path, query, header } = getOperationParameters(node);
95
+ return {
96
+ path: path.length > 0,
97
+ query: query.length > 0,
98
+ body: Boolean(node.requestBody?.content?.[0]?.schema),
99
+ headers: header.length > 0
100
+ };
101
+ }
102
+ /**
103
+ * Resolves which grouped request options an operation carries together with whether each group
104
+ * holds a required member. The grouped parameter stays optional only when nothing inside it is
105
+ * required, matching the generated `RequestConfig` type.
106
+ */
107
+ function getRequestGroupOptionality(node) {
108
+ const groups = getRequestGroups(node);
109
+ const { path, query, header } = getOperationParameters(node);
110
+ const hasRequiredPath = path.some((param) => param.required);
111
+ const hasRequiredQuery = query.some((param) => param.required);
112
+ const hasRequiredHeader = header.some((param) => param.required);
113
+ return {
114
+ groups,
115
+ hasRequiredPath,
116
+ hasRequiredQuery,
117
+ hasRequiredHeader,
118
+ isOptional: !hasRequiredPath && !hasRequiredQuery && !hasRequiredHeader && !groups.body
119
+ };
120
+ }
121
+ function buildOperationComments(node, options = {}) {
122
+ const { link = "pathTemplate", linkPosition = "afterDeprecated", splitLines = false } = options;
123
+ const linkComment = getOperationLink(node, link);
124
+ const filteredComments = (linkPosition === "beforeDeprecated" ? [
125
+ node.description && `@description ${node.description}`,
126
+ node.summary && `@summary ${node.summary}`,
127
+ linkComment,
128
+ node.deprecated && "@deprecated"
129
+ ] : [
130
+ node.description && `@description ${node.description}`,
131
+ node.summary && `@summary ${node.summary}`,
132
+ node.deprecated && "@deprecated",
133
+ linkComment
134
+ ]).filter((comment) => Boolean(comment));
135
+ if (!splitLines) return filteredComments;
136
+ return filteredComments.flatMap((text) => text.split(/\r?\n/).map((line) => line.trim())).filter((comment) => Boolean(comment));
137
+ }
138
+ function getOperationParameters(node) {
139
+ return {
140
+ path: dedupeParams(node.parameters.filter((param) => param.in === "path")),
141
+ query: dedupeParams(node.parameters.filter((param) => param.in === "query")),
142
+ header: dedupeParams(node.parameters.filter((param) => param.in === "header")),
143
+ cookie: dedupeParams(node.parameters.filter((param) => param.in === "cookie"))
144
+ };
145
+ }
146
+ function getStatusCodeNumber(statusCode) {
147
+ const code = Number(statusCode);
148
+ return Number.isNaN(code) ? null : code;
149
+ }
150
+ function isSuccessStatusCode(statusCode) {
151
+ const code = getStatusCodeNumber(statusCode);
152
+ return code !== null && code >= 200 && code < 300;
153
+ }
154
+ function isErrorStatusCode(statusCode) {
155
+ const code = getStatusCodeNumber(statusCode);
156
+ return code !== null && code >= 400;
157
+ }
158
+ function getSuccessResponses(responses) {
159
+ return responses.filter((response) => isSuccessStatusCode(response.statusCode));
160
+ }
161
+ function getOperationSuccessResponses(node) {
162
+ return getSuccessResponses(node.responses);
163
+ }
164
+ function getPrimarySuccessResponse(node) {
165
+ return getOperationSuccessResponses(node)[0] ?? null;
166
+ }
167
+ function resolveErrorNames(node, resolver) {
168
+ return node.responses.filter((response) => isErrorStatusCode(response.statusCode)).map((response) => resolver.response.status(node, response.statusCode));
169
+ }
170
+ function resolveSuccessNames(node, resolver) {
171
+ return node.responses.filter((response) => isSuccessStatusCode(response.statusCode)).map((response) => resolver.response.status(node, response.statusCode));
172
+ }
173
+ function resolveStatusCodeNames(node, resolver) {
174
+ return node.responses.map((response) => resolver.response.status(node, response.statusCode));
175
+ }
176
+ const typeNamesByResolver = /* @__PURE__ */ new WeakMap();
177
+ function resolveOperationTypeNames(node, resolver, options = {}) {
178
+ const cacheKey = `${node.operationId}\0${options.order ?? ""}\0${options.responseStatusNames ?? ""}\0${options.includeParams === false ? "noparams" : ""}\0${(options.exclude ?? []).join(",")}`;
179
+ let byResolver = typeNamesByResolver.get(resolver);
180
+ if (byResolver) {
181
+ const cached = byResolver.get(cacheKey);
182
+ if (cached) return cached;
183
+ } else {
184
+ byResolver = /* @__PURE__ */ new Map();
185
+ typeNamesByResolver.set(resolver, byResolver);
186
+ }
187
+ const { path, query, header } = getOperationParameters(node);
188
+ const responseStatusNames = options.responseStatusNames === "error" ? resolveErrorNames(node, resolver) : options.responseStatusNames === false ? [] : resolveStatusCodeNames(node, resolver);
189
+ const exclude = new Set(options.exclude ?? []);
190
+ const paramNames = options.includeParams === false ? [] : [
191
+ ...path.map((param) => resolver.param.path(node, param)),
192
+ ...query.map((param) => resolver.param.query(node, param)),
193
+ ...header.map((param) => resolver.param.headers(node, param))
194
+ ];
195
+ const bodyAndResponseNames = [node.requestBody?.content?.[0]?.schema ? resolver.response.body(node) : null, resolver.response.response(node)];
196
+ const result = (options.order === "body-response-first" ? [
197
+ ...bodyAndResponseNames,
198
+ ...paramNames,
199
+ ...responseStatusNames
200
+ ] : [
201
+ ...paramNames,
202
+ ...bodyAndResponseNames,
203
+ ...responseStatusNames
204
+ ]).filter((name) => Boolean(name) && !exclude.has(name));
205
+ byResolver.set(cacheKey, result);
206
+ return result;
207
+ }
208
+ //#endregion
209
+ //#region ../../internals/utils/src/casing.ts
210
+ /**
211
+ * Shared implementation for camelCase and PascalCase conversion.
212
+ * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)
213
+ * and capitalizes each word according to `pascal`.
214
+ *
215
+ * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
216
+ */
217
+ function toCamelOrPascal(text, pascal) {
218
+ 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) => {
219
+ if (word.length > 1 && word === word.toUpperCase()) return word;
220
+ return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
221
+ }).join("").replace(/[^a-zA-Z0-9]/g, "");
222
+ }
223
+ /**
224
+ * Converts `text` to camelCase.
225
+ *
226
+ * @example Word boundaries
227
+ * `camelCase('hello-world') // 'helloWorld'`
228
+ *
229
+ * @example With a prefix
230
+ * `camelCase('tag', { prefix: 'create' }) // 'createTag'`
231
+ */
232
+ function camelCase(text, { prefix = "", suffix = "" } = {}) {
233
+ return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
234
+ }
235
+ /**
236
+ * Uppercases only the first character of `text`, leaving the rest untouched.
237
+ * Unlike {@link pascalCase} it never re-splits word boundaries or strips characters.
238
+ *
239
+ * @example
240
+ * `capitalize('getPetById') // 'GetPetById'`
241
+ */
242
+ function capitalize(text) {
243
+ return `${text.charAt(0).toUpperCase()}${text.slice(1)}`;
244
+ }
245
+ //#endregion
246
+ //#region ../../internals/utils/src/strings.ts
247
+ /**
248
+ * Renders a dotted path or string array as an optional-chaining accessor expression rooted at
249
+ * `accessor`. Returns `null` for an empty path.
250
+ *
251
+ * @example
252
+ * ```ts
253
+ * getNestedAccessor('pagination.next.id', 'lastPage')
254
+ * // "lastPage?.['pagination']?.['next']?.['id']"
255
+ * ```
256
+ */
257
+ function getNestedAccessor(param, accessor) {
258
+ const parts = Array.isArray(param) ? param : param.split(".");
259
+ if (parts.length === 0 || parts.length === 1 && parts[0] === "") return null;
260
+ return `${accessor}?.['${`${parts.join("']?.['")}']`}`;
261
+ }
262
+ //#endregion
263
+ //#region ../../internals/shared/src/group.ts
264
+ /**
265
+ * Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the
266
+ * shared default naming so every plugin groups output consistently:
267
+ *
268
+ * - `path` groups use the second path segment (`/pet/findByStatus` → `pet`).
269
+ * - other groups use the camelCased group (`pet store` → `petStore`).
270
+ *
271
+ * A user-provided `group.name` always wins over the default namer, so callers stay in
272
+ * control of their output folders. Returns `null` when grouping is disabled, matching the
273
+ * per-plugin convention.
274
+ *
275
+ * @param group - The user-supplied group option, or `undefined` to disable grouping.
276
+ *
277
+ * @example
278
+ * ```ts
279
+ * createGroupConfig(group) // shared across every plugin
280
+ * ```
281
+ */
282
+ function createGroupConfig(group) {
283
+ if (!group) return null;
284
+ const defaultName = (ctx) => {
285
+ if (group.type === "path") return `${ctx.group.split("/")[1]}`;
286
+ return camelCase(ctx.group);
287
+ };
288
+ return {
289
+ ...group,
290
+ name: group.name ? group.name : defaultName
291
+ };
292
+ }
293
+ //#endregion
294
+ //#region ../../internals/tanstack-query/src/utils.ts
295
+ /**
296
+ * The grouped request options, ordered for both the destructured signature and the
297
+ * call passed to the underlying client.
298
+ */
299
+ const requestGroupOrder = [
300
+ "path",
301
+ "query",
302
+ "body",
303
+ "headers"
304
+ ];
305
+ /**
306
+ * Widens a request-group member type so a generated TanStack hook accepts either the value or a
307
+ * deferred value. Both plugins apply this through the `memberTypeWrapper` of `buildGroupedRequestParam`;
308
+ * they only differ in how the deferred form is later resolved.
309
+ *
310
+ * `maybeRefOrGetter` is used by vue-query, which keeps the ref/getter live and unwraps it lazily with
311
+ * `toValue` because vue-query keys are reactive. `maybeValueOrGetter` is used by react-query, which
312
+ * resolves the getter once at the hook boundary and forwards a plain value because React Query hashes
313
+ * keys structurally and cannot hold a function.
314
+ */
315
+ function maybeRefOrGetter(type) {
316
+ return `MaybeRefOrGetter<${type}>`;
317
+ }
318
+ /**
319
+ * Builds the grouped `{ path, query, body, headers }` parameter that mirrors the client
320
+ * function signature. Only the groups the operation carries are emitted, typed from the
321
+ * operation's `Options`. `keys` narrows the emitted groups, used by the query key which
322
+ * never carries `headers`.
323
+ *
324
+ * By default the whole group is typed as the single `Options` reference. When
325
+ * `memberTypeWrapper` is set, each group is emitted as its own member typed from the matching
326
+ * `Options['<group>']` slice and wrapped, used by vue-query to apply
327
+ * `MaybeRefOrGetter` per group.
328
+ */
329
+ function buildGroupedRequestParam(node, options) {
330
+ const { resolver, keys = requestGroupOrder, memberTypeWrapper } = options;
331
+ const { groups, hasRequiredPath, hasRequiredQuery, hasRequiredHeader } = getRequestGroupOptionality(node);
332
+ const names = keys.filter((key) => groups[key]);
333
+ if (names.length === 0) return null;
334
+ const requiredByGroup = {
335
+ path: hasRequiredPath,
336
+ query: hasRequiredQuery,
337
+ body: groups.body,
338
+ headers: hasRequiredHeader
339
+ };
340
+ const isOptional = names.every((name) => !requiredByGroup[name]);
341
+ const optionsName = resolver.response.options(node);
342
+ const omittedKeys = requestGroupOrder.filter((key) => !keys.includes(key));
343
+ const optionsType = omittedKeys.length > 0 ? `Omit<${optionsName}, ${omittedKeys.map((key) => `'${key}'`).join(" | ")}>` : optionsName;
344
+ if (memberTypeWrapper) {
345
+ const members = names.map((name) => ({
346
+ name,
347
+ type: memberTypeWrapper(`${optionsType}['${name}']`),
348
+ optional: !requiredByGroup[name]
349
+ }));
350
+ return createFunctionParameter({
351
+ name: createObjectBindingPattern({ elements: names.map((name) => ({ name })) }),
352
+ type: createTypeLiteral({ members }),
353
+ optional: false,
354
+ ...isOptional ? { default: "{}" } : {}
355
+ });
356
+ }
357
+ return createFunctionParameter({
358
+ name: createObjectBindingPattern({ elements: names.map((name) => ({ name })) }),
359
+ type: optionsType,
360
+ optional: false,
361
+ ...isOptional ? { default: "{}" } : {}
362
+ });
363
+ }
364
+ /**
365
+ * Builds the shared `({ path, query, body, headers }, config = {})` parameter list for a
366
+ * TanStack query-options function. The leading parameter mirrors the client signature, and the
367
+ * trailing `config` is a partial `RequestConfig` minus the grouped data-shape keys, which are passed
368
+ * explicitly. Framework plugins wrap the result when needed, for example vue-query applies `MaybeRefOrGetter`.
369
+ */
370
+ function buildQueryOptionsParams(node, options) {
371
+ const { resolver, memberTypeWrapper } = options;
372
+ return createFunctionParameters({ params: [buildGroupedRequestParam(node, {
373
+ resolver,
374
+ memberTypeWrapper
375
+ }), createFunctionParameter({
376
+ name: "config",
377
+ type: `Partial<Omit<RequestConfig, 'path' | 'query' | 'body' | 'headers' | 'url'>>`,
378
+ default: "{}"
379
+ })].filter((param) => param !== null) });
380
+ }
381
+ /**
382
+ * Builds the call to a client `<op>` function inside a query/mutation hook body. The function takes
383
+ * a single grouped options object, so the operation's request groups are passed as
384
+ * shorthand alongside the spread `config`, with `throwOnError: true` pinned last so a caller's config
385
+ * can't flip the query's error semantics. Queries thread the TanStack `signal`; mutations omit it.
386
+ *
387
+ * When `unwrapName` is set, each request group is passed as an explicit member unwrapped through it,
388
+ * used by vue-query to resolve refs and getters with `toValue(...)` at call time.
389
+ *
390
+ * @example
391
+ * ```ts
392
+ * buildClientCall(node, { clientName: 'getPetById', signal: true })
393
+ * // getPetById({ path, ...config, signal: config.signal ?? signal, throwOnError: true })
394
+ * ```
395
+ */
396
+ function buildClientCall(node, options) {
397
+ const { clientName, signal = false, unwrapName } = options;
398
+ const { groups } = getRequestGroupOptionality(node);
399
+ return `${clientName}({ ${[
400
+ "...config",
401
+ ...requestGroupOrder.filter((key) => groups[key]).map((name) => unwrapName ? `${name}: ${unwrapName(name)}` : name),
402
+ signal ? "signal: config.signal ?? signal" : null,
403
+ "throwOnError: true"
404
+ ].filter((part) => part !== null).join(", ")} })`;
405
+ }
406
+ /**
407
+ * Builds the `TData` / `TError` type expressions shared by every generated hook, joining the resolved
408
+ * success responses into `TData` and wrapping the error responses in `ResponseErrorConfig<...>`.
409
+ */
410
+ function buildResponseTypes(node, resolver) {
411
+ const successNames = resolveSuccessNames(node, resolver);
412
+ const responseName = successNames.length > 0 ? successNames.join(" | ") : resolver.response.response(node);
413
+ const errorNames = resolveErrorNames(node, resolver);
414
+ return {
415
+ TData: responseName,
416
+ TError: `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(" | ") : "Error"}>`
417
+ };
418
+ }
419
+ function resolveFallbackPageParamType(initialPageParam) {
420
+ if (typeof initialPageParam === "number") return "number";
421
+ if (typeof initialPageParam === "boolean") return "boolean";
422
+ if (typeof initialPageParam !== "string") return "unknown";
423
+ if (!initialPageParam.includes(" as ")) return "string";
424
+ return initialPageParam.split(" as ").at(-1) ?? "unknown";
425
+ }
426
+ /**
427
+ * Resolves the `TPageParam` generic for the infinite-query hooks. Prefers the type read from the
428
+ * configured `queryParam` on the operation's query object, and falls back to the type inferred from
429
+ * `initialPageParam` when that parameter type is unavailable. Also returns the query params type name
430
+ * so callers can reuse it when rewriting the paginated request.
431
+ */
432
+ function resolvePageParamType(node, { resolver, initialPageParam, queryParam }) {
433
+ const firstQueryParam = getOperationParameters(node).query[0];
434
+ const groupName = firstQueryParam ? resolver.param.query(node, firstQueryParam) : null;
435
+ const queryParamsTypeName = groupName !== (firstQueryParam ? resolver.param.name(node, firstQueryParam) : null) ? groupName : null;
436
+ const queryParamType = queryParam && queryParamsTypeName ? `${queryParamsTypeName}['${queryParam}']` : null;
437
+ if (!queryParamType) return {
438
+ queryParamsTypeName,
439
+ pageParamType: resolveFallbackPageParamType(initialPageParam)
440
+ };
441
+ return {
442
+ queryParamsTypeName,
443
+ pageParamType: initialPageParam !== void 0 && initialPageParam !== null ? `NonNullable<${queryParamType}>` : queryParamType
444
+ };
445
+ }
446
+ /**
447
+ * Applies the shared query defaults during plugin setup: `false` disables query generation, and an
448
+ * object merges over `methods: ['GET']` and the plugin's runtime `importPath`.
449
+ */
450
+ function resolveQueryConfig(query, options) {
451
+ if (query === false) return false;
452
+ return {
453
+ importPath: options.importPath,
454
+ methods: ["GET"],
455
+ ...query
456
+ };
457
+ }
458
+ /**
459
+ * Applies the shared mutation defaults during plugin setup: `false` disables mutation generation,
460
+ * and an object merges over `methods: ['POST', 'PUT', 'PATCH', 'DELETE']` and the plugin's runtime
461
+ * `importPath`.
462
+ */
463
+ function resolveMutationConfig(mutation, options) {
464
+ if (mutation === false) return false;
465
+ return {
466
+ importPath: options.importPath,
467
+ methods: [
468
+ "POST",
469
+ "PUT",
470
+ "PATCH",
471
+ "DELETE"
472
+ ],
473
+ ...mutation
474
+ };
475
+ }
476
+ /**
477
+ * Classifies an operation as a query or a mutation from the resolved `query` / `mutation` method lists.
478
+ * `query: false` still marks the operation as a query so the query-family generators keep matching it,
479
+ * and a method already claimed by `query` never counts as a mutation.
480
+ */
481
+ function classifyOperation(node, { query, mutation }) {
482
+ const isQuery = query === false || !!query && query.methods.some((method) => node.method.toLowerCase() === method.toLowerCase());
483
+ const queryMethods = new Set(query ? query.methods : []);
484
+ return {
485
+ isQuery,
486
+ isMutation: mutation !== false && !isQuery && (mutation ? mutation.methods : []).some((method) => !queryMethods.has(method) && node.method.toLowerCase() === method.toLowerCase())
487
+ };
488
+ }
489
+ /**
490
+ * Applies the shared infinite-query defaults during plugin setup: a falsy value disables infinite
491
+ * queries, and an object merges over `queryParam: 'id'` and `initialPageParam: 0` with the cursor
492
+ * paths cleared.
493
+ */
494
+ function resolveInfiniteConfig(infinite) {
495
+ if (!infinite) return false;
496
+ return {
497
+ queryParam: "id",
498
+ initialPageParam: 0,
499
+ cursorParam: null,
500
+ nextParam: null,
501
+ previousParam: null,
502
+ ...infinite
503
+ };
504
+ }
505
+ //#endregion
506
+ //#region ../../internals/tanstack-query/src/components/InfiniteQueryOptions.tsx
507
+ const declarationPrinter$7 = functionPrinter({ mode: "declaration" });
508
+ const callPrinter$4 = functionPrinter({ mode: "call" });
509
+ function InfiniteQueryOptions$1({ name, clientName, initialPageParam, cursorParam, nextParam, previousParam, node, tsResolver, queryParam, queryKeyName, queryKeyType = "typeof queryKey", memberTypeWrapper, unwrapName }) {
510
+ const { TData: queryFnDataType, TError: errorType } = buildResponseTypes(node, tsResolver);
511
+ const { queryParamsTypeName, pageParamType } = resolvePageParamType(node, {
512
+ resolver: tsResolver,
513
+ initialPageParam,
514
+ queryParam
515
+ });
516
+ const groupedKeyParam = buildGroupedRequestParam(node, {
517
+ resolver: tsResolver,
518
+ keys: [
519
+ "path",
520
+ "query",
521
+ "body"
522
+ ],
523
+ memberTypeWrapper
524
+ });
525
+ const queryKeyParamsNode = createFunctionParameters({ params: groupedKeyParam ? [groupedKeyParam] : [] });
526
+ const queryKeyParamsCall = callPrinter$4.print(queryKeyParamsNode) ?? "";
527
+ const paramsNode = buildQueryOptionsParams(node, {
528
+ resolver: tsResolver,
529
+ memberTypeWrapper
530
+ });
531
+ const paramsSignature = declarationPrinter$7.print(paramsNode) ?? "";
532
+ const queryFnBody = `const { data } = await ${buildClientCall(node, {
533
+ clientName,
534
+ signal: true,
535
+ unwrapName
536
+ })}
537
+ return data`;
538
+ const hasNewParams = nextParam != null || previousParam != null;
539
+ const [getNextPageParamExpr, getPreviousPageParamExpr] = (() => {
540
+ if (hasNewParams) {
541
+ const nextAccessor = nextParam ? getNestedAccessor(nextParam, "lastPage") : null;
542
+ const prevAccessor = previousParam ? getNestedAccessor(previousParam, "firstPage") : null;
543
+ return [nextAccessor ? `getNextPageParam: (lastPage) => ${nextAccessor}` : null, prevAccessor ? `getPreviousPageParam: (firstPage) => ${prevAccessor}` : null];
544
+ }
545
+ if (cursorParam) return [`getNextPageParam: (lastPage) => lastPage['${cursorParam}']`, `getPreviousPageParam: (firstPage) => firstPage['${cursorParam}']`];
546
+ return ["getNextPageParam: (lastPage, _allPages, lastPageParam) => Array.isArray(lastPage) && lastPage.length === 0 ? undefined : lastPageParam + 1", "getPreviousPageParam: (_firstPage, _allPages, firstPageParam) => firstPageParam <= 1 ? undefined : firstPageParam - 1"];
547
+ })();
548
+ const queryOptionsArr = [
549
+ `initialPageParam: ${typeof initialPageParam === "string" ? JSON.stringify(initialPageParam) : initialPageParam}`,
550
+ getNextPageParamExpr,
551
+ getPreviousPageParamExpr
552
+ ].filter(Boolean);
553
+ const infiniteOverrideParams = queryParam && queryParamsTypeName ? `query = {
554
+ ...(query ?? {}),
555
+ ['${queryParam}']: pageParam as unknown as ${queryParamsTypeName}['${queryParam}'],
556
+ } as ${queryParamsTypeName}` : "";
557
+ const queryFnArgs = infiniteOverrideParams ? "{ signal, pageParam }" : "{ signal }";
558
+ const queryFnStatements = infiniteOverrideParams ? `${infiniteOverrideParams}\n ${queryFnBody}` : queryFnBody;
559
+ return /* @__PURE__ */ jsx(File.Source, {
560
+ name,
561
+ isExportable: true,
562
+ isIndexable: true,
563
+ children: /* @__PURE__ */ jsx(Function, {
564
+ name,
565
+ export: true,
566
+ params: paramsSignature,
567
+ children: `
568
+ const queryKey = ${queryKeyName}(${queryKeyParamsCall})
569
+ return infiniteQueryOptions<${queryFnDataType}, ${errorType}, InfiniteData<${queryFnDataType}>, ${queryKeyType}, ${pageParamType}>({
570
+ queryKey,
571
+ queryFn: async (${queryFnArgs}) => {
572
+ ${queryFnStatements}
573
+ },
574
+ ${queryOptionsArr.join(",\n ")}
575
+ })
576
+ `
577
+ })
578
+ });
579
+ }
580
+ __name(InfiniteQueryOptions$1, "InfiniteQueryOptions");
581
+ //#endregion
582
+ //#region ../../internals/tanstack-query/src/components/MutationKey.tsx
583
+ const declarationPrinter$6 = functionPrinter({ mode: "declaration" });
584
+ const mutationKeyTransformer = ({ node }) => {
585
+ if (!node.path) return [];
586
+ return [`{ url: '${Url.toPath(node.path)}' }`];
587
+ };
588
+ function MutationKey({ name, node, transformer }) {
589
+ const paramsNode = createFunctionParameters({ params: [] });
590
+ const paramsSignature = declarationPrinter$6.print(paramsNode) ?? "";
591
+ const keys = (transformer ?? mutationKeyTransformer)({
592
+ node,
593
+ casing: "camelcase"
594
+ });
595
+ return /* @__PURE__ */ jsx(File.Source, {
596
+ name,
597
+ isExportable: true,
598
+ isIndexable: true,
599
+ children: /* @__PURE__ */ jsx(Function.Arrow, {
600
+ name,
601
+ export: true,
602
+ params: paramsSignature,
603
+ singleLine: true,
604
+ children: `[${keys.join(", ")}] as const`
605
+ })
606
+ });
607
+ }
608
+ //#endregion
609
+ //#region ../../internals/tanstack-query/src/resolver.ts
610
+ /**
611
+ * Builds the shared query namespace for a variant. Spread the result into
612
+ * `createResolver` once per variant the plugin supports.
613
+ *
614
+ * @example
615
+ * ```ts
616
+ * createResolver<PluginReactQuery>({
617
+ * query: createQueryResolver(),
618
+ * suspenseQuery: createQueryResolver('Suspense'),
619
+ * })
620
+ * ```
621
+ */
622
+ function createQueryResolver(variant = "") {
623
+ return {
624
+ name(node) {
625
+ return `use${capitalize(this.name(node.operationId))}${variant}`;
626
+ },
627
+ optionsName(node) {
628
+ return `${this.name(node.operationId)}${variant}QueryOptions`;
629
+ },
630
+ keyName(node) {
631
+ return `${this.name(node.operationId)}${variant}QueryKey`;
632
+ },
633
+ keyTypeName(node) {
634
+ return `${capitalize(this.name(node.operationId))}${variant}QueryKey`;
635
+ },
636
+ clientName(node) {
637
+ return `${this.name(node.operationId)}${variant}`;
638
+ }
639
+ };
640
+ }
641
+ /**
642
+ * Builds the shared mutation namespace. Spread the result into
643
+ * `createResolver` and add plugin-specific methods (`optionsName`,
644
+ * `typeName`, `argTypeName`) next to it.
645
+ *
646
+ * @example
647
+ * ```ts
648
+ * createResolver<PluginSwr>({ mutation: { ...createMutationResolver(), argTypeName(node) {...} } })
649
+ * ```
650
+ */
651
+ function createMutationResolver() {
652
+ return {
653
+ name(node) {
654
+ return `use${capitalize(this.name(node.operationId))}`;
655
+ },
656
+ keyName(node) {
657
+ return `${this.name(node.operationId)}MutationKey`;
658
+ }
659
+ };
660
+ }
661
+ functionPrinter({ mode: "declaration" });
662
+ const queryKeyTransformer = ({ node }) => {
663
+ if (!node.path) return [];
664
+ const hasPathParams = getOperationParameters(node).path.length > 0;
665
+ const hasQueryParams = getOperationParameters(node).query.length > 0;
666
+ const hasRequestBody = !!node.requestBody?.content?.[0]?.schema;
667
+ return [
668
+ hasPathParams ? `{ url: '${Url.toPath(node.path)}', params: path }` : `{ url: '${Url.toPath(node.path)}' }`,
669
+ hasQueryParams ? "...(query ? [query] : [])" : null,
670
+ hasRequestBody ? "...(body ? [body] : [])" : null
671
+ ].filter(Boolean);
672
+ };
673
+ //#endregion
674
+ //#region ../../internals/client/src/resolveClient.ts
675
+ /**
676
+ * Resolves which client plugin a consumer (react-query, vue-query, swr, mcp) should call for an
677
+ * operation, shared so the selection rules and diagnostics stay in one place.
678
+ *
679
+ * Every client runtime lives in a dedicated client plugin, so a consumer always calls a registered
680
+ * contract client plugin (plugin-fetch or plugin-axios) and never emits its own inline client:
681
+ *
682
+ * - `contract` — a registered contract client plugin owns the `<op>` functions and the consumer
683
+ * imports and calls them.
684
+ * - `error` — no client plugin is registered, several are registered without a selector, or the
685
+ * requested one is missing.
686
+ *
687
+ * The `client` string selects explicitly (`'fetch'` / `'axios'`); when it is unset a lone registered
688
+ * contract client plugin is picked up automatically.
689
+ */
690
+ const pluginFetchName = "plugin-fetch";
691
+ const pluginAxiosName = "plugin-axios";
692
+ const selectorToPlugin = {
693
+ fetch: pluginFetchName,
694
+ axios: pluginAxiosName
695
+ };
696
+ const contractPlugins = [pluginFetchName, pluginAxiosName];
697
+ /**
698
+ * Applies the `client` resolution rules. See the module comment for the strategy shape.
699
+ *
700
+ * @example
701
+ * ```ts
702
+ * resolveClient({ client: 'fetch', pluginNames: ['plugin-ts', 'plugin-fetch'] })
703
+ * // { kind: 'contract', pluginName: 'plugin-fetch' }
704
+ * ```
705
+ *
706
+ * @example
707
+ * ```ts
708
+ * resolveClient({ client: undefined, pluginNames: ['plugin-ts'] })
709
+ * // { kind: 'error', message: 'No client plugin is registered…' }
710
+ * ```
711
+ */
712
+ function resolveClient(options) {
713
+ const { client, pluginNames } = options;
714
+ const has = (name) => pluginNames.includes(name);
715
+ if (client === "fetch" || client === "axios") {
716
+ const pluginName = selectorToPlugin[client];
717
+ if (!has(pluginName)) return {
718
+ kind: "error",
719
+ message: `\`client: '${client}'\` is set but \`@kubb/plugin-${client}\` is not registered in \`plugins\`. Add it, or drop \`client\` to use a different client plugin.`
720
+ };
721
+ return {
722
+ kind: "contract",
723
+ pluginName
724
+ };
725
+ }
726
+ const registered = contractPlugins.filter(has);
727
+ if (registered.length === 1) return {
728
+ kind: "contract",
729
+ pluginName: registered[0]
730
+ };
731
+ if (registered.length > 1) return {
732
+ kind: "error",
733
+ message: `Multiple client plugins are registered (${registered.map((name) => `\`@kubb/${name}\``).join(", ")}). Set \`client: 'fetch' | 'axios'\` to choose which client the hooks call, or register a single client plugin.`
734
+ };
735
+ return {
736
+ kind: "error",
737
+ message: "No client plugin is registered. Add `@kubb/plugin-axios` or `@kubb/plugin-fetch` to `plugins` so the generated code has an HTTP client to call."
738
+ };
739
+ }
740
+ /**
741
+ * Resolves the contract client during a consumer plugin's setup hook. Extracts the plugin names
742
+ * from the raw `plugins` config, applies {@link resolveClient}, and throws the diagnostic on a
743
+ * misconfiguration so every consumer fails fast with the same message.
744
+ */
745
+ function resolveContractClient(options) {
746
+ const { client, plugins = [] } = options;
747
+ const resolved = resolveClient({
748
+ client,
749
+ pluginNames: plugins.map((plugin) => plugin.name).filter((name) => Boolean(name))
750
+ });
751
+ if (resolved.kind === "error") throw new Error(resolved.message);
752
+ return resolved;
753
+ }
754
+ //#endregion
755
+ //#region ../../internals/client/src/resolveClientOperation.ts
756
+ /**
757
+ * Resolves the contract client `<op>` a consumer (query hook, MCP handler) imports, by looking up
758
+ * the registered contract client plugin's resolver and output. Works for any contract client plugin
759
+ * (plugin-fetch or plugin-axios). Returns `null` when no contract plugin is in play (the inline
760
+ * path). The plugin injects `.kubb/client.ts` at the global output root, the same path consumers
761
+ * read `RequestConfig` / `ResponseErrorConfig` from.
762
+ */
763
+ function resolveClientOperation(options) {
764
+ const { clientPlugin, driver, node, root, output } = options;
765
+ if (!clientPlugin) return null;
766
+ const resolver = driver.getResolver(clientPlugin.pluginName);
767
+ const plugin = driver.getPlugin(clientPlugin.pluginName);
768
+ const file = resolver.file({
769
+ ...operationFileEntry(node, node.operationId),
770
+ root,
771
+ output: plugin?.options?.output ?? output,
772
+ group: plugin?.options?.group ?? void 0
773
+ });
774
+ return {
775
+ name: resolver.name(node.operationId),
776
+ path: file.path,
777
+ clientPath: path.resolve(root, ".kubb/client.ts")
778
+ };
779
+ }
780
+ //#endregion
781
+ //#region src/utils.ts
782
+ /**
783
+ * Builds the call to a contract client `<op>` function inside a vue-query composable body. The
784
+ * function takes a single grouped options object, so `config` is spread first, then the operation's
785
+ * request groups are unwrapped with `toValue()`, then the abort `signal` for queries, with
786
+ * `throwOnError: true` pinned last so a caller's config can't flip the query's error semantics.
787
+ * Mutations omit the `signal`.
788
+ */
789
+ function buildVueClientCall(node, options) {
790
+ return buildClientCall(node, {
791
+ ...options,
792
+ unwrapName: (name) => `toValue(${name})`
793
+ });
794
+ }
795
+ //#endregion
796
+ //#region src/components/QueryKey.tsx
797
+ const declarationPrinter$4 = functionPrinter({ mode: "declaration" });
798
+ function buildQueryKeyParamsNode(node, options) {
799
+ const groupedParam = buildGroupedRequestParam(node, {
800
+ resolver: options.resolver,
801
+ keys: [
802
+ "path",
803
+ "query",
804
+ "body"
805
+ ],
806
+ memberTypeWrapper: maybeRefOrGetter
807
+ });
808
+ return createFunctionParameters({ params: groupedParam ? [groupedParam] : [] });
809
+ }
810
+ function QueryKey({ name, node, tsResolver, typeName, transformer }) {
811
+ const paramsNode = buildQueryKeyParamsNode(node, { resolver: tsResolver });
812
+ const paramsSignature = declarationPrinter$4.print(paramsNode) ?? "";
813
+ const keys = (transformer ?? queryKeyTransformer)({
814
+ node,
815
+ casing: "camelcase"
816
+ });
817
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(File.Source, {
818
+ name,
819
+ isExportable: true,
820
+ isIndexable: true,
821
+ children: /* @__PURE__ */ jsx(Function.Arrow, {
822
+ name,
823
+ export: true,
824
+ params: paramsSignature,
825
+ singleLine: true,
826
+ children: `[${keys.join(", ")}] as const`
827
+ })
828
+ }), /* @__PURE__ */ jsx(File.Source, {
829
+ name: typeName,
830
+ isExportable: true,
831
+ isIndexable: true,
832
+ isTypeOnly: true,
833
+ children: /* @__PURE__ */ jsx(Type, {
834
+ name: typeName,
835
+ export: true,
836
+ children: `ReturnType<typeof ${name}>`
837
+ })
838
+ })] });
839
+ }
840
+ //#endregion
841
+ //#region src/components/QueryOptions.tsx
842
+ const declarationPrinter$3 = functionPrinter({ mode: "declaration" });
843
+ const callPrinter$3 = functionPrinter({ mode: "call" });
844
+ function getQueryOptionsParams(node, options) {
845
+ return buildQueryOptionsParams(node, {
846
+ resolver: options.resolver,
847
+ memberTypeWrapper: maybeRefOrGetter
848
+ });
849
+ }
850
+ function QueryOptions({ name, clientName, node, tsResolver, queryKeyName }) {
851
+ const { TData, TError } = buildResponseTypes(node, tsResolver);
852
+ const queryKeyParamsNode = buildQueryKeyParamsNode(node, { resolver: tsResolver });
853
+ const queryKeyParamsCall = callPrinter$3.print(queryKeyParamsNode) ?? "";
854
+ const paramsNode = getQueryOptionsParams(node, { resolver: tsResolver });
855
+ const paramsSignature = declarationPrinter$3.print(paramsNode) ?? "";
856
+ const queryFnBody = `const { data } = await ${buildVueClientCall(node, {
857
+ clientName,
858
+ signal: true
859
+ })}
860
+ return data`;
861
+ return /* @__PURE__ */ jsx(File.Source, {
862
+ name,
863
+ isExportable: true,
864
+ isIndexable: true,
865
+ children: /* @__PURE__ */ jsx(Function, {
866
+ name,
867
+ export: true,
868
+ params: paramsSignature,
869
+ children: `
870
+ const queryKey = ${queryKeyName}(${queryKeyParamsCall})
871
+ return queryOptions<${TData}, ${TError}, ${TData}>({
872
+ queryKey,
873
+ queryFn: async ({ signal }) => {
874
+ ${queryFnBody}
875
+ },
876
+ })
877
+ `
878
+ })
879
+ });
15
880
  }
881
+ //#endregion
882
+ //#region src/components/InfiniteQuery.tsx
883
+ const declarationPrinter$2 = functionPrinter({ mode: "declaration" });
884
+ const callPrinter$2 = functionPrinter({ mode: "call" });
885
+ function buildInfiniteQueryParamsNode(node, options) {
886
+ const { resolver } = options;
887
+ const { TData, TError } = buildResponseTypes(node, resolver);
888
+ const optionsParam = createFunctionParameter({
889
+ name: "options",
890
+ type: `{
891
+ query?: Partial<UseInfiniteQueryOptions<${[
892
+ TData,
893
+ TError,
894
+ "TQueryData",
895
+ "TQueryKey",
896
+ "TQueryData"
897
+ ].join(", ")}>> & { client?: QueryClient },
898
+ client?: ${buildClientOptionType()}
899
+ }`,
900
+ default: "{}"
901
+ });
902
+ return createFunctionParameters({ params: [buildGroupedRequestParam(node, {
903
+ resolver,
904
+ memberTypeWrapper: maybeRefOrGetter
905
+ }), optionsParam].filter((param) => param !== null) });
906
+ }
907
+ function InfiniteQuery({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, tsResolver }) {
908
+ const { TData, TError } = buildResponseTypes(node, tsResolver);
909
+ const returnType = `UseInfiniteQueryReturnType<${["TData", TError].join(", ")}> & { queryKey: TQueryKey }`;
910
+ const generics = [
911
+ `TData = InfiniteData<${TData}>`,
912
+ `TQueryData = ${TData}`,
913
+ `TQueryKey extends QueryKey = ${queryKeyTypeName}`
914
+ ];
915
+ const queryKeyParamsNode = buildQueryKeyParamsNode(node, { resolver: tsResolver });
916
+ const queryKeyParamsCall = callPrinter$2.print(queryKeyParamsNode) ?? "";
917
+ const queryOptionsParamsNode = getQueryOptionsParams(node, { resolver: tsResolver });
918
+ const queryOptionsParamsCall = callPrinter$2.print(queryOptionsParamsNode) ?? "";
919
+ const paramsNode = buildInfiniteQueryParamsNode(node, { resolver: tsResolver });
920
+ const paramsSignature = declarationPrinter$2.print(paramsNode) ?? "";
921
+ return /* @__PURE__ */ jsx(File.Source, {
922
+ name,
923
+ isExportable: true,
924
+ isIndexable: true,
925
+ children: /* @__PURE__ */ jsx(Function, {
926
+ name,
927
+ export: true,
928
+ generics: generics.join(", "),
929
+ params: paramsSignature,
930
+ JSDoc: { comments: buildOperationComments(node) },
931
+ children: `
932
+ const { query: queryConfig = {}, client: config = {} } = options ?? {}
933
+ const { client: queryClient, ...resolvedOptions } = queryConfig
934
+ const queryKey = (resolvedOptions && 'queryKey' in resolvedOptions ? toValue(resolvedOptions.queryKey) : undefined) ?? ${queryKeyName}(${queryKeyParamsCall})
935
+
936
+ const queryResult = useInfiniteQuery({
937
+ ...${queryOptionsName}(${queryOptionsParamsCall}),
938
+ ...resolvedOptions,
939
+ queryKey
940
+ } as unknown as UseInfiniteQueryOptions<${TData}, ${TError}, ${TData}, TQueryKey, ${TData}>, toValue(queryClient)) as ${returnType}
941
+
942
+ queryResult.queryKey = queryKey as TQueryKey
943
+
944
+ return queryResult
945
+ `
946
+ })
947
+ });
948
+ }
949
+ //#endregion
950
+ //#region src/components/InfiniteQueryOptions.tsx
951
+ /**
952
+ * The vue-query flavor of the shared `infiniteQueryOptions` component: request groups accept
953
+ * `MaybeRefOrGetter` values, are unwrapped with `toValue(...)` in the client call, and the emitted
954
+ * `TQueryKey` generic is the imported `QueryKey` type instead of `typeof queryKey`.
955
+ */
956
+ function InfiniteQueryOptions(props) {
957
+ return /* @__PURE__ */ jsx(InfiniteQueryOptions$1, {
958
+ ...props,
959
+ queryKeyType: "QueryKey",
960
+ memberTypeWrapper: maybeRefOrGetter,
961
+ unwrapName: (name) => `toValue(${name})`
962
+ });
963
+ }
964
+ //#endregion
965
+ //#region src/components/Mutation.tsx
966
+ const declarationPrinter$1 = functionPrinter({ mode: "declaration" });
967
+ const callPrinter$1 = functionPrinter({ mode: "call" });
968
+ function resolveMutationRequestType(node, resolver) {
969
+ return buildGroupedRequestParam(node, { resolver }) ? resolver.response.options(node) : "undefined";
970
+ }
971
+ function buildMutationParamsNode(node, options) {
972
+ const { resolver } = options;
973
+ const { TData, TError } = buildResponseTypes(node, resolver);
974
+ return createFunctionParameters({ params: [createFunctionParameter({
975
+ name: "options",
976
+ type: `{
977
+ mutation?: MutationObserverOptions<${[
978
+ TData,
979
+ TError,
980
+ resolveMutationRequestType(node, resolver),
981
+ "TContext"
982
+ ].join(", ")}> & { client?: QueryClient },
983
+ client?: ${buildRequestConfigType(node)},
984
+ }`,
985
+ default: "{}"
986
+ })] });
987
+ }
988
+ function Mutation({ name, clientName, node, tsResolver, mutationKeyName }) {
989
+ const { TData, TError } = buildResponseTypes(node, tsResolver);
990
+ const groupedParam = buildGroupedRequestParam(node, { resolver: tsResolver });
991
+ const hasMutationParams = groupedParam !== null;
992
+ const groupedParamsNode = createFunctionParameters({ params: groupedParam ? [groupedParam] : [] });
993
+ const argBindingStr = hasMutationParams ? callPrinter$1.print(groupedParamsNode) ?? "" : "";
994
+ const mutationFnBody = `const { data } = await ${buildVueClientCall(node, {
995
+ clientName,
996
+ signal: false
997
+ })}
998
+ return data`;
999
+ const generics = [
1000
+ TData,
1001
+ TError,
1002
+ resolveMutationRequestType(node, tsResolver),
1003
+ "TContext"
1004
+ ].join(", ");
1005
+ const paramsNode = buildMutationParamsNode(node, { resolver: tsResolver });
1006
+ const paramsSignature = declarationPrinter$1.print(paramsNode) ?? "";
1007
+ return /* @__PURE__ */ jsx(File.Source, {
1008
+ name,
1009
+ isExportable: true,
1010
+ isIndexable: true,
1011
+ children: /* @__PURE__ */ jsx(Function, {
1012
+ name,
1013
+ export: true,
1014
+ params: paramsSignature,
1015
+ JSDoc: { comments: buildOperationComments(node) },
1016
+ generics: ["TContext"],
1017
+ children: `
1018
+ const { mutation = {}, client: config = {} } = options ?? {}
1019
+ const { client: queryClient, ...mutationOptions } = mutation;
1020
+ const mutationKey = mutationOptions?.mutationKey ?? ${mutationKeyName}()
1021
+
1022
+ return useMutation<${generics}>({
1023
+ mutationFn: async(${argBindingStr}) => {
1024
+ ${mutationFnBody}
1025
+ },
1026
+ mutationKey,
1027
+ ...mutationOptions
1028
+ }, queryClient)
1029
+ `
1030
+ })
1031
+ });
1032
+ }
1033
+ //#endregion
1034
+ //#region src/components/Query.tsx
1035
+ const declarationPrinter = functionPrinter({ mode: "declaration" });
1036
+ const callPrinter = functionPrinter({ mode: "call" });
1037
+ function buildQueryParamsNode(node, options) {
1038
+ const { resolver } = options;
1039
+ const { TData, TError } = buildResponseTypes(node, resolver);
1040
+ const optionsParam = createFunctionParameter({
1041
+ name: "options",
1042
+ type: `{
1043
+ query?: Partial<UseQueryOptions<${[
1044
+ TData,
1045
+ TError,
1046
+ "TData",
1047
+ "TQueryData",
1048
+ "TQueryKey"
1049
+ ].join(", ")}>> & { client?: QueryClient },
1050
+ client?: ${buildClientOptionType()}
1051
+ }`,
1052
+ default: "{}"
1053
+ });
1054
+ return createFunctionParameters({ params: [buildGroupedRequestParam(node, {
1055
+ resolver,
1056
+ memberTypeWrapper: maybeRefOrGetter
1057
+ }), optionsParam].filter((param) => param !== null) });
1058
+ }
1059
+ function Query({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, tsResolver }) {
1060
+ const { TData, TError } = buildResponseTypes(node, tsResolver);
1061
+ const returnType = `UseQueryReturnType<${["TData", TError].join(", ")}> & { queryKey: TQueryKey }`;
1062
+ const generics = [
1063
+ `TData = ${TData}`,
1064
+ `TQueryData = ${TData}`,
1065
+ `TQueryKey extends QueryKey = ${queryKeyTypeName}`
1066
+ ];
1067
+ const queryKeyParamsNode = buildQueryKeyParamsNode(node, { resolver: tsResolver });
1068
+ const queryKeyParamsCall = callPrinter.print(queryKeyParamsNode) ?? "";
1069
+ const queryOptionsParamsNode = getQueryOptionsParams(node, { resolver: tsResolver });
1070
+ const queryOptionsParamsCall = callPrinter.print(queryOptionsParamsNode) ?? "";
1071
+ const paramsNode = buildQueryParamsNode(node, { resolver: tsResolver });
1072
+ const paramsSignature = declarationPrinter.print(paramsNode) ?? "";
1073
+ return /* @__PURE__ */ jsx(File.Source, {
1074
+ name,
1075
+ isExportable: true,
1076
+ isIndexable: true,
1077
+ children: /* @__PURE__ */ jsx(Function, {
1078
+ name,
1079
+ export: true,
1080
+ generics: generics.join(", "),
1081
+ params: paramsSignature,
1082
+ JSDoc: { comments: buildOperationComments(node) },
1083
+ children: `
1084
+ const { query: queryConfig = {}, client: config = {} } = options ?? {}
1085
+ const { client: queryClient, ...resolvedOptions } = queryConfig
1086
+ const queryKey = (resolvedOptions && 'queryKey' in resolvedOptions ? toValue(resolvedOptions.queryKey) : undefined) ?? ${queryKeyName}(${queryKeyParamsCall})
1087
+
1088
+ const queryResult = useQuery({
1089
+ ...${queryOptionsName}(${queryOptionsParamsCall}),
1090
+ ...resolvedOptions,
1091
+ queryKey
1092
+ } as unknown as UseQueryOptions<${TData}, ${TError}, TData, ${TData}, TQueryKey>, toValue(queryClient)) as ${returnType}
1093
+
1094
+ queryResult.queryKey = queryKey as TQueryKey
1095
+
1096
+ return queryResult
1097
+ `
1098
+ })
1099
+ });
1100
+ }
1101
+ //#endregion
1102
+ //#region src/generators/infiniteQueryGenerator.tsx
1103
+ /**
1104
+ * Built-in generator for `useInfiniteQuery` composables. Enabled when
1105
+ * `pluginVueQuery({ infinite: { ... }, hooks: true })`. Emits one
1106
+ * `useFooInfiniteQuery` composable per query operation, wiring the
1107
+ * configured cursor path into TanStack Query's cursor-based pagination.
1108
+ */
1109
+ const infiniteQueryGenerator = defineGenerator({
1110
+ name: "vue-query-infinite",
1111
+ renderer: jsxRenderer,
1112
+ operation(node, ctx) {
1113
+ if (!ast.isHttpOperationNode(node)) return null;
1114
+ const { config, driver, resolver, root } = ctx;
1115
+ const { output, query, mutation, infinite, client, group, hooks } = ctx.options;
1116
+ const pluginTs = driver.getPlugin(pluginTsName);
1117
+ if (!pluginTs) return null;
1118
+ const tsResolver = driver.getResolver(pluginTsName);
1119
+ const { isQuery, isMutation } = classifyOperation(node, {
1120
+ query,
1121
+ mutation
1122
+ });
1123
+ const infiniteOptions = infinite && typeof infinite === "object" ? infinite : null;
1124
+ if (!isQuery || isMutation || !infiniteOptions || !hooks) return null;
1125
+ const normalizeKey = (key) => key.replace(/\?$/, "");
1126
+ const queryParamKeys = getOperationParameters(node).query.map((p) => p.name);
1127
+ if (!(infiniteOptions.queryParam ? queryParamKeys.some((k) => normalizeKey(k) === infiniteOptions.queryParam) : false)) return null;
1128
+ const importPath = query ? query.importPath : "@tanstack/vue-query";
1129
+ const contractOp = resolveClientOperation({
1130
+ clientPlugin: { pluginName: client.pluginName },
1131
+ driver,
1132
+ node,
1133
+ root,
1134
+ output
1135
+ });
1136
+ if (!contractOp) return null;
1137
+ const queryName = resolver.infiniteQuery.name(node);
1138
+ const queryOptionsName = resolver.infiniteQuery.optionsName(node);
1139
+ const queryKeyName = resolver.infiniteQuery.keyName(node);
1140
+ const queryKeyTypeName = resolver.infiniteQuery.keyTypeName(node);
1141
+ const meta = {
1142
+ file: resolver.file({
1143
+ ...operationFileEntry(node, queryName),
1144
+ root,
1145
+ output,
1146
+ group: group ?? void 0
1147
+ }),
1148
+ fileTs: tsResolver.file({
1149
+ ...operationFileEntry(node, node.operationId),
1150
+ root,
1151
+ output: pluginTs.options?.output ?? output,
1152
+ group: pluginTs.options?.group ?? void 0
1153
+ })
1154
+ };
1155
+ const { queryParamsTypeName } = resolvePageParamType(node, {
1156
+ resolver: tsResolver,
1157
+ initialPageParam: infiniteOptions.initialPageParam,
1158
+ queryParam: infiniteOptions.queryParam
1159
+ });
1160
+ const importedTypeNames = [
1161
+ tsResolver.response.options(node),
1162
+ queryParamsTypeName,
1163
+ ...resolveOperationTypeNames(node, tsResolver, {
1164
+ exclude: [queryKeyTypeName],
1165
+ order: "body-response-first",
1166
+ includeParams: false
1167
+ })
1168
+ ].filter((name) => Boolean(name));
1169
+ const calledClientName = contractOp.name;
1170
+ return /* @__PURE__ */ jsxs(File, {
1171
+ baseName: meta.file.baseName,
1172
+ path: meta.file.path,
1173
+ meta: meta.file.meta,
1174
+ banner: resolver.default.banner(ctx.meta, {
1175
+ output,
1176
+ config,
1177
+ file: {
1178
+ path: meta.file.path,
1179
+ baseName: meta.file.baseName
1180
+ }
1181
+ }),
1182
+ footer: resolver.default.footer(ctx.meta, {
1183
+ output,
1184
+ config,
1185
+ file: {
1186
+ path: meta.file.path,
1187
+ baseName: meta.file.baseName
1188
+ }
1189
+ }),
1190
+ children: [
1191
+ /* @__PURE__ */ jsx(File.Import, {
1192
+ name: [contractOp.name],
1193
+ root: meta.file.path,
1194
+ path: contractOp.path
1195
+ }),
1196
+ /* @__PURE__ */ jsx(File.Import, {
1197
+ name: ["RequestConfig", "ResponseErrorConfig"],
1198
+ root: meta.file.path,
1199
+ path: contractOp.clientPath,
1200
+ isTypeOnly: true
1201
+ }),
1202
+ /* @__PURE__ */ jsx(File.Import, {
1203
+ name: ["toValue"],
1204
+ path: "vue"
1205
+ }),
1206
+ /* @__PURE__ */ jsx(File.Import, {
1207
+ name: ["MaybeRefOrGetter"],
1208
+ path: "vue",
1209
+ isTypeOnly: true
1210
+ }),
1211
+ meta.fileTs && importedTypeNames.length > 0 && /* @__PURE__ */ jsx(File.Import, {
1212
+ name: Array.from(new Set(importedTypeNames)),
1213
+ root: meta.file.path,
1214
+ path: meta.fileTs.path,
1215
+ isTypeOnly: true
1216
+ }),
1217
+ /* @__PURE__ */ jsx(QueryKey, {
1218
+ name: queryKeyName,
1219
+ typeName: queryKeyTypeName,
1220
+ node,
1221
+ tsResolver,
1222
+ transformer: ctx.options.queryKey
1223
+ }),
1224
+ /* @__PURE__ */ jsx(File.Import, {
1225
+ name: ["InfiniteData"],
1226
+ isTypeOnly: true,
1227
+ path: importPath
1228
+ }),
1229
+ /* @__PURE__ */ jsx(File.Import, {
1230
+ name: ["infiniteQueryOptions"],
1231
+ path: importPath
1232
+ }),
1233
+ /* @__PURE__ */ jsx(InfiniteQueryOptions, {
1234
+ name: queryOptionsName,
1235
+ clientName: calledClientName,
1236
+ queryKeyName,
1237
+ node,
1238
+ tsResolver,
1239
+ cursorParam: infiniteOptions.cursorParam,
1240
+ nextParam: infiniteOptions.nextParam,
1241
+ previousParam: infiniteOptions.previousParam,
1242
+ initialPageParam: infiniteOptions.initialPageParam,
1243
+ queryParam: infiniteOptions.queryParam
1244
+ }),
1245
+ /* @__PURE__ */ jsx(File.Import, {
1246
+ name: ["useInfiniteQuery"],
1247
+ path: importPath
1248
+ }),
1249
+ /* @__PURE__ */ jsx(File.Import, {
1250
+ name: [
1251
+ "QueryKey",
1252
+ "QueryClient",
1253
+ "UseInfiniteQueryOptions",
1254
+ "UseInfiniteQueryReturnType"
1255
+ ],
1256
+ path: importPath,
1257
+ isTypeOnly: true
1258
+ }),
1259
+ /* @__PURE__ */ jsx(InfiniteQuery, {
1260
+ name: queryName,
1261
+ queryOptionsName,
1262
+ queryKeyName,
1263
+ queryKeyTypeName,
1264
+ node,
1265
+ tsResolver,
1266
+ initialPageParam: infiniteOptions.initialPageParam,
1267
+ queryParam: infiniteOptions.queryParam
1268
+ })
1269
+ ]
1270
+ });
1271
+ }
1272
+ });
1273
+ //#endregion
1274
+ //#region src/generators/mutationGenerator.tsx
16
1275
  /**
17
- * Naming convention resolver for Vue Query plugin.
1276
+ * Built-in generator for `useMutation` composables. Emits one
1277
+ * `useFooMutation` composable per POST/PUT/DELETE operation (configurable
1278
+ * via `mutation.methods`) plus the matching `fooMutationKey` helper.
1279
+ */
1280
+ const mutationGenerator = defineGenerator({
1281
+ name: "vue-query-mutation",
1282
+ renderer: jsxRenderer,
1283
+ operation(node, ctx) {
1284
+ if (!ast.isHttpOperationNode(node)) return null;
1285
+ const { config, driver, resolver, root } = ctx;
1286
+ const { output, query, mutation, client, group, hooks } = ctx.options;
1287
+ const pluginTs = driver.getPlugin(pluginTsName);
1288
+ if (!pluginTs) return null;
1289
+ const tsResolver = driver.getResolver(pluginTsName);
1290
+ const { isMutation } = classifyOperation(node, {
1291
+ query,
1292
+ mutation
1293
+ });
1294
+ if (!isMutation) return null;
1295
+ const importPath = mutation ? mutation.importPath : "@tanstack/vue-query";
1296
+ const contractOp = resolveClientOperation({
1297
+ clientPlugin: { pluginName: client.pluginName },
1298
+ driver,
1299
+ node,
1300
+ root,
1301
+ output
1302
+ });
1303
+ if (!contractOp) return null;
1304
+ const mutationHookName = resolver.mutation.name(node);
1305
+ const mutationTypeName = resolver.mutation.typeName(node);
1306
+ const mutationKeyName = resolver.mutation.keyName(node);
1307
+ const meta = {
1308
+ file: resolver.file({
1309
+ ...operationFileEntry(node, mutationHookName),
1310
+ root,
1311
+ output,
1312
+ group: group ?? void 0
1313
+ }),
1314
+ fileTs: tsResolver.file({
1315
+ ...operationFileEntry(node, node.operationId),
1316
+ root,
1317
+ output: pluginTs.options?.output ?? output,
1318
+ group: pluginTs.options?.group ?? void 0
1319
+ })
1320
+ };
1321
+ const importedTypeNames = [tsResolver.response.options(node), ...resolveOperationTypeNames(node, tsResolver, {
1322
+ order: "body-response-first",
1323
+ includeParams: false
1324
+ })].filter((name) => Boolean(name));
1325
+ const calledClientName = contractOp.name;
1326
+ const groups = getRequestGroups(node);
1327
+ const hasRequestGroups = groups.path || groups.query || groups.body || groups.headers;
1328
+ return /* @__PURE__ */ jsxs(File, {
1329
+ baseName: meta.file.baseName,
1330
+ path: meta.file.path,
1331
+ meta: meta.file.meta,
1332
+ banner: resolver.default.banner(ctx.meta, {
1333
+ output,
1334
+ config,
1335
+ file: {
1336
+ path: meta.file.path,
1337
+ baseName: meta.file.baseName
1338
+ }
1339
+ }),
1340
+ footer: resolver.default.footer(ctx.meta, {
1341
+ output,
1342
+ config,
1343
+ file: {
1344
+ path: meta.file.path,
1345
+ baseName: meta.file.baseName
1346
+ }
1347
+ }),
1348
+ children: [
1349
+ /* @__PURE__ */ jsx(File.Import, {
1350
+ name: [contractOp.name],
1351
+ root: meta.file.path,
1352
+ path: contractOp.path
1353
+ }),
1354
+ /* @__PURE__ */ jsx(File.Import, {
1355
+ name: ["RequestConfig", "ResponseErrorConfig"],
1356
+ root: meta.file.path,
1357
+ path: contractOp.clientPath,
1358
+ isTypeOnly: true
1359
+ }),
1360
+ hasRequestGroups && /* @__PURE__ */ jsx(File.Import, {
1361
+ name: ["toValue"],
1362
+ path: "vue"
1363
+ }),
1364
+ /* @__PURE__ */ jsx(File.Import, {
1365
+ name: ["MaybeRefOrGetter"],
1366
+ path: "vue",
1367
+ isTypeOnly: true
1368
+ }),
1369
+ meta.fileTs && importedTypeNames.length > 0 && /* @__PURE__ */ jsx(File.Import, {
1370
+ name: Array.from(new Set(importedTypeNames)),
1371
+ root: meta.file.path,
1372
+ path: meta.fileTs.path,
1373
+ isTypeOnly: true
1374
+ }),
1375
+ /* @__PURE__ */ jsx(MutationKey, {
1376
+ name: mutationKeyName,
1377
+ node,
1378
+ transformer: ctx.options.mutationKey
1379
+ }),
1380
+ mutation && hooks && /* @__PURE__ */ jsxs(Fragment, { children: [
1381
+ /* @__PURE__ */ jsx(File.Import, {
1382
+ name: ["useMutation"],
1383
+ path: importPath
1384
+ }),
1385
+ /* @__PURE__ */ jsx(File.Import, {
1386
+ name: ["MutationObserverOptions", "QueryClient"],
1387
+ path: importPath,
1388
+ isTypeOnly: true
1389
+ }),
1390
+ /* @__PURE__ */ jsx(Mutation, {
1391
+ name: mutationHookName,
1392
+ clientName: calledClientName,
1393
+ typeName: mutationTypeName,
1394
+ node,
1395
+ tsResolver,
1396
+ mutationKeyName
1397
+ })
1398
+ ] })
1399
+ ]
1400
+ });
1401
+ }
1402
+ });
1403
+ //#endregion
1404
+ //#region src/generators/queryGenerator.tsx
1405
+ /**
1406
+ * Built-in generator for `useQuery` composables. Emits one `useFooQuery`
1407
+ * composable per GET operation (configurable via `query.methods`) plus the
1408
+ * matching `fooQueryKey` / `fooQueryOptions` helpers.
1409
+ */
1410
+ const queryGenerator = defineGenerator({
1411
+ name: "vue-query",
1412
+ renderer: jsxRenderer,
1413
+ operation(node, ctx) {
1414
+ if (!ast.isHttpOperationNode(node)) return null;
1415
+ const { config, driver, resolver, root } = ctx;
1416
+ const { output, query, mutation, client, group, hooks } = ctx.options;
1417
+ const pluginTs = driver.getPlugin(pluginTsName);
1418
+ if (!pluginTs) return null;
1419
+ const tsResolver = driver.getResolver(pluginTsName);
1420
+ const { isQuery, isMutation } = classifyOperation(node, {
1421
+ query,
1422
+ mutation
1423
+ });
1424
+ if (!isQuery || isMutation) return null;
1425
+ const importPath = query ? query.importPath : "@tanstack/vue-query";
1426
+ const contractOp = resolveClientOperation({
1427
+ clientPlugin: { pluginName: client.pluginName },
1428
+ driver,
1429
+ node,
1430
+ root,
1431
+ output
1432
+ });
1433
+ if (!contractOp) return null;
1434
+ const queryName = resolver.query.name(node);
1435
+ const queryOptionsName = resolver.query.optionsName(node);
1436
+ const queryKeyName = resolver.query.keyName(node);
1437
+ const queryKeyTypeName = resolver.query.keyTypeName(node);
1438
+ const meta = {
1439
+ file: resolver.file({
1440
+ ...operationFileEntry(node, queryName),
1441
+ root,
1442
+ output,
1443
+ group: group ?? void 0
1444
+ }),
1445
+ fileTs: tsResolver.file({
1446
+ ...operationFileEntry(node, node.operationId),
1447
+ root,
1448
+ output: pluginTs.options?.output ?? output,
1449
+ group: pluginTs.options?.group ?? void 0
1450
+ })
1451
+ };
1452
+ const importedTypeNames = [tsResolver.response.options(node), ...resolveOperationTypeNames(node, tsResolver, {
1453
+ exclude: [queryKeyTypeName],
1454
+ order: "body-response-first",
1455
+ includeParams: false
1456
+ })].filter((name) => Boolean(name));
1457
+ const calledClientName = contractOp.name;
1458
+ return /* @__PURE__ */ jsxs(File, {
1459
+ baseName: meta.file.baseName,
1460
+ path: meta.file.path,
1461
+ meta: meta.file.meta,
1462
+ banner: resolver.default.banner(ctx.meta, {
1463
+ output,
1464
+ config,
1465
+ file: {
1466
+ path: meta.file.path,
1467
+ baseName: meta.file.baseName
1468
+ }
1469
+ }),
1470
+ footer: resolver.default.footer(ctx.meta, {
1471
+ output,
1472
+ config,
1473
+ file: {
1474
+ path: meta.file.path,
1475
+ baseName: meta.file.baseName
1476
+ }
1477
+ }),
1478
+ children: [
1479
+ /* @__PURE__ */ jsx(File.Import, {
1480
+ name: [contractOp.name],
1481
+ root: meta.file.path,
1482
+ path: contractOp.path
1483
+ }),
1484
+ /* @__PURE__ */ jsx(File.Import, {
1485
+ name: ["RequestConfig", "ResponseErrorConfig"],
1486
+ root: meta.file.path,
1487
+ path: contractOp.clientPath,
1488
+ isTypeOnly: true
1489
+ }),
1490
+ /* @__PURE__ */ jsx(File.Import, {
1491
+ name: ["toValue"],
1492
+ path: "vue"
1493
+ }),
1494
+ /* @__PURE__ */ jsx(File.Import, {
1495
+ name: ["MaybeRefOrGetter"],
1496
+ path: "vue",
1497
+ isTypeOnly: true
1498
+ }),
1499
+ meta.fileTs && importedTypeNames.length > 0 && /* @__PURE__ */ jsx(File.Import, {
1500
+ name: Array.from(new Set(importedTypeNames)),
1501
+ root: meta.file.path,
1502
+ path: meta.fileTs.path,
1503
+ isTypeOnly: true
1504
+ }),
1505
+ /* @__PURE__ */ jsx(QueryKey, {
1506
+ name: queryKeyName,
1507
+ typeName: queryKeyTypeName,
1508
+ node,
1509
+ tsResolver,
1510
+ transformer: ctx.options.queryKey
1511
+ }),
1512
+ /* @__PURE__ */ jsx(File.Import, {
1513
+ name: ["queryOptions"],
1514
+ path: importPath
1515
+ }),
1516
+ /* @__PURE__ */ jsx(QueryOptions, {
1517
+ name: queryOptionsName,
1518
+ clientName: calledClientName,
1519
+ queryKeyName,
1520
+ node,
1521
+ tsResolver
1522
+ }),
1523
+ query && hooks && /* @__PURE__ */ jsxs(Fragment, { children: [
1524
+ /* @__PURE__ */ jsx(File.Import, {
1525
+ name: ["useQuery"],
1526
+ path: importPath
1527
+ }),
1528
+ /* @__PURE__ */ jsx(File.Import, {
1529
+ name: [
1530
+ "QueryKey",
1531
+ "QueryClient",
1532
+ "UseQueryOptions",
1533
+ "UseQueryReturnType"
1534
+ ],
1535
+ path: importPath,
1536
+ isTypeOnly: true
1537
+ }),
1538
+ /* @__PURE__ */ jsx(Query, {
1539
+ name: queryName,
1540
+ queryOptionsName,
1541
+ queryKeyName,
1542
+ queryKeyTypeName,
1543
+ node,
1544
+ tsResolver
1545
+ })
1546
+ ] })
1547
+ ]
1548
+ });
1549
+ }
1550
+ });
1551
+ //#endregion
1552
+ //#region src/resolvers/resolverVueQuery.ts
1553
+ /**
1554
+ * Default resolver used by `@kubb/plugin-vue-query`. Decides the names and
1555
+ * file paths for every generated TanStack Query composable (`useFoo`,
1556
+ * `useFooInfinite`) and its companion helpers.
18
1557
  *
19
- * Provides default naming helpers using camelCase for functions and file paths.
1558
+ * The `default` helpers are supplied by `createResolver`. Functions and files use camelCase;
1559
+ * composables get the `use` prefix. Operation-specific naming is grouped under the `query`,
1560
+ * `infiniteQuery`, and `mutation` namespaces.
1561
+ *
1562
+ * @example Resolve composable and helper names
1563
+ * ```ts
1564
+ * import { resolverVueQuery } from '@kubb/plugin-vue-query'
1565
+ *
1566
+ * resolverVueQuery.query.name(operationNode) // 'useGetPetById'
1567
+ * resolverVueQuery.query.keyName(operationNode) // 'getPetByIdQueryKey'
1568
+ * resolverVueQuery.query.optionsName(operationNode) // 'getPetByIdQueryOptions'
1569
+ * ```
20
1570
  */
21
- const resolverVueQuery = defineResolver(() => ({
22
- name: "default",
1571
+ const resolverVueQuery = createResolver({
23
1572
  pluginName: "plugin-vue-query",
24
- default(name, type) {
25
- return camelCase(name, { isFile: type === "file" });
26
- },
27
- resolveName(name) {
28
- return this.default(name, "function");
29
- },
30
- resolvePathName(name, type) {
31
- return this.default(name, type);
32
- },
33
- resolveQueryName(node) {
34
- return `use${capitalize(this.resolveName(node.operationId))}`;
35
- },
36
- resolveInfiniteQueryName(node) {
37
- return `use${capitalize(this.resolveName(node.operationId))}Infinite`;
38
- },
39
- resolveMutationName(node) {
40
- return `use${capitalize(this.resolveName(node.operationId))}`;
41
- },
42
- resolveQueryOptionsName(node) {
43
- return `${this.resolveName(node.operationId)}QueryOptions`;
44
- },
45
- resolveInfiniteQueryOptionsName(node) {
46
- return `${this.resolveName(node.operationId)}InfiniteQueryOptions`;
47
- },
48
- resolveQueryKeyName(node) {
49
- return `${this.resolveName(node.operationId)}QueryKey`;
50
- },
51
- resolveInfiniteQueryKeyName(node) {
52
- return `${this.resolveName(node.operationId)}InfiniteQueryKey`;
53
- },
54
- resolveMutationKeyName(node) {
55
- return `${this.resolveName(node.operationId)}MutationKey`;
56
- },
57
- resolveQueryKeyTypeName(node) {
58
- return `${capitalize(this.resolveName(node.operationId))}QueryKey`;
59
- },
60
- resolveInfiniteQueryKeyTypeName(node) {
61
- return `${capitalize(this.resolveName(node.operationId))}InfiniteQueryKey`;
62
- },
63
- resolveMutationTypeName(node) {
64
- return capitalize(this.resolveName(node.operationId));
65
- },
66
- resolveClientName(node) {
67
- return this.resolveName(node.operationId);
68
- },
69
- resolveInfiniteClientName(node) {
70
- return `${this.resolveName(node.operationId)}Infinite`;
1573
+ query: createQueryResolver(),
1574
+ infiniteQuery: createQueryResolver("Infinite"),
1575
+ mutation: {
1576
+ ...createMutationResolver(),
1577
+ typeName(node) {
1578
+ return capitalize(this.name(node.operationId));
1579
+ }
71
1580
  }
72
- }));
1581
+ });
73
1582
  //#endregion
74
1583
  //#region src/plugin.ts
1584
+ /**
1585
+ * Canonical plugin name for `@kubb/plugin-vue-query`. Used for driver lookups
1586
+ * and cross-plugin dependency references.
1587
+ */
75
1588
  const pluginVueQueryName = "plugin-vue-query";
1589
+ /**
1590
+ * Generates one TanStack Query composable per OpenAPI operation for Vue's
1591
+ * Composition API. Queries become `useFoo` (and optionally
1592
+ * `useFooInfinite`). Mutations become `useFoo` as well. Each composable
1593
+ * is fully typed end to end.
1594
+ *
1595
+ * @example
1596
+ * ```ts
1597
+ * import { defineConfig } from 'kubb/config'
1598
+ * import { pluginTs } from '@kubb/plugin-ts'
1599
+ * import { pluginVueQuery } from '@kubb/plugin-vue-query'
1600
+ *
1601
+ * export default defineConfig({
1602
+ * input: './petStore.yaml',
1603
+ * output: { path: './src/gen' },
1604
+ * plugins: [
1605
+ * pluginTs(),
1606
+ * pluginVueQuery({
1607
+ * output: { path: './hooks' },
1608
+ * }),
1609
+ * ],
1610
+ * })
1611
+ * ```
1612
+ */
76
1613
  const pluginVueQuery = definePlugin((options) => {
77
1614
  const { output = {
78
1615
  path: "hooks",
79
- barrelType: "named"
80
- }, group, exclude = [], include, override = [], parser = "client", infinite = false, paramsType = "inline", pathParamsType = paramsType === "object" ? "object" : options.pathParamsType || "inline", mutation = {}, query = {}, mutationKey = mutationKeyTransformer, queryKey = queryKeyTransformer, paramsCasing, client, resolver: userResolver, transformer: userTransformer, generators: userGenerators = [] } = options;
81
- const clientName = client?.client ?? "axios";
82
- const clientImportPath = client?.importPath ?? (!client?.bundle ? `@kubb/plugin-client/clients/${clientName}` : void 0);
83
- const selectedGenerators = options.generators ?? [
1616
+ barrel: { type: "named" }
1617
+ }, group, exclude = [], include, override = [], infinite = false, mutation = {}, query = {}, mutationKey = mutationKeyTransformer, queryKey = queryKeyTransformer, hooks = false, client, resolver: userResolver, macros: userMacros } = options;
1618
+ const selectedGenerators = [
84
1619
  queryGenerator,
85
1620
  infiniteQueryGenerator,
86
1621
  mutationGenerator
87
- ].filter((generator) => Boolean(generator));
88
- const groupConfig = group ? {
89
- ...group,
90
- name: group.name ? group.name : (ctx) => {
91
- if (group.type === "path") return `${ctx.group.split("/")[1]}`;
92
- return `${camelCase(ctx.group)}Controller`;
93
- }
94
- } : void 0;
1622
+ ];
1623
+ const groupConfig = createGroupConfig(group);
95
1624
  return {
96
1625
  name: pluginVueQueryName,
97
1626
  options,
98
- dependencies: [pluginTsName, parser === "zod" ? pluginZodName : void 0].filter((dependency) => Boolean(dependency)),
1627
+ dependencies: [pluginTsName],
99
1628
  hooks: { "kubb:plugin:setup"(ctx) {
100
- const resolver = userResolver ? {
101
- ...resolverVueQuery,
102
- ...userResolver
103
- } : resolverVueQuery;
1629
+ const resolver = userResolver ? Resolver.merge(resolverVueQuery, userResolver) : resolverVueQuery;
104
1630
  ctx.setOptions({
105
1631
  output,
106
- client: {
107
- bundle: client?.bundle,
108
- baseURL: client?.baseURL,
109
- client: clientName,
110
- clientType: client?.clientType ?? "function",
111
- importPath: clientImportPath,
112
- dataReturnType: client?.dataReturnType ?? "data",
113
- paramsCasing
114
- },
1632
+ client: resolveContractClient({
1633
+ client,
1634
+ plugins: ctx.config.plugins
1635
+ }),
115
1636
  queryKey,
116
- query: query === false ? false : {
117
- importPath: "@tanstack/vue-query",
118
- methods: ["get"],
119
- ...query
120
- },
1637
+ query: resolveQueryConfig(query, { importPath: "@tanstack/vue-query" }),
121
1638
  mutationKey,
122
- mutation: mutation === false ? false : {
123
- importPath: "@tanstack/vue-query",
124
- methods: [
125
- "post",
126
- "put",
127
- "patch",
128
- "delete"
129
- ],
130
- ...mutation
131
- },
132
- infinite: infinite ? {
133
- queryParam: "id",
134
- initialPageParam: 0,
135
- cursorParam: void 0,
136
- nextParam: void 0,
137
- previousParam: void 0,
138
- ...infinite
139
- } : false,
140
- parser,
141
- paramsType,
142
- pathParamsType,
143
- paramsCasing,
1639
+ mutation: resolveMutationConfig(mutation, { importPath: "@tanstack/vue-query" }),
1640
+ infinite: resolveInfiniteConfig(infinite),
1641
+ hooks,
144
1642
  group: groupConfig,
145
1643
  exclude,
146
1644
  include,
@@ -148,35 +1646,12 @@ const pluginVueQuery = definePlugin((options) => {
148
1646
  resolver
149
1647
  });
150
1648
  ctx.setResolver(resolver);
151
- if (userTransformer) ctx.setTransformer(userTransformer);
152
- for (const gen of selectedGenerators) ctx.addGenerator(gen);
153
- for (const gen of userGenerators) ctx.addGenerator(gen);
154
- const root = path.resolve(ctx.config.root, ctx.config.output.path);
155
- const hasClientPlugin = !!ctx.config.plugins?.some((p) => p.name === pluginClientName);
156
- if (client?.bundle && !hasClientPlugin && !clientImportPath) ctx.injectFile({
157
- baseName: "fetch.ts",
158
- path: path.resolve(root, ".kubb/fetch.ts"),
159
- sources: [ast.createSource({
160
- name: "fetch",
161
- nodes: [ast.createText(clientName === "fetch" ? source$1 : source)],
162
- isExportable: true,
163
- isIndexable: true
164
- })]
165
- });
166
- if (!hasClientPlugin) ctx.injectFile({
167
- baseName: "config.ts",
168
- path: path.resolve(root, ".kubb/config.ts"),
169
- sources: [ast.createSource({
170
- name: "config",
171
- nodes: [ast.createText(source$2)],
172
- isExportable: false,
173
- isIndexable: false
174
- })]
175
- });
1649
+ if (userMacros?.length) ctx.setMacros(userMacros);
1650
+ ctx.addGenerator(...selectedGenerators);
176
1651
  } }
177
1652
  };
178
1653
  });
179
1654
  //#endregion
180
- export { pluginVueQuery as default, pluginVueQuery, pluginVueQueryName };
1655
+ export { pluginVueQuery as default, pluginVueQuery, pluginVueQueryName, resolverVueQuery };
181
1656
 
182
1657
  //# sourceMappingURL=index.js.map