@kubb/plugin-client 5.0.0-alpha.3 → 5.0.0-alpha.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/clients/axios.d.ts +2 -2
  2. package/dist/index.cjs +1893 -74
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.ts +480 -4
  5. package/dist/index.js +1885 -77
  6. package/dist/index.js.map +1 -1
  7. package/package.json +10 -25
  8. package/src/components/ClassClient.tsx +42 -138
  9. package/src/components/Client.tsx +85 -124
  10. package/src/components/ClientLegacy.tsx +501 -0
  11. package/src/components/Operations.tsx +8 -8
  12. package/src/components/StaticClassClient.tsx +41 -135
  13. package/src/components/Url.tsx +37 -46
  14. package/src/generators/classClientGenerator.tsx +125 -148
  15. package/src/generators/clientGenerator.tsx +93 -82
  16. package/src/generators/groupedClientGenerator.tsx +47 -50
  17. package/src/generators/operationsGenerator.tsx +9 -17
  18. package/src/generators/staticClassClientGenerator.tsx +159 -164
  19. package/src/index.ts +11 -1
  20. package/src/plugin.ts +115 -108
  21. package/src/presets.ts +25 -0
  22. package/src/resolvers/resolverClient.ts +26 -0
  23. package/src/resolvers/resolverClientLegacy.ts +26 -0
  24. package/src/types.ts +105 -40
  25. package/src/utils.ts +148 -0
  26. package/dist/StaticClassClient-By-aMAe4.cjs +0 -677
  27. package/dist/StaticClassClient-By-aMAe4.cjs.map +0 -1
  28. package/dist/StaticClassClient-CCn9g9eF.js +0 -636
  29. package/dist/StaticClassClient-CCn9g9eF.js.map +0 -1
  30. package/dist/components.cjs +0 -7
  31. package/dist/components.d.ts +0 -216
  32. package/dist/components.js +0 -2
  33. package/dist/generators-C2jT7XCH.js +0 -723
  34. package/dist/generators-C2jT7XCH.js.map +0 -1
  35. package/dist/generators-qkDW17Hf.cjs +0 -753
  36. package/dist/generators-qkDW17Hf.cjs.map +0 -1
  37. package/dist/generators.cjs +0 -7
  38. package/dist/generators.d.ts +0 -512
  39. package/dist/generators.js +0 -2
  40. package/dist/types-CdM4DK1M.d.ts +0 -169
  41. package/src/components/index.ts +0 -5
  42. package/src/generators/index.ts +0 -5
package/dist/index.js CHANGED
@@ -1,79 +1,1910 @@
1
- import "./chunk--u3MIqq1.js";
2
- import { o as camelCase } from "./StaticClassClient-CCn9g9eF.js";
3
- import { a as classClientGenerator, i as clientGenerator, n as operationsGenerator, r as groupedClientGenerator, t as staticClassClientGenerator } from "./generators-C2jT7XCH.js";
1
+ import { t as __name } from "./chunk--u3MIqq1.js";
4
2
  import { source } from "./templates/clients/axios.source.js";
5
3
  import { source as source$1 } from "./templates/clients/fetch.source.js";
6
4
  import { source as source$2 } from "./templates/config.source.js";
7
5
  import path from "node:path";
8
- import { definePlugin, getBarrelFiles, getMode } from "@kubb/core";
9
- import { OperationGenerator, pluginOasName } from "@kubb/plugin-oas";
6
+ import { caseParams, createFunctionParameter, createOperationParams, createTypeNode } from "@kubb/ast";
7
+ import { functionPrinter, pluginTsName } from "@kubb/plugin-ts";
8
+ import { Const, File, Function as Function$1, FunctionParams } from "@kubb/react-fabric";
9
+ import { Fragment, jsx, jsxs } from "@kubb/react-fabric/jsx-runtime";
10
+ import { createPlugin, defineGenerator, definePresets, defineResolver, getPreset, mergeGenerators } from "@kubb/core";
10
11
  import { pluginZodName } from "@kubb/plugin-zod";
