@kubb/plugin-client 5.0.0-beta.3 → 5.0.0-beta.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -4
- package/dist/clients/axios.cjs +25 -3
- package/dist/clients/axios.cjs.map +1 -1
- package/dist/clients/axios.d.ts +9 -2
- package/dist/clients/axios.js +25 -3
- package/dist/clients/axios.js.map +1 -1
- package/dist/clients/fetch.cjs +76 -8
- package/dist/clients/fetch.cjs.map +1 -1
- package/dist/clients/fetch.d.ts +9 -2
- package/dist/clients/fetch.js +76 -8
- package/dist/clients/fetch.js.map +1 -1
- package/dist/index.cjs +627 -353
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +153 -86
- package/dist/index.js +628 -354
- package/dist/index.js.map +1 -1
- package/dist/templates/clients/axios.source.cjs +1 -1
- package/dist/templates/clients/axios.source.js +1 -1
- package/dist/templates/clients/fetch.source.cjs +1 -1
- package/dist/templates/clients/fetch.source.js +1 -1
- package/extension.yaml +1293 -0
- package/package.json +11 -17
- package/src/clients/axios.ts +41 -7
- package/src/clients/fetch.ts +106 -6
- package/src/components/ClassClient.tsx +19 -20
- package/src/components/Client.tsx +74 -53
- package/src/components/Operations.tsx +2 -1
- package/src/components/StaticClassClient.tsx +19 -20
- package/src/components/Url.tsx +8 -9
- package/src/components/WrapperClient.tsx +9 -5
- package/src/functionParams.ts +8 -8
- package/src/generators/classClientGenerator.tsx +51 -47
- package/src/generators/clientGenerator.tsx +37 -48
- package/src/generators/groupedClientGenerator.tsx +14 -8
- package/src/generators/operationsGenerator.tsx +14 -8
- package/src/generators/staticClassClientGenerator.tsx +45 -41
- package/src/plugin.ts +27 -26
- package/src/resolvers/resolverClient.ts +31 -8
- package/src/types.ts +93 -55
- package/src/utils.ts +35 -56
- package/templates/clients/axios.ts +0 -73
- package/templates/clients/fetch.ts +0 -96
- package/templates/config.ts +0 -43
package/dist/index.cjs
CHANGED
|
@@ -191,6 +191,26 @@ function isValidVarName(name) {
|
|
|
191
191
|
if (!name || reservedWords.has(name)) return false;
|
|
192
192
|
return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
|
|
193
193
|
}
|
|
194
|
+
/**
|
|
195
|
+
* Returns `name` when it's a syntactically valid JavaScript variable name,
|
|
196
|
+
* otherwise prefixes it with `_` so the result is a valid identifier.
|
|
197
|
+
*
|
|
198
|
+
* Useful for sanitizing OpenAPI schema names or operation IDs that start with
|
|
199
|
+
* a digit (e.g. `409`, `504AccountCancel`) before using them as exported
|
|
200
|
+
* variable, type, or function names.
|
|
201
|
+
*
|
|
202
|
+
* @example
|
|
203
|
+
* ```ts
|
|
204
|
+
* ensureValidVarName('409') // '_409'
|
|
205
|
+
* ensureValidVarName('504AccountCancel') // '_504AccountCancel'
|
|
206
|
+
* ensureValidVarName('Pet') // 'Pet'
|
|
207
|
+
* ensureValidVarName('class') // '_class'
|
|
208
|
+
* ```
|
|
209
|
+
*/
|
|
210
|
+
function ensureValidVarName(name) {
|
|
211
|
+
if (!name || isValidVarName(name)) return name;
|
|
212
|
+
return `_${name}`;
|
|
213
|
+
}
|
|
194
214
|
//#endregion
|
|
195
215
|
//#region ../../internals/utils/src/urlPath.ts
|
|
196
216
|
/**
|
|
@@ -257,16 +277,16 @@ var URLPath = class {
|
|
|
257
277
|
get object() {
|
|
258
278
|
return this.toObject();
|
|
259
279
|
}
|
|
260
|
-
/** Returns a map of path parameter names, or `
|
|
280
|
+
/** Returns a map of path parameter names, or `null` when the path has no parameters.
|
|
261
281
|
*
|
|
262
282
|
* @example
|
|
263
283
|
* ```ts
|
|
264
284
|
* new URLPath('/pet/{petId}').params // { petId: 'petId' }
|
|
265
|
-
* new URLPath('/pet').params //
|
|
285
|
+
* new URLPath('/pet').params // null
|
|
266
286
|
* ```
|
|
267
287
|
*/
|
|
268
288
|
get params() {
|
|
269
|
-
return this.
|
|
289
|
+
return this.toParamsObject();
|
|
270
290
|
}
|
|
271
291
|
#transformParam(raw) {
|
|
272
292
|
const param = isValidVarName(raw) ? raw : camelCase(raw);
|
|
@@ -284,7 +304,7 @@ var URLPath = class {
|
|
|
284
304
|
toObject({ type = "path", replacer, stringify } = {}) {
|
|
285
305
|
const object = {
|
|
286
306
|
url: type === "path" ? this.toURLPath() : this.toTemplateString({ replacer }),
|
|
287
|
-
params: this.
|
|
307
|
+
params: this.toParamsObject()
|
|
288
308
|
};
|
|
289
309
|
if (stringify) {
|
|
290
310
|
if (type === "template") return JSON.stringify(object).replaceAll("'", "").replaceAll(`"`, "");
|
|
@@ -300,12 +320,13 @@ var URLPath = class {
|
|
|
300
320
|
* @example
|
|
301
321
|
* new URLPath('/pet/{petId}').toTemplateString() // '`/pet/${petId}`'
|
|
302
322
|
*/
|
|
303
|
-
toTemplateString({ prefix
|
|
304
|
-
|
|
323
|
+
toTemplateString({ prefix, replacer } = {}) {
|
|
324
|
+
const result = this.path.split(/\{([^}]+)\}/).map((part, i) => {
|
|
305
325
|
if (i % 2 === 0) return part;
|
|
306
326
|
const param = this.#transformParam(part);
|
|
307
327
|
return `\${${replacer ? replacer(param) : param}}`;
|
|
308
|
-
}).join("")
|
|
328
|
+
}).join("");
|
|
329
|
+
return `\`${prefix ?? ""}${result}\``;
|
|
309
330
|
}
|
|
310
331
|
/**
|
|
311
332
|
* Extracts all `{param}` segments from the path and returns them as a key-value map.
|
|
@@ -314,17 +335,17 @@ var URLPath = class {
|
|
|
314
335
|
*
|
|
315
336
|
* @example
|
|
316
337
|
* ```ts
|
|
317
|
-
* new URLPath('/pet/{petId}/tag/{tagId}').
|
|
338
|
+
* new URLPath('/pet/{petId}/tag/{tagId}').toParamsObject()
|
|
318
339
|
* // { petId: 'petId', tagId: 'tagId' }
|
|
319
340
|
* ```
|
|
320
341
|
*/
|
|
321
|
-
|
|
342
|
+
toParamsObject(replacer) {
|
|
322
343
|
const params = {};
|
|
323
344
|
this.#eachParam((_raw, param) => {
|
|
324
345
|
const key = replacer ? replacer(param) : param;
|
|
325
346
|
params[key] = key;
|
|
326
347
|
});
|
|
327
|
-
return Object.keys(params).length > 0 ? params :
|
|
348
|
+
return Object.keys(params).length > 0 ? params : null;
|
|
328
349
|
}
|
|
329
350
|
/** Converts the OpenAPI path to Express-style colon syntax.
|
|
330
351
|
*
|
|
@@ -338,6 +359,198 @@ var URLPath = class {
|
|
|
338
359
|
}
|
|
339
360
|
};
|
|
340
361
|
//#endregion
|
|
362
|
+
//#region ../../internals/shared/src/operation.ts
|
|
363
|
+
/**
|
|
364
|
+
* Builds the `ResolverFileParams` every operation generator passes to
|
|
365
|
+
* `resolver.resolveFile`: a file named `name`, tagged by the operation's first
|
|
366
|
+
* tag (or `'default'`), at the operation's path. Centralizes the entry object
|
|
367
|
+
* that was repeated at dozens of call sites across the client and query plugins.
|
|
368
|
+
*
|
|
369
|
+
* @example
|
|
370
|
+
* ```ts
|
|
371
|
+
* resolver.resolveFile(operationFileEntry(node, node.operationId), { root, output, group })
|
|
372
|
+
* ```
|
|
373
|
+
*/
|
|
374
|
+
function operationFileEntry(node, name, extname = ".ts") {
|
|
375
|
+
return {
|
|
376
|
+
name,
|
|
377
|
+
extname,
|
|
378
|
+
tag: node.tags[0] ?? "default",
|
|
379
|
+
path: node.path
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
function getOperationLink(node, link) {
|
|
383
|
+
if (!link) return null;
|
|
384
|
+
if (typeof link === "function") return link(node) ?? null;
|
|
385
|
+
if (link === "urlPath") return node.path ? `{@link ${new URLPath(node.path).URL}}` : null;
|
|
386
|
+
return node.path ? `{@link ${node.path.replaceAll("{", ":").replaceAll("}", "")}}` : null;
|
|
387
|
+
}
|
|
388
|
+
function getContentTypeInfo(node) {
|
|
389
|
+
const contentTypes = node.requestBody?.content?.map((e) => e.contentType) ?? [];
|
|
390
|
+
const isMultipleContentTypes = contentTypes.length > 1;
|
|
391
|
+
return {
|
|
392
|
+
contentTypes,
|
|
393
|
+
isMultipleContentTypes,
|
|
394
|
+
contentTypeUnion: isMultipleContentTypes ? contentTypes.map((ct) => JSON.stringify(ct)).join(" | ") : "",
|
|
395
|
+
defaultContentType: contentTypes[0] ?? "application/json",
|
|
396
|
+
hasFormData: contentTypes.some((ct) => ct === "multipart/form-data")
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Derives the default `responseType` for an operation from its primary success response.
|
|
401
|
+
*
|
|
402
|
+
* Returns a value only when that response declares a single non-JSON content type — a binary type
|
|
403
|
+
* (`application/octet-stream`, `application/pdf`, `image/*`, `audio/*`, `video/*`) maps to `'blob'`
|
|
404
|
+
* and other `text/*` maps to `'text'`. Otherwise `undefined`, leaving the runtime client's
|
|
405
|
+
* `Content-Type` auto-detection in charge.
|
|
406
|
+
*/
|
|
407
|
+
function getResponseType(node) {
|
|
408
|
+
const contentTypes = getPrimarySuccessResponse(node)?.content?.map((entry) => entry.contentType) ?? [];
|
|
409
|
+
if (contentTypes.length !== 1) return void 0;
|
|
410
|
+
const baseType = contentTypes[0].split(";")[0].trim().toLowerCase();
|
|
411
|
+
if (baseType === "application/json" || baseType.endsWith("+json") || baseType === "text/json") return void 0;
|
|
412
|
+
if (baseType.startsWith("text/")) return "text";
|
|
413
|
+
if (baseType === "application/octet-stream" || baseType === "application/pdf" || /^(image|audio|video)\//.test(baseType)) return "blob";
|
|
414
|
+
}
|
|
415
|
+
function buildRequestConfigType(node, resolver) {
|
|
416
|
+
const requestName = node.requestBody?.content?.[0]?.schema ? resolver.resolveDataName(node) : null;
|
|
417
|
+
const { isMultipleContentTypes, contentTypeUnion } = getContentTypeInfo(node);
|
|
418
|
+
return `${requestName ? `Partial<RequestConfig<${requestName}>>` : "Partial<RequestConfig>"} & { ${["client?: Client", isMultipleContentTypes ? `contentType?: ${contentTypeUnion}` : null].filter(Boolean).join("; ")} }`;
|
|
419
|
+
}
|
|
420
|
+
function buildOperationComments(node, options = {}) {
|
|
421
|
+
const { link = "pathTemplate", linkPosition = "afterDeprecated", splitLines = false } = options;
|
|
422
|
+
const linkComment = getOperationLink(node, link);
|
|
423
|
+
const filteredComments = (linkPosition === "beforeDeprecated" ? [
|
|
424
|
+
node.description && `@description ${node.description}`,
|
|
425
|
+
node.summary && `@summary ${node.summary}`,
|
|
426
|
+
linkComment,
|
|
427
|
+
node.deprecated && "@deprecated"
|
|
428
|
+
] : [
|
|
429
|
+
node.description && `@description ${node.description}`,
|
|
430
|
+
node.summary && `@summary ${node.summary}`,
|
|
431
|
+
node.deprecated && "@deprecated",
|
|
432
|
+
linkComment
|
|
433
|
+
]).filter((comment) => Boolean(comment));
|
|
434
|
+
if (!splitLines) return filteredComments;
|
|
435
|
+
return filteredComments.flatMap((text) => text.split(/\r?\n/).map((line) => line.trim())).filter((comment) => Boolean(comment));
|
|
436
|
+
}
|
|
437
|
+
function getOperationParameters(node, options = {}) {
|
|
438
|
+
const params = _kubb_core.ast.caseParams(node.parameters, options.paramsCasing);
|
|
439
|
+
return {
|
|
440
|
+
path: params.filter((param) => param.in === "path"),
|
|
441
|
+
query: params.filter((param) => param.in === "query"),
|
|
442
|
+
header: params.filter((param) => param.in === "header"),
|
|
443
|
+
cookie: params.filter((param) => param.in === "cookie")
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
function getStatusCodeNumber(statusCode) {
|
|
447
|
+
const code = Number(statusCode);
|
|
448
|
+
return Number.isNaN(code) ? null : code;
|
|
449
|
+
}
|
|
450
|
+
function isSuccessStatusCode(statusCode) {
|
|
451
|
+
const code = getStatusCodeNumber(statusCode);
|
|
452
|
+
return code !== null && code >= 200 && code < 300;
|
|
453
|
+
}
|
|
454
|
+
function isErrorStatusCode(statusCode) {
|
|
455
|
+
const code = getStatusCodeNumber(statusCode);
|
|
456
|
+
return code !== null && code >= 400;
|
|
457
|
+
}
|
|
458
|
+
function getSuccessResponses(responses) {
|
|
459
|
+
return responses.filter((response) => isSuccessStatusCode(response.statusCode));
|
|
460
|
+
}
|
|
461
|
+
function getOperationSuccessResponses(node) {
|
|
462
|
+
return getSuccessResponses(node.responses);
|
|
463
|
+
}
|
|
464
|
+
function getPrimarySuccessResponse(node) {
|
|
465
|
+
return getOperationSuccessResponses(node)[0] ?? null;
|
|
466
|
+
}
|
|
467
|
+
function resolveErrorNames(node, resolver) {
|
|
468
|
+
return node.responses.filter((response) => isErrorStatusCode(response.statusCode)).map((response) => resolver.resolveResponseStatusName(node, response.statusCode));
|
|
469
|
+
}
|
|
470
|
+
function resolveSuccessNames(node, resolver) {
|
|
471
|
+
return node.responses.filter((response) => isSuccessStatusCode(response.statusCode)).map((response) => resolver.resolveResponseStatusName(node, response.statusCode));
|
|
472
|
+
}
|
|
473
|
+
function resolveStatusCodeNames(node, resolver) {
|
|
474
|
+
return node.responses.map((response) => resolver.resolveResponseStatusName(node, response.statusCode));
|
|
475
|
+
}
|
|
476
|
+
const typeNamesByResolver = /* @__PURE__ */ new WeakMap();
|
|
477
|
+
function resolveOperationTypeNames(node, resolver, options = {}) {
|
|
478
|
+
const cacheKey = `${node.operationId}\0${options.paramsCasing ?? ""}\0${options.order ?? ""}\0${options.responseStatusNames ?? ""}\0${(options.exclude ?? []).join(",")}`;
|
|
479
|
+
let byResolver = typeNamesByResolver.get(resolver);
|
|
480
|
+
if (byResolver) {
|
|
481
|
+
const cached = byResolver.get(cacheKey);
|
|
482
|
+
if (cached) return cached;
|
|
483
|
+
} else {
|
|
484
|
+
byResolver = /* @__PURE__ */ new Map();
|
|
485
|
+
typeNamesByResolver.set(resolver, byResolver);
|
|
486
|
+
}
|
|
487
|
+
const { path, query, header } = getOperationParameters(node, { paramsCasing: options.paramsCasing });
|
|
488
|
+
const responseStatusNames = options.responseStatusNames === "error" ? resolveErrorNames(node, resolver) : options.responseStatusNames === false ? [] : resolveStatusCodeNames(node, resolver);
|
|
489
|
+
const exclude = new Set(options.exclude ?? []);
|
|
490
|
+
const paramNames = [
|
|
491
|
+
...path.map((param) => resolver.resolvePathParamsName(node, param)),
|
|
492
|
+
...query.map((param) => resolver.resolveQueryParamsName(node, param)),
|
|
493
|
+
...header.map((param) => resolver.resolveHeaderParamsName(node, param))
|
|
494
|
+
];
|
|
495
|
+
const bodyAndResponseNames = [node.requestBody?.content?.[0]?.schema ? resolver.resolveDataName(node) : null, resolver.resolveResponseName(node)];
|
|
496
|
+
const result = (options.order === "body-response-first" ? [
|
|
497
|
+
...bodyAndResponseNames,
|
|
498
|
+
...paramNames,
|
|
499
|
+
...responseStatusNames
|
|
500
|
+
] : [
|
|
501
|
+
...paramNames,
|
|
502
|
+
...bodyAndResponseNames,
|
|
503
|
+
...responseStatusNames
|
|
504
|
+
]).filter((name) => Boolean(name) && !exclude.has(name));
|
|
505
|
+
byResolver.set(cacheKey, result);
|
|
506
|
+
return result;
|
|
507
|
+
}
|
|
508
|
+
//#endregion
|
|
509
|
+
//#region ../../internals/shared/src/group.ts
|
|
510
|
+
/**
|
|
511
|
+
* Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the
|
|
512
|
+
* shared default naming so every plugin groups output consistently:
|
|
513
|
+
*
|
|
514
|
+
* - `path` groups use the second path segment (`/pet/findByStatus` → `pet`).
|
|
515
|
+
* - other groups use `${camelCase(group)}${suffix}` (e.g. `petController`).
|
|
516
|
+
*
|
|
517
|
+
* Returns `null` when grouping is disabled, matching the per-plugin convention.
|
|
518
|
+
*
|
|
519
|
+
* @param group - The user-supplied group option, or `undefined` to disable grouping.
|
|
520
|
+
* @param options.suffix - Appended to non-`path` group names, e.g. `'Controller'` or `'Requests'`.
|
|
521
|
+
* @param options.honorName - When `true`, a user-provided `group.name` overrides the default namer.
|
|
522
|
+
*
|
|
523
|
+
* @example
|
|
524
|
+
* ```ts
|
|
525
|
+
* createGroupConfig(group, { suffix: 'Controller' }) // plugin-ts, plugin-zod
|
|
526
|
+
* createGroupConfig(group, { suffix: 'Controller', honorName: true }) // plugin-faker, plugin-client, …
|
|
527
|
+
* createGroupConfig(group, { suffix: 'Requests', honorName: true }) // plugin-cypress, plugin-mcp
|
|
528
|
+
* ```
|
|
529
|
+
*/
|
|
530
|
+
function createGroupConfig(group, options) {
|
|
531
|
+
if (!group) return null;
|
|
532
|
+
const defaultName = (ctx) => {
|
|
533
|
+
if (group.type === "path") return `${ctx.group.split("/")[1]}`;
|
|
534
|
+
return `${camelCase(ctx.group)}${options.suffix}`;
|
|
535
|
+
};
|
|
536
|
+
return {
|
|
537
|
+
...group,
|
|
538
|
+
name: options.honorName && group.name ? group.name : defaultName
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
//#endregion
|
|
542
|
+
//#region ../../internals/shared/src/params.ts
|
|
543
|
+
function buildParamsMapping(originalParams, mappedParams) {
|
|
544
|
+
const mapping = {};
|
|
545
|
+
let hasChanged = false;
|
|
546
|
+
originalParams.forEach((param, i) => {
|
|
547
|
+
const mappedName = mappedParams[i]?.name ?? param.name;
|
|
548
|
+
mapping[param.name] = mappedName;
|
|
549
|
+
if (param.name !== mappedName) hasChanged = true;
|
|
550
|
+
});
|
|
551
|
+
return hasChanged ? mapping : null;
|
|
552
|
+
}
|
|
553
|
+
//#endregion
|
|
341
554
|
//#region src/functionParams.ts
|
|
342
555
|
const declarationPrinter$4 = (0, _kubb_plugin_ts.functionPrinter)({ mode: "declaration" });
|
|
343
556
|
const callPrinter = (0, _kubb_plugin_ts.functionPrinter)({ mode: "call" });
|
|
@@ -348,18 +561,18 @@ function createType(type) {
|
|
|
348
561
|
return type ? _kubb_core.ast.createParamsType({
|
|
349
562
|
variant: "reference",
|
|
350
563
|
name: type
|
|
351
|
-
}) :
|
|
564
|
+
}) : null;
|
|
352
565
|
}
|
|
353
566
|
function createDeclarationLeaf(name, spec) {
|
|
354
567
|
if (spec.default !== void 0) return _kubb_core.ast.createFunctionParameter({
|
|
355
568
|
name,
|
|
356
|
-
type: createType(spec.type),
|
|
569
|
+
type: createType(spec.type) ?? void 0,
|
|
357
570
|
default: spec.default,
|
|
358
571
|
rest: spec.mode === "inlineSpread"
|
|
359
572
|
});
|
|
360
573
|
return _kubb_core.ast.createFunctionParameter({
|
|
361
574
|
name,
|
|
362
|
-
type: createType(spec.type),
|
|
575
|
+
type: createType(spec.type) ?? void 0,
|
|
363
576
|
optional: !!spec.optional,
|
|
364
577
|
rest: spec.mode === "inlineSpread"
|
|
365
578
|
});
|
|
@@ -368,14 +581,14 @@ function createDeclarationParam(name, spec) {
|
|
|
368
581
|
if (isGroup(spec)) return _kubb_core.ast.createParameterGroup({
|
|
369
582
|
inline: spec.mode === "inlineSpread",
|
|
370
583
|
default: spec.default,
|
|
371
|
-
properties: Object.entries(spec.children).filter(([, child]) => child
|
|
584
|
+
properties: Object.entries(spec.children).filter(([, child]) => child != null).map(([childName, child]) => createDeclarationLeaf(childName, child))
|
|
372
585
|
});
|
|
373
586
|
return createDeclarationLeaf(name, spec);
|
|
374
587
|
}
|
|
375
588
|
function createCallParam(name, spec) {
|
|
376
589
|
if (isGroup(spec)) return _kubb_core.ast.createParameterGroup({
|
|
377
590
|
inline: spec.mode === "inlineSpread",
|
|
378
|
-
properties: Object.entries(spec.children).filter(([, child]) => child
|
|
591
|
+
properties: Object.entries(spec.children).filter(([, child]) => child != null).map(([childName, child]) => _kubb_core.ast.createFunctionParameter({
|
|
379
592
|
name: child?.mode === "inlineSpread" ? spec.mode === "inlineSpread" ? child.value ?? childName : `...${child.value ?? childName}` : child?.value ? `${childName}: ${child.value}` : childName,
|
|
380
593
|
rest: spec.mode === "inlineSpread" && child?.mode === "inlineSpread"
|
|
381
594
|
}))
|
|
@@ -390,7 +603,7 @@ function createCallParam(name, spec) {
|
|
|
390
603
|
* Returns utilities to output constructor signatures (`toConstructor()`) or call expressions (`toCall()`).
|
|
391
604
|
*/
|
|
392
605
|
function createFunctionParams(params) {
|
|
393
|
-
const entries = Object.entries(params).filter(([, spec]) => spec
|
|
606
|
+
const entries = Object.entries(params).filter(([, spec]) => spec != null);
|
|
394
607
|
return {
|
|
395
608
|
toConstructor() {
|
|
396
609
|
return declarationPrinter$4.print(_kubb_core.ast.createFunctionParameters({ params: entries.map(([name, spec]) => createDeclarationParam(name, spec)) })) ?? "";
|
|
@@ -401,106 +614,9 @@ function createFunctionParams(params) {
|
|
|
401
614
|
};
|
|
402
615
|
}
|
|
403
616
|
//#endregion
|
|
404
|
-
//#region src/utils.ts
|
|
405
|
-
/**
|
|
406
|
-
* Extracts documentation comments from an operation node.
|
|
407
|
-
* Includes description, summary, link, and deprecation information.
|
|
408
|
-
*/
|
|
409
|
-
function getComments(node) {
|
|
410
|
-
return [
|
|
411
|
-
node.description && `@description ${node.description}`,
|
|
412
|
-
node.summary && `@summary ${node.summary}`,
|
|
413
|
-
node.path && `{@link ${new URLPath(node.path).URL}}`,
|
|
414
|
-
node.deprecated && "@deprecated"
|
|
415
|
-
].filter((x) => Boolean(x)).flatMap((text) => text.split(/\r?\n/).map((line) => line.trim())).filter((x) => Boolean(x));
|
|
416
|
-
}
|
|
417
|
-
/**
|
|
418
|
-
* Builds a mapping of original parameter names to their transformed (cased) names.
|
|
419
|
-
* Returns undefined if no names have changed.
|
|
420
|
-
*/
|
|
421
|
-
function buildParamsMapping(originalParams, casedParams) {
|
|
422
|
-
const mapping = {};
|
|
423
|
-
let hasChanged = false;
|
|
424
|
-
originalParams.forEach((param, i) => {
|
|
425
|
-
const casedName = casedParams[i]?.name ?? param.name;
|
|
426
|
-
mapping[param.name] = casedName;
|
|
427
|
-
if (param.name !== casedName) hasChanged = true;
|
|
428
|
-
});
|
|
429
|
-
return hasChanged ? mapping : void 0;
|
|
430
|
-
}
|
|
431
|
-
/**
|
|
432
|
-
* Builds HTTP headers array for a client request.
|
|
433
|
-
* Includes Content-Type (if not default) and spreads header parameters if present.
|
|
434
|
-
*/
|
|
435
|
-
function buildHeaders(contentType, hasHeaderParams) {
|
|
436
|
-
return [contentType !== "application/json" && contentType !== "multipart/form-data" ? `'Content-Type': '${contentType}'` : void 0, hasHeaderParams ? "...headers" : void 0].filter(Boolean);
|
|
437
|
-
}
|
|
438
|
-
/**
|
|
439
|
-
* Builds TypeScript generic parameters for a client method.
|
|
440
|
-
* Includes response type, error type, and optional request type.
|
|
441
|
-
*/
|
|
442
|
-
function buildGenerics(node, tsResolver) {
|
|
443
|
-
const responseName = tsResolver.resolveResponseName(node);
|
|
444
|
-
const requestName = node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : void 0;
|
|
445
|
-
const errorNames = node.responses.filter((r) => Number.parseInt(r.statusCode, 10) >= 400).map((r) => tsResolver.resolveResponseStatusName(node, r.statusCode));
|
|
446
|
-
return [
|
|
447
|
-
responseName,
|
|
448
|
-
`ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(" | ") : "Error"}>`,
|
|
449
|
-
requestName || "unknown"
|
|
450
|
-
].filter(Boolean);
|
|
451
|
-
}
|
|
452
|
-
/**
|
|
453
|
-
* Builds the parameters object for a class-based client method.
|
|
454
|
-
* Includes URL, method, base URL, headers, and request/response data.
|
|
455
|
-
*/
|
|
456
|
-
function buildClassClientParams({ node, path, baseURL, tsResolver, isFormData, headers }) {
|
|
457
|
-
const queryParamsName = node.parameters.filter((p) => p.in === "query").length > 0 ? tsResolver.resolveQueryParamsName(node, node.parameters.filter((p) => p.in === "query")[0]) : void 0;
|
|
458
|
-
const requestName = node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : void 0;
|
|
459
|
-
return createFunctionParams({ config: {
|
|
460
|
-
mode: "object",
|
|
461
|
-
children: {
|
|
462
|
-
requestConfig: { mode: "inlineSpread" },
|
|
463
|
-
method: { value: JSON.stringify(node.method.toUpperCase()) },
|
|
464
|
-
url: { value: path.template },
|
|
465
|
-
baseURL: baseURL ? { value: JSON.stringify(baseURL) } : void 0,
|
|
466
|
-
params: queryParamsName ? {} : void 0,
|
|
467
|
-
data: requestName ? { value: isFormData ? "formData as FormData" : "requestData" } : void 0,
|
|
468
|
-
headers: headers.length ? { value: `{ ${headers.join(", ")}, ...requestConfig.headers }` } : void 0
|
|
469
|
-
}
|
|
470
|
-
} });
|
|
471
|
-
}
|
|
472
|
-
/**
|
|
473
|
-
* Builds the request data parsing line for client methods.
|
|
474
|
-
* Applies Zod validation if configured, otherwise uses data directly.
|
|
475
|
-
*/
|
|
476
|
-
function buildRequestDataLine({ parser, node, zodResolver }) {
|
|
477
|
-
const zodRequestName = zodResolver && parser === "zod" && node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : void 0;
|
|
478
|
-
if (parser === "zod" && zodRequestName) return `const requestData = ${zodRequestName}.parse(data)`;
|
|
479
|
-
if (node.requestBody?.content?.[0]?.schema) return "const requestData = data";
|
|
480
|
-
return "";
|
|
481
|
-
}
|
|
482
|
-
/**
|
|
483
|
-
* Builds the form data conversion line for file upload requests.
|
|
484
|
-
* Returns empty string if not applicable.
|
|
485
|
-
*/
|
|
486
|
-
function buildFormDataLine(isFormData, hasRequest) {
|
|
487
|
-
return isFormData && hasRequest ? "const formData = buildFormData(requestData)" : "";
|
|
488
|
-
}
|
|
489
|
-
/**
|
|
490
|
-
* Builds the return statement for a client method.
|
|
491
|
-
* Applies Zod validation to response data if configured, otherwise returns raw response.
|
|
492
|
-
*/
|
|
493
|
-
function buildReturnStatement({ dataReturnType, parser, node, zodResolver }) {
|
|
494
|
-
const zodResponseName = zodResolver && parser === "zod" ? zodResolver.resolveResponseName?.(node) : void 0;
|
|
495
|
-
if (dataReturnType === "full" && parser === "zod" && zodResponseName) return `return {...res, data: ${zodResponseName}.parse(res.data)}`;
|
|
496
|
-
if (dataReturnType === "data" && parser === "zod" && zodResponseName) return `return ${zodResponseName}.parse(res.data)`;
|
|
497
|
-
if (dataReturnType === "full" && parser === "client") return "return res";
|
|
498
|
-
return "return res.data";
|
|
499
|
-
}
|
|
500
|
-
//#endregion
|
|
501
617
|
//#region src/components/Url.tsx
|
|
502
618
|
const declarationPrinter$3 = (0, _kubb_plugin_ts.functionPrinter)({ mode: "declaration" });
|
|
503
|
-
function
|
|
619
|
+
function buildUrlParamsNode({ paramsType, paramsCasing, pathParamsType, node, tsResolver }) {
|
|
504
620
|
const urlNode = {
|
|
505
621
|
...node,
|
|
506
622
|
parameters: node.parameters.filter((p) => p.in === "path"),
|
|
@@ -513,10 +629,10 @@ function getParams$1({ paramsType, paramsCasing, pathParamsType, node, tsResolve
|
|
|
513
629
|
resolver: tsResolver
|
|
514
630
|
});
|
|
515
631
|
}
|
|
516
|
-
require_chunk.__name(getParams$1, "getParams");
|
|
517
632
|
function Url({ name, isExportable = true, isIndexable = true, baseURL, paramsType, paramsCasing, pathParamsType, node, tsResolver }) {
|
|
633
|
+
if (!_kubb_core.ast.isHttpOperationNode(node)) return null;
|
|
518
634
|
const path = new URLPath(node.path);
|
|
519
|
-
const paramsNode =
|
|
635
|
+
const paramsNode = buildUrlParamsNode({
|
|
520
636
|
paramsType,
|
|
521
637
|
paramsCasing,
|
|
522
638
|
pathParamsType,
|
|
@@ -524,9 +640,9 @@ function Url({ name, isExportable = true, isIndexable = true, baseURL, paramsTyp
|
|
|
524
640
|
tsResolver
|
|
525
641
|
});
|
|
526
642
|
const paramsSignature = declarationPrinter$3.print(paramsNode) ?? "";
|
|
527
|
-
const originalPathParams = node
|
|
528
|
-
const casedPathParams =
|
|
529
|
-
const pathParamsMapping = paramsCasing ? buildParamsMapping(originalPathParams, casedPathParams) :
|
|
643
|
+
const { path: originalPathParams } = getOperationParameters(node);
|
|
644
|
+
const { path: casedPathParams } = getOperationParameters(node, { paramsCasing });
|
|
645
|
+
const pathParamsMapping = paramsCasing ? buildParamsMapping(originalPathParams, casedPathParams) : null;
|
|
530
646
|
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
|
|
531
647
|
name,
|
|
532
648
|
isExportable,
|
|
@@ -548,56 +664,53 @@ function Url({ name, isExportable = true, isIndexable = true, baseURL, paramsTyp
|
|
|
548
664
|
})
|
|
549
665
|
});
|
|
550
666
|
}
|
|
551
|
-
Url.getParams = getParams$1;
|
|
552
667
|
//#endregion
|
|
553
668
|
//#region src/components/Client.tsx
|
|
554
669
|
const declarationPrinter$2 = (0, _kubb_plugin_ts.functionPrinter)({ mode: "declaration" });
|
|
555
|
-
function
|
|
556
|
-
const requestName = node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : void 0;
|
|
670
|
+
function buildClientParamsNode({ paramsType, paramsCasing, pathParamsType, node, tsResolver, isConfigurable }) {
|
|
557
671
|
return _kubb_core.ast.createOperationParams(node, {
|
|
558
672
|
paramsType,
|
|
559
673
|
pathParamsType: paramsType === "object" ? "object" : pathParamsType === "object" ? "object" : "inline",
|
|
560
674
|
paramsCasing,
|
|
561
675
|
resolver: tsResolver,
|
|
562
|
-
extraParams: isConfigurable ? [_kubb_core.ast.createFunctionParameter({
|
|
676
|
+
extraParams: [...isConfigurable ? [_kubb_core.ast.createFunctionParameter({
|
|
563
677
|
name: "config",
|
|
564
678
|
type: _kubb_core.ast.createParamsType({
|
|
565
679
|
variant: "reference",
|
|
566
|
-
name:
|
|
680
|
+
name: buildRequestConfigType(node, tsResolver)
|
|
567
681
|
}),
|
|
568
682
|
default: "{}"
|
|
569
|
-
})] : []
|
|
683
|
+
})] : []]
|
|
570
684
|
});
|
|
571
685
|
}
|
|
572
686
|
function Client({ name, isExportable = true, isIndexable = true, returnType, baseURL, dataReturnType, parser, paramsType, paramsCasing, pathParamsType, node, tsResolver, zodResolver, urlName, children, isConfigurable = true }) {
|
|
687
|
+
if (!_kubb_core.ast.isHttpOperationNode(node)) return null;
|
|
573
688
|
const path = new URLPath(node.path);
|
|
574
|
-
const contentType = node
|
|
575
|
-
const isFormData = contentType === "multipart/form-data";
|
|
576
|
-
const
|
|
577
|
-
const
|
|
578
|
-
const
|
|
579
|
-
const
|
|
580
|
-
const
|
|
581
|
-
const
|
|
582
|
-
const
|
|
583
|
-
const
|
|
584
|
-
const
|
|
585
|
-
const
|
|
586
|
-
const
|
|
587
|
-
const
|
|
588
|
-
const
|
|
589
|
-
const zodResponseName = zodResolver && parser === "zod" ? zodResolver.resolveResponseName?.(node) : void 0;
|
|
590
|
-
const zodRequestName = zodResolver && parser === "zod" && node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : void 0;
|
|
689
|
+
const { defaultContentType: contentType, isMultipleContentTypes, hasFormData } = getContentTypeInfo(node);
|
|
690
|
+
const isFormData = !isMultipleContentTypes && contentType === "multipart/form-data";
|
|
691
|
+
const responseType = getResponseType(node);
|
|
692
|
+
const { path: originalPathParams, query: originalQueryParams, header: originalHeaderParams } = getOperationParameters(node);
|
|
693
|
+
const { path: casedPathParams, query: casedQueryParams, header: casedHeaderParams } = getOperationParameters(node, { paramsCasing });
|
|
694
|
+
const pathParamsMapping = paramsCasing && !urlName ? buildParamsMapping(originalPathParams, casedPathParams) : null;
|
|
695
|
+
const queryParamsMapping = paramsCasing ? buildParamsMapping(originalQueryParams, casedQueryParams) : null;
|
|
696
|
+
const headerParamsMapping = paramsCasing ? buildParamsMapping(originalHeaderParams, casedHeaderParams) : null;
|
|
697
|
+
const requestName = node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : null;
|
|
698
|
+
const successNames = resolveSuccessNames(node, tsResolver);
|
|
699
|
+
const responseName = successNames.length > 0 ? successNames.join(" | ") : tsResolver.resolveResponseName(node);
|
|
700
|
+
const queryParamsName = originalQueryParams.length > 0 ? tsResolver.resolveQueryParamsName(node, originalQueryParams[0]) : null;
|
|
701
|
+
const headerParamsName = originalHeaderParams.length > 0 ? tsResolver.resolveHeaderParamsName(node, originalHeaderParams[0]) : null;
|
|
702
|
+
const zodResponseName = zodResolver && parser === "zod" ? zodResolver.resolveResponseName?.(node) : null;
|
|
703
|
+
const zodRequestName = zodResolver && parser === "zod" && node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : null;
|
|
591
704
|
const errorNames = node.responses.filter((r) => {
|
|
592
705
|
return Number.parseInt(r.statusCode, 10) >= 400;
|
|
593
706
|
}).map((r) => tsResolver.resolveResponseStatusName(node, r.statusCode));
|
|
594
|
-
const headers = [contentType !== "application/json" && contentType !== "multipart/form-data" ? `'Content-Type': '${contentType}'` :
|
|
707
|
+
const headers = [!isMultipleContentTypes && contentType !== "application/json" && contentType !== "multipart/form-data" ? `'Content-Type': '${contentType}'` : null, headerParamsName ? headerParamsMapping ? "...mappedHeaders" : "...headers" : null].filter(Boolean);
|
|
595
708
|
const generics = [
|
|
596
709
|
responseName,
|
|
597
710
|
`ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(" | ") : "Error"}>`,
|
|
598
711
|
requestName || "unknown"
|
|
599
712
|
].filter(Boolean);
|
|
600
|
-
const paramsNode =
|
|
713
|
+
const paramsNode = buildClientParamsNode({
|
|
601
714
|
paramsType,
|
|
602
715
|
paramsCasing,
|
|
603
716
|
pathParamsType,
|
|
@@ -606,7 +719,7 @@ function Client({ name, isExportable = true, isIndexable = true, returnType, bas
|
|
|
606
719
|
isConfigurable
|
|
607
720
|
});
|
|
608
721
|
const paramsSignature = declarationPrinter$2.print(paramsNode) ?? "";
|
|
609
|
-
const urlParamsNode =
|
|
722
|
+
const urlParamsNode = buildUrlParamsNode({
|
|
610
723
|
paramsType,
|
|
611
724
|
paramsCasing,
|
|
612
725
|
pathParamsType,
|
|
@@ -619,18 +732,20 @@ function Client({ name, isExportable = true, isIndexable = true, returnType, bas
|
|
|
619
732
|
children: {
|
|
620
733
|
method: { value: JSON.stringify(node.method.toUpperCase()) },
|
|
621
734
|
url: { value: urlName ? `${urlName}(${urlParamsCall}).url.toString()` : path.template },
|
|
622
|
-
baseURL: baseURL && !urlName ? { value: `\`${baseURL}\`` } :
|
|
623
|
-
params: queryParamsName ? queryParamsMapping ? { value: "mappedParams" } : {} :
|
|
624
|
-
data: requestName ? { value: isFormData ? "formData as FormData" : "requestData" } :
|
|
625
|
-
|
|
626
|
-
|
|
735
|
+
baseURL: baseURL && !urlName ? { value: `\`${baseURL}\`` } : null,
|
|
736
|
+
params: queryParamsName ? queryParamsMapping ? { value: "mappedParams" } : {} : null,
|
|
737
|
+
data: requestName ? { value: isMultipleContentTypes && hasFormData ? "contentType === 'multipart/form-data' ? formData as FormData : requestData" : isFormData ? "formData as FormData" : "requestData" } : null,
|
|
738
|
+
contentType: isConfigurable && isMultipleContentTypes ? {} : null,
|
|
739
|
+
responseType: responseType ? { value: JSON.stringify(responseType) } : null,
|
|
740
|
+
requestConfig: isConfigurable ? { mode: "inlineSpread" } : null,
|
|
741
|
+
headers: headers.length ? { value: isConfigurable ? `{ ${headers.join(", ")}, ...requestConfig.headers }` : `{ ${headers.join(", ")} }` } : null
|
|
627
742
|
}
|
|
628
743
|
} });
|
|
629
744
|
const childrenElement = children ? children : /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [
|
|
630
745
|
dataReturnType === "full" && parser === "zod" && zodResponseName && `return {...res, data: ${zodResponseName}.parse(res.data)}`,
|
|
631
746
|
dataReturnType === "data" && parser === "zod" && zodResponseName && `return ${zodResponseName}.parse(res.data)`,
|
|
632
|
-
dataReturnType === "full" && parser
|
|
633
|
-
dataReturnType === "data" && parser
|
|
747
|
+
dataReturnType === "full" && parser !== "zod" && "return res",
|
|
748
|
+
dataReturnType === "data" && parser !== "zod" && "return res.data"
|
|
634
749
|
] });
|
|
635
750
|
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)("br", {}), /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
|
|
636
751
|
name,
|
|
@@ -641,10 +756,14 @@ function Client({ name, isExportable = true, isIndexable = true, returnType, bas
|
|
|
641
756
|
async: true,
|
|
642
757
|
export: isExportable,
|
|
643
758
|
params: paramsSignature,
|
|
644
|
-
JSDoc: { comments:
|
|
759
|
+
JSDoc: { comments: buildOperationComments(node, {
|
|
760
|
+
link: "urlPath",
|
|
761
|
+
linkPosition: "beforeDeprecated",
|
|
762
|
+
splitLines: true
|
|
763
|
+
}) },
|
|
645
764
|
returnType,
|
|
646
765
|
children: [
|
|
647
|
-
isConfigurable ?
|
|
766
|
+
isConfigurable ? `const { client: request = client, ${isMultipleContentTypes ? `contentType = ${JSON.stringify(contentType)}, ` : ""}...requestConfig } = config` : "",
|
|
648
767
|
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)("br", {}),
|
|
649
768
|
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)("br", {}),
|
|
650
769
|
pathParamsMapping && Object.entries(pathParamsMapping).filter(([originalName, camelCaseName]) => isValidVarName(originalName) && originalName !== camelCaseName).map(([originalName, camelCaseName]) => `const ${originalName} = ${camelCaseName}`).join("\n"),
|
|
@@ -661,26 +780,104 @@ function Client({ name, isExportable = true, isIndexable = true, returnType, bas
|
|
|
661
780
|
] }),
|
|
662
781
|
parser === "zod" && zodRequestName ? `const requestData = ${zodRequestName}.parse(data)` : requestName && "const requestData = data",
|
|
663
782
|
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)("br", {}),
|
|
664
|
-
isFormData && requestName && "const formData = buildFormData(requestData)",
|
|
783
|
+
(isFormData || isMultipleContentTypes && hasFormData) && requestName && "const formData = buildFormData(requestData)",
|
|
665
784
|
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)("br", {}),
|
|
666
|
-
isConfigurable ? `const res = await request<${generics.join(", ")}>(${clientParams.toCall()})` : `const res = await
|
|
785
|
+
isConfigurable ? `const res = await request<${generics.join(", ")}>(${clientParams.toCall()})` : `const res = await client<${generics.join(", ")}>(${clientParams.toCall()})`,
|
|
667
786
|
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)("br", {}),
|
|
668
787
|
childrenElement
|
|
669
788
|
]
|
|
670
789
|
})
|
|
671
790
|
})] });
|
|
672
791
|
}
|
|
673
|
-
|
|
792
|
+
//#endregion
|
|
793
|
+
//#region src/utils.ts
|
|
794
|
+
/**
|
|
795
|
+
* Builds HTTP headers array for a client request.
|
|
796
|
+
* Includes Content-Type (if not default) and spreads header parameters if present.
|
|
797
|
+
*/
|
|
798
|
+
function buildHeaders(contentType, hasHeaderParams) {
|
|
799
|
+
return [contentType !== "application/json" && contentType !== "multipart/form-data" ? `'Content-Type': '${contentType}'` : null, hasHeaderParams ? "...headers" : null].filter(Boolean);
|
|
800
|
+
}
|
|
801
|
+
/**
|
|
802
|
+
* Builds TypeScript generic parameters for a client method.
|
|
803
|
+
* Includes response type, error type, and optional request type.
|
|
804
|
+
*/
|
|
805
|
+
function buildGenerics(node, tsResolver) {
|
|
806
|
+
const successNames = resolveSuccessNames(node, tsResolver);
|
|
807
|
+
const responseName = successNames.length > 0 ? successNames.join(" | ") : tsResolver.resolveResponseName(node);
|
|
808
|
+
const requestName = node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : null;
|
|
809
|
+
const errorNames = node.responses.filter((r) => Number.parseInt(r.statusCode, 10) >= 400).map((r) => tsResolver.resolveResponseStatusName(node, r.statusCode));
|
|
810
|
+
return [
|
|
811
|
+
responseName,
|
|
812
|
+
`ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(" | ") : "Error"}>`,
|
|
813
|
+
requestName || "unknown"
|
|
814
|
+
].filter(Boolean);
|
|
815
|
+
}
|
|
816
|
+
/**
|
|
817
|
+
* Builds the parameters object for a class-based client method.
|
|
818
|
+
* Includes URL, method, base URL, headers, and request/response data.
|
|
819
|
+
*/
|
|
820
|
+
function buildClassClientParams({ node, path, baseURL, tsResolver, isFormData, isMultipleContentTypes, hasFormData, headers }) {
|
|
821
|
+
const { query: queryParams } = getOperationParameters(node);
|
|
822
|
+
const queryParamsName = queryParams.length > 0 ? tsResolver.resolveQueryParamsName(node, queryParams[0]) : null;
|
|
823
|
+
const requestName = node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : null;
|
|
824
|
+
const responseType = getResponseType(node);
|
|
825
|
+
return createFunctionParams({ config: {
|
|
826
|
+
mode: "object",
|
|
827
|
+
children: {
|
|
828
|
+
requestConfig: { mode: "inlineSpread" },
|
|
829
|
+
method: { value: JSON.stringify(_kubb_core.ast.isHttpOperationNode(node) ? node.method.toUpperCase() : "") },
|
|
830
|
+
url: { value: path.template },
|
|
831
|
+
baseURL: baseURL ? { value: JSON.stringify(baseURL) } : null,
|
|
832
|
+
params: queryParamsName ? {} : null,
|
|
833
|
+
data: requestName ? { value: isMultipleContentTypes && hasFormData ? "contentType === 'multipart/form-data' ? formData as FormData : requestData" : isFormData ? "formData as FormData" : "requestData" } : null,
|
|
834
|
+
contentType: isMultipleContentTypes ? {} : null,
|
|
835
|
+
responseType: responseType ? { value: JSON.stringify(responseType) } : null,
|
|
836
|
+
headers: headers.length ? { value: `{ ${headers.join(", ")}, ...requestConfig.headers }` } : null
|
|
837
|
+
}
|
|
838
|
+
} });
|
|
839
|
+
}
|
|
840
|
+
/**
|
|
841
|
+
* Builds the request data parsing line for client methods.
|
|
842
|
+
* Applies Zod validation if configured, otherwise uses data directly.
|
|
843
|
+
*/
|
|
844
|
+
function buildRequestDataLine({ parser, node, zodResolver }) {
|
|
845
|
+
const zodRequestName = zodResolver && parser === "zod" && node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : null;
|
|
846
|
+
if (parser === "zod" && zodRequestName) return `const requestData = ${zodRequestName}.parse(data)`;
|
|
847
|
+
if (node.requestBody?.content?.[0]?.schema) return "const requestData = data";
|
|
848
|
+
return "";
|
|
849
|
+
}
|
|
850
|
+
/**
|
|
851
|
+
* Builds the form data conversion line for file upload requests.
|
|
852
|
+
* Returns empty string if not applicable.
|
|
853
|
+
*/
|
|
854
|
+
function buildFormDataLine(isFormData, hasRequest) {
|
|
855
|
+
return isFormData && hasRequest ? "const formData = buildFormData(requestData)" : "";
|
|
856
|
+
}
|
|
857
|
+
/**
|
|
858
|
+
* Builds the return statement for a client method.
|
|
859
|
+
* Applies Zod validation to response data if configured, otherwise returns raw response.
|
|
860
|
+
*/
|
|
861
|
+
function buildReturnStatement({ dataReturnType, parser, node, zodResolver }) {
|
|
862
|
+
const zodResponseName = zodResolver && parser === "zod" ? zodResolver.resolveResponseName?.(node) : null;
|
|
863
|
+
if (dataReturnType === "full" && parser === "zod" && zodResponseName) return `return {...res, data: ${zodResponseName}.parse(res.data)}`;
|
|
864
|
+
if (dataReturnType === "data" && parser === "zod" && zodResponseName) return `return ${zodResponseName}.parse(res.data)`;
|
|
865
|
+
if (dataReturnType === "full" && parser !== "zod") return "return res";
|
|
866
|
+
return "return res.data";
|
|
867
|
+
}
|
|
674
868
|
//#endregion
|
|
675
869
|
//#region src/components/ClassClient.tsx
|
|
676
870
|
const declarationPrinter$1 = (0, _kubb_plugin_ts.functionPrinter)({ mode: "declaration" });
|
|
677
871
|
function generateMethod$1({ node, name, tsResolver, zodResolver, baseURL, dataReturnType, parser, paramsType, paramsCasing, pathParamsType }) {
|
|
872
|
+
if (!_kubb_core.ast.isHttpOperationNode(node)) return "";
|
|
678
873
|
const path = new URLPath(node.path, { casing: paramsCasing });
|
|
679
|
-
const contentType = node
|
|
680
|
-
const isFormData = contentType === "multipart/form-data";
|
|
681
|
-
const
|
|
874
|
+
const { defaultContentType: contentType, isMultipleContentTypes, hasFormData } = getContentTypeInfo(node);
|
|
875
|
+
const isFormData = !isMultipleContentTypes && contentType === "multipart/form-data";
|
|
876
|
+
const { header: headerParams } = getOperationParameters(node);
|
|
877
|
+
const headerParamsName = headerParams.length > 0 ? tsResolver.resolveHeaderParamsName(node, headerParams[0]) : null;
|
|
878
|
+
const headers = isMultipleContentTypes ? headerParamsName ? ["...headers"] : [] : buildHeaders(contentType, !!headerParamsName);
|
|
682
879
|
const generics = buildGenerics(node, tsResolver);
|
|
683
|
-
const paramsNode =
|
|
880
|
+
const paramsNode = buildClientParamsNode({
|
|
684
881
|
paramsType,
|
|
685
882
|
paramsCasing,
|
|
686
883
|
pathParamsType,
|
|
@@ -695,15 +892,21 @@ function generateMethod$1({ node, name, tsResolver, zodResolver, baseURL, dataRe
|
|
|
695
892
|
baseURL,
|
|
696
893
|
tsResolver,
|
|
697
894
|
isFormData,
|
|
895
|
+
isMultipleContentTypes,
|
|
896
|
+
hasFormData,
|
|
698
897
|
headers
|
|
699
898
|
});
|
|
700
|
-
const jsdoc = buildJSDoc(
|
|
899
|
+
const jsdoc = buildJSDoc(buildOperationComments(node, {
|
|
900
|
+
link: "urlPath",
|
|
901
|
+
linkPosition: "beforeDeprecated",
|
|
902
|
+
splitLines: true
|
|
903
|
+
}));
|
|
701
904
|
const requestDataLine = buildRequestDataLine({
|
|
702
905
|
parser,
|
|
703
906
|
node,
|
|
704
907
|
zodResolver
|
|
705
908
|
});
|
|
706
|
-
const formDataLine = buildFormDataLine(isFormData, !!node.requestBody?.content?.[0]?.schema);
|
|
909
|
+
const formDataLine = buildFormDataLine(isFormData || isMultipleContentTypes && hasFormData, !!node.requestBody?.content?.[0]?.schema);
|
|
707
910
|
const returnStatement = buildReturnStatement({
|
|
708
911
|
dataReturnType,
|
|
709
912
|
parser,
|
|
@@ -711,7 +914,7 @@ function generateMethod$1({ node, name, tsResolver, zodResolver, baseURL, dataRe
|
|
|
711
914
|
zodResolver
|
|
712
915
|
});
|
|
713
916
|
return `${jsdoc}async ${name}(${paramsSignature}) {\n${[
|
|
714
|
-
|
|
917
|
+
`const { client: request = client, ${isMultipleContentTypes ? `contentType = ${JSON.stringify(contentType)}, ` : ""}...requestConfig } = mergeConfig(this.#config, config)`,
|
|
715
918
|
"",
|
|
716
919
|
requestDataLine,
|
|
717
920
|
formDataLine,
|
|
@@ -748,15 +951,14 @@ ${operations.map(({ node, name: methodName, tsResolver, zodResolver }) => genera
|
|
|
748
951
|
children: [classCode, children]
|
|
749
952
|
});
|
|
750
953
|
}
|
|
751
|
-
ClassClient.getParams = Client.getParams;
|
|
752
954
|
//#endregion
|
|
753
955
|
//#region src/components/WrapperClient.tsx
|
|
754
|
-
function WrapperClient({ name,
|
|
956
|
+
function WrapperClient({ name, controllers, isExportable = true, isIndexable = true }) {
|
|
755
957
|
const classCode = `export class ${name} {
|
|
756
|
-
${
|
|
958
|
+
${controllers.map(({ className, propertyName }) => ` readonly ${propertyName}: ${className}`).join("\n")}
|
|
757
959
|
|
|
758
960
|
constructor(config: Partial<RequestConfig> & { client?: Client } = {}) {
|
|
759
|
-
${
|
|
961
|
+
${controllers.map(({ className, propertyName }) => ` this.${propertyName} = new ${className}(config)`).join("\n")}
|
|
760
962
|
}
|
|
761
963
|
}`;
|
|
762
964
|
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
|
|
@@ -769,54 +971,42 @@ ${classNames.map((className) => ` this.${camelCase(className)} = new ${classN
|
|
|
769
971
|
//#endregion
|
|
770
972
|
//#region src/generators/classClientGenerator.tsx
|
|
771
973
|
function resolveTypeImportNames$1(node, tsResolver) {
|
|
772
|
-
return
|
|
773
|
-
node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : void 0,
|
|
774
|
-
tsResolver.resolveResponseName(node),
|
|
775
|
-
...node.parameters.filter((p) => p.in === "path").map((p) => tsResolver.resolvePathParamsName(node, p)),
|
|
776
|
-
...node.parameters.filter((p) => p.in === "query").map((p) => tsResolver.resolveQueryParamsName(node, p)),
|
|
777
|
-
...node.parameters.filter((p) => p.in === "header").map((p) => tsResolver.resolveHeaderParamsName(node, p)),
|
|
778
|
-
...node.responses.map((res) => tsResolver.resolveResponseStatusName(node, res.statusCode))
|
|
779
|
-
].filter((n) => Boolean(n));
|
|
974
|
+
return resolveOperationTypeNames(node, tsResolver, { order: "body-response-first" });
|
|
780
975
|
}
|
|
781
976
|
require_chunk.__name(resolveTypeImportNames$1, "resolveTypeImportNames");
|
|
782
977
|
function resolveZodImportNames$1(node, zodResolver) {
|
|
783
|
-
return [zodResolver.resolveResponseName?.(node), node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) :
|
|
978
|
+
return [zodResolver.resolveResponseName?.(node), node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : null].filter((n) => Boolean(n));
|
|
784
979
|
}
|
|
785
980
|
require_chunk.__name(resolveZodImportNames$1, "resolveZodImportNames");
|
|
981
|
+
/**
|
|
982
|
+
* Built-in `operations` generator for `@kubb/plugin-client` when
|
|
983
|
+
* `clientType: 'class'`. Emits one class per tag, with one instance method
|
|
984
|
+
* per operation and a shared constructor for request configuration.
|
|
985
|
+
*/
|
|
786
986
|
const classClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
787
987
|
name: "classClient",
|
|
788
|
-
renderer: _kubb_renderer_jsx.
|
|
988
|
+
renderer: _kubb_renderer_jsx.jsxRendererSync,
|
|
789
989
|
operations(nodes, ctx) {
|
|
790
|
-
const {
|
|
990
|
+
const { config, driver, resolver, root } = ctx;
|
|
791
991
|
const { output, group, dataReturnType, paramsCasing, paramsType, pathParamsType, parser, importPath, sdk } = ctx.options;
|
|
792
|
-
const baseURL = ctx.options.baseURL ??
|
|
992
|
+
const baseURL = ctx.options.baseURL ?? ctx.meta.baseURL;
|
|
793
993
|
const pluginTs = driver.getPlugin(_kubb_plugin_ts.pluginTsName);
|
|
794
994
|
if (!pluginTs) return null;
|
|
795
995
|
const tsResolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
|
|
796
996
|
const tsPluginOptions = pluginTs.options;
|
|
797
|
-
const pluginZod = parser === "zod" ? driver.getPlugin(_kubb_plugin_zod.pluginZodName) :
|
|
798
|
-
const zodResolver = pluginZod ? driver.getResolver(_kubb_plugin_zod.pluginZodName) :
|
|
997
|
+
const pluginZod = parser === "zod" ? driver.getPlugin(_kubb_plugin_zod.pluginZodName) : null;
|
|
998
|
+
const zodResolver = pluginZod ? driver.getResolver(_kubb_plugin_zod.pluginZodName) : null;
|
|
799
999
|
function buildOperationData(node) {
|
|
800
|
-
const typeFile = tsResolver.resolveFile({
|
|
801
|
-
name: node.operationId,
|
|
802
|
-
extname: ".ts",
|
|
803
|
-
tag: node.tags[0] ?? "default",
|
|
804
|
-
path: node.path
|
|
805
|
-
}, {
|
|
1000
|
+
const typeFile = tsResolver.resolveFile(operationFileEntry(node, node.operationId), {
|
|
806
1001
|
root,
|
|
807
1002
|
output: tsPluginOptions?.output ?? output,
|
|
808
1003
|
group: tsPluginOptions?.group
|
|
809
1004
|
});
|
|
810
|
-
const zodFile = zodResolver && pluginZod?.options ? zodResolver.resolveFile({
|
|
811
|
-
name: node.operationId,
|
|
812
|
-
extname: ".ts",
|
|
813
|
-
tag: node.tags[0] ?? "default",
|
|
814
|
-
path: node.path
|
|
815
|
-
}, {
|
|
1005
|
+
const zodFile = zodResolver && pluginZod?.options ? zodResolver.resolveFile(operationFileEntry(node, node.operationId), {
|
|
816
1006
|
root,
|
|
817
1007
|
output: pluginZod.options?.output ?? output,
|
|
818
|
-
group: pluginZod.options?.group
|
|
819
|
-
}) :
|
|
1008
|
+
group: pluginZod.options?.group ?? void 0
|
|
1009
|
+
}) : null;
|
|
820
1010
|
return {
|
|
821
1011
|
node,
|
|
822
1012
|
name: resolver.resolveName(node.operationId),
|
|
@@ -827,27 +1017,31 @@ const classClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
827
1017
|
};
|
|
828
1018
|
}
|
|
829
1019
|
const controllers = nodes.reduce((acc, operationNode) => {
|
|
1020
|
+
if (!_kubb_core.ast.isHttpOperationNode(operationNode)) return acc;
|
|
830
1021
|
const tag = operationNode.tags[0];
|
|
831
|
-
const groupName = tag ? group?.name?.({ group: camelCase(tag) }) ??
|
|
1022
|
+
const groupName = tag ? group?.name?.({ group: camelCase(tag) }) ?? resolver.resolveGroupName(tag) : resolver.resolveGroupName("Client");
|
|
832
1023
|
if (!tag && !group) {
|
|
833
|
-
const name = "ApiClient";
|
|
1024
|
+
const name = resolver.resolveClassName("ApiClient");
|
|
834
1025
|
const file = resolver.resolveFile({
|
|
835
1026
|
name,
|
|
836
1027
|
extname: ".ts"
|
|
837
1028
|
}, {
|
|
838
1029
|
root,
|
|
839
1030
|
output,
|
|
840
|
-
group
|
|
1031
|
+
group: group ?? void 0
|
|
841
1032
|
});
|
|
842
1033
|
const operationData = buildOperationData(operationNode);
|
|
843
1034
|
const previous = acc.find((item) => item.file.path === file.path);
|
|
844
1035
|
if (previous) previous.operations.push(operationData);
|
|
845
1036
|
else acc.push({
|
|
846
1037
|
name,
|
|
1038
|
+
propertyName: resolver.resolveClientPropertyName(name),
|
|
847
1039
|
file,
|
|
848
1040
|
operations: [operationData]
|
|
849
1041
|
});
|
|
850
|
-
|
|
1042
|
+
return acc;
|
|
1043
|
+
}
|
|
1044
|
+
if (tag) {
|
|
851
1045
|
const name = groupName;
|
|
852
1046
|
const file = resolver.resolveFile({
|
|
853
1047
|
name,
|
|
@@ -856,13 +1050,14 @@ const classClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
856
1050
|
}, {
|
|
857
1051
|
root,
|
|
858
1052
|
output,
|
|
859
|
-
group
|
|
1053
|
+
group: group ?? void 0
|
|
860
1054
|
});
|
|
861
1055
|
const operationData = buildOperationData(operationNode);
|
|
862
1056
|
const previous = acc.find((item) => item.file.path === file.path);
|
|
863
1057
|
if (previous) previous.operations.push(operationData);
|
|
864
1058
|
else acc.push({
|
|
865
1059
|
name,
|
|
1060
|
+
propertyName: resolver.resolveClientPropertyName(name),
|
|
866
1061
|
file,
|
|
867
1062
|
operations: [operationData]
|
|
868
1063
|
});
|
|
@@ -910,23 +1105,31 @@ const classClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
910
1105
|
zodImportsByFile: /* @__PURE__ */ new Map(),
|
|
911
1106
|
zodFilesByPath: /* @__PURE__ */ new Map()
|
|
912
1107
|
};
|
|
913
|
-
const hasFormData = ops.some((op) => op.node.requestBody?.content?.
|
|
1108
|
+
const hasFormData = ops.some((op) => op.node.requestBody?.content?.some((e) => e.contentType === "multipart/form-data") ?? false);
|
|
914
1109
|
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.File, {
|
|
915
1110
|
baseName: file.baseName,
|
|
916
1111
|
path: file.path,
|
|
917
1112
|
meta: file.meta,
|
|
918
|
-
banner: resolver.resolveBanner(
|
|
1113
|
+
banner: resolver.resolveBanner(ctx.meta, {
|
|
919
1114
|
output,
|
|
920
|
-
config
|
|
1115
|
+
config,
|
|
1116
|
+
file: {
|
|
1117
|
+
path: file.path,
|
|
1118
|
+
baseName: file.baseName
|
|
1119
|
+
}
|
|
921
1120
|
}),
|
|
922
|
-
footer: resolver.resolveFooter(
|
|
1121
|
+
footer: resolver.resolveFooter(ctx.meta, {
|
|
923
1122
|
output,
|
|
924
|
-
config
|
|
1123
|
+
config,
|
|
1124
|
+
file: {
|
|
1125
|
+
path: file.path,
|
|
1126
|
+
baseName: file.baseName
|
|
1127
|
+
}
|
|
925
1128
|
}),
|
|
926
1129
|
children: [
|
|
927
1130
|
importPath ? /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [
|
|
928
1131
|
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
929
|
-
name: "
|
|
1132
|
+
name: "client",
|
|
930
1133
|
path: importPath
|
|
931
1134
|
}),
|
|
932
1135
|
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
@@ -944,7 +1147,7 @@ const classClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
944
1147
|
})
|
|
945
1148
|
] }) : /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [
|
|
946
1149
|
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
947
|
-
name: ["
|
|
1150
|
+
name: ["client"],
|
|
948
1151
|
root: file.path,
|
|
949
1152
|
path: node_path.default.resolve(root, ".kubb/client.ts")
|
|
950
1153
|
}),
|
|
@@ -1012,19 +1215,27 @@ const classClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1012
1215
|
}, {
|
|
1013
1216
|
root,
|
|
1014
1217
|
output,
|
|
1015
|
-
group
|
|
1218
|
+
group: group ?? void 0
|
|
1016
1219
|
});
|
|
1017
1220
|
files.push(/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.File, {
|
|
1018
1221
|
baseName: sdkFile.baseName,
|
|
1019
1222
|
path: sdkFile.path,
|
|
1020
1223
|
meta: sdkFile.meta,
|
|
1021
|
-
banner: resolver.resolveBanner(
|
|
1224
|
+
banner: resolver.resolveBanner(ctx.meta, {
|
|
1022
1225
|
output,
|
|
1023
|
-
config
|
|
1226
|
+
config,
|
|
1227
|
+
file: {
|
|
1228
|
+
path: sdkFile.path,
|
|
1229
|
+
baseName: sdkFile.baseName
|
|
1230
|
+
}
|
|
1024
1231
|
}),
|
|
1025
|
-
footer: resolver.resolveFooter(
|
|
1232
|
+
footer: resolver.resolveFooter(ctx.meta, {
|
|
1026
1233
|
output,
|
|
1027
|
-
config
|
|
1234
|
+
config,
|
|
1235
|
+
file: {
|
|
1236
|
+
path: sdkFile.path,
|
|
1237
|
+
baseName: sdkFile.baseName
|
|
1238
|
+
}
|
|
1028
1239
|
}),
|
|
1029
1240
|
children: [
|
|
1030
1241
|
importPath ? /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
@@ -1044,7 +1255,10 @@ const classClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1044
1255
|
}, name)),
|
|
1045
1256
|
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(WrapperClient, {
|
|
1046
1257
|
name: sdk.className,
|
|
1047
|
-
|
|
1258
|
+
controllers: controllers.map(({ name, propertyName }) => ({
|
|
1259
|
+
className: name,
|
|
1260
|
+
propertyName
|
|
1261
|
+
}))
|
|
1048
1262
|
})
|
|
1049
1263
|
]
|
|
1050
1264
|
}, sdkFile.path));
|
|
@@ -1054,81 +1268,69 @@ const classClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1054
1268
|
});
|
|
1055
1269
|
//#endregion
|
|
1056
1270
|
//#region src/generators/clientGenerator.tsx
|
|
1271
|
+
/**
|
|
1272
|
+
* Built-in operation generator for `@kubb/plugin-client`. Emits one async
|
|
1273
|
+
* function per OpenAPI operation, plus the matching URL helper. Used when
|
|
1274
|
+
* `clientType: 'function'` (the default).
|
|
1275
|
+
*/
|
|
1057
1276
|
const clientGenerator = (0, _kubb_core.defineGenerator)({
|
|
1058
1277
|
name: "client",
|
|
1059
|
-
renderer: _kubb_renderer_jsx.
|
|
1278
|
+
renderer: _kubb_renderer_jsx.jsxRendererSync,
|
|
1060
1279
|
operation(node, ctx) {
|
|
1061
|
-
|
|
1280
|
+
if (!_kubb_core.ast.isHttpOperationNode(node)) return null;
|
|
1281
|
+
const { config, driver, resolver, root } = ctx;
|
|
1062
1282
|
const { output, urlType, dataReturnType, paramsCasing, paramsType, pathParamsType, parser, importPath, group } = ctx.options;
|
|
1063
|
-
const baseURL = ctx.options.baseURL ??
|
|
1283
|
+
const baseURL = ctx.options.baseURL ?? ctx.meta.baseURL;
|
|
1064
1284
|
const pluginTs = driver.getPlugin(_kubb_plugin_ts.pluginTsName);
|
|
1065
1285
|
if (!pluginTs) return null;
|
|
1066
1286
|
const tsResolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
|
|
1067
|
-
const pluginZod = parser === "zod" ? driver.getPlugin(_kubb_plugin_zod.pluginZodName) :
|
|
1068
|
-
const zodResolver = pluginZod ? driver.getResolver(_kubb_plugin_zod.pluginZodName) :
|
|
1069
|
-
const
|
|
1070
|
-
const
|
|
1071
|
-
const queryParams = casedParams.filter((p) => p.in === "query");
|
|
1072
|
-
const headerParams = casedParams.filter((p) => p.in === "header");
|
|
1073
|
-
const importedTypeNames = [
|
|
1074
|
-
...pathParams.map((p) => tsResolver.resolvePathParamsName(node, p)),
|
|
1075
|
-
...queryParams.map((p) => tsResolver.resolveQueryParamsName(node, p)),
|
|
1076
|
-
...headerParams.map((p) => tsResolver.resolveHeaderParamsName(node, p)),
|
|
1077
|
-
node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : void 0,
|
|
1078
|
-
tsResolver.resolveResponseName(node),
|
|
1079
|
-
...node.responses.map((res) => tsResolver.resolveResponseStatusName(node, res.statusCode))
|
|
1080
|
-
].filter(Boolean);
|
|
1081
|
-
const importedZodNames = zodResolver && parser === "zod" ? [zodResolver.resolveResponseName?.(node), node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : void 0].filter(Boolean) : [];
|
|
1287
|
+
const pluginZod = parser === "zod" ? driver.getPlugin(_kubb_plugin_zod.pluginZodName) : null;
|
|
1288
|
+
const zodResolver = pluginZod ? driver.getResolver(_kubb_plugin_zod.pluginZodName) : null;
|
|
1289
|
+
const importedTypeNames = resolveOperationTypeNames(node, tsResolver, { paramsCasing });
|
|
1290
|
+
const importedZodNames = zodResolver && parser === "zod" ? [zodResolver.resolveResponseName?.(node), node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : null].filter((name) => Boolean(name)) : [];
|
|
1082
1291
|
const meta = {
|
|
1083
1292
|
name: resolver.resolveName(node.operationId),
|
|
1084
|
-
urlName:
|
|
1085
|
-
file: resolver.resolveFile({
|
|
1086
|
-
name: node.operationId,
|
|
1087
|
-
extname: ".ts",
|
|
1088
|
-
tag: node.tags[0] ?? "default",
|
|
1089
|
-
path: node.path
|
|
1090
|
-
}, {
|
|
1293
|
+
urlName: resolver.resolveUrlName(node),
|
|
1294
|
+
file: resolver.resolveFile(operationFileEntry(node, node.operationId), {
|
|
1091
1295
|
root,
|
|
1092
1296
|
output,
|
|
1093
|
-
group
|
|
1297
|
+
group: group ?? void 0
|
|
1094
1298
|
}),
|
|
1095
|
-
fileTs: tsResolver.resolveFile({
|
|
1096
|
-
name: node.operationId,
|
|
1097
|
-
extname: ".ts",
|
|
1098
|
-
tag: node.tags[0] ?? "default",
|
|
1099
|
-
path: node.path
|
|
1100
|
-
}, {
|
|
1299
|
+
fileTs: tsResolver.resolveFile(operationFileEntry(node, node.operationId), {
|
|
1101
1300
|
root,
|
|
1102
1301
|
output: pluginTs.options?.output ?? output,
|
|
1103
|
-
group: pluginTs.options?.group
|
|
1302
|
+
group: pluginTs.options?.group ?? void 0
|
|
1104
1303
|
}),
|
|
1105
|
-
fileZod: zodResolver && pluginZod?.options ? zodResolver.resolveFile({
|
|
1106
|
-
name: node.operationId,
|
|
1107
|
-
extname: ".ts",
|
|
1108
|
-
tag: node.tags[0] ?? "default",
|
|
1109
|
-
path: node.path
|
|
1110
|
-
}, {
|
|
1304
|
+
fileZod: zodResolver && pluginZod?.options ? zodResolver.resolveFile(operationFileEntry(node, node.operationId), {
|
|
1111
1305
|
root,
|
|
1112
1306
|
output: pluginZod.options.output ?? output,
|
|
1113
|
-
group: pluginZod.options?.group
|
|
1114
|
-
}) :
|
|
1307
|
+
group: pluginZod.options?.group ?? void 0
|
|
1308
|
+
}) : null
|
|
1115
1309
|
};
|
|
1116
|
-
const
|
|
1310
|
+
const hasFormData = node.requestBody?.content?.some((e) => e.contentType === "multipart/form-data") ?? false;
|
|
1117
1311
|
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.File, {
|
|
1118
1312
|
baseName: meta.file.baseName,
|
|
1119
1313
|
path: meta.file.path,
|
|
1120
1314
|
meta: meta.file.meta,
|
|
1121
|
-
banner: resolver.resolveBanner(
|
|
1315
|
+
banner: resolver.resolveBanner(ctx.meta, {
|
|
1122
1316
|
output,
|
|
1123
|
-
config
|
|
1317
|
+
config,
|
|
1318
|
+
file: {
|
|
1319
|
+
path: meta.file.path,
|
|
1320
|
+
baseName: meta.file.baseName
|
|
1321
|
+
}
|
|
1124
1322
|
}),
|
|
1125
|
-
footer: resolver.resolveFooter(
|
|
1323
|
+
footer: resolver.resolveFooter(ctx.meta, {
|
|
1126
1324
|
output,
|
|
1127
|
-
config
|
|
1325
|
+
config,
|
|
1326
|
+
file: {
|
|
1327
|
+
path: meta.file.path,
|
|
1328
|
+
baseName: meta.file.baseName
|
|
1329
|
+
}
|
|
1128
1330
|
}),
|
|
1129
1331
|
children: [
|
|
1130
1332
|
importPath ? /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1131
|
-
name: "
|
|
1333
|
+
name: "client",
|
|
1132
1334
|
path: importPath
|
|
1133
1335
|
}), /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1134
1336
|
name: [
|
|
@@ -1139,7 +1341,7 @@ const clientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1139
1341
|
path: importPath,
|
|
1140
1342
|
isTypeOnly: true
|
|
1141
1343
|
})] }) : /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1142
|
-
name: ["
|
|
1344
|
+
name: ["client"],
|
|
1143
1345
|
root: meta.file.path,
|
|
1144
1346
|
path: node_path.default.resolve(root, ".kubb/client.ts")
|
|
1145
1347
|
}), /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
@@ -1152,7 +1354,7 @@ const clientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1152
1354
|
path: node_path.default.resolve(root, ".kubb/client.ts"),
|
|
1153
1355
|
isTypeOnly: true
|
|
1154
1356
|
})] }),
|
|
1155
|
-
|
|
1357
|
+
hasFormData && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1156
1358
|
name: ["buildFormData"],
|
|
1157
1359
|
root: meta.file.path,
|
|
1158
1360
|
path: node_path.default.resolve(root, ".kubb/config.ts")
|
|
@@ -1198,16 +1400,22 @@ const clientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1198
1400
|
});
|
|
1199
1401
|
//#endregion
|
|
1200
1402
|
//#region src/generators/groupedClientGenerator.tsx
|
|
1403
|
+
/**
|
|
1404
|
+
* Emits one aggregate file per tag/group when `group` is configured. Each
|
|
1405
|
+
* file re-exports every client function for that group, so callers can
|
|
1406
|
+
* `import { petController } from './gen/clients'` instead of importing
|
|
1407
|
+
* each operation individually.
|
|
1408
|
+
*/
|
|
1201
1409
|
const groupedClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
1202
1410
|
name: "groupedClient",
|
|
1203
|
-
renderer: _kubb_renderer_jsx.
|
|
1411
|
+
renderer: _kubb_renderer_jsx.jsxRendererSync,
|
|
1204
1412
|
operations(nodes, ctx) {
|
|
1205
|
-
const { config, resolver,
|
|
1413
|
+
const { config, resolver, root } = ctx;
|
|
1206
1414
|
const { output, group } = ctx.options;
|
|
1207
1415
|
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: nodes.reduce((acc, operationNode) => {
|
|
1208
1416
|
if (group?.type === "tag") {
|
|
1209
1417
|
const tag = operationNode.tags[0];
|
|
1210
|
-
const name = tag ? group?.name?.({ group: camelCase(tag) }) :
|
|
1418
|
+
const name = tag ? group?.name?.({ group: camelCase(tag) }) : null;
|
|
1211
1419
|
if (!tag || !name) return acc;
|
|
1212
1420
|
const file = resolver.resolveFile({
|
|
1213
1421
|
name,
|
|
@@ -1216,7 +1424,7 @@ const groupedClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1216
1424
|
}, {
|
|
1217
1425
|
root,
|
|
1218
1426
|
output,
|
|
1219
|
-
group
|
|
1427
|
+
group: group ?? void 0
|
|
1220
1428
|
});
|
|
1221
1429
|
const clientFile = resolver.resolveFile({
|
|
1222
1430
|
name: operationNode.operationId,
|
|
@@ -1226,7 +1434,7 @@ const groupedClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1226
1434
|
}, {
|
|
1227
1435
|
root,
|
|
1228
1436
|
output,
|
|
1229
|
-
group
|
|
1437
|
+
group: group ?? void 0
|
|
1230
1438
|
});
|
|
1231
1439
|
const client = {
|
|
1232
1440
|
name: resolver.resolveName(operationNode.operationId),
|
|
@@ -1246,13 +1454,23 @@ const groupedClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1246
1454
|
baseName: file.baseName,
|
|
1247
1455
|
path: file.path,
|
|
1248
1456
|
meta: file.meta,
|
|
1249
|
-
banner: resolver.resolveBanner(
|
|
1457
|
+
banner: resolver.resolveBanner(ctx.meta, {
|
|
1250
1458
|
output,
|
|
1251
|
-
config
|
|
1459
|
+
config,
|
|
1460
|
+
file: {
|
|
1461
|
+
path: file.path,
|
|
1462
|
+
baseName: file.baseName,
|
|
1463
|
+
isAggregation: true
|
|
1464
|
+
}
|
|
1252
1465
|
}),
|
|
1253
|
-
footer: resolver.resolveFooter(
|
|
1466
|
+
footer: resolver.resolveFooter(ctx.meta, {
|
|
1254
1467
|
output,
|
|
1255
|
-
config
|
|
1468
|
+
config,
|
|
1469
|
+
file: {
|
|
1470
|
+
path: file.path,
|
|
1471
|
+
baseName: file.baseName,
|
|
1472
|
+
isAggregation: true
|
|
1473
|
+
}
|
|
1256
1474
|
}),
|
|
1257
1475
|
children: [clients.map((client) => /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1258
1476
|
name: [client.name],
|
|
@@ -1277,6 +1495,7 @@ const groupedClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1277
1495
|
function Operations({ name, nodes }) {
|
|
1278
1496
|
const operationsObject = {};
|
|
1279
1497
|
nodes.forEach((node) => {
|
|
1498
|
+
if (!_kubb_core.ast.isHttpOperationNode(node)) return;
|
|
1280
1499
|
operationsObject[node.operationId] = {
|
|
1281
1500
|
path: new URLPath(node.path).URL,
|
|
1282
1501
|
method: node.method.toLowerCase()
|
|
@@ -1295,11 +1514,17 @@ function Operations({ name, nodes }) {
|
|
|
1295
1514
|
}
|
|
1296
1515
|
//#endregion
|
|
1297
1516
|
//#region src/generators/operationsGenerator.tsx
|
|
1517
|
+
/**
|
|
1518
|
+
* Generates an `operations.ts` file that re-exports every operation grouped
|
|
1519
|
+
* by HTTP method. Enabled when `pluginClient({ operations: true })`. Useful
|
|
1520
|
+
* for building meta-tooling on top of the generated client (route
|
|
1521
|
+
* registries, API explorers).
|
|
1522
|
+
*/
|
|
1298
1523
|
const operationsGenerator = (0, _kubb_core.defineGenerator)({
|
|
1299
1524
|
name: "client",
|
|
1300
|
-
renderer: _kubb_renderer_jsx.
|
|
1525
|
+
renderer: _kubb_renderer_jsx.jsxRendererSync,
|
|
1301
1526
|
operations(nodes, ctx) {
|
|
1302
|
-
const { config, resolver,
|
|
1527
|
+
const { config, resolver, root } = ctx;
|
|
1303
1528
|
const { output, group } = ctx.options;
|
|
1304
1529
|
const name = "operations";
|
|
1305
1530
|
const file = resolver.resolveFile({
|
|
@@ -1308,23 +1533,31 @@ const operationsGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1308
1533
|
}, {
|
|
1309
1534
|
root,
|
|
1310
1535
|
output,
|
|
1311
|
-
group
|
|
1536
|
+
group: group ?? void 0
|
|
1312
1537
|
});
|
|
1313
1538
|
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File, {
|
|
1314
1539
|
baseName: file.baseName,
|
|
1315
1540
|
path: file.path,
|
|
1316
1541
|
meta: file.meta,
|
|
1317
|
-
banner: resolver.resolveBanner(
|
|
1542
|
+
banner: resolver.resolveBanner(ctx.meta, {
|
|
1318
1543
|
output,
|
|
1319
|
-
config
|
|
1544
|
+
config,
|
|
1545
|
+
file: {
|
|
1546
|
+
path: file.path,
|
|
1547
|
+
baseName: file.baseName
|
|
1548
|
+
}
|
|
1320
1549
|
}),
|
|
1321
|
-
footer: resolver.resolveFooter(
|
|
1550
|
+
footer: resolver.resolveFooter(ctx.meta, {
|
|
1322
1551
|
output,
|
|
1323
|
-
config
|
|
1552
|
+
config,
|
|
1553
|
+
file: {
|
|
1554
|
+
path: file.path,
|
|
1555
|
+
baseName: file.baseName
|
|
1556
|
+
}
|
|
1324
1557
|
}),
|
|
1325
1558
|
children: /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(Operations, {
|
|
1326
1559
|
name,
|
|
1327
|
-
nodes
|
|
1560
|
+
nodes: nodes.filter(_kubb_core.ast.isHttpOperationNode)
|
|
1328
1561
|
})
|
|
1329
1562
|
});
|
|
1330
1563
|
}
|
|
@@ -1333,12 +1566,15 @@ const operationsGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1333
1566
|
//#region src/components/StaticClassClient.tsx
|
|
1334
1567
|
const declarationPrinter = (0, _kubb_plugin_ts.functionPrinter)({ mode: "declaration" });
|
|
1335
1568
|
function generateMethod({ node, name, tsResolver, zodResolver, baseURL, dataReturnType, parser, paramsType, paramsCasing, pathParamsType }) {
|
|
1569
|
+
if (!_kubb_core.ast.isHttpOperationNode(node)) return "";
|
|
1336
1570
|
const path = new URLPath(node.path, { casing: paramsCasing });
|
|
1337
|
-
const contentType = node
|
|
1338
|
-
const isFormData = contentType === "multipart/form-data";
|
|
1339
|
-
const
|
|
1571
|
+
const { defaultContentType: contentType, isMultipleContentTypes, hasFormData } = getContentTypeInfo(node);
|
|
1572
|
+
const isFormData = !isMultipleContentTypes && contentType === "multipart/form-data";
|
|
1573
|
+
const { header: headerParams } = getOperationParameters(node);
|
|
1574
|
+
const headerParamsName = headerParams.length > 0 ? tsResolver.resolveHeaderParamsName(node, headerParams[0]) : null;
|
|
1575
|
+
const headers = isMultipleContentTypes ? headerParamsName ? ["...headers"] : [] : buildHeaders(contentType, !!headerParamsName);
|
|
1340
1576
|
const generics = buildGenerics(node, tsResolver);
|
|
1341
|
-
const paramsNode =
|
|
1577
|
+
const paramsNode = buildClientParamsNode({
|
|
1342
1578
|
paramsType,
|
|
1343
1579
|
paramsCasing,
|
|
1344
1580
|
pathParamsType,
|
|
@@ -1353,15 +1589,21 @@ function generateMethod({ node, name, tsResolver, zodResolver, baseURL, dataRetu
|
|
|
1353
1589
|
baseURL,
|
|
1354
1590
|
tsResolver,
|
|
1355
1591
|
isFormData,
|
|
1592
|
+
isMultipleContentTypes,
|
|
1593
|
+
hasFormData,
|
|
1356
1594
|
headers
|
|
1357
1595
|
});
|
|
1358
|
-
const jsdoc = buildJSDoc(
|
|
1596
|
+
const jsdoc = buildJSDoc(buildOperationComments(node, {
|
|
1597
|
+
link: "urlPath",
|
|
1598
|
+
linkPosition: "beforeDeprecated",
|
|
1599
|
+
splitLines: true
|
|
1600
|
+
}));
|
|
1359
1601
|
const requestDataLine = buildRequestDataLine({
|
|
1360
1602
|
parser,
|
|
1361
1603
|
node,
|
|
1362
1604
|
zodResolver
|
|
1363
1605
|
});
|
|
1364
|
-
const formDataLine = buildFormDataLine(isFormData, !!node.requestBody?.content?.[0]?.schema);
|
|
1606
|
+
const formDataLine = buildFormDataLine(isFormData || isMultipleContentTypes && hasFormData, !!node.requestBody?.content?.[0]?.schema);
|
|
1365
1607
|
const returnStatement = buildReturnStatement({
|
|
1366
1608
|
dataReturnType,
|
|
1367
1609
|
parser,
|
|
@@ -1369,7 +1611,7 @@ function generateMethod({ node, name, tsResolver, zodResolver, baseURL, dataRetu
|
|
|
1369
1611
|
zodResolver
|
|
1370
1612
|
});
|
|
1371
1613
|
return `${jsdoc} static async ${name}(${paramsSignature}) {\n${[
|
|
1372
|
-
|
|
1614
|
+
`const { client: request = client, ${isMultipleContentTypes ? `contentType = ${JSON.stringify(contentType)}, ` : ""}...requestConfig } = mergeConfig(this.#config, config)`,
|
|
1373
1615
|
"",
|
|
1374
1616
|
requestDataLine,
|
|
1375
1617
|
formDataLine,
|
|
@@ -1397,56 +1639,44 @@ function StaticClassClient({ name, isExportable = true, isIndexable = true, oper
|
|
|
1397
1639
|
children: [classCode, children]
|
|
1398
1640
|
});
|
|
1399
1641
|
}
|
|
1400
|
-
StaticClassClient.getParams = Client.getParams;
|
|
1401
1642
|
//#endregion
|
|
1402
1643
|
//#region src/generators/staticClassClientGenerator.tsx
|
|
1403
1644
|
function resolveTypeImportNames(node, tsResolver) {
|
|
1404
|
-
return
|
|
1405
|
-
node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : void 0,
|
|
1406
|
-
tsResolver.resolveResponseName(node),
|
|
1407
|
-
...node.parameters.filter((p) => p.in === "path").map((p) => tsResolver.resolvePathParamsName(node, p)),
|
|
1408
|
-
...node.parameters.filter((p) => p.in === "query").map((p) => tsResolver.resolveQueryParamsName(node, p)),
|
|
1409
|
-
...node.parameters.filter((p) => p.in === "header").map((p) => tsResolver.resolveHeaderParamsName(node, p)),
|
|
1410
|
-
...node.responses.map((res) => tsResolver.resolveResponseStatusName(node, res.statusCode))
|
|
1411
|
-
].filter((n) => Boolean(n));
|
|
1645
|
+
return resolveOperationTypeNames(node, tsResolver, { order: "body-response-first" });
|
|
1412
1646
|
}
|
|
1413
1647
|
function resolveZodImportNames(node, zodResolver) {
|
|
1414
|
-
return [zodResolver.resolveResponseName?.(node), node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) :
|
|
1648
|
+
return [zodResolver.resolveResponseName?.(node), node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : null].filter((n) => Boolean(n));
|
|
1415
1649
|
}
|
|
1650
|
+
/**
|
|
1651
|
+
* Built-in `operations` generator for `@kubb/plugin-client` when
|
|
1652
|
+
* `clientType: 'staticClass'`. Emits one class per tag, with a static method
|
|
1653
|
+
* per operation so callers can use `Pet.getPetById(...)` without
|
|
1654
|
+
* instantiating the class.
|
|
1655
|
+
*/
|
|
1416
1656
|
const staticClassClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
1417
1657
|
name: "staticClassClient",
|
|
1418
|
-
renderer: _kubb_renderer_jsx.
|
|
1658
|
+
renderer: _kubb_renderer_jsx.jsxRendererSync,
|
|
1419
1659
|
operations(nodes, ctx) {
|
|
1420
|
-
const {
|
|
1660
|
+
const { config, driver, resolver, root } = ctx;
|
|
1421
1661
|
const { output, group, dataReturnType, paramsCasing, paramsType, pathParamsType, parser, importPath } = ctx.options;
|
|
1422
|
-
const baseURL = ctx.options.baseURL ??
|
|
1662
|
+
const baseURL = ctx.options.baseURL ?? ctx.meta.baseURL;
|
|
1423
1663
|
const pluginTs = driver.getPlugin(_kubb_plugin_ts.pluginTsName);
|
|
1424
1664
|
if (!pluginTs) return null;
|
|
1425
1665
|
const tsResolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
|
|
1426
1666
|
const tsPluginOptions = pluginTs.options;
|
|
1427
|
-
const pluginZod = parser === "zod" ? driver.getPlugin(_kubb_plugin_zod.pluginZodName) :
|
|
1428
|
-
const zodResolver = pluginZod ? driver.getResolver(_kubb_plugin_zod.pluginZodName) :
|
|
1667
|
+
const pluginZod = parser === "zod" ? driver.getPlugin(_kubb_plugin_zod.pluginZodName) : null;
|
|
1668
|
+
const zodResolver = pluginZod ? driver.getResolver(_kubb_plugin_zod.pluginZodName) : null;
|
|
1429
1669
|
function buildOperationData(node) {
|
|
1430
|
-
const typeFile = tsResolver.resolveFile({
|
|
1431
|
-
name: node.operationId,
|
|
1432
|
-
extname: ".ts",
|
|
1433
|
-
tag: node.tags[0] ?? "default",
|
|
1434
|
-
path: node.path
|
|
1435
|
-
}, {
|
|
1670
|
+
const typeFile = tsResolver.resolveFile(operationFileEntry(node, node.operationId), {
|
|
1436
1671
|
root,
|
|
1437
1672
|
output: tsPluginOptions?.output ?? output,
|
|
1438
1673
|
group: tsPluginOptions?.group
|
|
1439
1674
|
});
|
|
1440
|
-
const zodFile = zodResolver && pluginZod?.options ? zodResolver.resolveFile({
|
|
1441
|
-
name: node.operationId,
|
|
1442
|
-
extname: ".ts",
|
|
1443
|
-
tag: node.tags[0] ?? "default",
|
|
1444
|
-
path: node.path
|
|
1445
|
-
}, {
|
|
1675
|
+
const zodFile = zodResolver && pluginZod?.options ? zodResolver.resolveFile(operationFileEntry(node, node.operationId), {
|
|
1446
1676
|
root,
|
|
1447
1677
|
output: pluginZod.options?.output ?? output,
|
|
1448
|
-
group: pluginZod.options?.group
|
|
1449
|
-
}) :
|
|
1678
|
+
group: pluginZod.options?.group ?? void 0
|
|
1679
|
+
}) : null;
|
|
1450
1680
|
return {
|
|
1451
1681
|
node,
|
|
1452
1682
|
name: resolver.resolveName(node.operationId),
|
|
@@ -1457,17 +1687,18 @@ const staticClassClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1457
1687
|
};
|
|
1458
1688
|
}
|
|
1459
1689
|
const controllers = nodes.reduce((acc, operationNode) => {
|
|
1690
|
+
if (!_kubb_core.ast.isHttpOperationNode(operationNode)) return acc;
|
|
1460
1691
|
const tag = operationNode.tags[0];
|
|
1461
|
-
const groupName = tag ? group?.name?.({ group: camelCase(tag) }) ??
|
|
1692
|
+
const groupName = tag ? group?.name?.({ group: camelCase(tag) }) ?? resolver.resolveGroupName(tag) : resolver.resolveGroupName("Client");
|
|
1462
1693
|
if (!tag && !group) {
|
|
1463
|
-
const name = "ApiClient";
|
|
1694
|
+
const name = resolver.resolveClassName("ApiClient");
|
|
1464
1695
|
const file = resolver.resolveFile({
|
|
1465
1696
|
name,
|
|
1466
1697
|
extname: ".ts"
|
|
1467
1698
|
}, {
|
|
1468
1699
|
root,
|
|
1469
1700
|
output,
|
|
1470
|
-
group
|
|
1701
|
+
group: group ?? void 0
|
|
1471
1702
|
});
|
|
1472
1703
|
const operationData = buildOperationData(operationNode);
|
|
1473
1704
|
const previous = acc.find((item) => item.file.path === file.path);
|
|
@@ -1477,7 +1708,9 @@ const staticClassClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1477
1708
|
file,
|
|
1478
1709
|
operations: [operationData]
|
|
1479
1710
|
});
|
|
1480
|
-
|
|
1711
|
+
return acc;
|
|
1712
|
+
}
|
|
1713
|
+
if (tag) {
|
|
1481
1714
|
const name = groupName;
|
|
1482
1715
|
const file = resolver.resolveFile({
|
|
1483
1716
|
name,
|
|
@@ -1486,7 +1719,7 @@ const staticClassClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1486
1719
|
}, {
|
|
1487
1720
|
root,
|
|
1488
1721
|
output,
|
|
1489
|
-
group
|
|
1722
|
+
group: group ?? void 0
|
|
1490
1723
|
});
|
|
1491
1724
|
const operationData = buildOperationData(operationNode);
|
|
1492
1725
|
const previous = acc.find((item) => item.file.path === file.path);
|
|
@@ -1540,23 +1773,31 @@ const staticClassClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1540
1773
|
zodImportsByFile: /* @__PURE__ */ new Map(),
|
|
1541
1774
|
zodFilesByPath: /* @__PURE__ */ new Map()
|
|
1542
1775
|
};
|
|
1543
|
-
const hasFormData = ops.some((op) => op.node.requestBody?.content?.
|
|
1776
|
+
const hasFormData = ops.some((op) => op.node.requestBody?.content?.some((e) => e.contentType === "multipart/form-data") ?? false);
|
|
1544
1777
|
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.File, {
|
|
1545
1778
|
baseName: file.baseName,
|
|
1546
1779
|
path: file.path,
|
|
1547
1780
|
meta: file.meta,
|
|
1548
|
-
banner: resolver.resolveBanner(
|
|
1781
|
+
banner: resolver.resolveBanner(ctx.meta, {
|
|
1549
1782
|
output,
|
|
1550
|
-
config
|
|
1783
|
+
config,
|
|
1784
|
+
file: {
|
|
1785
|
+
path: file.path,
|
|
1786
|
+
baseName: file.baseName
|
|
1787
|
+
}
|
|
1551
1788
|
}),
|
|
1552
|
-
footer: resolver.resolveFooter(
|
|
1789
|
+
footer: resolver.resolveFooter(ctx.meta, {
|
|
1553
1790
|
output,
|
|
1554
|
-
config
|
|
1791
|
+
config,
|
|
1792
|
+
file: {
|
|
1793
|
+
path: file.path,
|
|
1794
|
+
baseName: file.baseName
|
|
1795
|
+
}
|
|
1555
1796
|
}),
|
|
1556
1797
|
children: [
|
|
1557
1798
|
importPath ? /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [
|
|
1558
1799
|
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1559
|
-
name: "
|
|
1800
|
+
name: "client",
|
|
1560
1801
|
path: importPath
|
|
1561
1802
|
}),
|
|
1562
1803
|
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
@@ -1574,7 +1815,7 @@ const staticClassClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1574
1815
|
})
|
|
1575
1816
|
] }) : /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [
|
|
1576
1817
|
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1577
|
-
name: ["
|
|
1818
|
+
name: ["client"],
|
|
1578
1819
|
root: file.path,
|
|
1579
1820
|
path: node_path.default.resolve(root, ".kubb/client.ts")
|
|
1580
1821
|
}),
|
|
@@ -1640,39 +1881,75 @@ const staticClassClientGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
1640
1881
|
//#endregion
|
|
1641
1882
|
//#region src/resolvers/resolverClient.ts
|
|
1642
1883
|
/**
|
|
1643
|
-
*
|
|
1884
|
+
* Default resolver used by `@kubb/plugin-client`. Decides the names and file
|
|
1885
|
+
* paths for every generated client function or class. Functions and files use
|
|
1886
|
+
* camelCase; classes and tag groups use PascalCase.
|
|
1644
1887
|
*
|
|
1645
|
-
*
|
|
1888
|
+
* @example Resolve client function and class names
|
|
1889
|
+
* ```ts
|
|
1890
|
+
* import { resolverClient } from '@kubb/plugin-client'
|
|
1646
1891
|
*
|
|
1647
|
-
*
|
|
1648
|
-
*
|
|
1892
|
+
* resolverClient.default('list pets', 'function') // 'listPets'
|
|
1893
|
+
* resolverClient.resolveClassName('pet') // 'Pet'
|
|
1894
|
+
* resolverClient.resolveUrlName(operationNode) // 'getShowPetByIdUrl'
|
|
1895
|
+
* ```
|
|
1649
1896
|
*/
|
|
1650
|
-
const resolverClient = (0, _kubb_core.defineResolver)((
|
|
1897
|
+
const resolverClient = (0, _kubb_core.defineResolver)(() => ({
|
|
1651
1898
|
name: "default",
|
|
1652
1899
|
pluginName: "plugin-client",
|
|
1653
1900
|
default(name, type) {
|
|
1654
|
-
|
|
1901
|
+
const resolved = camelCase(name, { isFile: type === "file" });
|
|
1902
|
+
return type === "file" ? resolved : ensureValidVarName(resolved);
|
|
1655
1903
|
},
|
|
1656
1904
|
resolveName(name) {
|
|
1657
|
-
return
|
|
1905
|
+
return this.default(name, "function");
|
|
1906
|
+
},
|
|
1907
|
+
resolvePathName(name, type) {
|
|
1908
|
+
return this.default(name, type);
|
|
1909
|
+
},
|
|
1910
|
+
resolveClassName(name) {
|
|
1911
|
+
return ensureValidVarName(pascalCase(name));
|
|
1912
|
+
},
|
|
1913
|
+
resolveGroupName(name) {
|
|
1914
|
+
return ensureValidVarName(pascalCase(name));
|
|
1915
|
+
},
|
|
1916
|
+
resolveClientPropertyName(name) {
|
|
1917
|
+
return ensureValidVarName(camelCase(name));
|
|
1918
|
+
},
|
|
1919
|
+
resolveUrlName(node) {
|
|
1920
|
+
const name = this.resolveName(node.operationId);
|
|
1921
|
+
return `get${name.charAt(0).toUpperCase()}${name.slice(1)}Url`;
|
|
1658
1922
|
}
|
|
1659
1923
|
}));
|
|
1660
1924
|
//#endregion
|
|
1661
1925
|
//#region src/plugin.ts
|
|
1662
1926
|
/**
|
|
1663
|
-
* Canonical plugin name for `@kubb/plugin-client
|
|
1927
|
+
* Canonical plugin name for `@kubb/plugin-client`. Used for driver lookups and
|
|
1928
|
+
* cross-plugin dependency references.
|
|
1664
1929
|
*/
|
|
1665
1930
|
const pluginClientName = "plugin-client";
|
|
1666
1931
|
/**
|
|
1667
|
-
* Generates
|
|
1668
|
-
*
|
|
1669
|
-
*
|
|
1932
|
+
* Generates one HTTP client function per OpenAPI operation. Each function has
|
|
1933
|
+
* typed path params, query params, body, and response, so callers use the API
|
|
1934
|
+
* like any other typed function. Ships with `axios` and `fetch` runtimes; bring
|
|
1935
|
+
* your own by setting `importPath`.
|
|
1670
1936
|
*
|
|
1671
|
-
* @example
|
|
1937
|
+
* @example
|
|
1672
1938
|
* ```ts
|
|
1673
|
-
* import
|
|
1939
|
+
* import { defineConfig } from 'kubb'
|
|
1940
|
+
* import { pluginTs } from '@kubb/plugin-ts'
|
|
1941
|
+
* import { pluginClient } from '@kubb/plugin-client'
|
|
1942
|
+
*
|
|
1674
1943
|
* export default defineConfig({
|
|
1675
|
-
*
|
|
1944
|
+
* input: { path: './petStore.yaml' },
|
|
1945
|
+
* output: { path: './src/gen' },
|
|
1946
|
+
* plugins: [
|
|
1947
|
+
* pluginTs(),
|
|
1948
|
+
* pluginClient({
|
|
1949
|
+
* output: { path: './clients' },
|
|
1950
|
+
* client: 'fetch',
|
|
1951
|
+
* }),
|
|
1952
|
+
* ],
|
|
1676
1953
|
* })
|
|
1677
1954
|
* ```
|
|
1678
1955
|
*/
|
|
@@ -1680,24 +1957,21 @@ const pluginClient = (0, _kubb_core.definePlugin)((options) => {
|
|
|
1680
1957
|
const { output = {
|
|
1681
1958
|
path: "clients",
|
|
1682
1959
|
barrelType: "named"
|
|
1683
|
-
}, group, exclude = [], include, override = [], urlType = false, dataReturnType = "data", paramsType = "inline", pathParamsType = paramsType === "object" ? "object" : options.pathParamsType || "inline", operations = false, paramsCasing, clientType = options.sdk ? "class" : "function", parser =
|
|
1960
|
+
}, group, exclude = [], include, override = [], urlType = false, dataReturnType = "data", paramsType = "inline", pathParamsType = paramsType === "object" ? "object" : options.pathParamsType || "inline", operations = false, paramsCasing, clientType = options.sdk ? "class" : "function", parser = false, client = "axios", importPath, bundle = false, sdk, baseURL, resolver: userResolver, transformer: userTransformer } = options;
|
|
1684
1961
|
const resolvedImportPath = importPath ?? (!bundle ? `@kubb/plugin-client/clients/${client}` : void 0);
|
|
1685
1962
|
const selectedGenerators = options.generators ?? [
|
|
1686
1963
|
clientType === "staticClass" ? staticClassClientGenerator : clientType === "class" ? classClientGenerator : clientGenerator,
|
|
1687
|
-
group && clientType === "function" ? groupedClientGenerator :
|
|
1688
|
-
operations ? operationsGenerator :
|
|
1964
|
+
group && clientType === "function" ? groupedClientGenerator : null,
|
|
1965
|
+
operations ? operationsGenerator : null
|
|
1689
1966
|
].filter((x) => Boolean(x));
|
|
1690
|
-
const groupConfig = group
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
return `${camelCase(ctx.group)}Controller`;
|
|
1695
|
-
}
|
|
1696
|
-
} : void 0;
|
|
1967
|
+
const groupConfig = createGroupConfig(group, {
|
|
1968
|
+
suffix: "Controller",
|
|
1969
|
+
honorName: true
|
|
1970
|
+
});
|
|
1697
1971
|
return {
|
|
1698
1972
|
name: pluginClientName,
|
|
1699
1973
|
options,
|
|
1700
|
-
dependencies: [_kubb_plugin_ts.pluginTsName, parser === "zod" ? _kubb_plugin_zod.pluginZodName :
|
|
1974
|
+
dependencies: [_kubb_plugin_ts.pluginTsName, parser === "zod" ? _kubb_plugin_zod.pluginZodName : null].filter((dependency) => Boolean(dependency)),
|
|
1701
1975
|
hooks: { "kubb:plugin:setup"(ctx) {
|
|
1702
1976
|
const resolver = userResolver ? {
|
|
1703
1977
|
...resolverClient,
|