@kubb/plugin-swr 5.0.0-alpha.8 → 5.0.0-beta.100

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 CHANGED
@@ -1,146 +1,1245 @@
1
- Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_components = require("./components-jd0l9XKn.cjs");
3
- const require_generators = require("./generators-D062obA7.cjs");
1
+ Object.defineProperties(exports, {
2
+ __esModule: { value: true },
3
+ [Symbol.toStringTag]: { value: "Module" }
4
+ });
5
+ //#region \0rolldown/runtime.js
6
+ var __create = Object.create;
7
+ var __defProp = Object.defineProperty;
8
+ var __name = (target, value) => __defProp(target, "name", {
9
+ value,
10
+ configurable: true
11
+ });
12
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
13
+ var __getOwnPropNames = Object.getOwnPropertyNames;
14
+ var __getProtoOf = Object.getPrototypeOf;
15
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
16
+ var __copyProps = (to, from, except, desc) => {
17
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
18
+ key = keys[i];
19
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
20
+ get: ((k) => from[k]).bind(null, key),
21
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
22
+ });
23
+ }
24
+ return to;
25
+ };
26
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
27
+ value: mod,
28
+ enumerable: true
29
+ }) : target, mod));
30
+ //#endregion
31
+ let kubb_kit = require("kubb/kit");
4
32
  let node_path = require("node:path");
5
- node_path = require_components.__toESM(node_path);
6
- let _kubb_core = require("@kubb/core");
7
- let _kubb_plugin_client = require("@kubb/plugin-client");
8
- let _kubb_plugin_client_templates_clients_axios_source = require("@kubb/plugin-client/templates/clients/axios.source");
9
- let _kubb_plugin_client_templates_clients_fetch_source = require("@kubb/plugin-client/templates/clients/fetch.source");
10
- let _kubb_plugin_client_templates_config_source = require("@kubb/plugin-client/templates/config.source");
11
- let _kubb_plugin_oas = require("@kubb/plugin-oas");
33
+ node_path = __toESM(node_path, 1);
12
34
  let _kubb_plugin_ts = require("@kubb/plugin-ts");
