@kubb/plugin-client 5.0.0-beta.56 → 5.5.2
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 +8 -61
- package/dist/index.cjs +754 -1745
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +170 -349
- package/dist/index.js +733 -1733
- package/dist/index.js.map +1 -1
- package/package.json +10 -63
- package/src/generators/clientGenerator.tsx +6 -132
- package/src/index.ts +1 -9
- package/src/plugin.ts +32 -122
- package/src/types.ts +27 -249
- package/dist/chunk-Bx3C2hgW.cjs +0 -38
- package/dist/clients/axios.cjs +0 -68
- package/dist/clients/axios.cjs.map +0 -1
- package/dist/clients/axios.d.ts +0 -49
- package/dist/clients/axios.js +0 -58
- package/dist/clients/axios.js.map +0 -1
- package/dist/clients/fetch.cjs +0 -128
- package/dist/clients/fetch.cjs.map +0 -1
- package/dist/clients/fetch.d.ts +0 -50
- package/dist/clients/fetch.js +0 -120
- package/dist/clients/fetch.js.map +0 -1
- package/dist/templates/clients/axios.source.cjs +0 -7
- package/dist/templates/clients/axios.source.cjs.map +0 -1
- package/dist/templates/clients/axios.source.d.ts +0 -7
- package/dist/templates/clients/axios.source.js +0 -6
- package/dist/templates/clients/axios.source.js.map +0 -1
- package/dist/templates/clients/fetch.source.cjs +0 -7
- package/dist/templates/clients/fetch.source.cjs.map +0 -1
- package/dist/templates/clients/fetch.source.d.ts +0 -7
- package/dist/templates/clients/fetch.source.js +0 -6
- package/dist/templates/clients/fetch.source.js.map +0 -1
- package/dist/templates/config.source.cjs +0 -7
- package/dist/templates/config.source.cjs.map +0 -1
- package/dist/templates/config.source.d.ts +0 -7
- package/dist/templates/config.source.js +0 -6
- package/dist/templates/config.source.js.map +0 -1
- package/src/clients/axios.ts +0 -113
- package/src/clients/fetch.ts +0 -201
- package/src/components/ClassClient.tsx +0 -161
- package/src/components/Client.tsx +0 -281
- package/src/components/StaticClassClient.tsx +0 -153
- package/src/components/Url.tsx +0 -90
- package/src/components/WrapperClient.tsx +0 -33
- package/src/functionParams.ts +0 -118
- package/src/generators/classClientGenerator.tsx +0 -261
- package/src/generators/groupedClientGenerator.tsx +0 -82
- package/src/generators/operationsGenerator.ts +0 -47
- package/src/generators/staticClassClientGenerator.tsx +0 -240
- package/src/resolvers/resolverClient.ts +0 -46
- package/src/templates/clients/axios.source.ts +0 -4
- package/src/templates/clients/fetch.source.ts +0 -4
- package/src/templates/config.source.ts +0 -4
- package/src/utils.ts +0 -259
- /package/dist/{chunk-C0LytTxp.js → rolldown-runtime-C0LytTxp.js} +0 -0
package/dist/index.cjs
CHANGED
|
@@ -2,19 +2,241 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
//#region \0rolldown/runtime.js
|
|
6
|
+
var __create = Object.create;
|
|
7
|
+
var __defProp = Object.defineProperty;
|
|
8
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
9
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
10
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
11
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
14
|
+
key = keys[i];
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
16
|
+
get: ((k) => from[k]).bind(null, key),
|
|
17
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
return to;
|
|
21
|
+
};
|
|
22
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
|
|
23
|
+
value: mod,
|
|
24
|
+
enumerable: true
|
|
25
|
+
}) : target, mod));
|
|
26
|
+
//#endregion
|
|
27
|
+
let kubb_kit = require("kubb/kit");
|
|
9
28
|
let node_path = require("node:path");
|
|
10
|
-
|
|
11
|
-
node_path = require_chunk.__toESM(node_path);
|
|
12
|
-
let _kubb_core = require("@kubb/core");
|
|
13
|
-
let _kubb_ast_utils = require("@kubb/ast/utils");
|
|
29
|
+
node_path = __toESM(node_path, 1);
|
|
14
30
|
let _kubb_plugin_ts = require("@kubb/plugin-ts");
|
|
15
|
-
let _kubb_renderer_jsx = require("@kubb/renderer-jsx");
|
|
16
|
-
let _kubb_renderer_jsx_jsx_runtime = require("@kubb/renderer-jsx/jsx-runtime");
|
|
17
31
|
let _kubb_plugin_zod = require("@kubb/plugin-zod");
|
|
32
|
+
let kubb_jsx = require("kubb/jsx");
|
|
33
|
+
let kubb_jsx_jsx_runtime = require("kubb/jsx/jsx-runtime");
|
|
34
|
+
//#region ../../internals/shared/src/params.ts
|
|
35
|
+
/**
|
|
36
|
+
* Drops parameters that share the same name, keeping the first.
|
|
37
|
+
*
|
|
38
|
+
* A malformed spec can declare the same parameter name twice within one `in` location. Both would
|
|
39
|
+
* resolve to the same output property, so emitting both would yield an object type with a duplicate
|
|
40
|
+
* member, which TypeScript rejects. This is a defensive guard against that case, not a casing guard:
|
|
41
|
+
* parameter names flow through unchanged, so no two distinct names ever collide here anymore.
|
|
42
|
+
*/
|
|
43
|
+
function dedupeParams(params) {
|
|
44
|
+
const seen = /* @__PURE__ */ new Set();
|
|
45
|
+
return params.filter((param) => {
|
|
46
|
+
if (seen.has(param.name)) return false;
|
|
47
|
+
seen.add(param.name);
|
|
48
|
+
return true;
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
//#endregion
|
|
52
|
+
//#region ../../internals/shared/src/operation.ts
|
|
53
|
+
/**
|
|
54
|
+
* Builds the `ResolverFileParams` every operation generator passes to
|
|
55
|
+
* `resolver.file`: a file named `name`, tagged by the operation's first
|
|
56
|
+
* tag (or `'default'`), at the operation's path. Centralizes the entry object
|
|
57
|
+
* that was repeated at dozens of call sites across the client and query plugins.
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```ts
|
|
61
|
+
* resolver.file(operationFileEntry(node, node.operationId), { root, output, group })
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
function operationFileEntry(node, name, extname = ".ts") {
|
|
65
|
+
return {
|
|
66
|
+
name,
|
|
67
|
+
extname,
|
|
68
|
+
tag: node.tags[0] ?? "default",
|
|
69
|
+
path: node.path
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Resolves a dependency plugin's generated file for `node.operationId`, cached in `cache` (the
|
|
74
|
+
* current node's `ctx.cache`) under the resolver's own plugin name. Several dependents reading the
|
|
75
|
+
* same dependency for the same operation in one pass (a query plugin's several hook generators, the
|
|
76
|
+
* MCP handler, ...) share one computed name and path instead of each calling `resolver.file` again.
|
|
77
|
+
*
|
|
78
|
+
* @example Cache `plugin-ts`'s file for the current operation
|
|
79
|
+
* ```ts
|
|
80
|
+
* const fileTs = resolveDependencyOperationFile({ cache: ctx.cache, node, resolver: tsResolver, root, output })
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
function resolveDependencyOperationFile(options) {
|
|
84
|
+
const { cache, node, resolver, root, output, group } = options;
|
|
85
|
+
return cache.ensureItem(`${resolver.pluginName}:operationFile`, () => resolver.file({
|
|
86
|
+
...operationFileEntry(node, node.operationId),
|
|
87
|
+
root,
|
|
88
|
+
output,
|
|
89
|
+
group: group ?? void 0
|
|
90
|
+
}));
|
|
91
|
+
}
|
|
92
|
+
function getOperationLink(node, link) {
|
|
93
|
+
if (!link) return null;
|
|
94
|
+
if (typeof link === "function") return link(node) ?? null;
|
|
95
|
+
return node.path ? `{@link ${kubb_kit.Url.toPath(node.path)}}` : null;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Derives the shared `ContentTypeInfo` shape from a list of content types, tracking whether several
|
|
99
|
+
* are present and the union, default, and form-data flags the client uses to pick one.
|
|
100
|
+
*/
|
|
101
|
+
function buildContentTypeInfo(contentTypes) {
|
|
102
|
+
const isMultipleContentTypes = contentTypes.length > 1;
|
|
103
|
+
return {
|
|
104
|
+
contentTypes,
|
|
105
|
+
isMultipleContentTypes,
|
|
106
|
+
contentTypeUnion: isMultipleContentTypes ? contentTypes.map((ct) => JSON.stringify(ct)).join(" | ") : "",
|
|
107
|
+
defaultContentType: contentTypes[0] ?? "application/json",
|
|
108
|
+
hasFormData: contentTypes.some((ct) => ct === "multipart/form-data")
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
function getContentTypeInfo(node) {
|
|
112
|
+
return buildContentTypeInfo(node.requestBody?.content?.map((e) => e.contentType) ?? []);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* The request-body counterpart for the primary success response: the content types it documents and
|
|
116
|
+
* whether several are present, so the client can let a caller pick which one to accept.
|
|
117
|
+
*/
|
|
118
|
+
function getResponseContentTypeInfo(node) {
|
|
119
|
+
return buildContentTypeInfo(getPrimarySuccessResponse(node)?.content?.map((e) => e.contentType) ?? []);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Reads the single base content type of an operation's primary success response, lowercased and
|
|
123
|
+
* stripped of any `; charset=...` suffix. Returns `undefined` when the response declares zero or
|
|
124
|
+
* more than one content type, since neither case has a single type to act on.
|
|
125
|
+
*/
|
|
126
|
+
function getPrimarySuccessContentType(node) {
|
|
127
|
+
const contentTypes = getPrimarySuccessResponse(node)?.content?.map((entry) => entry.contentType) ?? [];
|
|
128
|
+
if (contentTypes.length !== 1) return void 0;
|
|
129
|
+
return contentTypes[0].split(";")[0].trim().toLowerCase();
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Whether an operation streams its primary success response as Server-Sent Events
|
|
133
|
+
* (`text/event-stream`). The client generator uses this to return a typed event stream instead of a
|
|
134
|
+
* one-shot `RequestResult`.
|
|
135
|
+
*/
|
|
136
|
+
function isEventStream(node) {
|
|
137
|
+
return getPrimarySuccessContentType(node) === "text/event-stream";
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Derives the default `responseType` for an operation from its primary success response.
|
|
141
|
+
*
|
|
142
|
+
* Returns a value only when that response declares a single non-JSON content type. `text/event-stream`
|
|
143
|
+
* and other binary types (`application/octet-stream`, `application/pdf`, `image/*`, `audio/*`,
|
|
144
|
+
* `video/*`) map to a stream or `'blob'`, and other `text/*` maps to `'text'`. Otherwise `undefined`,
|
|
145
|
+
* leaving the runtime client's `Content-Type` auto-detection in charge.
|
|
146
|
+
*/
|
|
147
|
+
function getResponseType(node) {
|
|
148
|
+
const baseType = getPrimarySuccessContentType(node);
|
|
149
|
+
if (!baseType) return void 0;
|
|
150
|
+
if (baseType === "application/json" || baseType.endsWith("+json") || baseType === "text/json") return void 0;
|
|
151
|
+
if (baseType === "text/event-stream") return "stream";
|
|
152
|
+
if (baseType.startsWith("text/")) return "text";
|
|
153
|
+
if (baseType === "application/octet-stream" || baseType === "application/pdf" || /^(image|audio|video)\//.test(baseType)) return "blob";
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Which of the grouped request options an operation carries.
|
|
157
|
+
*/
|
|
158
|
+
function getRequestGroups(node) {
|
|
159
|
+
const { path, query, header } = getOperationParameters(node);
|
|
160
|
+
return {
|
|
161
|
+
path: path.length > 0,
|
|
162
|
+
query: query.length > 0,
|
|
163
|
+
body: Boolean(node.requestBody?.content?.[0]?.schema),
|
|
164
|
+
headers: header.length > 0
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Resolves which grouped request options an operation carries together with whether each group
|
|
169
|
+
* holds a required member. The grouped parameter stays optional only when nothing inside it is
|
|
170
|
+
* required, matching the generated `RequestConfig` type.
|
|
171
|
+
*/
|
|
172
|
+
function getRequestGroupOptionality(node) {
|
|
173
|
+
const groups = getRequestGroups(node);
|
|
174
|
+
const { path, query, header } = getOperationParameters(node);
|
|
175
|
+
const hasRequiredPath = path.some((param) => param.required);
|
|
176
|
+
const hasRequiredQuery = query.some((param) => param.required);
|
|
177
|
+
const hasRequiredHeader = header.some((param) => param.required);
|
|
178
|
+
return {
|
|
179
|
+
groups,
|
|
180
|
+
hasRequiredPath,
|
|
181
|
+
hasRequiredQuery,
|
|
182
|
+
hasRequiredHeader,
|
|
183
|
+
isOptional: !hasRequiredPath && !hasRequiredQuery && !hasRequiredHeader && !groups.body
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
function buildOperationComments(node, options = {}) {
|
|
187
|
+
const { link = "pathTemplate", linkPosition = "afterDeprecated", splitLines = false } = options;
|
|
188
|
+
const linkComment = getOperationLink(node, link);
|
|
189
|
+
const filteredComments = (linkPosition === "beforeDeprecated" ? [
|
|
190
|
+
node.description && `@description ${node.description}`,
|
|
191
|
+
node.summary && `@summary ${node.summary}`,
|
|
192
|
+
linkComment,
|
|
193
|
+
node.deprecated && "@deprecated"
|
|
194
|
+
] : [
|
|
195
|
+
node.description && `@description ${node.description}`,
|
|
196
|
+
node.summary && `@summary ${node.summary}`,
|
|
197
|
+
node.deprecated && "@deprecated",
|
|
198
|
+
linkComment
|
|
199
|
+
]).filter((comment) => Boolean(comment));
|
|
200
|
+
if (!splitLines) return filteredComments;
|
|
201
|
+
return filteredComments.flatMap((text) => text.split(/\r?\n/).map((line) => line.trim())).filter((comment) => Boolean(comment));
|
|
202
|
+
}
|
|
203
|
+
const operationParameterGroupsByNode = /* @__PURE__ */ new WeakMap();
|
|
204
|
+
/**
|
|
205
|
+
* Groups an operation's parameters by location (`path`/`query`/`header`/`cookie`), deduping each
|
|
206
|
+
* group by name. Every plugin generator visiting the same `OperationNode` shares one AST instance
|
|
207
|
+
* (see `KubbDriver`), so the result is cached per node to avoid re-filtering and re-deduping the
|
|
208
|
+
* same parameters once per plugin.
|
|
209
|
+
*/
|
|
210
|
+
function getOperationParameters(node) {
|
|
211
|
+
const cached = operationParameterGroupsByNode.get(node);
|
|
212
|
+
if (cached) return cached;
|
|
213
|
+
const groups = {
|
|
214
|
+
path: dedupeParams(node.parameters.filter((param) => param.in === "path")),
|
|
215
|
+
query: dedupeParams(node.parameters.filter((param) => param.in === "query")),
|
|
216
|
+
header: dedupeParams(node.parameters.filter((param) => param.in === "header")),
|
|
217
|
+
cookie: dedupeParams(node.parameters.filter((param) => param.in === "cookie"))
|
|
218
|
+
};
|
|
219
|
+
operationParameterGroupsByNode.set(node, groups);
|
|
220
|
+
return groups;
|
|
221
|
+
}
|
|
222
|
+
function getStatusCodeNumber(statusCode) {
|
|
223
|
+
const code = Number(statusCode);
|
|
224
|
+
return Number.isNaN(code) ? null : code;
|
|
225
|
+
}
|
|
226
|
+
function isSuccessStatusCode(statusCode) {
|
|
227
|
+
const code = getStatusCodeNumber(statusCode);
|
|
228
|
+
return code !== null && code >= 200 && code < 300;
|
|
229
|
+
}
|
|
230
|
+
function getSuccessResponses(responses) {
|
|
231
|
+
return responses.filter((response) => isSuccessStatusCode(response.statusCode));
|
|
232
|
+
}
|
|
233
|
+
function getOperationSuccessResponses(node) {
|
|
234
|
+
return getSuccessResponses(node.responses);
|
|
235
|
+
}
|
|
236
|
+
function getPrimarySuccessResponse(node) {
|
|
237
|
+
return getOperationSuccessResponses(node)[0] ?? null;
|
|
238
|
+
}
|
|
239
|
+
//#endregion
|
|
18
240
|
//#region ../../internals/utils/src/casing.ts
|
|
19
241
|
/**
|
|
20
242
|
* Shared implementation for camelCase and PascalCase conversion.
|
|
@@ -54,37 +276,12 @@ function pascalCase(text, { prefix = "", suffix = "" } = {}) {
|
|
|
54
276
|
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true);
|
|
55
277
|
}
|
|
56
278
|
//#endregion
|
|
57
|
-
//#region ../../internals/utils/src/fs.ts
|
|
58
|
-
/**
|
|
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 `/`.
|
|
62
|
-
*
|
|
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'`
|
|
76
|
-
*/
|
|
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("/");
|
|
80
|
-
}
|
|
81
|
-
//#endregion
|
|
82
279
|
//#region ../../internals/utils/src/reserved.ts
|
|
83
280
|
/**
|
|
84
281
|
* JavaScript and Java reserved words.
|
|
85
282
|
* @link https://github.com/jonschlinkert/reserved/blob/master/index.js
|
|
86
283
|
*/
|
|
87
|
-
const reservedWords = new Set([
|
|
284
|
+
const reservedWords = /* @__PURE__ */ new Set([
|
|
88
285
|
"abstract",
|
|
89
286
|
"arguments",
|
|
90
287
|
"boolean",
|
|
@@ -179,7 +376,7 @@ const reservedWords = new Set([
|
|
|
179
376
|
*/
|
|
180
377
|
function isValidVarName(name) {
|
|
181
378
|
if (!name || reservedWords.has(name)) return false;
|
|
182
|
-
return
|
|
379
|
+
return isIdentifier(name);
|
|
183
380
|
}
|
|
184
381
|
/**
|
|
185
382
|
* Returns `name` when it's a syntactically valid JavaScript variable name,
|
|
@@ -201,252 +398,21 @@ function ensureValidVarName(name) {
|
|
|
201
398
|
if (!name || isValidVarName(name)) return name;
|
|
202
399
|
return `_${name}`;
|
|
203
400
|
}
|
|
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;
|
|
216
|
-
}
|
|
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");
|
|
225
|
-
}
|
|
226
|
-
/**
|
|
227
|
-
* Reports whether `url` is a parseable absolute URL. Delegates to the native `URL.canParse`.
|
|
228
|
-
*
|
|
229
|
-
* @example
|
|
230
|
-
* Url.canParse('https://petstore.swagger.io/v2') // true
|
|
231
|
-
* Url.canParse('/pet/{petId}') // false
|
|
232
|
-
*/
|
|
233
|
-
static canParse(url, base) {
|
|
234
|
-
return URL.canParse(url, base);
|
|
235
|
-
}
|
|
236
|
-
/**
|
|
237
|
-
* Converts an OpenAPI/Swagger path to Express-style colon syntax.
|
|
238
|
-
*
|
|
239
|
-
* @example
|
|
240
|
-
* Url.toPath('/pet/{petId}') // '/pet/:petId'
|
|
241
|
-
*/
|
|
242
|
-
static toPath(path) {
|
|
243
|
-
return path.replace(/\{([^}]+)\}/g, ":$1");
|
|
244
|
-
}
|
|
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.
|
|
249
|
-
*
|
|
250
|
-
* @example
|
|
251
|
-
* Url.toTemplateString('/pet/{petId}') // '`/pet/${petId}`'
|
|
252
|
-
*
|
|
253
|
-
* @example
|
|
254
|
-
* Url.toTemplateString('/pet/{petId}', { prefix: 'https://api' }) // '`https://api/pet/${petId}`'
|
|
255
|
-
*/
|
|
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}\``;
|
|
263
|
-
}
|
|
264
|
-
/**
|
|
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' } }
|
|
271
|
-
*/
|
|
272
|
-
static toObject(path, { type = "path", replacer, stringify, casing } = {}) {
|
|
273
|
-
const object = {
|
|
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
|
-
})
|
|
282
|
-
};
|
|
283
|
-
if (stringify) {
|
|
284
|
-
if (type === "template") return JSON.stringify(object).replaceAll("'", "").replaceAll(`"`, "");
|
|
285
|
-
if (object.params) return `{ url: '${object.url}', params: ${JSON.stringify(object.params).replaceAll("'", "").replaceAll(`"`, "")} }`;
|
|
286
|
-
return `{ url: '${object.url}' }`;
|
|
287
|
-
}
|
|
288
|
-
return object;
|
|
289
|
-
}
|
|
290
|
-
};
|
|
291
|
-
//#endregion
|
|
292
|
-
//#region ../../internals/shared/src/operation.ts
|
|
293
401
|
/**
|
|
294
|
-
*
|
|
295
|
-
*
|
|
296
|
-
*
|
|
297
|
-
*
|
|
402
|
+
* Returns `true` when `name` is syntactically a valid identifier, ignoring reserved words.
|
|
403
|
+
*
|
|
404
|
+
* Reserved words and globals (`class`, `name`, `Date`, …) are valid as bare object-literal keys
|
|
405
|
+
* even though they are not valid variable names, so use this (not {@link isValidVarName}) when
|
|
406
|
+
* deciding whether an object key needs quoting.
|
|
298
407
|
*
|
|
299
408
|
* @example
|
|
300
409
|
* ```ts
|
|
301
|
-
*
|
|
410
|
+
* isIdentifier('name') // true
|
|
411
|
+
* isIdentifier('x-total')// false
|
|
302
412
|
* ```
|
|
303
413
|
*/
|
|
304
|
-
function
|
|
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;
|
|
414
|
+
function isIdentifier(name) {
|
|
415
|
+
return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
|
|
450
416
|
}
|
|
451
417
|
//#endregion
|
|
452
418
|
//#region ../../internals/shared/src/group.ts
|
|
@@ -480,1612 +446,655 @@ function createGroupConfig(group) {
|
|
|
480
446
|
};
|
|
481
447
|
}
|
|
482
448
|
//#endregion
|
|
483
|
-
//#region ../../internals/
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
449
|
+
//#region ../../internals/client/src/builders/generics.ts
|
|
450
|
+
/**
|
|
451
|
+
* Builds the `RequestResult` generic arguments for one operation: the per-status responses record
|
|
452
|
+
* plus the per-call `ThrowOnError` flag. `SuccessOf` / `ErrorOf` split the record inside the
|
|
453
|
+
* runtime, so this only names the record and threads `ThrowOnError`.
|
|
454
|
+
*
|
|
455
|
+
* @example
|
|
456
|
+
* `buildRequestResultGenerics({ node, types }) // 'AddPetResponses, ThrowOnError'`
|
|
457
|
+
*/
|
|
458
|
+
function buildRequestResultGenerics({ node, types }) {
|
|
459
|
+
return `${types.response.responses(node)}, ThrowOnError`;
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* Builds the full return type an operation's function signature uses: `Unwrappable<RequestResult>`
|
|
463
|
+
* for the default `returnType: 'full'`, already a promise so no further wrapping is needed, a plain
|
|
464
|
+
* `Promise<RequestResult>` for the internal `'plain'` shape, or a
|
|
465
|
+
* `Promise` of the runtime's `UnwrappedResult` when `returnType: 'data'` narrows a resolved call
|
|
466
|
+
* down to the bare success body.
|
|
467
|
+
*
|
|
468
|
+
* @example
|
|
469
|
+
* `buildResultType({ node, types, returnType: 'data' }) // 'Promise<UnwrappedResult<AddPetResponses, ThrowOnError>>'`
|
|
470
|
+
*/
|
|
471
|
+
function buildResultType({ node, types, returnType }) {
|
|
472
|
+
const generics = buildRequestResultGenerics({
|
|
473
|
+
node,
|
|
474
|
+
types
|
|
491
475
|
});
|
|
492
|
-
|
|
476
|
+
if (returnType === "data") return `Promise<UnwrappedResult<${generics}>>`;
|
|
477
|
+
if (returnType === "plain") return `Promise<RequestResult<${generics}>>`;
|
|
478
|
+
return `Unwrappable<RequestResult<${generics}>>`;
|
|
493
479
|
}
|
|
494
480
|
//#endregion
|
|
495
|
-
//#region src/
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
481
|
+
//#region ../../internals/client/src/builders/returnStatement.ts
|
|
482
|
+
/**
|
|
483
|
+
* Builds the return statement of a generated operation function. With the default
|
|
484
|
+
* `returnType: 'full'` the runtime call already resolves to `{ data, error, request, response }`.
|
|
485
|
+
* The generated code casts that result to the operation's `RequestResult`, then wraps it with
|
|
486
|
+
* `withUnwrap`, so the caller can `await` it directly or call `.unwrap()` for the bare success
|
|
487
|
+
* body. With `returnType: 'data'` it instead routes the call through the runtime's `unwrapResult`,
|
|
488
|
+
* which narrows the resolved value down to the bare success body the same way `RequestResult`
|
|
489
|
+
* already does, using the plugin default when the call leaves `throwOnError` unset.
|
|
490
|
+
* With `returnType: 'plain'` it returns the runtime call as is, cast to `RequestResult`, with no helper.
|
|
491
|
+
*
|
|
492
|
+
* Cast first, wrap second, for the `'full'` path. That order keeps `withUnwrap`'s generic inferred
|
|
493
|
+
* as `RequestResult` instead of the runtime's own internal result type. Casting an `Unwrappable<A>`
|
|
494
|
+
* straight to `Unwrappable<B>` does not work: the `.then` overload stays pinned to `A`, and `as`
|
|
495
|
+
* rejects that two-generic swap even where `A` and `B` on their own would satisfy it.
|
|
496
|
+
*
|
|
497
|
+
* @example
|
|
498
|
+
* `return withUnwrap(request({ method: 'POST', url: '/pet', ...config }) as Promise<RequestResult<AddPetResponses, ThrowOnError>>)`
|
|
499
|
+
* @example
|
|
500
|
+
* `return unwrapResult(request({ method: 'POST', url: '/pet', ...config }), config.throwOnError ?? false) as Promise<UnwrappedResult<AddPetResponses, ThrowOnError>>`
|
|
501
|
+
* @example
|
|
502
|
+
* `return request({ method: 'POST', url: '/pet', ...config }) as Promise<RequestResult<AddPetResponses, ThrowOnError>>`
|
|
503
|
+
*/
|
|
504
|
+
function buildReturnStatement({ node, types, callConfig, returnType, throwOnErrorDefault }) {
|
|
505
|
+
if (returnType === "data") return `return unwrapResult(request(${callConfig}), config.throwOnError ?? ${throwOnErrorDefault}) as ${buildResultType({
|
|
506
|
+
node,
|
|
507
|
+
types,
|
|
508
|
+
returnType
|
|
509
|
+
})}`;
|
|
510
|
+
if (returnType === "plain") return `return request(${callConfig}) as Promise<RequestResult<${buildRequestResultGenerics({
|
|
511
|
+
node,
|
|
512
|
+
types
|
|
513
|
+
})}>>`;
|
|
514
|
+
return `return withUnwrap(request(${callConfig}) as Promise<RequestResult<${buildRequestResultGenerics({
|
|
515
|
+
node,
|
|
516
|
+
types
|
|
517
|
+
})}>>)`;
|
|
500
518
|
}
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
name,
|
|
510
|
-
type: createType(spec.type) ?? void 0,
|
|
511
|
-
default: spec.default,
|
|
512
|
-
rest: spec.mode === "inlineSpread"
|
|
513
|
-
});
|
|
514
|
-
return _kubb_core.ast.createFunctionParameter({
|
|
515
|
-
name,
|
|
516
|
-
type: createType(spec.type) ?? void 0,
|
|
517
|
-
optional: !!spec.optional,
|
|
518
|
-
rest: spec.mode === "inlineSpread"
|
|
519
|
-
});
|
|
520
|
-
}
|
|
521
|
-
function createDeclarationParam(name, spec) {
|
|
522
|
-
if (isGroup(spec)) return _kubb_core.ast.createParameterGroup({
|
|
523
|
-
inline: spec.mode === "inlineSpread",
|
|
524
|
-
default: spec.default,
|
|
525
|
-
properties: Object.entries(spec.children).filter(([, child]) => child != null).map(([childName, child]) => createDeclarationLeaf(childName, child))
|
|
526
|
-
});
|
|
527
|
-
return createDeclarationLeaf(name, spec);
|
|
528
|
-
}
|
|
529
|
-
function createCallParam(name, spec) {
|
|
530
|
-
if (isGroup(spec)) return _kubb_core.ast.createParameterGroup({
|
|
531
|
-
inline: spec.mode === "inlineSpread",
|
|
532
|
-
properties: Object.entries(spec.children).filter(([, child]) => child != null).map(([childName, child]) => _kubb_core.ast.createFunctionParameter({
|
|
533
|
-
name: child?.mode === "inlineSpread" ? spec.mode === "inlineSpread" ? child.value ?? childName : `...${child.value ?? childName}` : child?.value ? `${childName}: ${child.value}` : childName,
|
|
534
|
-
rest: spec.mode === "inlineSpread" && child?.mode === "inlineSpread"
|
|
535
|
-
}))
|
|
536
|
-
});
|
|
537
|
-
return _kubb_core.ast.createFunctionParameter({
|
|
538
|
-
name: spec.value ?? name,
|
|
539
|
-
rest: spec.mode === "inlineSpread"
|
|
540
|
-
});
|
|
519
|
+
//#endregion
|
|
520
|
+
//#region ../../internals/client/src/builders/security.ts
|
|
521
|
+
function serializeAuth(auth) {
|
|
522
|
+
const parts = [`type: '${auth.type}'`];
|
|
523
|
+
if (auth.scheme) parts.push(`scheme: '${auth.scheme}'`);
|
|
524
|
+
if (auth.name) parts.push(`name: '${auth.name}'`);
|
|
525
|
+
if (auth.in) parts.push(`in: '${auth.in}'`);
|
|
526
|
+
return `{ ${parts.join(", ")} }`;
|
|
541
527
|
}
|
|
542
528
|
/**
|
|
543
|
-
*
|
|
544
|
-
*
|
|
529
|
+
* Maps an OpenAPI security scheme to the inline `Auth` object, or `null` when the runtime cannot
|
|
530
|
+
* place it (an unresolved `$ref`, or an `apiKey` without a name or outside `header` / `query` /
|
|
531
|
+
* `cookie`). `http` schemes other than `basic` are treated as bearer.
|
|
545
532
|
*/
|
|
546
|
-
function
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
}
|
|
533
|
+
function resolveSecurityScheme(scheme) {
|
|
534
|
+
if (!scheme || "$ref" in scheme) return null;
|
|
535
|
+
if (scheme.type === "apiKey") {
|
|
536
|
+
if (!scheme.name || scheme.in !== "header" && scheme.in !== "query" && scheme.in !== "cookie") return null;
|
|
537
|
+
return {
|
|
538
|
+
type: "apiKey",
|
|
539
|
+
name: scheme.name,
|
|
540
|
+
in: scheme.in
|
|
541
|
+
};
|
|
542
|
+
}
|
|
543
|
+
if (scheme.type === "http") return {
|
|
544
|
+
type: "http",
|
|
545
|
+
scheme: scheme.scheme?.toLowerCase() === "basic" ? "basic" : "bearer"
|
|
555
546
|
};
|
|
547
|
+
if (scheme.type === "oauth2") return { type: "oauth2" };
|
|
548
|
+
if (scheme.type === "openIdConnect") return { type: "openIdConnect" };
|
|
549
|
+
return null;
|
|
556
550
|
}
|
|
557
|
-
//#endregion
|
|
558
|
-
//#region src/utils.ts
|
|
559
551
|
/**
|
|
560
|
-
*
|
|
552
|
+
* Derives the per-operation security metadata from the OpenAPI document. The operation's own
|
|
553
|
+
* `security` overrides the global `security` (an explicit empty array disables auth), and every
|
|
554
|
+
* referenced scheme is resolved from `components.securitySchemes` into a flat, de-duplicated list of
|
|
555
|
+
* `Auth` objects the runtime walks in order.
|
|
556
|
+
*
|
|
557
|
+
* @example
|
|
558
|
+
* `getOperationSecurity({ document, method: 'POST', path: '/pet' })`
|
|
559
|
+
* `// [{ type: 'http', scheme: 'bearer' }]`
|
|
561
560
|
*/
|
|
562
|
-
function
|
|
563
|
-
if (!
|
|
564
|
-
|
|
565
|
-
|
|
561
|
+
function getOperationSecurity({ document, method, path }) {
|
|
562
|
+
if (!document) return void 0;
|
|
563
|
+
const requirements = (document.paths?.[path]?.[method.toLowerCase()])?.security ?? document.security;
|
|
564
|
+
if (!requirements?.length) return void 0;
|
|
565
|
+
const definitions = document.components?.securitySchemes ?? {};
|
|
566
|
+
const security = [];
|
|
567
|
+
const seen = /* @__PURE__ */ new Set();
|
|
568
|
+
for (const requirement of requirements) for (const schemeName of Object.keys(requirement)) {
|
|
569
|
+
if (seen.has(schemeName)) continue;
|
|
570
|
+
seen.add(schemeName);
|
|
571
|
+
const auth = resolveSecurityScheme(definitions[schemeName]);
|
|
572
|
+
if (auth) security.push(auth);
|
|
573
|
+
}
|
|
574
|
+
return security.length ? security : void 0;
|
|
566
575
|
}
|
|
567
576
|
/**
|
|
568
|
-
*
|
|
569
|
-
* The
|
|
577
|
+
* Serializes the per-operation security into the literal emitted on each generated call's `security`
|
|
578
|
+
* field. The runtime `resolveAuth` helper walks it, calling the configured `auth` resolver per entry.
|
|
579
|
+
*
|
|
580
|
+
* @example
|
|
581
|
+
* `buildSecurityMetadata({ security: [{ type: 'http', scheme: 'bearer' }] }) // "[{ type: 'http', scheme: 'bearer' }]"`
|
|
570
582
|
*/
|
|
571
|
-
function
|
|
572
|
-
if (!
|
|
573
|
-
|
|
574
|
-
return parser.request ?? null;
|
|
583
|
+
function buildSecurityMetadata({ security }) {
|
|
584
|
+
if (!security?.length) return null;
|
|
585
|
+
return `[${security.map(serializeAuth).join(", ")}]`;
|
|
575
586
|
}
|
|
587
|
+
//#endregion
|
|
588
|
+
//#region ../../internals/client/src/builders/signature.ts
|
|
589
|
+
const declarationPrinter = (0, _kubb_plugin_ts.functionPrinter)({ mode: "declaration" });
|
|
576
590
|
/**
|
|
577
|
-
*
|
|
578
|
-
*
|
|
579
|
-
*
|
|
591
|
+
* Builds the grouped-options signature for one operation: a single `options` object whose `TData`
|
|
592
|
+
* is the `<Name>Options` type, and a `RequestResult` return type keyed to the per-status responses
|
|
593
|
+
* record. There are no positional arguments.
|
|
594
|
+
*
|
|
595
|
+
* The generated file imports `<Name>Options` and `<Name>Responses` and uses them directly, so no
|
|
596
|
+
* per-operation input type has to be emitted. Both names come from `types`, which is `plugin-ts` or
|
|
597
|
+
* `plugin-zod`'s inferred types (see `resolveOperationTypes`).
|
|
580
598
|
*/
|
|
581
|
-
function
|
|
582
|
-
|
|
583
|
-
|
|
599
|
+
function buildGroupedOptionsSignature({ node, types, returnType, throwOnErrorDefault }) {
|
|
600
|
+
const optionsName = types.response.options(node);
|
|
601
|
+
const { isOptional } = getRequestGroupOptionality(node);
|
|
602
|
+
return {
|
|
603
|
+
paramsSignature: declarationPrinter.print((0, _kubb_plugin_ts.createFunctionParameters)({ params: [(0, _kubb_plugin_ts.createFunctionParameter)({
|
|
604
|
+
name: "options",
|
|
605
|
+
type: `Options<${optionsName}, ThrowOnError>`,
|
|
606
|
+
...isOptional ? { default: "{}" } : {}
|
|
607
|
+
})] })) ?? "",
|
|
608
|
+
returnType: buildResultType({
|
|
609
|
+
node,
|
|
610
|
+
types,
|
|
611
|
+
returnType
|
|
612
|
+
}),
|
|
613
|
+
generics: [`ThrowOnError extends boolean = ${throwOnErrorDefault}`]
|
|
614
|
+
};
|
|
584
615
|
}
|
|
616
|
+
//#endregion
|
|
617
|
+
//#region ../../internals/client/src/builders/validatorOptions.ts
|
|
585
618
|
/**
|
|
586
|
-
* Returns `'zod'` when
|
|
587
|
-
* `
|
|
619
|
+
* Returns `'zod'` when request body parsing is enabled, `null` otherwise. The string shorthand
|
|
620
|
+
* `'zod'` validates the response only, so it does not enable request parsing.
|
|
588
621
|
*/
|
|
589
|
-
function
|
|
590
|
-
if (!
|
|
591
|
-
|
|
592
|
-
return parser.response ?? null;
|
|
622
|
+
function resolveRequestValidator(validator) {
|
|
623
|
+
if (!validator || validator === "zod") return null;
|
|
624
|
+
return validator.request ?? null;
|
|
593
625
|
}
|
|
594
626
|
/**
|
|
595
|
-
*
|
|
596
|
-
*
|
|
627
|
+
* Returns `'zod'` when response parsing is enabled, `null` otherwise. The string shorthand `'zod'`
|
|
628
|
+
* maps to response parsing.
|
|
597
629
|
*/
|
|
598
|
-
function
|
|
599
|
-
|
|
630
|
+
function resolveResponseValidator(validator) {
|
|
631
|
+
if (!validator) return null;
|
|
632
|
+
if (validator === "zod") return "zod";
|
|
633
|
+
return validator.response ?? null;
|
|
600
634
|
}
|
|
601
635
|
/**
|
|
602
|
-
*
|
|
603
|
-
*
|
|
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).
|
|
636
|
+
* Resolves the zod expression a generated client validates a success response with. Only success
|
|
637
|
+
* (2xx) bodies reach the parse under the throw-on-error contract, so the success-only
|
|
638
|
+
* `<operation>ResponseSchema` is used; error bodies are never zod-parsed.
|
|
608
639
|
*/
|
|
609
|
-
function
|
|
610
|
-
const
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
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;
|
|
617
|
-
return [
|
|
618
|
-
responseName,
|
|
619
|
-
TError,
|
|
620
|
-
zodRequestName ? `z.output<typeof ${zodRequestName}>` : requestName || "unknown"
|
|
621
|
-
].filter(Boolean);
|
|
640
|
+
function buildZodResponseParse(node, zodResolver) {
|
|
641
|
+
const name = zodResolver.response.response(node);
|
|
642
|
+
return name ? {
|
|
643
|
+
expression: name,
|
|
644
|
+
importNames: [name]
|
|
645
|
+
} : null;
|
|
622
646
|
}
|
|
623
647
|
/**
|
|
624
|
-
*
|
|
625
|
-
*
|
|
648
|
+
* Resolves the zod expression a generated client validates an error body with on the non-throw path.
|
|
649
|
+
* Uses the error-only `<operation>ErrorSchema` (the union of non-2xx statuses); returns `null` when the
|
|
650
|
+
* operation documents no error responses with a schema.
|
|
626
651
|
*/
|
|
627
|
-
function
|
|
628
|
-
|
|
629
|
-
const
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
children: {
|
|
635
|
-
requestConfig: { mode: "inlineSpread" },
|
|
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
|
|
644
|
-
}
|
|
645
|
-
} });
|
|
652
|
+
function buildZodErrorParse(node, zodResolver) {
|
|
653
|
+
if (!node.responses.some((res) => !isSuccessStatusCode(res.statusCode) && res.content?.some((entry) => entry.schema))) return null;
|
|
654
|
+
const name = zodResolver.response.error?.(node);
|
|
655
|
+
return name ? {
|
|
656
|
+
expression: name,
|
|
657
|
+
importNames: [name]
|
|
658
|
+
} : null;
|
|
646
659
|
}
|
|
660
|
+
//#endregion
|
|
661
|
+
//#region ../../internals/client/src/builders/validator.ts
|
|
647
662
|
/**
|
|
648
|
-
* Builds the
|
|
649
|
-
*
|
|
663
|
+
* Builds the validator-hook references for one operation. Request validation runs before the send;
|
|
664
|
+
* response validation runs on the success body only. Returns `null` references when the matching
|
|
665
|
+
* direction is disabled or the schema is absent.
|
|
650
666
|
*/
|
|
651
|
-
function
|
|
652
|
-
const
|
|
653
|
-
const
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
667
|
+
function buildValidatorHooks({ node, validator, zodResolver }) {
|
|
668
|
+
const importedZodNames = [];
|
|
669
|
+
const hasRequestBody = Boolean(node.requestBody?.content?.[0]?.schema);
|
|
670
|
+
const zodRequestName = zodResolver && resolveRequestValidator(validator) === "zod" && hasRequestBody ? zodResolver.response.body(node) : null;
|
|
671
|
+
const request = zodRequestName ?? null;
|
|
672
|
+
if (zodRequestName) importedZodNames.push(zodRequestName);
|
|
673
|
+
const responseParse = zodResolver && resolveResponseValidator(validator) === "zod" ? buildZodResponseParse(node, zodResolver) : null;
|
|
674
|
+
const response = responseParse ? responseParse.expression : null;
|
|
675
|
+
if (responseParse) importedZodNames.push(...responseParse.importNames);
|
|
676
|
+
const errorParse = zodResolver && resolveResponseValidator(validator) === "zod" ? buildZodErrorParse(node, zodResolver) : null;
|
|
677
|
+
const error = errorParse ? errorParse.expression : null;
|
|
678
|
+
if (errorParse) importedZodNames.push(...errorParse.importNames);
|
|
679
|
+
return {
|
|
680
|
+
request,
|
|
681
|
+
response,
|
|
682
|
+
error,
|
|
683
|
+
importedZodNames
|
|
684
|
+
};
|
|
657
685
|
}
|
|
686
|
+
//#endregion
|
|
687
|
+
//#region ../../internals/client/src/builders/styles.ts
|
|
658
688
|
/**
|
|
659
|
-
*
|
|
660
|
-
*
|
|
661
|
-
*
|
|
689
|
+
* Renders a parameter name as an object-literal key, quoted when it is not a bare identifier.
|
|
690
|
+
* Path keys are camelCased to match the URL template placeholders. Query, header, and cookie keys
|
|
691
|
+
* keep the spec name, matching the remapped keys the runtime serializes.
|
|
662
692
|
*/
|
|
663
|
-
function
|
|
664
|
-
|
|
665
|
-
|
|
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)`;
|
|
693
|
+
function toKey(name, location) {
|
|
694
|
+
const key = location === "path" ? camelCase(name) : name;
|
|
695
|
+
return isValidVarName(key) ? key : JSON.stringify(key);
|
|
670
696
|
}
|
|
671
697
|
/**
|
|
672
|
-
*
|
|
673
|
-
*
|
|
698
|
+
* Serializes one parameter's metadata into a `{ style, explode }` literal, or `null` when the
|
|
699
|
+
* parameter carries neither. Path and query carry the serialization `style`; header and cookie use a
|
|
700
|
+
* fixed style (`simple` and `form`), so only `explode` is emitted for them.
|
|
674
701
|
*/
|
|
675
|
-
function
|
|
676
|
-
|
|
702
|
+
function serializeParameter(parameter) {
|
|
703
|
+
const parts = [];
|
|
704
|
+
if ((parameter.in === "path" || parameter.in === "query") && parameter.style) parts.push(`style: '${parameter.style}'`);
|
|
705
|
+
if (parameter.explode !== void 0) parts.push(`explode: ${parameter.explode}`);
|
|
706
|
+
return parts.length > 0 ? `{ ${parts.join(", ")} }` : null;
|
|
677
707
|
}
|
|
678
708
|
/**
|
|
679
|
-
* Builds the
|
|
680
|
-
*
|
|
681
|
-
*
|
|
709
|
+
* Builds the per-operation `styles` literal from the operation's parameters, grouped by location.
|
|
710
|
+
* Path entries are keyed by the camelCased name to match the URL template placeholders; query,
|
|
711
|
+
* header, and cookie entries keep the spec name to match the keys the runtime serializes.
|
|
712
|
+
* Only parameters whose source defines `style` or `explode` are emitted, so calls without
|
|
713
|
+
* serialization metadata keep the runtime defaults and existing output is unchanged. Returns `null`
|
|
714
|
+
* when no parameter carries metadata.
|
|
715
|
+
*
|
|
716
|
+
* @example
|
|
717
|
+
* ```ts
|
|
718
|
+
* // a path param with { style: 'matrix', explode: true } and a query param with { explode: false }
|
|
719
|
+
* buildStyles({ node }) // "{ path: { id: { style: 'matrix', explode: true } }, query: { tags: { explode: false } } }"
|
|
720
|
+
* ```
|
|
682
721
|
*/
|
|
683
|
-
function
|
|
684
|
-
|
|
685
|
-
const
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
722
|
+
function buildStyles({ node }) {
|
|
723
|
+
if (!kubb_kit.ast.isHttpOperationNode(node)) return null;
|
|
724
|
+
const groups = {
|
|
725
|
+
path: [],
|
|
726
|
+
query: [],
|
|
727
|
+
header: [],
|
|
728
|
+
cookie: []
|
|
729
|
+
};
|
|
730
|
+
for (const parameter of node.parameters) {
|
|
731
|
+
const literal = serializeParameter(parameter);
|
|
732
|
+
if (!literal) continue;
|
|
733
|
+
groups[parameter.in].push(`${toKey(parameter.name, parameter.in)}: ${literal}`);
|
|
690
734
|
}
|
|
691
|
-
|
|
692
|
-
|
|
735
|
+
const locations = Object.keys(groups).filter((location) => groups[location].length > 0);
|
|
736
|
+
if (locations.length === 0) return null;
|
|
737
|
+
return `{ ${locations.map((location) => `${location}: { ${groups[location].join(", ")} }`).join(", ")} }`;
|
|
693
738
|
}
|
|
694
739
|
//#endregion
|
|
695
|
-
//#region src/components/
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
pathParamsType: paramsType === "object" ? "object" : pathParamsType === "object" ? "object" : "inline",
|
|
706
|
-
paramsCasing,
|
|
707
|
-
resolver: tsResolver
|
|
708
|
-
});
|
|
709
|
-
}
|
|
710
|
-
function Url({ name, isExportable = true, isIndexable = true, baseURL, paramsType, paramsCasing, pathParamsType, node, tsResolver }) {
|
|
711
|
-
if (!_kubb_core.ast.isHttpOperationNode(node)) return null;
|
|
712
|
-
const paramsNode = buildUrlParamsNode({
|
|
713
|
-
paramsType,
|
|
714
|
-
paramsCasing,
|
|
715
|
-
pathParamsType,
|
|
740
|
+
//#region ../../internals/client/src/components/Operation.tsx
|
|
741
|
+
/**
|
|
742
|
+
* Renders one client operation: the grouped `<Name>Request` type and the function that forwards a
|
|
743
|
+
* single `options` object to the resolved client and returns the `Unwrappable<RequestResult>`. The
|
|
744
|
+
* type, signature, and call config are built with the AST factory, and only the jsx-renderer emits
|
|
745
|
+
* the source.
|
|
746
|
+
*/
|
|
747
|
+
function Operation({ name, node, types, zodResolver, validator, returnType, throwOnErrorDefault, security, isExportable = true, isIndexable = true }) {
|
|
748
|
+
if (!kubb_kit.ast.isHttpOperationNode(node)) return null;
|
|
749
|
+
const signature = buildGroupedOptionsSignature({
|
|
716
750
|
node,
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
const { path: originalPathParams } = getOperationParameters(node);
|
|
721
|
-
const { path: casedPathParams } = getOperationParameters(node, { paramsCasing });
|
|
722
|
-
const pathParamsMapping = paramsCasing ? buildParamsMapping(originalPathParams, casedPathParams) : null;
|
|
723
|
-
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
|
|
724
|
-
name,
|
|
725
|
-
isExportable,
|
|
726
|
-
isIndexable,
|
|
727
|
-
children: /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.Function, {
|
|
728
|
-
name,
|
|
729
|
-
export: isExportable,
|
|
730
|
-
params: paramsSignature,
|
|
731
|
-
children: [
|
|
732
|
-
pathParamsMapping && Object.entries(pathParamsMapping).filter(([originalName, camelCaseName]) => isValidVarName(originalName) && originalName !== camelCaseName).map(([originalName, camelCaseName]) => `const ${originalName} = ${camelCaseName}`).join("\n"),
|
|
733
|
-
pathParamsMapping && Object.keys(pathParamsMapping).length > 0 && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)("br", {}),
|
|
734
|
-
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.Const, {
|
|
735
|
-
name: "res",
|
|
736
|
-
children: `{ method: '${node.method.toUpperCase()}', url: ${Url$1.toTemplateString(node.path, { prefix: baseURL })} as const }`
|
|
737
|
-
}),
|
|
738
|
-
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)("br", {}),
|
|
739
|
-
"return res"
|
|
740
|
-
]
|
|
741
|
-
})
|
|
751
|
+
types,
|
|
752
|
+
returnType,
|
|
753
|
+
throwOnErrorDefault
|
|
742
754
|
});
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
function buildClientParamsNode({ paramsType, paramsCasing, pathParamsType, node, tsResolver, isConfigurable }) {
|
|
748
|
-
return _kubb_core.ast.createOperationParams(node, {
|
|
749
|
-
paramsType,
|
|
750
|
-
pathParamsType: paramsType === "object" ? "object" : pathParamsType === "object" ? "object" : "inline",
|
|
751
|
-
paramsCasing,
|
|
752
|
-
resolver: tsResolver,
|
|
753
|
-
extraParams: [...isConfigurable ? [_kubb_core.ast.createFunctionParameter({
|
|
754
|
-
name: "config",
|
|
755
|
-
type: _kubb_core.ast.createParamsType({
|
|
756
|
-
variant: "reference",
|
|
757
|
-
name: buildRequestConfigType(node, tsResolver)
|
|
758
|
-
}),
|
|
759
|
-
default: "{}"
|
|
760
|
-
})] : []]
|
|
755
|
+
const validators = buildValidatorHooks({
|
|
756
|
+
node,
|
|
757
|
+
validator,
|
|
758
|
+
zodResolver
|
|
761
759
|
});
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
const
|
|
766
|
-
const
|
|
760
|
+
const securityLiteral = buildSecurityMetadata({ security });
|
|
761
|
+
const stylesLiteral = buildStyles({ node });
|
|
762
|
+
const { defaultContentType } = getContentTypeInfo(node);
|
|
763
|
+
const bakedRequestContentType = Boolean(node.requestBody?.content?.[0]?.schema) && defaultContentType !== "application/json" ? defaultContentType : null;
|
|
764
|
+
const mergeContentType = Boolean(bakedRequestContentType) && getResponseContentTypeInfo(node).isMultipleContentTypes;
|
|
765
|
+
const contentTypeLiteral = !bakedRequestContentType ? null : mergeContentType ? `contentType: { request: '${bakedRequestContentType}', ...(typeof contentType === 'string' ? { request: contentType } : contentType) }` : `contentType: { request: '${bakedRequestContentType}' }`;
|
|
766
|
+
const eventStream = isEventStream(node);
|
|
767
767
|
const responseType = getResponseType(node);
|
|
768
|
-
const
|
|
769
|
-
const
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
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;
|
|
784
|
-
const errorNames = node.responses.filter((r) => {
|
|
785
|
-
return Number.parseInt(r.statusCode, 10) >= 400;
|
|
786
|
-
}).map((r) => tsResolver.resolveResponseStatusName(node, r.statusCode));
|
|
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));
|
|
790
|
-
const generics = [
|
|
791
|
-
dataReturnType === "full" ? allStatusNames.length > 0 ? allStatusNames.join(" | ") : responseName : responseName,
|
|
792
|
-
TError,
|
|
793
|
-
parser === "zod" && zodRequestName ? `z.output<typeof ${zodRequestName}>` : requestName || "unknown"
|
|
768
|
+
const responseTypeLiteral = responseType ? `responseType: '${responseType}'` : null;
|
|
769
|
+
const validatorEntries = [
|
|
770
|
+
validators.request ? `request: ${validators.request}` : null,
|
|
771
|
+
validators.response ? `response: ${validators.response}` : null,
|
|
772
|
+
validators.error ? `error: ${validators.error}` : null
|
|
794
773
|
].filter(Boolean);
|
|
795
|
-
const
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
774
|
+
const validatorLiteral = validatorEntries.length ? `validator: { ${validatorEntries.join(", ")} }` : null;
|
|
775
|
+
const callConfig = `{ ${[
|
|
776
|
+
`method: '${node.method.toUpperCase()}'`,
|
|
777
|
+
`url: '${node.path}'`,
|
|
778
|
+
securityLiteral ? `security: ${securityLiteral}` : null,
|
|
779
|
+
stylesLiteral ? `styles: ${stylesLiteral}` : null,
|
|
780
|
+
validatorLiteral,
|
|
781
|
+
contentTypeLiteral,
|
|
782
|
+
responseTypeLiteral,
|
|
783
|
+
"...config",
|
|
784
|
+
`throwOnError: config.throwOnError ?? ${throwOnErrorDefault}`
|
|
785
|
+
].filter(Boolean).join(", ")} }`;
|
|
786
|
+
const eventType = `SuccessOf<${types.response.responses(node)}>`;
|
|
787
|
+
const functionReturnType = eventStream ? `Promise<EventStreamResult<${eventType}>>` : signature.returnType;
|
|
788
|
+
const returnStatement = eventStream ? `return toEventStream<${eventType}>(request(${callConfig}))` : buildReturnStatement({
|
|
799
789
|
node,
|
|
800
|
-
|
|
801
|
-
|
|
790
|
+
types,
|
|
791
|
+
callConfig,
|
|
792
|
+
returnType,
|
|
793
|
+
throwOnErrorDefault
|
|
802
794
|
});
|
|
803
|
-
|
|
804
|
-
const urlParamsNode = buildUrlParamsNode({
|
|
805
|
-
paramsType,
|
|
806
|
-
paramsCasing,
|
|
807
|
-
pathParamsType,
|
|
808
|
-
node,
|
|
809
|
-
tsResolver
|
|
810
|
-
});
|
|
811
|
-
const urlParamsCall = (0, _kubb_plugin_ts.functionPrinter)({ mode: "call" }).print(urlParamsNode) ?? "";
|
|
812
|
-
const clientParams = createFunctionParams({ config: {
|
|
813
|
-
mode: "object",
|
|
814
|
-
children: {
|
|
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
|
|
824
|
-
}
|
|
825
|
-
} });
|
|
826
|
-
const statusUnionType = dataReturnType === "full" ? buildStatusUnionType(node, tsResolver) : null;
|
|
827
|
-
const childrenElement = children ? children : /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [
|
|
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"
|
|
832
|
-
] });
|
|
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, {
|
|
795
|
+
return /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Source, {
|
|
834
796
|
name,
|
|
835
797
|
isExportable,
|
|
836
798
|
isIndexable,
|
|
837
|
-
children: /* @__PURE__ */ (0,
|
|
799
|
+
children: /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsxs)(kubb_jsx.Function, {
|
|
838
800
|
name,
|
|
839
|
-
async: true,
|
|
840
801
|
export: isExportable,
|
|
841
|
-
|
|
802
|
+
generics: signature.generics,
|
|
803
|
+
params: signature.paramsSignature,
|
|
804
|
+
returnType: functionReturnType,
|
|
842
805
|
JSDoc: { comments: buildOperationComments(node, {
|
|
843
806
|
link: "urlPath",
|
|
844
807
|
linkPosition: "beforeDeprecated",
|
|
845
808
|
splitLines: true
|
|
846
809
|
}) },
|
|
847
|
-
returnType,
|
|
848
810
|
children: [
|
|
849
|
-
|
|
850
|
-
/* @__PURE__ */ (0,
|
|
851
|
-
|
|
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)",
|
|
858
|
-
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)("br", {}),
|
|
859
|
-
isConfigurable ? `const res = await request<${generics.join(", ")}>(${clientParams.toCall()})` : `const res = await client<${generics.join(", ")}>(${clientParams.toCall()})`,
|
|
860
|
-
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)("br", {}),
|
|
861
|
-
childrenElement
|
|
811
|
+
mergeContentType ? "const { client: request = client, contentType, ...config } = options" : "const { client: request = client, ...config } = options",
|
|
812
|
+
/* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)("br", {}),
|
|
813
|
+
returnStatement
|
|
862
814
|
]
|
|
863
815
|
})
|
|
864
|
-
})] });
|
|
865
|
-
}
|
|
866
|
-
//#endregion
|
|
867
|
-
//#region src/components/ClassClient.tsx
|
|
868
|
-
const declarationPrinter$1 = (0, _kubb_plugin_ts.functionPrinter)({ mode: "declaration" });
|
|
869
|
-
function generateMethod$1({ node, name, tsResolver, zodResolver, baseURL, dataReturnType, parser, paramsType, paramsCasing, pathParamsType }) {
|
|
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({
|
|
882
|
-
paramsType,
|
|
883
|
-
paramsCasing,
|
|
884
|
-
pathParamsType,
|
|
885
|
-
node,
|
|
886
|
-
tsResolver,
|
|
887
|
-
isConfigurable: true
|
|
888
|
-
});
|
|
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;
|
|
892
|
-
const clientParams = buildClassClientParams({
|
|
893
|
-
node,
|
|
894
|
-
url: Url$1.toTemplateString(node.path, { casing: paramsCasing }),
|
|
895
|
-
baseURL,
|
|
896
|
-
tsResolver,
|
|
897
|
-
isFormData,
|
|
898
|
-
isMultipleContentTypes,
|
|
899
|
-
hasFormData,
|
|
900
|
-
headers,
|
|
901
|
-
zodQueryParamsName
|
|
902
|
-
});
|
|
903
|
-
const jsdoc = (0, _kubb_ast_utils.buildJSDoc)(buildOperationComments(node, {
|
|
904
|
-
link: "urlPath",
|
|
905
|
-
linkPosition: "beforeDeprecated",
|
|
906
|
-
splitLines: true
|
|
907
|
-
}));
|
|
908
|
-
const requestDataLine = buildRequestDataLine({
|
|
909
|
-
parser,
|
|
910
|
-
node,
|
|
911
|
-
zodResolver
|
|
912
|
-
});
|
|
913
|
-
const queryParamsLine = buildQueryParamsLine({
|
|
914
|
-
parser,
|
|
915
|
-
node,
|
|
916
|
-
zodResolver
|
|
917
|
-
});
|
|
918
|
-
const formDataLine = buildFormDataLine(isFormData || isMultipleContentTypes && hasFormData, !!node.requestBody?.content?.[0]?.schema);
|
|
919
|
-
const returnStatement = buildReturnStatement({
|
|
920
|
-
dataReturnType,
|
|
921
|
-
parser,
|
|
922
|
-
node,
|
|
923
|
-
zodResolver,
|
|
924
|
-
tsResolver
|
|
925
|
-
});
|
|
926
|
-
return `${jsdoc}async ${name}(${paramsSignature}) {\n${[
|
|
927
|
-
`const { client: request = client, ${isMultipleContentTypes ? `contentType = ${(0, _kubb_ast_utils.stringify)(contentType)}, ` : ""}...requestConfig } = mergeConfig(this.#config, config)`,
|
|
928
|
-
"",
|
|
929
|
-
requestDataLine,
|
|
930
|
-
queryParamsLine,
|
|
931
|
-
formDataLine,
|
|
932
|
-
`const res = await request<${generics.join(", ")}>(${clientParams.toCall()})`,
|
|
933
|
-
returnStatement
|
|
934
|
-
].filter(Boolean).map((line) => ` ${line}`).join("\n")}\n }`;
|
|
935
|
-
}
|
|
936
|
-
require_chunk.__name(generateMethod$1, "generateMethod");
|
|
937
|
-
function ClassClient({ name, isExportable = true, isIndexable = true, operations, baseURL, dataReturnType, parser, paramsType, paramsCasing, pathParamsType, children }) {
|
|
938
|
-
const classCode = `export class ${name} {
|
|
939
|
-
#config: Partial<RequestConfig> & { client?: Client }
|
|
940
|
-
|
|
941
|
-
constructor(config: Partial<RequestConfig> & { client?: Client } = {}) {
|
|
942
|
-
this.#config = config
|
|
943
|
-
}
|
|
944
|
-
|
|
945
|
-
${operations.map(({ node, name: methodName, tsResolver, zodResolver }) => generateMethod$1({
|
|
946
|
-
node,
|
|
947
|
-
name: methodName,
|
|
948
|
-
tsResolver,
|
|
949
|
-
zodResolver,
|
|
950
|
-
baseURL,
|
|
951
|
-
dataReturnType,
|
|
952
|
-
parser,
|
|
953
|
-
paramsType,
|
|
954
|
-
paramsCasing,
|
|
955
|
-
pathParamsType
|
|
956
|
-
})).join("\n\n")}
|
|
957
|
-
}`;
|
|
958
|
-
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.File.Source, {
|
|
959
|
-
name,
|
|
960
|
-
isExportable,
|
|
961
|
-
isIndexable,
|
|
962
|
-
children: [classCode, children]
|
|
963
816
|
});
|
|
964
817
|
}
|
|
965
818
|
//#endregion
|
|
966
|
-
//#region src/
|
|
967
|
-
function WrapperClient({ name, controllers, isExportable = true, isIndexable = true }) {
|
|
968
|
-
const classCode = `export class ${name} {
|
|
969
|
-
${controllers.map(({ className, propertyName }) => ` readonly ${propertyName}: ${className}`).join("\n")}
|
|
970
|
-
|
|
971
|
-
constructor(config: Partial<RequestConfig> & { client?: Client } = {}) {
|
|
972
|
-
${controllers.map(({ className, propertyName }) => ` this.${propertyName} = new ${className}(config)`).join("\n")}
|
|
973
|
-
}
|
|
974
|
-
}`;
|
|
975
|
-
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
|
|
976
|
-
name,
|
|
977
|
-
isExportable,
|
|
978
|
-
isIndexable,
|
|
979
|
-
children: classCode
|
|
980
|
-
});
|
|
981
|
-
}
|
|
982
|
-
//#endregion
|
|
983
|
-
//#region src/generators/classClientGenerator.tsx
|
|
984
|
-
function resolveTypeImportNames$1(node, tsResolver) {
|
|
985
|
-
return resolveOperationTypeNames(node, tsResolver, { order: "body-response-first" });
|
|
986
|
-
}
|
|
987
|
-
require_chunk.__name(resolveTypeImportNames$1, "resolveTypeImportNames");
|
|
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));
|
|
995
|
-
}
|
|
996
|
-
require_chunk.__name(resolveZodImportNames$1, "resolveZodImportNames");
|
|
819
|
+
//#region ../../internals/client/src/resolveOperationTypes.ts
|
|
997
820
|
/**
|
|
998
|
-
*
|
|
999
|
-
*
|
|
1000
|
-
* per operation and a shared constructor for request configuration.
|
|
821
|
+
* Warning a client generator reports when neither plugin can supply the operation types, so the
|
|
822
|
+
* pipeline says why nothing was generated instead of silently emitting no files.
|
|
1001
823
|
*/
|
|
1002
|
-
const
|
|
1003
|
-
name: "classClient",
|
|
1004
|
-
renderer: _kubb_renderer_jsx.jsxRenderer,
|
|
1005
|
-
operations(nodes, ctx) {
|
|
1006
|
-
const { config, driver, resolver, root } = ctx;
|
|
1007
|
-
const { output, group, dataReturnType, paramsCasing, paramsType, pathParamsType, parser, importPath, sdk } = ctx.options;
|
|
1008
|
-
const baseURL = ctx.options.baseURL ?? ctx.meta.baseURL;
|
|
1009
|
-
const pluginTs = driver.getPlugin(_kubb_plugin_ts.pluginTsName);
|
|
1010
|
-
if (!pluginTs) return null;
|
|
1011
|
-
const tsResolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
|
|
1012
|
-
const tsPluginOptions = pluginTs.options;
|
|
1013
|
-
const pluginZod = isParserEnabled(parser) ? driver.getPlugin(_kubb_plugin_zod.pluginZodName) : null;
|
|
1014
|
-
const zodResolver = pluginZod ? driver.getResolver(_kubb_plugin_zod.pluginZodName) : null;
|
|
1015
|
-
function buildOperationData(node) {
|
|
1016
|
-
const typeFile = tsResolver.resolveFile(operationFileEntry(node, node.operationId), {
|
|
1017
|
-
root,
|
|
1018
|
-
output: tsPluginOptions?.output ?? output,
|
|
1019
|
-
group: tsPluginOptions?.group
|
|
1020
|
-
});
|
|
1021
|
-
const zodFile = zodResolver && pluginZod?.options ? zodResolver.resolveFile(operationFileEntry(node, node.operationId), {
|
|
1022
|
-
root,
|
|
1023
|
-
output: pluginZod.options?.output ?? output,
|
|
1024
|
-
group: pluginZod.options?.group ?? void 0
|
|
1025
|
-
}) : null;
|
|
1026
|
-
return {
|
|
1027
|
-
node,
|
|
1028
|
-
name: resolver.resolveName(node.operationId),
|
|
1029
|
-
tsResolver,
|
|
1030
|
-
zodResolver,
|
|
1031
|
-
typeFile,
|
|
1032
|
-
zodFile
|
|
1033
|
-
};
|
|
1034
|
-
}
|
|
1035
|
-
const controllers = nodes.reduce((acc, operationNode) => {
|
|
1036
|
-
if (!_kubb_core.ast.isHttpOperationNode(operationNode)) return acc;
|
|
1037
|
-
const tag = operationNode.tags[0];
|
|
1038
|
-
const groupName = tag ? group?.name?.({ group: camelCase(tag) }) ?? resolver.resolveGroupName(tag) : resolver.resolveClassName("Client");
|
|
1039
|
-
if (!tag && !group) {
|
|
1040
|
-
const name = resolver.resolveClassName("ApiClient");
|
|
1041
|
-
const file = resolver.resolveFile({
|
|
1042
|
-
name,
|
|
1043
|
-
extname: ".ts"
|
|
1044
|
-
}, {
|
|
1045
|
-
root,
|
|
1046
|
-
output,
|
|
1047
|
-
group: group ?? void 0
|
|
1048
|
-
});
|
|
1049
|
-
const operationData = buildOperationData(operationNode);
|
|
1050
|
-
const previous = acc.find((item) => item.file.path === file.path);
|
|
1051
|
-
if (previous) previous.operations.push(operationData);
|
|
1052
|
-
else acc.push({
|
|
1053
|
-
name,
|
|
1054
|
-
propertyName: resolver.resolveClientPropertyName(name),
|
|
1055
|
-
file,
|
|
1056
|
-
operations: [operationData]
|
|
1057
|
-
});
|
|
1058
|
-
return acc;
|
|
1059
|
-
}
|
|
1060
|
-
if (tag) {
|
|
1061
|
-
const name = groupName;
|
|
1062
|
-
const file = resolver.resolveFile({
|
|
1063
|
-
name,
|
|
1064
|
-
extname: ".ts",
|
|
1065
|
-
tag
|
|
1066
|
-
}, {
|
|
1067
|
-
root,
|
|
1068
|
-
output,
|
|
1069
|
-
group: group ?? void 0
|
|
1070
|
-
});
|
|
1071
|
-
const operationData = buildOperationData(operationNode);
|
|
1072
|
-
const previous = acc.find((item) => item.file.path === file.path);
|
|
1073
|
-
if (previous) previous.operations.push(operationData);
|
|
1074
|
-
else acc.push({
|
|
1075
|
-
name,
|
|
1076
|
-
propertyName: resolver.resolveClientPropertyName(name),
|
|
1077
|
-
file,
|
|
1078
|
-
operations: [operationData]
|
|
1079
|
-
});
|
|
1080
|
-
}
|
|
1081
|
-
return acc;
|
|
1082
|
-
}, []);
|
|
1083
|
-
function collectTypeImports(ops) {
|
|
1084
|
-
const typeImportsByFile = /* @__PURE__ */ new Map();
|
|
1085
|
-
const typeFilesByPath = /* @__PURE__ */ new Map();
|
|
1086
|
-
ops.forEach((op) => {
|
|
1087
|
-
const names = resolveTypeImportNames$1(op.node, tsResolver);
|
|
1088
|
-
if (!typeImportsByFile.has(op.typeFile.path)) typeImportsByFile.set(op.typeFile.path, /* @__PURE__ */ new Set());
|
|
1089
|
-
const imports = typeImportsByFile.get(op.typeFile.path);
|
|
1090
|
-
names.forEach((n) => {
|
|
1091
|
-
imports.add(n);
|
|
1092
|
-
});
|
|
1093
|
-
typeFilesByPath.set(op.typeFile.path, op.typeFile);
|
|
1094
|
-
});
|
|
1095
|
-
return {
|
|
1096
|
-
typeImportsByFile,
|
|
1097
|
-
typeFilesByPath
|
|
1098
|
-
};
|
|
1099
|
-
}
|
|
1100
|
-
function collectZodImports(ops) {
|
|
1101
|
-
const zodImportsByFile = /* @__PURE__ */ new Map();
|
|
1102
|
-
const zodFilesByPath = /* @__PURE__ */ new Map();
|
|
1103
|
-
ops.forEach((op) => {
|
|
1104
|
-
if (!op.zodFile || !zodResolver) return;
|
|
1105
|
-
const names = resolveZodImportNames$1(op.node, zodResolver, parser);
|
|
1106
|
-
if (!zodImportsByFile.has(op.zodFile.path)) zodImportsByFile.set(op.zodFile.path, /* @__PURE__ */ new Set());
|
|
1107
|
-
const imports = zodImportsByFile.get(op.zodFile.path);
|
|
1108
|
-
names.forEach((n) => {
|
|
1109
|
-
imports.add(n);
|
|
1110
|
-
});
|
|
1111
|
-
zodFilesByPath.set(op.zodFile.path, op.zodFile);
|
|
1112
|
-
});
|
|
1113
|
-
return {
|
|
1114
|
-
zodImportsByFile,
|
|
1115
|
-
zodFilesByPath
|
|
1116
|
-
};
|
|
1117
|
-
}
|
|
1118
|
-
const files = controllers.map(({ name, file, operations: ops }) => {
|
|
1119
|
-
const { typeImportsByFile, typeFilesByPath } = collectTypeImports(ops);
|
|
1120
|
-
const { zodImportsByFile, zodFilesByPath } = isParserEnabled(parser) ? collectZodImports(ops) : {
|
|
1121
|
-
zodImportsByFile: /* @__PURE__ */ new Map(),
|
|
1122
|
-
zodFilesByPath: /* @__PURE__ */ new Map()
|
|
1123
|
-
};
|
|
1124
|
-
const hasFormData = ops.some((op) => op.node.requestBody?.content?.some((e) => e.contentType === "multipart/form-data") ?? false);
|
|
1125
|
-
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.File, {
|
|
1126
|
-
baseName: file.baseName,
|
|
1127
|
-
path: file.path,
|
|
1128
|
-
meta: file.meta,
|
|
1129
|
-
banner: resolver.resolveBanner(ctx.meta, {
|
|
1130
|
-
output,
|
|
1131
|
-
config,
|
|
1132
|
-
file: {
|
|
1133
|
-
path: file.path,
|
|
1134
|
-
baseName: file.baseName
|
|
1135
|
-
}
|
|
1136
|
-
}),
|
|
1137
|
-
footer: resolver.resolveFooter(ctx.meta, {
|
|
1138
|
-
output,
|
|
1139
|
-
config,
|
|
1140
|
-
file: {
|
|
1141
|
-
path: file.path,
|
|
1142
|
-
baseName: file.baseName
|
|
1143
|
-
}
|
|
1144
|
-
}),
|
|
1145
|
-
children: [
|
|
1146
|
-
importPath ? /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [
|
|
1147
|
-
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1148
|
-
name: "client",
|
|
1149
|
-
path: importPath
|
|
1150
|
-
}),
|
|
1151
|
-
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1152
|
-
name: ["mergeConfig"],
|
|
1153
|
-
path: importPath
|
|
1154
|
-
}),
|
|
1155
|
-
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1156
|
-
name: [
|
|
1157
|
-
"Client",
|
|
1158
|
-
"RequestConfig",
|
|
1159
|
-
"ResponseErrorConfig"
|
|
1160
|
-
],
|
|
1161
|
-
path: importPath,
|
|
1162
|
-
isTypeOnly: true
|
|
1163
|
-
})
|
|
1164
|
-
] }) : /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [
|
|
1165
|
-
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1166
|
-
name: ["client"],
|
|
1167
|
-
root: file.path,
|
|
1168
|
-
path: node_path.default.resolve(root, ".kubb/client.ts")
|
|
1169
|
-
}),
|
|
1170
|
-
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1171
|
-
name: ["mergeConfig"],
|
|
1172
|
-
root: file.path,
|
|
1173
|
-
path: node_path.default.resolve(root, ".kubb/client.ts")
|
|
1174
|
-
}),
|
|
1175
|
-
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1176
|
-
name: [
|
|
1177
|
-
"Client",
|
|
1178
|
-
"RequestConfig",
|
|
1179
|
-
"ResponseErrorConfig"
|
|
1180
|
-
],
|
|
1181
|
-
root: file.path,
|
|
1182
|
-
path: node_path.default.resolve(root, ".kubb/client.ts"),
|
|
1183
|
-
isTypeOnly: true
|
|
1184
|
-
})
|
|
1185
|
-
] }),
|
|
1186
|
-
hasFormData && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1187
|
-
name: ["buildFormData"],
|
|
1188
|
-
root: file.path,
|
|
1189
|
-
path: node_path.default.resolve(root, ".kubb/config.ts")
|
|
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
|
-
}),
|
|
1196
|
-
Array.from(typeImportsByFile.entries()).map(([filePath, importSet]) => {
|
|
1197
|
-
const typeFile = typeFilesByPath.get(filePath);
|
|
1198
|
-
if (!typeFile) return null;
|
|
1199
|
-
const importNames = Array.from(importSet).filter(Boolean);
|
|
1200
|
-
if (importNames.length === 0) return null;
|
|
1201
|
-
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1202
|
-
name: importNames,
|
|
1203
|
-
root: file.path,
|
|
1204
|
-
path: typeFile.path,
|
|
1205
|
-
isTypeOnly: true
|
|
1206
|
-
}, filePath);
|
|
1207
|
-
}),
|
|
1208
|
-
isParserEnabled(parser) && Array.from(zodImportsByFile.entries()).map(([filePath, importSet]) => {
|
|
1209
|
-
const zodFile = zodFilesByPath.get(filePath);
|
|
1210
|
-
if (!zodFile) return null;
|
|
1211
|
-
const importNames = Array.from(importSet).filter(Boolean);
|
|
1212
|
-
if (importNames.length === 0) return null;
|
|
1213
|
-
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1214
|
-
name: importNames,
|
|
1215
|
-
root: file.path,
|
|
1216
|
-
path: zodFile.path
|
|
1217
|
-
}, filePath);
|
|
1218
|
-
}),
|
|
1219
|
-
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(ClassClient, {
|
|
1220
|
-
name,
|
|
1221
|
-
operations: ops,
|
|
1222
|
-
baseURL,
|
|
1223
|
-
dataReturnType,
|
|
1224
|
-
pathParamsType,
|
|
1225
|
-
paramsCasing,
|
|
1226
|
-
paramsType,
|
|
1227
|
-
parser
|
|
1228
|
-
})
|
|
1229
|
-
]
|
|
1230
|
-
}, file.path);
|
|
1231
|
-
});
|
|
1232
|
-
if (sdk) {
|
|
1233
|
-
const sdkFile = resolver.resolveFile({
|
|
1234
|
-
name: sdk.className,
|
|
1235
|
-
extname: ".ts"
|
|
1236
|
-
}, {
|
|
1237
|
-
root,
|
|
1238
|
-
output,
|
|
1239
|
-
group: group ?? void 0
|
|
1240
|
-
});
|
|
1241
|
-
files.push(/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.File, {
|
|
1242
|
-
baseName: sdkFile.baseName,
|
|
1243
|
-
path: sdkFile.path,
|
|
1244
|
-
meta: sdkFile.meta,
|
|
1245
|
-
banner: resolver.resolveBanner(ctx.meta, {
|
|
1246
|
-
output,
|
|
1247
|
-
config,
|
|
1248
|
-
file: {
|
|
1249
|
-
path: sdkFile.path,
|
|
1250
|
-
baseName: sdkFile.baseName
|
|
1251
|
-
}
|
|
1252
|
-
}),
|
|
1253
|
-
footer: resolver.resolveFooter(ctx.meta, {
|
|
1254
|
-
output,
|
|
1255
|
-
config,
|
|
1256
|
-
file: {
|
|
1257
|
-
path: sdkFile.path,
|
|
1258
|
-
baseName: sdkFile.baseName
|
|
1259
|
-
}
|
|
1260
|
-
}),
|
|
1261
|
-
children: [
|
|
1262
|
-
importPath ? /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1263
|
-
name: ["Client", "RequestConfig"],
|
|
1264
|
-
path: importPath,
|
|
1265
|
-
isTypeOnly: true
|
|
1266
|
-
}) : /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1267
|
-
name: ["Client", "RequestConfig"],
|
|
1268
|
-
root: sdkFile.path,
|
|
1269
|
-
path: node_path.default.resolve(root, ".kubb/client.ts"),
|
|
1270
|
-
isTypeOnly: true
|
|
1271
|
-
}),
|
|
1272
|
-
controllers.map(({ name, file }) => /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1273
|
-
name: [name],
|
|
1274
|
-
root: sdkFile.path,
|
|
1275
|
-
path: file.path
|
|
1276
|
-
}, name)),
|
|
1277
|
-
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(WrapperClient, {
|
|
1278
|
-
name: sdk.className,
|
|
1279
|
-
controllers: controllers.map(({ name, propertyName }) => ({
|
|
1280
|
-
className: name,
|
|
1281
|
-
propertyName
|
|
1282
|
-
}))
|
|
1283
|
-
})
|
|
1284
|
-
]
|
|
1285
|
-
}, sdkFile.path));
|
|
1286
|
-
}
|
|
1287
|
-
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: files });
|
|
1288
|
-
}
|
|
1289
|
-
});
|
|
1290
|
-
//#endregion
|
|
1291
|
-
//#region src/generators/clientGenerator.tsx
|
|
824
|
+
const MISSING_OPERATION_TYPES_WARNING = "Skipped: no operation types available. Add `pluginTs()`, or `pluginZod({ inferred: true })` to type the client from its zod schemas.";
|
|
1292
825
|
/**
|
|
1293
|
-
*
|
|
1294
|
-
*
|
|
1295
|
-
* `
|
|
826
|
+
* Picks the plugin a generated client takes its `Options` and `Responses` types from.
|
|
827
|
+
*
|
|
828
|
+
* `plugin-ts` wins whenever it is in the pipeline, so existing configs keep the types they generate
|
|
829
|
+
* today. Without it, `pluginZod({ inferred: true })` takes over: its inferred options and responses
|
|
830
|
+
* types are built from the same shared schemas as the `plugin-ts` ones, so a client typed off
|
|
831
|
+
* `z.infer` carries what the codecs decode to (a `Temporal` instance, a `Date`) rather than the raw
|
|
832
|
+
* wire type. Returns `null` when neither is available, leaving the caller nothing to type against.
|
|
833
|
+
*
|
|
834
|
+
* @example
|
|
835
|
+
* ```ts
|
|
836
|
+
* const types = resolveOperationTypes(ctx.driver)
|
|
837
|
+
* if (!types) return null
|
|
838
|
+
* types.response.options(node) // 'GetPetByIdOptions', or 'GetPetByIdOptionsSchemaType' from zod
|
|
839
|
+
* ```
|
|
1296
840
|
*/
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
if (!pluginTs) return null;
|
|
1307
|
-
const tsResolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
|
|
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;
|
|
1318
|
-
const meta = {
|
|
1319
|
-
name: resolver.resolveName(node.operationId),
|
|
1320
|
-
urlName: resolver.resolveUrlName(node),
|
|
1321
|
-
file: resolver.resolveFile(operationFileEntry(node, node.operationId), {
|
|
1322
|
-
root,
|
|
1323
|
-
output,
|
|
1324
|
-
group: group ?? void 0
|
|
1325
|
-
}),
|
|
1326
|
-
fileTs: tsResolver.resolveFile(operationFileEntry(node, node.operationId), {
|
|
1327
|
-
root,
|
|
1328
|
-
output: pluginTs.options?.output ?? output,
|
|
1329
|
-
group: pluginTs.options?.group ?? void 0
|
|
1330
|
-
}),
|
|
1331
|
-
fileZod: zodResolver && pluginZod?.options ? zodResolver.resolveFile(operationFileEntry(node, node.operationId), {
|
|
1332
|
-
root,
|
|
1333
|
-
output: pluginZod.options.output ?? output,
|
|
1334
|
-
group: pluginZod.options?.group ?? void 0
|
|
1335
|
-
}) : null
|
|
841
|
+
function resolveOperationTypes(driver) {
|
|
842
|
+
const pluginTs = driver.getPlugin(_kubb_plugin_ts.pluginTsName);
|
|
843
|
+
if (pluginTs) {
|
|
844
|
+
const resolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
|
|
845
|
+
return {
|
|
846
|
+
response: resolver.response,
|
|
847
|
+
resolver,
|
|
848
|
+
output: pluginTs.options?.output,
|
|
849
|
+
group: pluginTs.options?.group
|
|
1336
850
|
};
|
|
1337
|
-
const hasFormData = node.requestBody?.content?.some((e) => e.contentType === "multipart/form-data") ?? false;
|
|
1338
|
-
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.File, {
|
|
1339
|
-
baseName: meta.file.baseName,
|
|
1340
|
-
path: meta.file.path,
|
|
1341
|
-
meta: meta.file.meta,
|
|
1342
|
-
banner: resolver.resolveBanner(ctx.meta, {
|
|
1343
|
-
output,
|
|
1344
|
-
config,
|
|
1345
|
-
file: {
|
|
1346
|
-
path: meta.file.path,
|
|
1347
|
-
baseName: meta.file.baseName
|
|
1348
|
-
}
|
|
1349
|
-
}),
|
|
1350
|
-
footer: resolver.resolveFooter(ctx.meta, {
|
|
1351
|
-
output,
|
|
1352
|
-
config,
|
|
1353
|
-
file: {
|
|
1354
|
-
path: meta.file.path,
|
|
1355
|
-
baseName: meta.file.baseName
|
|
1356
|
-
}
|
|
1357
|
-
}),
|
|
1358
|
-
children: [
|
|
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, {
|
|
1360
|
-
name: "client",
|
|
1361
|
-
path: importPath
|
|
1362
|
-
}), /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1363
|
-
name: [
|
|
1364
|
-
"Client",
|
|
1365
|
-
"RequestConfig",
|
|
1366
|
-
"ResponseErrorConfig"
|
|
1367
|
-
],
|
|
1368
|
-
path: importPath,
|
|
1369
|
-
isTypeOnly: true
|
|
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, {
|
|
1371
|
-
name: ["client"],
|
|
1372
|
-
root: meta.file.path,
|
|
1373
|
-
path: node_path.default.resolve(root, ".kubb/client.ts")
|
|
1374
|
-
}), /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1375
|
-
name: [
|
|
1376
|
-
"Client",
|
|
1377
|
-
"RequestConfig",
|
|
1378
|
-
"ResponseErrorConfig"
|
|
1379
|
-
],
|
|
1380
|
-
root: meta.file.path,
|
|
1381
|
-
path: node_path.default.resolve(root, ".kubb/client.ts"),
|
|
1382
|
-
isTypeOnly: true
|
|
1383
|
-
})] }),
|
|
1384
|
-
hasFormData && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1385
|
-
name: ["buildFormData"],
|
|
1386
|
-
root: meta.file.path,
|
|
1387
|
-
path: node_path.default.resolve(root, ".kubb/config.ts")
|
|
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
|
-
}),
|
|
1394
|
-
meta.fileZod && importedZodNames.length > 0 && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1395
|
-
name: importedZodNames,
|
|
1396
|
-
root: meta.file.path,
|
|
1397
|
-
path: meta.fileZod.path
|
|
1398
|
-
}),
|
|
1399
|
-
meta.fileTs && importedTypeNames.length > 0 && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1400
|
-
name: Array.from(new Set(importedTypeNames)),
|
|
1401
|
-
root: meta.file.path,
|
|
1402
|
-
path: meta.fileTs.path,
|
|
1403
|
-
isTypeOnly: true
|
|
1404
|
-
}),
|
|
1405
|
-
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(Url, {
|
|
1406
|
-
name: meta.urlName,
|
|
1407
|
-
baseURL,
|
|
1408
|
-
pathParamsType,
|
|
1409
|
-
paramsCasing,
|
|
1410
|
-
paramsType,
|
|
1411
|
-
node,
|
|
1412
|
-
tsResolver,
|
|
1413
|
-
isIndexable: urlType === "export",
|
|
1414
|
-
isExportable: urlType === "export"
|
|
1415
|
-
}),
|
|
1416
|
-
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(Client, {
|
|
1417
|
-
name: meta.name,
|
|
1418
|
-
urlName: meta.urlName,
|
|
1419
|
-
baseURL,
|
|
1420
|
-
dataReturnType,
|
|
1421
|
-
pathParamsType,
|
|
1422
|
-
paramsCasing,
|
|
1423
|
-
paramsType,
|
|
1424
|
-
node,
|
|
1425
|
-
tsResolver,
|
|
1426
|
-
zodResolver,
|
|
1427
|
-
parser
|
|
1428
|
-
})
|
|
1429
|
-
]
|
|
1430
|
-
});
|
|
1431
851
|
}
|
|
1432
|
-
|
|
852
|
+
const pluginZod = driver.getPlugin(_kubb_plugin_zod.pluginZodName);
|
|
853
|
+
if (!pluginZod?.options?.inferred) return null;
|
|
854
|
+
const resolver = driver.getResolver(_kubb_plugin_zod.pluginZodName);
|
|
855
|
+
return {
|
|
856
|
+
response: {
|
|
857
|
+
options: resolver.response.options,
|
|
858
|
+
responses: (node) => resolver.schema.type(resolver.response.responses(node))
|
|
859
|
+
},
|
|
860
|
+
resolver,
|
|
861
|
+
output: pluginZod.options.output,
|
|
862
|
+
group: pluginZod.options.group
|
|
863
|
+
};
|
|
864
|
+
}
|
|
1433
865
|
//#endregion
|
|
1434
|
-
//#region src/generators/
|
|
866
|
+
//#region ../../internals/client/src/generators/clientGenerator.tsx
|
|
1435
867
|
/**
|
|
1436
|
-
*
|
|
1437
|
-
*
|
|
1438
|
-
* `
|
|
1439
|
-
*
|
|
868
|
+
* Builds the built-in per-operation generator shared by the client plugins (`@kubb/plugin-fetch`,
|
|
869
|
+
* `@kubb/plugin-axios`). Emits one async function per OpenAPI operation using the shared
|
|
870
|
+
* `Operation` component: a grouped `<Name>Request` type and a function that forwards a single
|
|
871
|
+
* `options` object to the bundled `client` and returns the `Unwrappable<RequestResult>`. Only the
|
|
872
|
+
* generator `name` differs between plugins. Every other resolution, import, and rendering step is
|
|
873
|
+
* identical.
|
|
1440
874
|
*/
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
875
|
+
function createClientGenerator(name, resolveClientPath) {
|
|
876
|
+
return (0, kubb_kit.defineGenerator)({
|
|
877
|
+
name,
|
|
878
|
+
renderer: kubb_jsx.jsxRenderer,
|
|
879
|
+
operation(node, ctx) {
|
|
880
|
+
if (!kubb_kit.ast.isHttpOperationNode(node)) return null;
|
|
881
|
+
const { config, driver, resolver, root } = ctx;
|
|
882
|
+
const { output, validator, returnType, throwOnErrorDefault, group } = ctx.options;
|
|
883
|
+
const types = resolveOperationTypes(driver);
|
|
884
|
+
if (!types) {
|
|
885
|
+
ctx.warn(MISSING_OPERATION_TYPES_WARNING);
|
|
886
|
+
return null;
|
|
887
|
+
}
|
|
888
|
+
const pluginZod = resolveResponseValidator(validator) === "zod" || resolveRequestValidator(validator) === "zod" ? driver.getPlugin(_kubb_plugin_zod.pluginZodName) : null;
|
|
889
|
+
const zodResolver = pluginZod ? driver.getResolver(_kubb_plugin_zod.pluginZodName) : null;
|
|
890
|
+
const hasRequestBody = Boolean(node.requestBody?.content?.[0]?.schema);
|
|
891
|
+
const importedTypeNames = [types.response.options(node), types.response.responses(node)];
|
|
892
|
+
const importedZodNames = zodResolver ? [
|
|
893
|
+
resolveResponseValidator(validator) === "zod" ? zodResolver.response.response?.(node) : null,
|
|
894
|
+
resolveResponseValidator(validator) === "zod" ? buildZodErrorParse(node, zodResolver)?.expression ?? null : null,
|
|
895
|
+
resolveRequestValidator(validator) === "zod" && hasRequestBody ? zodResolver.response.body?.(node) : null
|
|
896
|
+
].filter((name) => Boolean(name)) : [];
|
|
897
|
+
const meta = {
|
|
898
|
+
name: resolver.name(node.operationId),
|
|
899
|
+
file: resolver.file({
|
|
900
|
+
...operationFileEntry(node, node.operationId),
|
|
1467
901
|
root,
|
|
1468
902
|
output,
|
|
1469
903
|
group: group ?? void 0
|
|
1470
|
-
});
|
|
1471
|
-
const client = {
|
|
1472
|
-
name: resolver.resolveName(operationNode.operationId),
|
|
1473
|
-
file: clientFile
|
|
1474
|
-
};
|
|
1475
|
-
const previous = acc.find((item) => item.file.path === file.path);
|
|
1476
|
-
if (previous) previous.clients.push(client);
|
|
1477
|
-
else acc.push({
|
|
1478
|
-
name,
|
|
1479
|
-
file,
|
|
1480
|
-
clients: [client]
|
|
1481
|
-
});
|
|
1482
|
-
}
|
|
1483
|
-
return acc;
|
|
1484
|
-
}, []).map(({ name, file, clients }) => {
|
|
1485
|
-
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.File, {
|
|
1486
|
-
baseName: file.baseName,
|
|
1487
|
-
path: file.path,
|
|
1488
|
-
meta: file.meta,
|
|
1489
|
-
banner: resolver.resolveBanner(ctx.meta, {
|
|
1490
|
-
output,
|
|
1491
|
-
config,
|
|
1492
|
-
file: {
|
|
1493
|
-
path: file.path,
|
|
1494
|
-
baseName: file.baseName,
|
|
1495
|
-
isAggregation: true
|
|
1496
|
-
}
|
|
1497
|
-
}),
|
|
1498
|
-
footer: resolver.resolveFooter(ctx.meta, {
|
|
1499
|
-
output,
|
|
1500
|
-
config,
|
|
1501
|
-
file: {
|
|
1502
|
-
path: file.path,
|
|
1503
|
-
baseName: file.baseName,
|
|
1504
|
-
isAggregation: true
|
|
1505
|
-
}
|
|
1506
904
|
}),
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
}, client.name)), /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
|
|
1512
|
-
name,
|
|
1513
|
-
isExportable: true,
|
|
1514
|
-
isIndexable: true,
|
|
1515
|
-
children: /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.Function, {
|
|
1516
|
-
export: true,
|
|
1517
|
-
name,
|
|
1518
|
-
children: `return { ${clients.map((client) => client.name).join(", ")} }`
|
|
1519
|
-
})
|
|
1520
|
-
})]
|
|
1521
|
-
}, file.path);
|
|
1522
|
-
}) });
|
|
1523
|
-
}
|
|
1524
|
-
});
|
|
1525
|
-
//#endregion
|
|
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
|
-
*/
|
|
1533
|
-
const operationsGenerator = (0, _kubb_core.defineGenerator)({
|
|
1534
|
-
name: "client",
|
|
1535
|
-
operations(nodes, ctx) {
|
|
1536
|
-
const { config, resolver, root } = ctx;
|
|
1537
|
-
const { output, group } = ctx.options;
|
|
1538
|
-
const name = "operations";
|
|
1539
|
-
const file = resolver.resolveFile({
|
|
1540
|
-
name,
|
|
1541
|
-
extname: ".ts"
|
|
1542
|
-
}, {
|
|
1543
|
-
root,
|
|
1544
|
-
output,
|
|
1545
|
-
group: group ?? void 0
|
|
1546
|
-
});
|
|
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({
|
|
1556
|
-
baseName: file.baseName,
|
|
1557
|
-
path: file.path,
|
|
1558
|
-
meta: file.meta,
|
|
1559
|
-
banner: resolver.resolveBanner(ctx.meta, {
|
|
1560
|
-
output,
|
|
1561
|
-
config,
|
|
1562
|
-
file: {
|
|
1563
|
-
path: file.path,
|
|
1564
|
-
baseName: file.baseName
|
|
1565
|
-
}
|
|
1566
|
-
}),
|
|
1567
|
-
footer: resolver.resolveFooter(ctx.meta, {
|
|
1568
|
-
output,
|
|
1569
|
-
config,
|
|
1570
|
-
file: {
|
|
1571
|
-
path: file.path,
|
|
1572
|
-
baseName: file.baseName
|
|
1573
|
-
}
|
|
1574
|
-
}),
|
|
1575
|
-
sources: [_kubb_core.ast.createSource({
|
|
1576
|
-
name,
|
|
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
|
-
})];
|
|
1586
|
-
}
|
|
1587
|
-
});
|
|
1588
|
-
//#endregion
|
|
1589
|
-
//#region src/components/StaticClassClient.tsx
|
|
1590
|
-
const declarationPrinter = (0, _kubb_plugin_ts.functionPrinter)({ mode: "declaration" });
|
|
1591
|
-
function generateMethod({ node, name, tsResolver, zodResolver, baseURL, dataReturnType, parser, paramsType, paramsCasing, pathParamsType }) {
|
|
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({
|
|
1604
|
-
paramsType,
|
|
1605
|
-
paramsCasing,
|
|
1606
|
-
pathParamsType,
|
|
1607
|
-
node,
|
|
1608
|
-
tsResolver,
|
|
1609
|
-
isConfigurable: true
|
|
1610
|
-
});
|
|
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;
|
|
1614
|
-
const clientParams = buildClassClientParams({
|
|
1615
|
-
node,
|
|
1616
|
-
url: Url$1.toTemplateString(node.path, { casing: paramsCasing }),
|
|
1617
|
-
baseURL,
|
|
1618
|
-
tsResolver,
|
|
1619
|
-
isFormData,
|
|
1620
|
-
isMultipleContentTypes,
|
|
1621
|
-
hasFormData,
|
|
1622
|
-
headers,
|
|
1623
|
-
zodQueryParamsName
|
|
1624
|
-
});
|
|
1625
|
-
const jsdoc = (0, _kubb_ast_utils.buildJSDoc)(buildOperationComments(node, {
|
|
1626
|
-
link: "urlPath",
|
|
1627
|
-
linkPosition: "beforeDeprecated",
|
|
1628
|
-
splitLines: true
|
|
1629
|
-
}));
|
|
1630
|
-
const requestDataLine = buildRequestDataLine({
|
|
1631
|
-
parser,
|
|
1632
|
-
node,
|
|
1633
|
-
zodResolver
|
|
1634
|
-
});
|
|
1635
|
-
const queryParamsLine = buildQueryParamsLine({
|
|
1636
|
-
parser,
|
|
1637
|
-
node,
|
|
1638
|
-
zodResolver
|
|
1639
|
-
});
|
|
1640
|
-
const formDataLine = buildFormDataLine(isFormData || isMultipleContentTypes && hasFormData, !!node.requestBody?.content?.[0]?.schema);
|
|
1641
|
-
const returnStatement = buildReturnStatement({
|
|
1642
|
-
dataReturnType,
|
|
1643
|
-
parser,
|
|
1644
|
-
node,
|
|
1645
|
-
zodResolver,
|
|
1646
|
-
tsResolver
|
|
1647
|
-
});
|
|
1648
|
-
return `${jsdoc} static async ${name}(${paramsSignature}) {\n${[
|
|
1649
|
-
`const { client: request = client, ${isMultipleContentTypes ? `contentType = ${(0, _kubb_ast_utils.stringify)(contentType)}, ` : ""}...requestConfig } = mergeConfig(this.#config, config)`,
|
|
1650
|
-
"",
|
|
1651
|
-
requestDataLine,
|
|
1652
|
-
queryParamsLine,
|
|
1653
|
-
formDataLine,
|
|
1654
|
-
`const res = await request<${generics.join(", ")}>(${clientParams.toCall()})`,
|
|
1655
|
-
returnStatement
|
|
1656
|
-
].filter(Boolean).map((line) => ` ${line}`).join("\n")}\n }`;
|
|
1657
|
-
}
|
|
1658
|
-
function StaticClassClient({ name, isExportable = true, isIndexable = true, operations, baseURL, dataReturnType, parser, paramsType, paramsCasing, pathParamsType, children }) {
|
|
1659
|
-
const classCode = `export class ${name} {\n static #config: Partial<RequestConfig> & { client?: Client } = {}\n\n${operations.map(({ node, name: methodName, tsResolver, zodResolver }) => generateMethod({
|
|
1660
|
-
node,
|
|
1661
|
-
name: methodName,
|
|
1662
|
-
tsResolver,
|
|
1663
|
-
zodResolver,
|
|
1664
|
-
baseURL,
|
|
1665
|
-
dataReturnType,
|
|
1666
|
-
parser,
|
|
1667
|
-
paramsType,
|
|
1668
|
-
paramsCasing,
|
|
1669
|
-
pathParamsType
|
|
1670
|
-
})).join("\n\n")}\n}`;
|
|
1671
|
-
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.File.Source, {
|
|
1672
|
-
name,
|
|
1673
|
-
isExportable,
|
|
1674
|
-
isIndexable,
|
|
1675
|
-
children: [classCode, children]
|
|
1676
|
-
});
|
|
1677
|
-
}
|
|
1678
|
-
//#endregion
|
|
1679
|
-
//#region src/generators/staticClassClientGenerator.tsx
|
|
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);
|
|
1685
|
-
return [
|
|
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
|
|
1689
|
-
].filter((n) => Boolean(n));
|
|
1690
|
-
}
|
|
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
|
-
*/
|
|
1697
|
-
const staticClassClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
1698
|
-
name: "staticClassClient",
|
|
1699
|
-
renderer: _kubb_renderer_jsx.jsxRenderer,
|
|
1700
|
-
operations(nodes, ctx) {
|
|
1701
|
-
const { config, driver, resolver, root } = ctx;
|
|
1702
|
-
const { output, group, dataReturnType, paramsCasing, paramsType, pathParamsType, parser, importPath } = ctx.options;
|
|
1703
|
-
const baseURL = ctx.options.baseURL ?? ctx.meta.baseURL;
|
|
1704
|
-
const pluginTs = driver.getPlugin(_kubb_plugin_ts.pluginTsName);
|
|
1705
|
-
if (!pluginTs) return null;
|
|
1706
|
-
const tsResolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
|
|
1707
|
-
const tsPluginOptions = pluginTs.options;
|
|
1708
|
-
const pluginZod = isParserEnabled(parser) ? driver.getPlugin(_kubb_plugin_zod.pluginZodName) : null;
|
|
1709
|
-
const zodResolver = pluginZod ? driver.getResolver(_kubb_plugin_zod.pluginZodName) : null;
|
|
1710
|
-
function buildOperationData(node) {
|
|
1711
|
-
const typeFile = tsResolver.resolveFile(operationFileEntry(node, node.operationId), {
|
|
1712
|
-
root,
|
|
1713
|
-
output: tsPluginOptions?.output ?? output,
|
|
1714
|
-
group: tsPluginOptions?.group
|
|
1715
|
-
});
|
|
1716
|
-
const zodFile = zodResolver && pluginZod?.options ? zodResolver.resolveFile(operationFileEntry(node, node.operationId), {
|
|
1717
|
-
root,
|
|
1718
|
-
output: pluginZod.options?.output ?? output,
|
|
1719
|
-
group: pluginZod.options?.group ?? void 0
|
|
1720
|
-
}) : null;
|
|
1721
|
-
return {
|
|
1722
|
-
node,
|
|
1723
|
-
name: resolver.resolveName(node.operationId),
|
|
1724
|
-
tsResolver,
|
|
1725
|
-
zodResolver,
|
|
1726
|
-
typeFile,
|
|
1727
|
-
zodFile
|
|
1728
|
-
};
|
|
1729
|
-
}
|
|
1730
|
-
const controllers = nodes.reduce((acc, operationNode) => {
|
|
1731
|
-
if (!_kubb_core.ast.isHttpOperationNode(operationNode)) return acc;
|
|
1732
|
-
const tag = operationNode.tags[0];
|
|
1733
|
-
const groupName = tag ? group?.name?.({ group: camelCase(tag) }) ?? resolver.resolveGroupName(tag) : resolver.resolveClassName("Client");
|
|
1734
|
-
if (!tag && !group) {
|
|
1735
|
-
const name = resolver.resolveClassName("ApiClient");
|
|
1736
|
-
const file = resolver.resolveFile({
|
|
1737
|
-
name,
|
|
1738
|
-
extname: ".ts"
|
|
1739
|
-
}, {
|
|
905
|
+
fileTypes: resolveDependencyOperationFile({
|
|
906
|
+
cache: ctx.cache,
|
|
907
|
+
node,
|
|
908
|
+
resolver: types.resolver,
|
|
1740
909
|
root,
|
|
1741
|
-
output,
|
|
1742
|
-
group: group
|
|
1743
|
-
})
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
if (previous) previous.operations.push(operationData);
|
|
1747
|
-
else acc.push({
|
|
1748
|
-
name,
|
|
1749
|
-
file,
|
|
1750
|
-
operations: [operationData]
|
|
1751
|
-
});
|
|
1752
|
-
return acc;
|
|
1753
|
-
}
|
|
1754
|
-
if (tag) {
|
|
1755
|
-
const name = groupName;
|
|
1756
|
-
const file = resolver.resolveFile({
|
|
1757
|
-
name,
|
|
1758
|
-
extname: ".ts",
|
|
1759
|
-
tag
|
|
1760
|
-
}, {
|
|
910
|
+
output: types.output ?? output,
|
|
911
|
+
group: types.group
|
|
912
|
+
}),
|
|
913
|
+
fileZod: zodResolver && pluginZod?.options ? zodResolver.file({
|
|
914
|
+
...operationFileEntry(node, node.operationId),
|
|
1761
915
|
root,
|
|
1762
|
-
output,
|
|
1763
|
-
group: group ?? void 0
|
|
1764
|
-
})
|
|
1765
|
-
const operationData = buildOperationData(operationNode);
|
|
1766
|
-
const previous = acc.find((item) => item.file.path === file.path);
|
|
1767
|
-
if (previous) previous.operations.push(operationData);
|
|
1768
|
-
else acc.push({
|
|
1769
|
-
name,
|
|
1770
|
-
file,
|
|
1771
|
-
operations: [operationData]
|
|
1772
|
-
});
|
|
1773
|
-
}
|
|
1774
|
-
return acc;
|
|
1775
|
-
}, []);
|
|
1776
|
-
function collectTypeImports(ops) {
|
|
1777
|
-
const typeImportsByFile = /* @__PURE__ */ new Map();
|
|
1778
|
-
const typeFilesByPath = /* @__PURE__ */ new Map();
|
|
1779
|
-
ops.forEach((op) => {
|
|
1780
|
-
const names = resolveTypeImportNames(op.node, tsResolver);
|
|
1781
|
-
if (!typeImportsByFile.has(op.typeFile.path)) typeImportsByFile.set(op.typeFile.path, /* @__PURE__ */ new Set());
|
|
1782
|
-
const imports = typeImportsByFile.get(op.typeFile.path);
|
|
1783
|
-
names.forEach((n) => {
|
|
1784
|
-
imports.add(n);
|
|
1785
|
-
});
|
|
1786
|
-
typeFilesByPath.set(op.typeFile.path, op.typeFile);
|
|
1787
|
-
});
|
|
1788
|
-
return {
|
|
1789
|
-
typeImportsByFile,
|
|
1790
|
-
typeFilesByPath
|
|
916
|
+
output: pluginZod.options.output ?? output,
|
|
917
|
+
group: pluginZod.options?.group ?? void 0
|
|
918
|
+
}) : null
|
|
1791
919
|
};
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
ops.forEach((op) => {
|
|
1797
|
-
if (!op.zodFile || !zodResolver) return;
|
|
1798
|
-
const names = resolveZodImportNames(op.node, zodResolver, parser);
|
|
1799
|
-
if (!zodImportsByFile.has(op.zodFile.path)) zodImportsByFile.set(op.zodFile.path, /* @__PURE__ */ new Set());
|
|
1800
|
-
const imports = zodImportsByFile.get(op.zodFile.path);
|
|
1801
|
-
names.forEach((n) => {
|
|
1802
|
-
imports.add(n);
|
|
1803
|
-
});
|
|
1804
|
-
zodFilesByPath.set(op.zodFile.path, op.zodFile);
|
|
920
|
+
const security = getOperationSecurity({
|
|
921
|
+
document: ctx.adapter.document,
|
|
922
|
+
method: node.method,
|
|
923
|
+
path: node.path
|
|
1805
924
|
});
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
925
|
+
const customClientPath = resolveClientPath?.(ctx.options, root);
|
|
926
|
+
const clientPath = customClientPath ?? node_path.default.resolve(root, ".kubb/client.ts");
|
|
927
|
+
const clientRoot = customClientPath === void 0 ? meta.file.path : void 0;
|
|
928
|
+
const eventStream = isEventStream(node);
|
|
929
|
+
const clientValueImports = (() => {
|
|
930
|
+
if (eventStream) return ["client", "toEventStream"];
|
|
931
|
+
if (returnType === "plain") return ["client"];
|
|
932
|
+
if (returnType === "data") return ["client", "unwrapResult"];
|
|
933
|
+
return ["client", "withUnwrap"];
|
|
934
|
+
})();
|
|
935
|
+
const clientTypeImports = (() => {
|
|
936
|
+
if (eventStream) return [
|
|
937
|
+
"Options",
|
|
938
|
+
"EventStreamResult",
|
|
939
|
+
"SuccessOf"
|
|
940
|
+
];
|
|
941
|
+
if (returnType === "plain") return ["Options", "RequestResult"];
|
|
942
|
+
if (returnType === "data") return ["Options", "UnwrappedResult"];
|
|
943
|
+
return [
|
|
944
|
+
"Options",
|
|
945
|
+
"Unwrappable",
|
|
946
|
+
"RequestResult"
|
|
947
|
+
];
|
|
948
|
+
})();
|
|
949
|
+
return /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsxs)(kubb_jsx.File, {
|
|
950
|
+
baseName: meta.file.baseName,
|
|
951
|
+
path: meta.file.path,
|
|
952
|
+
meta: meta.file.meta,
|
|
953
|
+
banner: resolver.default.banner(ctx.meta, {
|
|
1823
954
|
output,
|
|
1824
955
|
config,
|
|
1825
956
|
file: {
|
|
1826
|
-
path: file.path,
|
|
1827
|
-
baseName: file.baseName
|
|
957
|
+
path: meta.file.path,
|
|
958
|
+
baseName: meta.file.baseName
|
|
1828
959
|
}
|
|
1829
960
|
}),
|
|
1830
|
-
footer: resolver.
|
|
961
|
+
footer: resolver.default.footer(ctx.meta, {
|
|
1831
962
|
output,
|
|
1832
963
|
config,
|
|
1833
964
|
file: {
|
|
1834
|
-
path: file.path,
|
|
1835
|
-
baseName: file.baseName
|
|
965
|
+
path: meta.file.path,
|
|
966
|
+
baseName: meta.file.baseName
|
|
1836
967
|
}
|
|
1837
968
|
}),
|
|
1838
969
|
children: [
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
}),
|
|
1844
|
-
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1845
|
-
name: ["mergeConfig"],
|
|
1846
|
-
path: importPath
|
|
1847
|
-
}),
|
|
1848
|
-
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1849
|
-
name: [
|
|
1850
|
-
"Client",
|
|
1851
|
-
"RequestConfig",
|
|
1852
|
-
"ResponseErrorConfig"
|
|
1853
|
-
],
|
|
1854
|
-
path: importPath,
|
|
1855
|
-
isTypeOnly: true
|
|
1856
|
-
})
|
|
1857
|
-
] }) : /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [
|
|
1858
|
-
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1859
|
-
name: ["client"],
|
|
1860
|
-
root: file.path,
|
|
1861
|
-
path: node_path.default.resolve(root, ".kubb/client.ts")
|
|
1862
|
-
}),
|
|
1863
|
-
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1864
|
-
name: ["mergeConfig"],
|
|
1865
|
-
root: file.path,
|
|
1866
|
-
path: node_path.default.resolve(root, ".kubb/client.ts")
|
|
1867
|
-
}),
|
|
1868
|
-
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1869
|
-
name: [
|
|
1870
|
-
"Client",
|
|
1871
|
-
"RequestConfig",
|
|
1872
|
-
"ResponseErrorConfig"
|
|
1873
|
-
],
|
|
1874
|
-
root: file.path,
|
|
1875
|
-
path: node_path.default.resolve(root, ".kubb/client.ts"),
|
|
1876
|
-
isTypeOnly: true
|
|
1877
|
-
})
|
|
1878
|
-
] }),
|
|
1879
|
-
hasFormData && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1880
|
-
name: ["buildFormData"],
|
|
1881
|
-
root: file.path,
|
|
1882
|
-
path: node_path.default.resolve(root, ".kubb/config.ts")
|
|
970
|
+
/* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
|
|
971
|
+
name: clientValueImports,
|
|
972
|
+
root: clientRoot,
|
|
973
|
+
path: clientPath
|
|
1883
974
|
}),
|
|
1884
|
-
|
|
1885
|
-
name:
|
|
1886
|
-
|
|
975
|
+
/* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
|
|
976
|
+
name: clientTypeImports,
|
|
977
|
+
root: clientRoot,
|
|
978
|
+
path: clientPath,
|
|
1887
979
|
isTypeOnly: true
|
|
1888
980
|
}),
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1895
|
-
name: importNames,
|
|
1896
|
-
root: file.path,
|
|
1897
|
-
path: typeFile.path,
|
|
1898
|
-
isTypeOnly: true
|
|
1899
|
-
}, filePath);
|
|
981
|
+
meta.fileTypes && importedTypeNames.length > 0 && /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
|
|
982
|
+
name: Array.from(new Set(importedTypeNames)),
|
|
983
|
+
root: meta.file.path,
|
|
984
|
+
path: meta.fileTypes.path,
|
|
985
|
+
isTypeOnly: true
|
|
1900
986
|
}),
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
if (importNames.length === 0) return null;
|
|
1906
|
-
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1907
|
-
name: importNames,
|
|
1908
|
-
root: file.path,
|
|
1909
|
-
path: zodFile.path
|
|
1910
|
-
}, filePath);
|
|
987
|
+
meta.fileZod && importedZodNames.length > 0 && /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
|
|
988
|
+
name: importedZodNames,
|
|
989
|
+
root: meta.file.path,
|
|
990
|
+
path: meta.fileZod.path
|
|
1911
991
|
}),
|
|
1912
|
-
/* @__PURE__ */ (0,
|
|
1913
|
-
name,
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
992
|
+
/* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(Operation, {
|
|
993
|
+
name: meta.name,
|
|
994
|
+
node,
|
|
995
|
+
types,
|
|
996
|
+
zodResolver,
|
|
997
|
+
validator,
|
|
998
|
+
returnType,
|
|
999
|
+
throwOnErrorDefault,
|
|
1000
|
+
security
|
|
1921
1001
|
})
|
|
1922
1002
|
]
|
|
1923
|
-
}
|
|
1924
|
-
}
|
|
1925
|
-
}
|
|
1926
|
-
}
|
|
1003
|
+
});
|
|
1004
|
+
}
|
|
1005
|
+
});
|
|
1006
|
+
}
|
|
1007
|
+
//#endregion
|
|
1008
|
+
//#region ../../internals/client/src/macros.ts
|
|
1009
|
+
/**
|
|
1010
|
+
* Macros the client plugins apply by default, ahead of any user macros. `macroSimplifyUnion`
|
|
1011
|
+
* drops union members a broader scalar already covers, keeping the generated response and error
|
|
1012
|
+
* unions tidy. A plugin wires them with `ctx.setMacros([...defaultMacros, ...userMacros])`.
|
|
1013
|
+
*/
|
|
1014
|
+
const defaultMacros = [kubb_kit.macroSimplifyUnion];
|
|
1927
1015
|
//#endregion
|
|
1928
|
-
//#region src/
|
|
1016
|
+
//#region ../../internals/client/src/resolver.ts
|
|
1929
1017
|
/**
|
|
1930
|
-
* Default resolver
|
|
1931
|
-
*
|
|
1932
|
-
* camelCase; classes and tag groups use PascalCase.
|
|
1018
|
+
* Default resolver shared by the client plugins. Functions and files inherit the built-in camelCase
|
|
1019
|
+
* `name` and `file`; classes and tag groups use PascalCase.
|
|
1933
1020
|
*
|
|
1934
|
-
* @example
|
|
1021
|
+
* @example
|
|
1935
1022
|
* ```ts
|
|
1936
|
-
*
|
|
1937
|
-
*
|
|
1938
|
-
* resolverClient.default('list pets', 'function') // 'listPets'
|
|
1939
|
-
* resolverClient.resolveClassName('pet') // 'Pet'
|
|
1940
|
-
* resolverClient.resolveGroupName('pet') // 'PetClient'
|
|
1941
|
-
* resolverClient.resolveUrlName(operationNode) // 'getShowPetByIdUrl'
|
|
1023
|
+
* resolverClient.name('show pet by id') // 'showPetById'
|
|
1024
|
+
* resolverClient.groupName('pet') // 'PetClient'
|
|
1942
1025
|
* ```
|
|
1943
1026
|
*/
|
|
1944
|
-
const resolverClient = (0,
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
default(name, type) {
|
|
1948
|
-
if (type === "file") return toFilePath(name);
|
|
1949
|
-
return ensureValidVarName(camelCase(name));
|
|
1950
|
-
},
|
|
1951
|
-
resolveName(name) {
|
|
1952
|
-
return this.default(name, "function");
|
|
1953
|
-
},
|
|
1954
|
-
resolvePathName(name, type) {
|
|
1955
|
-
return this.default(name, type);
|
|
1956
|
-
},
|
|
1957
|
-
resolveClassName(name) {
|
|
1027
|
+
const resolverClient = (0, kubb_kit.createResolver)({
|
|
1028
|
+
pluginName: "plugin-contract-client",
|
|
1029
|
+
className(name) {
|
|
1958
1030
|
return ensureValidVarName(pascalCase(name));
|
|
1959
1031
|
},
|
|
1960
|
-
|
|
1032
|
+
groupName(name) {
|
|
1961
1033
|
return ensureValidVarName(pascalCase(`${name} Client`));
|
|
1962
1034
|
},
|
|
1963
|
-
|
|
1035
|
+
propertyName(name) {
|
|
1964
1036
|
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`;
|
|
1969
1037
|
}
|
|
1970
|
-
})
|
|
1038
|
+
});
|
|
1039
|
+
//#endregion
|
|
1040
|
+
//#region src/generators/clientGenerator.tsx
|
|
1041
|
+
/**
|
|
1042
|
+
* Built-in operation generator for `@kubb/plugin-client`. Emits one async function per OpenAPI
|
|
1043
|
+
* operation using the shared `Operation` component: a grouped `<Name>Request` type and a function
|
|
1044
|
+
* that forwards a single `options` object to the user-provided client module and returns the `RequestResult`.
|
|
1045
|
+
*/
|
|
1046
|
+
const clientGenerator = createClientGenerator("client", (options) => options.importPath);
|
|
1971
1047
|
//#endregion
|
|
1972
1048
|
//#region src/plugin.ts
|
|
1973
1049
|
/**
|
|
1974
|
-
* Canonical plugin name for `@kubb/plugin-client`.
|
|
1975
|
-
* cross-plugin dependency references.
|
|
1050
|
+
* Canonical plugin name for `@kubb/plugin-client`.
|
|
1976
1051
|
*/
|
|
1977
1052
|
const pluginClientName = "plugin-client";
|
|
1978
1053
|
/**
|
|
1979
|
-
* Generates
|
|
1980
|
-
*
|
|
1981
|
-
*
|
|
1982
|
-
* your own by setting `importPath`.
|
|
1054
|
+
* Generates typed operations that call a client module owned by your application.
|
|
1055
|
+
* The module at `importPath` must export the runtime helpers and types used by generated operations.
|
|
1056
|
+
* Kubb does not copy or inject a transport implementation.
|
|
1983
1057
|
*
|
|
1984
1058
|
* @example
|
|
1985
1059
|
* ```ts
|
|
1986
|
-
*
|
|
1987
|
-
* import { pluginTs } from '@kubb/plugin-ts'
|
|
1988
|
-
* import { pluginClient } from '@kubb/plugin-client'
|
|
1989
|
-
*
|
|
1990
|
-
* export default defineConfig({
|
|
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
|
-
* ],
|
|
2000
|
-
* })
|
|
1060
|
+
* pluginClient({ importPath: '../api/client' })
|
|
2001
1061
|
* ```
|
|
2002
1062
|
*/
|
|
2003
|
-
const pluginClient = (0,
|
|
1063
|
+
const pluginClient = (0, kubb_kit.definePlugin)((options) => {
|
|
2004
1064
|
const { output = {
|
|
2005
1065
|
path: "clients",
|
|
2006
1066
|
barrel: { type: "named" }
|
|
2007
|
-
},
|
|
2008
|
-
const
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
1067
|
+
}, exclude = [], include, override = [], importPath, throwOnErrorDefault = true, validator = false, group, resolver: userResolver } = options;
|
|
1068
|
+
const resolved = {
|
|
1069
|
+
output,
|
|
1070
|
+
exclude,
|
|
1071
|
+
include,
|
|
1072
|
+
override,
|
|
1073
|
+
group: createGroupConfig(group),
|
|
1074
|
+
importPath,
|
|
1075
|
+
baseURL: void 0,
|
|
1076
|
+
throwOnErrorDefault,
|
|
1077
|
+
validator,
|
|
1078
|
+
returnType: "plain",
|
|
1079
|
+
sdk: void 0,
|
|
1080
|
+
resolver: userResolver ? kubb_kit.Resolver.merge(resolverClient, userResolver) : resolverClient
|
|
1081
|
+
};
|
|
2015
1082
|
return {
|
|
2016
1083
|
name: pluginClientName,
|
|
2017
1084
|
options,
|
|
2018
|
-
dependencies: [_kubb_plugin_ts.pluginTsName,
|
|
1085
|
+
dependencies: [_kubb_plugin_ts.pluginTsName, _kubb_plugin_zod.pluginZodName],
|
|
2019
1086
|
hooks: { "kubb:plugin:setup"(ctx) {
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
ctx.
|
|
2025
|
-
client,
|
|
2026
|
-
clientType,
|
|
2027
|
-
bundle,
|
|
2028
|
-
output,
|
|
2029
|
-
exclude,
|
|
2030
|
-
include,
|
|
2031
|
-
override,
|
|
2032
|
-
group: groupConfig,
|
|
2033
|
-
parser,
|
|
2034
|
-
dataReturnType,
|
|
2035
|
-
importPath: resolvedImportPath,
|
|
2036
|
-
baseURL,
|
|
2037
|
-
paramsType,
|
|
2038
|
-
paramsCasing,
|
|
2039
|
-
pathParamsType,
|
|
2040
|
-
urlType,
|
|
2041
|
-
sdk,
|
|
2042
|
-
resolver
|
|
2043
|
-
});
|
|
2044
|
-
ctx.setResolver(resolver);
|
|
2045
|
-
if (userTransformer) ctx.setTransformer(userTransformer);
|
|
2046
|
-
for (const gen of selectedGenerators) ctx.addGenerator(gen);
|
|
2047
|
-
const root = node_path$1.default.resolve(ctx.config.root, ctx.config.output.path);
|
|
2048
|
-
if (!resolvedImportPath?.startsWith(".")) {
|
|
2049
|
-
const isInlineSource = bundle && !resolvedImportPath;
|
|
2050
|
-
ctx.injectFile({
|
|
2051
|
-
baseName: "client.ts",
|
|
2052
|
-
path: node_path$1.default.resolve(root, ".kubb/client.ts"),
|
|
2053
|
-
sources: [_kubb_core.ast.createSource({
|
|
2054
|
-
name: "client",
|
|
2055
|
-
nodes: isInlineSource ? [_kubb_core.ast.createText(client === "fetch" ? require_templates_clients_fetch_source.source : require_templates_clients_axios_source.source)] : [],
|
|
2056
|
-
isExportable: true,
|
|
2057
|
-
isIndexable: true
|
|
2058
|
-
})],
|
|
2059
|
-
exports: !isInlineSource && resolvedImportPath ? [_kubb_core.ast.createExport({ path: resolvedImportPath })] : []
|
|
2060
|
-
});
|
|
2061
|
-
}
|
|
2062
|
-
ctx.injectFile({
|
|
2063
|
-
baseName: "config.ts",
|
|
2064
|
-
path: node_path$1.default.resolve(root, ".kubb/config.ts"),
|
|
2065
|
-
sources: [_kubb_core.ast.createSource({
|
|
2066
|
-
name: "config",
|
|
2067
|
-
nodes: [_kubb_core.ast.createText(require_templates_config_source.source)],
|
|
2068
|
-
isExportable: false,
|
|
2069
|
-
isIndexable: false
|
|
2070
|
-
})]
|
|
2071
|
-
});
|
|
1087
|
+
if (validator && !ctx.config.plugins?.some((plugin) => plugin.name === _kubb_plugin_zod.pluginZodName)) throw new Error(`${pluginClientName}: \`validator\` needs ${_kubb_plugin_zod.pluginZodName}. Add pluginZod() to the plugins or set \`validator: false\`.`);
|
|
1088
|
+
ctx.setOptions(resolved);
|
|
1089
|
+
ctx.setResolver(resolved.resolver);
|
|
1090
|
+
ctx.setMacros([...defaultMacros, ...options.macros ?? []]);
|
|
1091
|
+
ctx.addGenerator(clientGenerator);
|
|
2072
1092
|
} }
|
|
2073
1093
|
};
|
|
2074
1094
|
});
|
|
2075
1095
|
//#endregion
|
|
2076
|
-
exports.Client = Client;
|
|
2077
|
-
exports.classClientGenerator = classClientGenerator;
|
|
2078
|
-
exports.clientGenerator = clientGenerator;
|
|
2079
1096
|
exports.default = pluginClient;
|
|
2080
|
-
exports.groupedClientGenerator = groupedClientGenerator;
|
|
2081
|
-
exports.isParserEnabled = isParserEnabled;
|
|
2082
|
-
exports.operationsGenerator = operationsGenerator;
|
|
2083
1097
|
exports.pluginClient = pluginClient;
|
|
2084
1098
|
exports.pluginClientName = pluginClientName;
|
|
2085
|
-
exports.resolveQueryParamsParser = resolveQueryParamsParser;
|
|
2086
|
-
exports.resolveRequestParser = resolveRequestParser;
|
|
2087
|
-
exports.resolveResponseParser = resolveResponseParser;
|
|
2088
|
-
exports.resolverClient = resolverClient;
|
|
2089
|
-
exports.staticClassClientGenerator = staticClassClientGenerator;
|
|
2090
1099
|
|
|
2091
1100
|
//# sourceMappingURL=index.cjs.map
|