@kubb/plugin-react-query 5.10.0-canary.20261109T191216 → 5.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +598 -569
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -5
- package/dist/index.d.ts +8 -5
- package/dist/index.js +597 -568
- package/dist/index.js.map +1 -1
- package/docs/options.md +1 -1
- package/kubb-extension.json +1 -1
- package/package.json +9 -8
package/dist/index.js
CHANGED
|
@@ -1,10 +1,293 @@
|
|
|
1
|
-
import { Diagnostics, Resolver, Url, addGenerator, ast,
|
|
1
|
+
import { Diagnostics, Resolver, Url, addGenerator, ast, casing, createResolver, defineExtension, defineGenerator, setMacros, setResolver, useConfig } from "@kubb/kit";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import { pluginZodName } from "@kubb/plugin-zod";
|
|
4
|
-
import { File, Function, Type, jsxRenderer } from "@kubb/renderer-jsx";
|
|
5
3
|
import { createFunctionParameter, createFunctionParameters, createObjectBindingPattern, createTypeLiteral, functionPrinter, pluginTsName } from "@kubb/plugin-ts";
|
|
4
|
+
import { File, Function, Type, jsxRenderer } from "@kubb/renderer-jsx";
|
|
6
5
|
import { Fragment, jsx, jsxs } from "@kubb/renderer-jsx/jsx-runtime";
|
|
7
6
|
import fs from "node:fs";
|
|
7
|
+
// kubb-extension.json
|
|
8
|
+
var compatibility = {
|
|
9
|
+
"kubb": ">=5.18.4",
|
|
10
|
+
"node": ">=22.22"
|
|
11
|
+
};
|
|
12
|
+
// package.json
|
|
13
|
+
var version = "5.10.0";
|
|
14
|
+
// ../../internals/client/src/resolveClient.ts
|
|
15
|
+
/**
|
|
16
|
+
* Resolves which client plugin a consumer (react-query, vue-query, swr, mcp) should call for an
|
|
17
|
+
* operation, shared so the selection rules and diagnostics stay in one place.
|
|
18
|
+
*
|
|
19
|
+
* Every client runtime lives in a dedicated client plugin, so a consumer always calls a registered
|
|
20
|
+
* contract client plugin (plugin-fetch, plugin-axios, or plugin-client) and never emits its own
|
|
21
|
+
* inline client:
|
|
22
|
+
*
|
|
23
|
+
* - `contract` — a registered contract client plugin owns the `<op>` functions and the consumer
|
|
24
|
+
* imports and calls them.
|
|
25
|
+
* - `error` — no client plugin is registered, several are registered without a selector, the
|
|
26
|
+
* requested one is missing, or `client` is not a known selector.
|
|
27
|
+
*
|
|
28
|
+
* The `client` string selects explicitly (`'fetch'` / `'axios'` / `'client'`); when it is unset a
|
|
29
|
+
* lone registered contract client plugin is picked up automatically.
|
|
30
|
+
*/
|
|
31
|
+
const pluginFetchName = "plugin-fetch";
|
|
32
|
+
const pluginAxiosName = "plugin-axios";
|
|
33
|
+
const pluginClientName = "plugin-client";
|
|
34
|
+
const selectorToPlugin = {
|
|
35
|
+
fetch: pluginFetchName,
|
|
36
|
+
axios: pluginAxiosName,
|
|
37
|
+
client: pluginClientName
|
|
38
|
+
};
|
|
39
|
+
const contractPlugins = [
|
|
40
|
+
pluginFetchName,
|
|
41
|
+
pluginAxiosName,
|
|
42
|
+
pluginClientName
|
|
43
|
+
];
|
|
44
|
+
/**
|
|
45
|
+
* Applies the `client` resolution rules. See the module comment for the strategy shape.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```ts
|
|
49
|
+
* resolveClient({ client: 'fetch', pluginNames: ['plugin-ts', 'plugin-fetch'] })
|
|
50
|
+
* // { kind: 'contract', pluginName: 'plugin-fetch' }
|
|
51
|
+
* ```
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```ts
|
|
55
|
+
* resolveClient({ client: undefined, pluginNames: ['plugin-ts'] })
|
|
56
|
+
* // { kind: 'error', code: 'KUBB_MISSING_DEPENDENCY', message: 'No client plugin is registered.', help: 'Add …' }
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
function resolveClient(options) {
|
|
60
|
+
const { client, pluginNames } = options;
|
|
61
|
+
const has = (name) => pluginNames.includes(name);
|
|
62
|
+
if (client === "fetch" || client === "axios" || client === "client") {
|
|
63
|
+
const pluginName = selectorToPlugin[client];
|
|
64
|
+
if (!has(pluginName)) return {
|
|
65
|
+
kind: "error",
|
|
66
|
+
code: Diagnostics.code.missingDependency,
|
|
67
|
+
message: `\`client: '${client}'\` is set but \`@kubb/plugin-${client}\` is not registered in \`plugins\`.`,
|
|
68
|
+
help: `Add \`@kubb/plugin-${client}\` to \`plugins\`, or drop \`client\` to use a different client plugin.`
|
|
69
|
+
};
|
|
70
|
+
return {
|
|
71
|
+
kind: "contract",
|
|
72
|
+
pluginName
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
if (client !== void 0) return {
|
|
76
|
+
kind: "error",
|
|
77
|
+
code: Diagnostics.code.invalidPluginOptions,
|
|
78
|
+
message: `Option \`client\` is ${typeof client === "string" ? `'${client}'` : String(client)}, but it must be one of 'fetch', 'axios', 'client'.`,
|
|
79
|
+
help: "Set `client` to one of those values, or drop it to use the registered client plugin."
|
|
80
|
+
};
|
|
81
|
+
const registered = contractPlugins.filter(has);
|
|
82
|
+
if (registered.length === 1) return {
|
|
83
|
+
kind: "contract",
|
|
84
|
+
pluginName: registered[0]
|
|
85
|
+
};
|
|
86
|
+
if (registered.length > 1) return {
|
|
87
|
+
kind: "error",
|
|
88
|
+
code: Diagnostics.code.invalidPluginOptions,
|
|
89
|
+
message: `Multiple client plugins are registered (${registered.map((name) => `\`@kubb/${name}\``).join(", ")}) and \`client\` is not set.`,
|
|
90
|
+
help: "Set `client: 'fetch' | 'axios' | 'client'` to choose which client the hooks call, or register a single client plugin."
|
|
91
|
+
};
|
|
92
|
+
return {
|
|
93
|
+
kind: "error",
|
|
94
|
+
code: Diagnostics.code.missingDependency,
|
|
95
|
+
message: "No client plugin is registered.",
|
|
96
|
+
help: "Add `@kubb/plugin-fetch`, `@kubb/plugin-axios`, or `@kubb/plugin-client` to `plugins` so the generated code has an HTTP client to call."
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Resolves the contract client during a consumer plugin's setup hook.
|
|
101
|
+
* It extracts the plugin names from the raw `plugins` config and applies {@link resolveClient}.
|
|
102
|
+
* On a misconfiguration it throws a config diagnostic tagged with `plugin`, so every consumer
|
|
103
|
+
* fails fast with the same message.
|
|
104
|
+
*/
|
|
105
|
+
function resolveContractClient(options) {
|
|
106
|
+
const { plugin, client, plugins = [] } = options;
|
|
107
|
+
const resolved = resolveClient({
|
|
108
|
+
client,
|
|
109
|
+
pluginNames: plugins.map((plugin) => plugin.name).filter((name) => Boolean(name))
|
|
110
|
+
});
|
|
111
|
+
if (resolved.kind === "error") {
|
|
112
|
+
const { code, message, help } = resolved;
|
|
113
|
+
throw new Diagnostics.Error({
|
|
114
|
+
code,
|
|
115
|
+
severity: "error",
|
|
116
|
+
message,
|
|
117
|
+
help,
|
|
118
|
+
location: { kind: "config" },
|
|
119
|
+
plugin
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
return resolved;
|
|
123
|
+
}
|
|
124
|
+
// ../../internals/utils/src/reserved.ts
|
|
125
|
+
/**
|
|
126
|
+
* JavaScript and Java reserved words.
|
|
127
|
+
* @link https://github.com/jonschlinkert/reserved/blob/master/index.js
|
|
128
|
+
*/
|
|
129
|
+
const reservedWords = /* @__PURE__ */ new Set([
|
|
130
|
+
"abstract",
|
|
131
|
+
"arguments",
|
|
132
|
+
"await",
|
|
133
|
+
"boolean",
|
|
134
|
+
"break",
|
|
135
|
+
"byte",
|
|
136
|
+
"case",
|
|
137
|
+
"catch",
|
|
138
|
+
"char",
|
|
139
|
+
"class",
|
|
140
|
+
"const",
|
|
141
|
+
"continue",
|
|
142
|
+
"debugger",
|
|
143
|
+
"default",
|
|
144
|
+
"delete",
|
|
145
|
+
"do",
|
|
146
|
+
"double",
|
|
147
|
+
"else",
|
|
148
|
+
"enum",
|
|
149
|
+
"eval",
|
|
150
|
+
"export",
|
|
151
|
+
"extends",
|
|
152
|
+
"false",
|
|
153
|
+
"final",
|
|
154
|
+
"finally",
|
|
155
|
+
"float",
|
|
156
|
+
"for",
|
|
157
|
+
"function",
|
|
158
|
+
"goto",
|
|
159
|
+
"if",
|
|
160
|
+
"implements",
|
|
161
|
+
"import",
|
|
162
|
+
"in",
|
|
163
|
+
"instanceof",
|
|
164
|
+
"int",
|
|
165
|
+
"interface",
|
|
166
|
+
"let",
|
|
167
|
+
"long",
|
|
168
|
+
"native",
|
|
169
|
+
"new",
|
|
170
|
+
"null",
|
|
171
|
+
"package",
|
|
172
|
+
"private",
|
|
173
|
+
"protected",
|
|
174
|
+
"public",
|
|
175
|
+
"return",
|
|
176
|
+
"short",
|
|
177
|
+
"static",
|
|
178
|
+
"super",
|
|
179
|
+
"switch",
|
|
180
|
+
"synchronized",
|
|
181
|
+
"this",
|
|
182
|
+
"throw",
|
|
183
|
+
"throws",
|
|
184
|
+
"transient",
|
|
185
|
+
"true",
|
|
186
|
+
"try",
|
|
187
|
+
"typeof",
|
|
188
|
+
"var",
|
|
189
|
+
"void",
|
|
190
|
+
"volatile",
|
|
191
|
+
"while",
|
|
192
|
+
"with",
|
|
193
|
+
"yield",
|
|
194
|
+
"Array",
|
|
195
|
+
"Date",
|
|
196
|
+
"hasOwnProperty",
|
|
197
|
+
"Infinity",
|
|
198
|
+
"isFinite",
|
|
199
|
+
"isNaN",
|
|
200
|
+
"isPrototypeOf",
|
|
201
|
+
"length",
|
|
202
|
+
"Math",
|
|
203
|
+
"name",
|
|
204
|
+
"NaN",
|
|
205
|
+
"Number",
|
|
206
|
+
"Object",
|
|
207
|
+
"prototype",
|
|
208
|
+
"String",
|
|
209
|
+
"toString",
|
|
210
|
+
"undefined",
|
|
211
|
+
"valueOf"
|
|
212
|
+
]);
|
|
213
|
+
/**
|
|
214
|
+
* Returns `true` when `name` is a syntactically valid JavaScript variable name.
|
|
215
|
+
*
|
|
216
|
+
* @example
|
|
217
|
+
* ```ts
|
|
218
|
+
* isValidVarName('status') // true
|
|
219
|
+
* isValidVarName('class') // false (reserved word)
|
|
220
|
+
* isValidVarName('42foo') // false (starts with digit)
|
|
221
|
+
* ```
|
|
222
|
+
*/
|
|
223
|
+
function isValidVarName(name) {
|
|
224
|
+
if (!name || reservedWords.has(name)) return false;
|
|
225
|
+
return isIdentifier(name);
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Returns `name` when it's a syntactically valid JavaScript variable name,
|
|
229
|
+
* otherwise prefixes it with `_` so the result is a valid identifier.
|
|
230
|
+
*
|
|
231
|
+
* Useful for sanitizing OpenAPI schema names or operation IDs that start with
|
|
232
|
+
* a digit (e.g. `409`, `504AccountCancel`) before using them as exported
|
|
233
|
+
* variable, type, or function names.
|
|
234
|
+
*
|
|
235
|
+
* @example
|
|
236
|
+
* ```ts
|
|
237
|
+
* ensureValidVarName('409') // '_409'
|
|
238
|
+
* ensureValidVarName('504AccountCancel') // '_504AccountCancel'
|
|
239
|
+
* ensureValidVarName('Pet') // 'Pet'
|
|
240
|
+
* ensureValidVarName('class') // '_class'
|
|
241
|
+
* ```
|
|
242
|
+
*/
|
|
243
|
+
function ensureValidVarName(name) {
|
|
244
|
+
if (!name || isValidVarName(name)) return name;
|
|
245
|
+
return `_${name}`;
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Returns `true` when `name` is syntactically a valid identifier, ignoring reserved words.
|
|
249
|
+
*
|
|
250
|
+
* Reserved words and globals (`class`, `name`, `Date`, …) are valid as bare object-literal keys
|
|
251
|
+
* even though they are not valid variable names, so use this (not {@link isValidVarName}) when
|
|
252
|
+
* deciding whether an object key needs quoting.
|
|
253
|
+
*
|
|
254
|
+
* @example
|
|
255
|
+
* ```ts
|
|
256
|
+
* isIdentifier('name') // true
|
|
257
|
+
* isIdentifier('x-total')// false
|
|
258
|
+
* ```
|
|
259
|
+
*/
|
|
260
|
+
function isIdentifier(name) {
|
|
261
|
+
return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
|
|
262
|
+
}
|
|
263
|
+
// ../../internals/utils/src/strings.ts
|
|
264
|
+
/**
|
|
265
|
+
* Renders a dotted path or string array as an optional-chaining accessor expression rooted at
|
|
266
|
+
* `accessor`. Returns `null` for an empty path.
|
|
267
|
+
*
|
|
268
|
+
* @example
|
|
269
|
+
* ```ts
|
|
270
|
+
* getNestedAccessor('pagination.next.id', 'lastPage')
|
|
271
|
+
* // "lastPage?.['pagination']?.['next']?.['id']"
|
|
272
|
+
* ```
|
|
273
|
+
*/
|
|
274
|
+
function getNestedAccessor(param, accessor) {
|
|
275
|
+
const parts = Array.isArray(param) ? param : param.split(".");
|
|
276
|
+
if (parts.length === 0 || parts.length === 1 && parts[0] === "") return null;
|
|
277
|
+
return `${accessor}?.['${`${parts.join("']?.['")}']`}`;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Escapes an `@` at the start of a line, so a multi-line description can't start a new JSDoc tag.
|
|
281
|
+
* Editors render `\@` as `@` in hovers.
|
|
282
|
+
*
|
|
283
|
+
* @example
|
|
284
|
+
* ```ts
|
|
285
|
+
* jsDocEscape('intro\n@example value') // 'intro\n\\@example value'
|
|
286
|
+
* ```
|
|
287
|
+
*/
|
|
288
|
+
function jsDocEscape(input) {
|
|
289
|
+
return `${input}`.replace(/^(\s*)@/gm, "$1\\@");
|
|
290
|
+
}
|
|
8
291
|
// ../../internals/shared/src/operation.ts
|
|
9
292
|
/**
|
|
10
293
|
* Builds the `ResolverFileParams` every operation generator passes to
|
|
@@ -26,29 +309,55 @@ function operationFileEntry(node, name, extname = ".ts") {
|
|
|
26
309
|
};
|
|
27
310
|
}
|
|
28
311
|
/**
|
|
29
|
-
* Resolves a
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
312
|
+
* Resolves the file a schema-emitting plugin (`plugin-ts`, `plugin-zod`, `plugin-faker`) writes
|
|
313
|
+
* `node` to, cached in `ctx.memo` under the resolver's plugin name and the
|
|
314
|
+
* operation. The plugin itself and every plugin that imports from it call this, so they all get
|
|
315
|
+
* the same path.
|
|
316
|
+
*
|
|
317
|
+
* When that path matches the file of a component schema in `ctx.driver.inputNode`, ignoring case, the file name
|
|
318
|
+
* gets an `Operation` suffix: operation `point` goes to `PointOperation.ts` next to schema `Point.ts`.
|
|
319
|
+
* Otherwise the two merge into one file, or overwrite each other on a case-insensitive file system.
|
|
320
|
+
* Only the file name changes. The declarations keep their names.
|
|
33
321
|
*
|
|
34
|
-
* @example
|
|
322
|
+
* @example Resolve `plugin-ts`'s file for the current operation
|
|
35
323
|
* ```ts
|
|
36
|
-
* const fileTs =
|
|
324
|
+
* const fileTs = resolveOperationFile({ ctx, node, resolver: tsResolver, root, output })
|
|
37
325
|
* ```
|
|
38
326
|
*/
|
|
39
|
-
function
|
|
40
|
-
const {
|
|
41
|
-
|
|
42
|
-
|
|
327
|
+
function resolveOperationFile(options) {
|
|
328
|
+
const { ctx, node, resolver, root, output } = options;
|
|
329
|
+
const { memo } = ctx;
|
|
330
|
+
const location = {
|
|
43
331
|
root,
|
|
44
332
|
output,
|
|
45
|
-
group: group ?? void 0
|
|
46
|
-
}
|
|
333
|
+
group: options.group ?? void 0
|
|
334
|
+
};
|
|
335
|
+
return memo(`${resolver.pluginName}:operationFile:${node.operationId}`, () => {
|
|
336
|
+
const schemaPaths = memo(`${resolver.pluginName}:schemaFilePaths`, () => new Set((ctx.driver.inputNode?.schemas ?? []).flatMap((schema) => schema.name ? [resolver.file({
|
|
337
|
+
name: schema.name,
|
|
338
|
+
extname: ".ts",
|
|
339
|
+
...location
|
|
340
|
+
}).path.toLowerCase()] : [])));
|
|
341
|
+
let file = resolver.file({
|
|
342
|
+
...operationFileEntry(node, node.operationId),
|
|
343
|
+
...location
|
|
344
|
+
});
|
|
345
|
+
for (let name = `${node.operationId}Operation`; schemaPaths.has(file.path.toLowerCase()); name += "Operation") {
|
|
346
|
+
const next = resolver.file({
|
|
347
|
+
...operationFileEntry(node, name),
|
|
348
|
+
...location
|
|
349
|
+
});
|
|
350
|
+
if (next.path === file.path) break;
|
|
351
|
+
file = next;
|
|
352
|
+
}
|
|
353
|
+
return file;
|
|
354
|
+
});
|
|
47
355
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
356
|
+
/**
|
|
357
|
+
* The operation's method and path as plain text, such as `` `GET /pet/{petId}` ``. A path is not a valid `{@link}` target.
|
|
358
|
+
*/
|
|
359
|
+
function getOperationRequestLine(node) {
|
|
360
|
+
return ast.http.isOperation(node) && node.path ? `\`${node.method.toUpperCase()} ${node.path}\`` : null;
|
|
52
361
|
}
|
|
53
362
|
/**
|
|
54
363
|
* Derives the shared `ContentTypeInfo` shape from a list of content types, tracking whether several
|
|
@@ -72,18 +381,7 @@ function getContentTypeInfo(node) {
|
|
|
72
381
|
* whether several are present, so the client can let a caller pick which one to accept.
|
|
73
382
|
*/
|
|
74
383
|
function getResponseContentTypeInfo(node) {
|
|
75
|
-
return buildContentTypeInfo(
|
|
76
|
-
}
|
|
77
|
-
function baseContentType(contentType) {
|
|
78
|
-
return contentType.split(";")[0].trim().toLowerCase();
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Whether a content entry is a sequence of JSON values the adapter marks as a stream, such as `application/jsonl`,
|
|
82
|
-
* `application/x-ndjson`, `application/json-seq`, or any media type with an OpenAPI 3.2 `itemSchema`.
|
|
83
|
-
*/
|
|
84
|
-
function isJsonLines(entry) {
|
|
85
|
-
const baseType = baseContentType(entry.contentType);
|
|
86
|
-
return Boolean(entry.stream) && baseType !== "text/event-stream" && !baseType.startsWith("multipart/");
|
|
384
|
+
return buildContentTypeInfo(ast.http.responses.findPrimary(node)?.content?.map((e) => e.contentType) ?? []);
|
|
87
385
|
}
|
|
88
386
|
/**
|
|
89
387
|
* How an operation streams its primary success response item by item, when that response declares one content type:
|
|
@@ -95,11 +393,19 @@ function isJsonLines(entry) {
|
|
|
95
393
|
* call with its query hooks.
|
|
96
394
|
*/
|
|
97
395
|
function getEventStream(node) {
|
|
98
|
-
const content =
|
|
396
|
+
const content = ast.http.responses.findPrimary(node)?.content ?? [];
|
|
99
397
|
if (content.length !== 1) return null;
|
|
100
398
|
const entry = content[0];
|
|
101
|
-
|
|
102
|
-
|
|
399
|
+
const framing = getStreamFraming(entry);
|
|
400
|
+
if (framing === "events") return entry.stream?.shape ?? "data";
|
|
401
|
+
return framing === "lines" ? "line" : null;
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* How a content entry is framed as a stream: `'events'` for Server-Sent Events, `'lines'` for JSON Lines.
|
|
405
|
+
*/
|
|
406
|
+
function getStreamFraming(entry) {
|
|
407
|
+
if (ast.mediaType.getBase(entry) === "text/event-stream") return "events";
|
|
408
|
+
return entry.stream && ast.mediaType.isStream(entry) ? "lines" : void 0;
|
|
103
409
|
}
|
|
104
410
|
/**
|
|
105
411
|
* Whether an operation streams its primary success response, as Server-Sent Events or JSON Lines. The client generator uses
|
|
@@ -109,20 +415,42 @@ function isEventStream(node) {
|
|
|
109
415
|
return getEventStream(node) !== null;
|
|
110
416
|
}
|
|
111
417
|
/**
|
|
418
|
+
* Whether a success response offers a stream media type next to other content types. The client returns that variant's
|
|
419
|
+
* body as a `ReadableStream`, so the stream runtime is registered and a hook's data type includes the stream.
|
|
420
|
+
*/
|
|
421
|
+
function hasStreamVariant(node) {
|
|
422
|
+
return ast.http.responses.filterSuccess(node).some((response) => {
|
|
423
|
+
const variants = (response.content ?? []).filter((entry) => entry.schema);
|
|
424
|
+
return variants.length > 1 && variants.some((entry) => ast.mediaType.isStream(entry));
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
112
428
|
* Builds the `client?:` option type shared by the generated query hooks (`useQuery`,
|
|
113
|
-
* `useInfiniteQuery`, `useSWR`, ...)
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
429
|
+
* `useInfiniteQuery`, `useSWR`, ...): `RequestConfig` minus what the
|
|
430
|
+
* hook fills in, which is every request group and `throwOnError`. Unlike {@link buildRequestConfigType},
|
|
431
|
+
* it never narrows `contentType`: query hooks wrap GET operations, which carry no request body to select
|
|
432
|
+
* a content type for.
|
|
117
433
|
*/
|
|
118
|
-
function buildClientOptionType(
|
|
119
|
-
return `Partial<Omit<RequestConfig,
|
|
434
|
+
function buildClientOptionType(options = {}) {
|
|
435
|
+
return `Partial<Omit<RequestConfig, ${[
|
|
436
|
+
...requestGroupOrder,
|
|
437
|
+
"url",
|
|
438
|
+
...options.omit ?? [],
|
|
439
|
+
"throwOnError"
|
|
440
|
+
].map((key) => `'${key}'`).join(" | ")}>>`;
|
|
120
441
|
}
|
|
442
|
+
/**
|
|
443
|
+
* The `client?:` option type of a mutation hook. When the operation has a request content type choice,
|
|
444
|
+
* the mutation variables carry `contentType`, so the config leaves it out. Otherwise the ambiguous side is
|
|
445
|
+
* narrowed to the operation's media types; a single-type side has nothing to pick, so it stays baked in the
|
|
446
|
+
* generated call.
|
|
447
|
+
*/
|
|
121
448
|
function buildRequestConfigType(node) {
|
|
449
|
+
if (hasRequestContentTypeChoice(node)) return buildClientOptionType({ omit: ["contentType"] });
|
|
122
450
|
const request = getContentTypeInfo(node);
|
|
123
451
|
const response = getResponseContentTypeInfo(node);
|
|
124
452
|
const members = [request.isMultipleContentTypes ? `request?: ${request.contentTypeUnion}` : null, response.isMultipleContentTypes ? `response?: ${response.contentTypeUnion}` : null].filter(Boolean);
|
|
125
|
-
const base = buildClientOptionType(
|
|
453
|
+
const base = buildClientOptionType();
|
|
126
454
|
return members.length ? `${base} & { contentType?: { ${members.join("; ")} } }` : base;
|
|
127
455
|
}
|
|
128
456
|
/** The grouped request options, in the order generated signatures and calls list them. */
|
|
@@ -137,11 +465,11 @@ const requestGroupOrder = [
|
|
|
137
465
|
* Which of the grouped request options an operation carries.
|
|
138
466
|
*/
|
|
139
467
|
function getRequestGroups(node) {
|
|
140
|
-
const { path, query, header, cookie } =
|
|
468
|
+
const { path, query, header, cookie } = ast.http.groupParameters(node);
|
|
141
469
|
return {
|
|
142
470
|
path: path.length > 0,
|
|
143
471
|
query: query.length > 0,
|
|
144
|
-
body: Boolean(
|
|
472
|
+
body: Boolean(ast.http.requestBody.getSchema(node)),
|
|
145
473
|
headers: header.length > 0,
|
|
146
474
|
cookies: cookie.length > 0
|
|
147
475
|
};
|
|
@@ -153,7 +481,7 @@ function getRequestGroups(node) {
|
|
|
153
481
|
*/
|
|
154
482
|
function getRequestGroupOptionality(node) {
|
|
155
483
|
const groups = getRequestGroups(node);
|
|
156
|
-
const { path, query, header } =
|
|
484
|
+
const { path, query, header } = ast.http.groupParameters(node);
|
|
157
485
|
const hasRequiredPath = path.some((param) => param.required);
|
|
158
486
|
const hasRequiredQuery = query.some((param) => param.required);
|
|
159
487
|
const hasRequiredHeader = header.some((param) => param.required);
|
|
@@ -166,104 +494,28 @@ function getRequestGroupOptionality(node) {
|
|
|
166
494
|
};
|
|
167
495
|
}
|
|
168
496
|
function buildOperationComments(node, options = {}) {
|
|
169
|
-
const {
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
node.description && `@description ${node.description}`,
|
|
173
|
-
node.summary && `@summary ${node.summary}`,
|
|
174
|
-
linkComment,
|
|
175
|
-
node.deprecated && "@deprecated"
|
|
176
|
-
] : [
|
|
497
|
+
const { splitLines = false } = options;
|
|
498
|
+
const filteredComments = [
|
|
499
|
+
getOperationRequestLine(node),
|
|
177
500
|
node.description && `@description ${node.description}`,
|
|
178
501
|
node.summary && `@summary ${node.summary}`,
|
|
179
502
|
node.deprecated && "@deprecated",
|
|
180
|
-
|
|
181
|
-
]
|
|
503
|
+
node.externalDocs && `@see ${jsDocEscape([node.externalDocs.url, node.externalDocs.description].filter(Boolean).join(" "))}`
|
|
504
|
+
].filter((comment) => Boolean(comment));
|
|
182
505
|
if (!splitLines) return filteredComments;
|
|
183
506
|
return filteredComments.flatMap((text) => text.split(/\r?\n/).map((line) => line.trim())).filter((comment) => Boolean(comment));
|
|
184
507
|
}
|
|
185
|
-
const operationParameterGroupsByNode = /* @__PURE__ */ new WeakMap();
|
|
186
|
-
/**
|
|
187
|
-
* An OpenAPI 3.2 `querystring` parameter is the whole query string, so a form-encoded object becomes one query parameter
|
|
188
|
-
* per property, typed and serialized like any other.
|
|
189
|
-
* Another content type, such as JSON, stays one parameter named after it, and the runtime sends its value as the whole query string.
|
|
190
|
-
*/
|
|
191
|
-
function spreadQuerystring(param) {
|
|
192
|
-
const schema = param.schema.type === "ref" ? param.schema.schema : param.schema;
|
|
193
|
-
const formEncoded = !param.contentType || param.contentType.split(";")[0].trim().toLowerCase() === "application/x-www-form-urlencoded";
|
|
194
|
-
if (schema?.type !== "object" || !formEncoded) return [param];
|
|
195
|
-
return schema.properties.map((property) => ast.factory.createParameter({
|
|
196
|
-
name: property.name,
|
|
197
|
-
in: "query",
|
|
198
|
-
schema: property.schema,
|
|
199
|
-
required: param.required && property.required
|
|
200
|
-
}));
|
|
201
|
-
}
|
|
202
|
-
/**
|
|
203
|
-
* Groups an operation's parameters by location (`path`/`query`/`header`/`cookie`), deduping each
|
|
204
|
-
* group by name. Every plugin generator visiting the same `OperationNode` shares one AST instance
|
|
205
|
-
* (see `KubbDriver`), so the result is cached per node to avoid re-filtering and re-deduping the
|
|
206
|
-
* same parameters once per plugin.
|
|
207
|
-
*/
|
|
208
|
-
function getOperationParameters(node) {
|
|
209
|
-
const cached = operationParameterGroupsByNode.get(node);
|
|
210
|
-
if (cached) return cached;
|
|
211
|
-
const dedupe = (params) => {
|
|
212
|
-
const seen = /* @__PURE__ */ new Set();
|
|
213
|
-
return params.filter((param) => {
|
|
214
|
-
if (seen.has(param.name)) return false;
|
|
215
|
-
seen.add(param.name);
|
|
216
|
-
return true;
|
|
217
|
-
});
|
|
218
|
-
};
|
|
219
|
-
const group = (location) => dedupe(node.parameters.filter((param) => param.in === location));
|
|
220
|
-
const groups = {
|
|
221
|
-
path: group("path"),
|
|
222
|
-
query: dedupe([...group("query"), ...group("querystring").flatMap(spreadQuerystring)]),
|
|
223
|
-
header: group("header"),
|
|
224
|
-
cookie: group("cookie")
|
|
225
|
-
};
|
|
226
|
-
operationParameterGroupsByNode.set(node, groups);
|
|
227
|
-
return groups;
|
|
228
|
-
}
|
|
229
508
|
/**
|
|
230
509
|
* Whether the operation declares more than one request media type with a schema, so a caller must pick one on `contentType`.
|
|
231
510
|
*/
|
|
232
511
|
function hasRequestContentTypeChoice(node) {
|
|
233
512
|
return (node.requestBody?.content ?? []).filter((entry) => entry.schema).length > 1;
|
|
234
513
|
}
|
|
235
|
-
/**
|
|
236
|
-
* Casts a call argument to the client's parameter type; a `'plain'` client is non-generic.
|
|
237
|
-
*/
|
|
238
|
-
function castToClientOptions(callArg, clientName, returnType = "full") {
|
|
239
|
-
return `${callArg} as Parameters<typeof ${clientName}${returnType === "plain" ? "" : "<true>"}>[0]`;
|
|
240
|
-
}
|
|
241
|
-
function getStatusCodeNumber(statusCode) {
|
|
242
|
-
const code = Number(statusCode);
|
|
243
|
-
return Number.isNaN(code) ? null : code;
|
|
244
|
-
}
|
|
245
|
-
function isSuccessStatusCode(statusCode) {
|
|
246
|
-
const code = getStatusCodeNumber(statusCode);
|
|
247
|
-
return code !== null && code >= 200 && code < 300;
|
|
248
|
-
}
|
|
249
|
-
function isErrorStatusCode(statusCode) {
|
|
250
|
-
const code = getStatusCodeNumber(statusCode);
|
|
251
|
-
return code !== null && code >= 400;
|
|
252
|
-
}
|
|
253
|
-
function getSuccessResponses(responses) {
|
|
254
|
-
return responses.filter((response) => isSuccessStatusCode(response.statusCode));
|
|
255
|
-
}
|
|
256
|
-
function getOperationSuccessResponses(node) {
|
|
257
|
-
return getSuccessResponses(node.responses);
|
|
258
|
-
}
|
|
259
|
-
function getPrimarySuccessResponse(node) {
|
|
260
|
-
return getOperationSuccessResponses(node)[0] ?? null;
|
|
261
|
-
}
|
|
262
514
|
function resolveErrorNames(node, resolver) {
|
|
263
|
-
return
|
|
515
|
+
return ast.http.responses.filterError(node).map((response) => resolver.response.status(node, response.statusCode));
|
|
264
516
|
}
|
|
265
517
|
function resolveSuccessNames(node, resolver) {
|
|
266
|
-
return
|
|
518
|
+
return ast.http.responses.filterSuccess(node).map((response) => resolver.response.status(node, response.statusCode));
|
|
267
519
|
}
|
|
268
520
|
function resolveStatusCodeNames(node, resolver) {
|
|
269
521
|
return node.responses.map((response) => resolver.response.status(node, response.statusCode));
|
|
@@ -275,7 +527,7 @@ function resolveStatusCodeNames(node, resolver) {
|
|
|
275
527
|
function resolveOperationTypeNames(node, resolver, options = {}) {
|
|
276
528
|
const key = `${node.operationId}\0${options.order ?? ""}\0${options.responseStatusNames ?? ""}\0${options.includeParams === false ? "noparams" : ""}\0${(options.exclude ?? []).join(",")}`;
|
|
277
529
|
return resolver.memo(`operationTypeNames:${key}`, () => {
|
|
278
|
-
const { path, query, header, cookie } =
|
|
530
|
+
const { path, query, header, cookie } = ast.http.groupParameters(node);
|
|
279
531
|
const responseStatusNames = options.responseStatusNames === "error" ? resolveErrorNames(node, resolver) : options.responseStatusNames === false ? [] : resolveStatusCodeNames(node, resolver);
|
|
280
532
|
const exclude = new Set(options.exclude ?? []);
|
|
281
533
|
const paramNames = options.includeParams === false ? [] : [
|
|
@@ -284,7 +536,7 @@ function resolveOperationTypeNames(node, resolver, options = {}) {
|
|
|
284
536
|
...header.map((param) => resolver.param.headers(node, param)),
|
|
285
537
|
...cookie.map((param) => resolver.param.cookies(node, param))
|
|
286
538
|
];
|
|
287
|
-
const bodyAndResponseNames = [
|
|
539
|
+
const bodyAndResponseNames = [ast.http.requestBody.getSchema(node) ? resolver.response.body(node) : null, resolver.response.response(node)];
|
|
288
540
|
return (options.order === "body-response-first" ? [
|
|
289
541
|
...bodyAndResponseNames,
|
|
290
542
|
...paramNames,
|
|
@@ -296,235 +548,139 @@ function resolveOperationTypeNames(node, resolver, options = {}) {
|
|
|
296
548
|
]).filter((name) => Boolean(name) && !exclude.has(name));
|
|
297
549
|
});
|
|
298
550
|
}
|
|
299
|
-
// ../../internals/
|
|
300
|
-
/**
|
|
301
|
-
* Uppercases only the first character of `text`, leaving the rest untouched.
|
|
302
|
-
* Unlike `pascalCase` it never re-splits word boundaries or strips characters.
|
|
303
|
-
*
|
|
304
|
-
* @example
|
|
305
|
-
* `capitalize('getPetById') // 'GetPetById'`
|
|
306
|
-
*/
|
|
307
|
-
function capitalize(text) {
|
|
308
|
-
return `${text.charAt(0).toUpperCase()}${text.slice(1)}`;
|
|
309
|
-
}
|
|
310
|
-
// ../../internals/utils/src/reserved.ts
|
|
311
|
-
/**
|
|
312
|
-
* JavaScript and Java reserved words.
|
|
313
|
-
* @link https://github.com/jonschlinkert/reserved/blob/master/index.js
|
|
314
|
-
*/
|
|
315
|
-
const reservedWords = /* @__PURE__ */ new Set([
|
|
316
|
-
"abstract",
|
|
317
|
-
"arguments",
|
|
318
|
-
"await",
|
|
319
|
-
"boolean",
|
|
320
|
-
"break",
|
|
321
|
-
"byte",
|
|
322
|
-
"case",
|
|
323
|
-
"catch",
|
|
324
|
-
"char",
|
|
325
|
-
"class",
|
|
326
|
-
"const",
|
|
327
|
-
"continue",
|
|
328
|
-
"debugger",
|
|
329
|
-
"default",
|
|
330
|
-
"delete",
|
|
331
|
-
"do",
|
|
332
|
-
"double",
|
|
333
|
-
"else",
|
|
334
|
-
"enum",
|
|
335
|
-
"eval",
|
|
336
|
-
"export",
|
|
337
|
-
"extends",
|
|
338
|
-
"false",
|
|
339
|
-
"final",
|
|
340
|
-
"finally",
|
|
341
|
-
"float",
|
|
342
|
-
"for",
|
|
343
|
-
"function",
|
|
344
|
-
"goto",
|
|
345
|
-
"if",
|
|
346
|
-
"implements",
|
|
347
|
-
"import",
|
|
348
|
-
"in",
|
|
349
|
-
"instanceof",
|
|
350
|
-
"int",
|
|
351
|
-
"interface",
|
|
352
|
-
"let",
|
|
353
|
-
"long",
|
|
354
|
-
"native",
|
|
355
|
-
"new",
|
|
356
|
-
"null",
|
|
357
|
-
"package",
|
|
358
|
-
"private",
|
|
359
|
-
"protected",
|
|
360
|
-
"public",
|
|
361
|
-
"return",
|
|
362
|
-
"short",
|
|
363
|
-
"static",
|
|
364
|
-
"super",
|
|
365
|
-
"switch",
|
|
366
|
-
"synchronized",
|
|
367
|
-
"this",
|
|
368
|
-
"throw",
|
|
369
|
-
"throws",
|
|
370
|
-
"transient",
|
|
371
|
-
"true",
|
|
372
|
-
"try",
|
|
373
|
-
"typeof",
|
|
374
|
-
"var",
|
|
375
|
-
"void",
|
|
376
|
-
"volatile",
|
|
377
|
-
"while",
|
|
378
|
-
"with",
|
|
379
|
-
"yield",
|
|
380
|
-
"Array",
|
|
381
|
-
"Date",
|
|
382
|
-
"hasOwnProperty",
|
|
383
|
-
"Infinity",
|
|
384
|
-
"isFinite",
|
|
385
|
-
"isNaN",
|
|
386
|
-
"isPrototypeOf",
|
|
387
|
-
"length",
|
|
388
|
-
"Math",
|
|
389
|
-
"name",
|
|
390
|
-
"NaN",
|
|
391
|
-
"Number",
|
|
392
|
-
"Object",
|
|
393
|
-
"prototype",
|
|
394
|
-
"String",
|
|
395
|
-
"toString",
|
|
396
|
-
"undefined",
|
|
397
|
-
"valueOf"
|
|
398
|
-
]);
|
|
551
|
+
// ../../internals/shared/src/resolver.ts
|
|
399
552
|
/**
|
|
400
|
-
*
|
|
401
|
-
*
|
|
402
|
-
* @example
|
|
403
|
-
* ```ts
|
|
404
|
-
* isValidVarName('status') // true
|
|
405
|
-
* isValidVarName('class') // false (reserved word)
|
|
406
|
-
* isValidVarName('42foo') // false (starts with digit)
|
|
407
|
-
* ```
|
|
553
|
+
* The shared top-level `name` of the operation plugins, computed once per operation name and build.
|
|
408
554
|
*/
|
|
409
|
-
function
|
|
410
|
-
|
|
411
|
-
return isIdentifier(name);
|
|
555
|
+
function resolveOperationName(name) {
|
|
556
|
+
return this.memo(`operation:${name}`, () => ensureValidVarName(casing.camel(name)));
|
|
412
557
|
}
|
|
413
558
|
/**
|
|
414
|
-
*
|
|
415
|
-
*
|
|
559
|
+
* Builds the allocation key for a declaration an operation owns. `scope` names which declaration
|
|
560
|
+
* it is, so two of them never share an allocation even when a custom resolver gives both the same
|
|
561
|
+
* name. Leave `scope` empty for the operation's own declaration.
|
|
416
562
|
*
|
|
417
|
-
*
|
|
418
|
-
*
|
|
419
|
-
* variable, type, or function names.
|
|
563
|
+
* The key starts from the operation's input `pointer`, which macros keep, so a plugin whose macro
|
|
564
|
+
* rewrites the method or path still resolves another plugin's names for the same operation.
|
|
420
565
|
*
|
|
421
566
|
* @example
|
|
422
567
|
* ```ts
|
|
423
|
-
*
|
|
424
|
-
* ensureValidVarName('504AccountCancel') // '_504AccountCancel'
|
|
425
|
-
* ensureValidVarName('Pet') // 'Pet'
|
|
426
|
-
* ensureValidVarName('class') // '_class'
|
|
568
|
+
* resolver.resolveName({ key: operationKey(node, 'response', 'status', 404), name })
|
|
427
569
|
* ```
|
|
428
570
|
*/
|
|
429
|
-
function
|
|
430
|
-
|
|
431
|
-
|
|
571
|
+
function operationKey(node, ...scope) {
|
|
572
|
+
return [
|
|
573
|
+
"operation",
|
|
574
|
+
...node.pointer ? [node.pointer] : [node.method, node.path],
|
|
575
|
+
...scope.map(String)
|
|
576
|
+
];
|
|
577
|
+
}
|
|
578
|
+
// ../../internals/client/src/resolveClientOperation.ts
|
|
579
|
+
function isRelativeImport(importPath) {
|
|
580
|
+
return importPath.startsWith(".");
|
|
581
|
+
}
|
|
582
|
+
function resolveImportPath(options) {
|
|
583
|
+
const { importPath, operationFile } = options;
|
|
584
|
+
return isRelativeImport(importPath) ? path.resolve(path.dirname(operationFile), importPath) : importPath;
|
|
432
585
|
}
|
|
433
586
|
/**
|
|
434
|
-
*
|
|
587
|
+
* Resolves the contract client `<op>` a consumer (query hook, MCP handler) imports, by looking up
|
|
588
|
+
* the registered contract client plugin's resolver and output. Works for any contract client plugin
|
|
589
|
+
* (plugin-fetch, plugin-axios, or plugin-client). Returns `null` when no contract plugin is in play (the inline
|
|
590
|
+
* path), or when the client plugin's `exclude` / `include` leaves this operation out, since it then
|
|
591
|
+
* emits no `<op>` to import. plugin-fetch / plugin-axios inject `.kubb/client.ts` at the global
|
|
592
|
+
* output root, the same path consumers read `RequestConfig` / `ResponseErrorConfig` from.
|
|
593
|
+
* With plugin-client they come from the user's `importPath` module instead.
|
|
435
594
|
*
|
|
436
|
-
*
|
|
437
|
-
*
|
|
438
|
-
*
|
|
595
|
+
* The result is cached in `memo` (the build's `ctx.memo`) under the client plugin's name and the operation,
|
|
596
|
+
* so several dependents reading the same client plugin for one operation in a single pass
|
|
597
|
+
* (react-query's query/mutation/infinite generators, vue-query, swr, the MCP handler, ...) share
|
|
598
|
+
* one computed result instead of each re-deriving the name and path.
|
|
439
599
|
*
|
|
440
|
-
*
|
|
441
|
-
*
|
|
442
|
-
*
|
|
443
|
-
* isIdentifier('x-total')// false
|
|
444
|
-
* ```
|
|
600
|
+
* `returnType`, `output`, and `group` are the client plugin's options for this operation, after its
|
|
601
|
+
* `override` entries, the same resolution its own generator sees. A dependent's generated call body
|
|
602
|
+
* and import path therefore match the `<op>` actually emitted, even when an `override` changes it.
|
|
445
603
|
*/
|
|
446
|
-
function
|
|
447
|
-
|
|
604
|
+
function resolveClientOperation(options) {
|
|
605
|
+
const { clientPlugin, driver, node, root, output, memo } = options;
|
|
606
|
+
if (!clientPlugin) return null;
|
|
607
|
+
return memo(`${clientPlugin.pluginName}:clientOperation:${node.operationId}`, () => {
|
|
608
|
+
const resolver = driver.getResolver(clientPlugin.pluginName);
|
|
609
|
+
const pluginOptions = driver.getPlugin(clientPlugin.pluginName)?.options ?? {};
|
|
610
|
+
const { exclude, include, override } = pluginOptions;
|
|
611
|
+
const operationOptions = Boolean(exclude?.length || include?.length || override?.length) && resolver.default ? resolver.default.options(node, {
|
|
612
|
+
options: pluginOptions,
|
|
613
|
+
exclude,
|
|
614
|
+
include,
|
|
615
|
+
override
|
|
616
|
+
}) : pluginOptions;
|
|
617
|
+
if (!operationOptions) return null;
|
|
618
|
+
const file = resolver.file({
|
|
619
|
+
...operationFileEntry(node, node.operationId),
|
|
620
|
+
root,
|
|
621
|
+
output: operationOptions.output ?? output,
|
|
622
|
+
group: operationOptions.group ?? void 0
|
|
623
|
+
});
|
|
624
|
+
const { importPath } = operationOptions;
|
|
625
|
+
const name = resolver.name(node.operationId);
|
|
626
|
+
return {
|
|
627
|
+
name: resolver.resolveName({
|
|
628
|
+
key: operationKey(node),
|
|
629
|
+
name
|
|
630
|
+
}),
|
|
631
|
+
path: file.path,
|
|
632
|
+
clientPath: importPath === void 0 ? path.resolve(root, ".kubb/client.ts") : resolveImportPath({
|
|
633
|
+
importPath,
|
|
634
|
+
operationFile: file.path
|
|
635
|
+
}),
|
|
636
|
+
clientPathIsFile: importPath === void 0 || isRelativeImport(importPath),
|
|
637
|
+
returnType: operationOptions.returnType ?? "full",
|
|
638
|
+
typedHeaders: importPath === void 0
|
|
639
|
+
};
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
// ../../internals/client/src/resolveOperationTypes.ts
|
|
643
|
+
const pluginZodName = "plugin-zod";
|
|
644
|
+
function getResponseHeadersEntries({ node, types }) {
|
|
645
|
+
const resolve = types.response.headers;
|
|
646
|
+
if (!resolve) return [];
|
|
647
|
+
return node.responses.filter((response) => response.headers?.length).map((response) => [response.statusCode, resolve.call(types.response, node, response.statusCode)]);
|
|
448
648
|
}
|
|
449
|
-
// ../../internals/utils/src/strings.ts
|
|
450
649
|
/**
|
|
451
|
-
*
|
|
452
|
-
* `accessor`. Returns `null` for an empty path.
|
|
453
|
-
*
|
|
454
|
-
* @example
|
|
455
|
-
* ```ts
|
|
456
|
-
* getNestedAccessor('pagination.next.id', 'lastPage')
|
|
457
|
-
* // "lastPage?.['pagination']?.['next']?.['id']"
|
|
458
|
-
* ```
|
|
650
|
+
* The headers type argument of `RequestResult`, such as `{ '200': LoginUserStatus200Headers }`, or `null` when no response declares headers.
|
|
459
651
|
*/
|
|
460
|
-
function
|
|
461
|
-
const
|
|
462
|
-
|
|
463
|
-
|
|
652
|
+
function buildResponseHeadersType({ node, types }) {
|
|
653
|
+
const entries = getResponseHeadersEntries({
|
|
654
|
+
node,
|
|
655
|
+
types
|
|
656
|
+
}).map(([statusCode, name]) => `'${statusCode}': ${name}`);
|
|
657
|
+
return entries.length ? `{ ${entries.join("; ")} }` : null;
|
|
464
658
|
}
|
|
465
|
-
// ../../internals/shared/src/resolver.ts
|
|
466
659
|
/**
|
|
467
|
-
*
|
|
660
|
+
* A runtime result type, such as `RequestResult`, in its `WithHeaders` form when `headers` is set.
|
|
468
661
|
*/
|
|
469
|
-
function
|
|
470
|
-
return
|
|
662
|
+
function resultTypeName(name, headers) {
|
|
663
|
+
return headers ? `${name}WithHeaders` : name;
|
|
471
664
|
}
|
|
472
665
|
/**
|
|
473
|
-
*
|
|
474
|
-
* it is, so two of them never share an allocation even when a custom resolver gives both the same
|
|
475
|
-
* name. Leave `scope` empty for the operation's own declaration.
|
|
476
|
-
*
|
|
477
|
-
* @example
|
|
478
|
-
* ```ts
|
|
479
|
-
* resolver.resolveName({ key: operationKey(node, 'response', 'status', 404), name })
|
|
480
|
-
* ```
|
|
666
|
+
* A runtime result type with its arguments, such as `RequestResultWithHeaders<Responses, Headers, ThrowOnError>`.
|
|
481
667
|
*/
|
|
482
|
-
function
|
|
483
|
-
return [
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
];
|
|
668
|
+
function buildResultTypeRef(name, responses, headers, rest = []) {
|
|
669
|
+
return `${resultTypeName(name, headers !== null)}<${[
|
|
670
|
+
responses,
|
|
671
|
+
headers,
|
|
672
|
+
...rest
|
|
673
|
+
].filter(Boolean).join(", ")}>`;
|
|
489
674
|
}
|
|
490
|
-
// ../../internals/shared/src/group.ts
|
|
491
675
|
/**
|
|
492
|
-
*
|
|
493
|
-
* shared default naming so every plugin groups output consistently:
|
|
494
|
-
*
|
|
495
|
-
* - `path` groups use the second path segment (`/pet/findByStatus` → `pet`).
|
|
496
|
-
* - other groups use the camelCased group (`pet store` → `petStore`).
|
|
497
|
-
*
|
|
498
|
-
* A user-provided `group.name` always wins over the default namer, so callers stay in
|
|
499
|
-
* control of their output folders. Returns `null` when grouping is disabled, matching the
|
|
500
|
-
* per-plugin convention.
|
|
501
|
-
*
|
|
502
|
-
* @param group - The user-supplied group option, or `undefined` to disable grouping.
|
|
503
|
-
*
|
|
504
|
-
* @example
|
|
505
|
-
* ```ts
|
|
506
|
-
* createGroupConfig(group) // shared across every plugin
|
|
507
|
-
* ```
|
|
676
|
+
* The names of the headers types `buildResponseHeadersType` references, for the file's imports.
|
|
508
677
|
*/
|
|
509
|
-
function
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
};
|
|
515
|
-
return {
|
|
516
|
-
...group,
|
|
517
|
-
name: group.name ? group.name : defaultName
|
|
518
|
-
};
|
|
678
|
+
function getResponseHeadersTypeNames({ node, types }) {
|
|
679
|
+
return getResponseHeadersEntries({
|
|
680
|
+
node,
|
|
681
|
+
types
|
|
682
|
+
}).map(([, name]) => name);
|
|
519
683
|
}
|
|
520
|
-
// kubb-extension.json
|
|
521
|
-
var compatibility = {
|
|
522
|
-
"kubb": ">=5.16.0",
|
|
523
|
-
"node": ">=22.22"
|
|
524
|
-
};
|
|
525
|
-
// package.json
|
|
526
|
-
var version = "5.10.0-canary.20261109T191216";
|
|
527
|
-
// ../../internals/client/src/resolveOperationTypes.ts
|
|
528
684
|
/**
|
|
529
685
|
* A `plugin-ts` shaped resolver whose operation type names point at the types `pluginZod({ inferred })`
|
|
530
686
|
* exports next to each schema, so code written against `plugin-ts` names picks up the zod types.
|
|
@@ -547,6 +703,7 @@ function toZodTypeResolver(resolver) {
|
|
|
547
703
|
status: (node, statusCode) => type(resolver.response.status(node, statusCode)),
|
|
548
704
|
response: (node) => type(resolver.response.response(node)),
|
|
549
705
|
responses: (node) => type(resolver.response.responses(node)),
|
|
706
|
+
headers: (node, statusCode) => type(resolver.response.headers(node, statusCode)),
|
|
550
707
|
options: (node) => resolver.response.options(node)
|
|
551
708
|
}
|
|
552
709
|
};
|
|
@@ -594,179 +751,6 @@ function resolveOperationTypes(driver, pluginName) {
|
|
|
594
751
|
};
|
|
595
752
|
});
|
|
596
753
|
}
|
|
597
|
-
// ../../internals/client/src/resolveClient.ts
|
|
598
|
-
/**
|
|
599
|
-
* Resolves which client plugin a consumer (react-query, vue-query, swr, mcp) should call for an
|
|
600
|
-
* operation, shared so the selection rules and diagnostics stay in one place.
|
|
601
|
-
*
|
|
602
|
-
* Every client runtime lives in a dedicated client plugin, so a consumer always calls a registered
|
|
603
|
-
* contract client plugin (plugin-fetch, plugin-axios, or plugin-client) and never emits its own
|
|
604
|
-
* inline client:
|
|
605
|
-
*
|
|
606
|
-
* - `contract` — a registered contract client plugin owns the `<op>` functions and the consumer
|
|
607
|
-
* imports and calls them.
|
|
608
|
-
* - `error` — no client plugin is registered, several are registered without a selector, the
|
|
609
|
-
* requested one is missing, or `client` is not a known selector.
|
|
610
|
-
*
|
|
611
|
-
* The `client` string selects explicitly (`'fetch'` / `'axios'` / `'client'`); when it is unset a
|
|
612
|
-
* lone registered contract client plugin is picked up automatically.
|
|
613
|
-
*/
|
|
614
|
-
const pluginFetchName = "plugin-fetch";
|
|
615
|
-
const pluginAxiosName = "plugin-axios";
|
|
616
|
-
const pluginClientName = "plugin-client";
|
|
617
|
-
const selectorToPlugin = {
|
|
618
|
-
fetch: pluginFetchName,
|
|
619
|
-
axios: pluginAxiosName,
|
|
620
|
-
client: pluginClientName
|
|
621
|
-
};
|
|
622
|
-
const contractPlugins = [
|
|
623
|
-
pluginFetchName,
|
|
624
|
-
pluginAxiosName,
|
|
625
|
-
pluginClientName
|
|
626
|
-
];
|
|
627
|
-
/**
|
|
628
|
-
* Applies the `client` resolution rules. See the module comment for the strategy shape.
|
|
629
|
-
*
|
|
630
|
-
* @example
|
|
631
|
-
* ```ts
|
|
632
|
-
* resolveClient({ client: 'fetch', pluginNames: ['plugin-ts', 'plugin-fetch'] })
|
|
633
|
-
* // { kind: 'contract', pluginName: 'plugin-fetch' }
|
|
634
|
-
* ```
|
|
635
|
-
*
|
|
636
|
-
* @example
|
|
637
|
-
* ```ts
|
|
638
|
-
* resolveClient({ client: undefined, pluginNames: ['plugin-ts'] })
|
|
639
|
-
* // { kind: 'error', code: 'KUBB_MISSING_DEPENDENCY', message: 'No client plugin is registered.', help: 'Add …' }
|
|
640
|
-
* ```
|
|
641
|
-
*/
|
|
642
|
-
function resolveClient(options) {
|
|
643
|
-
const { client, pluginNames } = options;
|
|
644
|
-
const has = (name) => pluginNames.includes(name);
|
|
645
|
-
if (client === "fetch" || client === "axios" || client === "client") {
|
|
646
|
-
const pluginName = selectorToPlugin[client];
|
|
647
|
-
if (!has(pluginName)) return {
|
|
648
|
-
kind: "error",
|
|
649
|
-
code: Diagnostics.code.missingDependency,
|
|
650
|
-
message: `\`client: '${client}'\` is set but \`@kubb/plugin-${client}\` is not registered in \`plugins\`.`,
|
|
651
|
-
help: `Add \`@kubb/plugin-${client}\` to \`plugins\`, or drop \`client\` to use a different client plugin.`
|
|
652
|
-
};
|
|
653
|
-
return {
|
|
654
|
-
kind: "contract",
|
|
655
|
-
pluginName
|
|
656
|
-
};
|
|
657
|
-
}
|
|
658
|
-
if (client !== void 0) return {
|
|
659
|
-
kind: "error",
|
|
660
|
-
code: Diagnostics.code.invalidPluginOptions,
|
|
661
|
-
message: `Option \`client\` is ${typeof client === "string" ? `'${client}'` : String(client)}, but it must be one of 'fetch', 'axios', 'client'.`,
|
|
662
|
-
help: "Set `client` to one of those values, or drop it to use the registered client plugin."
|
|
663
|
-
};
|
|
664
|
-
const registered = contractPlugins.filter(has);
|
|
665
|
-
if (registered.length === 1) return {
|
|
666
|
-
kind: "contract",
|
|
667
|
-
pluginName: registered[0]
|
|
668
|
-
};
|
|
669
|
-
if (registered.length > 1) return {
|
|
670
|
-
kind: "error",
|
|
671
|
-
code: Diagnostics.code.invalidPluginOptions,
|
|
672
|
-
message: `Multiple client plugins are registered (${registered.map((name) => `\`@kubb/${name}\``).join(", ")}) and \`client\` is not set.`,
|
|
673
|
-
help: "Set `client: 'fetch' | 'axios' | 'client'` to choose which client the hooks call, or register a single client plugin."
|
|
674
|
-
};
|
|
675
|
-
return {
|
|
676
|
-
kind: "error",
|
|
677
|
-
code: Diagnostics.code.missingDependency,
|
|
678
|
-
message: "No client plugin is registered.",
|
|
679
|
-
help: "Add `@kubb/plugin-fetch`, `@kubb/plugin-axios`, or `@kubb/plugin-client` to `plugins` so the generated code has an HTTP client to call."
|
|
680
|
-
};
|
|
681
|
-
}
|
|
682
|
-
/**
|
|
683
|
-
* Resolves the contract client during a consumer plugin's setup hook.
|
|
684
|
-
* It extracts the plugin names from the raw `plugins` config and applies {@link resolveClient}.
|
|
685
|
-
* On a misconfiguration it throws a config diagnostic tagged with `plugin`, so every consumer
|
|
686
|
-
* fails fast with the same message.
|
|
687
|
-
*/
|
|
688
|
-
function resolveContractClient(options) {
|
|
689
|
-
const { plugin, client, plugins = [] } = options;
|
|
690
|
-
const resolved = resolveClient({
|
|
691
|
-
client,
|
|
692
|
-
pluginNames: plugins.map((plugin) => plugin.name).filter((name) => Boolean(name))
|
|
693
|
-
});
|
|
694
|
-
if (resolved.kind === "error") {
|
|
695
|
-
const { code, message, help } = resolved;
|
|
696
|
-
throw new Diagnostics.Error({
|
|
697
|
-
code,
|
|
698
|
-
severity: "error",
|
|
699
|
-
message,
|
|
700
|
-
help,
|
|
701
|
-
location: { kind: "config" },
|
|
702
|
-
plugin
|
|
703
|
-
});
|
|
704
|
-
}
|
|
705
|
-
return resolved;
|
|
706
|
-
}
|
|
707
|
-
// ../../internals/client/src/resolveClientOperation.ts
|
|
708
|
-
function isRelativeImport(importPath) {
|
|
709
|
-
return importPath.startsWith(".");
|
|
710
|
-
}
|
|
711
|
-
function resolveImportPath(options) {
|
|
712
|
-
const { importPath, operationFile } = options;
|
|
713
|
-
return isRelativeImport(importPath) ? path.resolve(path.dirname(operationFile), importPath) : importPath;
|
|
714
|
-
}
|
|
715
|
-
/**
|
|
716
|
-
* Resolves the contract client `<op>` a consumer (query hook, MCP handler) imports, by looking up
|
|
717
|
-
* the registered contract client plugin's resolver and output. Works for any contract client plugin
|
|
718
|
-
* (plugin-fetch, plugin-axios, or plugin-client). Returns `null` when no contract plugin is in play (the inline
|
|
719
|
-
* path), or when the client plugin's `exclude` / `include` leaves this operation out, since it then
|
|
720
|
-
* emits no `<op>` to import. plugin-fetch / plugin-axios inject `.kubb/client.ts` at the global
|
|
721
|
-
* output root, the same path consumers read `RequestConfig` / `ResponseErrorConfig` from.
|
|
722
|
-
* With plugin-client they come from the user's `importPath` module instead.
|
|
723
|
-
*
|
|
724
|
-
* The result is cached in `memo` (the build's `ctx.memo`) under the client plugin's name and the operation,
|
|
725
|
-
* so several dependents reading the same client plugin for one operation in a single pass
|
|
726
|
-
* (react-query's query/mutation/infinite generators, vue-query, swr, the MCP handler, ...) share
|
|
727
|
-
* one computed result instead of each re-deriving the name and path.
|
|
728
|
-
*
|
|
729
|
-
* `returnType`, `output`, and `group` are the client plugin's options for this operation, after its
|
|
730
|
-
* `override` entries, the same resolution its own generator sees. A dependent's generated call body
|
|
731
|
-
* and import path therefore match the `<op>` actually emitted, even when an `override` changes it.
|
|
732
|
-
*/
|
|
733
|
-
function resolveClientOperation(options) {
|
|
734
|
-
const { clientPlugin, driver, node, root, output, memo } = options;
|
|
735
|
-
if (!clientPlugin) return null;
|
|
736
|
-
return memo(`${clientPlugin.pluginName}:clientOperation:${node.operationId}`, () => {
|
|
737
|
-
const resolver = driver.getResolver(clientPlugin.pluginName);
|
|
738
|
-
const pluginOptions = driver.getPlugin(clientPlugin.pluginName)?.options ?? {};
|
|
739
|
-
const { exclude, include, override } = pluginOptions;
|
|
740
|
-
const operationOptions = Boolean(exclude?.length || include?.length || override?.length) && resolver.default ? resolver.default.options(node, {
|
|
741
|
-
options: pluginOptions,
|
|
742
|
-
exclude,
|
|
743
|
-
include,
|
|
744
|
-
override
|
|
745
|
-
}) : pluginOptions;
|
|
746
|
-
if (!operationOptions) return null;
|
|
747
|
-
const file = resolver.file({
|
|
748
|
-
...operationFileEntry(node, node.operationId),
|
|
749
|
-
root,
|
|
750
|
-
output: operationOptions.output ?? output,
|
|
751
|
-
group: operationOptions.group ?? void 0
|
|
752
|
-
});
|
|
753
|
-
const { importPath } = operationOptions;
|
|
754
|
-
const name = resolver.name(node.operationId);
|
|
755
|
-
return {
|
|
756
|
-
name: resolver.resolveName({
|
|
757
|
-
key: operationKey(node),
|
|
758
|
-
name
|
|
759
|
-
}),
|
|
760
|
-
path: file.path,
|
|
761
|
-
clientPath: importPath === void 0 ? path.resolve(root, ".kubb/client.ts") : resolveImportPath({
|
|
762
|
-
importPath,
|
|
763
|
-
operationFile: file.path
|
|
764
|
-
}),
|
|
765
|
-
clientPathIsFile: importPath === void 0 || isRelativeImport(importPath),
|
|
766
|
-
returnType: operationOptions.returnType ?? "full"
|
|
767
|
-
};
|
|
768
|
-
});
|
|
769
|
-
}
|
|
770
754
|
// ../../internals/tanstack-query/src/components/HookFile.tsx
|
|
771
755
|
/**
|
|
772
756
|
* Resolves what every TanStack hook file shares: its file, the operation types file and names (`@kubb/plugin-ts`, or
|
|
@@ -785,14 +769,18 @@ function resolveHookFile(node, ctx, options) {
|
|
|
785
769
|
});
|
|
786
770
|
const types = resolveOperationTypes(ctx.driver, resolver.pluginName);
|
|
787
771
|
const tsResolver = types.resolver;
|
|
772
|
+
const headerTypeNames = returnType === "data" || !contractOp.typedHeaders ? [] : getResponseHeadersTypeNames({
|
|
773
|
+
node,
|
|
774
|
+
types: tsResolver
|
|
775
|
+
});
|
|
788
776
|
const file = resolver.file({
|
|
789
777
|
...operationFileEntry(node, name),
|
|
790
778
|
root,
|
|
791
779
|
output,
|
|
792
780
|
group: group ?? void 0
|
|
793
781
|
});
|
|
794
|
-
const fileTs =
|
|
795
|
-
|
|
782
|
+
const fileTs = resolveOperationFile({
|
|
783
|
+
ctx,
|
|
796
784
|
node,
|
|
797
785
|
resolver: tsResolver,
|
|
798
786
|
root,
|
|
@@ -802,6 +790,7 @@ function resolveHookFile(node, ctx, options) {
|
|
|
802
790
|
const importedTypeNames = [
|
|
803
791
|
tsResolver.response.options(node),
|
|
804
792
|
tsResolver.response.responses(node),
|
|
793
|
+
...headerTypeNames,
|
|
805
794
|
...extraTypeNames,
|
|
806
795
|
...resolveOperationTypeNames(node, tsResolver, {
|
|
807
796
|
exclude: [keyTypeName, returnType !== "data" ? tsResolver.response.response(node) : null].filter((name) => Boolean(name)),
|
|
@@ -819,6 +808,7 @@ function resolveHookFile(node, ctx, options) {
|
|
|
819
808
|
tsResolver,
|
|
820
809
|
contractOp,
|
|
821
810
|
importedTypeNames,
|
|
811
|
+
resultTypeName: headerTypeNames.length ? "RequestResultWithHeaders" : "RequestResult",
|
|
822
812
|
returnType,
|
|
823
813
|
banner: resolver.default.banner(ctx.meta, {
|
|
824
814
|
output,
|
|
@@ -836,7 +826,7 @@ function resolveHookFile(node, ctx, options) {
|
|
|
836
826
|
* The `<File>` shell shared by the TanStack hook generators; renders `children` after the imports.
|
|
837
827
|
*/
|
|
838
828
|
function HookFile({ hook, imports, children }) {
|
|
839
|
-
const { file, fileTs, contractOp, importedTypeNames, banner, footer } = hook;
|
|
829
|
+
const { file, fileTs, contractOp, importedTypeNames, resultTypeName, banner, footer } = hook;
|
|
840
830
|
return /* @__PURE__ */ jsxs(File, {
|
|
841
831
|
baseName: file.baseName,
|
|
842
832
|
path: file.path,
|
|
@@ -853,7 +843,7 @@ function HookFile({ hook, imports, children }) {
|
|
|
853
843
|
name: [
|
|
854
844
|
"RequestConfig",
|
|
855
845
|
"ResponseErrorConfig",
|
|
856
|
-
|
|
846
|
+
resultTypeName
|
|
857
847
|
],
|
|
858
848
|
root: contractOp.clientPathIsFile ? file.path : void 0,
|
|
859
849
|
path: contractOp.clientPath,
|
|
@@ -929,8 +919,8 @@ function buildGroupedRequestParam(node, options) {
|
|
|
929
919
|
/**
|
|
930
920
|
* Builds the shared `({ path, query, body, headers, cookies }, config = {})` parameter list for a
|
|
931
921
|
* TanStack query-options function. The leading parameter mirrors the client signature, and the
|
|
932
|
-
* trailing `config` is
|
|
933
|
-
*
|
|
922
|
+
* trailing `config` is the client's `Options` minus the request groups and `throwOnError`, which the
|
|
923
|
+
* hook passes itself. Framework plugins wrap the result when needed, for example vue-query applies `MaybeRefOrGetter`.
|
|
934
924
|
*/
|
|
935
925
|
function buildQueryOptionsParams(node, options) {
|
|
936
926
|
const { resolver, memberTypeWrapper } = options;
|
|
@@ -940,7 +930,7 @@ function buildQueryOptionsParams(node, options) {
|
|
|
940
930
|
});
|
|
941
931
|
const configParam = createFunctionParameter({
|
|
942
932
|
name: "config",
|
|
943
|
-
type: buildClientOptionType(
|
|
933
|
+
type: buildClientOptionType(),
|
|
944
934
|
default: "{}"
|
|
945
935
|
});
|
|
946
936
|
return createFunctionParameters({ params: [groupedParam, configParam].filter((param) => param !== null) });
|
|
@@ -952,26 +942,30 @@ function buildQueryOptionsParams(node, options) {
|
|
|
952
942
|
* can't flip the query's error semantics. Queries thread the TanStack `signal`; mutations omit it.
|
|
953
943
|
*
|
|
954
944
|
* When `unwrapName` is set, each request group is passed as an explicit member unwrapped through it,
|
|
955
|
-
* used by vue-query to resolve refs and getters with `toValue(...)` at call time.
|
|
945
|
+
* used by vue-query to resolve refs and getters with `toValue(...)` at call time. `pageParam` names the
|
|
946
|
+
* query parameter an infinite query sets from TanStack's `pageParam`.
|
|
956
947
|
*
|
|
957
948
|
* @example
|
|
958
949
|
* ```ts
|
|
959
950
|
* buildClientCall(node, { clientName: 'getPetById', signal: true })
|
|
960
|
-
* // getPetById({
|
|
951
|
+
* // getPetById({ ...config, path, signal: config.signal ?? signal, throwOnError: true })
|
|
961
952
|
* ```
|
|
962
953
|
*/
|
|
963
954
|
function buildClientCall(node, options) {
|
|
964
|
-
const { clientName, signal = false, unwrapName, withContentType = false,
|
|
955
|
+
const { clientName, signal = false, unwrapName, withContentType = false, pageParam } = options;
|
|
965
956
|
const { groups } = getRequestGroupOptionality(node);
|
|
966
957
|
const names = requestGroupOrder.filter((key) => groups[key]);
|
|
967
|
-
const
|
|
958
|
+
const member = (name) => {
|
|
959
|
+
const value = unwrapName ? unwrapName(name) : name;
|
|
960
|
+
if (name === "query" && pageParam) return `query: { ...${value}, ${JSON.stringify(pageParam)}: pageParam }`;
|
|
961
|
+
return unwrapName ? `${name}: ${value}` : name;
|
|
962
|
+
};
|
|
963
|
+
return `${clientName}({ ${[
|
|
968
964
|
"...config",
|
|
969
|
-
...withContentType && hasRequestContentTypeChoice(node) ? ["...variables"] : names.map(
|
|
965
|
+
...withContentType && hasRequestContentTypeChoice(node) ? ["...variables"] : names.map(member),
|
|
970
966
|
signal ? "signal: config.signal ?? signal" : null,
|
|
971
967
|
"throwOnError: true"
|
|
972
|
-
].filter((part) => part !== null)
|
|
973
|
-
if (withContentType && hasRequestContentTypeChoice(node)) return `${clientName}(${castToClientOptions(`{ ${args.join(", ")} }`, clientName, returnType)})`;
|
|
974
|
-
return `${clientName}({ ${args.join(", ")} })`;
|
|
968
|
+
].filter((part) => part !== null).join(", ")} })`;
|
|
975
969
|
}
|
|
976
970
|
/**
|
|
977
971
|
* Builds the query/mutation body that resolves a `buildClientCall` expression down to the bare
|
|
@@ -994,19 +988,28 @@ function buildCallResultBody(call, options = {}) {
|
|
|
994
988
|
if (clientReturnType === "plain") return `return (await ${call}).data`;
|
|
995
989
|
return `return ${call}.unwrap()`;
|
|
996
990
|
}
|
|
991
|
+
function buildResultType(node, resolver, typedHeaders) {
|
|
992
|
+
const headers = typedHeaders ? buildResponseHeadersType({
|
|
993
|
+
node,
|
|
994
|
+
types: resolver
|
|
995
|
+
}) : null;
|
|
996
|
+
return buildResultTypeRef("RequestResult", resolver.response.responses(node), headers, ["true"]);
|
|
997
|
+
}
|
|
997
998
|
/**
|
|
998
999
|
* Builds the `TData` / `TError` type expressions shared by every generated hook, joining the resolved
|
|
999
1000
|
* success responses into `TData` and wrapping the error responses in `ResponseErrorConfig<...>`.
|
|
1000
|
-
* With `returnType` `'full'`, `TData` is the client's `RequestResult` over the operation's responses record
|
|
1001
|
+
* With `returnType` `'full'`, `TData` is the client's `RequestResult` over the operation's responses record, with the
|
|
1002
|
+
* response headers the operation declares.
|
|
1001
1003
|
*/
|
|
1002
1004
|
function buildResponseTypes(node, resolver, options = {}) {
|
|
1003
|
-
const { returnType = "data" } = options;
|
|
1004
|
-
return resolver.memo(`responseTypes:${returnType}:${node.method}\0${node.path}`, () => {
|
|
1005
|
+
const { returnType = "data", typedHeaders = true } = options;
|
|
1006
|
+
return resolver.memo(`responseTypes:${returnType}:${typedHeaders}:${node.method}\0${node.path}`, () => {
|
|
1005
1007
|
const successNames = resolveSuccessNames(node, resolver);
|
|
1006
|
-
const
|
|
1008
|
+
const bodyName = successNames.length > 0 ? successNames.join(" | ") : resolver.response.response(node);
|
|
1009
|
+
const responseName = hasStreamVariant(node) ? `${bodyName} | ReadableStream<Uint8Array>` : bodyName;
|
|
1007
1010
|
const errorNames = resolveErrorNames(node, resolver);
|
|
1008
1011
|
return {
|
|
1009
|
-
TData: returnType
|
|
1012
|
+
TData: returnType === "data" ? responseName : buildResultType(node, resolver, typedHeaders),
|
|
1010
1013
|
TError: `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(" | ") : "Error"}>`
|
|
1011
1014
|
};
|
|
1012
1015
|
});
|
|
@@ -1025,7 +1028,7 @@ function resolveFallbackPageParamType(initialPageParam) {
|
|
|
1025
1028
|
* so callers can reuse it when rewriting the paginated request.
|
|
1026
1029
|
*/
|
|
1027
1030
|
function resolvePageParamType(node, { resolver, initialPageParam, queryParam }) {
|
|
1028
|
-
const firstQueryParam =
|
|
1031
|
+
const firstQueryParam = ast.http.groupParameters(node).query[0];
|
|
1029
1032
|
const groupName = firstQueryParam ? resolver.param.query(node, firstQueryParam) : null;
|
|
1030
1033
|
const queryParamsTypeName = groupName !== (firstQueryParam ? resolver.param.name(node, firstQueryParam) : null) ? groupName : null;
|
|
1031
1034
|
const queryParamType = queryParam && queryParamsTypeName ? `${queryParamsTypeName}['${queryParam}']` : null;
|
|
@@ -1128,7 +1131,7 @@ function resolveInfiniteConfig(infinite) {
|
|
|
1128
1131
|
*/
|
|
1129
1132
|
function matchesInfinite(node, infinite) {
|
|
1130
1133
|
if (!infinite.queryParam) return false;
|
|
1131
|
-
return
|
|
1134
|
+
return ast.http.groupParameters(node).query.some((param) => param.name.replace(/\?$/, "") === infinite.queryParam);
|
|
1132
1135
|
}
|
|
1133
1136
|
/**
|
|
1134
1137
|
* Warning for an infinite hook that falls back to the built-in page params on a response that
|
|
@@ -1136,8 +1139,8 @@ function matchesInfinite(node, infinite) {
|
|
|
1136
1139
|
*/
|
|
1137
1140
|
function getDefaultPageParamsWarning(node, infinite) {
|
|
1138
1141
|
if (!(infinite.getNextPageParam == null && infinite.getPreviousPageParam == null && infinite.nextParam == null && infinite.previousParam == null && !infinite.cursorParam)) return null;
|
|
1139
|
-
const content =
|
|
1140
|
-
let resolved = (content?.find((item) =>
|
|
1142
|
+
const content = ast.http.responses.findPrimary(node)?.content;
|
|
1143
|
+
let resolved = (content?.find((item) => ast.mediaType.isJson(item)) ?? content?.[0])?.schema;
|
|
1141
1144
|
while (resolved?.type === "ref" || resolved?.type === "intersection" && resolved.members?.length === 1) resolved = resolved.type === "ref" ? resolved.schema : resolved.members?.[0];
|
|
1142
1145
|
if (!resolved || resolved.type === "array") return null;
|
|
1143
1146
|
return `${node.operationId}: the default infinite page params expect an array response and never end for this one. Set \`infinite.getNextPageParam\` (or \`nextParam\`) to read the next page from the response.`;
|
|
@@ -1220,9 +1223,15 @@ function buildHookParams(node, options) {
|
|
|
1220
1223
|
}
|
|
1221
1224
|
/**
|
|
1222
1225
|
* The `TRequest` type argument of a mutation hook: the options type when the operation takes a request, else `undefined`.
|
|
1226
|
+
* When the variables carry the request media type and the response has several, `contentType` can pick the
|
|
1227
|
+
* response one too, as `{ request, response }`.
|
|
1223
1228
|
*/
|
|
1224
1229
|
function resolveMutationRequestType(node, resolver) {
|
|
1225
|
-
|
|
1230
|
+
if (!buildGroupedRequestParam(node, { resolver })) return "undefined";
|
|
1231
|
+
const optionsName = resolver.response.options(node);
|
|
1232
|
+
const response = getResponseContentTypeInfo(node);
|
|
1233
|
+
if (!hasRequestContentTypeChoice(node) || !response.isMultipleContentTypes) return optionsName;
|
|
1234
|
+
return `${/^[\w$]+$/.test(optionsName) ? optionsName : `(${optionsName})`} & { contentType?: string | { response?: ${response.contentTypeUnion} } }`;
|
|
1226
1235
|
}
|
|
1227
1236
|
/**
|
|
1228
1237
|
* Builds the object literal that unwraps each request group's getter before it reaches `queryKey`/`queryOptions`; `null` without a request group.
|
|
@@ -1236,8 +1245,11 @@ function buildResolvedRequestParams(node) {
|
|
|
1236
1245
|
// ../../internals/tanstack-query/src/components/InfiniteQueryOptions.tsx
|
|
1237
1246
|
const declarationPrinter$6 = functionPrinter({ mode: "declaration" });
|
|
1238
1247
|
const callPrinter$3 = functionPrinter({ mode: "call" });
|
|
1239
|
-
function InfiniteQueryOptions({ name, clientName, initialPageParam, hasExplicitInitialPageParam, cursorParam, nextParam, previousParam, getNextPageParam, getPreviousPageParam, node, tsResolver, queryParam, queryKeyName, queryKeyType = "typeof queryKey", memberTypeWrapper, unwrapName, clientReturnType, returnType }) {
|
|
1240
|
-
const { TData: queryFnDataType, TError: errorType } = buildResponseTypes(node, tsResolver, {
|
|
1248
|
+
function InfiniteQueryOptions({ name, clientName, initialPageParam, hasExplicitInitialPageParam, cursorParam, nextParam, previousParam, getNextPageParam, getPreviousPageParam, node, tsResolver, queryParam, queryKeyName, queryKeyType = "typeof queryKey", memberTypeWrapper, unwrapName, clientReturnType, returnType, typedHeaders }) {
|
|
1249
|
+
const { TData: queryFnDataType, TError: errorType } = buildResponseTypes(node, tsResolver, {
|
|
1250
|
+
returnType,
|
|
1251
|
+
typedHeaders
|
|
1252
|
+
});
|
|
1241
1253
|
const dataSuffix = returnType === "data" ? "" : ".data";
|
|
1242
1254
|
const { queryParamsTypeName, pageParamType } = resolvePageParamType(node, {
|
|
1243
1255
|
resolver: tsResolver,
|
|
@@ -1256,10 +1268,12 @@ function InfiniteQueryOptions({ name, clientName, initialPageParam, hasExplicitI
|
|
|
1256
1268
|
memberTypeWrapper
|
|
1257
1269
|
});
|
|
1258
1270
|
const paramsSignature = declarationPrinter$6.print(paramsNode) ?? "";
|
|
1271
|
+
const pageParam = queryParam && queryParamsTypeName ? queryParam : void 0;
|
|
1259
1272
|
const queryFnBody = buildCallResultBody(buildClientCall(node, {
|
|
1260
1273
|
clientName,
|
|
1261
1274
|
signal: true,
|
|
1262
|
-
unwrapName
|
|
1275
|
+
unwrapName,
|
|
1276
|
+
pageParam
|
|
1263
1277
|
}), {
|
|
1264
1278
|
clientReturnType,
|
|
1265
1279
|
returnType
|
|
@@ -1286,12 +1300,7 @@ function InfiniteQueryOptions({ name, clientName, initialPageParam, hasExplicitI
|
|
|
1286
1300
|
getNextPageParamExpr,
|
|
1287
1301
|
getPreviousPageParamExpr
|
|
1288
1302
|
].filter(Boolean);
|
|
1289
|
-
const
|
|
1290
|
-
...(query ?? {}),
|
|
1291
|
-
['${queryParam}']: pageParam as unknown as ${queryParamsTypeName}['${queryParam}'],
|
|
1292
|
-
} as ${queryParamsTypeName}` : "";
|
|
1293
|
-
const queryFnArgs = infiniteOverrideParams ? "{ signal, pageParam }" : "{ signal }";
|
|
1294
|
-
const queryFnStatements = infiniteOverrideParams ? `${infiniteOverrideParams}\n ${queryFnBody}` : queryFnBody;
|
|
1303
|
+
const queryFnArgs = pageParam ? "{ signal, pageParam }" : "{ signal }";
|
|
1295
1304
|
return /* @__PURE__ */ jsx(File.Source, {
|
|
1296
1305
|
name,
|
|
1297
1306
|
isExportable: true,
|
|
@@ -1305,7 +1314,7 @@ const queryKey = ${queryKeyName}(${queryKeyParamsCall})
|
|
|
1305
1314
|
return infiniteQueryOptions<${queryFnDataType}, ${errorType}, InfiniteData<${queryFnDataType}>, ${queryKeyType}, ${pageParamType}>({
|
|
1306
1315
|
queryKey,
|
|
1307
1316
|
queryFn: async (${queryFnArgs}) => {
|
|
1308
|
-
${
|
|
1317
|
+
${queryFnBody}
|
|
1309
1318
|
},
|
|
1310
1319
|
${queryOptionsArr.join(",\n ")}
|
|
1311
1320
|
})
|
|
@@ -1376,7 +1385,7 @@ function MutationKey({ name, node, transformer, typeName }) {
|
|
|
1376
1385
|
function createQueryResolver(variant = "") {
|
|
1377
1386
|
return {
|
|
1378
1387
|
name(node) {
|
|
1379
|
-
const name = `use${capitalize(this.name(node.operationId))}${variant}`;
|
|
1388
|
+
const name = `use${casing.capitalize(this.name(node.operationId))}${variant}`;
|
|
1380
1389
|
return this.resolveName({
|
|
1381
1390
|
key: operationKey(node, "query", variant, "name"),
|
|
1382
1391
|
name
|
|
@@ -1397,7 +1406,7 @@ function createQueryResolver(variant = "") {
|
|
|
1397
1406
|
});
|
|
1398
1407
|
},
|
|
1399
1408
|
keyTypeName(node) {
|
|
1400
|
-
const name = `${capitalize(this.name(node.operationId))}${variant}QueryKey`;
|
|
1409
|
+
const name = `${casing.capitalize(this.name(node.operationId))}${variant}QueryKey`;
|
|
1401
1410
|
return this.resolveName({
|
|
1402
1411
|
key: operationKey(node, "query", variant, "keyTypeName"),
|
|
1403
1412
|
name
|
|
@@ -1418,7 +1427,7 @@ function createQueryResolver(variant = "") {
|
|
|
1418
1427
|
function createMutationResolver() {
|
|
1419
1428
|
return {
|
|
1420
1429
|
name(node) {
|
|
1421
|
-
const name = `use${capitalize(this.name(node.operationId))}`;
|
|
1430
|
+
const name = `use${casing.capitalize(this.name(node.operationId))}`;
|
|
1422
1431
|
return this.resolveName({
|
|
1423
1432
|
key: operationKey(node, "mutation", "name"),
|
|
1424
1433
|
name
|
|
@@ -1447,14 +1456,14 @@ const declarationPrinter$4 = functionPrinter({ mode: "declaration" });
|
|
|
1447
1456
|
*/
|
|
1448
1457
|
const queryKeyTransformer = ({ node, variant }) => {
|
|
1449
1458
|
if (!node.path) return [];
|
|
1450
|
-
const { path, query } =
|
|
1459
|
+
const { path, query } = ast.http.groupParameters(node);
|
|
1451
1460
|
const isInfinite = variant === "infiniteQuery" || variant === "suspenseInfiniteQuery";
|
|
1452
1461
|
const urlFields = [`url: '${Url.toPath(node.path)}'`];
|
|
1453
1462
|
if (path.length > 0) urlFields.push("params: path");
|
|
1454
1463
|
if (isInfinite) urlFields.push("infinite: true");
|
|
1455
1464
|
const result = [`{ ${urlFields.join(", ")} }`];
|
|
1456
1465
|
if (query.length > 0) result.push("...(query ? [query] : [])");
|
|
1457
|
-
if (
|
|
1466
|
+
if (ast.http.requestBody.getSchema(node)) result.push("...(body !== undefined ? [body] : [])");
|
|
1458
1467
|
return result;
|
|
1459
1468
|
};
|
|
1460
1469
|
function QueryKey({ name, node, tsResolver, typeName, transformer, variant = "query", memberTypeWrapper, exportType }) {
|
|
@@ -1618,7 +1627,7 @@ const hookOptionsGenerator = defineGenerator({
|
|
|
1618
1627
|
const imports = [];
|
|
1619
1628
|
const hookOptions = {};
|
|
1620
1629
|
for (const node of nodes) {
|
|
1621
|
-
if (!ast.
|
|
1630
|
+
if (!ast.http.isOperation(node)) continue;
|
|
1622
1631
|
const opOverrides = resolveOperationOverrides(node, override);
|
|
1623
1632
|
const nodeQuery = "query" in opOverrides ? opOverrides.query : query;
|
|
1624
1633
|
const nodeMutation = "mutation" in opOverrides ? opOverrides.mutation : mutation;
|
|
@@ -1741,8 +1750,11 @@ function buildHookTypes({ node, tsResolver, infinite, suspense, TData, TError, q
|
|
|
1741
1750
|
resultType: `${resultTypeName}<TData, ${TError}> & { queryKey: TQueryKey }`
|
|
1742
1751
|
};
|
|
1743
1752
|
}
|
|
1744
|
-
function Query({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, tsResolver, customOptions, suspense, infinite, returnType }) {
|
|
1745
|
-
const { TData, TError } = buildResponseTypes(node, tsResolver, {
|
|
1753
|
+
function Query({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, tsResolver, customOptions, suspense, infinite, returnType, typedHeaders }) {
|
|
1754
|
+
const { TData, TError } = buildResponseTypes(node, tsResolver, {
|
|
1755
|
+
returnType,
|
|
1756
|
+
typedHeaders
|
|
1757
|
+
});
|
|
1746
1758
|
const prefix = suspense ? "UseSuspense" : "Use";
|
|
1747
1759
|
const hookName = `${suspense ? "useSuspense" : "use"}${infinite ? "InfiniteQuery" : "Query"}`;
|
|
1748
1760
|
const observerOptionsName = OBSERVER_OPTIONS_NAMES[infinite ? "infinite" : "plain"][suspense ? "suspense" : "standard"];
|
|
@@ -1766,7 +1778,7 @@ function Query({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, t
|
|
|
1766
1778
|
memberTypeWrapper: maybeValueOrGetter,
|
|
1767
1779
|
optionsType: `{
|
|
1768
1780
|
query?: Partial<${observerOptionsType}> & { client?: QueryClient },
|
|
1769
|
-
client?: ${buildClientOptionType(
|
|
1781
|
+
client?: ${buildClientOptionType()}
|
|
1770
1782
|
}`
|
|
1771
1783
|
});
|
|
1772
1784
|
const paramsSignature = declarationPrinter$3.print(paramsNode) ?? "";
|
|
@@ -1802,8 +1814,11 @@ function Query({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, t
|
|
|
1802
1814
|
// src/components/QueryOptions.tsx
|
|
1803
1815
|
const declarationPrinter$2 = functionPrinter({ mode: "declaration" });
|
|
1804
1816
|
const callPrinter$2 = functionPrinter({ mode: "call" });
|
|
1805
|
-
function QueryOptions({ name, clientName, node, tsResolver, queryKeyName, clientReturnType, returnType }) {
|
|
1806
|
-
const { TData, TError } = buildResponseTypes(node, tsResolver, {
|
|
1817
|
+
function QueryOptions({ name, clientName, node, tsResolver, queryKeyName, clientReturnType, returnType, typedHeaders }) {
|
|
1818
|
+
const { TData, TError } = buildResponseTypes(node, tsResolver, {
|
|
1819
|
+
returnType,
|
|
1820
|
+
typedHeaders
|
|
1821
|
+
});
|
|
1807
1822
|
const queryKeyParamsNode = buildQueryKeyParams(node, { resolver: tsResolver });
|
|
1808
1823
|
const queryKeyParamsCall = callPrinter$2.print(queryKeyParamsNode) ?? "";
|
|
1809
1824
|
const paramsNode = buildQueryOptionsParams(node, { resolver: tsResolver });
|
|
@@ -1856,7 +1871,7 @@ function createQueryGenerator({ name, variant }) {
|
|
|
1856
1871
|
renderer: jsxRenderer,
|
|
1857
1872
|
match(node, ctx) {
|
|
1858
1873
|
const operationNode = node;
|
|
1859
|
-
if (!ast.
|
|
1874
|
+
if (!ast.http.isOperation(operationNode)) return false;
|
|
1860
1875
|
const { query, mutation, infinite: infiniteConfig, suspense: suspenseConfig, hooks } = ctx.options;
|
|
1861
1876
|
const { isQuery, isMutation } = classifyOperation(operationNode, {
|
|
1862
1877
|
query,
|
|
@@ -1871,7 +1886,7 @@ function createQueryGenerator({ name, variant }) {
|
|
|
1871
1886
|
return !!infiniteOptions && matchesInfinite(operationNode, infiniteOptions);
|
|
1872
1887
|
},
|
|
1873
1888
|
operation(node, ctx) {
|
|
1874
|
-
if (!ast.
|
|
1889
|
+
if (!ast.http.isOperation(node)) return null;
|
|
1875
1890
|
const { driver, resolver, root } = ctx;
|
|
1876
1891
|
const { output, query, infinite: infiniteConfig, client, group, customOptions, hooks } = ctx.options;
|
|
1877
1892
|
const infiniteOptions = infinite && infiniteConfig && typeof infiniteConfig === "object" ? infiniteConfig : null;
|
|
@@ -1949,7 +1964,8 @@ function createQueryGenerator({ name, variant }) {
|
|
|
1949
1964
|
hasExplicitInitialPageParam: infiniteOptions.hasExplicitInitialPageParam,
|
|
1950
1965
|
queryParam: infiniteOptions.queryParam,
|
|
1951
1966
|
clientReturnType: contractOp.returnType,
|
|
1952
|
-
returnType: hook.returnType
|
|
1967
|
+
returnType: hook.returnType,
|
|
1968
|
+
typedHeaders: hook.contractOp.typedHeaders
|
|
1953
1969
|
})
|
|
1954
1970
|
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(File.Import, {
|
|
1955
1971
|
name: ["queryOptions"],
|
|
@@ -1961,7 +1977,8 @@ function createQueryGenerator({ name, variant }) {
|
|
|
1961
1977
|
node,
|
|
1962
1978
|
tsResolver: hook.tsResolver,
|
|
1963
1979
|
clientReturnType: contractOp.returnType,
|
|
1964
|
-
returnType: hook.returnType
|
|
1980
|
+
returnType: hook.returnType,
|
|
1981
|
+
typedHeaders: hook.contractOp.typedHeaders
|
|
1965
1982
|
})] }),
|
|
1966
1983
|
(variant !== "query" || query && hooks) && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1967
1984
|
/* @__PURE__ */ jsx(File.Import, {
|
|
@@ -1986,6 +2003,7 @@ function createQueryGenerator({ name, variant }) {
|
|
|
1986
2003
|
tsResolver: hook.tsResolver,
|
|
1987
2004
|
customOptions,
|
|
1988
2005
|
returnType: hook.returnType,
|
|
2006
|
+
typedHeaders: hook.contractOp.typedHeaders,
|
|
1989
2007
|
suspense,
|
|
1990
2008
|
infinite: infiniteOptions ? {
|
|
1991
2009
|
initialPageParam: infiniteOptions.initialPageParam,
|
|
@@ -2020,8 +2038,11 @@ function buildMutationConfigParamsNode(node) {
|
|
|
2020
2038
|
default: "{}"
|
|
2021
2039
|
})] });
|
|
2022
2040
|
}
|
|
2023
|
-
function MutationOptions({ name, clientName, node, tsResolver, mutationKeyName, clientReturnType, returnType }) {
|
|
2024
|
-
const { TData, TError } = buildResponseTypes(node, tsResolver, {
|
|
2041
|
+
function MutationOptions({ name, clientName, node, tsResolver, mutationKeyName, clientReturnType, returnType, typedHeaders }) {
|
|
2042
|
+
const { TData, TError } = buildResponseTypes(node, tsResolver, {
|
|
2043
|
+
returnType,
|
|
2044
|
+
typedHeaders
|
|
2045
|
+
});
|
|
2025
2046
|
const configParamsNode = buildMutationConfigParamsNode(node);
|
|
2026
2047
|
const paramsSignature = declarationPrinter$1.print(configParamsNode) ?? "";
|
|
2027
2048
|
const groupedParam = buildGroupedRequestParam(node, {
|
|
@@ -2030,13 +2051,12 @@ function MutationOptions({ name, clientName, node, tsResolver, mutationKeyName,
|
|
|
2030
2051
|
});
|
|
2031
2052
|
const hasMutationParams = groupedParam !== null;
|
|
2032
2053
|
const groupedParamsNode = createFunctionParameters({ params: groupedParam ? [groupedParam] : [] });
|
|
2033
|
-
const TRequest =
|
|
2054
|
+
const TRequest = resolveMutationRequestType(node, tsResolver);
|
|
2034
2055
|
const argBindingStr = hasMutationParams ? callPrinter$1.print(groupedParamsNode) ?? "" : "_";
|
|
2035
2056
|
const mutationFnBody = buildCallResultBody(buildClientCall(node, {
|
|
2036
2057
|
clientName,
|
|
2037
2058
|
signal: false,
|
|
2038
|
-
withContentType: true
|
|
2039
|
-
returnType: clientReturnType
|
|
2059
|
+
withContentType: true
|
|
2040
2060
|
}), {
|
|
2041
2061
|
clientReturnType,
|
|
2042
2062
|
returnType
|
|
@@ -2066,8 +2086,11 @@ function MutationOptions({ name, clientName, node, tsResolver, mutationKeyName,
|
|
|
2066
2086
|
const declarationPrinter = functionPrinter({ mode: "declaration" });
|
|
2067
2087
|
const callPrinter = functionPrinter({ mode: "call" });
|
|
2068
2088
|
function buildMutationParamsNode(node, options) {
|
|
2069
|
-
const { resolver, returnType } = options;
|
|
2070
|
-
const { TData, TError } = buildResponseTypes(node, resolver, {
|
|
2089
|
+
const { resolver, returnType, typedHeaders } = options;
|
|
2090
|
+
const { TData, TError } = buildResponseTypes(node, resolver, {
|
|
2091
|
+
returnType,
|
|
2092
|
+
typedHeaders
|
|
2093
|
+
});
|
|
2071
2094
|
return buildHookParams(node, {
|
|
2072
2095
|
resolver,
|
|
2073
2096
|
withRequest: false,
|
|
@@ -2082,8 +2105,11 @@ function buildMutationParamsNode(node, options) {
|
|
|
2082
2105
|
}`
|
|
2083
2106
|
});
|
|
2084
2107
|
}
|
|
2085
|
-
function Mutation({ name, mutationOptionsName, node, tsResolver, mutationKeyName, customOptions, returnType }) {
|
|
2086
|
-
const { TData, TError } = buildResponseTypes(node, tsResolver, {
|
|
2108
|
+
function Mutation({ name, mutationOptionsName, node, tsResolver, mutationKeyName, customOptions, returnType, typedHeaders }) {
|
|
2109
|
+
const { TData, TError } = buildResponseTypes(node, tsResolver, {
|
|
2110
|
+
returnType,
|
|
2111
|
+
typedHeaders
|
|
2112
|
+
});
|
|
2087
2113
|
const generics = [
|
|
2088
2114
|
TData,
|
|
2089
2115
|
TError,
|
|
@@ -2095,7 +2121,8 @@ function Mutation({ name, mutationOptionsName, node, tsResolver, mutationKeyName
|
|
|
2095
2121
|
const mutationOptionsParamsCall = callPrinter.print(mutationOptionsConfigNode) ?? "";
|
|
2096
2122
|
const paramsNode = buildMutationParamsNode(node, {
|
|
2097
2123
|
resolver: tsResolver,
|
|
2098
|
-
returnType
|
|
2124
|
+
returnType,
|
|
2125
|
+
typedHeaders
|
|
2099
2126
|
});
|
|
2100
2127
|
const paramsSignature = declarationPrinter.print(paramsNode) ?? "";
|
|
2101
2128
|
return /* @__PURE__ */ jsx(File.Source, {
|
|
@@ -2135,7 +2162,7 @@ const mutationGenerator = defineGenerator({
|
|
|
2135
2162
|
renderer: jsxRenderer,
|
|
2136
2163
|
match(node, ctx) {
|
|
2137
2164
|
const operationNode = node;
|
|
2138
|
-
if (!ast.
|
|
2165
|
+
if (!ast.http.isOperation(operationNode)) return false;
|
|
2139
2166
|
const { query, mutation } = ctx.options;
|
|
2140
2167
|
return classifyOperation(operationNode, {
|
|
2141
2168
|
query,
|
|
@@ -2143,7 +2170,7 @@ const mutationGenerator = defineGenerator({
|
|
|
2143
2170
|
}).isMutation;
|
|
2144
2171
|
},
|
|
2145
2172
|
operation(node, ctx) {
|
|
2146
|
-
if (!ast.
|
|
2173
|
+
if (!ast.http.isOperation(node)) return null;
|
|
2147
2174
|
const { driver, resolver, root } = ctx;
|
|
2148
2175
|
const { output, mutation, client, group, customOptions, hooks } = ctx.options;
|
|
2149
2176
|
const importPath = mutation ? mutation.importPath : "@tanstack/react-query";
|
|
@@ -2190,7 +2217,8 @@ const mutationGenerator = defineGenerator({
|
|
|
2190
2217
|
node,
|
|
2191
2218
|
tsResolver,
|
|
2192
2219
|
clientReturnType: contractOp.returnType,
|
|
2193
|
-
returnType: hook.returnType
|
|
2220
|
+
returnType: hook.returnType,
|
|
2221
|
+
typedHeaders: hook.contractOp.typedHeaders
|
|
2194
2222
|
}),
|
|
2195
2223
|
mutation && hooks && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2196
2224
|
/* @__PURE__ */ jsx(File.Import, {
|
|
@@ -2213,7 +2241,8 @@ const mutationGenerator = defineGenerator({
|
|
|
2213
2241
|
node,
|
|
2214
2242
|
tsResolver,
|
|
2215
2243
|
customOptions,
|
|
2216
|
-
returnType: hook.returnType
|
|
2244
|
+
returnType: hook.returnType,
|
|
2245
|
+
typedHeaders: hook.contractOp.typedHeaders
|
|
2217
2246
|
})
|
|
2218
2247
|
] })
|
|
2219
2248
|
]
|
|
@@ -2372,7 +2401,7 @@ const pluginReactQuery = defineExtension({
|
|
|
2372
2401
|
...customOptions
|
|
2373
2402
|
} : null,
|
|
2374
2403
|
hooks,
|
|
2375
|
-
group:
|
|
2404
|
+
group: group ?? null,
|
|
2376
2405
|
exclude,
|
|
2377
2406
|
include,
|
|
2378
2407
|
override,
|