12
+ //#region ../../internals/utils/src/casing.ts
13
+ /**
14
+ * Shared implementation for camelCase and PascalCase conversion.
15
+ * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)
16
+ * and capitalizes each word according to `pascal`.
17
+ *
18
+ * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
19
+ */
20
+ function toCamelOrPascal(text, pascal) {
21
+ 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) => {
22
+ if (word.length > 1 && word === word.toUpperCase()) return word;
23
+ if (i === 0 && !pascal) return word.charAt(0).toLowerCase() + word.slice(1);
24
+ return word.charAt(0).toUpperCase() + word.slice(1);
25
+ }).join("").replace(/[^a-zA-Z0-9]/g, "");
26
+ }
27
+ /**
28
+ * Splits `text` on `.` and applies `transformPart` to each segment.
29
+ * The last segment receives `isLast = true`, all earlier segments receive `false`.
30
+ * Segments are joined with `/` to form a file path.
31
+ *
32
+ * Only splits on dots followed by a letter so that version numbers
33
+ * embedded in operationIds (e.g. `v2025.0`) are kept intact.
34
+ */
35
+ function applyToFileParts(text, transformPart) {
36
+ const parts = text.split(/\.(?=[a-zA-Z])/);
37
+ return parts.map((part, i) => transformPart(part, i === parts.length - 1)).join("/");
38
+ }
39
+ /**
40
+ * Converts `text` to camelCase.
41
+ * When `isFile` is `true`, dot-separated segments are each cased independently and joined with `/`.
42
+ *
43
+ * @example
44
+ * camelCase('hello-world') // 'helloWorld'
45
+ * camelCase('pet.petId', { isFile: true }) // 'pet/petId'
46
+ */
47
+ function camelCase(text, { isFile, prefix = "", suffix = "" } = {}) {
48
+ if (isFile) return applyToFileParts(text, (part, isLast) => camelCase(part, isLast ? {
49
+ prefix,
50
+ suffix
51
+ } : {}));
52
+ return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
53
+ }
54
+ /**
55
+ * Converts `text` to PascalCase.
56
+ * When `isFile` is `true`, the last dot-separated segment is PascalCased and earlier segments are camelCased.
57
+ *
58
+ * @example
59
+ * pascalCase('hello-world') // 'HelloWorld'
60
+ * pascalCase('pet.petId', { isFile: true }) // 'pet/PetId'
61
+ */
62
+ function pascalCase(text, { isFile, prefix = "", suffix = "" } = {}) {
63
+ if (isFile) return applyToFileParts(text, (part, isLast) => isLast ? pascalCase(part, {
64
+ prefix,
65
+ suffix
66
+ }) : camelCase(part));
67
+ return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true);
68
+ }
69
+ //#endregion
70
+ //#region ../../internals/utils/src/jsdoc.ts
71
+ /**
72
+ * Builds a JSDoc comment block from an array of lines.
73
+ * Returns `fallback` when `comments` is empty so callers always get a usable string.
74
+ *
75
+ * @example
76
+ * ```ts
77
+ * buildJSDoc(['@type string', '@example hello'])
78
+ * // '/**\n * @type string\n * @example hello\n *\/\n '
79
+ * ```
80
+ */
81
+ function buildJSDoc(comments, options = {}) {
82
+ const { indent = " * ", suffix = "\n ", fallback = " " } = options;
83
+ if (comments.length === 0) return fallback;
84
+ return `/**\n${comments.map((c) => `${indent}${c}`).join("\n")}\n */${suffix}`;
85
+ }
86
+ //#endregion
87
+ //#region ../../internals/utils/src/reserved.ts
88
+ /**
89
+ * Returns `true` when `name` is a syntactically valid JavaScript variable name.
90
+ *
91
+ * @example
92
+ * ```ts
93
+ * isValidVarName('status') // true
94
+ * isValidVarName('class') // false (reserved word)
95
+ * isValidVarName('42foo') // false (starts with digit)
96
+ * ```
97
+ */
98
+ function isValidVarName(name) {
99
+ try {
100
+ new Function(`var ${name}`);
101
+ } catch {
102
+ return false;
103
+ }
104
+ return true;
105
+ }
106
+ //#endregion
107
+ //#region ../../internals/utils/src/urlPath.ts
108
+ /**
109
+ * Parses and transforms an OpenAPI/Swagger path string into various URL formats.
110
+ *
111
+ * @example
112
+ * const p = new URLPath('/pet/{petId}')
113
+ * p.URL // '/pet/:petId'
114
+ * p.template // '`/pet/${petId}`'
115
+ */
116
+ var URLPath = class {
117
+ /**
118
+ * The raw OpenAPI/Swagger path string, e.g. `/pet/{petId}`.
119
+ */
120
+ path;
121
+ #options;
122
+ constructor(path, options = {}) {
123
+ this.path = path;
124
+ this.#options = options;
125
+ }
126
+ /** Converts the OpenAPI path to Express-style colon syntax, e.g. `/pet/{petId}` → `/pet/:petId`.
127
+ *
128
+ * @example
129
+ * ```ts
130
+ * new URLPath('/pet/{petId}').URL // '/pet/:petId'
131
+ * ```
132
+ */
133
+ get URL() {
134
+ return this.toURLPath();
135
+ }
136
+ /** Returns `true` when `path` is a fully-qualified URL (e.g. starts with `https://`).
137
+ *
138
+ * @example
139
+ * ```ts
140
+ * new URLPath('https://petstore.swagger.io/v2/pet').isURL // true
141
+ * new URLPath('/pet/{petId}').isURL // false
142
+ * ```
143
+ */
144
+ get isURL() {
145
+ try {
146
+ return !!new URL(this.path).href;
147
+ } catch {
148
+ return false;
149
+ }
150
+ }
151
+ /**
152
+ * Converts the OpenAPI path to a TypeScript template literal string.
153
+ *
154
+ * @example
155
+ * new URLPath('/pet/{petId}').template // '`/pet/${petId}`'
156
+ * new URLPath('/account/monetary-accountID').template // '`/account/${monetaryAccountId}`'
157
+ */
158
+ get template() {
159
+ return this.toTemplateString();
160
+ }
161
+ /** Returns the path and its extracted params as a structured `URLObject`, or as a stringified expression when `stringify` is set.
162
+ *
163
+ * @example
164
+ * ```ts
165
+ * new URLPath('/pet/{petId}').object
166
+ * // { url: '/pet/:petId', params: { petId: 'petId' } }
167
+ * ```
168
+ */
169
+ get object() {
170
+ return this.toObject();
171
+ }
172
+ /** Returns a map of path parameter names, or `undefined` when the path has no parameters.
173
+ *
174
+ * @example
175
+ * ```ts
176
+ * new URLPath('/pet/{petId}').params // { petId: 'petId' }
177
+ * new URLPath('/pet').params // undefined
178
+ * ```
179
+ */
180
+ get params() {
181
+ return this.getParams();
182
+ }
183
+ #transformParam(raw) {
184
+ const param = isValidVarName(raw) ? raw : camelCase(raw);
185
+ return this.#options.casing === "camelcase" ? camelCase(param) : param;
186
+ }
187
+ /**
188
+ * Iterates over every `{param}` token in `path`, calling `fn` with the raw token and transformed name.
189
+ */
190
+ #eachParam(fn) {
191
+ for (const match of this.path.matchAll(/\{([^}]+)\}/g)) {
192
+ const raw = match[1];
193
+ fn(raw, this.#transformParam(raw));
194
+ }
195
+ }
196
+ toObject({ type = "path", replacer, stringify } = {}) {
197
+ const object = {
198
+ url: type === "path" ? this.toURLPath() : this.toTemplateString({ replacer }),
199
+ params: this.getParams()
200
+ };
201
+ if (stringify) {
202
+ if (type === "template") return JSON.stringify(object).replaceAll("'", "").replaceAll(`"`, "");
203
+ if (object.params) return `{ url: '${object.url}', params: ${JSON.stringify(object.params).replaceAll("'", "").replaceAll(`"`, "")} }`;
204
+ return `{ url: '${object.url}' }`;
205
+ }
206
+ return object;
207
+ }
208
+ /**
209
+ * Converts the OpenAPI path to a TypeScript template literal string.
210
+ * An optional `replacer` can transform each extracted parameter name before interpolation.
211
+ *
212
+ * @example
213
+ * new URLPath('/pet/{petId}').toTemplateString() // '`/pet/${petId}`'
214
+ */
215
+ toTemplateString({ prefix = "", replacer } = {}) {
216
+ return `\`${prefix}${this.path.split(/\{([^}]+)\}/).map((part, i) => {
217
+ if (i % 2 === 0) return part;
218
+ const param = this.#transformParam(part);
219
+ return `\${${replacer ? replacer(param) : param}}`;
220
+ }).join("")}\``;
221
+ }
222
+ /**
223
+ * Extracts all `{param}` segments from the path and returns them as a key-value map.
224
+ * An optional `replacer` transforms each parameter name in both key and value positions.
225
+ * Returns `undefined` when no path parameters are found.
226
+ *
227
+ * @example
228
+ * ```ts
229
+ * new URLPath('/pet/{petId}/tag/{tagId}').getParams()
230
+ * // { petId: 'petId', tagId: 'tagId' }
231
+ * ```
232
+ */
233
+ getParams(replacer) {
234
+ const params = {};
235
+ this.#eachParam((_raw, param) => {
236
+ const key = replacer ? replacer(param) : param;
237
+ params[key] = key;
238
+ });
239
+ return Object.keys(params).length > 0 ? params : void 0;
240
+ }
241
+ /** Converts the OpenAPI path to Express-style colon syntax.
242
+ *
243
+ * @example
244
+ * ```ts
245
+ * new URLPath('/pet/{petId}').toURLPath() // '/pet/:petId'
246
+ * ```
247
+ */
248
+ toURLPath() {
249
+ return this.path.replace(/\{([^}]+)\}/g, ":$1");
250
+ }
251
+ };
252
+ //#endregion
253
+ //#region src/utils.ts
254
+ function getComments(node) {
255
+ return [
256
+ node.description && `@description ${node.description}`,
257
+ node.summary && `@summary ${node.summary}`,
258
+ node.path && `{@link ${new URLPath(node.path).URL}}`,
259
+ node.deprecated && "@deprecated"
260
+ ].filter((x) => Boolean(x)).flatMap((text) => text.split(/\r?\n/).map((line) => line.trim())).filter((x) => Boolean(x));
261
+ }
262
+ function buildParamsMapping(originalParams, casedParams) {
263
+ const mapping = {};
264
+ let hasChanged = false;
265
+ originalParams.forEach((param, i) => {
266
+ const casedName = casedParams[i]?.name ?? param.name;
267
+ mapping[param.name] = casedName;
268
+ if (param.name !== casedName) hasChanged = true;
269
+ });
270
+ return hasChanged ? mapping : void 0;
271
+ }
272
+ function buildHeaders(contentType, hasHeaderParams) {
273
+ return [contentType !== "application/json" && contentType !== "multipart/form-data" ? `'Content-Type': '${contentType}'` : void 0, hasHeaderParams ? "...headers" : void 0].filter(Boolean);
274
+ }
275
+ function buildGenerics(node, tsResolver) {
276
+ const responseName = tsResolver.resolveResponseName(node);
277
+ const requestName = node.requestBody?.schema ? tsResolver.resolveDataName(node) : void 0;
278
+ const errorNames = node.responses.filter((r) => Number.parseInt(r.statusCode, 10) >= 400).map((r) => tsResolver.resolveResponseStatusName(node, r.statusCode));
279
+ return [
280
+ responseName,
281
+ `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(" | ") : "Error"}>`,
282
+ requestName || "unknown"
283
+ ].filter(Boolean);
284
+ }
285
+ function buildClassClientParams({ node, path, baseURL, tsResolver, isFormData, headers }) {
286
+ const queryParamsName = node.parameters.filter((p) => p.in === "query").length > 0 ? tsResolver.resolveQueryParamsName(node, node.parameters.filter((p) => p.in === "query")[0]) : void 0;
287
+ const requestName = node.requestBody?.schema ? tsResolver.resolveDataName(node) : void 0;
288
+ return FunctionParams.factory({ config: {
289
+ mode: "object",
290
+ children: {
291
+ requestConfig: { mode: "inlineSpread" },
292
+ method: { value: JSON.stringify(node.method.toUpperCase()) },
293
+ url: { value: path.template },
294
+ baseURL: baseURL ? { value: JSON.stringify(baseURL) } : void 0,
295
+ params: queryParamsName ? {} : void 0,
296
+ data: requestName ? { value: isFormData ? "formData as FormData" : "requestData" } : void 0,
297
+ headers: headers.length ? { value: `{ ${headers.join(", ")}, ...requestConfig.headers }` } : void 0
298
+ }
299
+ } });
300
+ }
301
+ function buildRequestDataLine({ parser, node, zodResolver }) {
302
+ const zodRequestName = zodResolver && parser === "zod" && node.requestBody?.schema ? zodResolver.resolveDataName?.(node) : void 0;
303
+ if (parser === "zod" && zodRequestName) return `const requestData = ${zodRequestName}.parse(data)`;
304
+ if (node.requestBody?.schema) return "const requestData = data";
305
+ return "";
306
+ }
307
+ function buildFormDataLine(isFormData, hasRequest) {
308
+ return isFormData && hasRequest ? "const formData = buildFormData(requestData)" : "";
309
+ }
310
+ function buildReturnStatement({ dataReturnType, parser, node, zodResolver }) {
311
+ const zodResponseName = zodResolver && parser === "zod" ? zodResolver.resolveResponseName?.(node) : void 0;
312
+ if (dataReturnType === "full" && parser === "zod" && zodResponseName) return `return {...res, data: ${zodResponseName}.parse(res.data)}`;
313
+ if (dataReturnType === "data" && parser === "zod" && zodResponseName) return `return ${zodResponseName}.parse(res.data)`;
314
+ if (dataReturnType === "full" && parser === "client") return "return res";
315
+ return "return res.data";
316
+ }
317
+ //#endregion
318
+ //#region src/components/Url.tsx
319
+ const declarationPrinter$3 = functionPrinter({ mode: "declaration" });
320
+ function getParams$2({ paramsType, paramsCasing, pathParamsType, node, tsResolver }) {
321
+ return createOperationParams({
322
+ ...node,
323
+ parameters: node.parameters.filter((p) => p.in === "path"),
324
+ requestBody: void 0
325
+ }, {
326
+ paramsType: paramsType === "object" ? "object" : "inline",
327
+ pathParamsType: paramsType === "object" ? "object" : pathParamsType === "object" ? "object" : "inline",
328
+ paramsCasing,
329
+ resolver: tsResolver
330
+ });
331
+ }
332
+ __name(getParams$2, "getParams");
333
+ function Url({ name, isExportable = true, isIndexable = true, baseURL, paramsType, paramsCasing, pathParamsType, node, tsResolver }) {
334
+ const path = new URLPath(node.path);
335
+ const paramsNode = getParams$2({
336
+ paramsType,
337
+ paramsCasing,
338
+ pathParamsType,
339
+ node,
340
+ tsResolver
341
+ });
342
+ const paramsSignature = declarationPrinter$3.print(paramsNode) ?? "";
343
+ const originalPathParams = node.parameters.filter((p) => p.in === "path");
344
+ const casedPathParams = caseParams(originalPathParams, paramsCasing);
345
+ const pathParamsMapping = paramsCasing ? buildParamsMapping(originalPathParams, casedPathParams) : void 0;
346
+ return /* @__PURE__ */ jsx(File.Source, {
347
+ name,
348
+ isExportable,
349
+ isIndexable,
350
+ children: /* @__PURE__ */ jsxs(Function$1, {
351
+ name,
352
+ export: isExportable,
353
+ params: paramsSignature,
354
+ children: [
355
+ pathParamsMapping && Object.entries(pathParamsMapping).filter(([originalName, camelCaseName]) => isValidVarName(originalName) && originalName !== camelCaseName).map(([originalName, camelCaseName]) => `const ${originalName} = ${camelCaseName}`).join("\n"),
356
+ pathParamsMapping && Object.keys(pathParamsMapping).length > 0 && /* @__PURE__ */ jsx("br", {}),
357
+ /* @__PURE__ */ jsx(Const, {
358
+ name: "res",
359
+ children: `{ method: '${node.method.toUpperCase()}', url: ${path.toTemplateString({ prefix: baseURL })} as const }`
360
+ }),
361
+ /* @__PURE__ */ jsx("br", {}),
362
+ "return res"
363
+ ]
364
+ })
365
+ });
366
+ }
367
+ Url.getParams = getParams$2;
368
+ //#endregion
369
+ //#region src/components/Client.tsx
370
+ const declarationPrinter$2 = functionPrinter({ mode: "declaration" });
371
+ function getParams$1({ paramsType, paramsCasing, pathParamsType, node, tsResolver, isConfigurable }) {
372
+ const requestName = node.requestBody?.schema ? tsResolver.resolveDataName(node) : void 0;
373
+ return createOperationParams(node, {
374
+ paramsType,
375
+ pathParamsType: paramsType === "object" ? "object" : pathParamsType === "object" ? "object" : "inline",
376
+ paramsCasing,
377
+ resolver: tsResolver,
378
+ extraParams: isConfigurable ? [createFunctionParameter({
379
+ name: "config",
380
+ type: createTypeNode({
381
+ variant: "reference",
382
+ name: requestName ? `Partial<RequestConfig<${requestName}>> & { client?: Client }` : "Partial<RequestConfig> & { client?: Client }"
383
+ }),
384
+ default: "{}"
385
+ })] : []
386
+ });
387
+ }
388
+ __name(getParams$1, "getParams");
389
+ function Client({ name, isExportable = true, isIndexable = true, returnType, baseURL, dataReturnType, parser, paramsType, paramsCasing, pathParamsType, node, tsResolver, zodResolver, urlName, children, isConfigurable = true }) {
390
+ const path = new URLPath(node.path);
391
+ const contentType = node.requestBody?.contentType ?? "application/json";
392
+ const isFormData = contentType === "multipart/form-data";
393
+ const originalPathParams = node.parameters.filter((p) => p.in === "path");
394
+ const casedPathParams = caseParams(originalPathParams, paramsCasing);
395
+ const originalQueryParams = node.parameters.filter((p) => p.in === "query");
396
+ const casedQueryParams = caseParams(originalQueryParams, paramsCasing);
397
+ const originalHeaderParams = node.parameters.filter((p) => p.in === "header");
398
+ const casedHeaderParams = caseParams(originalHeaderParams, paramsCasing);
399
+ const pathParamsMapping = paramsCasing && !urlName ? buildParamsMapping(originalPathParams, casedPathParams) : void 0;
400
+ const queryParamsMapping = paramsCasing ? buildParamsMapping(originalQueryParams, casedQueryParams) : void 0;
401
+ const headerParamsMapping = paramsCasing ? buildParamsMapping(originalHeaderParams, casedHeaderParams) : void 0;
402
+ const requestName = node.requestBody?.schema ? tsResolver.resolveDataName(node) : void 0;
403
+ const responseName = tsResolver.resolveResponseName(node);
404
+ const queryParamsName = originalQueryParams.length > 0 ? tsResolver.resolveQueryParamsName(node, originalQueryParams[0]) : void 0;
405
+ const headerParamsName = originalHeaderParams.length > 0 ? tsResolver.resolveHeaderParamsName(node, originalHeaderParams[0]) : void 0;
406
+ const zodResponseName = zodResolver && parser === "zod" ? zodResolver.resolveResponseName?.(node) : void 0;
407
+ const zodRequestName = zodResolver && parser === "zod" && node.requestBody?.schema ? zodResolver.resolveDataName?.(node) : void 0;
408
+ const errorNames = node.responses.filter((r) => {
409
+ return Number.parseInt(r.statusCode, 10) >= 400;
410
+ }).map((r) => tsResolver.resolveResponseStatusName(node, r.statusCode));
411
+ const headers = [contentType !== "application/json" && contentType !== "multipart/form-data" ? `'Content-Type': '${contentType}'` : void 0, headerParamsName ? headerParamsMapping ? "...mappedHeaders" : "...headers" : void 0].filter(Boolean);
412
+ const generics = [
413
+ responseName,
414
+ `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(" | ") : "Error"}>`,
415
+ requestName || "unknown"
416
+ ].filter(Boolean);
417
+ const paramsNode = getParams$1({
418
+ paramsType,
419
+ paramsCasing,
420
+ pathParamsType,
421
+ node,
422
+ tsResolver,
423
+ isConfigurable
424
+ });
425
+ const paramsSignature = declarationPrinter$2.print(paramsNode) ?? "";
426
+ const urlParamsNode = Url.getParams({
427
+ paramsType,
428
+ paramsCasing,
429
+ pathParamsType,
430
+ node,
431
+ tsResolver
432
+ });
433
+ const urlParamsCall = functionPrinter({ mode: "call" }).print(urlParamsNode) ?? "";
434
+ const clientParams = FunctionParams.factory({ config: {
435
+ mode: "object",
436
+ children: {
437
+ method: { value: JSON.stringify(node.method.toUpperCase()) },
438
+ url: { value: urlName ? `${urlName}(${urlParamsCall}).url.toString()` : path.template },
439
+ baseURL: baseURL && !urlName ? { value: `\`${baseURL}\`` } : void 0,
440
+ params: queryParamsName ? queryParamsMapping ? { value: "mappedParams" } : {} : void 0,
441
+ data: requestName ? { value: isFormData ? "formData as FormData" : "requestData" } : void 0,
442
+ requestConfig: isConfigurable ? { mode: "inlineSpread" } : void 0,
443
+ headers: headers.length ? { value: isConfigurable ? `{ ${headers.join(", ")}, ...requestConfig.headers }` : `{ ${headers.join(", ")} }` } : void 0
444
+ }
445
+ } });
446
+ const childrenElement = children ? children : /* @__PURE__ */ jsxs(Fragment, { children: [
447
+ dataReturnType === "full" && parser === "zod" && zodResponseName && `return {...res, data: ${zodResponseName}.parse(res.data)}`,
448
+ dataReturnType === "data" && parser === "zod" && zodResponseName && `return ${zodResponseName}.parse(res.data)`,
449
+ dataReturnType === "full" && parser === "client" && "return res",
450
+ dataReturnType === "data" && parser === "client" && "return res.data"
451
+ ] });
452
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("br", {}), /* @__PURE__ */ jsx(File.Source, {
453
+ name,
454
+ isExportable,
455
+ isIndexable,
456
+ children: /* @__PURE__ */ jsxs(Function$1, {
457
+ name,
458
+ async: true,
459
+ export: isExportable,
460
+ params: paramsSignature,
461
+ JSDoc: { comments: getComments(node) },
462
+ returnType,
463
+ children: [
464
+ isConfigurable ? "const { client: request = fetch, ...requestConfig } = config" : "",
465
+ /* @__PURE__ */ jsx("br", {}),
466
+ /* @__PURE__ */ jsx("br", {}),
467
+ pathParamsMapping && Object.entries(pathParamsMapping).filter(([originalName, camelCaseName]) => isValidVarName(originalName) && originalName !== camelCaseName).map(([originalName, camelCaseName]) => `const ${originalName} = ${camelCaseName}`).join("\n"),
468
+ pathParamsMapping && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("br", {}), /* @__PURE__ */ jsx("br", {})] }),
469
+ queryParamsMapping && queryParamsName && /* @__PURE__ */ jsxs(Fragment, { children: [
470
+ `const mappedParams = params ? { ${Object.entries(queryParamsMapping).map(([originalName, camelCaseName]) => `"${originalName}": params.${camelCaseName}`).join(", ")} } : undefined`,
471
+ /* @__PURE__ */ jsx("br", {}),
472
+ /* @__PURE__ */ jsx("br", {})
473
+ ] }),
474
+ headerParamsMapping && headerParamsName && /* @__PURE__ */ jsxs(Fragment, { children: [
475
+ `const mappedHeaders = headers ? { ${Object.entries(headerParamsMapping).map(([originalName, camelCaseName]) => `"${originalName}": headers.${camelCaseName}`).join(", ")} } : undefined`,
476
+ /* @__PURE__ */ jsx("br", {}),
477
+ /* @__PURE__ */ jsx("br", {})
478
+ ] }),
479
+ parser === "zod" && zodRequestName ? `const requestData = ${zodRequestName}.parse(data)` : requestName && "const requestData = data",
480
+ /* @__PURE__ */ jsx("br", {}),
481
+ isFormData && requestName && "const formData = buildFormData(requestData)",
482
+ /* @__PURE__ */ jsx("br", {}),
483
+ isConfigurable ? `const res = await request<${generics.join(", ")}>(${clientParams.toCall()})` : `const res = await fetch<${generics.join(", ")}>(${clientParams.toCall()})`,
484
+ /* @__PURE__ */ jsx("br", {}),
485
+ childrenElement
486
+ ]
487
+ })
488
+ })] });
489
+ }
490
+ Client.getParams = getParams$1;
491
+ //#endregion
492
+ //#region src/components/ClientLegacy.tsx
493
+ function isSchemaRequired(schema) {
494
+ if (!schema) return false;
495
+ return Array.isArray(schema.required) ? !!schema.required.length : !!schema.required;
496
+ }
497
+ function isSchemaOptional(schema) {
498
+ return !isSchemaRequired(schema);
499
+ }
500
+ function isAllOptionalDeep(schema) {
501
+ if (!schema) return true;
502
+ if (Array.isArray(schema.required) && schema.required.length > 0) return false;
503
+ if (schema.allOf) return schema.allOf.every(isAllOptionalDeep);
504
+ return true;
505
+ }
506
+ function getSchemaDefaultValue(schema) {
507
+ if (!schema || !isSchemaOptional(schema)) return void 0;
508
+ if (schema.type === "array") return "[]";
509
+ if (schema.anyOf || schema.oneOf) {
510
+ const variants = schema.anyOf || schema.oneOf;
511
+ if (!Array.isArray(variants)) return void 0;
512
+ if (variants.some(isAllOptionalDeep)) return "{}";
513
+ return;
514
+ }
515
+ if (schema.type === "object" || schema.properties) return "{}";
516
+ }
517
+ function legacyGetPathParams(operationSchema, options = {}) {
518
+ if (!operationSchema?.schema?.properties || !operationSchema.name) return {};
519
+ const requiredFields = Array.isArray(operationSchema.schema.required) ? operationSchema.schema.required : [];
520
+ return Object.entries(operationSchema.schema.properties).reduce((acc, [name]) => {
521
+ if (!name) return acc;
522
+ let paramName = name;
523
+ if (options.casing === "camelcase") paramName = camelCase(name);
524
+ else if (!isValidVarName(name)) paramName = camelCase(name);
525
+ const accessName = options.casing === "camelcase" ? camelCase(name) : name;
526
+ acc[paramName] = {
527
+ default: void 0,
528
+ type: options.typed ? `${operationSchema.name}["${accessName}"]` : void 0,
529
+ optional: !requiredFields.includes(name)
530
+ };
531
+ return acc;
532
+ }, {});
533
+ }
534
+ function legacyGetParamsMapping(operationSchema, options = {}) {
535
+ if (!operationSchema?.schema?.properties) return void 0;
536
+ const allEntries = [];
537
+ let hasTransformation = false;
538
+ Object.entries(operationSchema.schema.properties).forEach(([originalName]) => {
539
+ let transformedName = originalName;
540
+ if (options.casing === "camelcase") transformedName = camelCase(originalName);
541
+ else if (!isValidVarName(originalName)) transformedName = camelCase(originalName);
542
+ allEntries.push([originalName, transformedName]);
543
+ if (transformedName !== originalName) hasTransformation = true;
544
+ });
545
+ if (options.casing === "camelcase" && hasTransformation) return Object.fromEntries(allEntries);
546
+ const mapping = {};
547
+ allEntries.forEach(([originalName, transformedName]) => {
548
+ if (transformedName !== originalName) mapping[originalName] = transformedName;
549
+ });
550
+ return Object.keys(mapping).length > 0 ? mapping : void 0;
551
+ }
552
+ function legacyGetComments(operation) {
553
+ return [
554
+ operation.getDescription?.() && `@description ${operation.getDescription()}`,
555
+ operation.getSummary?.() && `@summary ${operation.getSummary()}`,
556
+ operation.path && `{@link ${new URLPath(operation.path).URL}}`,
557
+ operation.isDeprecated?.() && "@deprecated"
558
+ ].filter((x) => Boolean(x)).flatMap((text) => text.split(/\r?\n/).map((line) => line.trim())).filter((x) => Boolean(x));
559
+ }
560
+ function getParams({ paramsType, paramsCasing, pathParamsType, typeSchemas, isConfigurable }) {
561
+ if (paramsType === "object") {
562
+ const children = {
563
+ ...legacyGetPathParams(typeSchemas.pathParams, {
564
+ typed: true,
565
+ casing: paramsCasing
566
+ }),
567
+ data: typeSchemas.request?.name ? {
568
+ type: typeSchemas.request?.name,
569
+ optional: isSchemaOptional(typeSchemas.request?.schema)
570
+ } : void 0,
571
+ params: typeSchemas.queryParams?.name ? {
572
+ type: typeSchemas.queryParams?.name,
573
+ optional: isSchemaOptional(typeSchemas.queryParams?.schema)
574
+ } : void 0,
575
+ headers: typeSchemas.headerParams?.name ? {
576
+ type: typeSchemas.headerParams?.name,
577
+ optional: isSchemaOptional(typeSchemas.headerParams?.schema)
578
+ } : void 0
579
+ };
580
+ const allChildrenAreOptional = Object.values(children).every((child) => !child || child.optional);
581
+ return FunctionParams.factory({
582
+ data: {
583
+ mode: "object",
584
+ children,
585
+ default: allChildrenAreOptional ? "{}" : void 0
586
+ },
587
+ config: isConfigurable ? {
588
+ type: typeSchemas.request?.name ? `Partial<RequestConfig<${typeSchemas.request?.name}>> & { client?: Client }` : "Partial<RequestConfig> & { client?: Client }",
589
+ default: "{}"
590
+ } : void 0
591
+ });
592
+ }
593
+ return FunctionParams.factory({
594
+ pathParams: typeSchemas.pathParams?.name ? {
595
+ mode: pathParamsType === "object" ? "object" : "inlineSpread",
596
+ children: legacyGetPathParams(typeSchemas.pathParams, {
597
+ typed: true,
598
+ casing: paramsCasing
599
+ }),
600
+ default: getSchemaDefaultValue(typeSchemas.pathParams?.schema)
601
+ } : void 0,
602
+ data: typeSchemas.request?.name ? {
603
+ type: typeSchemas.request?.name,
604
+ optional: isSchemaOptional(typeSchemas.request?.schema)
605
+ } : void 0,
606
+ params: typeSchemas.queryParams?.name ? {
607
+ type: typeSchemas.queryParams?.name,
608
+ optional: isSchemaOptional(typeSchemas.queryParams?.schema)
609
+ } : void 0,
610
+ headers: typeSchemas.headerParams?.name ? {
611
+ type: typeSchemas.headerParams?.name,
612
+ optional: isSchemaOptional(typeSchemas.headerParams?.schema)
613
+ } : void 0,
614
+ config: isConfigurable ? {
615
+ type: typeSchemas.request?.name ? `Partial<RequestConfig<${typeSchemas.request?.name}>> & { client?: Client }` : "Partial<RequestConfig> & { client?: Client }",
616
+ default: "{}"
617
+ } : void 0
618
+ });
619
+ }
620
+ function ClientLegacy({ name, isExportable = true, isIndexable = true, returnType, typeSchemas, baseURL, dataReturnType, parser, zodSchemas, paramsType, paramsCasing, pathParamsType, operation, urlName, children, isConfigurable = true }) {
621
+ const path = new URLPath(operation.path);
622
+ const contentType = operation.getContentType?.() ?? "application/json";
623
+ const isFormData = contentType === "multipart/form-data";
624
+ const pathParamsMapping = paramsCasing && !urlName ? legacyGetParamsMapping(typeSchemas.pathParams, { casing: paramsCasing }) : void 0;
625
+ const queryParamsMapping = paramsCasing ? legacyGetParamsMapping(typeSchemas.queryParams, { casing: paramsCasing }) : void 0;
626
+ const headerParamsMapping = paramsCasing ? legacyGetParamsMapping(typeSchemas.headerParams, { casing: paramsCasing }) : void 0;
627
+ const headers = [contentType !== "application/json" && contentType !== "multipart/form-data" ? `'Content-Type': '${contentType}'` : void 0, typeSchemas.headerParams?.name ? headerParamsMapping ? "...mappedHeaders" : "...headers" : void 0].filter(Boolean);
628
+ const TError = `ResponseErrorConfig<${typeSchemas.errors?.map((item) => item.name).join(" | ") || "Error"}>`;
629
+ const generics = [
630
+ typeSchemas.response.name,
631
+ TError,
632
+ typeSchemas.request?.name || "unknown"
633
+ ].filter(Boolean);
634
+ const params = getParams({
635
+ paramsType,
636
+ paramsCasing,
637
+ pathParamsType,
638
+ typeSchemas,
639
+ isConfigurable
640
+ });
641
+ const urlParams = UrlLegacy.getParams({
642
+ paramsType,
643
+ paramsCasing,
644
+ pathParamsType,
645
+ typeSchemas
646
+ });
647
+ const clientParams = FunctionParams.factory({ config: {
648
+ mode: "object",
649
+ children: {
650
+ method: { value: JSON.stringify(operation.method.toUpperCase()) },
651
+ url: { value: urlName ? `${urlName}(${urlParams.toCall()}).url.toString()` : path.template },
652
+ baseURL: baseURL && !urlName ? { value: `\`${baseURL}\`` } : void 0,
653
+ params: typeSchemas.queryParams?.name ? queryParamsMapping ? { value: "mappedParams" } : {} : void 0,
654
+ data: typeSchemas.request?.name ? { value: isFormData ? "formData as FormData" : "requestData" } : void 0,
655
+ requestConfig: isConfigurable ? { mode: "inlineSpread" } : void 0,
656
+ headers: headers.length ? { value: isConfigurable ? `{ ${headers.join(", ")}, ...requestConfig.headers }` : `{ ${headers.join(", ")} }` } : void 0
657
+ }
658
+ } });
659
+ const childrenElement = children ? children : /* @__PURE__ */ jsxs(Fragment, { children: [
660
+ dataReturnType === "full" && parser === "zod" && zodSchemas && `return {...res, data: ${zodSchemas.response.name}.parse(res.data)}`,
661
+ dataReturnType === "data" && parser === "zod" && zodSchemas && `return ${zodSchemas.response.name}.parse(res.data)`,
662
+ dataReturnType === "full" && parser === "client" && "return res",
663
+ dataReturnType === "data" && parser === "client" && "return res.data"
664
+ ] });
665
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("br", {}), /* @__PURE__ */ jsx(File.Source, {
666
+ name,
667
+ isExportable,
668
+ isIndexable,
669
+ children: /* @__PURE__ */ jsxs(Function$1, {
670
+ name,
671
+ async: true,
672
+ export: isExportable,
673
+ params: params.toConstructor(),
674
+ JSDoc: { comments: legacyGetComments(operation) },
675
+ returnType,
676
+ children: [
677
+ isConfigurable ? "const { client: request = fetch, ...requestConfig } = config" : "",
678
+ /* @__PURE__ */ jsx("br", {}),
679
+ /* @__PURE__ */ jsx("br", {}),
680
+ pathParamsMapping && Object.entries(pathParamsMapping).filter(([originalName, camelCaseName]) => originalName !== camelCaseName && isValidVarName(originalName)).map(([originalName, camelCaseName]) => `const ${originalName} = ${camelCaseName}`).join("\n"),
681
+ pathParamsMapping && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("br", {}), /* @__PURE__ */ jsx("br", {})] }),
682
+ queryParamsMapping && typeSchemas.queryParams?.name && /* @__PURE__ */ jsxs(Fragment, { children: [
683
+ `const mappedParams = params ? { ${Object.entries(queryParamsMapping).map(([originalName, camelCaseName]) => `"${originalName}": params.${camelCaseName}`).join(", ")} } : undefined`,
684
+ /* @__PURE__ */ jsx("br", {}),
685
+ /* @__PURE__ */ jsx("br", {})
686
+ ] }),
687
+ headerParamsMapping && typeSchemas.headerParams?.name && /* @__PURE__ */ jsxs(Fragment, { children: [
688
+ `const mappedHeaders = headers ? { ${Object.entries(headerParamsMapping).map(([originalName, camelCaseName]) => `"${originalName}": headers.${camelCaseName}`).join(", ")} } : undefined`,
689
+ /* @__PURE__ */ jsx("br", {}),
690
+ /* @__PURE__ */ jsx("br", {})
691
+ ] }),
692
+ parser === "zod" && zodSchemas?.request?.name ? `const requestData = ${zodSchemas.request.name}.parse(data)` : typeSchemas?.request?.name && "const requestData = data",
693
+ /* @__PURE__ */ jsx("br", {}),
694
+ isFormData && typeSchemas?.request?.name && "const formData = buildFormData(requestData)",
695
+ /* @__PURE__ */ jsx("br", {}),
696
+ isConfigurable ? `const res = await request<${generics.join(", ")}>(${clientParams.toCall()})` : `const res = await fetch<${generics.join(", ")}>(${clientParams.toCall()})`,
697
+ /* @__PURE__ */ jsx("br", {}),
698
+ childrenElement
699
+ ]
700
+ })
701
+ })] });
702
+ }
703
+ ClientLegacy.getParams = getParams;
704
+ function getUrlParams({ paramsType, paramsCasing, pathParamsType, typeSchemas }) {
705
+ if (paramsType === "object") {
706
+ const pathParams = legacyGetPathParams(typeSchemas.pathParams, {
707
+ typed: true,
708
+ casing: paramsCasing
709
+ });
710
+ return FunctionParams.factory({ data: {
711
+ mode: "object",
712
+ children: { ...pathParams }
713
+ } });
714
+ }
715
+ return FunctionParams.factory({ pathParams: typeSchemas.pathParams?.name ? {
716
+ mode: pathParamsType === "object" ? "object" : "inlineSpread",
717
+ children: legacyGetPathParams(typeSchemas.pathParams, {
718
+ typed: true,
719
+ casing: paramsCasing
720
+ }),
721
+ default: getSchemaDefaultValue(typeSchemas.pathParams?.schema)
722
+ } : void 0 });
723
+ }
724
+ function UrlLegacy({ name, isExportable = true, isIndexable = true, typeSchemas, baseURL, paramsType, paramsCasing, pathParamsType, operation }) {
725
+ const path = new URLPath(operation.path);
726
+ const params = getUrlParams({
727
+ paramsType,
728
+ paramsCasing,
729
+ pathParamsType,
730
+ typeSchemas
731
+ });
732
+ const pathParamsMapping = paramsCasing ? legacyGetParamsMapping(typeSchemas.pathParams, { casing: paramsCasing }) : void 0;
733
+ return /* @__PURE__ */ jsx(File.Source, {
734
+ name,
735
+ isExportable,
736
+ isIndexable,
737
+ children: /* @__PURE__ */ jsxs(Function$1, {
738
+ name,
739
+ export: isExportable,
740
+ params: params.toConstructor(),
741
+ children: [
742
+ pathParamsMapping && Object.entries(pathParamsMapping).filter(([originalName, camelCaseName]) => originalName !== camelCaseName && isValidVarName(originalName)).map(([originalName, camelCaseName]) => `const ${originalName} = ${camelCaseName}`).join("\n"),
743
+ pathParamsMapping && /* @__PURE__ */ jsx("br", {}),
744
+ /* @__PURE__ */ jsx(Const, {
745
+ name: "res",
746
+ children: `{ method: '${operation.method.toUpperCase()}', url: ${path.toTemplateString({ prefix: baseURL })} as const }`
747
+ }),
748
+ /* @__PURE__ */ jsx("br", {}),
749
+ "return res"
750
+ ]
751
+ })
752
+ });
753
+ }
754
+ UrlLegacy.getParams = getUrlParams;
755
+ //#endregion
756
+ //#region src/components/ClassClient.tsx
757
+ const declarationPrinter$1 = functionPrinter({ mode: "declaration" });
758
+ function generateMethod$1({ node, name, tsResolver, zodResolver, baseURL, dataReturnType, parser, paramsType, paramsCasing, pathParamsType }) {
759
+ const path = new URLPath(node.path, { casing: paramsCasing });
760
+ const contentType = node.requestBody?.contentType ?? "application/json";
761
+ const isFormData = contentType === "multipart/form-data";
762
+ const headers = buildHeaders(contentType, !!(node.parameters.filter((p) => p.in === "header").length > 0 ? tsResolver.resolveHeaderParamsName(node, node.parameters.filter((p) => p.in === "header")[0]) : void 0));
763
+ const generics = buildGenerics(node, tsResolver);
764
+ const paramsNode = ClassClient.getParams({
765
+ paramsType,
766
+ paramsCasing,
767
+ pathParamsType,
768
+ node,
769
+ tsResolver,
770
+ isConfigurable: true
771
+ });
772
+ const paramsSignature = declarationPrinter$1.print(paramsNode) ?? "";
773
+ const clientParams = buildClassClientParams({
774
+ node,
775
+ path,
776
+ baseURL,
777
+ tsResolver,
778
+ isFormData,
779
+ headers
780
+ });
781
+ const jsdoc = buildJSDoc(getComments(node));
782
+ const requestDataLine = buildRequestDataLine({
783
+ parser,
784
+ node,
785
+ zodResolver
786
+ });
787
+ const formDataLine = buildFormDataLine(isFormData, !!node.requestBody?.schema);
788
+ const returnStatement = buildReturnStatement({
789
+ dataReturnType,
790
+ parser,
791
+ node,
792
+ zodResolver
793
+ });
794
+ return `${jsdoc}async ${name}(${paramsSignature}) {\n${[
795
+ "const { client: request = fetch, ...requestConfig } = mergeConfig(this.#config, config)",
796
+ "",
797
+ requestDataLine,
798
+ formDataLine,
799
+ `const res = await request<${generics.join(", ")}>(${clientParams.toCall()})`,
800
+ returnStatement
801
+ ].filter(Boolean).map((line) => ` ${line}`).join("\n")}\n }`;
802
+ }
803
+ __name(generateMethod$1, "generateMethod");
804
+ function ClassClient({ name, isExportable = true, isIndexable = true, operations, baseURL, dataReturnType, parser, paramsType, paramsCasing, pathParamsType, children }) {
805
+ const classCode = `export class ${name} {
806
+ #config: Partial<RequestConfig> & { client?: Client }
807
+
808
+ constructor(config: Partial<RequestConfig> & { client?: Client } = {}) {
809
+ this.#config = config
810
+ }
811
+
812
+ ${operations.map(({ node, name: methodName, tsResolver, zodResolver }) => generateMethod$1({
813
+ node,
814
+ name: methodName,
815
+ tsResolver,
816
+ zodResolver,
817
+ baseURL,
818
+ dataReturnType,
819
+ parser,
820
+ paramsType,
821
+ paramsCasing,
822
+ pathParamsType
823
+ })).join("\n\n")}
824
+ }`;
825
+ return /* @__PURE__ */ jsxs(File.Source, {
826
+ name,
827
+ isExportable,
828
+ isIndexable,
829
+ children: [classCode, children]
830
+ });
831
+ }
832
+ ClassClient.getParams = Client.getParams;
833
+ //#endregion
834
+ //#region src/components/WrapperClient.tsx
835
+ function WrapperClient({ name, classNames, isExportable = true, isIndexable = true }) {
836
+ const classCode = `export class ${name} {
837
+ ${classNames.map((className) => ` readonly ${camelCase(className)}: ${className}`).join("\n")}
838
+
839
+ constructor(config: Partial<RequestConfig> & { client?: Client } = {}) {
840
+ ${classNames.map((className) => ` this.${camelCase(className)} = new ${className}(config)`).join("\n")}
841
+ }
842
+ }`;
843
+ return /* @__PURE__ */ jsx(File.Source, {
844
+ name,
845
+ isExportable,
846
+ isIndexable,
847
+ children: classCode
848
+ });
849
+ }
850
+ //#endregion
851
+ //#region src/generators/classClientGenerator.tsx
852
+ function resolveTypeImportNames$1(node, tsResolver) {
853
+ return [
854
+ node.requestBody?.schema ? tsResolver.resolveDataName(node) : void 0,
855
+ tsResolver.resolveResponseName(node),
856
+ ...node.parameters.filter((p) => p.in === "path").map((p) => tsResolver.resolvePathParamsName(node, p)),
857
+ ...node.parameters.filter((p) => p.in === "query").map((p) => tsResolver.resolveQueryParamsName(node, p)),
858
+ ...node.parameters.filter((p) => p.in === "header").map((p) => tsResolver.resolveHeaderParamsName(node, p)),
859
+ ...node.responses.map((res) => tsResolver.resolveResponseStatusName(node, res.statusCode))
860
+ ].filter((n) => Boolean(n));
861
+ }
862
+ __name(resolveTypeImportNames$1, "resolveTypeImportNames");
863
+ function resolveZodImportNames$1(node, zodResolver) {
864
+ return [zodResolver.resolveResponseName?.(node), node.requestBody?.schema ? zodResolver.resolveDataName?.(node) : void 0].filter((n) => Boolean(n));
865
+ }
866
+ __name(resolveZodImportNames$1, "resolveZodImportNames");
867
+ const classClientGenerator = defineGenerator({
868
+ name: "classClient",
869
+ operations(nodes, options) {
870
+ const { adapter, config, driver, resolver, root } = this;
871
+ const { output, group, dataReturnType, paramsCasing, paramsType, pathParamsType, parser, importPath, wrapper } = options;
872
+ const baseURL = options.baseURL ?? adapter.rootNode?.meta?.baseURL;
873
+ const pluginTs = driver.getPlugin(pluginTsName);
874
+ if (!pluginTs?.resolver) return null;
875
+ const tsResolver = pluginTs.resolver;
876
+ const tsPluginOptions = pluginTs.options;
877
+ const pluginZod = parser === "zod" ? driver.getPlugin(pluginZodName) : void 0;
878
+ const zodResolver = pluginZod?.resolver;
879
+ function buildOperationData(node) {
880
+ const typeFile = tsResolver.resolveFile({
881
+ name: node.operationId,
882
+ extname: ".ts",
883
+ tag: node.tags[0] ?? "default",
884
+ path: node.path
885
+ }, {
886
+ root,
887
+ output: tsPluginOptions?.output ?? output,
888
+ group: tsPluginOptions?.group
889
+ });
890
+ const zodFile = zodResolver && pluginZod?.options ? zodResolver.resolveFile({
891
+ name: node.operationId,
892
+ extname: ".ts",
893
+ tag: node.tags[0] ?? "default",
894
+ path: node.path
895
+ }, {
896
+ root,
897
+ output: pluginZod.options.output ?? output,
898
+ group: pluginZod.options.group
899
+ }) : void 0;
900
+ return {
901
+ node,
902
+ name: resolver.resolveName(node.operationId),
903
+ tsResolver,
904
+ zodResolver,
905
+ typeFile,
906
+ zodFile
907
+ };
908
+ }
909
+ const controllers = nodes.reduce((acc, operationNode) => {
910
+ const tag = operationNode.tags[0];
911
+ const groupName = tag ? group?.name?.({ group: camelCase(tag) }) ?? pascalCase(tag) : "Client";
912
+ if (!tag && !group) {
913
+ const name = "ApiClient";
914
+ const file = resolver.resolveFile({
915
+ name,
916
+ extname: ".ts"
917
+ }, {
918
+ root,
919
+ output,
920
+ group
921
+ });
922
+ const operationData = buildOperationData(operationNode);
923
+ const previous = acc.find((item) => item.file.path === file.path);
924
+ if (previous) previous.operations.push(operationData);
925
+ else acc.push({
926
+ name,
927
+ file,
928
+ operations: [operationData]
929
+ });
930
+ } else if (tag) {
931
+ const name = groupName;
932
+ const file = resolver.resolveFile({
933
+ name,
934
+ extname: ".ts",
935
+ tag
936
+ }, {
937
+ root,
938
+ output,
939
+ group
940
+ });
941
+ const operationData = buildOperationData(operationNode);
942
+ const previous = acc.find((item) => item.file.path === file.path);
943
+ if (previous) previous.operations.push(operationData);
944
+ else acc.push({
945
+ name,
946
+ file,
947
+ operations: [operationData]
948
+ });
949
+ }
950
+ return acc;
951
+ }, []);
952
+ function collectTypeImports(ops) {
953
+ const typeImportsByFile = /* @__PURE__ */ new Map();
954
+ const typeFilesByPath = /* @__PURE__ */ new Map();
955
+ ops.forEach((op) => {
956
+ const names = resolveTypeImportNames$1(op.node, tsResolver);
957
+ if (!typeImportsByFile.has(op.typeFile.path)) typeImportsByFile.set(op.typeFile.path, /* @__PURE__ */ new Set());
958
+ const imports = typeImportsByFile.get(op.typeFile.path);
959
+ names.forEach((n) => {
960
+ imports.add(n);
961
+ });
962
+ typeFilesByPath.set(op.typeFile.path, op.typeFile);
963
+ });
964
+ return {
965
+ typeImportsByFile,
966
+ typeFilesByPath
967
+ };
968
+ }
969
+ function collectZodImports(ops) {
970
+ const zodImportsByFile = /* @__PURE__ */ new Map();
971
+ const zodFilesByPath = /* @__PURE__ */ new Map();
972
+ ops.forEach((op) => {
973
+ if (!op.zodFile || !zodResolver) return;
974
+ const names = resolveZodImportNames$1(op.node, zodResolver);
975
+ if (!zodImportsByFile.has(op.zodFile.path)) zodImportsByFile.set(op.zodFile.path, /* @__PURE__ */ new Set());
976
+ const imports = zodImportsByFile.get(op.zodFile.path);
977
+ names.forEach((n) => {
978
+ imports.add(n);
979
+ });
980
+ zodFilesByPath.set(op.zodFile.path, op.zodFile);
981
+ });
982
+ return {
983
+ zodImportsByFile,
984
+ zodFilesByPath
985
+ };
986
+ }
987
+ const files = controllers.map(({ name, file, operations: ops }) => {
988
+ const { typeImportsByFile, typeFilesByPath } = collectTypeImports(ops);
989
+ const { zodImportsByFile, zodFilesByPath } = parser === "zod" ? collectZodImports(ops) : {
990
+ zodImportsByFile: /* @__PURE__ */ new Map(),
991
+ zodFilesByPath: /* @__PURE__ */ new Map()
992
+ };
993
+ const hasFormData = ops.some((op) => op.node.requestBody?.contentType === "multipart/form-data");
994
+ return /* @__PURE__ */ jsxs(File, {
995
+ baseName: file.baseName,
996
+ path: file.path,
997
+ meta: file.meta,
998
+ banner: resolver.resolveBanner(adapter.rootNode, {
999
+ output,
1000
+ config
1001
+ }),
1002
+ footer: resolver.resolveFooter(adapter.rootNode, {
1003
+ output,
1004
+ config
1005
+ }),
1006
+ children: [
1007
+ importPath ? /* @__PURE__ */ jsxs(Fragment, { children: [
1008
+ /* @__PURE__ */ jsx(File.Import, {
1009
+ name: "fetch",
1010
+ path: importPath
1011
+ }),
1012
+ /* @__PURE__ */ jsx(File.Import, {
1013
+ name: ["mergeConfig"],
1014
+ path: importPath
1015
+ }),
1016
+ /* @__PURE__ */ jsx(File.Import, {
1017
+ name: [
1018
+ "Client",
1019
+ "RequestConfig",
1020
+ "ResponseErrorConfig"
1021
+ ],
1022
+ path: importPath,
1023
+ isTypeOnly: true
1024
+ })
1025
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
1026
+ /* @__PURE__ */ jsx(File.Import, {
1027
+ name: ["fetch"],
1028
+ root: file.path,
1029
+ path: path.resolve(root, ".kubb/fetch.ts")
1030
+ }),
1031
+ /* @__PURE__ */ jsx(File.Import, {
1032
+ name: ["mergeConfig"],
1033
+ root: file.path,
1034
+ path: path.resolve(root, ".kubb/fetch.ts")
1035
+ }),
1036
+ /* @__PURE__ */ jsx(File.Import, {
1037
+ name: [
1038
+ "Client",
1039
+ "RequestConfig",
1040
+ "ResponseErrorConfig"
1041
+ ],
1042
+ root: file.path,
1043
+ path: path.resolve(root, ".kubb/fetch.ts"),
1044
+ isTypeOnly: true
1045
+ })
1046
+ ] }),
1047
+ hasFormData && /* @__PURE__ */ jsx(File.Import, {
1048
+ name: ["buildFormData"],
1049
+ root: file.path,
1050
+ path: path.resolve(root, ".kubb/config.ts")
1051
+ }),
1052
+ Array.from(typeImportsByFile.entries()).map(([filePath, importSet]) => {
1053
+ const typeFile = typeFilesByPath.get(filePath);
1054
+ if (!typeFile) return null;
1055
+ const importNames = Array.from(importSet).filter(Boolean);
1056
+ if (importNames.length === 0) return null;
1057
+ return /* @__PURE__ */ jsx(File.Import, {
1058
+ name: importNames,
1059
+ root: file.path,
1060
+ path: typeFile.path,
1061
+ isTypeOnly: true
1062
+ }, filePath);
1063
+ }),
1064
+ parser === "zod" && Array.from(zodImportsByFile.entries()).map(([filePath, importSet]) => {
1065
+ const zodFile = zodFilesByPath.get(filePath);
1066
+ if (!zodFile) return null;
1067
+ const importNames = Array.from(importSet).filter(Boolean);
1068
+ if (importNames.length === 0) return null;
1069
+ return /* @__PURE__ */ jsx(File.Import, {
1070
+ name: importNames,
1071
+ root: file.path,
1072
+ path: zodFile.path
1073
+ }, filePath);
1074
+ }),
1075
+ /* @__PURE__ */ jsx(ClassClient, {
1076
+ name,
1077
+ operations: ops,
1078
+ baseURL,
1079
+ dataReturnType,
1080
+ pathParamsType,
1081
+ paramsCasing,
1082
+ paramsType,
1083
+ parser
1084
+ })
1085
+ ]
1086
+ }, file.path);
1087
+ });
1088
+ if (wrapper) {
1089
+ const wrapperFile = resolver.resolveFile({
1090
+ name: wrapper.className,
1091
+ extname: ".ts"
1092
+ }, {
1093
+ root,
1094
+ output,
1095
+ group
1096
+ });
1097
+ files.push(/* @__PURE__ */ jsxs(File, {
1098
+ baseName: wrapperFile.baseName,
1099
+ path: wrapperFile.path,
1100
+ meta: wrapperFile.meta,
1101
+ banner: resolver.resolveBanner(adapter.rootNode, {
1102
+ output,
1103
+ config
1104
+ }),
1105
+ footer: resolver.resolveFooter(adapter.rootNode, {
1106
+ output,
1107
+ config
1108
+ }),
1109
+ children: [
1110
+ importPath ? /* @__PURE__ */ jsx(File.Import, {
1111
+ name: ["Client", "RequestConfig"],
1112
+ path: importPath,
1113
+ isTypeOnly: true
1114
+ }) : /* @__PURE__ */ jsx(File.Import, {
1115
+ name: ["Client", "RequestConfig"],
1116
+ root: wrapperFile.path,
1117
+ path: path.resolve(root, ".kubb/fetch.ts"),
1118
+ isTypeOnly: true
1119
+ }),
1120
+ controllers.map(({ name, file }) => /* @__PURE__ */ jsx(File.Import, {
1121
+ name: [name],
1122
+ root: wrapperFile.path,
1123
+ path: file.path
1124
+ }, name)),
1125
+ /* @__PURE__ */ jsx(WrapperClient, {
1126
+ name: wrapper.className,
1127
+ classNames: controllers.map(({ name }) => name)
1128
+ })
1129
+ ]
1130
+ }, wrapperFile.path));
1131
+ }
1132
+ return /* @__PURE__ */ jsx(Fragment, { children: files });
1133
+ }
1134
+ });
1135
+ //#endregion
1136
+ //#region src/generators/clientGenerator.tsx
1137
+ const clientGenerator = defineGenerator({
1138
+ name: "client",
1139
+ operation(node, options) {
1140
+ const { adapter, config, driver, resolver, root } = this;
1141
+ const { output, urlType, dataReturnType, paramsCasing, paramsType, pathParamsType, parser, importPath, group } = options;
1142
+ const baseURL = options.baseURL ?? adapter.rootNode?.meta?.baseURL;
1143
+ const pluginTs = driver.getPlugin(pluginTsName);
1144
+ if (!pluginTs?.resolver) return null;
1145
+ const tsResolver = pluginTs.resolver;
1146
+ const pluginZod = parser === "zod" ? driver.getPlugin(pluginZodName) : void 0;
1147
+ const zodResolver = pluginZod?.resolver;
1148
+ const casedParams = caseParams(node.parameters, paramsCasing);
1149
+ const pathParams = casedParams.filter((p) => p.in === "path");
1150
+ const queryParams = casedParams.filter((p) => p.in === "query");
1151
+ const headerParams = casedParams.filter((p) => p.in === "header");
1152
+ const importedTypeNames = [
1153
+ ...pathParams.map((p) => tsResolver.resolvePathParamsName(node, p)),
1154
+ ...queryParams.map((p) => tsResolver.resolveQueryParamsName(node, p)),
1155
+ ...headerParams.map((p) => tsResolver.resolveHeaderParamsName(node, p)),
1156
+ node.requestBody?.schema ? tsResolver.resolveDataName(node) : void 0,
1157
+ tsResolver.resolveResponseName(node),
1158
+ ...node.responses.map((res) => tsResolver.resolveResponseStatusName(node, res.statusCode))
1159
+ ].filter(Boolean);
1160
+ const importedZodNames = zodResolver && parser === "zod" ? [zodResolver.resolveResponseName?.(node), node.requestBody?.schema ? zodResolver.resolveDataName?.(node) : void 0].filter(Boolean) : [];
1161
+ const meta = {
1162
+ name: resolver.resolveName(node.operationId),
1163
+ urlName: `get${resolver.resolveName(node.operationId).charAt(0).toUpperCase()}${resolver.resolveName(node.operationId).slice(1)}Url`,
1164
+ file: resolver.resolveFile({
1165
+ name: node.operationId,
1166
+ extname: ".ts",
1167
+ tag: node.tags[0] ?? "default",
1168
+ path: node.path
1169
+ }, {
1170
+ root,
1171
+ output,
1172
+ group
1173
+ }),
1174
+ fileTs: tsResolver.resolveFile({
1175
+ name: node.operationId,
1176
+ extname: ".ts",
1177
+ tag: node.tags[0] ?? "default",
1178
+ path: node.path
1179
+ }, {
1180
+ root,
1181
+ output: pluginTs.options?.output ?? output,
1182
+ group: pluginTs.options?.group
1183
+ }),
1184
+ fileZod: zodResolver && pluginZod?.options ? zodResolver.resolveFile({
1185
+ name: node.operationId,
1186
+ extname: ".ts",
1187
+ tag: node.tags[0] ?? "default",
1188
+ path: node.path
1189
+ }, {
1190
+ root,
1191
+ output: pluginZod.options.output ?? output,
1192
+ group: pluginZod.options.group
1193
+ }) : void 0
1194
+ };
1195
+ const isFormData = node.requestBody?.contentType === "multipart/form-data";
1196
+ return /* @__PURE__ */ jsxs(File, {
1197
+ baseName: meta.file.baseName,
1198
+ path: meta.file.path,
1199
+ meta: meta.file.meta,
1200
+ banner: resolver.resolveBanner(adapter.rootNode, {
1201
+ output,
1202
+ config
1203
+ }),
1204
+ footer: resolver.resolveFooter(adapter.rootNode, {
1205
+ output,
1206
+ config
1207
+ }),
1208
+ children: [
1209
+ importPath ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(File.Import, {
1210
+ name: "fetch",
1211
+ path: importPath
1212
+ }), /* @__PURE__ */ jsx(File.Import, {
1213
+ name: [
1214
+ "Client",
1215
+ "RequestConfig",
1216
+ "ResponseErrorConfig"
1217
+ ],
1218
+ path: importPath,
1219
+ isTypeOnly: true
1220
+ })] }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(File.Import, {
1221
+ name: ["fetch"],
1222
+ root: meta.file.path,
1223
+ path: path.resolve(root, ".kubb/fetch.ts")
1224
+ }), /* @__PURE__ */ jsx(File.Import, {
1225
+ name: [
1226
+ "Client",
1227
+ "RequestConfig",
1228
+ "ResponseErrorConfig"
1229
+ ],
1230
+ root: meta.file.path,
1231
+ path: path.resolve(root, ".kubb/fetch.ts"),
1232
+ isTypeOnly: true
1233
+ })] }),
1234
+ isFormData && node.requestBody?.schema && /* @__PURE__ */ jsx(File.Import, {
1235
+ name: ["buildFormData"],
1236
+ root: meta.file.path,
1237
+ path: path.resolve(root, ".kubb/config.ts")
1238
+ }),
1239
+ meta.fileZod && importedZodNames.length > 0 && /* @__PURE__ */ jsx(File.Import, {
1240
+ name: importedZodNames,
1241
+ root: meta.file.path,
1242
+ path: meta.fileZod.path
1243
+ }),
1244
+ meta.fileTs && importedTypeNames.length > 0 && /* @__PURE__ */ jsx(File.Import, {
1245
+ name: Array.from(new Set(importedTypeNames)),
1246
+ root: meta.file.path,
1247
+ path: meta.fileTs.path,
1248
+ isTypeOnly: true
1249
+ }),
1250
+ /* @__PURE__ */ jsx(Url, {
1251
+ name: meta.urlName,
1252
+ baseURL,
1253
+ pathParamsType,
1254
+ paramsCasing,
1255
+ paramsType,
1256
+ node,
1257
+ tsResolver,
1258
+ isIndexable: urlType === "export",
1259
+ isExportable: urlType === "export"
1260
+ }),
1261
+ /* @__PURE__ */ jsx(Client, {
1262
+ name: meta.name,
1263
+ urlName: meta.urlName,
1264
+ baseURL,
1265
+ dataReturnType,
1266
+ pathParamsType,
1267
+ paramsCasing,
1268
+ paramsType,
1269
+ node,
1270
+ tsResolver,
1271
+ zodResolver,
1272
+ parser
1273
+ })
1274
+ ]
1275
+ });
1276
+ }
1277
+ });
1278
+ //#endregion
1279
+ //#region src/generators/groupedClientGenerator.tsx
1280
+ const groupedClientGenerator = defineGenerator({
1281
+ name: "groupedClient",
1282
+ operations(nodes, options) {
1283
+ const { config, resolver, adapter, root } = this;
1284
+ const { output, group } = options;
1285
+ return /* @__PURE__ */ jsx(Fragment, { children: nodes.reduce((acc, operationNode) => {
1286
+ if (group?.type === "tag") {
1287
+ const tag = operationNode.tags[0];
1288
+ const name = tag ? group?.name?.({ group: camelCase(tag) }) : void 0;
1289
+ if (!tag || !name) return acc;
1290
+ const file = resolver.resolveFile({
1291
+ name,
1292
+ extname: ".ts",
1293
+ tag
1294
+ }, {
1295
+ root,
1296
+ output,
1297
+ group
1298
+ });
1299
+ const clientFile = resolver.resolveFile({
1300
+ name: operationNode.operationId,
1301
+ extname: ".ts",
1302
+ tag: operationNode.tags[0] ?? "default",
1303
+ path: operationNode.path
1304
+ }, {
1305
+ root,
1306
+ output,
1307
+ group
1308
+ });
1309
+ const client = {
1310
+ name: resolver.resolveName(operationNode.operationId),
1311
+ file: clientFile
1312
+ };
1313
+ const previous = acc.find((item) => item.file.path === file.path);
1314
+ if (previous) previous.clients.push(client);
1315
+ else acc.push({
1316
+ name,
1317
+ file,
1318
+ clients: [client]
1319
+ });
1320
+ }
1321
+ return acc;
1322
+ }, []).map(({ name, file, clients }) => {
1323
+ return /* @__PURE__ */ jsxs(File, {
1324
+ baseName: file.baseName,
1325
+ path: file.path,
1326
+ meta: file.meta,
1327
+ banner: resolver.resolveBanner(adapter.rootNode, {
1328
+ output,
1329
+ config
1330
+ }),
1331
+ footer: resolver.resolveFooter(adapter.rootNode, {
1332
+ output,
1333
+ config
1334
+ }),
1335
+ children: [clients.map((client) => /* @__PURE__ */ jsx(File.Import, {
1336
+ name: [client.name],
1337
+ root: file.path,
1338
+ path: client.file.path
1339
+ }, client.name)), /* @__PURE__ */ jsx(File.Source, {
1340
+ name,
1341
+ isExportable: true,
1342
+ isIndexable: true,
1343
+ children: /* @__PURE__ */ jsx(Function$1, {
1344
+ export: true,
1345
+ name,
1346
+ children: `return { ${clients.map((client) => client.name).join(", ")} }`
1347
+ })
1348
+ })]
1349
+ }, file.path);
1350
+ }) });
1351
+ }
1352
+ });
1353
+ //#endregion
1354
+ //#region src/components/Operations.tsx
1355
+ function Operations({ name, nodes }) {
1356
+ const operationsObject = {};
1357
+ nodes.forEach((node) => {
1358
+ operationsObject[node.operationId] = {
1359
+ path: new URLPath(node.path).URL,
1360
+ method: node.method.toLowerCase()
1361
+ };
1362
+ });
1363
+ return /* @__PURE__ */ jsx(File.Source, {
1364
+ name,
1365
+ isExportable: true,
1366
+ isIndexable: true,
1367
+ children: /* @__PURE__ */ jsx(Const, {
1368
+ name,
1369
+ export: true,
1370
+ children: JSON.stringify(operationsObject, void 0, 2)
1371
+ })
1372
+ });
1373
+ }
1374
+ //#endregion
1375
+ //#region src/generators/operationsGenerator.tsx
1376
+ const operationsGenerator = defineGenerator({
1377
+ name: "client",
1378
+ operations(nodes, options) {
1379
+ const { config, resolver, adapter, root } = this;
1380
+ const { output, group } = options;
1381
+ const name = "operations";
1382
+ const file = resolver.resolveFile({
1383
+ name,
1384
+ extname: ".ts"
1385
+ }, {
1386
+ root,
1387
+ output,
1388
+ group
1389
+ });
1390
+ return /* @__PURE__ */ jsx(File, {
1391
+ baseName: file.baseName,
1392
+ path: file.path,
1393
+ meta: file.meta,
1394
+ banner: resolver.resolveBanner(adapter.rootNode, {
1395
+ output,
1396
+ config
1397
+ }),
1398
+ footer: resolver.resolveFooter(adapter.rootNode, {
1399
+ output,
1400
+ config
1401
+ }),
1402
+ children: /* @__PURE__ */ jsx(Operations, {
1403
+ name,
1404
+ nodes
1405
+ })
1406
+ });
1407
+ }
1408
+ });
1409
+ //#endregion
1410
+ //#region src/components/StaticClassClient.tsx
1411
+ const declarationPrinter = functionPrinter({ mode: "declaration" });
1412
+ function generateMethod({ node, name, tsResolver, zodResolver, baseURL, dataReturnType, parser, paramsType, paramsCasing, pathParamsType }) {
1413
+ const path = new URLPath(node.path, { casing: paramsCasing });
1414
+ const contentType = node.requestBody?.contentType ?? "application/json";
1415
+ const isFormData = contentType === "multipart/form-data";
1416
+ const headers = buildHeaders(contentType, !!(node.parameters.filter((p) => p.in === "header").length > 0 ? tsResolver.resolveHeaderParamsName(node, node.parameters.filter((p) => p.in === "header")[0]) : void 0));
1417
+ const generics = buildGenerics(node, tsResolver);
1418
+ const paramsNode = Client.getParams({
1419
+ paramsType,
1420
+ paramsCasing,
1421
+ pathParamsType,
1422
+ node,
1423
+ tsResolver,
1424
+ isConfigurable: true
1425
+ });
1426
+ const paramsSignature = declarationPrinter.print(paramsNode) ?? "";
1427
+ const clientParams = buildClassClientParams({
1428
+ node,
1429
+ path,
1430
+ baseURL,
1431
+ tsResolver,
1432
+ isFormData,
1433
+ headers
1434
+ });
1435
+ const jsdoc = buildJSDoc(getComments(node));
1436
+ const requestDataLine = buildRequestDataLine({
1437
+ parser,
1438
+ node,
1439
+ zodResolver
1440
+ });
1441
+ const formDataLine = buildFormDataLine(isFormData, !!node.requestBody?.schema);
1442
+ const returnStatement = buildReturnStatement({
1443
+ dataReturnType,
1444
+ parser,
1445
+ node,
1446
+ zodResolver
1447
+ });
1448
+ return `${jsdoc} static async ${name}(${paramsSignature}) {\n${[
1449
+ "const { client: request = fetch, ...requestConfig } = mergeConfig(this.#config, config)",
1450
+ "",
1451
+ requestDataLine,
1452
+ formDataLine,
1453
+ `const res = await request<${generics.join(", ")}>(${clientParams.toCall()})`,
1454
+ returnStatement
1455
+ ].filter(Boolean).map((line) => ` ${line}`).join("\n")}\n }`;
1456
+ }
1457
+ function StaticClassClient({ name, isExportable = true, isIndexable = true, operations, baseURL, dataReturnType, parser, paramsType, paramsCasing, pathParamsType, children }) {
1458
+ const classCode = `export class ${name} {\n static #config: Partial<RequestConfig> & { client?: Client } = {}\n\n${operations.map(({ node, name: methodName, tsResolver, zodResolver }) => generateMethod({
1459
+ node,
1460
+ name: methodName,
1461
+ tsResolver,
1462
+ zodResolver,
1463
+ baseURL,
1464
+ dataReturnType,
1465
+ parser,
1466
+ paramsType,
1467
+ paramsCasing,
1468
+ pathParamsType
1469
+ })).join("\n\n")}\n}`;
1470
+ return /* @__PURE__ */ jsxs(File.Source, {
1471
+ name,
1472
+ isExportable,
1473
+ isIndexable,
1474
+ children: [classCode, children]
1475
+ });
1476
+ }
1477
+ StaticClassClient.getParams = Client.getParams;
1478
+ //#endregion
1479
+ //#region src/generators/staticClassClientGenerator.tsx
1480
+ function resolveTypeImportNames(node, tsResolver) {
1481
+ return [
1482
+ node.requestBody?.schema ? tsResolver.resolveDataName(node) : void 0,
1483
+ tsResolver.resolveResponseName(node),
1484
+ ...node.parameters.filter((p) => p.in === "path").map((p) => tsResolver.resolvePathParamsName(node, p)),
1485
+ ...node.parameters.filter((p) => p.in === "query").map((p) => tsResolver.resolveQueryParamsName(node, p)),
1486
+ ...node.parameters.filter((p) => p.in === "header").map((p) => tsResolver.resolveHeaderParamsName(node, p)),
1487
+ ...node.responses.map((res) => tsResolver.resolveResponseStatusName(node, res.statusCode))
1488
+ ].filter((n) => Boolean(n));
1489
+ }
1490
+ function resolveZodImportNames(node, zodResolver) {
1491
+ return [zodResolver.resolveResponseName?.(node), node.requestBody?.schema ? zodResolver.resolveDataName?.(node) : void 0].filter((n) => Boolean(n));
1492
+ }
1493
+ const staticClassClientGenerator = defineGenerator({
1494
+ name: "staticClassClient",
1495
+ operations(nodes, options) {
1496
+ const { adapter, config, driver, resolver, root } = this;
1497
+ const { output, group, dataReturnType, paramsCasing, paramsType, pathParamsType, parser, importPath } = options;
1498
+ const baseURL = options.baseURL ?? adapter.rootNode?.meta?.baseURL;
1499
+ const pluginTs = driver.getPlugin(pluginTsName);
1500
+ if (!pluginTs?.resolver) return null;
1501
+ const tsResolver = pluginTs.resolver;
1502
+ const tsPluginOptions = pluginTs.options;
1503
+ const pluginZod = parser === "zod" ? driver.getPlugin(pluginZodName) : void 0;
1504
+ const zodResolver = pluginZod?.resolver;
1505
+ function buildOperationData(node) {
1506
+ const typeFile = tsResolver.resolveFile({
1507
+ name: node.operationId,
1508
+ extname: ".ts",
1509
+ tag: node.tags[0] ?? "default",
1510
+ path: node.path
1511
+ }, {
1512
+ root,
1513
+ output: tsPluginOptions?.output ?? output,
1514
+ group: tsPluginOptions?.group
1515
+ });
1516
+ const zodFile = zodResolver && pluginZod?.options ? zodResolver.resolveFile({
1517
+ name: node.operationId,
1518
+ extname: ".ts",
1519
+ tag: node.tags[0] ?? "default",
1520
+ path: node.path
1521
+ }, {
1522
+ root,
1523
+ output: pluginZod.options.output ?? output,
1524
+ group: pluginZod.options.group
1525
+ }) : void 0;
1526
+ return {
1527
+ node,
1528
+ name: resolver.resolveName(node.operationId),
1529
+ tsResolver,
1530
+ zodResolver,
1531
+ typeFile,
1532
+ zodFile
1533
+ };
1534
+ }
1535
+ const controllers = nodes.reduce((acc, operationNode) => {
1536
+ const tag = operationNode.tags[0];
1537
+ const groupName = tag ? group?.name?.({ group: camelCase(tag) }) ?? pascalCase(tag) : "Client";
1538
+ if (!tag && !group) {
1539
+ const name = "ApiClient";
1540
+ const file = resolver.resolveFile({
1541
+ name,
1542
+ extname: ".ts"
1543
+ }, {
1544
+ root,
1545
+ output,
1546
+ group
1547
+ });
1548
+ const operationData = buildOperationData(operationNode);
1549
+ const previous = acc.find((item) => item.file.path === file.path);
1550
+ if (previous) previous.operations.push(operationData);
1551
+ else acc.push({
1552
+ name,
1553
+ file,
1554
+ operations: [operationData]
1555
+ });
1556
+ } else if (tag) {
1557
+ const name = groupName;
1558
+ const file = resolver.resolveFile({
1559
+ name,
1560
+ extname: ".ts",
1561
+ tag
1562
+ }, {
1563
+ root,
1564
+ output,
1565
+ group
1566
+ });
1567
+ const operationData = buildOperationData(operationNode);
1568
+ const previous = acc.find((item) => item.file.path === file.path);
1569
+ if (previous) previous.operations.push(operationData);
1570
+ else acc.push({
1571
+ name,
1572
+ file,
1573
+ operations: [operationData]
1574
+ });
1575
+ }
1576
+ return acc;
1577
+ }, []);
1578
+ function collectTypeImports(ops) {
1579
+ const typeImportsByFile = /* @__PURE__ */ new Map();
1580
+ const typeFilesByPath = /* @__PURE__ */ new Map();
1581
+ ops.forEach((op) => {
1582
+ const names = resolveTypeImportNames(op.node, tsResolver);
1583
+ if (!typeImportsByFile.has(op.typeFile.path)) typeImportsByFile.set(op.typeFile.path, /* @__PURE__ */ new Set());
1584
+ const imports = typeImportsByFile.get(op.typeFile.path);
1585
+ names.forEach((n) => {
1586
+ imports.add(n);
1587
+ });
1588
+ typeFilesByPath.set(op.typeFile.path, op.typeFile);
1589
+ });
1590
+ return {
1591
+ typeImportsByFile,
1592
+ typeFilesByPath
1593
+ };
1594
+ }
1595
+ function collectZodImports(ops) {
1596
+ const zodImportsByFile = /* @__PURE__ */ new Map();
1597
+ const zodFilesByPath = /* @__PURE__ */ new Map();
1598
+ ops.forEach((op) => {
1599
+ if (!op.zodFile || !zodResolver) return;
1600
+ const names = resolveZodImportNames(op.node, zodResolver);
1601
+ if (!zodImportsByFile.has(op.zodFile.path)) zodImportsByFile.set(op.zodFile.path, /* @__PURE__ */ new Set());
1602
+ const imports = zodImportsByFile.get(op.zodFile.path);
1603
+ names.forEach((n) => {
1604
+ imports.add(n);
1605
+ });
1606
+ zodFilesByPath.set(op.zodFile.path, op.zodFile);
1607
+ });
1608
+ return {
1609
+ zodImportsByFile,
1610
+ zodFilesByPath
1611
+ };
1612
+ }
1613
+ return /* @__PURE__ */ jsx(Fragment, { children: controllers.map(({ name, file, operations: ops }) => {
1614
+ const { typeImportsByFile, typeFilesByPath } = collectTypeImports(ops);
1615
+ const { zodImportsByFile, zodFilesByPath } = parser === "zod" ? collectZodImports(ops) : {
1616
+ zodImportsByFile: /* @__PURE__ */ new Map(),
1617
+ zodFilesByPath: /* @__PURE__ */ new Map()
1618
+ };
1619
+ const hasFormData = ops.some((op) => op.node.requestBody?.contentType === "multipart/form-data");
1620
+ return /* @__PURE__ */ jsxs(File, {
1621
+ baseName: file.baseName,
1622
+ path: file.path,
1623
+ meta: file.meta,
1624
+ banner: resolver.resolveBanner(adapter.rootNode, {
1625
+ output,
1626
+ config
1627
+ }),
1628
+ footer: resolver.resolveFooter(adapter.rootNode, {
1629
+ output,
1630
+ config
1631
+ }),
1632
+ children: [
1633
+ importPath ? /* @__PURE__ */ jsxs(Fragment, { children: [
1634
+ /* @__PURE__ */ jsx(File.Import, {
1635
+ name: "fetch",
1636
+ path: importPath
1637
+ }),
1638
+ /* @__PURE__ */ jsx(File.Import, {
1639
+ name: ["mergeConfig"],
1640
+ path: importPath
1641
+ }),
1642
+ /* @__PURE__ */ jsx(File.Import, {
1643
+ name: [
1644
+ "Client",
1645
+ "RequestConfig",
1646
+ "ResponseErrorConfig"
1647
+ ],
1648
+ path: importPath,
1649
+ isTypeOnly: true
1650
+ })
1651
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
1652
+ /* @__PURE__ */ jsx(File.Import, {
1653
+ name: ["fetch"],
1654
+ root: file.path,
1655
+ path: path.resolve(root, ".kubb/fetch.ts")
1656
+ }),
1657
+ /* @__PURE__ */ jsx(File.Import, {
1658
+ name: ["mergeConfig"],
1659
+ root: file.path,
1660
+ path: path.resolve(root, ".kubb/fetch.ts")
1661
+ }),
1662
+ /* @__PURE__ */ jsx(File.Import, {
1663
+ name: [
1664
+ "Client",
1665
+ "RequestConfig",
1666
+ "ResponseErrorConfig"
1667
+ ],
1668
+ root: file.path,
1669
+ path: path.resolve(root, ".kubb/fetch.ts"),
1670
+ isTypeOnly: true
1671
+ })
1672
+ ] }),
1673
+ hasFormData && /* @__PURE__ */ jsx(File.Import, {
1674
+ name: ["buildFormData"],
1675
+ root: file.path,
1676
+ path: path.resolve(root, ".kubb/config.ts")
1677
+ }),
1678
+ Array.from(typeImportsByFile.entries()).map(([filePath, importSet]) => {
1679
+ const typeFile = typeFilesByPath.get(filePath);
1680
+ if (!typeFile) return null;
1681
+ const importNames = Array.from(importSet).filter(Boolean);
1682
+ if (importNames.length === 0) return null;
1683
+ return /* @__PURE__ */ jsx(File.Import, {
1684
+ name: importNames,
1685
+ root: file.path,
1686
+ path: typeFile.path,
1687
+ isTypeOnly: true
1688
+ }, filePath);
1689
+ }),
1690
+ parser === "zod" && Array.from(zodImportsByFile.entries()).map(([filePath, importSet]) => {
1691
+ const zodFile = zodFilesByPath.get(filePath);
1692
+ if (!zodFile) return null;
1693
+ const importNames = Array.from(importSet).filter(Boolean);
1694
+ if (importNames.length === 0) return null;
1695
+ return /* @__PURE__ */ jsx(File.Import, {
1696
+ name: importNames,
1697
+ root: file.path,
1698
+ path: zodFile.path
1699
+ }, filePath);
1700
+ }),
1701
+ /* @__PURE__ */ jsx(StaticClassClient, {
1702
+ name,
1703
+ operations: ops,
1704
+ baseURL,
1705
+ dataReturnType,
1706
+ pathParamsType,
1707
+ paramsCasing,
1708
+ paramsType,
1709
+ parser
1710
+ })
1711
+ ]
1712
+ }, file.path);
1713
+ }) });
1714
+ }
1715
+ });
1716
+ //#endregion
1717
+ //#region package.json
1718
+ var version = "5.0.0-alpha.31";
1719
+ //#endregion
1720
+ //#region src/resolvers/resolverClient.ts
1721
+ /**
1722
+ * Resolver for `@kubb/plugin-client` that provides the default naming
1723
+ * and path-resolution helpers used by the plugin.
1724
+ *
1725
+ * @example
1726
+ * ```ts
1727
+ * import { resolverClient } from '@kubb/plugin-client'
1728
+ *
1729
+ * resolverClient.default('list pets', 'function') // -> 'listPets'
1730
+ * resolverClient.resolveName('show pet by id') // -> 'showPetById'
1731
+ * ```
1732
+ */
1733
+ const resolverClient = defineResolver(() => ({
1734
+ name: "default",
1735
+ pluginName: "plugin-client",
1736
+ default(name, type) {
1737
+ return camelCase(name, { isFile: type === "file" });
1738
+ },
1739
+ resolveName(name) {
1740
+ return this.default(name, "function");
1741
+ }
1742
+ }));
1743
+ //#endregion
1744
+ //#region src/resolvers/resolverClientLegacy.ts
1745
+ /**
1746
+ * Legacy resolver for `@kubb/plugin-client` that provides backward-compatible
1747
+ * naming conventions matching the v4 behavior.
1748
+ *
1749
+ * @example
1750
+ * ```ts
1751
+ * import { resolverClientLegacy } from '@kubb/plugin-client'
1752
+ *
1753
+ * resolverClientLegacy.default('list pets', 'function') // -> 'listPets'
1754
+ * resolverClientLegacy.resolveName('show pet by id') // -> 'showPetById'
1755
+ * ```
1756
+ */
1757
+ const resolverClientLegacy = defineResolver(() => ({
1758
+ name: "kubbV4",
1759
+ pluginName: "plugin-client",
1760
+ default(name, type) {
1761
+ return camelCase(name, { isFile: type === "file" });
1762
+ },
1763
+ resolveName(name) {
1764
+ return this.default(name, "function");
1765
+ }
1766
+ }));
1767
+ //#endregion
1768
+ //#region src/presets.ts
1769
+ /**
1770
+ * Built-in preset registry for `@kubb/plugin-client`.
1771
+ *
1772
+ * - `default` — uses `resolverClient` with v5 naming conventions.
1773
+ * - `kubbV4` — uses `resolverClientLegacy` with backward-compatible naming.
1774
+ *
1775
+ * Note: Unlike plugin-ts/plugin-zod, generators are not defined here because
1776
+ * plugin-client selects generators dynamically based on `clientType`, `group`,
1777
+ * and `operations` options. Generator selection happens in `plugin.ts`.
1778
+ */
1779
+ const presets = definePresets({
1780
+ default: {
1781
+ name: "default",
1782
+ resolver: resolverClient
1783
+ },
1784
+ kubbV4: {
1785
+ name: "kubbV4",
1786
+ resolver: resolverClientLegacy
1787
+ }
1788
+ });
1789
+ //#endregion
11
1790
  //#region src/plugin.ts
