@kubb/plugin-client 5.0.0-beta.4 → 5.0.0-beta.56
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/README.md +39 -24
- package/dist/clients/axios.cjs +26 -4
- package/dist/clients/axios.cjs.map +1 -1
- package/dist/clients/axios.d.ts +11 -5
- package/dist/clients/axios.js +26 -4
- package/dist/clients/axios.js.map +1 -1
- package/dist/clients/fetch.cjs +77 -9
- package/dist/clients/fetch.cjs.map +1 -1
- package/dist/clients/fetch.d.ts +10 -3
- package/dist/clients/fetch.js +77 -9
- package/dist/clients/fetch.js.map +1 -1
- package/dist/index.cjs +836 -514
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +206 -105
- package/dist/index.js +833 -515
- package/dist/index.js.map +1 -1
- package/dist/templates/clients/axios.source.cjs +1 -1
- package/dist/templates/clients/axios.source.cjs.map +1 -1
- package/dist/templates/clients/axios.source.d.ts +1 -1
- package/dist/templates/clients/axios.source.js +1 -1
- package/dist/templates/clients/axios.source.js.map +1 -1
- package/dist/templates/clients/fetch.source.cjs +1 -1
- package/dist/templates/clients/fetch.source.cjs.map +1 -1
- package/dist/templates/clients/fetch.source.d.ts +1 -1
- package/dist/templates/clients/fetch.source.js +1 -1
- package/dist/templates/clients/fetch.source.js.map +1 -1
- package/dist/templates/config.source.cjs.map +1 -1
- package/dist/templates/config.source.d.ts +1 -1
- package/dist/templates/config.source.js.map +1 -1
- package/package.json +14 -26
- package/src/clients/axios.ts +41 -7
- package/src/clients/fetch.ts +106 -6
- package/src/components/ClassClient.tsx +47 -24
- package/src/components/Client.tsx +100 -71
- package/src/components/StaticClassClient.tsx +47 -24
- package/src/components/Url.tsx +10 -12
- package/src/components/WrapperClient.tsx +9 -5
- package/src/functionParams.ts +8 -8
- package/src/generators/classClientGenerator.tsx +63 -51
- package/src/generators/clientGenerator.tsx +45 -48
- package/src/generators/groupedClientGenerator.tsx +12 -6
- package/src/generators/operationsGenerator.ts +47 -0
- package/src/generators/staticClassClientGenerator.tsx +57 -45
- package/src/index.ts +2 -1
- package/src/plugin.ts +30 -28
- package/src/resolvers/resolverClient.ts +32 -8
- package/src/types.ts +111 -65
- package/src/utils.ts +142 -63
- package/extension.yaml +0 -776
- package/src/components/Operations.tsx +0 -28
- package/src/generators/operationsGenerator.tsx +0 -28
- package/templates/clients/axios.ts +0 -73
- package/templates/clients/fetch.ts +0 -96
- package/templates/config.ts +0 -43
- /package/dist/{chunk-ByKO4r7w.cjs → chunk-Bx3C2hgW.cjs} +0 -0
- /package/dist/{chunk--u3MIqq1.js → chunk-C0LytTxp.js} +0 -0
package/dist/index.cjs
CHANGED
|
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_chunk = require("./chunk-
|
|
5
|
+
const require_chunk = require("./chunk-Bx3C2hgW.cjs");
|
|
6
6
|
const require_templates_clients_axios_source = require("./templates/clients/axios.source.cjs");
|
|
7
7
|
const require_templates_clients_fetch_source = require("./templates/clients/fetch.source.cjs");
|
|
8
8
|
const require_templates_config_source = require("./templates/config.source.cjs");
|
|
@@ -10,6 +10,7 @@ let node_path = require("node:path");
|
|
|
10
10
|
let node_path$1 = require_chunk.__toESM(node_path, 1);
|
|
11
11
|
node_path = require_chunk.__toESM(node_path);
|
|
12
12
|
let _kubb_core = require("@kubb/core");
|
|
13
|
+
let _kubb_ast_utils = require("@kubb/ast/utils");
|
|
13
14
|
let _kubb_plugin_ts = require("@kubb/plugin-ts");
|
|
14
15
|
let _kubb_renderer_jsx = require("@kubb/renderer-jsx");
|
|
15
16
|
let _kubb_renderer_jsx_jsx_runtime = require("@kubb/renderer-jsx/jsx-runtime");
|
|
@@ -25,68 +26,57 @@ let _kubb_plugin_zod = require("@kubb/plugin-zod");
|
|
|
25
26
|
function toCamelOrPascal(text, pascal) {
|
|
26
27
|
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) => {
|
|
27
28
|
if (word.length > 1 && word === word.toUpperCase()) return word;
|
|
28
|
-
|
|
29
|
-
return word.charAt(0).toUpperCase() + word.slice(1);
|
|
29
|
+
return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
|
|
30
30
|
}).join("").replace(/[^a-zA-Z0-9]/g, "");
|
|
31
31
|
}
|
|
32
32
|
/**
|
|
33
|
-
* Splits `text` on `.` and applies `transformPart` to each segment.
|
|
34
|
-
* The last segment receives `isLast = true`, all earlier segments receive `false`.
|
|
35
|
-
* Segments are joined with `/` to form a file path.
|
|
36
|
-
*
|
|
37
|
-
* Only splits on dots followed by a letter so that version numbers
|
|
38
|
-
* embedded in operationIds (e.g. `v2025.0`) are kept intact.
|
|
39
|
-
*/
|
|
40
|
-
function applyToFileParts(text, transformPart) {
|
|
41
|
-
const parts = text.split(/\.(?=[a-zA-Z])/);
|
|
42
|
-
return parts.map((part, i) => transformPart(part, i === parts.length - 1)).join("/");
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
33
|
* Converts `text` to camelCase.
|
|
46
|
-
* When `isFile` is `true`, dot-separated segments are each cased independently and joined with `/`.
|
|
47
34
|
*
|
|
48
|
-
* @example
|
|
49
|
-
* camelCase('hello-world')
|
|
50
|
-
*
|
|
35
|
+
* @example Word boundaries
|
|
36
|
+
* `camelCase('hello-world') // 'helloWorld'`
|
|
37
|
+
*
|
|
38
|
+
* @example With a prefix
|
|
39
|
+
* `camelCase('tag', { prefix: 'create' }) // 'createTag'`
|
|
51
40
|
*/
|
|
52
|
-
function camelCase(text, {
|
|
53
|
-
if (isFile) return applyToFileParts(text, (part, isLast) => camelCase(part, isLast ? {
|
|
54
|
-
prefix,
|
|
55
|
-
suffix
|
|
56
|
-
} : {}));
|
|
41
|
+
function camelCase(text, { prefix = "", suffix = "" } = {}) {
|
|
57
42
|
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
|
|
58
43
|
}
|
|
59
44
|
/**
|
|
60
45
|
* Converts `text` to PascalCase.
|
|
61
|
-
* When `isFile` is `true`, the last dot-separated segment is PascalCased and earlier segments are camelCased.
|
|
62
46
|
*
|
|
63
|
-
* @example
|
|
64
|
-
* pascalCase('hello-world')
|
|
65
|
-
*
|
|
47
|
+
* @example Word boundaries
|
|
48
|
+
* `pascalCase('hello-world') // 'HelloWorld'`
|
|
49
|
+
*
|
|
50
|
+
* @example With a suffix
|
|
51
|
+
* `pascalCase('tag', { suffix: 'schema' }) // 'TagSchema'`
|
|
66
52
|
*/
|
|
67
|
-
function pascalCase(text, {
|
|
68
|
-
if (isFile) return applyToFileParts(text, (part, isLast) => isLast ? pascalCase(part, {
|
|
69
|
-
prefix,
|
|
70
|
-
suffix
|
|
71
|
-
}) : camelCase(part));
|
|
53
|
+
function pascalCase(text, { prefix = "", suffix = "" } = {}) {
|
|
72
54
|
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true);
|
|
73
55
|
}
|
|
74
56
|
//#endregion
|
|
75
|
-
//#region ../../internals/utils/src/
|
|
57
|
+
//#region ../../internals/utils/src/fs.ts
|
|
76
58
|
/**
|
|
77
|
-
* Builds a
|
|
78
|
-
*
|
|
59
|
+
* Builds a nested file path from a dotted name. Splits on dots that precede a letter
|
|
60
|
+
* (so version numbers embedded in operationIds like `v2025.0` stay intact), camelCases
|
|
61
|
+
* every earlier segment, applies `caseLast` to the final segment, and joins with `/`.
|
|
79
62
|
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
63
|
+
* Empty segments are dropped before joining. They arise when the name starts with a dot
|
|
64
|
+
* followed by a letter (e.g. `..Schema` splits into `['..', 'Schema']` and `'..'` cases to
|
|
65
|
+
* an empty string). Without this a leading `/` would form, which `path.resolve` reads as an
|
|
66
|
+
* absolute path, letting generated files escape the configured output directory.
|
|
67
|
+
*
|
|
68
|
+
* @example Nested path from a dotted name
|
|
69
|
+
* `toFilePath('pet.petId') // 'pet/petId'`
|
|
70
|
+
*
|
|
71
|
+
* @example PascalCase the final segment
|
|
72
|
+
* `toFilePath('pet.Pet', pascalCase) // 'pet/Pet'`
|
|
73
|
+
*
|
|
74
|
+
* @example Suffix applied to the final segment only
|
|
75
|
+
* `toFilePath('tag.tag', (part) => camelCase(part, { suffix: 'schema' })) // 'tag/tagSchema'`
|
|
85
76
|
*/
|
|
86
|
-
function
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
return `/**\n${comments.map((c) => `${indent}${c}`).join("\n")}\n */${suffix}`;
|
|
77
|
+
function toFilePath(name, caseLast = camelCase) {
|
|
78
|
+
const parts = name.split(/\.(?=[a-zA-Z])/);
|
|
79
|
+
return parts.map((part, i) => i === parts.length - 1 ? caseLast(part) : camelCase(part)).filter(Boolean).join("/");
|
|
90
80
|
}
|
|
91
81
|
//#endregion
|
|
92
82
|
//#region ../../internals/utils/src/reserved.ts
|
|
@@ -191,100 +181,104 @@ function isValidVarName(name) {
|
|
|
191
181
|
if (!name || reservedWords.has(name)) return false;
|
|
192
182
|
return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
|
|
193
183
|
}
|
|
194
|
-
//#endregion
|
|
195
|
-
//#region ../../internals/utils/src/urlPath.ts
|
|
196
184
|
/**
|
|
197
|
-
*
|
|
185
|
+
* Returns `name` when it's a syntactically valid JavaScript variable name,
|
|
186
|
+
* otherwise prefixes it with `_` so the result is a valid identifier.
|
|
187
|
+
*
|
|
188
|
+
* Useful for sanitizing OpenAPI schema names or operation IDs that start with
|
|
189
|
+
* a digit (e.g. `409`, `504AccountCancel`) before using them as exported
|
|
190
|
+
* variable, type, or function names.
|
|
198
191
|
*
|
|
199
192
|
* @example
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
*
|
|
193
|
+
* ```ts
|
|
194
|
+
* ensureValidVarName('409') // '_409'
|
|
195
|
+
* ensureValidVarName('504AccountCancel') // '_504AccountCancel'
|
|
196
|
+
* ensureValidVarName('Pet') // 'Pet'
|
|
197
|
+
* ensureValidVarName('class') // '_class'
|
|
198
|
+
* ```
|
|
203
199
|
*/
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
200
|
+
function ensureValidVarName(name) {
|
|
201
|
+
if (!name || isValidVarName(name)) return name;
|
|
202
|
+
return `_${name}`;
|
|
203
|
+
}
|
|
204
|
+
//#endregion
|
|
205
|
+
//#region ../../internals/utils/src/url.ts
|
|
206
|
+
function transformParam(raw, casing) {
|
|
207
|
+
const param = isValidVarName(raw) ? raw : camelCase(raw);
|
|
208
|
+
return casing === "camelcase" ? camelCase(param) : param;
|
|
209
|
+
}
|
|
210
|
+
function toParamsObject(path, { replacer, casing } = {}) {
|
|
211
|
+
const params = {};
|
|
212
|
+
for (const match of path.matchAll(/\{([^}]+)\}/g)) {
|
|
213
|
+
const param = transformParam(match[1], casing);
|
|
214
|
+
const key = replacer ? replacer(param) : param;
|
|
215
|
+
params[key] = key;
|
|
213
216
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
return this.toURLPath();
|
|
217
|
+
return Object.keys(params).length > 0 ? params : null;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Helpers for OpenAPI/Swagger paths, plus a thin wrapper over the native `URL`.
|
|
221
|
+
*/
|
|
222
|
+
var Url$1 = class Url$1 {
|
|
223
|
+
static {
|
|
224
|
+
require_chunk.__name(this, "Url");
|
|
223
225
|
}
|
|
224
|
-
/**
|
|
226
|
+
/**
|
|
227
|
+
* Reports whether `url` is a parseable absolute URL. Delegates to the native `URL.canParse`.
|
|
225
228
|
*
|
|
226
229
|
* @example
|
|
227
|
-
*
|
|
228
|
-
*
|
|
229
|
-
* new URLPath('/pet/{petId}').isURL // false
|
|
230
|
-
* ```
|
|
230
|
+
* Url.canParse('https://petstore.swagger.io/v2') // true
|
|
231
|
+
* Url.canParse('/pet/{petId}') // false
|
|
231
232
|
*/
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
return !!new URL(this.path).href;
|
|
235
|
-
} catch {
|
|
236
|
-
return false;
|
|
237
|
-
}
|
|
233
|
+
static canParse(url, base) {
|
|
234
|
+
return URL.canParse(url, base);
|
|
238
235
|
}
|
|
239
236
|
/**
|
|
240
|
-
* Converts
|
|
237
|
+
* Converts an OpenAPI/Swagger path to Express-style colon syntax.
|
|
241
238
|
*
|
|
242
239
|
* @example
|
|
243
|
-
*
|
|
244
|
-
* new URLPath('/account/monetary-accountID').template // '`/account/${monetaryAccountId}`'
|
|
240
|
+
* Url.toPath('/pet/{petId}') // '/pet/:petId'
|
|
245
241
|
*/
|
|
246
|
-
|
|
247
|
-
return
|
|
242
|
+
static toPath(path) {
|
|
243
|
+
return path.replace(/\{([^}]+)\}/g, ":$1");
|
|
248
244
|
}
|
|
249
|
-
/**
|
|
245
|
+
/**
|
|
246
|
+
* Converts an OpenAPI/Swagger path to a TypeScript template literal string.
|
|
247
|
+
* `prefix` is prepended inside the literal, `replacer` transforms each parameter name,
|
|
248
|
+
* and `casing` controls parameter identifier casing.
|
|
250
249
|
*
|
|
251
250
|
* @example
|
|
252
|
-
*
|
|
253
|
-
* new URLPath('/pet/{petId}').object
|
|
254
|
-
* // { url: '/pet/:petId', params: { petId: 'petId' } }
|
|
255
|
-
* ```
|
|
256
|
-
*/
|
|
257
|
-
get object() {
|
|
258
|
-
return this.toObject();
|
|
259
|
-
}
|
|
260
|
-
/** Returns a map of path parameter names, or `undefined` when the path has no parameters.
|
|
251
|
+
* Url.toTemplateString('/pet/{petId}') // '`/pet/${petId}`'
|
|
261
252
|
*
|
|
262
253
|
* @example
|
|
263
|
-
*
|
|
264
|
-
* new URLPath('/pet/{petId}').params // { petId: 'petId' }
|
|
265
|
-
* new URLPath('/pet').params // undefined
|
|
266
|
-
* ```
|
|
254
|
+
* Url.toTemplateString('/pet/{petId}', { prefix: 'https://api' }) // '`https://api/pet/${petId}`'
|
|
267
255
|
*/
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
256
|
+
static toTemplateString(path, { prefix, replacer, casing } = {}) {
|
|
257
|
+
const result = path.split(/\{([^}]+)\}/).map((part, i) => {
|
|
258
|
+
if (i % 2 === 0) return part;
|
|
259
|
+
const param = transformParam(part, casing);
|
|
260
|
+
return `\${${replacer ? replacer(param) : param}}`;
|
|
261
|
+
}).join("");
|
|
262
|
+
return `\`${prefix ?? ""}${result}\``;
|
|
274
263
|
}
|
|
275
264
|
/**
|
|
276
|
-
*
|
|
265
|
+
* Returns the path and its extracted params as a structured `URLObject`, or as a stringified
|
|
266
|
+
* expression when `stringify` is set.
|
|
267
|
+
*
|
|
268
|
+
* @example
|
|
269
|
+
* Url.toObject('/pet/{petId}')
|
|
270
|
+
* // { url: '/pet/:petId', params: { petId: 'petId' } }
|
|
277
271
|
*/
|
|
278
|
-
|
|
279
|
-
for (const match of this.path.matchAll(/\{([^}]+)\}/g)) {
|
|
280
|
-
const raw = match[1];
|
|
281
|
-
fn(raw, this.#transformParam(raw));
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
toObject({ type = "path", replacer, stringify } = {}) {
|
|
272
|
+
static toObject(path, { type = "path", replacer, stringify, casing } = {}) {
|
|
285
273
|
const object = {
|
|
286
|
-
url: type === "path" ?
|
|
287
|
-
|
|
274
|
+
url: type === "path" ? Url$1.toPath(path) : Url$1.toTemplateString(path, {
|
|
275
|
+
replacer,
|
|
276
|
+
casing
|
|
277
|
+
}),
|
|
278
|
+
params: toParamsObject(path, {
|
|
279
|
+
replacer,
|
|
280
|
+
casing
|
|
281
|
+
})
|
|
288
282
|
};
|
|
289
283
|
if (stringify) {
|
|
290
284
|
if (type === "template") return JSON.stringify(object).replaceAll("'", "").replaceAll(`"`, "");
|
|
@@ -293,51 +287,211 @@ var URLPath = class {
|
|
|
293
287
|
}
|
|
294
288
|
return object;
|
|
295
289
|
}
|
|
296
|
-
/**
|
|
297
|
-
* Converts the OpenAPI path to a TypeScript template literal string.
|
|
298
|
-
* An optional `replacer` can transform each extracted parameter name before interpolation.
|
|
299
|
-
*
|
|
300
|
-
* @example
|
|
301
|
-
* new URLPath('/pet/{petId}').toTemplateString() // '`/pet/${petId}`'
|
|
302
|
-
*/
|
|
303
|
-
toTemplateString({ prefix = "", replacer } = {}) {
|
|
304
|
-
return `\`${prefix}${this.path.split(/\{([^}]+)\}/).map((part, i) => {
|
|
305
|
-
if (i % 2 === 0) return part;
|
|
306
|
-
const param = this.#transformParam(part);
|
|
307
|
-
return `\${${replacer ? replacer(param) : param}}`;
|
|
308
|
-
}).join("")}\``;
|
|
309
|
-
}
|
|
310
|
-
/**
|
|
311
|
-
* Extracts all `{param}` segments from the path and returns them as a key-value map.
|
|
312
|
-
* An optional `replacer` transforms each parameter name in both key and value positions.
|
|
313
|
-
* Returns `undefined` when no path parameters are found.
|
|
314
|
-
*
|
|
315
|
-
* @example
|
|
316
|
-
* ```ts
|
|
317
|
-
* new URLPath('/pet/{petId}/tag/{tagId}').getParams()
|
|
318
|
-
* // { petId: 'petId', tagId: 'tagId' }
|
|
319
|
-
* ```
|
|
320
|
-
*/
|
|
321
|
-
getParams(replacer) {
|
|
322
|
-
const params = {};
|
|
323
|
-
this.#eachParam((_raw, param) => {
|
|
324
|
-
const key = replacer ? replacer(param) : param;
|
|
325
|
-
params[key] = key;
|
|
326
|
-
});
|
|
327
|
-
return Object.keys(params).length > 0 ? params : void 0;
|
|
328
|
-
}
|
|
329
|
-
/** Converts the OpenAPI path to Express-style colon syntax.
|
|
330
|
-
*
|
|
331
|
-
* @example
|
|
332
|
-
* ```ts
|
|
333
|
-
* new URLPath('/pet/{petId}').toURLPath() // '/pet/:petId'
|
|
334
|
-
* ```
|
|
335
|
-
*/
|
|
336
|
-
toURLPath() {
|
|
337
|
-
return this.path.replace(/\{([^}]+)\}/g, ":$1");
|
|
338
|
-
}
|
|
339
290
|
};
|
|
340
291
|
//#endregion
|
|
292
|
+
//#region ../../internals/shared/src/operation.ts
|
|
293
|
+
/**
|
|
294
|
+
* Builds the `ResolverFileParams` every operation generator passes to
|
|
295
|
+
* `resolver.resolveFile`: a file named `name`, tagged by the operation's first
|
|
296
|
+
* tag (or `'default'`), at the operation's path. Centralizes the entry object
|
|
297
|
+
* that was repeated at dozens of call sites across the client and query plugins.
|
|
298
|
+
*
|
|
299
|
+
* @example
|
|
300
|
+
* ```ts
|
|
301
|
+
* resolver.resolveFile(operationFileEntry(node, node.operationId), { root, output, group })
|
|
302
|
+
* ```
|
|
303
|
+
*/
|
|
304
|
+
function operationFileEntry(node, name, extname = ".ts") {
|
|
305
|
+
return {
|
|
306
|
+
name,
|
|
307
|
+
extname,
|
|
308
|
+
tag: node.tags[0] ?? "default",
|
|
309
|
+
path: node.path
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
function getOperationLink(node, link) {
|
|
313
|
+
if (!link) return null;
|
|
314
|
+
if (typeof link === "function") return link(node) ?? null;
|
|
315
|
+
if (link === "urlPath") return node.path ? `{@link ${Url$1.toPath(node.path)}}` : null;
|
|
316
|
+
return node.path ? `{@link ${node.path.replaceAll("{", ":").replaceAll("}", "")}}` : null;
|
|
317
|
+
}
|
|
318
|
+
function getContentTypeInfo(node) {
|
|
319
|
+
const contentTypes = node.requestBody?.content?.map((e) => e.contentType) ?? [];
|
|
320
|
+
const isMultipleContentTypes = contentTypes.length > 1;
|
|
321
|
+
return {
|
|
322
|
+
contentTypes,
|
|
323
|
+
isMultipleContentTypes,
|
|
324
|
+
contentTypeUnion: isMultipleContentTypes ? contentTypes.map((ct) => JSON.stringify(ct)).join(" | ") : "",
|
|
325
|
+
defaultContentType: contentTypes[0] ?? "application/json",
|
|
326
|
+
hasFormData: contentTypes.some((ct) => ct === "multipart/form-data")
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Derives the default `responseType` for an operation from its primary success response.
|
|
331
|
+
*
|
|
332
|
+
* Returns a value only when that response declares a single non-JSON content type — a binary type
|
|
333
|
+
* (`application/octet-stream`, `application/pdf`, `image/*`, `audio/*`, `video/*`) maps to `'blob'`
|
|
334
|
+
* and other `text/*` maps to `'text'`. Otherwise `undefined`, leaving the runtime client's
|
|
335
|
+
* `Content-Type` auto-detection in charge.
|
|
336
|
+
*/
|
|
337
|
+
function getResponseType(node) {
|
|
338
|
+
const contentTypes = getPrimarySuccessResponse(node)?.content?.map((entry) => entry.contentType) ?? [];
|
|
339
|
+
if (contentTypes.length !== 1) return void 0;
|
|
340
|
+
const baseType = contentTypes[0].split(";")[0].trim().toLowerCase();
|
|
341
|
+
if (baseType === "application/json" || baseType.endsWith("+json") || baseType === "text/json") return void 0;
|
|
342
|
+
if (baseType.startsWith("text/")) return "text";
|
|
343
|
+
if (baseType === "application/octet-stream" || baseType === "application/pdf" || /^(image|audio|video)\//.test(baseType)) return "blob";
|
|
344
|
+
}
|
|
345
|
+
function buildRequestConfigType(node, resolver) {
|
|
346
|
+
const requestName = node.requestBody?.content?.[0]?.schema ? resolver.resolveDataName(node) : null;
|
|
347
|
+
const { isMultipleContentTypes, contentTypeUnion } = getContentTypeInfo(node);
|
|
348
|
+
return `${requestName ? `Partial<RequestConfig<${requestName}>>` : "Partial<RequestConfig>"} & { ${["client?: Client", isMultipleContentTypes ? `contentType?: ${contentTypeUnion}` : null].filter(Boolean).join("; ")} }`;
|
|
349
|
+
}
|
|
350
|
+
function buildOperationComments(node, options = {}) {
|
|
351
|
+
const { link = "pathTemplate", linkPosition = "afterDeprecated", splitLines = false } = options;
|
|
352
|
+
const linkComment = getOperationLink(node, link);
|
|
353
|
+
const filteredComments = (linkPosition === "beforeDeprecated" ? [
|
|
354
|
+
node.description && `@description ${node.description}`,
|
|
355
|
+
node.summary && `@summary ${node.summary}`,
|
|
356
|
+
linkComment,
|
|
357
|
+
node.deprecated && "@deprecated"
|
|
358
|
+
] : [
|
|
359
|
+
node.description && `@description ${node.description}`,
|
|
360
|
+
node.summary && `@summary ${node.summary}`,
|
|
361
|
+
node.deprecated && "@deprecated",
|
|
362
|
+
linkComment
|
|
363
|
+
]).filter((comment) => Boolean(comment));
|
|
364
|
+
if (!splitLines) return filteredComments;
|
|
365
|
+
return filteredComments.flatMap((text) => text.split(/\r?\n/).map((line) => line.trim())).filter((comment) => Boolean(comment));
|
|
366
|
+
}
|
|
367
|
+
function getOperationParameters(node, options = {}) {
|
|
368
|
+
const params = _kubb_core.ast.caseParams(node.parameters, options.paramsCasing);
|
|
369
|
+
return {
|
|
370
|
+
path: params.filter((param) => param.in === "path"),
|
|
371
|
+
query: params.filter((param) => param.in === "query"),
|
|
372
|
+
header: params.filter((param) => param.in === "header"),
|
|
373
|
+
cookie: params.filter((param) => param.in === "cookie")
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
function getStatusCodeNumber(statusCode) {
|
|
377
|
+
const code = Number(statusCode);
|
|
378
|
+
return Number.isNaN(code) ? null : code;
|
|
379
|
+
}
|
|
380
|
+
function isSuccessStatusCode(statusCode) {
|
|
381
|
+
const code = getStatusCodeNumber(statusCode);
|
|
382
|
+
return code !== null && code >= 200 && code < 300;
|
|
383
|
+
}
|
|
384
|
+
function isErrorStatusCode(statusCode) {
|
|
385
|
+
const code = getStatusCodeNumber(statusCode);
|
|
386
|
+
return code !== null && code >= 400;
|
|
387
|
+
}
|
|
388
|
+
function getSuccessResponses(responses) {
|
|
389
|
+
return responses.filter((response) => isSuccessStatusCode(response.statusCode));
|
|
390
|
+
}
|
|
391
|
+
function getOperationSuccessResponses(node) {
|
|
392
|
+
return getSuccessResponses(node.responses);
|
|
393
|
+
}
|
|
394
|
+
function getPrimarySuccessResponse(node) {
|
|
395
|
+
return getOperationSuccessResponses(node)[0] ?? null;
|
|
396
|
+
}
|
|
397
|
+
function resolveErrorNames(node, resolver) {
|
|
398
|
+
return node.responses.filter((response) => isErrorStatusCode(response.statusCode)).map((response) => resolver.resolveResponseStatusName(node, response.statusCode));
|
|
399
|
+
}
|
|
400
|
+
function resolveSuccessNames(node, resolver) {
|
|
401
|
+
return node.responses.filter((response) => isSuccessStatusCode(response.statusCode)).map((response) => resolver.resolveResponseStatusName(node, response.statusCode));
|
|
402
|
+
}
|
|
403
|
+
function resolveStatusCodeNames(node, resolver) {
|
|
404
|
+
return node.responses.map((response) => resolver.resolveResponseStatusName(node, response.statusCode));
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Builds the discriminated union type string for `dataReturnType: 'full'` return shapes.
|
|
408
|
+
* Each member is `{ status: N; data: StatusNType; statusText: string }`.
|
|
409
|
+
*/
|
|
410
|
+
function buildStatusUnionType(node, resolver) {
|
|
411
|
+
const members = node.responses.map((r) => {
|
|
412
|
+
const typeName = resolver.resolveResponseStatusName(node, r.statusCode);
|
|
413
|
+
const statusCode = Number.parseInt(r.statusCode, 10);
|
|
414
|
+
return `{ status: ${Number.isNaN(statusCode) ? "number" : String(statusCode)}; data: ${typeName}; statusText: string }`;
|
|
415
|
+
});
|
|
416
|
+
if (members.length === 1) return members[0];
|
|
417
|
+
return `(${members.join(" | ")})`;
|
|
418
|
+
}
|
|
419
|
+
const typeNamesByResolver = /* @__PURE__ */ new WeakMap();
|
|
420
|
+
function resolveOperationTypeNames(node, resolver, options = {}) {
|
|
421
|
+
const cacheKey = `${node.operationId}\0${options.paramsCasing ?? ""}\0${options.order ?? ""}\0${options.responseStatusNames ?? ""}\0${(options.exclude ?? []).join(",")}`;
|
|
422
|
+
let byResolver = typeNamesByResolver.get(resolver);
|
|
423
|
+
if (byResolver) {
|
|
424
|
+
const cached = byResolver.get(cacheKey);
|
|
425
|
+
if (cached) return cached;
|
|
426
|
+
} else {
|
|
427
|
+
byResolver = /* @__PURE__ */ new Map();
|
|
428
|
+
typeNamesByResolver.set(resolver, byResolver);
|
|
429
|
+
}
|
|
430
|
+
const { path, query, header } = getOperationParameters(node, { paramsCasing: options.paramsCasing });
|
|
431
|
+
const responseStatusNames = options.responseStatusNames === "error" ? resolveErrorNames(node, resolver) : options.responseStatusNames === false ? [] : resolveStatusCodeNames(node, resolver);
|
|
432
|
+
const exclude = new Set(options.exclude ?? []);
|
|
433
|
+
const paramNames = [
|
|
434
|
+
...path.map((param) => resolver.resolvePathParamsName(node, param)),
|
|
435
|
+
...query.map((param) => resolver.resolveQueryParamsName(node, param)),
|
|
436
|
+
...header.map((param) => resolver.resolveHeaderParamsName(node, param))
|
|
437
|
+
];
|
|
438
|
+
const bodyAndResponseNames = [node.requestBody?.content?.[0]?.schema ? resolver.resolveDataName(node) : null, resolver.resolveResponseName(node)];
|
|
439
|
+
const result = (options.order === "body-response-first" ? [
|
|
440
|
+
...bodyAndResponseNames,
|
|
441
|
+
...paramNames,
|
|
442
|
+
...responseStatusNames
|
|
443
|
+
] : [
|
|
444
|
+
...paramNames,
|
|
445
|
+
...bodyAndResponseNames,
|
|
446
|
+
...responseStatusNames
|
|
447
|
+
]).filter((name) => Boolean(name) && !exclude.has(name));
|
|
448
|
+
byResolver.set(cacheKey, result);
|
|
449
|
+
return result;
|
|
450
|
+
}
|
|
451
|
+
//#endregion
|
|
452
|
+
//#region ../../internals/shared/src/group.ts
|
|
453
|
+
/**
|
|
454
|
+
* Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the
|
|
455
|
+
* shared default naming so every plugin groups output consistently:
|
|
456
|
+
*
|
|
457
|
+
* - `path` groups use the second path segment (`/pet/findByStatus` → `pet`).
|
|
458
|
+
* - other groups use the camelCased group (`pet store` → `petStore`).
|
|
459
|
+
*
|
|
460
|
+
* A user-provided `group.name` always wins over the default namer, so callers stay in
|
|
461
|
+
* control of their output folders. Returns `null` when grouping is disabled, matching the
|
|
462
|
+
* per-plugin convention.
|
|
463
|
+
*
|
|
464
|
+
* @param group - The user-supplied group option, or `undefined` to disable grouping.
|
|
465
|
+
*
|
|
466
|
+
* @example
|
|
467
|
+
* ```ts
|
|
468
|
+
* createGroupConfig(group) // shared across every plugin
|
|
469
|
+
* ```
|
|
470
|
+
*/
|
|
471
|
+
function createGroupConfig(group) {
|
|
472
|
+
if (!group) return null;
|
|
473
|
+
const defaultName = (ctx) => {
|
|
474
|
+
if (group.type === "path") return `${ctx.group.split("/")[1]}`;
|
|
475
|
+
return camelCase(ctx.group);
|
|
476
|
+
};
|
|
477
|
+
return {
|
|
478
|
+
...group,
|
|
479
|
+
name: group.name ? group.name : defaultName
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
//#endregion
|
|
483
|
+
//#region ../../internals/shared/src/params.ts
|
|
484
|
+
function buildParamsMapping(originalParams, mappedParams) {
|
|
485
|
+
const mapping = {};
|
|
486
|
+
let hasChanged = false;
|
|
487
|
+
originalParams.forEach((param, i) => {
|
|
488
|
+
const mappedName = mappedParams[i]?.name ?? param.name;
|
|
489
|
+
mapping[param.name] = mappedName;
|
|
490
|
+
if (param.name !== mappedName) hasChanged = true;
|
|
491
|
+
});
|
|
492
|
+
return hasChanged ? mapping : null;
|
|
493
|
+
}
|
|
494
|
+
//#endregion
|
|
341
495
|
//#region src/functionParams.ts
|
|
342
496
|
const declarationPrinter$4 = (0, _kubb_plugin_ts.functionPrinter)({ mode: "declaration" });
|
|
343
497
|
const callPrinter = (0, _kubb_plugin_ts.functionPrinter)({ mode: "call" });
|
|
@@ -348,18 +502,18 @@ function createType(type) {
|
|
|
348
502
|
return type ? _kubb_core.ast.createParamsType({
|
|
349
503
|
variant: "reference",
|
|
350
504
|
name: type
|
|
351
|
-
}) :
|
|
505
|
+
}) : null;
|
|
352
506
|
}
|
|
353
507
|
function createDeclarationLeaf(name, spec) {
|
|
354
508
|
if (spec.default !== void 0) return _kubb_core.ast.createFunctionParameter({
|
|
355
509
|
name,
|
|
356
|
-
type: createType(spec.type),
|
|
510
|
+
type: createType(spec.type) ?? void 0,
|
|
357
511
|
default: spec.default,
|
|
358
512
|
rest: spec.mode === "inlineSpread"
|
|
359
513
|
});
|
|
360
514
|
return _kubb_core.ast.createFunctionParameter({
|
|
361
515
|
name,
|
|
362
|
-
type: createType(spec.type),
|
|
516
|
+
type: createType(spec.type) ?? void 0,
|
|
363
517
|
optional: !!spec.optional,
|
|
364
518
|
rest: spec.mode === "inlineSpread"
|
|
365
519
|
});
|
|
@@ -368,14 +522,14 @@ function createDeclarationParam(name, spec) {
|
|
|
368
522
|
if (isGroup(spec)) return _kubb_core.ast.createParameterGroup({
|
|
369
523
|
inline: spec.mode === "inlineSpread",
|
|
370
524
|
default: spec.default,
|
|
371
|
-
properties: Object.entries(spec.children).filter(([, child]) => child
|
|
525
|
+
properties: Object.entries(spec.children).filter(([, child]) => child != null).map(([childName, child]) => createDeclarationLeaf(childName, child))
|
|
372
526
|
});
|
|
373
527
|
return createDeclarationLeaf(name, spec);
|
|
374
528
|
}
|
|
375
529
|
function createCallParam(name, spec) {
|
|
376
530
|
if (isGroup(spec)) return _kubb_core.ast.createParameterGroup({
|
|
377
531
|
inline: spec.mode === "inlineSpread",
|
|
378
|
-
properties: Object.entries(spec.children).filter(([, child]) => child
|
|
532
|
+
properties: Object.entries(spec.children).filter(([, child]) => child != null).map(([childName, child]) => _kubb_core.ast.createFunctionParameter({
|
|
379
533
|
name: child?.mode === "inlineSpread" ? spec.mode === "inlineSpread" ? child.value ?? childName : `...${child.value ?? childName}` : child?.value ? `${childName}: ${child.value}` : childName,
|
|
380
534
|
rest: spec.mode === "inlineSpread" && child?.mode === "inlineSpread"
|
|
381
535
|
}))
|
|
@@ -390,7 +544,7 @@ function createCallParam(name, spec) {
|
|
|
390
544
|
* Returns utilities to output constructor signatures (`toConstructor()`) or call expressions (`toCall()`).
|
|
391
545
|
*/
|
|
392
546
|
function createFunctionParams(params) {
|
|
393
|
-
const entries = Object.entries(params).filter(([, spec]) => spec
|
|
547
|
+
const entries = Object.entries(params).filter(([, spec]) => spec != null);
|
|
394
548
|
return {
|
|
395
549
|
toConstructor() {
|
|
396
550
|
return declarationPrinter$4.print(_kubb_core.ast.createFunctionParameters({ params: entries.map(([name, spec]) => createDeclarationParam(name, spec)) })) ?? "";
|
|
@@ -403,83 +557,118 @@ function createFunctionParams(params) {
|
|
|
403
557
|
//#endregion
|
|
404
558
|
//#region src/utils.ts
|
|
405
559
|
/**
|
|
406
|
-
*
|
|
407
|
-
* Includes description, summary, link, and deprecation information.
|
|
560
|
+
* Returns `true` when any direction of the parser uses Zod (used for dependency checks).
|
|
408
561
|
*/
|
|
409
|
-
function
|
|
410
|
-
return
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
node.path && `{@link ${new URLPath(node.path).URL}}`,
|
|
414
|
-
node.deprecated && "@deprecated"
|
|
415
|
-
].filter((x) => Boolean(x)).flatMap((text) => text.split(/\r?\n/).map((line) => line.trim())).filter((x) => Boolean(x));
|
|
562
|
+
function isParserEnabled(parser) {
|
|
563
|
+
if (!parser) return false;
|
|
564
|
+
if (parser === "zod") return true;
|
|
565
|
+
return !!(parser.request || parser.response);
|
|
416
566
|
}
|
|
417
567
|
/**
|
|
418
|
-
*
|
|
419
|
-
*
|
|
568
|
+
* Returns `'zod'` when request body parsing is enabled, `null` otherwise.
|
|
569
|
+
* The string shorthand `'zod'` also enables request body parsing (existing behavior).
|
|
420
570
|
*/
|
|
421
|
-
function
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
571
|
+
function resolveRequestParser(parser) {
|
|
572
|
+
if (!parser) return null;
|
|
573
|
+
if (parser === "zod") return "zod";
|
|
574
|
+
return parser.request ?? null;
|
|
575
|
+
}
|
|
576
|
+
/**
|
|
577
|
+
* Returns `'zod'` when query-parameters parsing is enabled, `null` otherwise.
|
|
578
|
+
* Only the object form `{ request: 'zod' }` enables query-params parsing.
|
|
579
|
+
* The string shorthand `'zod'` does not, preserving its existing behavior.
|
|
580
|
+
*/
|
|
581
|
+
function resolveQueryParamsParser(parser) {
|
|
582
|
+
if (!parser || parser === "zod") return null;
|
|
583
|
+
return parser.request ?? null;
|
|
584
|
+
}
|
|
585
|
+
/**
|
|
586
|
+
* Returns `'zod'` when response-direction parsing is enabled, `null` otherwise.
|
|
587
|
+
* `parser: 'zod'` (string shorthand) maps to response parsing and returns `'zod'`.
|
|
588
|
+
*/
|
|
589
|
+
function resolveResponseParser(parser) {
|
|
590
|
+
if (!parser) return null;
|
|
591
|
+
if (parser === "zod") return "zod";
|
|
592
|
+
return parser.response ?? null;
|
|
430
593
|
}
|
|
431
594
|
/**
|
|
432
595
|
* Builds HTTP headers array for a client request.
|
|
433
596
|
* Includes Content-Type (if not default) and spreads header parameters if present.
|
|
434
597
|
*/
|
|
435
598
|
function buildHeaders(contentType, hasHeaderParams) {
|
|
436
|
-
return [contentType !== "application/json" && contentType !== "multipart/form-data" ? `'Content-Type': '${contentType}'` :
|
|
599
|
+
return [contentType !== "application/json" && contentType !== "multipart/form-data" ? `'Content-Type': '${contentType}'` : null, hasHeaderParams ? "...headers" : null].filter(Boolean);
|
|
437
600
|
}
|
|
438
601
|
/**
|
|
439
|
-
*
|
|
440
|
-
*
|
|
602
|
+
* Returns the generic type arguments — response, error, and request body — for a generated
|
|
603
|
+
* client call.
|
|
604
|
+
*
|
|
605
|
+
* When `dataReturnType` is `'full'`, the response generic widens to a union of all documented
|
|
606
|
+
* status types. When `parser` is `'zod'` and a request body schema exists, the request type
|
|
607
|
+
* uses `z.output<typeof schema>` to reflect post-transform types (e.g. date coercion).
|
|
441
608
|
*/
|
|
442
|
-
function buildGenerics(node, tsResolver) {
|
|
443
|
-
const
|
|
444
|
-
const
|
|
609
|
+
function buildGenerics(node, tsResolver, options = {}) {
|
|
610
|
+
const allStatusNames = node.responses.map((r) => tsResolver.resolveResponseStatusName(node, r.statusCode));
|
|
611
|
+
const successNames = resolveSuccessNames(node, tsResolver);
|
|
612
|
+
const responseName = options.dataReturnType === "full" ? allStatusNames.length > 0 ? allStatusNames.join(" | ") : tsResolver.resolveResponseName(node) : successNames.length > 0 ? successNames.join(" | ") : tsResolver.resolveResponseName(node);
|
|
613
|
+
const requestName = node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : null;
|
|
445
614
|
const errorNames = node.responses.filter((r) => Number.parseInt(r.statusCode, 10) >= 400).map((r) => tsResolver.resolveResponseStatusName(node, r.statusCode));
|
|
615
|
+
const TError = `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(" | ") : "Error"}>`;
|
|
616
|
+
const zodRequestName = options.parser === "zod" && options.zodResolver && node.requestBody?.content?.[0]?.schema ? options.zodResolver.resolveDataName?.(node) ?? null : null;
|
|
446
617
|
return [
|
|
447
618
|
responseName,
|
|
448
|
-
|
|
449
|
-
requestName || "unknown"
|
|
619
|
+
TError,
|
|
620
|
+
zodRequestName ? `z.output<typeof ${zodRequestName}>` : requestName || "unknown"
|
|
450
621
|
].filter(Boolean);
|
|
451
622
|
}
|
|
452
623
|
/**
|
|
453
624
|
* Builds the parameters object for a class-based client method.
|
|
454
625
|
* Includes URL, method, base URL, headers, and request/response data.
|
|
455
626
|
*/
|
|
456
|
-
function buildClassClientParams({ node,
|
|
457
|
-
const
|
|
458
|
-
const
|
|
627
|
+
function buildClassClientParams({ node, url, baseURL, tsResolver, isFormData, isMultipleContentTypes, hasFormData, headers, zodQueryParamsName }) {
|
|
628
|
+
const { query: queryParams } = getOperationParameters(node);
|
|
629
|
+
const queryParamsName = queryParams.length > 0 ? tsResolver.resolveQueryParamsName(node, queryParams[0]) : null;
|
|
630
|
+
const requestName = node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : null;
|
|
631
|
+
const responseType = getResponseType(node);
|
|
459
632
|
return createFunctionParams({ config: {
|
|
460
633
|
mode: "object",
|
|
461
634
|
children: {
|
|
462
635
|
requestConfig: { mode: "inlineSpread" },
|
|
463
|
-
method: { value: JSON.stringify(node.method.toUpperCase()) },
|
|
464
|
-
url: { value:
|
|
465
|
-
baseURL: baseURL ? { value: JSON.stringify(baseURL) } :
|
|
466
|
-
params: queryParamsName ? {} :
|
|
467
|
-
data: requestName ? { value: isFormData ? "formData as FormData" : "requestData" } :
|
|
468
|
-
|
|
636
|
+
method: { value: JSON.stringify(_kubb_core.ast.isHttpOperationNode(node) ? node.method.toUpperCase() : "") },
|
|
637
|
+
url: { value: url },
|
|
638
|
+
baseURL: baseURL ? { value: JSON.stringify(baseURL) } : null,
|
|
639
|
+
params: queryParamsName ? zodQueryParamsName ? { value: "requestParams" } : {} : null,
|
|
640
|
+
data: requestName ? { value: isMultipleContentTypes && hasFormData ? "contentType === 'multipart/form-data' ? formData as FormData : requestData" : isFormData ? "formData as FormData" : "requestData" } : null,
|
|
641
|
+
contentType: isMultipleContentTypes ? {} : null,
|
|
642
|
+
responseType: responseType ? { value: JSON.stringify(responseType) } : null,
|
|
643
|
+
headers: headers.length ? { value: `{ ${headers.join(", ")}, ...requestConfig.headers }` } : null
|
|
469
644
|
}
|
|
470
645
|
} });
|
|
471
646
|
}
|
|
472
647
|
/**
|
|
473
648
|
* Builds the request data parsing line for client methods.
|
|
474
|
-
* Applies Zod validation
|
|
649
|
+
* Applies Zod validation when `parser.request === 'zod'`, otherwise assigns data directly.
|
|
475
650
|
*/
|
|
476
651
|
function buildRequestDataLine({ parser, node, zodResolver }) {
|
|
477
|
-
const
|
|
478
|
-
|
|
652
|
+
const requestParser = resolveRequestParser(parser);
|
|
653
|
+
const zodRequestName = zodResolver && requestParser === "zod" && node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : null;
|
|
654
|
+
if (requestParser === "zod" && zodRequestName) return `const requestData = ${zodRequestName}.parse(data)`;
|
|
479
655
|
if (node.requestBody?.content?.[0]?.schema) return "const requestData = data";
|
|
480
656
|
return "";
|
|
481
657
|
}
|
|
482
658
|
/**
|
|
659
|
+
* Builds the query parameters parsing line for client methods.
|
|
660
|
+
* Returns an empty string when no query params exist or query-params parsing is not enabled.
|
|
661
|
+
* Only the object form `parser: { request: 'zod' }` triggers this. `parser: 'zod'` does not.
|
|
662
|
+
*/
|
|
663
|
+
function buildQueryParamsLine({ parser, node, zodResolver }) {
|
|
664
|
+
if (resolveQueryParamsParser(parser) !== "zod" || !zodResolver) return "";
|
|
665
|
+
const { query: queryParams } = getOperationParameters(node);
|
|
666
|
+
if (queryParams.length === 0) return "";
|
|
667
|
+
const zodQueryParamsName = zodResolver.resolveQueryParamsName?.(node, queryParams[0]);
|
|
668
|
+
if (!zodQueryParamsName) return "";
|
|
669
|
+
return `const requestParams = ${zodQueryParamsName}.parse(params)`;
|
|
670
|
+
}
|
|
671
|
+
/**
|
|
483
672
|
* Builds the form data conversion line for file upload requests.
|
|
484
673
|
* Returns empty string if not applicable.
|
|
485
674
|
*/
|
|
@@ -488,19 +677,24 @@ function buildFormDataLine(isFormData, hasRequest) {
|
|
|
488
677
|
}
|
|
489
678
|
/**
|
|
490
679
|
* Builds the return statement for a client method.
|
|
491
|
-
*
|
|
680
|
+
* When `dataReturnType` is `'full'`, casts the response to the status-discriminated union type.
|
|
681
|
+
* When `parser.response` is `'zod'`, pipes the response body through the Zod schema before returning.
|
|
492
682
|
*/
|
|
493
|
-
function buildReturnStatement({ dataReturnType, parser, node, zodResolver }) {
|
|
494
|
-
const
|
|
495
|
-
|
|
496
|
-
if (dataReturnType === "
|
|
497
|
-
|
|
683
|
+
function buildReturnStatement({ dataReturnType, parser, node, zodResolver, tsResolver }) {
|
|
684
|
+
const responseParser = resolveResponseParser(parser);
|
|
685
|
+
const zodResponseName = zodResolver && responseParser === "zod" ? zodResolver.resolveResponseName?.(node) : null;
|
|
686
|
+
if (dataReturnType === "full" && tsResolver) {
|
|
687
|
+
const unionType = buildStatusUnionType(node, tsResolver);
|
|
688
|
+
if (responseParser === "zod" && zodResponseName) return `return {...res, data: ${zodResponseName}.parse(res.data)} as ${unionType}`;
|
|
689
|
+
return `return res as ${unionType}`;
|
|
690
|
+
}
|
|
691
|
+
if (dataReturnType === "data" && responseParser === "zod" && zodResponseName) return `return ${zodResponseName}.parse(res.data)`;
|
|
498
692
|
return "return res.data";
|
|
499
693
|
}
|
|
500
694
|
//#endregion
|
|
501
695
|
//#region src/components/Url.tsx
|
|
502
696
|
const declarationPrinter$3 = (0, _kubb_plugin_ts.functionPrinter)({ mode: "declaration" });
|
|
503
|
-
function
|
|
697
|
+
function buildUrlParamsNode({ paramsType, paramsCasing, pathParamsType, node, tsResolver }) {
|
|
504
698
|
const urlNode = {
|
|
505
699
|
...node,
|
|
506
700
|
parameters: node.parameters.filter((p) => p.in === "path"),
|
|
@@ -513,10 +707,9 @@ function getParams$1({ paramsType, paramsCasing, pathParamsType, node, tsResolve
|
|
|
513
707
|
resolver: tsResolver
|
|
514
708
|
});
|
|
515
709
|
}
|
|
516
|
-
require_chunk.__name(getParams$1, "getParams");
|
|
517
710
|
function Url({ name, isExportable = true, isIndexable = true, baseURL, paramsType, paramsCasing, pathParamsType, node, tsResolver }) {
|
|
518
|
-
|
|
519
|
-
const paramsNode =
|
|
711
|
+
if (!_kubb_core.ast.isHttpOperationNode(node)) return null;
|
|
712
|
+
const paramsNode = buildUrlParamsNode({
|
|
520
713
|
paramsType,
|
|
521
714
|
paramsCasing,
|
|
522
715
|
pathParamsType,
|
|
@@ -524,9 +717,9 @@ function Url({ name, isExportable = true, isIndexable = true, baseURL, paramsTyp
|
|
|
524
717
|
tsResolver
|
|
525
718
|
});
|
|
526
719
|
const paramsSignature = declarationPrinter$3.print(paramsNode) ?? "";
|
|
527
|
-
const originalPathParams = node
|
|
528
|
-
const casedPathParams =
|
|
529
|
-
const pathParamsMapping = paramsCasing ? buildParamsMapping(originalPathParams, casedPathParams) :
|
|
720
|
+
const { path: originalPathParams } = getOperationParameters(node);
|
|
721
|
+
const { path: casedPathParams } = getOperationParameters(node, { paramsCasing });
|
|
722
|
+
const pathParamsMapping = paramsCasing ? buildParamsMapping(originalPathParams, casedPathParams) : null;
|
|
530
723
|
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
|
|
531
724
|
name,
|
|
532
725
|
isExportable,
|
|
@@ -540,7 +733,7 @@ function Url({ name, isExportable = true, isIndexable = true, baseURL, paramsTyp
|
|
|
540
733
|
pathParamsMapping && Object.keys(pathParamsMapping).length > 0 && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)("br", {}),
|
|
541
734
|
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.Const, {
|
|
542
735
|
name: "res",
|
|
543
|
-
children: `{ method: '${node.method.toUpperCase()}', url: ${
|
|
736
|
+
children: `{ method: '${node.method.toUpperCase()}', url: ${Url$1.toTemplateString(node.path, { prefix: baseURL })} as const }`
|
|
544
737
|
}),
|
|
545
738
|
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)("br", {}),
|
|
546
739
|
"return res"
|
|
@@ -548,56 +741,58 @@ function Url({ name, isExportable = true, isIndexable = true, baseURL, paramsTyp
|
|
|
548
741
|
})
|
|
549
742
|
});
|
|
550
743
|
}
|
|
551
|
-
Url.getParams = getParams$1;
|
|
552
744
|
//#endregion
|
|
553
745
|
//#region src/components/Client.tsx
|
|
554
746
|
const declarationPrinter$2 = (0, _kubb_plugin_ts.functionPrinter)({ mode: "declaration" });
|
|
555
|
-
function
|
|
556
|
-
const requestName = node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : void 0;
|
|
747
|
+
function buildClientParamsNode({ paramsType, paramsCasing, pathParamsType, node, tsResolver, isConfigurable }) {
|
|
557
748
|
return _kubb_core.ast.createOperationParams(node, {
|
|
558
749
|
paramsType,
|
|
559
750
|
pathParamsType: paramsType === "object" ? "object" : pathParamsType === "object" ? "object" : "inline",
|
|
560
751
|
paramsCasing,
|
|
561
752
|
resolver: tsResolver,
|
|
562
|
-
extraParams: isConfigurable ? [_kubb_core.ast.createFunctionParameter({
|
|
753
|
+
extraParams: [...isConfigurable ? [_kubb_core.ast.createFunctionParameter({
|
|
563
754
|
name: "config",
|
|
564
755
|
type: _kubb_core.ast.createParamsType({
|
|
565
756
|
variant: "reference",
|
|
566
|
-
name:
|
|
757
|
+
name: buildRequestConfigType(node, tsResolver)
|
|
567
758
|
}),
|
|
568
759
|
default: "{}"
|
|
569
|
-
})] : []
|
|
760
|
+
})] : []]
|
|
570
761
|
});
|
|
571
762
|
}
|
|
572
763
|
function Client({ name, isExportable = true, isIndexable = true, returnType, baseURL, dataReturnType, parser, paramsType, paramsCasing, pathParamsType, node, tsResolver, zodResolver, urlName, children, isConfigurable = true }) {
|
|
573
|
-
|
|
574
|
-
const contentType = node
|
|
575
|
-
const isFormData = contentType === "multipart/form-data";
|
|
576
|
-
const
|
|
577
|
-
const
|
|
578
|
-
const
|
|
579
|
-
const
|
|
580
|
-
const
|
|
581
|
-
const
|
|
582
|
-
const
|
|
583
|
-
const
|
|
584
|
-
const
|
|
585
|
-
const
|
|
586
|
-
const
|
|
587
|
-
const
|
|
588
|
-
const
|
|
589
|
-
const zodResponseName = zodResolver &&
|
|
590
|
-
const zodRequestName = zodResolver &&
|
|
764
|
+
if (!_kubb_core.ast.isHttpOperationNode(node)) return null;
|
|
765
|
+
const { defaultContentType: contentType, isMultipleContentTypes, hasFormData } = getContentTypeInfo(node);
|
|
766
|
+
const isFormData = !isMultipleContentTypes && contentType === "multipart/form-data";
|
|
767
|
+
const responseType = getResponseType(node);
|
|
768
|
+
const { path: originalPathParams, query: originalQueryParams, header: originalHeaderParams } = getOperationParameters(node);
|
|
769
|
+
const { path: casedPathParams, query: casedQueryParams, header: casedHeaderParams } = getOperationParameters(node, { paramsCasing });
|
|
770
|
+
const pathParamsMapping = paramsCasing && !urlName ? buildParamsMapping(originalPathParams, casedPathParams) : null;
|
|
771
|
+
const queryParamsMapping = paramsCasing ? buildParamsMapping(originalQueryParams, casedQueryParams) : null;
|
|
772
|
+
const headerParamsMapping = paramsCasing ? buildParamsMapping(originalHeaderParams, casedHeaderParams) : null;
|
|
773
|
+
const requestName = node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : null;
|
|
774
|
+
const successNames = resolveSuccessNames(node, tsResolver);
|
|
775
|
+
const responseName = successNames.length > 0 ? successNames.join(" | ") : tsResolver.resolveResponseName(node);
|
|
776
|
+
const queryParamsName = originalQueryParams.length > 0 ? tsResolver.resolveQueryParamsName(node, originalQueryParams[0]) : null;
|
|
777
|
+
const headerParamsName = originalHeaderParams.length > 0 ? tsResolver.resolveHeaderParamsName(node, originalHeaderParams[0]) : null;
|
|
778
|
+
const requestParser = resolveRequestParser(parser);
|
|
779
|
+
const responseParser = resolveResponseParser(parser);
|
|
780
|
+
const zodResponseName = zodResolver && responseParser === "zod" ? zodResolver.resolveResponseName?.(node) : null;
|
|
781
|
+
const zodRequestName = zodResolver && requestParser === "zod" && node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : null;
|
|
782
|
+
const queryParamsParser = resolveQueryParamsParser(parser);
|
|
783
|
+
const zodQueryParamsName = zodResolver && queryParamsParser === "zod" && originalQueryParams.length > 0 ? zodResolver.resolveQueryParamsName?.(node, originalQueryParams[0]) : null;
|
|
591
784
|
const errorNames = node.responses.filter((r) => {
|
|
592
785
|
return Number.parseInt(r.statusCode, 10) >= 400;
|
|
593
786
|
}).map((r) => tsResolver.resolveResponseStatusName(node, r.statusCode));
|
|
594
|
-
const headers = [contentType !== "application/json" && contentType !== "multipart/form-data" ? `'Content-Type': '${contentType}'` :
|
|
787
|
+
const headers = [!isMultipleContentTypes && contentType !== "application/json" && contentType !== "multipart/form-data" ? `'Content-Type': '${contentType}'` : null, headerParamsName ? headerParamsMapping ? "...mappedHeaders" : "...headers" : null].filter(Boolean);
|
|
788
|
+
const TError = `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(" | ") : "Error"}>`;
|
|
789
|
+
const allStatusNames = node.responses.map((r) => tsResolver.resolveResponseStatusName(node, r.statusCode));
|
|
595
790
|
const generics = [
|
|
596
|
-
responseName,
|
|
597
|
-
|
|
598
|
-
requestName || "unknown"
|
|
791
|
+
dataReturnType === "full" ? allStatusNames.length > 0 ? allStatusNames.join(" | ") : responseName : responseName,
|
|
792
|
+
TError,
|
|
793
|
+
parser === "zod" && zodRequestName ? `z.output<typeof ${zodRequestName}>` : requestName || "unknown"
|
|
599
794
|
].filter(Boolean);
|
|
600
|
-
const paramsNode =
|
|
795
|
+
const paramsNode = buildClientParamsNode({
|
|
601
796
|
paramsType,
|
|
602
797
|
paramsCasing,
|
|
603
798
|
pathParamsType,
|
|
@@ -606,7 +801,7 @@ function Client({ name, isExportable = true, isIndexable = true, returnType, bas
|
|
|
606
801
|
isConfigurable
|
|
607
802
|
});
|
|
608
803
|
const paramsSignature = declarationPrinter$2.print(paramsNode) ?? "";
|
|
609
|
-
const urlParamsNode =
|
|
804
|
+
const urlParamsNode = buildUrlParamsNode({
|
|
610
805
|
paramsType,
|
|
611
806
|
paramsCasing,
|
|
612
807
|
pathParamsType,
|
|
@@ -617,20 +812,23 @@ function Client({ name, isExportable = true, isIndexable = true, returnType, bas
|
|
|
617
812
|
const clientParams = createFunctionParams({ config: {
|
|
618
813
|
mode: "object",
|
|
619
814
|
children: {
|
|
620
|
-
method: { value:
|
|
621
|
-
url: { value: urlName ? `${urlName}(${urlParamsCall}).url.toString()` : path
|
|
622
|
-
baseURL: baseURL && !urlName ? { value: `\`${baseURL}\`` } :
|
|
623
|
-
params: queryParamsName ? queryParamsMapping ? { value: "mappedParams" } : {} :
|
|
624
|
-
data: requestName ? { value: isFormData ? "formData as FormData" : "requestData" } :
|
|
625
|
-
|
|
626
|
-
|
|
815
|
+
method: { value: (0, _kubb_ast_utils.stringify)(node.method.toUpperCase()) },
|
|
816
|
+
url: { value: urlName ? `${urlName}(${urlParamsCall}).url.toString()` : Url$1.toTemplateString(node.path) },
|
|
817
|
+
baseURL: baseURL && !urlName ? { value: `\`${baseURL}\`` } : null,
|
|
818
|
+
params: queryParamsName ? zodQueryParamsName ? { value: "requestParams" } : queryParamsMapping ? { value: "mappedParams" } : {} : null,
|
|
819
|
+
data: requestName ? { value: isMultipleContentTypes && hasFormData ? "contentType === 'multipart/form-data' ? formData as FormData : requestData" : isFormData ? "formData as FormData" : "requestData" } : null,
|
|
820
|
+
contentType: isConfigurable && isMultipleContentTypes ? {} : null,
|
|
821
|
+
responseType: responseType ? { value: (0, _kubb_ast_utils.stringify)(responseType) } : null,
|
|
822
|
+
requestConfig: isConfigurable ? { mode: "inlineSpread" } : null,
|
|
823
|
+
headers: headers.length ? { value: isConfigurable ? `{ ${headers.join(", ")}, ...requestConfig.headers }` : `{ ${headers.join(", ")} }` } : null
|
|
627
824
|
}
|
|
628
825
|
} });
|
|
826
|
+
const statusUnionType = dataReturnType === "full" ? buildStatusUnionType(node, tsResolver) : null;
|
|
629
827
|
const childrenElement = children ? children : /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [
|
|
630
|
-
dataReturnType === "full" &&
|
|
631
|
-
dataReturnType === "
|
|
632
|
-
dataReturnType === "
|
|
633
|
-
dataReturnType === "data" &&
|
|
828
|
+
dataReturnType === "full" && responseParser === "zod" && zodResponseName && statusUnionType && `return {...res, data: ${zodResponseName}.parse(res.data)} as ${statusUnionType}`,
|
|
829
|
+
dataReturnType === "full" && responseParser !== "zod" && statusUnionType && `return res as ${statusUnionType}`,
|
|
830
|
+
dataReturnType === "data" && responseParser === "zod" && zodResponseName && `return ${zodResponseName}.parse(res.data)`,
|
|
831
|
+
dataReturnType === "data" && responseParser !== "zod" && "return res.data"
|
|
634
832
|
] });
|
|
635
833
|
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)("br", {}), /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
|
|
636
834
|
name,
|
|
@@ -641,46 +839,46 @@ function Client({ name, isExportable = true, isIndexable = true, returnType, bas
|
|
|
641
839
|
async: true,
|
|
642
840
|
export: isExportable,
|
|
643
841
|
params: paramsSignature,
|
|
644
|
-
JSDoc: { comments:
|
|
842
|
+
JSDoc: { comments: buildOperationComments(node, {
|
|
843
|
+
link: "urlPath",
|
|
844
|
+
linkPosition: "beforeDeprecated",
|
|
845
|
+
splitLines: true
|
|
846
|
+
}) },
|
|
645
847
|
returnType,
|
|
646
848
|
children: [
|
|
647
|
-
isConfigurable ?
|
|
648
|
-
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)("br", {}),
|
|
849
|
+
isConfigurable ? `const { client: request = client, ${isMultipleContentTypes ? `contentType = ${(0, _kubb_ast_utils.stringify)(contentType)}, ` : ""}...requestConfig } = config` : "",
|
|
649
850
|
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)("br", {}),
|
|
650
851
|
pathParamsMapping && Object.entries(pathParamsMapping).filter(([originalName, camelCaseName]) => isValidVarName(originalName) && originalName !== camelCaseName).map(([originalName, camelCaseName]) => `const ${originalName} = ${camelCaseName}`).join("\n"),
|
|
651
|
-
pathParamsMapping && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.
|
|
652
|
-
queryParamsMapping && queryParamsName && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
headerParamsMapping && headerParamsName && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [
|
|
658
|
-
`const mappedHeaders = headers ? { ${Object.entries(headerParamsMapping).map(([originalName, camelCaseName]) => `"${originalName}": headers.${camelCaseName}`).join(", ")} } : undefined`,
|
|
659
|
-
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)("br", {}),
|
|
660
|
-
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)("br", {})
|
|
661
|
-
] }),
|
|
662
|
-
parser === "zod" && zodRequestName ? `const requestData = ${zodRequestName}.parse(data)` : requestName && "const requestData = data",
|
|
663
|
-
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)("br", {}),
|
|
664
|
-
isFormData && requestName && "const formData = buildFormData(requestData)",
|
|
852
|
+
pathParamsMapping && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)("br", {}),
|
|
853
|
+
queryParamsMapping && queryParamsName && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [`const mappedParams = params ? { ${Object.entries(queryParamsMapping).map(([originalName, camelCaseName]) => `"${originalName}": params.${camelCaseName}`).join(", ")} } : undefined`, /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)("br", {})] }),
|
|
854
|
+
headerParamsMapping && headerParamsName && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [`const mappedHeaders = headers ? { ${Object.entries(headerParamsMapping).map(([originalName, camelCaseName]) => `"${originalName}": headers.${camelCaseName}`).join(", ")} } : undefined`, /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)("br", {})] }),
|
|
855
|
+
requestParser === "zod" && zodRequestName ? `const requestData = ${zodRequestName}.parse(data)` : requestName && "const requestData = data",
|
|
856
|
+
zodQueryParamsName && `const requestParams = ${zodQueryParamsName}.parse(params)`,
|
|
857
|
+
(isFormData || isMultipleContentTypes && hasFormData) && requestName && "const formData = buildFormData(requestData)",
|
|
665
858
|
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)("br", {}),
|
|
666
|
-
isConfigurable ? `const res = await request<${generics.join(", ")}>(${clientParams.toCall()})` : `const res = await
|
|
859
|
+
isConfigurable ? `const res = await request<${generics.join(", ")}>(${clientParams.toCall()})` : `const res = await client<${generics.join(", ")}>(${clientParams.toCall()})`,
|
|
667
860
|
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)("br", {}),
|
|
668
861
|
childrenElement
|
|
669
862
|
]
|
|
670
863
|
})
|
|
671
864
|
})] });
|
|
672
865
|
}
|
|
673
|
-
Client.getParams = getParams;
|
|
674
866
|
//#endregion
|
|
675
867
|
//#region src/components/ClassClient.tsx
|
|
676
868
|
const declarationPrinter$1 = (0, _kubb_plugin_ts.functionPrinter)({ mode: "declaration" });
|
|
677
869
|
function generateMethod$1({ node, name, tsResolver, zodResolver, baseURL, dataReturnType, parser, paramsType, paramsCasing, pathParamsType }) {
|
|
678
|
-
|
|
679
|
-
const contentType = node
|
|
680
|
-
const isFormData = contentType === "multipart/form-data";
|
|
681
|
-
const
|
|
682
|
-
const
|
|
683
|
-
const
|
|
870
|
+
if (!_kubb_core.ast.isHttpOperationNode(node)) return "";
|
|
871
|
+
const { defaultContentType: contentType, isMultipleContentTypes, hasFormData } = getContentTypeInfo(node);
|
|
872
|
+
const isFormData = !isMultipleContentTypes && contentType === "multipart/form-data";
|
|
873
|
+
const { header: headerParams } = getOperationParameters(node);
|
|
874
|
+
const headerParamsName = headerParams.length > 0 ? tsResolver.resolveHeaderParamsName(node, headerParams[0]) : null;
|
|
875
|
+
const headers = isMultipleContentTypes ? headerParamsName ? ["...headers"] : [] : buildHeaders(contentType, !!headerParamsName);
|
|
876
|
+
const generics = buildGenerics(node, tsResolver, {
|
|
877
|
+
dataReturnType,
|
|
878
|
+
zodResolver,
|
|
879
|
+
parser
|
|
880
|
+
});
|
|
881
|
+
const paramsNode = buildClientParamsNode({
|
|
684
882
|
paramsType,
|
|
685
883
|
paramsCasing,
|
|
686
884
|
pathParamsType,
|
|
@@ -689,31 +887,47 @@ function generateMethod$1({ node, name, tsResolver, zodResolver, baseURL, dataRe
|
|
|
689
887
|
isConfigurable: true
|
|
690
888
|
});
|
|
691
889
|
const paramsSignature = declarationPrinter$1.print(paramsNode) ?? "";
|
|
890
|
+
const { query: queryParams } = getOperationParameters(node);
|
|
891
|
+
const zodQueryParamsName = zodResolver && resolveQueryParamsParser(parser) === "zod" && queryParams.length > 0 ? zodResolver.resolveQueryParamsName?.(node, queryParams[0]) : null;
|
|
692
892
|
const clientParams = buildClassClientParams({
|
|
693
893
|
node,
|
|
694
|
-
path,
|
|
894
|
+
url: Url$1.toTemplateString(node.path, { casing: paramsCasing }),
|
|
695
895
|
baseURL,
|
|
696
896
|
tsResolver,
|
|
697
897
|
isFormData,
|
|
698
|
-
|
|
898
|
+
isMultipleContentTypes,
|
|
899
|
+
hasFormData,
|
|
900
|
+
headers,
|
|
901
|
+
zodQueryParamsName
|
|
699
902
|
});
|
|
700
|
-
const jsdoc = buildJSDoc(
|
|
903
|
+
const jsdoc = (0, _kubb_ast_utils.buildJSDoc)(buildOperationComments(node, {
|
|
904
|
+
link: "urlPath",
|
|
905
|
+
linkPosition: "beforeDeprecated",
|
|
906
|
+
splitLines: true
|
|
907
|
+
}));
|
|
701
908
|
const requestDataLine = buildRequestDataLine({
|
|
702
909
|
parser,
|
|
703
910
|
node,
|
|
704
911
|
zodResolver
|
|
705
912
|
});
|
|
706
|
-
const
|
|
913
|
+
const queryParamsLine = buildQueryParamsLine({
|
|
914
|
+
parser,
|
|
915
|
+
node,
|
|
916
|
+
zodResolver
|
|
917
|
+
});
|
|
918
|
+
const formDataLine = buildFormDataLine(isFormData || isMultipleContentTypes && hasFormData, !!node.requestBody?.content?.[0]?.schema);
|
|
707
919
|
const returnStatement = buildReturnStatement({
|
|
708
920
|
dataReturnType,
|
|
709
921
|
parser,
|
|
710
922
|
node,
|
|
711
|
-
zodResolver
|
|
923
|
+
zodResolver,
|
|
924
|
+
tsResolver
|
|
712
925
|
});
|
|
713
926
|
return `${jsdoc}async ${name}(${paramsSignature}) {\n${[
|
|
714
|
-
|
|
927
|
+
`const { client: request = client, ${isMultipleContentTypes ? `contentType = ${(0, _kubb_ast_utils.stringify)(contentType)}, ` : ""}...requestConfig } = mergeConfig(this.#config, config)`,
|
|
715
928
|
"",
|
|
716
929
|
requestDataLine,
|
|
930
|
+
queryParamsLine,
|
|
717
931
|
formDataLine,
|
|
718
932
|
`const res = await request<${generics.join(", ")}>(${clientParams.toCall()})`,
|
|
719
933
|
returnStatement
|
|
@@ -748,15 +962,14 @@ ${operations.map(({ node, name: methodName, tsResolver, zodResolver }) => genera
|
|
|
748
962
|
children: [classCode, children]
|
|
749
963
|
});
|
|
750
964
|
}
|
|
751
|
-
ClassClient.getParams = Client.getParams;
|
|
752
965
|
//#endregion
|
|
753
966
|
//#region src/components/WrapperClient.tsx
|
|
754
|
-
function WrapperClient({ name,
|
|
967
|
+
function WrapperClient({ name, controllers, isExportable = true, isIndexable = true }) {
|
|
755
968
|
const classCode = `export class ${name} {
|
|
756
|
-
${
|
|
969
|
+
${controllers.map(({ className, propertyName }) => ` readonly ${propertyName}: ${className}`).join("\n")}
|
|
757
970
|
|
|
758
971
|
constructor(config: Partial<RequestConfig> & { client?: Client } = {}) {
|
|
759
|
-
${
|
|
972
|
+
${controllers.map(({ className, propertyName }) => ` this.${propertyName} = new ${className}(config)`).join("\n")}
|
|
760
973
|
}
|
|
761
974
|
}`;
|
|
762
975
|
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
|
|
@@ -769,54 +982,47 @@ ${classNames.map((className) => ` this.${camelCase(className)} = new ${classN
|
|
|
769
982
|
//#endregion
|
|
770
983
|
//#region src/generators/classClientGenerator.tsx
|
|
771
984
|
function resolveTypeImportNames$1(node, tsResolver) {
|
|
772
|
-
return
|
|
773
|
-
node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : void 0,
|
|
774
|
-
tsResolver.resolveResponseName(node),
|
|
775
|
-
...node.parameters.filter((p) => p.in === "path").map((p) => tsResolver.resolvePathParamsName(node, p)),
|
|
776
|
-
...node.parameters.filter((p) => p.in === "query").map((p) => tsResolver.resolveQueryParamsName(node, p)),
|
|
777
|
-
...node.parameters.filter((p) => p.in === "header").map((p) => tsResolver.resolveHeaderParamsName(node, p)),
|
|
778
|
-
...node.responses.map((res) => tsResolver.resolveResponseStatusName(node, res.statusCode))
|
|
779
|
-
].filter((n) => Boolean(n));
|
|
985
|
+
return resolveOperationTypeNames(node, tsResolver, { order: "body-response-first" });
|
|
780
986
|
}
|
|
781
987
|
require_chunk.__name(resolveTypeImportNames$1, "resolveTypeImportNames");
|
|
782
|
-
function resolveZodImportNames$1(node, zodResolver) {
|
|
783
|
-
|
|
988
|
+
function resolveZodImportNames$1(node, zodResolver, parser) {
|
|
989
|
+
const { query: queryParams } = getOperationParameters(node);
|
|
990
|
+
return [
|
|
991
|
+
resolveResponseParser(parser) === "zod" ? zodResolver.resolveResponseName?.(node) : null,
|
|
992
|
+
resolveRequestParser(parser) === "zod" && node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : null,
|
|
993
|
+
resolveQueryParamsParser(parser) === "zod" && queryParams.length > 0 ? zodResolver.resolveQueryParamsName?.(node, queryParams[0]) : null
|
|
994
|
+
].filter((n) => Boolean(n));
|
|
784
995
|
}
|
|
785
996
|
require_chunk.__name(resolveZodImportNames$1, "resolveZodImportNames");
|
|
997
|
+
/**
|
|
998
|
+
* Built-in `operations` generator for `@kubb/plugin-client` when
|
|
999
|
+
* `clientType: 'class'`. Emits one class per tag, with one instance method
|
|
1000
|
+
* per operation and a shared constructor for request configuration.
|
|
1001
|
+
*/
|
|
786
1002
|
const classClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
787
1003
|
name: "classClient",
|
|
788
1004
|
renderer: _kubb_renderer_jsx.jsxRenderer,
|
|
789
1005
|
operations(nodes, ctx) {
|
|
790
|
-
const {
|
|
1006
|
+
const { config, driver, resolver, root } = ctx;
|
|
791
1007
|
const { output, group, dataReturnType, paramsCasing, paramsType, pathParamsType, parser, importPath, sdk } = ctx.options;
|
|
792
|
-
const baseURL = ctx.options.baseURL ??
|
|
1008
|
+
const baseURL = ctx.options.baseURL ?? ctx.meta.baseURL;
|
|
793
1009
|
const pluginTs = driver.getPlugin(_kubb_plugin_ts.pluginTsName);
|
|
794
1010
|
if (!pluginTs) return null;
|
|
795
1011
|
const tsResolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
|
|
796
1012
|
const tsPluginOptions = pluginTs.options;
|
|
797
|
-
const pluginZod = parser
|
|
798
|
-
const zodResolver = pluginZod ? driver.getResolver(_kubb_plugin_zod.pluginZodName) :
|
|
1013
|
+
const pluginZod = isParserEnabled(parser) ? driver.getPlugin(_kubb_plugin_zod.pluginZodName) : null;
|
|
1014
|
+
const zodResolver = pluginZod ? driver.getResolver(_kubb_plugin_zod.pluginZodName) : null;
|
|
799
1015
|
function buildOperationData(node) {
|
|
800
|
-
const typeFile = tsResolver.resolveFile({
|
|
801
|
-
name: node.operationId,
|
|
802
|
-
extname: ".ts",
|
|
803
|
-
tag: node.tags[0] ?? "default",
|
|
804
|
-
path: node.path
|
|
805
|
-
}, {
|
|
1016
|
+
const typeFile = tsResolver.resolveFile(operationFileEntry(node, node.operationId), {
|
|
806
1017
|
root,
|
|
807
1018
|
output: tsPluginOptions?.output ?? output,
|
|
808
1019
|
group: tsPluginOptions?.group
|
|
809
1020
|
});
|
|
810
|
-
const zodFile = zodResolver && pluginZod?.options ? zodResolver.resolveFile({
|
|
811
|
-
name: node.operationId,
|
|
812
|
-
extname: ".ts",
|
|
813
|
-
tag: node.tags[0] ?? "default",
|
|
814
|
-
path: node.path
|
|
815
|
-
}, {
|
|
1021
|
+
const zodFile = zodResolver && pluginZod?.options ? zodResolver.resolveFile(operationFileEntry(node, node.operationId), {
|
|
816
1022
|
root,
|
|
817
1023
|
output: pluginZod.options?.output ?? output,
|
|
818
|
-
group: pluginZod.options?.group
|
|
819
|
-
}) :
|
|
1024
|
+
group: pluginZod.options?.group ?? void 0
|
|
1025
|
+
}) : null;
|
|
820
1026
|
return {
|
|
821
1027
|
node,
|
|
822
1028
|
name: resolver.resolveName(node.operationId),
|
|
@@ -827,27 +1033,31 @@ const classClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
827
1033
|
};
|
|
828
1034
|
}
|
|
829
1035
|
const controllers = nodes.reduce((acc, operationNode) => {
|
|
1036
|
+
if (!_kubb_core.ast.isHttpOperationNode(operationNode)) return acc;
|
|
830
1037
|
const tag = operationNode.tags[0];
|
|
831
|
-
const groupName = tag ? group?.name?.({ group: camelCase(tag) }) ??
|
|
1038
|
+
const groupName = tag ? group?.name?.({ group: camelCase(tag) }) ?? resolver.resolveGroupName(tag) : resolver.resolveClassName("Client");
|
|
832
1039
|
if (!tag && !group) {
|
|
833
|
-
const name = "ApiClient";
|
|
1040
|
+
const name = resolver.resolveClassName("ApiClient");
|
|
834
1041
|
const file = resolver.resolveFile({
|
|
835
1042
|
name,
|
|
836
1043
|
extname: ".ts"
|
|
837
1044
|
}, {
|
|
838
1045
|
root,
|
|
839
1046
|
output,
|
|
840
|
-
group
|
|
1047
|
+
group: group ?? void 0
|
|
841
1048
|
});
|
|
842
1049
|
const operationData = buildOperationData(operationNode);
|
|
843
1050
|
const previous = acc.find((item) => item.file.path === file.path);
|
|
844
1051
|
if (previous) previous.operations.push(operationData);
|
|
845
1052
|
else acc.push({
|
|
846
1053
|
name,
|
|
1054
|
+
propertyName: resolver.resolveClientPropertyName(name),
|
|
847
1055
|
file,
|
|
848
1056
|
operations: [operationData]
|
|
849
1057
|
});
|
|
850
|
-
|
|
1058
|
+
return acc;
|
|
1059
|
+
}
|
|
1060
|
+
if (tag) {
|
|
851
1061
|
const name = groupName;
|
|
852
1062
|
const file = resolver.resolveFile({
|
|
853
1063
|
name,
|
|
@@ -856,13 +1066,14 @@ const classClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
856
1066
|
}, {
|
|
857
1067
|
root,
|
|
858
1068
|
output,
|
|
859
|
-
group
|
|
1069
|
+
group: group ?? void 0
|
|
860
1070
|
});
|
|
861
1071
|
const operationData = buildOperationData(operationNode);
|
|
862
1072
|
const previous = acc.find((item) => item.file.path === file.path);
|
|
863
1073
|
if (previous) previous.operations.push(operationData);
|
|
864
1074
|
else acc.push({
|
|
865
1075
|
name,
|
|
1076
|
+
propertyName: resolver.resolveClientPropertyName(name),
|
|
866
1077
|
file,
|
|
867
1078
|
operations: [operationData]
|
|
868
1079
|
});
|
|
@@ -891,7 +1102,7 @@ const classClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
891
1102
|
const zodFilesByPath = /* @__PURE__ */ new Map();
|
|
892
1103
|
ops.forEach((op) => {
|
|
893
1104
|
if (!op.zodFile || !zodResolver) return;
|
|
894
|
-
const names = resolveZodImportNames$1(op.node, zodResolver);
|
|
1105
|
+
const names = resolveZodImportNames$1(op.node, zodResolver, parser);
|
|
895
1106
|
if (!zodImportsByFile.has(op.zodFile.path)) zodImportsByFile.set(op.zodFile.path, /* @__PURE__ */ new Set());
|
|
896
1107
|
const imports = zodImportsByFile.get(op.zodFile.path);
|
|
897
1108
|
names.forEach((n) => {
|
|
@@ -906,27 +1117,35 @@ const classClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
906
1117
|
}
|
|
907
1118
|
const files = controllers.map(({ name, file, operations: ops }) => {
|
|
908
1119
|
const { typeImportsByFile, typeFilesByPath } = collectTypeImports(ops);
|
|
909
|
-
const { zodImportsByFile, zodFilesByPath } = parser
|
|
1120
|
+
const { zodImportsByFile, zodFilesByPath } = isParserEnabled(parser) ? collectZodImports(ops) : {
|
|
910
1121
|
zodImportsByFile: /* @__PURE__ */ new Map(),
|
|
911
1122
|
zodFilesByPath: /* @__PURE__ */ new Map()
|
|
912
1123
|
};
|
|
913
|
-
const hasFormData = ops.some((op) => op.node.requestBody?.content?.
|
|
1124
|
+
const hasFormData = ops.some((op) => op.node.requestBody?.content?.some((e) => e.contentType === "multipart/form-data") ?? false);
|
|
914
1125
|
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.File, {
|
|
915
1126
|
baseName: file.baseName,
|
|
916
1127
|
path: file.path,
|
|
917
1128
|
meta: file.meta,
|
|
918
|
-
banner: resolver.resolveBanner(
|
|
1129
|
+
banner: resolver.resolveBanner(ctx.meta, {
|
|
919
1130
|
output,
|
|
920
|
-
config
|
|
1131
|
+
config,
|
|
1132
|
+
file: {
|
|
1133
|
+
path: file.path,
|
|
1134
|
+
baseName: file.baseName
|
|
1135
|
+
}
|
|
921
1136
|
}),
|
|
922
|
-
footer: resolver.resolveFooter(
|
|
1137
|
+
footer: resolver.resolveFooter(ctx.meta, {
|
|
923
1138
|
output,
|
|
924
|
-
config
|
|
1139
|
+
config,
|
|
1140
|
+
file: {
|
|
1141
|
+
path: file.path,
|
|
1142
|
+
baseName: file.baseName
|
|
1143
|
+
}
|
|
925
1144
|
}),
|
|
926
1145
|
children: [
|
|
927
1146
|
importPath ? /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [
|
|
928
1147
|
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
929
|
-
name: "
|
|
1148
|
+
name: "client",
|
|
930
1149
|
path: importPath
|
|
931
1150
|
}),
|
|
932
1151
|
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
@@ -944,7 +1163,7 @@ const classClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
944
1163
|
})
|
|
945
1164
|
] }) : /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [
|
|
946
1165
|
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
947
|
-
name: ["
|
|
1166
|
+
name: ["client"],
|
|
948
1167
|
root: file.path,
|
|
949
1168
|
path: node_path.default.resolve(root, ".kubb/client.ts")
|
|
950
1169
|
}),
|
|
@@ -969,6 +1188,11 @@ const classClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
969
1188
|
root: file.path,
|
|
970
1189
|
path: node_path.default.resolve(root, ".kubb/config.ts")
|
|
971
1190
|
}),
|
|
1191
|
+
parser === "zod" && zodResolver && ops.some((op) => op.node.requestBody?.content?.[0]?.schema != null) && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1192
|
+
name: ["z"],
|
|
1193
|
+
path: "zod",
|
|
1194
|
+
isTypeOnly: true
|
|
1195
|
+
}),
|
|
972
1196
|
Array.from(typeImportsByFile.entries()).map(([filePath, importSet]) => {
|
|
973
1197
|
const typeFile = typeFilesByPath.get(filePath);
|
|
974
1198
|
if (!typeFile) return null;
|
|
@@ -981,7 +1205,7 @@ const classClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
981
1205
|
isTypeOnly: true
|
|
982
1206
|
}, filePath);
|
|
983
1207
|
}),
|
|
984
|
-
parser
|
|
1208
|
+
isParserEnabled(parser) && Array.from(zodImportsByFile.entries()).map(([filePath, importSet]) => {
|
|
985
1209
|
const zodFile = zodFilesByPath.get(filePath);
|
|
986
1210
|
if (!zodFile) return null;
|
|
987
1211
|
const importNames = Array.from(importSet).filter(Boolean);
|
|
@@ -1012,19 +1236,27 @@ const classClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1012
1236
|
}, {
|
|
1013
1237
|
root,
|
|
1014
1238
|
output,
|
|
1015
|
-
group
|
|
1239
|
+
group: group ?? void 0
|
|
1016
1240
|
});
|
|
1017
1241
|
files.push(/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.File, {
|
|
1018
1242
|
baseName: sdkFile.baseName,
|
|
1019
1243
|
path: sdkFile.path,
|
|
1020
1244
|
meta: sdkFile.meta,
|
|
1021
|
-
banner: resolver.resolveBanner(
|
|
1245
|
+
banner: resolver.resolveBanner(ctx.meta, {
|
|
1022
1246
|
output,
|
|
1023
|
-
config
|
|
1247
|
+
config,
|
|
1248
|
+
file: {
|
|
1249
|
+
path: sdkFile.path,
|
|
1250
|
+
baseName: sdkFile.baseName
|
|
1251
|
+
}
|
|
1024
1252
|
}),
|
|
1025
|
-
footer: resolver.resolveFooter(
|
|
1253
|
+
footer: resolver.resolveFooter(ctx.meta, {
|
|
1026
1254
|
output,
|
|
1027
|
-
config
|
|
1255
|
+
config,
|
|
1256
|
+
file: {
|
|
1257
|
+
path: sdkFile.path,
|
|
1258
|
+
baseName: sdkFile.baseName
|
|
1259
|
+
}
|
|
1028
1260
|
}),
|
|
1029
1261
|
children: [
|
|
1030
1262
|
importPath ? /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
@@ -1044,7 +1276,10 @@ const classClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1044
1276
|
}, name)),
|
|
1045
1277
|
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(WrapperClient, {
|
|
1046
1278
|
name: sdk.className,
|
|
1047
|
-
|
|
1279
|
+
controllers: controllers.map(({ name, propertyName }) => ({
|
|
1280
|
+
className: name,
|
|
1281
|
+
propertyName
|
|
1282
|
+
}))
|
|
1048
1283
|
})
|
|
1049
1284
|
]
|
|
1050
1285
|
}, sdkFile.path));
|
|
@@ -1054,81 +1289,75 @@ const classClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1054
1289
|
});
|
|
1055
1290
|
//#endregion
|
|
1056
1291
|
//#region src/generators/clientGenerator.tsx
|
|
1292
|
+
/**
|
|
1293
|
+
* Built-in operation generator for `@kubb/plugin-client`. Emits one async
|
|
1294
|
+
* function per OpenAPI operation, plus the matching URL helper. Used when
|
|
1295
|
+
* `clientType: 'function'` (the default).
|
|
1296
|
+
*/
|
|
1057
1297
|
const clientGenerator = (0, _kubb_core.defineGenerator)({
|
|
1058
1298
|
name: "client",
|
|
1059
1299
|
renderer: _kubb_renderer_jsx.jsxRenderer,
|
|
1060
1300
|
operation(node, ctx) {
|
|
1061
|
-
|
|
1301
|
+
if (!_kubb_core.ast.isHttpOperationNode(node)) return null;
|
|
1302
|
+
const { config, driver, resolver, root } = ctx;
|
|
1062
1303
|
const { output, urlType, dataReturnType, paramsCasing, paramsType, pathParamsType, parser, importPath, group } = ctx.options;
|
|
1063
|
-
const baseURL = ctx.options.baseURL ??
|
|
1304
|
+
const baseURL = ctx.options.baseURL ?? ctx.meta.baseURL;
|
|
1064
1305
|
const pluginTs = driver.getPlugin(_kubb_plugin_ts.pluginTsName);
|
|
1065
1306
|
if (!pluginTs) return null;
|
|
1066
1307
|
const tsResolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
|
|
1067
|
-
const pluginZod = parser
|
|
1068
|
-
const zodResolver = pluginZod ? driver.getResolver(_kubb_plugin_zod.pluginZodName) :
|
|
1069
|
-
const
|
|
1070
|
-
const
|
|
1071
|
-
const
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : void 0,
|
|
1078
|
-
tsResolver.resolveResponseName(node),
|
|
1079
|
-
...node.responses.map((res) => tsResolver.resolveResponseStatusName(node, res.statusCode))
|
|
1080
|
-
].filter(Boolean);
|
|
1081
|
-
const importedZodNames = zodResolver && parser === "zod" ? [zodResolver.resolveResponseName?.(node), node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : void 0].filter(Boolean) : [];
|
|
1308
|
+
const pluginZod = isParserEnabled(parser) ? driver.getPlugin(_kubb_plugin_zod.pluginZodName) : null;
|
|
1309
|
+
const zodResolver = pluginZod ? driver.getResolver(_kubb_plugin_zod.pluginZodName) : null;
|
|
1310
|
+
const importedTypeNames = resolveOperationTypeNames(node, tsResolver, { paramsCasing });
|
|
1311
|
+
const { query: queryParams } = getOperationParameters(node);
|
|
1312
|
+
const importedZodNames = zodResolver ? [
|
|
1313
|
+
resolveResponseParser(parser) === "zod" ? zodResolver.resolveResponseName?.(node) : null,
|
|
1314
|
+
resolveRequestParser(parser) === "zod" && node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : null,
|
|
1315
|
+
resolveQueryParamsParser(parser) === "zod" && queryParams.length > 0 ? zodResolver.resolveQueryParamsName?.(node, queryParams[0]) : null
|
|
1316
|
+
].filter((name) => Boolean(name)) : [];
|
|
1317
|
+
const zodRequestName = zodResolver && parser === "zod" && node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) ?? null : null;
|
|
1082
1318
|
const meta = {
|
|
1083
1319
|
name: resolver.resolveName(node.operationId),
|
|
1084
|
-
urlName:
|
|
1085
|
-
file: resolver.resolveFile({
|
|
1086
|
-
name: node.operationId,
|
|
1087
|
-
extname: ".ts",
|
|
1088
|
-
tag: node.tags[0] ?? "default",
|
|
1089
|
-
path: node.path
|
|
1090
|
-
}, {
|
|
1320
|
+
urlName: resolver.resolveUrlName(node),
|
|
1321
|
+
file: resolver.resolveFile(operationFileEntry(node, node.operationId), {
|
|
1091
1322
|
root,
|
|
1092
1323
|
output,
|
|
1093
|
-
group
|
|
1324
|
+
group: group ?? void 0
|
|
1094
1325
|
}),
|
|
1095
|
-
fileTs: tsResolver.resolveFile({
|
|
1096
|
-
name: node.operationId,
|
|
1097
|
-
extname: ".ts",
|
|
1098
|
-
tag: node.tags[0] ?? "default",
|
|
1099
|
-
path: node.path
|
|
1100
|
-
}, {
|
|
1326
|
+
fileTs: tsResolver.resolveFile(operationFileEntry(node, node.operationId), {
|
|
1101
1327
|
root,
|
|
1102
1328
|
output: pluginTs.options?.output ?? output,
|
|
1103
|
-
group: pluginTs.options?.group
|
|
1329
|
+
group: pluginTs.options?.group ?? void 0
|
|
1104
1330
|
}),
|
|
1105
|
-
fileZod: zodResolver && pluginZod?.options ? zodResolver.resolveFile({
|
|
1106
|
-
name: node.operationId,
|
|
1107
|
-
extname: ".ts",
|
|
1108
|
-
tag: node.tags[0] ?? "default",
|
|
1109
|
-
path: node.path
|
|
1110
|
-
}, {
|
|
1331
|
+
fileZod: zodResolver && pluginZod?.options ? zodResolver.resolveFile(operationFileEntry(node, node.operationId), {
|
|
1111
1332
|
root,
|
|
1112
1333
|
output: pluginZod.options.output ?? output,
|
|
1113
|
-
group: pluginZod.options?.group
|
|
1114
|
-
}) :
|
|
1334
|
+
group: pluginZod.options?.group ?? void 0
|
|
1335
|
+
}) : null
|
|
1115
1336
|
};
|
|
1116
|
-
const
|
|
1337
|
+
const hasFormData = node.requestBody?.content?.some((e) => e.contentType === "multipart/form-data") ?? false;
|
|
1117
1338
|
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.File, {
|
|
1118
1339
|
baseName: meta.file.baseName,
|
|
1119
1340
|
path: meta.file.path,
|
|
1120
1341
|
meta: meta.file.meta,
|
|
1121
|
-
banner: resolver.resolveBanner(
|
|
1342
|
+
banner: resolver.resolveBanner(ctx.meta, {
|
|
1122
1343
|
output,
|
|
1123
|
-
config
|
|
1344
|
+
config,
|
|
1345
|
+
file: {
|
|
1346
|
+
path: meta.file.path,
|
|
1347
|
+
baseName: meta.file.baseName
|
|
1348
|
+
}
|
|
1124
1349
|
}),
|
|
1125
|
-
footer: resolver.resolveFooter(
|
|
1350
|
+
footer: resolver.resolveFooter(ctx.meta, {
|
|
1126
1351
|
output,
|
|
1127
|
-
config
|
|
1352
|
+
config,
|
|
1353
|
+
file: {
|
|
1354
|
+
path: meta.file.path,
|
|
1355
|
+
baseName: meta.file.baseName
|
|
1356
|
+
}
|
|
1128
1357
|
}),
|
|
1129
1358
|
children: [
|
|
1130
1359
|
importPath ? /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1131
|
-
name: "
|
|
1360
|
+
name: "client",
|
|
1132
1361
|
path: importPath
|
|
1133
1362
|
}), /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1134
1363
|
name: [
|
|
@@ -1139,7 +1368,7 @@ const clientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1139
1368
|
path: importPath,
|
|
1140
1369
|
isTypeOnly: true
|
|
1141
1370
|
})] }) : /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1142
|
-
name: ["
|
|
1371
|
+
name: ["client"],
|
|
1143
1372
|
root: meta.file.path,
|
|
1144
1373
|
path: node_path.default.resolve(root, ".kubb/client.ts")
|
|
1145
1374
|
}), /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
@@ -1152,11 +1381,16 @@ const clientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1152
1381
|
path: node_path.default.resolve(root, ".kubb/client.ts"),
|
|
1153
1382
|
isTypeOnly: true
|
|
1154
1383
|
})] }),
|
|
1155
|
-
|
|
1384
|
+
hasFormData && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1156
1385
|
name: ["buildFormData"],
|
|
1157
1386
|
root: meta.file.path,
|
|
1158
1387
|
path: node_path.default.resolve(root, ".kubb/config.ts")
|
|
1159
1388
|
}),
|
|
1389
|
+
zodRequestName && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1390
|
+
name: ["z"],
|
|
1391
|
+
path: "zod",
|
|
1392
|
+
isTypeOnly: true
|
|
1393
|
+
}),
|
|
1160
1394
|
meta.fileZod && importedZodNames.length > 0 && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1161
1395
|
name: importedZodNames,
|
|
1162
1396
|
root: meta.file.path,
|
|
@@ -1198,16 +1432,22 @@ const clientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1198
1432
|
});
|
|
1199
1433
|
//#endregion
|
|
1200
1434
|
//#region src/generators/groupedClientGenerator.tsx
|
|
1435
|
+
/**
|
|
1436
|
+
* Emits one aggregate file per tag/group when `group` is configured. Each
|
|
1437
|
+
* file re-exports every client function for that group, so callers can
|
|
1438
|
+
* `import { petController } from './gen/clients'` instead of importing
|
|
1439
|
+
* each operation individually.
|
|
1440
|
+
*/
|
|
1201
1441
|
const groupedClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
1202
1442
|
name: "groupedClient",
|
|
1203
1443
|
renderer: _kubb_renderer_jsx.jsxRenderer,
|
|
1204
1444
|
operations(nodes, ctx) {
|
|
1205
|
-
const { config, resolver,
|
|
1445
|
+
const { config, resolver, root } = ctx;
|
|
1206
1446
|
const { output, group } = ctx.options;
|
|
1207
1447
|
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: nodes.reduce((acc, operationNode) => {
|
|
1208
1448
|
if (group?.type === "tag") {
|
|
1209
1449
|
const tag = operationNode.tags[0];
|
|
1210
|
-
const name = tag ? group?.name?.({ group: camelCase(tag) }) :
|
|
1450
|
+
const name = tag ? group?.name?.({ group: camelCase(tag) }) : null;
|
|
1211
1451
|
if (!tag || !name) return acc;
|
|
1212
1452
|
const file = resolver.resolveFile({
|
|
1213
1453
|
name,
|
|
@@ -1216,7 +1456,7 @@ const groupedClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1216
1456
|
}, {
|
|
1217
1457
|
root,
|
|
1218
1458
|
output,
|
|
1219
|
-
group
|
|
1459
|
+
group: group ?? void 0
|
|
1220
1460
|
});
|
|
1221
1461
|
const clientFile = resolver.resolveFile({
|
|
1222
1462
|
name: operationNode.operationId,
|
|
@@ -1226,7 +1466,7 @@ const groupedClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1226
1466
|
}, {
|
|
1227
1467
|
root,
|
|
1228
1468
|
output,
|
|
1229
|
-
group
|
|
1469
|
+
group: group ?? void 0
|
|
1230
1470
|
});
|
|
1231
1471
|
const client = {
|
|
1232
1472
|
name: resolver.resolveName(operationNode.operationId),
|
|
@@ -1246,13 +1486,23 @@ const groupedClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1246
1486
|
baseName: file.baseName,
|
|
1247
1487
|
path: file.path,
|
|
1248
1488
|
meta: file.meta,
|
|
1249
|
-
banner: resolver.resolveBanner(
|
|
1489
|
+
banner: resolver.resolveBanner(ctx.meta, {
|
|
1250
1490
|
output,
|
|
1251
|
-
config
|
|
1491
|
+
config,
|
|
1492
|
+
file: {
|
|
1493
|
+
path: file.path,
|
|
1494
|
+
baseName: file.baseName,
|
|
1495
|
+
isAggregation: true
|
|
1496
|
+
}
|
|
1252
1497
|
}),
|
|
1253
|
-
footer: resolver.resolveFooter(
|
|
1498
|
+
footer: resolver.resolveFooter(ctx.meta, {
|
|
1254
1499
|
output,
|
|
1255
|
-
config
|
|
1500
|
+
config,
|
|
1501
|
+
file: {
|
|
1502
|
+
path: file.path,
|
|
1503
|
+
baseName: file.baseName,
|
|
1504
|
+
isAggregation: true
|
|
1505
|
+
}
|
|
1256
1506
|
}),
|
|
1257
1507
|
children: [clients.map((client) => /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1258
1508
|
name: [client.name],
|
|
@@ -1273,33 +1523,17 @@ const groupedClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1273
1523
|
}
|
|
1274
1524
|
});
|
|
1275
1525
|
//#endregion
|
|
1276
|
-
//#region src/
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
};
|
|
1284
|
-
});
|
|
1285
|
-
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
|
|
1286
|
-
name,
|
|
1287
|
-
isExportable: true,
|
|
1288
|
-
isIndexable: true,
|
|
1289
|
-
children: /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.Const, {
|
|
1290
|
-
name,
|
|
1291
|
-
export: true,
|
|
1292
|
-
children: JSON.stringify(operationsObject, void 0, 2)
|
|
1293
|
-
})
|
|
1294
|
-
});
|
|
1295
|
-
}
|
|
1296
|
-
//#endregion
|
|
1297
|
-
//#region src/generators/operationsGenerator.tsx
|
|
1526
|
+
//#region src/generators/operationsGenerator.ts
|
|
1527
|
+
/**
|
|
1528
|
+
* Generates an `operations.ts` file that re-exports every operation grouped
|
|
1529
|
+
* by HTTP method. Enabled when `pluginClient({ operations: true })`. Useful
|
|
1530
|
+
* for building meta-tooling on top of the generated client (route
|
|
1531
|
+
* registries, API explorers).
|
|
1532
|
+
*/
|
|
1298
1533
|
const operationsGenerator = (0, _kubb_core.defineGenerator)({
|
|
1299
1534
|
name: "client",
|
|
1300
|
-
renderer: _kubb_renderer_jsx.jsxRenderer,
|
|
1301
1535
|
operations(nodes, ctx) {
|
|
1302
|
-
const { config, resolver,
|
|
1536
|
+
const { config, resolver, root } = ctx;
|
|
1303
1537
|
const { output, group } = ctx.options;
|
|
1304
1538
|
const name = "operations";
|
|
1305
1539
|
const file = resolver.resolveFile({
|
|
@@ -1308,37 +1542,65 @@ const operationsGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1308
1542
|
}, {
|
|
1309
1543
|
root,
|
|
1310
1544
|
output,
|
|
1311
|
-
group
|
|
1545
|
+
group: group ?? void 0
|
|
1312
1546
|
});
|
|
1313
|
-
|
|
1547
|
+
const operationsObject = {};
|
|
1548
|
+
for (const node of nodes) {
|
|
1549
|
+
if (!_kubb_core.ast.isHttpOperationNode(node)) continue;
|
|
1550
|
+
operationsObject[node.operationId] = {
|
|
1551
|
+
path: Url$1.toPath(node.path),
|
|
1552
|
+
method: node.method.toLowerCase()
|
|
1553
|
+
};
|
|
1554
|
+
}
|
|
1555
|
+
return [_kubb_core.ast.createFile({
|
|
1314
1556
|
baseName: file.baseName,
|
|
1315
1557
|
path: file.path,
|
|
1316
1558
|
meta: file.meta,
|
|
1317
|
-
banner: resolver.resolveBanner(
|
|
1559
|
+
banner: resolver.resolveBanner(ctx.meta, {
|
|
1318
1560
|
output,
|
|
1319
|
-
config
|
|
1561
|
+
config,
|
|
1562
|
+
file: {
|
|
1563
|
+
path: file.path,
|
|
1564
|
+
baseName: file.baseName
|
|
1565
|
+
}
|
|
1320
1566
|
}),
|
|
1321
|
-
footer: resolver.resolveFooter(
|
|
1567
|
+
footer: resolver.resolveFooter(ctx.meta, {
|
|
1322
1568
|
output,
|
|
1323
|
-
config
|
|
1569
|
+
config,
|
|
1570
|
+
file: {
|
|
1571
|
+
path: file.path,
|
|
1572
|
+
baseName: file.baseName
|
|
1573
|
+
}
|
|
1324
1574
|
}),
|
|
1325
|
-
|
|
1575
|
+
sources: [_kubb_core.ast.createSource({
|
|
1326
1576
|
name,
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1577
|
+
isExportable: true,
|
|
1578
|
+
isIndexable: true,
|
|
1579
|
+
nodes: [_kubb_core.ast.createConst({
|
|
1580
|
+
name,
|
|
1581
|
+
export: true,
|
|
1582
|
+
nodes: [_kubb_core.ast.createText(JSON.stringify(operationsObject, void 0, 2))]
|
|
1583
|
+
})]
|
|
1584
|
+
})]
|
|
1585
|
+
})];
|
|
1330
1586
|
}
|
|
1331
1587
|
});
|
|
1332
1588
|
//#endregion
|
|
1333
1589
|
//#region src/components/StaticClassClient.tsx
|
|
1334
1590
|
const declarationPrinter = (0, _kubb_plugin_ts.functionPrinter)({ mode: "declaration" });
|
|
1335
1591
|
function generateMethod({ node, name, tsResolver, zodResolver, baseURL, dataReturnType, parser, paramsType, paramsCasing, pathParamsType }) {
|
|
1336
|
-
|
|
1337
|
-
const contentType = node
|
|
1338
|
-
const isFormData = contentType === "multipart/form-data";
|
|
1339
|
-
const
|
|
1340
|
-
const
|
|
1341
|
-
const
|
|
1592
|
+
if (!_kubb_core.ast.isHttpOperationNode(node)) return "";
|
|
1593
|
+
const { defaultContentType: contentType, isMultipleContentTypes, hasFormData } = getContentTypeInfo(node);
|
|
1594
|
+
const isFormData = !isMultipleContentTypes && contentType === "multipart/form-data";
|
|
1595
|
+
const { header: headerParams } = getOperationParameters(node);
|
|
1596
|
+
const headerParamsName = headerParams.length > 0 ? tsResolver.resolveHeaderParamsName(node, headerParams[0]) : null;
|
|
1597
|
+
const headers = isMultipleContentTypes ? headerParamsName ? ["...headers"] : [] : buildHeaders(contentType, !!headerParamsName);
|
|
1598
|
+
const generics = buildGenerics(node, tsResolver, {
|
|
1599
|
+
dataReturnType,
|
|
1600
|
+
zodResolver,
|
|
1601
|
+
parser
|
|
1602
|
+
});
|
|
1603
|
+
const paramsNode = buildClientParamsNode({
|
|
1342
1604
|
paramsType,
|
|
1343
1605
|
paramsCasing,
|
|
1344
1606
|
pathParamsType,
|
|
@@ -1347,31 +1609,47 @@ function generateMethod({ node, name, tsResolver, zodResolver, baseURL, dataRetu
|
|
|
1347
1609
|
isConfigurable: true
|
|
1348
1610
|
});
|
|
1349
1611
|
const paramsSignature = declarationPrinter.print(paramsNode) ?? "";
|
|
1612
|
+
const { query: queryParams } = getOperationParameters(node);
|
|
1613
|
+
const zodQueryParamsName = zodResolver && resolveQueryParamsParser(parser) === "zod" && queryParams.length > 0 ? zodResolver.resolveQueryParamsName?.(node, queryParams[0]) : null;
|
|
1350
1614
|
const clientParams = buildClassClientParams({
|
|
1351
1615
|
node,
|
|
1352
|
-
path,
|
|
1616
|
+
url: Url$1.toTemplateString(node.path, { casing: paramsCasing }),
|
|
1353
1617
|
baseURL,
|
|
1354
1618
|
tsResolver,
|
|
1355
1619
|
isFormData,
|
|
1356
|
-
|
|
1620
|
+
isMultipleContentTypes,
|
|
1621
|
+
hasFormData,
|
|
1622
|
+
headers,
|
|
1623
|
+
zodQueryParamsName
|
|
1357
1624
|
});
|
|
1358
|
-
const jsdoc = buildJSDoc(
|
|
1625
|
+
const jsdoc = (0, _kubb_ast_utils.buildJSDoc)(buildOperationComments(node, {
|
|
1626
|
+
link: "urlPath",
|
|
1627
|
+
linkPosition: "beforeDeprecated",
|
|
1628
|
+
splitLines: true
|
|
1629
|
+
}));
|
|
1359
1630
|
const requestDataLine = buildRequestDataLine({
|
|
1360
1631
|
parser,
|
|
1361
1632
|
node,
|
|
1362
1633
|
zodResolver
|
|
1363
1634
|
});
|
|
1364
|
-
const
|
|
1635
|
+
const queryParamsLine = buildQueryParamsLine({
|
|
1636
|
+
parser,
|
|
1637
|
+
node,
|
|
1638
|
+
zodResolver
|
|
1639
|
+
});
|
|
1640
|
+
const formDataLine = buildFormDataLine(isFormData || isMultipleContentTypes && hasFormData, !!node.requestBody?.content?.[0]?.schema);
|
|
1365
1641
|
const returnStatement = buildReturnStatement({
|
|
1366
1642
|
dataReturnType,
|
|
1367
1643
|
parser,
|
|
1368
1644
|
node,
|
|
1369
|
-
zodResolver
|
|
1645
|
+
zodResolver,
|
|
1646
|
+
tsResolver
|
|
1370
1647
|
});
|
|
1371
1648
|
return `${jsdoc} static async ${name}(${paramsSignature}) {\n${[
|
|
1372
|
-
|
|
1649
|
+
`const { client: request = client, ${isMultipleContentTypes ? `contentType = ${(0, _kubb_ast_utils.stringify)(contentType)}, ` : ""}...requestConfig } = mergeConfig(this.#config, config)`,
|
|
1373
1650
|
"",
|
|
1374
1651
|
requestDataLine,
|
|
1652
|
+
queryParamsLine,
|
|
1375
1653
|
formDataLine,
|
|
1376
1654
|
`const res = await request<${generics.join(", ")}>(${clientParams.toCall()})`,
|
|
1377
1655
|
returnStatement
|
|
@@ -1397,56 +1675,49 @@ function StaticClassClient({ name, isExportable = true, isIndexable = true, oper
|
|
|
1397
1675
|
children: [classCode, children]
|
|
1398
1676
|
});
|
|
1399
1677
|
}
|
|
1400
|
-
StaticClassClient.getParams = Client.getParams;
|
|
1401
1678
|
//#endregion
|
|
1402
1679
|
//#region src/generators/staticClassClientGenerator.tsx
|
|
1403
1680
|
function resolveTypeImportNames(node, tsResolver) {
|
|
1681
|
+
return resolveOperationTypeNames(node, tsResolver, { order: "body-response-first" });
|
|
1682
|
+
}
|
|
1683
|
+
function resolveZodImportNames(node, zodResolver, parser) {
|
|
1684
|
+
const { query: queryParams } = getOperationParameters(node);
|
|
1404
1685
|
return [
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
...node.parameters.filter((p) => p.in === "query").map((p) => tsResolver.resolveQueryParamsName(node, p)),
|
|
1409
|
-
...node.parameters.filter((p) => p.in === "header").map((p) => tsResolver.resolveHeaderParamsName(node, p)),
|
|
1410
|
-
...node.responses.map((res) => tsResolver.resolveResponseStatusName(node, res.statusCode))
|
|
1686
|
+
resolveResponseParser(parser) === "zod" ? zodResolver.resolveResponseName?.(node) : null,
|
|
1687
|
+
resolveRequestParser(parser) === "zod" && node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : null,
|
|
1688
|
+
resolveQueryParamsParser(parser) === "zod" && queryParams.length > 0 ? zodResolver.resolveQueryParamsName?.(node, queryParams[0]) : null
|
|
1411
1689
|
].filter((n) => Boolean(n));
|
|
1412
1690
|
}
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1691
|
+
/**
|
|
1692
|
+
* Built-in `operations` generator for `@kubb/plugin-client` when
|
|
1693
|
+
* `clientType: 'staticClass'`. Emits one class per tag, with a static method
|
|
1694
|
+
* per operation so callers can use `Pet.getPetById(...)` without
|
|
1695
|
+
* instantiating the class.
|
|
1696
|
+
*/
|
|
1416
1697
|
const staticClassClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
1417
1698
|
name: "staticClassClient",
|
|
1418
1699
|
renderer: _kubb_renderer_jsx.jsxRenderer,
|
|
1419
1700
|
operations(nodes, ctx) {
|
|
1420
|
-
const {
|
|
1701
|
+
const { config, driver, resolver, root } = ctx;
|
|
1421
1702
|
const { output, group, dataReturnType, paramsCasing, paramsType, pathParamsType, parser, importPath } = ctx.options;
|
|
1422
|
-
const baseURL = ctx.options.baseURL ??
|
|
1703
|
+
const baseURL = ctx.options.baseURL ?? ctx.meta.baseURL;
|
|
1423
1704
|
const pluginTs = driver.getPlugin(_kubb_plugin_ts.pluginTsName);
|
|
1424
1705
|
if (!pluginTs) return null;
|
|
1425
1706
|
const tsResolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
|
|
1426
1707
|
const tsPluginOptions = pluginTs.options;
|
|
1427
|
-
const pluginZod = parser
|
|
1428
|
-
const zodResolver = pluginZod ? driver.getResolver(_kubb_plugin_zod.pluginZodName) :
|
|
1708
|
+
const pluginZod = isParserEnabled(parser) ? driver.getPlugin(_kubb_plugin_zod.pluginZodName) : null;
|
|
1709
|
+
const zodResolver = pluginZod ? driver.getResolver(_kubb_plugin_zod.pluginZodName) : null;
|
|
1429
1710
|
function buildOperationData(node) {
|
|
1430
|
-
const typeFile = tsResolver.resolveFile({
|
|
1431
|
-
name: node.operationId,
|
|
1432
|
-
extname: ".ts",
|
|
1433
|
-
tag: node.tags[0] ?? "default",
|
|
1434
|
-
path: node.path
|
|
1435
|
-
}, {
|
|
1711
|
+
const typeFile = tsResolver.resolveFile(operationFileEntry(node, node.operationId), {
|
|
1436
1712
|
root,
|
|
1437
1713
|
output: tsPluginOptions?.output ?? output,
|
|
1438
1714
|
group: tsPluginOptions?.group
|
|
1439
1715
|
});
|
|
1440
|
-
const zodFile = zodResolver && pluginZod?.options ? zodResolver.resolveFile({
|
|
1441
|
-
name: node.operationId,
|
|
1442
|
-
extname: ".ts",
|
|
1443
|
-
tag: node.tags[0] ?? "default",
|
|
1444
|
-
path: node.path
|
|
1445
|
-
}, {
|
|
1716
|
+
const zodFile = zodResolver && pluginZod?.options ? zodResolver.resolveFile(operationFileEntry(node, node.operationId), {
|
|
1446
1717
|
root,
|
|
1447
1718
|
output: pluginZod.options?.output ?? output,
|
|
1448
|
-
group: pluginZod.options?.group
|
|
1449
|
-
}) :
|
|
1719
|
+
group: pluginZod.options?.group ?? void 0
|
|
1720
|
+
}) : null;
|
|
1450
1721
|
return {
|
|
1451
1722
|
node,
|
|
1452
1723
|
name: resolver.resolveName(node.operationId),
|
|
@@ -1457,17 +1728,18 @@ const staticClassClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1457
1728
|
};
|
|
1458
1729
|
}
|
|
1459
1730
|
const controllers = nodes.reduce((acc, operationNode) => {
|
|
1731
|
+
if (!_kubb_core.ast.isHttpOperationNode(operationNode)) return acc;
|
|
1460
1732
|
const tag = operationNode.tags[0];
|
|
1461
|
-
const groupName = tag ? group?.name?.({ group: camelCase(tag) }) ??
|
|
1733
|
+
const groupName = tag ? group?.name?.({ group: camelCase(tag) }) ?? resolver.resolveGroupName(tag) : resolver.resolveClassName("Client");
|
|
1462
1734
|
if (!tag && !group) {
|
|
1463
|
-
const name = "ApiClient";
|
|
1735
|
+
const name = resolver.resolveClassName("ApiClient");
|
|
1464
1736
|
const file = resolver.resolveFile({
|
|
1465
1737
|
name,
|
|
1466
1738
|
extname: ".ts"
|
|
1467
1739
|
}, {
|
|
1468
1740
|
root,
|
|
1469
1741
|
output,
|
|
1470
|
-
group
|
|
1742
|
+
group: group ?? void 0
|
|
1471
1743
|
});
|
|
1472
1744
|
const operationData = buildOperationData(operationNode);
|
|
1473
1745
|
const previous = acc.find((item) => item.file.path === file.path);
|
|
@@ -1477,7 +1749,9 @@ const staticClassClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1477
1749
|
file,
|
|
1478
1750
|
operations: [operationData]
|
|
1479
1751
|
});
|
|
1480
|
-
|
|
1752
|
+
return acc;
|
|
1753
|
+
}
|
|
1754
|
+
if (tag) {
|
|
1481
1755
|
const name = groupName;
|
|
1482
1756
|
const file = resolver.resolveFile({
|
|
1483
1757
|
name,
|
|
@@ -1486,7 +1760,7 @@ const staticClassClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1486
1760
|
}, {
|
|
1487
1761
|
root,
|
|
1488
1762
|
output,
|
|
1489
|
-
group
|
|
1763
|
+
group: group ?? void 0
|
|
1490
1764
|
});
|
|
1491
1765
|
const operationData = buildOperationData(operationNode);
|
|
1492
1766
|
const previous = acc.find((item) => item.file.path === file.path);
|
|
@@ -1521,7 +1795,7 @@ const staticClassClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1521
1795
|
const zodFilesByPath = /* @__PURE__ */ new Map();
|
|
1522
1796
|
ops.forEach((op) => {
|
|
1523
1797
|
if (!op.zodFile || !zodResolver) return;
|
|
1524
|
-
const names = resolveZodImportNames(op.node, zodResolver);
|
|
1798
|
+
const names = resolveZodImportNames(op.node, zodResolver, parser);
|
|
1525
1799
|
if (!zodImportsByFile.has(op.zodFile.path)) zodImportsByFile.set(op.zodFile.path, /* @__PURE__ */ new Set());
|
|
1526
1800
|
const imports = zodImportsByFile.get(op.zodFile.path);
|
|
1527
1801
|
names.forEach((n) => {
|
|
@@ -1536,27 +1810,35 @@ const staticClassClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1536
1810
|
}
|
|
1537
1811
|
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: controllers.map(({ name, file, operations: ops }) => {
|
|
1538
1812
|
const { typeImportsByFile, typeFilesByPath } = collectTypeImports(ops);
|
|
1539
|
-
const { zodImportsByFile, zodFilesByPath } = parser
|
|
1813
|
+
const { zodImportsByFile, zodFilesByPath } = isParserEnabled(parser) ? collectZodImports(ops) : {
|
|
1540
1814
|
zodImportsByFile: /* @__PURE__ */ new Map(),
|
|
1541
1815
|
zodFilesByPath: /* @__PURE__ */ new Map()
|
|
1542
1816
|
};
|
|
1543
|
-
const hasFormData = ops.some((op) => op.node.requestBody?.content?.
|
|
1817
|
+
const hasFormData = ops.some((op) => op.node.requestBody?.content?.some((e) => e.contentType === "multipart/form-data") ?? false);
|
|
1544
1818
|
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.File, {
|
|
1545
1819
|
baseName: file.baseName,
|
|
1546
1820
|
path: file.path,
|
|
1547
1821
|
meta: file.meta,
|
|
1548
|
-
banner: resolver.resolveBanner(
|
|
1822
|
+
banner: resolver.resolveBanner(ctx.meta, {
|
|
1549
1823
|
output,
|
|
1550
|
-
config
|
|
1824
|
+
config,
|
|
1825
|
+
file: {
|
|
1826
|
+
path: file.path,
|
|
1827
|
+
baseName: file.baseName
|
|
1828
|
+
}
|
|
1551
1829
|
}),
|
|
1552
|
-
footer: resolver.resolveFooter(
|
|
1830
|
+
footer: resolver.resolveFooter(ctx.meta, {
|
|
1553
1831
|
output,
|
|
1554
|
-
config
|
|
1832
|
+
config,
|
|
1833
|
+
file: {
|
|
1834
|
+
path: file.path,
|
|
1835
|
+
baseName: file.baseName
|
|
1836
|
+
}
|
|
1555
1837
|
}),
|
|
1556
1838
|
children: [
|
|
1557
1839
|
importPath ? /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [
|
|
1558
1840
|
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1559
|
-
name: "
|
|
1841
|
+
name: "client",
|
|
1560
1842
|
path: importPath
|
|
1561
1843
|
}),
|
|
1562
1844
|
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
@@ -1574,7 +1856,7 @@ const staticClassClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1574
1856
|
})
|
|
1575
1857
|
] }) : /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [
|
|
1576
1858
|
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1577
|
-
name: ["
|
|
1859
|
+
name: ["client"],
|
|
1578
1860
|
root: file.path,
|
|
1579
1861
|
path: node_path.default.resolve(root, ".kubb/client.ts")
|
|
1580
1862
|
}),
|
|
@@ -1599,6 +1881,11 @@ const staticClassClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1599
1881
|
root: file.path,
|
|
1600
1882
|
path: node_path.default.resolve(root, ".kubb/config.ts")
|
|
1601
1883
|
}),
|
|
1884
|
+
parser === "zod" && zodResolver && ops.some((op) => op.node.requestBody?.content?.[0]?.schema != null) && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1885
|
+
name: ["z"],
|
|
1886
|
+
path: "zod",
|
|
1887
|
+
isTypeOnly: true
|
|
1888
|
+
}),
|
|
1602
1889
|
Array.from(typeImportsByFile.entries()).map(([filePath, importSet]) => {
|
|
1603
1890
|
const typeFile = typeFilesByPath.get(filePath);
|
|
1604
1891
|
if (!typeFile) return null;
|
|
@@ -1611,7 +1898,7 @@ const staticClassClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1611
1898
|
isTypeOnly: true
|
|
1612
1899
|
}, filePath);
|
|
1613
1900
|
}),
|
|
1614
|
-
parser
|
|
1901
|
+
isParserEnabled(parser) && Array.from(zodImportsByFile.entries()).map(([filePath, importSet]) => {
|
|
1615
1902
|
const zodFile = zodFilesByPath.get(filePath);
|
|
1616
1903
|
if (!zodFile) return null;
|
|
1617
1904
|
const importNames = Array.from(importSet).filter(Boolean);
|
|
@@ -1640,64 +1927,95 @@ const staticClassClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1640
1927
|
//#endregion
|
|
1641
1928
|
//#region src/resolvers/resolverClient.ts
|
|
1642
1929
|
/**
|
|
1643
|
-
*
|
|
1930
|
+
* Default resolver used by `@kubb/plugin-client`. Decides the names and file
|
|
1931
|
+
* paths for every generated client function or class. Functions and files use
|
|
1932
|
+
* camelCase; classes and tag groups use PascalCase.
|
|
1644
1933
|
*
|
|
1645
|
-
*
|
|
1934
|
+
* @example Resolve client function and class names
|
|
1935
|
+
* ```ts
|
|
1936
|
+
* import { resolverClient } from '@kubb/plugin-client'
|
|
1646
1937
|
*
|
|
1647
|
-
*
|
|
1648
|
-
*
|
|
1938
|
+
* resolverClient.default('list pets', 'function') // 'listPets'
|
|
1939
|
+
* resolverClient.resolveClassName('pet') // 'Pet'
|
|
1940
|
+
* resolverClient.resolveGroupName('pet') // 'PetClient'
|
|
1941
|
+
* resolverClient.resolveUrlName(operationNode) // 'getShowPetByIdUrl'
|
|
1942
|
+
* ```
|
|
1649
1943
|
*/
|
|
1650
|
-
const resolverClient = (0, _kubb_core.defineResolver)((
|
|
1944
|
+
const resolverClient = (0, _kubb_core.defineResolver)(() => ({
|
|
1651
1945
|
name: "default",
|
|
1652
1946
|
pluginName: "plugin-client",
|
|
1653
1947
|
default(name, type) {
|
|
1654
|
-
|
|
1948
|
+
if (type === "file") return toFilePath(name);
|
|
1949
|
+
return ensureValidVarName(camelCase(name));
|
|
1655
1950
|
},
|
|
1656
1951
|
resolveName(name) {
|
|
1657
|
-
return
|
|
1952
|
+
return this.default(name, "function");
|
|
1953
|
+
},
|
|
1954
|
+
resolvePathName(name, type) {
|
|
1955
|
+
return this.default(name, type);
|
|
1956
|
+
},
|
|
1957
|
+
resolveClassName(name) {
|
|
1958
|
+
return ensureValidVarName(pascalCase(name));
|
|
1959
|
+
},
|
|
1960
|
+
resolveGroupName(name) {
|
|
1961
|
+
return ensureValidVarName(pascalCase(`${name} Client`));
|
|
1962
|
+
},
|
|
1963
|
+
resolveClientPropertyName(name) {
|
|
1964
|
+
return ensureValidVarName(camelCase(name));
|
|
1965
|
+
},
|
|
1966
|
+
resolveUrlName(node) {
|
|
1967
|
+
const name = this.resolveName(node.operationId);
|
|
1968
|
+
return `get${name.charAt(0).toUpperCase()}${name.slice(1)}Url`;
|
|
1658
1969
|
}
|
|
1659
1970
|
}));
|
|
1660
1971
|
//#endregion
|
|
1661
1972
|
//#region src/plugin.ts
|
|
1662
1973
|
/**
|
|
1663
|
-
* Canonical plugin name for `@kubb/plugin-client
|
|
1974
|
+
* Canonical plugin name for `@kubb/plugin-client`. Used for driver lookups and
|
|
1975
|
+
* cross-plugin dependency references.
|
|
1664
1976
|
*/
|
|
1665
1977
|
const pluginClientName = "plugin-client";
|
|
1666
1978
|
/**
|
|
1667
|
-
* Generates
|
|
1668
|
-
*
|
|
1669
|
-
*
|
|
1979
|
+
* Generates one HTTP client function per OpenAPI operation. Each function has
|
|
1980
|
+
* typed path params, query params, body, and response, so callers use the API
|
|
1981
|
+
* like any other typed function. Ships with `axios` and `fetch` runtimes; bring
|
|
1982
|
+
* your own by setting `importPath`.
|
|
1670
1983
|
*
|
|
1671
|
-
* @example
|
|
1984
|
+
* @example
|
|
1672
1985
|
* ```ts
|
|
1673
|
-
* import
|
|
1986
|
+
* import { defineConfig } from 'kubb'
|
|
1987
|
+
* import { pluginTs } from '@kubb/plugin-ts'
|
|
1988
|
+
* import { pluginClient } from '@kubb/plugin-client'
|
|
1989
|
+
*
|
|
1674
1990
|
* export default defineConfig({
|
|
1675
|
-
*
|
|
1991
|
+
* input: { path: './petStore.yaml' },
|
|
1992
|
+
* output: { path: './src/gen' },
|
|
1993
|
+
* plugins: [
|
|
1994
|
+
* pluginTs(),
|
|
1995
|
+
* pluginClient({
|
|
1996
|
+
* output: { path: './clients' },
|
|
1997
|
+
* client: 'fetch',
|
|
1998
|
+
* }),
|
|
1999
|
+
* ],
|
|
1676
2000
|
* })
|
|
1677
2001
|
* ```
|
|
1678
2002
|
*/
|
|
1679
2003
|
const pluginClient = (0, _kubb_core.definePlugin)((options) => {
|
|
1680
2004
|
const { output = {
|
|
1681
2005
|
path: "clients",
|
|
1682
|
-
|
|
1683
|
-
}, group, exclude = [], include, override = [], urlType = false, dataReturnType = "data", paramsType = "inline", pathParamsType = paramsType === "object" ? "object" : options.pathParamsType || "inline", operations = false, paramsCasing, clientType = options.sdk ? "class" : "function", parser =
|
|
2006
|
+
barrel: { type: "named" }
|
|
2007
|
+
}, group, exclude = [], include, override = [], urlType = false, dataReturnType = "data", paramsType = "inline", pathParamsType = paramsType === "object" ? "object" : options.pathParamsType || "inline", operations = false, paramsCasing, clientType = options.sdk ? "class" : "function", parser = false, client = "axios", importPath, bundle = false, sdk, baseURL, resolver: userResolver, transformer: userTransformer } = options;
|
|
1684
2008
|
const resolvedImportPath = importPath ?? (!bundle ? `@kubb/plugin-client/clients/${client}` : void 0);
|
|
1685
2009
|
const selectedGenerators = options.generators ?? [
|
|
1686
2010
|
clientType === "staticClass" ? staticClassClientGenerator : clientType === "class" ? classClientGenerator : clientGenerator,
|
|
1687
|
-
group && clientType === "function" ? groupedClientGenerator :
|
|
1688
|
-
operations ? operationsGenerator :
|
|
2011
|
+
group && clientType === "function" ? groupedClientGenerator : null,
|
|
2012
|
+
operations ? operationsGenerator : null
|
|
1689
2013
|
].filter((x) => Boolean(x));
|
|
1690
|
-
const groupConfig = group
|
|
1691
|
-
...group,
|
|
1692
|
-
name: group.name ? group.name : (ctx) => {
|
|
1693
|
-
if (group.type === "path") return `${ctx.group.split("/")[1]}`;
|
|
1694
|
-
return `${camelCase(ctx.group)}Controller`;
|
|
1695
|
-
}
|
|
1696
|
-
} : void 0;
|
|
2014
|
+
const groupConfig = createGroupConfig(group);
|
|
1697
2015
|
return {
|
|
1698
2016
|
name: pluginClientName,
|
|
1699
2017
|
options,
|
|
1700
|
-
dependencies: [_kubb_plugin_ts.pluginTsName, parser
|
|
2018
|
+
dependencies: [_kubb_plugin_ts.pluginTsName, isParserEnabled(parser) ? _kubb_plugin_zod.pluginZodName : null].filter((dependency) => Boolean(dependency)),
|
|
1701
2019
|
hooks: { "kubb:plugin:setup"(ctx) {
|
|
1702
2020
|
const resolver = userResolver ? {
|
|
1703
2021
|
...resolverClient,
|
|
@@ -1760,9 +2078,13 @@ exports.classClientGenerator = classClientGenerator;
|
|
|
1760
2078
|
exports.clientGenerator = clientGenerator;
|
|
1761
2079
|
exports.default = pluginClient;
|
|
1762
2080
|
exports.groupedClientGenerator = groupedClientGenerator;
|
|
2081
|
+
exports.isParserEnabled = isParserEnabled;
|
|
1763
2082
|
exports.operationsGenerator = operationsGenerator;
|
|
1764
2083
|
exports.pluginClient = pluginClient;
|
|
1765
2084
|
exports.pluginClientName = pluginClientName;
|
|
2085
|
+
exports.resolveQueryParamsParser = resolveQueryParamsParser;
|
|
2086
|
+
exports.resolveRequestParser = resolveRequestParser;
|
|
2087
|
+
exports.resolveResponseParser = resolveResponseParser;
|
|
1766
2088
|
exports.resolverClient = resolverClient;
|
|
1767
2089
|
exports.staticClassClientGenerator = staticClassClientGenerator;
|
|
1768
2090
|
|