13
- let _kubb_plugin_zod = require("@kubb/plugin-zod");
35
+ let kubb_jsx = require("kubb/jsx");
36
+ let kubb_jsx_jsx_runtime = require("kubb/jsx/jsx-runtime");
37
+ //#region ../../internals/shared/src/params.ts
38
+ /**
39
+ * Drops parameters that share the same name, keeping the first.
40
+ *
41
+ * A malformed spec can declare the same parameter name twice within one `in` location. Both would
42
+ * resolve to the same output property, so emitting both would yield an object type with a duplicate
43
+ * member, which TypeScript rejects. This is a defensive guard against that case, not a casing guard:
44
+ * parameter names flow through unchanged, so no two distinct names ever collide here anymore.
45
+ */
46
+ function dedupeParams(params) {
47
+ const seen = /* @__PURE__ */ new Set();
48
+ return params.filter((param) => {
49
+ if (seen.has(param.name)) return false;
50
+ seen.add(param.name);
51
+ return true;
52
+ });
53
+ }
54
+ //#endregion
55
+ //#region ../../internals/shared/src/operation.ts
56
+ /**
57
+ * Builds the `ResolverFileParams` every operation generator passes to
58
+ * `resolver.file`: a file named `name`, tagged by the operation's first
59
+ * tag (or `'default'`), at the operation's path. Centralizes the entry object
60
+ * that was repeated at dozens of call sites across the client and query plugins.
61
+ *
62
+ * @example
63
+ * ```ts
64
+ * resolver.file(operationFileEntry(node, node.operationId), { root, output, group })
65
+ * ```
66
+ */
67
+ function operationFileEntry(node, name, extname = ".ts") {
68
+ return {
69
+ name,
70
+ extname,
71
+ tag: node.tags[0] ?? "default",
72
+ path: node.path
73
+ };
74
+ }
75
+ function getOperationLink(node, link) {
76
+ if (!link) return null;
77
+ if (typeof link === "function") return link(node) ?? null;
78
+ return node.path ? `{@link ${kubb_kit.Url.toPath(node.path)}}` : null;
79
+ }
80
+ /**
81
+ * Derives the shared `ContentTypeInfo` shape from a list of content types, tracking whether several
82
+ * are present and the union, default, and form-data flags the client uses to pick one.
83
+ */
84
+ function buildContentTypeInfo(contentTypes) {
85
+ const isMultipleContentTypes = contentTypes.length > 1;
86
+ return {
87
+ contentTypes,
88
+ isMultipleContentTypes,
89
+ contentTypeUnion: isMultipleContentTypes ? contentTypes.map((ct) => JSON.stringify(ct)).join(" | ") : "",
90
+ defaultContentType: contentTypes[0] ?? "application/json",
91
+ hasFormData: contentTypes.some((ct) => ct === "multipart/form-data")
92
+ };
93
+ }
94
+ function getContentTypeInfo(node) {
95
+ return buildContentTypeInfo(node.requestBody?.content?.map((e) => e.contentType) ?? []);
96
+ }
97
+ /**
98
+ * The request-body counterpart for the primary success response: the content types it documents and
99
+ * whether several are present, so the client can let a caller pick which one to accept.
100
+ */
101
+ function getResponseContentTypeInfo(node) {
102
+ return buildContentTypeInfo(getPrimarySuccessResponse(node)?.content?.map((e) => e.contentType) ?? []);
103
+ }
104
+ function buildRequestConfigType(node) {
105
+ const request = getContentTypeInfo(node);
106
+ const response = getResponseContentTypeInfo(node);
107
+ const configType = `Partial<Omit<RequestConfig, 'path' | 'query' | 'body' | 'headers' | 'url'>>`;
108
+ const members = [request.isMultipleContentTypes ? `request?: ${request.contentTypeUnion}` : null, response.isMultipleContentTypes ? `response?: ${response.contentTypeUnion}` : null].filter(Boolean);
109
+ return members.length ? `${configType} & { contentType?: { ${members.join("; ")} } }` : configType;
110
+ }
111
+ /**
112
+ * Builds the `client?:` option type shared by the generated query hooks (`useQuery`,
113
+ * `useInfiniteQuery`, `useSWR`, ...). Unlike {@link buildRequestConfigType}, it never adds a
114
+ * `contentType?:` member: query hooks wrap GET operations, which carry no request body to select a
115
+ * content type for.
116
+ */
117
+ function buildClientOptionType() {
118
+ return `Partial<Omit<RequestConfig, 'path' | 'query' | 'body' | 'headers' | 'url'>>`;
119
+ }
120
+ /**
121
+ * Which of the grouped request options an operation carries.
122
+ */
123
+ function getRequestGroups(node) {
124
+ const { path, query, header } = getOperationParameters(node);
125
+ return {
126
+ path: path.length > 0,
127
+ query: query.length > 0,
128
+ body: Boolean(node.requestBody?.content?.[0]?.schema),
129
+ headers: header.length > 0
130
+ };
131
+ }
132
+ /**
133
+ * Resolves which grouped request options an operation carries together with whether each group
134
+ * holds a required member. The grouped parameter stays optional only when nothing inside it is
135
+ * required, matching the generated `RequestConfig` type.
136
+ */
137
+ function getRequestGroupOptionality(node) {
138
+ const groups = getRequestGroups(node);
139
+ const { path, query, header } = getOperationParameters(node);
140
+ const hasRequiredPath = path.some((param) => param.required);
141
+ const hasRequiredQuery = query.some((param) => param.required);
142
+ const hasRequiredHeader = header.some((param) => param.required);
143
+ return {
144
+ groups,
145
+ hasRequiredPath,
146
+ hasRequiredQuery,
147
+ hasRequiredHeader,
148
+ isOptional: !hasRequiredPath && !hasRequiredQuery && !hasRequiredHeader && !groups.body
149
+ };
150
+ }
151
+ function buildOperationComments(node, options = {}) {
152
+ const { link = "pathTemplate", linkPosition = "afterDeprecated", splitLines = false } = options;
153
+ const linkComment = getOperationLink(node, link);
154
+ const filteredComments = (linkPosition === "beforeDeprecated" ? [
155
+ node.description && `@description ${node.description}`,
156
+ node.summary && `@summary ${node.summary}`,
157
+ linkComment,
158
+ node.deprecated && "@deprecated"
159
+ ] : [
160
+ node.description && `@description ${node.description}`,
161
+ node.summary && `@summary ${node.summary}`,
162
+ node.deprecated && "@deprecated",
163
+ linkComment
164
+ ]).filter((comment) => Boolean(comment));
165
+ if (!splitLines) return filteredComments;
166
+ return filteredComments.flatMap((text) => text.split(/\r?\n/).map((line) => line.trim())).filter((comment) => Boolean(comment));
167
+ }
168
+ function getOperationParameters(node) {
169
+ return {
170
+ path: dedupeParams(node.parameters.filter((param) => param.in === "path")),
171
+ query: dedupeParams(node.parameters.filter((param) => param.in === "query")),
172
+ header: dedupeParams(node.parameters.filter((param) => param.in === "header")),
173
+ cookie: dedupeParams(node.parameters.filter((param) => param.in === "cookie"))
174
+ };
175
+ }
176
+ function getStatusCodeNumber(statusCode) {
177
+ const code = Number(statusCode);
178
+ return Number.isNaN(code) ? null : code;
179
+ }
180
+ function isSuccessStatusCode(statusCode) {
181
+ const code = getStatusCodeNumber(statusCode);
182
+ return code !== null && code >= 200 && code < 300;
183
+ }
184
+ function isErrorStatusCode(statusCode) {
185
+ const code = getStatusCodeNumber(statusCode);
186
+ return code !== null && code >= 400;
187
+ }
188
+ function getSuccessResponses(responses) {
189
+ return responses.filter((response) => isSuccessStatusCode(response.statusCode));
190
+ }
191
+ function getOperationSuccessResponses(node) {
192
+ return getSuccessResponses(node.responses);
193
+ }
194
+ function getPrimarySuccessResponse(node) {
195
+ return getOperationSuccessResponses(node)[0] ?? null;
196
+ }
197
+ function resolveErrorNames(node, resolver) {
198
+ return node.responses.filter((response) => isErrorStatusCode(response.statusCode)).map((response) => resolver.response.status(node, response.statusCode));
199
+ }
200
+ function resolveStatusCodeNames(node, resolver) {
201
+ return node.responses.map((response) => resolver.response.status(node, response.statusCode));
202
+ }
203
+ const typeNamesByResolver = /* @__PURE__ */ new WeakMap();
204
+ function resolveOperationTypeNames(node, resolver, options = {}) {
205
+ const cacheKey = `${node.operationId}\0${options.order ?? ""}\0${options.responseStatusNames ?? ""}\0${options.includeParams === false ? "noparams" : ""}\0${(options.exclude ?? []).join(",")}`;
206
+ let byResolver = typeNamesByResolver.get(resolver);
207
+ if (byResolver) {
208
+ const cached = byResolver.get(cacheKey);
209
+ if (cached) return cached;
210
+ } else {
211
+ byResolver = /* @__PURE__ */ new Map();
212
+ typeNamesByResolver.set(resolver, byResolver);
213
+ }
214
+ const { path, query, header } = getOperationParameters(node);
215
+ const responseStatusNames = options.responseStatusNames === "error" ? resolveErrorNames(node, resolver) : options.responseStatusNames === false ? [] : resolveStatusCodeNames(node, resolver);
216
+ const exclude = new Set(options.exclude ?? []);
217
+ const paramNames = options.includeParams === false ? [] : [
218
+ ...path.map((param) => resolver.param.path(node, param)),
219
+ ...query.map((param) => resolver.param.query(node, param)),
220
+ ...header.map((param) => resolver.param.headers(node, param))
221
+ ];
222
+ const bodyAndResponseNames = [node.requestBody?.content?.[0]?.schema ? resolver.response.body(node) : null, resolver.response.response(node)];
223
+ const result = (options.order === "body-response-first" ? [
224
+ ...bodyAndResponseNames,
225
+ ...paramNames,
226
+ ...responseStatusNames
227
+ ] : [
228
+ ...paramNames,
229
+ ...bodyAndResponseNames,
230
+ ...responseStatusNames
231
+ ]).filter((name) => Boolean(name) && !exclude.has(name));
232
+ byResolver.set(cacheKey, result);
233
+ return result;
234
+ }
235
+ //#endregion
236
+ //#region ../../internals/utils/src/casing.ts
237
+ /**
238
+ * Shared implementation for camelCase and PascalCase conversion.
239
+ * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)
240
+ * and capitalizes each word according to `pascal`.
241
+ *
242
+ * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
243
+ */
244
+ function toCamelOrPascal(text, pascal) {
245
+ 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) => {
246
+ if (word.length > 1 && word === word.toUpperCase()) return word;
247
+ return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
248
+ }).join("").replace(/[^a-zA-Z0-9]/g, "");
249
+ }
250
+ /**
251
+ * Converts `text` to camelCase.
252
+ *
253
+ * @example Word boundaries
254
+ * `camelCase('hello-world') // 'helloWorld'`
255
+ *
256
+ * @example With a prefix
257
+ * `camelCase('tag', { prefix: 'create' }) // 'createTag'`
258
+ */
259
+ function camelCase(text, { prefix = "", suffix = "" } = {}) {
260
+ return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
261
+ }
262
+ /**
263
+ * Uppercases only the first character of `text`, leaving the rest untouched.
264
+ * Unlike {@link pascalCase} it never re-splits word boundaries or strips characters.
265
+ *
266
+ * @example
267
+ * `capitalize('getPetById') // 'GetPetById'`
268
+ */
269
+ function capitalize(text) {
270
+ return `${text.charAt(0).toUpperCase()}${text.slice(1)}`;
271
+ }
272
+ //#endregion
273
+ //#region ../../internals/shared/src/group.ts
274
+ /**
275
+ * Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the
276
+ * shared default naming so every plugin groups output consistently:
277
+ *
278
+ * - `path` groups use the second path segment (`/pet/findByStatus` → `pet`).
279
+ * - other groups use the camelCased group (`pet store` → `petStore`).
280
+ *
281
+ * A user-provided `group.name` always wins over the default namer, so callers stay in
282
+ * control of their output folders. Returns `null` when grouping is disabled, matching the
283
+ * per-plugin convention.
284
+ *
285
+ * @param group - The user-supplied group option, or `undefined` to disable grouping.
286
+ *
287
+ * @example
288
+ * ```ts
289
+ * createGroupConfig(group) // shared across every plugin
290
+ * ```
291
+ */
292
+ function createGroupConfig(group) {
293
+ if (!group) return null;
294
+ const defaultName = (ctx) => {
295
+ if (group.type === "path") return `${ctx.group.split("/")[1]}`;
296
+ return camelCase(ctx.group);
297
+ };
298
+ return {
299
+ ...group,
300
+ name: group.name ? group.name : defaultName
301
+ };
302
+ }
303
+ //#endregion
304
+ //#region ../../internals/client/src/resolveClient.ts
305
+ /**
306
+ * Resolves which client plugin a consumer (react-query, vue-query, swr, mcp) should call for an
307
+ * operation, shared so the selection rules and diagnostics stay in one place.
308
+ *
309
+ * Every client runtime lives in a dedicated client plugin, so a consumer always calls a registered
310
+ * contract client plugin (plugin-fetch or plugin-axios) and never emits its own inline client:
311
+ *
312
+ * - `contract` — a registered contract client plugin owns the `<op>` functions and the consumer
313
+ * imports and calls them.
314
+ * - `error` — no client plugin is registered, several are registered without a selector, or the
315
+ * requested one is missing.
316
+ *
317
+ * The `client` string selects explicitly (`'fetch'` / `'axios'`); when it is unset a lone registered
318
+ * contract client plugin is picked up automatically.
319
+ */
320
+ const pluginFetchName = "plugin-fetch";
321
+ const pluginAxiosName = "plugin-axios";
322
+ const selectorToPlugin = {
323
+ fetch: pluginFetchName,
324
+ axios: pluginAxiosName
325
+ };
326
+ const contractPlugins = [pluginFetchName, pluginAxiosName];
327
+ /**
328
+ * Applies the `client` resolution rules. See the module comment for the strategy shape.
329
+ *
330
+ * @example
331
+ * ```ts
332
+ * resolveClient({ client: 'fetch', pluginNames: ['plugin-ts', 'plugin-fetch'] })
333
+ * // { kind: 'contract', pluginName: 'plugin-fetch' }
334
+ * ```
335
+ *
336
+ * @example
337
+ * ```ts
338
+ * resolveClient({ client: undefined, pluginNames: ['plugin-ts'] })
339
+ * // { kind: 'error', message: 'No client plugin is registered…' }
340
+ * ```
341
+ */
342
+ function resolveClient(options) {
343
+ const { client, pluginNames } = options;
344
+ const has = (name) => pluginNames.includes(name);
345
+ if (client === "fetch" || client === "axios") {
346
+ const pluginName = selectorToPlugin[client];
347
+ if (!has(pluginName)) return {
348
+ kind: "error",
349
+ 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.`
350
+ };
351
+ return {
352
+ kind: "contract",
353
+ pluginName
354
+ };
355
+ }
356
+ const registered = contractPlugins.filter(has);
357
+ if (registered.length === 1) return {
358
+ kind: "contract",
359
+ pluginName: registered[0]
360
+ };
361
+ if (registered.length > 1) return {
362
+ kind: "error",
363
+ 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.`
364
+ };
365
+ return {
366
+ kind: "error",
367
+ 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."
368
+ };
369
+ }
370
+ /**
371
+ * Resolves the contract client during a consumer plugin's setup hook. Extracts the plugin names
372
+ * from the raw `plugins` config, applies {@link resolveClient}, and throws the diagnostic on a
373
+ * misconfiguration so every consumer fails fast with the same message.
374
+ */
375
+ function resolveContractClient(options) {
376
+ const { client, plugins = [] } = options;
377
+ const resolved = resolveClient({
378
+ client,
379
+ pluginNames: plugins.map((plugin) => plugin.name).filter((name) => Boolean(name))
380
+ });
381
+ if (resolved.kind === "error") throw new Error(resolved.message);
382
+ return resolved;
383
+ }
384
+ //#endregion
385
+ //#region ../../internals/client/src/resolveClientOperation.ts
386
+ /**
387
+ * Resolves the contract client `<op>` a consumer (query hook, MCP handler) imports, by looking up
388
+ * the registered contract client plugin's resolver and output. Works for any contract client plugin
389
+ * (plugin-fetch or plugin-axios). Returns `null` when no contract plugin is in play (the inline
390
+ * path). The plugin injects `.kubb/client.ts` at the global output root, the same path consumers
391
+ * read `RequestConfig` / `ResponseErrorConfig` from.
392
+ */
393
+ function resolveClientOperation(options) {
394
+ const { clientPlugin, driver, node, root, output } = options;
395
+ if (!clientPlugin) return null;
396
+ const resolver = driver.getResolver(clientPlugin.pluginName);
397
+ const plugin = driver.getPlugin(clientPlugin.pluginName);
398
+ const file = resolver.file({
399
+ ...operationFileEntry(node, node.operationId),
400
+ root,
401
+ output: plugin?.options?.output ?? output,
402
+ group: plugin?.options?.group ?? void 0
403
+ });
404
+ return {
405
+ name: resolver.name(node.operationId),
406
+ path: file.path,
407
+ clientPath: node_path.default.resolve(root, ".kubb/client.ts")
408
+ };
409
+ }
410
+ //#endregion
411
+ //#region ../../internals/tanstack-query/src/utils.ts
412
+ /**
413
+ * The grouped request options, ordered for both the destructured signature and the
414
+ * call passed to the underlying client.
415
+ */
416
+ const requestGroupOrder = [
417
+ "path",
418
+ "query",
419
+ "body",
420
+ "headers"
421
+ ];
422
+ /**
423
+ * Builds the grouped `{ path, query, body, headers }` parameter that mirrors the client
424
+ * function signature. Only the groups the operation carries are emitted, typed from the
425
+ * operation's `Options`. `keys` narrows the emitted groups, used by the query key which
426
+ * never carries `headers`.
427
+ *
428
+ * By default the whole group is typed as the single `Options` reference. When
429
+ * `memberTypeWrapper` is set, each group is emitted as its own member typed from the matching
430
+ * `Options['<group>']` slice and wrapped, used by vue-query to apply
431
+ * `MaybeRefOrGetter` per group.
432
+ */
433
+ function buildGroupedRequestParam(node, options) {
434
+ const { resolver, keys = requestGroupOrder, memberTypeWrapper } = options;
435
+ const { groups, hasRequiredPath, hasRequiredQuery, hasRequiredHeader } = getRequestGroupOptionality(node);
436
+ const names = keys.filter((key) => groups[key]);
437
+ if (names.length === 0) return null;
438
+ const requiredByGroup = {
439
+ path: hasRequiredPath,
440
+ query: hasRequiredQuery,
441
+ body: groups.body,
442
+ headers: hasRequiredHeader
443
+ };
444
+ const isOptional = names.every((name) => !requiredByGroup[name]);
445
+ const optionsName = resolver.response.options(node);
446
+ const omittedKeys = requestGroupOrder.filter((key) => !keys.includes(key));
447
+ const optionsType = omittedKeys.length > 0 ? `Omit<${optionsName}, ${omittedKeys.map((key) => `'${key}'`).join(" | ")}>` : optionsName;
448
+ if (memberTypeWrapper) {
449
+ const members = names.map((name) => ({
450
+ name,
451
+ type: memberTypeWrapper(`${optionsType}['${name}']`),
452
+ optional: !requiredByGroup[name]
453
+ }));
454
+ return (0, _kubb_plugin_ts.createFunctionParameter)({
455
+ name: (0, _kubb_plugin_ts.createObjectBindingPattern)({ elements: names.map((name) => ({ name })) }),
456
+ type: (0, _kubb_plugin_ts.createTypeLiteral)({ members }),
457
+ optional: false,
458
+ ...isOptional ? { default: "{}" } : {}
459
+ });
460
+ }
461
+ return (0, _kubb_plugin_ts.createFunctionParameter)({
462
+ name: (0, _kubb_plugin_ts.createObjectBindingPattern)({ elements: names.map((name) => ({ name })) }),
463
+ type: optionsType,
464
+ optional: false,
465
+ ...isOptional ? { default: "{}" } : {}
466
+ });
467
+ }
468
+ /**
469
+ * Builds the shared `({ path, query, body, headers }, config = {})` parameter list for a
470
+ * TanStack query-options function. The leading parameter mirrors the client signature, and the
471
+ * trailing `config` is a partial `RequestConfig` minus the grouped data-shape keys, which are passed
472
+ * explicitly. Framework plugins wrap the result when needed, for example vue-query applies `MaybeRefOrGetter`.
473
+ */
474
+ function buildQueryOptionsParams(node, options) {
475
+ const { resolver, memberTypeWrapper } = options;
476
+ return (0, _kubb_plugin_ts.createFunctionParameters)({ params: [buildGroupedRequestParam(node, {
477
+ resolver,
478
+ memberTypeWrapper
479
+ }), (0, _kubb_plugin_ts.createFunctionParameter)({
480
+ name: "config",
481
+ type: `Partial<Omit<RequestConfig, 'path' | 'query' | 'body' | 'headers' | 'url'>>`,
482
+ default: "{}"
483
+ })].filter((param) => param !== null) });
484
+ }
485
+ /**
486
+ * Builds the call to a client `<op>` function inside a query/mutation hook body. The function takes
487
+ * a single grouped options object, so the operation's request groups are passed as
488
+ * shorthand alongside the spread `config`, with `throwOnError: true` pinned last so a caller's config
489
+ * can't flip the query's error semantics. Queries thread the TanStack `signal`; mutations omit it.
490
+ *
491
+ * When `unwrapName` is set, each request group is passed as an explicit member unwrapped through it,
492
+ * used by vue-query to resolve refs and getters with `toValue(...)` at call time.
493
+ *
494
+ * @example
495
+ * ```ts
496
+ * buildClientCall(node, { clientName: 'getPetById', signal: true })
497
+ * // getPetById({ path, ...config, signal: config.signal ?? signal, throwOnError: true })
498
+ * ```
499
+ */
500
+ function buildClientCall(node, options) {
501
+ const { clientName, signal = false, unwrapName } = options;
502
+ const { groups } = getRequestGroupOptionality(node);
503
+ return `${clientName}({ ${[
504
+ "...config",
505
+ ...requestGroupOrder.filter((key) => groups[key]).map((name) => unwrapName ? `${name}: ${unwrapName(name)}` : name),
506
+ signal ? "signal: config.signal ?? signal" : null,
507
+ "throwOnError: true"
508
+ ].filter((part) => part !== null).join(", ")} })`;
509
+ }
510
+ /**
511
+ * Applies the shared query defaults during plugin setup: `false` disables query generation, and an
512
+ * object merges over `methods: ['GET']` and the plugin's runtime `importPath`.
513
+ */
514
+ function resolveQueryConfig(query, options) {
515
+ if (query === false) return false;
516
+ return {
517
+ importPath: options.importPath,
518
+ methods: ["GET"],
519
+ ...query
520
+ };
521
+ }
522
+ /**
523
+ * Applies the shared mutation defaults during plugin setup: `false` disables mutation generation,
524
+ * and an object merges over `methods: ['POST', 'PUT', 'PATCH', 'DELETE']` and the plugin's runtime
525
+ * `importPath`.
526
+ */
527
+ function resolveMutationConfig(mutation, options) {
528
+ if (mutation === false) return false;
529
+ return {
530
+ importPath: options.importPath,
531
+ methods: [
532
+ "POST",
533
+ "PUT",
534
+ "PATCH",
535
+ "DELETE"
536
+ ],
537
+ ...mutation
538
+ };
539
+ }
540
+ /**
541
+ * Classifies an operation as a query or a mutation from the resolved `query` / `mutation` method lists.
542
+ * `query: false` still marks the operation as a query so the query-family generators keep matching it,
543
+ * and a method already claimed by `query` never counts as a mutation.
544
+ */
545
+ function classifyOperation(node, { query, mutation }) {
546
+ const isQuery = query === false || !!query && query.methods.some((method) => node.method.toLowerCase() === method.toLowerCase());
547
+ const queryMethods = new Set(query ? query.methods : []);
548
+ return {
549
+ isQuery,
550
+ isMutation: mutation !== false && !isQuery && (mutation ? mutation.methods : []).some((method) => !queryMethods.has(method) && node.method.toLowerCase() === method.toLowerCase())
551
+ };
552
+ }
553
+ /**
554
+ * Build QueryKey params as the grouped `{ path, query, body }` object (NO headers, NO config),
555
+ * typed from the operation's `Options` minus `url`. The query key transformer reads the
556
+ * grouped `path`/`query`/`body` bindings.
557
+ */
558
+ function buildQueryKeyParams(node, options) {
559
+ const { resolver } = options;
560
+ const groupedParam = buildGroupedRequestParam(node, {
561
+ resolver,
562
+ keys: [
563
+ "path",
564
+ "query",
565
+ "body"
566
+ ]
567
+ });
568
+ return (0, _kubb_plugin_ts.createFunctionParameters)({ params: groupedParam ? [groupedParam] : [] });
569
+ }
570
+ //#endregion
571
+ //#region ../../internals/tanstack-query/src/components/MutationKey.tsx
572
+ const declarationPrinter$4 = (0, _kubb_plugin_ts.functionPrinter)({ mode: "declaration" });
573
+ const mutationKeyTransformer = ({ node }) => {
574
+ if (!node.path) return [];
575
+ return [`{ url: '${kubb_kit.Url.toPath(node.path)}' }`];
576
+ };
577
+ function MutationKey$1({ name, node, transformer }) {
578
+ const paramsNode = (0, _kubb_plugin_ts.createFunctionParameters)({ params: [] });
579
+ const paramsSignature = declarationPrinter$4.print(paramsNode) ?? "";
580
+ const keys = (transformer ?? mutationKeyTransformer)({
581
+ node,
582
+ casing: "camelcase"
583
+ });
584
+ return /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Source, {
585
+ name,
586
+ isExportable: true,
587
+ isIndexable: true,
588
+ children: /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.Function.Arrow, {
589
+ name,
590
+ export: true,
591
+ params: paramsSignature,
592
+ singleLine: true,
593
+ children: `[${keys.join(", ")}] as const`
594
+ })
595
+ });
596
+ }
597
+ __name(MutationKey$1, "MutationKey");
598
+ //#endregion
599
+ //#region ../../internals/tanstack-query/src/resolver.ts
600
+ /**
601
+ * Builds the shared query namespace for a variant. Spread the result into
602
+ * `createResolver` once per variant the plugin supports.
603
+ *
604
+ * @example
605
+ * ```ts
606
+ * createResolver<PluginReactQuery>({
607
+ * query: createQueryResolver(),
608
+ * suspenseQuery: createQueryResolver('Suspense'),
609
+ * })
610
+ * ```
611
+ */
612
+ function createQueryResolver(variant = "") {
613
+ return {
614
+ name(node) {
615
+ return `use${capitalize(this.name(node.operationId))}${variant}`;
616
+ },
617
+ optionsName(node) {
618
+ return `${this.name(node.operationId)}${variant}QueryOptions`;
619
+ },
620
+ keyName(node) {
621
+ return `${this.name(node.operationId)}${variant}QueryKey`;
622
+ },
623
+ keyTypeName(node) {
624
+ return `${capitalize(this.name(node.operationId))}${variant}QueryKey`;
625
+ },
626
+ clientName(node) {
627
+ return `${this.name(node.operationId)}${variant}`;
628
+ }
629
+ };
630
+ }
631
+ /**
632
+ * Builds the shared mutation namespace. Spread the result into
633
+ * `createResolver` and add plugin-specific methods (`optionsName`,
634
+ * `typeName`, `argTypeName`) next to it.
635
+ *
636
+ * @example
637
+ * ```ts
638
+ * createResolver<PluginSwr>({ mutation: { ...createMutationResolver(), argTypeName(node) {...} } })
639
+ * ```
640
+ */
641
+ function createMutationResolver() {
642
+ return {
643
+ name(node) {
644
+ return `use${capitalize(this.name(node.operationId))}`;
645
+ },
646
+ keyName(node) {
647
+ return `${this.name(node.operationId)}MutationKey`;
648
+ }
649
+ };
650
+ }
651
+ //#endregion
652
+ //#region ../../internals/tanstack-query/src/components/QueryKey.tsx
653
+ const declarationPrinter$3 = (0, _kubb_plugin_ts.functionPrinter)({ mode: "declaration" });
654
+ const queryKeyTransformer = ({ node }) => {
655
+ if (!node.path) return [];
656
+ const hasPathParams = getOperationParameters(node).path.length > 0;
657
+ const hasQueryParams = getOperationParameters(node).query.length > 0;
658
+ const hasRequestBody = !!node.requestBody?.content?.[0]?.schema;
659
+ return [
660
+ hasPathParams ? `{ url: '${kubb_kit.Url.toPath(node.path)}', params: path }` : `{ url: '${kubb_kit.Url.toPath(node.path)}' }`,
661
+ hasQueryParams ? "...(query ? [query] : [])" : null,
662
+ hasRequestBody ? "...(body ? [body] : [])" : null
663
+ ].filter(Boolean);
664
+ };
665
+ function QueryKey({ name, node, tsResolver, typeName, transformer }) {
666
+ const paramsNode = buildQueryKeyParams(node, { resolver: tsResolver });
667
+ const paramsSignature = declarationPrinter$3.print(paramsNode) ?? "";
668
+ const keys = (transformer ?? queryKeyTransformer)({
669
+ node,
670
+ casing: "camelcase"
671
+ });
672
+ return /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsxs)(kubb_jsx_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Source, {
673
+ name,
674
+ isExportable: true,
675
+ isIndexable: true,
676
+ children: /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.Function.Arrow, {
677
+ name,
678
+ export: true,
679
+ params: paramsSignature,
680
+ singleLine: true,
681
+ children: `[${keys.join(", ")}] as const`
682
+ })
683
+ }), /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Source, {
684
+ name: typeName,
685
+ isTypeOnly: true,
686
+ children: /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.Type, {
687
+ name: typeName,
688
+ children: `ReturnType<typeof ${name}>`
689
+ })
690
+ })] });
691
+ }
692
+ //#endregion
693
+ //#region src/components/Mutation.tsx
694
+ const declarationPrinter$2 = (0, _kubb_plugin_ts.functionPrinter)({ mode: "declaration" });
695
+ const callPrinter$1 = (0, _kubb_plugin_ts.functionPrinter)({ mode: "call" });
696
+ function buildMutationParamsNode(node, options) {
697
+ const { mutationKeyTypeName, mutationArgTypeName, resolver } = options;
698
+ const responseName = resolver.response.response(node);
699
+ const errorNames = resolveErrorNames(node, resolver);
700
+ return (0, _kubb_plugin_ts.createFunctionParameters)({ params: [(0, _kubb_plugin_ts.createFunctionParameter)({
701
+ name: "options",
702
+ type: `{
703
+ mutation?: SWRMutationConfiguration<${responseName}, ${`ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(" | ") : "Error"}>`}, ${mutationKeyTypeName} | null, ${mutationArgTypeName}> & { throwOnError?: boolean },
704
+ client?: ${buildRequestConfigType(node)},
705
+ shouldFetch?: boolean,
706
+ }`,
707
+ default: "{}"
708
+ })] });
709
+ }
710
+ function Mutation({ name, clientName, mutationKeyName, mutationKeyTypeName, mutationArgTypeName, node, tsResolver }) {
711
+ const responseName = tsResolver.response.response(node);
712
+ const errorNames = resolveErrorNames(node, tsResolver);
713
+ const TData = responseName;
714
+ const TError = `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(" | ") : "Error"}>`;
715
+ const groupedParam = buildGroupedRequestParam(node, { resolver: tsResolver });
716
+ const hasMutationParams = groupedParam !== null;
717
+ const groupedParamsNode = (0, _kubb_plugin_ts.createFunctionParameters)({ params: groupedParam ? [groupedParam] : [] });
718
+ const argTypeBody = hasMutationParams ? tsResolver.response.options(node) : "";
719
+ const argBindingStr = hasMutationParams ? callPrinter$1.print(groupedParamsNode) ?? "" : "";
720
+ const mutationFnBody = `const { data } = await ${buildClientCall(node, {
721
+ clientName,
722
+ signal: false
723
+ })}
724
+ return data`;
725
+ const generics = [
726
+ TData,
727
+ TError,
728
+ `${mutationKeyTypeName} | null`,
729
+ mutationArgTypeName
730
+ ];
731
+ const paramsNode = buildMutationParamsNode(node, {
732
+ mutationKeyTypeName,
733
+ mutationArgTypeName,
734
+ resolver: tsResolver
735
+ });
736
+ const paramsSignature = declarationPrinter$2.print(paramsNode) ?? "";
737
+ return /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsxs)(kubb_jsx_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Source, {
738
+ name: mutationArgTypeName,
739
+ isExportable: true,
740
+ isIndexable: true,
741
+ isTypeOnly: true,
742
+ children: /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.Type, {
743
+ name: mutationArgTypeName,
744
+ export: true,
745
+ children: hasMutationParams ? argTypeBody : "never"
746
+ })
747
+ }), /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Source, {
748
+ name,
749
+ isExportable: true,
750
+ isIndexable: true,
751
+ children: /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.Function, {
752
+ name,
753
+ export: true,
754
+ params: paramsSignature,
755
+ JSDoc: { comments: buildOperationComments(node) },
756
+ children: `
757
+ const { mutation: mutationOptions, client: config = {}, shouldFetch = true } = options ?? {}
758
+ const mutationKey = ${mutationKeyName}()
759
+
760
+ return useSWRMutation<${generics.join(", ")}>(
761
+ shouldFetch ? mutationKey : null,
762
+ async (_url${hasMutationParams ? `, { arg: ${argBindingStr} }` : ""}) => {
763
+ ${mutationFnBody}
764
+ },
765
+ mutationOptions
766
+ )
767
+ `
768
+ })
769
+ })] });
770
+ }
771
+ //#endregion
772
+ //#region src/components/MutationKey.tsx
773
+ function MutationKey({ name, typeName, node, transformer }) {
774
+ return /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsxs)(kubb_jsx_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(MutationKey$1, {
775
+ name,
776
+ node,
777
+ transformer
778
+ }), /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Source, {
779
+ name: typeName,
780
+ isExportable: true,
781
+ isIndexable: true,
782
+ isTypeOnly: true,
783
+ children: /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.Type, {
784
+ export: true,
785
+ name: typeName,
786
+ children: `ReturnType<typeof ${name}>`
787
+ })
788
+ })] });
789
+ }
790
+ //#endregion
791
+ //#region src/components/Query.tsx
792
+ const declarationPrinter$1 = (0, _kubb_plugin_ts.functionPrinter)({ mode: "declaration" });
793
+ const callPrinter = (0, _kubb_plugin_ts.functionPrinter)({ mode: "call" });
794
+ function buildQueryParamsNode(node, options) {
795
+ const { resolver } = options;
796
+ const responseName = resolver.response.response(node);
797
+ const errorNames = resolveErrorNames(node, resolver);
798
+ const optionsParam = (0, _kubb_plugin_ts.createFunctionParameter)({
799
+ name: "options",
800
+ type: `{
801
+ query?: SWRConfiguration<${[responseName, `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(" | ") : "Error"}>`].join(", ")}>,
802
+ client?: ${buildClientOptionType()},
803
+ shouldFetch?: boolean,
804
+ immutable?: boolean
805
+ }`,
806
+ default: "{}"
807
+ });
808
+ return (0, _kubb_plugin_ts.createFunctionParameters)({ params: [buildGroupedRequestParam(node, { resolver }), optionsParam].filter((param) => param !== null) });
809
+ }
810
+ function Query({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, tsResolver }) {
811
+ const responseName = tsResolver.response.response(node);
812
+ const errorNames = resolveErrorNames(node, tsResolver);
813
+ const generics = [
814
+ responseName,
815
+ `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(" | ") : "Error"}>`,
816
+ `${queryKeyTypeName} | null`
817
+ ];
818
+ const queryKeyParamsNode = buildQueryKeyParams(node, { resolver: tsResolver });
819
+ const queryKeyParamsCall = callPrinter.print(queryKeyParamsNode) ?? "";
820
+ const queryOptionsParamsNode = buildQueryOptionsParams(node, { resolver: tsResolver });
821
+ const queryOptionsParamsCall = callPrinter.print(queryOptionsParamsNode) ?? "";
822
+ const paramsNode = buildQueryParamsNode(node, { resolver: tsResolver });
823
+ const paramsSignature = declarationPrinter$1.print(paramsNode) ?? "";
824
+ return /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Source, {
825
+ name,
826
+ isExportable: true,
827
+ isIndexable: true,
828
+ children: /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.Function, {
829
+ name,
830
+ export: true,
831
+ params: paramsSignature,
832
+ JSDoc: { comments: buildOperationComments(node) },
833
+ children: `
834
+ const { query: queryOptions, client: config = {}, shouldFetch = true, immutable } = options ?? {}
835
+
836
+ const queryKey = ${queryKeyName}(${queryKeyParamsCall})
837
+
838
+ return useSWR<${generics.join(", ")}>(
839
+ shouldFetch ? queryKey : null,
840
+ {
841
+ ...${queryOptionsName}(${queryOptionsParamsCall}),
842
+ ...(immutable ? {
843
+ revalidateIfStale: false,
844
+ revalidateOnFocus: false,
845
+ revalidateOnReconnect: false
846
+ } : { }),
847
+ ...queryOptions,
848
+ }
849
+ )
850
+ `
851
+ })
852
+ });
853
+ }
854
+ //#endregion
855
+ //#region src/components/QueryOptions.tsx
856
+ const declarationPrinter = (0, _kubb_plugin_ts.functionPrinter)({ mode: "declaration" });
857
+ function QueryOptions({ name, clientName, node, tsResolver }) {
858
+ const paramsNode = buildQueryOptionsParams(node, { resolver: tsResolver });
859
+ const paramsSignature = declarationPrinter.print(paramsNode) ?? "";
860
+ const fetcherBody = `const { data } = await ${buildClientCall(node, {
861
+ clientName,
862
+ signal: false
863
+ })}
864
+ return data`;
865
+ return /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Source, {
866
+ name,
867
+ isExportable: true,
868
+ isIndexable: true,
869
+ children: /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.Function, {
870
+ name,
871
+ export: true,
872
+ params: paramsSignature,
873
+ children: `
874
+ return {
875
+ fetcher: async () => {
876
+ ${fetcherBody}
877
+ },
878
+ }
879
+ `
880
+ })
881
+ });
882
+ }
883
+ //#endregion
884
+ //#region src/generators/mutationGenerator.tsx
885
+ /**
886
+ * Built-in generator for `useSWRMutation` hooks. Emits one `useFooMutation` hook
887
+ * per POST/PUT/DELETE operation (configurable via `mutation.methods`) plus
888
+ * the matching `fooMutationKey` helper.
889
+ */
890
+ const mutationGenerator = (0, kubb_kit.defineGenerator)({
891
+ name: "swr-mutation",
892
+ renderer: kubb_jsx.jsxRenderer,
893
+ operation(node, ctx) {
894
+ if (!kubb_kit.ast.isHttpOperationNode(node)) return null;
895
+ const { config, driver, resolver, root } = ctx;
896
+ const { output, query, mutation, client, group } = ctx.options;
897
+ const pluginTs = driver.getPlugin(_kubb_plugin_ts.pluginTsName);
898
+ if (!pluginTs) return null;
899
+ const tsResolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
900
+ const { isMutation } = classifyOperation(node, {
901
+ query,
902
+ mutation
903
+ });
904
+ if (!isMutation) return null;
905
+ const importPath = mutation ? mutation.importPath : "swr/mutation";
906
+ const contractOp = resolveClientOperation({
907
+ clientPlugin: { pluginName: client.pluginName },
908
+ driver,
909
+ node,
910
+ root,
911
+ output
912
+ });
913
+ if (!contractOp) return null;
914
+ const mutationHookName = resolver.mutation.name(node);
915
+ const mutationKeyName = resolver.mutation.keyName(node);
916
+ const mutationKeyTypeName = resolver.mutation.keyTypeName(node);
917
+ const mutationArgTypeName = resolver.mutation.argTypeName(node);
918
+ const meta = {
919
+ file: resolver.file({
920
+ name: mutationHookName,
921
+ extname: ".ts",
922
+ tag: node.tags[0] ?? "default",
923
+ path: node.path,
924
+ root,
925
+ output,
926
+ group
927
+ }),
928
+ fileTs: tsResolver.file({
929
+ name: node.operationId,
930
+ extname: ".ts",
931
+ tag: node.tags[0] ?? "default",
932
+ path: node.path,
933
+ root,
934
+ output: pluginTs.options?.output ?? output,
935
+ group: pluginTs.options?.group
936
+ })
937
+ };
938
+ const importedTypeNames = [tsResolver.response.options(node), ...resolveOperationTypeNames(node, tsResolver, {
939
+ order: "body-response-first",
940
+ includeParams: false
941
+ })].filter((name) => Boolean(name));
942
+ const calledClientName = contractOp.name;
943
+ return /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsxs)(kubb_jsx.File, {
944
+ baseName: meta.file.baseName,
945
+ path: meta.file.path,
946
+ meta: meta.file.meta,
947
+ banner: resolver.default.banner(ctx.meta, {
948
+ output,
949
+ config,
950
+ file: {
951
+ path: meta.file.path,
952
+ baseName: meta.file.baseName
953
+ }
954
+ }),
955
+ footer: resolver.default.footer(ctx.meta, {
956
+ output,
957
+ config,
958
+ file: {
959
+ path: meta.file.path,
960
+ baseName: meta.file.baseName
961
+ }
962
+ }),
963
+ children: [
964
+ /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
965
+ name: [contractOp.name],
966
+ root: meta.file.path,
967
+ path: contractOp.path
968
+ }),
969
+ /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
970
+ name: ["RequestConfig", "ResponseErrorConfig"],
971
+ root: meta.file.path,
972
+ path: contractOp.clientPath,
973
+ isTypeOnly: true
974
+ }),
975
+ meta.fileTs && importedTypeNames.length > 0 && /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
976
+ name: Array.from(new Set(importedTypeNames)),
977
+ root: meta.file.path,
978
+ path: meta.fileTs.path,
979
+ isTypeOnly: true
980
+ }),
981
+ /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(MutationKey, {
982
+ name: mutationKeyName,
983
+ typeName: mutationKeyTypeName,
984
+ node,
985
+ transformer: ctx.options.mutationKey
986
+ }),
987
+ mutation && /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsxs)(kubb_jsx_jsx_runtime.Fragment, { children: [
988
+ /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
989
+ name: "useSWRMutation",
990
+ path: importPath
991
+ }),
992
+ /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
993
+ name: ["SWRMutationConfiguration"],
994
+ path: importPath,
995
+ isTypeOnly: true
996
+ }),
997
+ /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(Mutation, {
998
+ name: mutationHookName,
999
+ clientName: calledClientName,
1000
+ mutationKeyName,
1001
+ mutationKeyTypeName,
1002
+ mutationArgTypeName,
1003
+ node,
1004
+ tsResolver
1005
+ })
1006
+ ] })
1007
+ ]
1008
+ });
1009
+ }
1010
+ });
1011
+ //#endregion
1012
+ //#region src/generators/queryGenerator.tsx
1013
+ /**
1014
+ * Built-in generator for `useSWR` hooks. Emits one `useFoo` hook per read operation plus the
1015
+ * matching `fooQueryKey` helper and `fooQueryOptions` factory.
1016
+ */
1017
+ const queryGenerator = (0, kubb_kit.defineGenerator)({
1018
+ name: "swr-query",
1019
+ renderer: kubb_jsx.jsxRenderer,
1020
+ operation(node, ctx) {
1021
+ if (!kubb_kit.ast.isHttpOperationNode(node)) return null;
1022
+ const { config, driver, resolver, root } = ctx;
1023
+ const { output, query, mutation, client, group } = ctx.options;
1024
+ const pluginTs = driver.getPlugin(_kubb_plugin_ts.pluginTsName);
1025
+ if (!pluginTs) return null;
1026
+ const tsResolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
1027
+ const { isQuery } = classifyOperation(node, {
1028
+ query,
1029
+ mutation
1030
+ });
1031
+ if (!isQuery) return null;
1032
+ const importPath = query ? query.importPath : "swr";
1033
+ const contractOp = resolveClientOperation({
1034
+ clientPlugin: { pluginName: client.pluginName },
1035
+ driver,
1036
+ node,
1037
+ root,
1038
+ output
1039
+ });
1040
+ if (!contractOp) return null;
1041
+ const queryName = resolver.query.name(node);
1042
+ const queryOptionsName = resolver.query.optionsName(node);
1043
+ const queryKeyName = resolver.query.keyName(node);
1044
+ const queryKeyTypeName = resolver.query.keyTypeName(node);
1045
+ const meta = {
1046
+ file: resolver.file({
1047
+ name: queryName,
1048
+ extname: ".ts",
1049
+ tag: node.tags[0] ?? "default",
1050
+ path: node.path,
1051
+ root,
1052
+ output,
1053
+ group
1054
+ }),
1055
+ fileTs: tsResolver.file({
1056
+ name: node.operationId,
1057
+ extname: ".ts",
1058
+ tag: node.tags[0] ?? "default",
1059
+ path: node.path,
1060
+ root,
1061
+ output: pluginTs.options?.output ?? output,
1062
+ group: pluginTs.options?.group
1063
+ })
1064
+ };
1065
+ const importedTypeNames = [tsResolver.response.options(node), ...resolveOperationTypeNames(node, tsResolver, {
1066
+ exclude: [queryKeyTypeName],
1067
+ order: "body-response-first",
1068
+ includeParams: false
1069
+ })].filter((name) => Boolean(name));
1070
+ const calledClientName = contractOp.name;
1071
+ return /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsxs)(kubb_jsx.File, {
1072
+ baseName: meta.file.baseName,
1073
+ path: meta.file.path,
1074
+ meta: meta.file.meta,
1075
+ banner: resolver.default.banner(ctx.meta, {
1076
+ output,
1077
+ config,
1078
+ file: {
1079
+ path: meta.file.path,
1080
+ baseName: meta.file.baseName
1081
+ }
1082
+ }),
1083
+ footer: resolver.default.footer(ctx.meta, {
1084
+ output,
1085
+ config,
1086
+ file: {
1087
+ path: meta.file.path,
1088
+ baseName: meta.file.baseName
1089
+ }
1090
+ }),
1091
+ children: [
1092
+ /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
1093
+ name: [contractOp.name],
1094
+ root: meta.file.path,
1095
+ path: contractOp.path
1096
+ }),
1097
+ /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
1098
+ name: ["RequestConfig", "ResponseErrorConfig"],
1099
+ root: meta.file.path,
1100
+ path: contractOp.clientPath,
1101
+ isTypeOnly: true
1102
+ }),
1103
+ meta.fileTs && importedTypeNames.length > 0 && /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
1104
+ name: Array.from(new Set(importedTypeNames)),
1105
+ root: meta.file.path,
1106
+ path: meta.fileTs.path,
1107
+ isTypeOnly: true
1108
+ }),
1109
+ /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(QueryKey, {
1110
+ name: queryKeyName,
1111
+ typeName: queryKeyTypeName,
1112
+ node,
1113
+ tsResolver,
1114
+ transformer: ctx.options.queryKey
1115
+ }),
1116
+ /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(QueryOptions, {
1117
+ name: queryOptionsName,
1118
+ clientName: calledClientName,
1119
+ node,
1120
+ tsResolver
1121
+ }),
1122
+ query && /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsxs)(kubb_jsx_jsx_runtime.Fragment, { children: [
1123
+ /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
1124
+ name: "useSWR",
1125
+ path: importPath
1126
+ }),
1127
+ /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
1128
+ name: ["SWRConfiguration"],
1129
+ path: importPath,
1130
+ isTypeOnly: true
1131
+ }),
1132
+ /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(Query, {
1133
+ name: queryName,
1134
+ queryOptionsName,
1135
+ queryKeyName,
1136
+ queryKeyTypeName,
1137
+ node,
1138
+ tsResolver
1139
+ })
1140
+ ] })
1141
+ ]
1142
+ });
1143
+ }
1144
+ });
1145
+ //#endregion
1146
+ //#region src/resolvers/resolverSwr.ts
1147
+ /**
1148
+ * Default resolver used by `@kubb/plugin-swr`. Decides the names and file paths for every generated
1149
+ * SWR hook (`useFoo`, `useFooMutation`) and its companion helpers (`fooQueryKey`, `fooQueryOptions`,
1150
+ * `fooMutationKey`).
1151
+ *
1152
+ * Functions and files use the built-in camelCase casing; hooks get the `use` prefix.
1153
+ *
1154
+ * @example Resolve hook and helper names
1155
+ * ```ts
1156
+ * import { resolverSwr } from '@kubb/plugin-swr'
1157
+ *
1158
+ * resolverSwr.query.name(operationNode) // 'useGetPetById'
1159
+ * resolverSwr.query.keyName(operationNode) // 'getPetByIdQueryKey'
1160
+ * resolverSwr.mutation.name(operationNode) // 'useUpdatePet'
1161
+ * ```
1162
+ */
1163
+ const resolverSwr = (0, kubb_kit.createResolver)({
1164
+ pluginName: "plugin-swr",
1165
+ query: createQueryResolver(),
1166
+ mutation: {
1167
+ ...createMutationResolver(),
1168
+ keyTypeName(node) {
1169
+ return `${capitalize(this.name(node.operationId))}MutationKey`;
1170
+ },
1171
+ argTypeName(node) {
1172
+ return `${capitalize(this.name(node.operationId))}MutationArg`;
1173
+ }
1174
+ }
1175
+ });
1176
+ //#endregion
14
1177
  //#region src/plugin.ts