1791
+ /**
1792
+ * Canonical plugin name for `@kubb/plugin-client`, used to identify the plugin
1793
+ * in driver lookups and warnings.
1794
+ */
12
1795
  const pluginClientName = "plugin-client";
13
- const pluginClient = definePlugin((options) => {
1796
+ /**
1797
+ * The `@kubb/plugin-client` plugin factory.
1798
+ *
1799
+ * Generates type-safe HTTP client functions (or classes) from an OpenAPI/AST `RootNode`.
1800
+ * Walks operations, delegates rendering to the active generators,
1801
+ * and writes barrel files based on `output.barrelType`.
1802
+ *
1803
+ * @example
1804
+ * ```ts
1805
+ * import { pluginClient } from '@kubb/plugin-client'
1806
+ *
1807
+ * export default defineConfig({
1808
+ * plugins: [pluginClient({ output: { path: 'clients' } })],
1809
+ * })
1810
+ * ```
1811
+ */
1812
+ const pluginClient = createPlugin((options) => {
14
1813
  const { output = {
15
1814
  path: "clients",
16
1815
  barrelType: "named"
17
- }, group, urlType = false, exclude = [], include, override = [], transformers = {}, dataReturnType = "data", paramsType = "inline", pathParamsType = paramsType === "object" ? "object" : options.pathParamsType || "inline", operations = false, baseURL, paramsCasing, clientType = "function", parser = "client", client = "axios", importPath, contentType, bundle = false, wrapper } = options;
1816
+ }, group, exclude = [], include, override = [], urlType = false, dataReturnType = "data", paramsType = "inline", pathParamsType = paramsType === "object" ? "object" : options.pathParamsType || "inline", operations = false, paramsCasing, clientType = "function", parser = "client", client = "axios", importPath, bundle = false, wrapper, baseURL, compatibilityPreset = "default", resolver: userResolver, transformer: userTransformer } = options;
18
1817
  const resolvedImportPath = importPath ?? (!bundle ? `@kubb/plugin-client/clients/${client}` : void 0);
19
- const defaultGenerators = [
20
- clientType === "staticClass" ? staticClassClientGenerator : clientType === "class" ? classClientGenerator : clientGenerator,
21
- group && clientType === "function" ? groupedClientGenerator : void 0,
22
- operations ? operationsGenerator : void 0
23
- ].filter((x) => Boolean(x));
24
- const generators = options.generators ?? defaultGenerators;
1818
+ const preset = getPreset({
1819
+ preset: compatibilityPreset,
1820
+ presets,
1821
+ resolver: userResolver,
1822
+ transformer: userTransformer,
1823
+ generators: options.generators ?? [
1824
+ clientType === "staticClass" ? staticClassClientGenerator : clientType === "class" ? classClientGenerator : clientGenerator,
1825
+ group && clientType === "function" ? groupedClientGenerator : void 0,
1826
+ operations ? operationsGenerator : void 0
1827
+ ].filter((x) => Boolean(x))
1828
+ });
1829
+ const mergedGenerator = mergeGenerators(preset.generators ?? []);
1830
+ let resolveNameWarning = false;
1831
+ let resolvePathWarning = false;
25
1832
  return {
26
1833
  name: pluginClientName,
27
- options: {
28
- client,
29
- clientType,
30
- bundle,
31
- output,
32
- group,
33
- parser,
34
- dataReturnType,
35
- importPath: resolvedImportPath,
36
- paramsType,
37
- paramsCasing,
38
- pathParamsType,
39
- baseURL,
40
- urlType,
41
- wrapper
1834
+ version,
1835
+ get resolver() {
1836
+ return preset.resolver;
1837
+ },
1838
+ get transformer() {
1839
+ return preset.transformer;
42
1840
  },
43
- pre: [pluginOasName, parser === "zod" ? pluginZodName : void 0].filter(Boolean),
1841
+ get options() {
1842
+ return {
1843
+ client,
1844
+ clientType,
1845
+ bundle,
1846
+ output,
1847
+ exclude,
1848
+ include,
1849
+ override,
1850
+ group: group ? {
1851
+ ...group,
1852
+ name: group.name ? group.name : (ctx) => {
1853
+ if (group.type === "path") return `${ctx.group.split("/")[1]}`;
1854
+ return `${camelCase(ctx.group)}Controller`;
1855
+ }
1856
+ } : void 0,
1857
+ parser,
1858
+ dataReturnType,
1859
+ importPath: resolvedImportPath,
1860
+ baseURL,
1861
+ paramsType,
1862
+ paramsCasing,
1863
+ pathParamsType,
1864
+ urlType,
1865
+ wrapper,
1866
+ resolver: preset.resolver
1867
+ };
1868
+ },
1869
+ pre: [pluginTsName, parser === "zod" ? pluginZodName : void 0].filter(Boolean),
44
1870
  resolvePath(baseName, pathMode, options) {
45
- const root = path.resolve(this.config.root, this.config.output.path);
46
- if ((pathMode ?? getMode(path.resolve(root, output.path))) === "single")
47
- /**
48
- * when output is a file then we will always append to the same file(output file), see fileManager.addOrAppend
49
- * Other plugins then need to call addOrAppend instead of just add from the fileManager class
50
- */
51
- return path.resolve(root, output.path);
52
- if (group && (options?.group?.path || options?.group?.tag)) {
53
- const groupName = group?.name ? group.name : (ctx) => {
54
- if (group?.type === "path") return `${ctx.group.split("/")[1]}`;
55
- return `${camelCase(ctx.group)}Controller`;
56
- };
57
- return path.resolve(root, output.path, groupName({ group: group.type === "path" ? options.group.path : options.group.tag }), baseName);
1871
+ if (!resolvePathWarning) {
1872
+ this.warn("Do not use resolvePath for pluginClient, use resolverClient.resolvePath instead");
1873
+ resolvePathWarning = true;
58
1874
  }
59
- return path.resolve(root, output.path, baseName);
1875
+ return this.plugin.resolver.resolvePath({
1876
+ baseName,
1877
+ pathMode,
1878
+ tag: options?.group?.tag,
1879
+ path: options?.group?.path
1880
+ }, {
1881
+ root: this.root,
1882
+ output,
1883
+ group: this.plugin.options.group
1884
+ });
60
1885
  },
61
1886
  resolveName(name, type) {
62
- const resolvedName = camelCase(name, { isFile: type === "file" });
63
- if (type) return transformers?.name?.(resolvedName, type) || resolvedName;
64
- return resolvedName;
1887
+ if (!resolveNameWarning) {
1888
+ this.warn("Do not use resolveName for pluginClient, use resolverClient.default instead");
1889
+ resolveNameWarning = true;
1890
+ }
1891
+ return this.plugin.resolver.default(name, type);
65
1892
  },
66
- async install() {
67
- const root = path.resolve(this.config.root, this.config.output.path);
68
- const mode = getMode(path.resolve(root, output.path));
69
- const oas = await this.getOas();
70
- const baseURL = await this.getBaseURL();
71
- if (bundle && !this.plugin.options.importPath) await this.addFile({
1893
+ async operation(node, options) {
1894
+ return mergedGenerator.operation?.call(this, node, options);
1895
+ },
1896
+ async operations(nodes, options) {
1897
+ return mergedGenerator.operations?.call(this, nodes, options);
1898
+ },
1899
+ async buildStart() {
1900
+ const { plugin } = this;
1901
+ const root = this.root;
1902
+ if (bundle && !plugin.options.importPath) await this.addFile({
72
1903
  baseName: "fetch.ts",
73
1904
  path: path.resolve(root, ".kubb/fetch.ts"),
74
1905
  sources: [{
75
1906
  name: "fetch",
76
- value: this.plugin.options.client === "fetch" ? source$1 : source,
1907
+ value: plugin.options.client === "fetch" ? source$1 : source,
77
1908
  isExportable: true,
78
1909
  isIndexable: true
79
1910
  }],
@@ -92,33 +1923,10 @@ const pluginClient = definePlugin((options) => {
92
1923
  imports: [],
93
1924
  exports: []
94
1925
  });
95
- const files = await new OperationGenerator(baseURL ? {
96
- ...this.plugin.options,
97
- baseURL
98
- } : this.plugin.options, {
99
- fabric: this.fabric,
100
- oas,
101
- pluginManager: this.pluginManager,
102
- events: this.events,
103
- plugin: this.plugin,
104
- contentType,
105
- exclude,
106
- include,
107
- override,
108
- mode
109
- }).build(...generators);
110
- await this.upsertFile(...files);
111
- const barrelFiles = await getBarrelFiles(this.fabric.files, {
112
- type: output.barrelType ?? "named",
113
- root,
114
- output,
115
- meta: { pluginName: this.plugin.name }
116
- });
117
- await this.upsertFile(...barrelFiles);
118
1926
  }
119
1927
  };
120
1928
  });
121
1929
  //#endregion
122
- export { pluginClient, pluginClientName };
1930
+ export { Client, ClientLegacy, UrlLegacy, classClientGenerator, clientGenerator, groupedClientGenerator, operationsGenerator, pluginClient, pluginClientName, presets, resolverClient, resolverClientLegacy, staticClassClientGenerator };
123
1931
 
124
1932
  //# sourceMappingURL=index.js.map