@kubb/plugin-mcp 5.0.0-beta.98 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +102 -316
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +101 -315
- package/dist/index.js.map +1 -1
- package/package.json +7 -10
package/dist/index.cjs
CHANGED
|
@@ -19,309 +19,32 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
19
19
|
}
|
|
20
20
|
return to;
|
|
21
21
|
};
|
|
22
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
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
23
|
value: mod,
|
|
24
24
|
enumerable: true
|
|
25
25
|
}) : target, mod));
|
|
26
26
|
//#endregion
|
|
27
|
+
let kubb_kit = require("kubb/kit");
|
|
27
28
|
let node_path = require("node:path");
|
|
28
29
|
node_path = __toESM(node_path, 1);
|
|
29
|
-
let kubb_kit = require("kubb/kit");
|
|
30
30
|
let kubb_jsx = require("kubb/jsx");
|
|
31
31
|
let kubb_jsx_jsx_runtime = require("kubb/jsx/jsx-runtime");
|
|
32
32
|
let _kubb_plugin_ts = require("@kubb/plugin-ts");
|
|
33
33
|
let _kubb_plugin_zod = require("@kubb/plugin-zod");
|
|
34
|
-
//#region ../../internals/utils/src/casing.ts
|
|
35
|
-
/**
|
|
36
|
-
* Shared implementation for camelCase and PascalCase conversion.
|
|
37
|
-
* Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)
|
|
38
|
-
* and capitalizes each word according to `pascal`.
|
|
39
|
-
*
|
|
40
|
-
* When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
|
|
41
|
-
*/
|
|
42
|
-
function toCamelOrPascal(text, pascal) {
|
|
43
|
-
return text.trim().replace(/([a-z\d])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/(\d)([a-z])/g, "$1 $2").split(/[\s\-_./\\:]+/).filter(Boolean).map((word, i) => {
|
|
44
|
-
if (word.length > 1 && word === word.toUpperCase()) return word;
|
|
45
|
-
return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
|
|
46
|
-
}).join("").replace(/[^a-zA-Z0-9]/g, "");
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Converts `text` to camelCase.
|
|
50
|
-
*
|
|
51
|
-
* @example Word boundaries
|
|
52
|
-
* `camelCase('hello-world') // 'helloWorld'`
|
|
53
|
-
*
|
|
54
|
-
* @example With a prefix
|
|
55
|
-
* `camelCase('tag', { prefix: 'create' }) // 'createTag'`
|
|
56
|
-
*/
|
|
57
|
-
function camelCase(text, { prefix = "", suffix = "" } = {}) {
|
|
58
|
-
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
|
|
59
|
-
}
|
|
60
|
-
//#endregion
|
|
61
|
-
//#region ../../internals/utils/src/reserved.ts
|
|
62
|
-
/**
|
|
63
|
-
* JavaScript and Java reserved words.
|
|
64
|
-
* @link https://github.com/jonschlinkert/reserved/blob/master/index.js
|
|
65
|
-
*/
|
|
66
|
-
const reservedWords = /* @__PURE__ */ new Set([
|
|
67
|
-
"abstract",
|
|
68
|
-
"arguments",
|
|
69
|
-
"boolean",
|
|
70
|
-
"break",
|
|
71
|
-
"byte",
|
|
72
|
-
"case",
|
|
73
|
-
"catch",
|
|
74
|
-
"char",
|
|
75
|
-
"class",
|
|
76
|
-
"const",
|
|
77
|
-
"continue",
|
|
78
|
-
"debugger",
|
|
79
|
-
"default",
|
|
80
|
-
"delete",
|
|
81
|
-
"do",
|
|
82
|
-
"double",
|
|
83
|
-
"else",
|
|
84
|
-
"enum",
|
|
85
|
-
"eval",
|
|
86
|
-
"export",
|
|
87
|
-
"extends",
|
|
88
|
-
"false",
|
|
89
|
-
"final",
|
|
90
|
-
"finally",
|
|
91
|
-
"float",
|
|
92
|
-
"for",
|
|
93
|
-
"function",
|
|
94
|
-
"goto",
|
|
95
|
-
"if",
|
|
96
|
-
"implements",
|
|
97
|
-
"import",
|
|
98
|
-
"in",
|
|
99
|
-
"instanceof",
|
|
100
|
-
"int",
|
|
101
|
-
"interface",
|
|
102
|
-
"let",
|
|
103
|
-
"long",
|
|
104
|
-
"native",
|
|
105
|
-
"new",
|
|
106
|
-
"null",
|
|
107
|
-
"package",
|
|
108
|
-
"private",
|
|
109
|
-
"protected",
|
|
110
|
-
"public",
|
|
111
|
-
"return",
|
|
112
|
-
"short",
|
|
113
|
-
"static",
|
|
114
|
-
"super",
|
|
115
|
-
"switch",
|
|
116
|
-
"synchronized",
|
|
117
|
-
"this",
|
|
118
|
-
"throw",
|
|
119
|
-
"throws",
|
|
120
|
-
"transient",
|
|
121
|
-
"true",
|
|
122
|
-
"try",
|
|
123
|
-
"typeof",
|
|
124
|
-
"var",
|
|
125
|
-
"void",
|
|
126
|
-
"volatile",
|
|
127
|
-
"while",
|
|
128
|
-
"with",
|
|
129
|
-
"yield",
|
|
130
|
-
"Array",
|
|
131
|
-
"Date",
|
|
132
|
-
"hasOwnProperty",
|
|
133
|
-
"Infinity",
|
|
134
|
-
"isFinite",
|
|
135
|
-
"isNaN",
|
|
136
|
-
"isPrototypeOf",
|
|
137
|
-
"length",
|
|
138
|
-
"Math",
|
|
139
|
-
"name",
|
|
140
|
-
"NaN",
|
|
141
|
-
"Number",
|
|
142
|
-
"Object",
|
|
143
|
-
"prototype",
|
|
144
|
-
"String",
|
|
145
|
-
"toString",
|
|
146
|
-
"undefined",
|
|
147
|
-
"valueOf"
|
|
148
|
-
]);
|
|
149
|
-
/**
|
|
150
|
-
* Returns `true` when `name` is a syntactically valid JavaScript variable name.
|
|
151
|
-
*
|
|
152
|
-
* @example
|
|
153
|
-
* ```ts
|
|
154
|
-
* isValidVarName('status') // true
|
|
155
|
-
* isValidVarName('class') // false (reserved word)
|
|
156
|
-
* isValidVarName('42foo') // false (starts with digit)
|
|
157
|
-
* ```
|
|
158
|
-
*/
|
|
159
|
-
function isValidVarName(name) {
|
|
160
|
-
if (!name || reservedWords.has(name)) return false;
|
|
161
|
-
return isIdentifier(name);
|
|
162
|
-
}
|
|
163
|
-
/**
|
|
164
|
-
* Returns `true` when `name` is syntactically a valid identifier, ignoring reserved words.
|
|
165
|
-
*
|
|
166
|
-
* Reserved words and globals (`class`, `name`, `Date`, …) are valid as bare object-literal keys
|
|
167
|
-
* even though they are not valid variable names, so use this (not {@link isValidVarName}) when
|
|
168
|
-
* deciding whether an object key needs quoting.
|
|
169
|
-
*
|
|
170
|
-
* @example
|
|
171
|
-
* ```ts
|
|
172
|
-
* isIdentifier('name') // true
|
|
173
|
-
* isIdentifier('x-total')// false
|
|
174
|
-
* ```
|
|
175
|
-
*/
|
|
176
|
-
function isIdentifier(name) {
|
|
177
|
-
return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
|
|
178
|
-
}
|
|
179
|
-
//#endregion
|
|
180
|
-
//#region ../../internals/utils/src/url.ts
|
|
181
|
-
function transformParam(raw, casing) {
|
|
182
|
-
const param = isValidVarName(raw) ? raw : camelCase(raw);
|
|
183
|
-
return casing === "camelcase" ? camelCase(param) : param;
|
|
184
|
-
}
|
|
185
|
-
function toParamsObject(path, { replacer, casing } = {}) {
|
|
186
|
-
const params = {};
|
|
187
|
-
for (const match of path.matchAll(/\{([^}]+)\}/g)) {
|
|
188
|
-
const param = transformParam(match[1], casing);
|
|
189
|
-
const key = replacer ? replacer(param) : param;
|
|
190
|
-
params[key] = key;
|
|
191
|
-
}
|
|
192
|
-
return Object.keys(params).length > 0 ? params : null;
|
|
193
|
-
}
|
|
194
|
-
/**
|
|
195
|
-
* Helpers for OpenAPI/Swagger paths, plus a thin wrapper over the native `URL`.
|
|
196
|
-
*/
|
|
197
|
-
var Url = class Url {
|
|
198
|
-
/**
|
|
199
|
-
* Reports whether `url` is a parseable absolute URL. Delegates to the native `URL.canParse`.
|
|
200
|
-
*
|
|
201
|
-
* @example
|
|
202
|
-
* Url.canParse('https://petstore.swagger.io/v2') // true
|
|
203
|
-
* Url.canParse('/pet/{petId}') // false
|
|
204
|
-
*/
|
|
205
|
-
static canParse(url, base) {
|
|
206
|
-
return URL.canParse(url, base);
|
|
207
|
-
}
|
|
208
|
-
/**
|
|
209
|
-
* Converts an OpenAPI/Swagger path to Express-style colon syntax.
|
|
210
|
-
*
|
|
211
|
-
* @example
|
|
212
|
-
* Url.toPath('/pet/{petId}') // '/pet/:petId'
|
|
213
|
-
*/
|
|
214
|
-
static toPath(path) {
|
|
215
|
-
return path.replace(/\{([^}]+)\}/g, ":$1");
|
|
216
|
-
}
|
|
217
|
-
/**
|
|
218
|
-
* Rewrites OpenAPI placeholder names while keeping the `{...}` braces, so the generated `url`
|
|
219
|
-
* literal aligns with the grouped `path` request option that the runtime client interpolates by
|
|
220
|
-
* key.
|
|
221
|
-
*
|
|
222
|
-
* @example
|
|
223
|
-
* Url.toCasedTemplate('/projects/{project_id}', { casing: 'camelcase' }) // '/projects/{projectId}'
|
|
224
|
-
*/
|
|
225
|
-
static toCasedTemplate(path, { casing } = {}) {
|
|
226
|
-
return path.replace(/\{([^}]+)\}/g, (_, name) => `{${transformParam(name, casing)}}`);
|
|
227
|
-
}
|
|
228
|
-
/**
|
|
229
|
-
* Converts an OpenAPI/Swagger path to a TypeScript template literal string.
|
|
230
|
-
* `prefix` is prepended inside the literal, `replacer` transforms each parameter name,
|
|
231
|
-
* and `casing` controls parameter identifier casing.
|
|
232
|
-
*
|
|
233
|
-
* @example
|
|
234
|
-
* Url.toTemplateString('/pet/{petId}') // '`/pet/${petId}`'
|
|
235
|
-
*
|
|
236
|
-
* @example
|
|
237
|
-
* Url.toTemplateString('/pet/{petId}', { prefix: 'https://api' }) // '`https://api/pet/${petId}`'
|
|
238
|
-
*/
|
|
239
|
-
static toTemplateString(path, { prefix, replacer, casing } = {}) {
|
|
240
|
-
const result = path.split(/\{([^}]+)\}/).map((part, i) => {
|
|
241
|
-
if (i % 2 === 0) return part;
|
|
242
|
-
const param = transformParam(part, casing);
|
|
243
|
-
return `\${${replacer ? replacer(param) : param}}`;
|
|
244
|
-
}).join("");
|
|
245
|
-
return `\`${prefix ?? ""}${result}\``;
|
|
246
|
-
}
|
|
247
|
-
/**
|
|
248
|
-
* Converts an OpenAPI/Swagger path to a template literal that reads each parameter off the
|
|
249
|
-
* grouped `path` request option, e.g. `/pet/{petId}` becomes `` `/pet/${path.petId}` ``. Parameter
|
|
250
|
-
* names are camelCased to match the generated `path` type, and `prefix` is prepended inside the
|
|
251
|
-
* literal. Shared by the client and cypress generators that pass a grouped `path` object.
|
|
252
|
-
*
|
|
253
|
-
* @example
|
|
254
|
-
* Url.toGroupedTemplateString('/pet/{petId}') // '`/pet/${path.petId}`'
|
|
255
|
-
*/
|
|
256
|
-
static toGroupedTemplateString(path, { prefix } = {}) {
|
|
257
|
-
return Url.toTemplateString(path, {
|
|
258
|
-
prefix,
|
|
259
|
-
casing: "camelcase",
|
|
260
|
-
replacer: (name) => `path.${name}`
|
|
261
|
-
});
|
|
262
|
-
}
|
|
263
|
-
/**
|
|
264
|
-
* Returns the path and its extracted params as a structured `URLObject`, or as a stringified
|
|
265
|
-
* expression when `stringify` is set.
|
|
266
|
-
*
|
|
267
|
-
* @example
|
|
268
|
-
* Url.toObject('/pet/{petId}')
|
|
269
|
-
* // { url: '/pet/:petId', params: { petId: 'petId' } }
|
|
270
|
-
*/
|
|
271
|
-
static toObject(path, { type = "path", replacer, stringify, casing } = {}) {
|
|
272
|
-
const object = {
|
|
273
|
-
url: type === "path" ? Url.toPath(path) : Url.toTemplateString(path, {
|
|
274
|
-
replacer,
|
|
275
|
-
casing
|
|
276
|
-
}),
|
|
277
|
-
params: toParamsObject(path, {
|
|
278
|
-
replacer,
|
|
279
|
-
casing
|
|
280
|
-
})
|
|
281
|
-
};
|
|
282
|
-
if (stringify) {
|
|
283
|
-
if (type === "template") return JSON.stringify(object).replaceAll("'", "").replaceAll(`"`, "");
|
|
284
|
-
if (object.params) return `{ url: '${object.url}', params: ${JSON.stringify(object.params).replaceAll("'", "").replaceAll(`"`, "")} }`;
|
|
285
|
-
return `{ url: '${object.url}' }`;
|
|
286
|
-
}
|
|
287
|
-
return object;
|
|
288
|
-
}
|
|
289
|
-
};
|
|
290
|
-
//#endregion
|
|
291
34
|
//#region ../../internals/shared/src/params.ts
|
|
292
|
-
const caseParamsCache = /* @__PURE__ */ new WeakMap();
|
|
293
|
-
/**
|
|
294
|
-
* Applies camelCase to parameter names and returns a new array without mutating the input.
|
|
295
|
-
*
|
|
296
|
-
* Run it before handing parameters to schema builders so output property keys get the right casing
|
|
297
|
-
* while `OperationNode.parameters` stays intact for other consumers. When `casing` is unset, the
|
|
298
|
-
* original array is returned unchanged. Results are cached per input array.
|
|
299
|
-
*/
|
|
300
|
-
function caseParams(params, casing) {
|
|
301
|
-
if (!casing) return params;
|
|
302
|
-
const cached = caseParamsCache.get(params);
|
|
303
|
-
if (cached) return cached;
|
|
304
|
-
const result = params.map((param) => ({
|
|
305
|
-
...param,
|
|
306
|
-
name: camelCase(param.name)
|
|
307
|
-
}));
|
|
308
|
-
caseParamsCache.set(params, result);
|
|
309
|
-
return result;
|
|
310
|
-
}
|
|
311
35
|
/**
|
|
312
|
-
* Drops parameters that
|
|
36
|
+
* Drops parameters that share the same name, keeping the first.
|
|
313
37
|
*
|
|
314
|
-
*
|
|
315
|
-
*
|
|
316
|
-
*
|
|
317
|
-
*
|
|
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.
|
|
318
42
|
*/
|
|
319
|
-
function
|
|
43
|
+
function dedupeParams(params) {
|
|
320
44
|
const seen = /* @__PURE__ */ new Set();
|
|
321
45
|
return params.filter((param) => {
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
seen.add(key);
|
|
46
|
+
if (seen.has(param.name)) return false;
|
|
47
|
+
seen.add(param.name);
|
|
325
48
|
return true;
|
|
326
49
|
});
|
|
327
50
|
}
|
|
@@ -346,11 +69,30 @@ function operationFileEntry(node, name, extname = ".ts") {
|
|
|
346
69
|
path: node.path
|
|
347
70
|
};
|
|
348
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
|
+
}
|
|
349
92
|
function getOperationLink(node, link) {
|
|
350
93
|
if (!link) return null;
|
|
351
94
|
if (typeof link === "function") return link(node) ?? null;
|
|
352
|
-
|
|
353
|
-
return node.path ? `{@link ${node.path.replaceAll("{", ":").replaceAll("}", "")}}` : null;
|
|
95
|
+
return node.path ? `{@link ${kubb_kit.Url.toPath(node.path)}}` : null;
|
|
354
96
|
}
|
|
355
97
|
/**
|
|
356
98
|
* Derives the shared `ContentTypeInfo` shape from a list of content types, tracking whether several
|
|
@@ -451,14 +193,24 @@ function buildOperationComments(node, options = {}) {
|
|
|
451
193
|
if (!splitLines) return filteredComments;
|
|
452
194
|
return filteredComments.flatMap((text) => text.split(/\r?\n/).map((line) => line.trim())).filter((comment) => Boolean(comment));
|
|
453
195
|
}
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
196
|
+
const operationParameterGroupsByNode = /* @__PURE__ */ new WeakMap();
|
|
197
|
+
/**
|
|
198
|
+
* Groups an operation's parameters by location (`path`/`query`/`header`/`cookie`), deduping each
|
|
199
|
+
* group by name. Every plugin generator visiting the same `OperationNode` shares one AST instance
|
|
200
|
+
* (see `KubbDriver`), so the result is cached per node to avoid re-filtering and re-deduping the
|
|
201
|
+
* same parameters once per plugin.
|
|
202
|
+
*/
|
|
203
|
+
function getOperationParameters(node) {
|
|
204
|
+
const cached = operationParameterGroupsByNode.get(node);
|
|
205
|
+
if (cached) return cached;
|
|
206
|
+
const groups = {
|
|
207
|
+
path: dedupeParams(node.parameters.filter((param) => param.in === "path")),
|
|
208
|
+
query: dedupeParams(node.parameters.filter((param) => param.in === "query")),
|
|
209
|
+
header: dedupeParams(node.parameters.filter((param) => param.in === "header")),
|
|
210
|
+
cookie: dedupeParams(node.parameters.filter((param) => param.in === "cookie"))
|
|
461
211
|
};
|
|
212
|
+
operationParameterGroupsByNode.set(node, groups);
|
|
213
|
+
return groups;
|
|
462
214
|
}
|
|
463
215
|
function getStatusCodeNumber(statusCode) {
|
|
464
216
|
const code = Number(statusCode);
|
|
@@ -482,6 +234,33 @@ function findSuccessStatusCode(responses) {
|
|
|
482
234
|
return null;
|
|
483
235
|
}
|
|
484
236
|
//#endregion
|
|
237
|
+
//#region ../../internals/utils/src/casing.ts
|
|
238
|
+
/**
|
|
239
|
+
* Shared implementation for camelCase and PascalCase conversion.
|
|
240
|
+
* Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)
|
|
241
|
+
* and capitalizes each word according to `pascal`.
|
|
242
|
+
*
|
|
243
|
+
* When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
|
|
244
|
+
*/
|
|
245
|
+
function toCamelOrPascal(text, pascal) {
|
|
246
|
+
return text.trim().replace(/([a-z\d])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/(\d)([a-z])/g, "$1 $2").split(/[\s\-_./\\:]+/).filter(Boolean).map((word, i) => {
|
|
247
|
+
if (word.length > 1 && word === word.toUpperCase()) return word;
|
|
248
|
+
return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
|
|
249
|
+
}).join("").replace(/[^a-zA-Z0-9]/g, "");
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Converts `text` to camelCase.
|
|
253
|
+
*
|
|
254
|
+
* @example Word boundaries
|
|
255
|
+
* `camelCase('hello-world') // 'helloWorld'`
|
|
256
|
+
*
|
|
257
|
+
* @example With a prefix
|
|
258
|
+
* `camelCase('tag', { prefix: 'create' }) // 'createTag'`
|
|
259
|
+
*/
|
|
260
|
+
function camelCase(text, { prefix = "", suffix = "" } = {}) {
|
|
261
|
+
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
|
|
262
|
+
}
|
|
263
|
+
//#endregion
|
|
485
264
|
//#region ../../internals/shared/src/group.ts
|
|
486
265
|
/**
|
|
487
266
|
* Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the
|
|
@@ -768,23 +547,30 @@ function resolveContractClient(options) {
|
|
|
768
547
|
* (plugin-fetch or plugin-axios). Returns `null` when no contract plugin is in play (the inline
|
|
769
548
|
* path). The plugin injects `.kubb/client.ts` at the global output root, the same path consumers
|
|
770
549
|
* read `RequestConfig` / `ResponseErrorConfig` from.
|
|
550
|
+
*
|
|
551
|
+
* The result is cached in the current node's `cache` (`ctx.cache`) under the client plugin's name,
|
|
552
|
+
* so several dependents reading the same client plugin for one operation in a single pass
|
|
553
|
+
* (react-query's query/mutation/infinite generators, vue-query, swr, the MCP handler, ...) share
|
|
554
|
+
* one computed result instead of each re-deriving the name and path.
|
|
771
555
|
*/
|
|
772
556
|
function resolveClientOperation(options) {
|
|
773
|
-
const { clientPlugin, driver, node, root, output } = options;
|
|
557
|
+
const { clientPlugin, driver, node, root, output, cache } = options;
|
|
774
558
|
if (!clientPlugin) return null;
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
559
|
+
return cache.ensureItem(`${clientPlugin.pluginName}:clientOperation`, () => {
|
|
560
|
+
const resolver = driver.getResolver(clientPlugin.pluginName);
|
|
561
|
+
const plugin = driver.getPlugin(clientPlugin.pluginName);
|
|
562
|
+
const file = resolver.file({
|
|
563
|
+
...operationFileEntry(node, node.operationId),
|
|
564
|
+
root,
|
|
565
|
+
output: plugin?.options?.output ?? output,
|
|
566
|
+
group: plugin?.options?.group ?? void 0
|
|
567
|
+
});
|
|
568
|
+
return {
|
|
569
|
+
name: resolver.name(node.operationId),
|
|
570
|
+
path: file.path,
|
|
571
|
+
clientPath: node_path.default.resolve(root, ".kubb/client.ts")
|
|
572
|
+
};
|
|
782
573
|
});
|
|
783
|
-
return {
|
|
784
|
-
name: resolver.name(node.operationId),
|
|
785
|
-
path: file.path,
|
|
786
|
-
clientPath: node_path.default.resolve(root, ".kubb/client.ts")
|
|
787
|
-
};
|
|
788
574
|
}
|
|
789
575
|
//#endregion
|
|
790
576
|
//#region src/generators/mcpGenerator.tsx
|
|
@@ -809,7 +595,8 @@ const mcpGenerator = (0, kubb_kit.defineGenerator)({
|
|
|
809
595
|
driver,
|
|
810
596
|
node,
|
|
811
597
|
root,
|
|
812
|
-
output
|
|
598
|
+
output,
|
|
599
|
+
cache: ctx.cache
|
|
813
600
|
});
|
|
814
601
|
if (!contractOp) return null;
|
|
815
602
|
const optionsName = tsResolver.response.options(node);
|
|
@@ -824,14 +611,13 @@ const mcpGenerator = (0, kubb_kit.defineGenerator)({
|
|
|
824
611
|
output,
|
|
825
612
|
group: group ?? void 0
|
|
826
613
|
}),
|
|
827
|
-
fileTs:
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
path: node.path,
|
|
614
|
+
fileTs: resolveDependencyOperationFile({
|
|
615
|
+
cache: ctx.cache,
|
|
616
|
+
node,
|
|
617
|
+
resolver: tsResolver,
|
|
832
618
|
root,
|
|
833
619
|
output: pluginTs.options?.output ?? output,
|
|
834
|
-
group: pluginTs.options?.group
|
|
620
|
+
group: pluginTs.options?.group
|
|
835
621
|
})
|
|
836
622
|
};
|
|
837
623
|
return /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsxs)(kubb_jsx.File, {
|