1178
+ /**
1179
+ * Canonical plugin name for `@kubb/plugin-swr`. Used for driver lookups and cross-plugin
1180
+ * dependency references.
1181
+ */
15
1182
  const pluginSwrName = "plugin-swr";
16
- const pluginSwr = (0, _kubb_core.createPlugin)((options) => {
1183
+ /**
1184
+ * Generates SWR hooks from OpenAPI operations. Read operations become `useFoo` hooks built on
1185
+ * `useSWR` and write operations become `useFoo` hooks built on `useSWRMutation`, wrapping the
1186
+ * client functions from `@kubb/plugin-axios` or `@kubb/plugin-fetch`.
1187
+ *
1188
+ * @example
1189
+ * ```ts
1190
+ * import { defineConfig } from 'kubb/config'
1191
+ * import { pluginTs } from '@kubb/plugin-ts'
1192
+ * import { pluginSwr } from '@kubb/plugin-swr'
1193
+ *
1194
+ * export default defineConfig({
1195
+ * input: './petStore.yaml',
1196
+ * output: { path: './src/gen' },
1197
+ * plugins: [
1198
+ * pluginTs(),
1199
+ * pluginSwr({ output: { path: './hooks' } }),
1200
+ * ],
1201
+ * })
1202
+ * ```
1203
+ */
1204
+ const pluginSwr = (0, kubb_kit.definePlugin)((options) => {
17
1205
  const { output = {
18
1206
  path: "hooks",
19
- barrelType: "named"
20
- }, group, exclude = [], include, override = [], parser = "client", transformers = {}, query, mutation, client, paramsType = "inline", pathParamsType = paramsType === "object" ? "object" : options.pathParamsType || "inline", mutationKey = require_components.MutationKey.getTransformer, queryKey = require_components.QueryKey.getTransformer, generators = [require_generators.queryGenerator, require_generators.mutationGenerator].filter(Boolean), paramsCasing, contentType } = options;
21
- const clientName = client?.client ?? "axios";
22
- const clientImportPath = client?.importPath ?? (!client?.bundle ? `@kubb/plugin-client/clients/${clientName}` : void 0);
1207
+ barrel: { type: "named" }
1208
+ }, group, exclude = [], include, override = [], mutation = {}, query = {}, mutationKey = mutationKeyTransformer, queryKey = queryKeyTransformer, client, resolver: userResolver, macros: userMacros } = options;
1209
+ const selectedGenerators = [queryGenerator, mutationGenerator];
1210
+ const groupConfig = createGroupConfig(group) ?? void 0;
23
1211
  return {
24
1212
  name: pluginSwrName,
25
- options: {
26
- output,
27
- client: {
28
- bundle: client?.bundle,
29
- baseURL: client?.baseURL,
30
- client: clientName,
31
- clientType: client?.clientType ?? "function",
32
- importPath: clientImportPath,
33
- dataReturnType: client?.dataReturnType ?? "data",
34
- paramsCasing
35
- },
36
- queryKey,
37
- query: query === false ? false : {
38
- importPath: "swr",
39
- methods: ["get"],
40
- ...query
41
- },
42
- mutationKey,
43
- mutation: mutation === false ? false : {
44
- importPath: "swr/mutation",
45
- methods: [
46
- "post",
47
- "put",
48
- "delete",
49
- "patch"
50
- ],
51
- ...mutation
52
- },
53
- parser,
54
- paramsType,
55
- pathParamsType,
56
- paramsCasing,
57
- group
58
- },
59
- pre: [
60
- _kubb_plugin_oas.pluginOasName,
61
- _kubb_plugin_ts.pluginTsName,
62
- parser === "zod" ? _kubb_plugin_zod.pluginZodName : void 0
63
- ].filter(Boolean),
64
- resolvePath(baseName, pathMode, options) {
65
- const root = node_path.default.resolve(this.config.root, this.config.output.path);
66
- if ((pathMode ?? (0, _kubb_core.getMode)(node_path.default.resolve(root, output.path))) === "single")
67
- /**
68
- * when output is a file then we will always append to the same file(output file), see fileManager.addOrAppend
69
- * Other plugins then need to call addOrAppend instead of just add from the fileManager class
70
- */
71
- return node_path.default.resolve(root, output.path);
72
- if (group && (options?.group?.path || options?.group?.tag)) {
73
- const groupName = group?.name ? group.name : (ctx) => {
74
- if (group?.type === "path") return `${ctx.group.split("/")[1]}`;
75
- return `${require_components.camelCase(ctx.group)}Controller`;
76
- };
77
- return node_path.default.resolve(root, output.path, groupName({ group: group.type === "path" ? options.group.path : options.group.tag }), baseName);
78
- }
79
- return node_path.default.resolve(root, output.path, baseName);
80
- },
81
- resolveName(name, type) {
82
- let resolvedName = require_components.camelCase(name);
83
- if (type === "file" || type === "function") resolvedName = require_components.camelCase(name, { isFile: type === "file" });
84
- if (type === "type") resolvedName = require_components.pascalCase(name);
85
- if (type) return transformers?.name?.(resolvedName, type) || resolvedName;
86
- return resolvedName;
87
- },
88
- async install() {
89
- const root = node_path.default.resolve(this.config.root, this.config.output.path);
90
- const mode = (0, _kubb_core.getMode)(node_path.default.resolve(root, output.path));
91
- const oas = await this.getOas();
92
- const baseURL = await this.getBaseURL();
93
- if (baseURL) this.plugin.options.client.baseURL = baseURL;
94
- const hasClientPlugin = !!this.driver.getPluginByName(_kubb_plugin_client.pluginClientName);
95
- if (this.plugin.options.client.bundle && !hasClientPlugin && !this.plugin.options.client.importPath) await this.upsertFile({
96
- baseName: "fetch.ts",
97
- path: node_path.default.resolve(root, ".kubb/fetch.ts"),
98
- sources: [{
99
- name: "fetch",
100
- value: this.plugin.options.client.client === "fetch" ? _kubb_plugin_client_templates_clients_fetch_source.source : _kubb_plugin_client_templates_clients_axios_source.source,
101
- isExportable: true,
102
- isIndexable: true
103
- }],
104
- imports: [],
105
- exports: []
106
- });
107
- if (!hasClientPlugin) await this.addFile({
108
- baseName: "config.ts",
109
- path: node_path.default.resolve(root, ".kubb/config.ts"),
110
- sources: [{
111
- name: "config",
112
- value: _kubb_plugin_client_templates_config_source.source,
113
- isExportable: false,
114
- isIndexable: false
115
- }],
116
- imports: [],
117
- exports: []
118
- });
119
- const files = await new _kubb_plugin_oas.OperationGenerator(this.plugin.options, {
120
- fabric: this.fabric,
121
- oas,
122
- driver: this.driver,
123
- events: this.events,
124
- plugin: this.plugin,
125
- contentType,
1213
+ options,
1214
+ dependencies: [_kubb_plugin_ts.pluginTsName],
1215
+ hooks: { "kubb:plugin:setup"(ctx) {
1216
+ const resolver = userResolver ? kubb_kit.Resolver.merge(resolverSwr, userResolver) : resolverSwr;
1217
+ ctx.setOptions({
1218
+ output,
1219
+ client: resolveContractClient({
1220
+ client,
1221
+ plugins: ctx.config.plugins
1222
+ }),
1223
+ queryKey,
1224
+ query: resolveQueryConfig(query, { importPath: "swr" }),
1225
+ mutationKey,
1226
+ mutation: resolveMutationConfig(mutation, { importPath: "swr/mutation" }),
1227
+ group: groupConfig,
126
1228
  exclude,
127
1229
  include,
128
1230
  override,
129
- mode
130
- }).build(...generators);
131
- await this.upsertFile(...files);
132
- const barrelFiles = await (0, _kubb_core.getBarrelFiles)(this.fabric.files, {
133
- type: output.barrelType ?? "named",
134
- root,
135
- output,
136
- meta: { pluginName: this.plugin.name }
1231
+ resolver
137
1232
  });
138
- await this.upsertFile(...barrelFiles);
139
- }
1233
+ ctx.setResolver(resolver);
1234
+ if (userMacros?.length) ctx.setMacros(userMacros);
1235
+ ctx.addGenerator(...selectedGenerators);
1236
+ } }
140
1237
  };
141
1238
  });
142
1239
  //#endregion
1240
+ exports.default = pluginSwr;
143
1241
  exports.pluginSwr = pluginSwr;
144
1242
  exports.pluginSwrName = pluginSwrName;
1243
+ exports.resolverSwr = resolverSwr;
145
1244
 
146
1245
  //# sourceMappingURL=index.cjs.map