@kubb/plugin-fetch 5.0.0-beta.85 → 5.0.0-beta.87
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 +100 -106
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +8 -19
- package/dist/index.js +101 -107
- package/dist/index.js.map +1 -1
- package/package.json +6 -7
- package/src/generators/clientGenerator.tsx +11 -9
- package/src/plugin.ts +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as __name } from "./rolldown-runtime-C0LytTxp.js";
|
|
2
|
-
import { Exclude, Group, Include, Output, OutputOptions, Override, PluginFactoryOptions, Resolver, ast } from "kubb/kit";
|
|
2
|
+
import { Exclude, Group, Include, Output, OutputOptions, Override, PluginFactoryOptions, Resolver, ResolverPatch, ast } from "kubb/kit";
|
|
3
3
|
//#region ../../internals/client/src/types.d.ts
|
|
4
4
|
/**
|
|
5
5
|
* Validator applied to request and response bodies using schemas from `@kubb/plugin-zod`.
|
|
@@ -21,39 +21,28 @@ type ValidatorOptions = false | 'zod' | {
|
|
|
21
21
|
*/
|
|
22
22
|
type Mode = 'tag' | 'flat';
|
|
23
23
|
/**
|
|
24
|
-
* The resolver shared by the client plugins.
|
|
25
|
-
* a `
|
|
24
|
+
* The resolver shared by the client plugins. Inherits the built-in camelCase `name` and `file`;
|
|
25
|
+
* classes and tag groups use PascalCase (with a `Client` suffix for groups).
|
|
26
26
|
*/
|
|
27
27
|
type ResolverClient = Resolver & {
|
|
28
|
-
/**
|
|
29
|
-
* Resolves the function name for a raw operation name.
|
|
30
|
-
*
|
|
31
|
-
* @example
|
|
32
|
-
* `resolver.resolveName('show pet by id') // -> 'showPetById'`
|
|
33
|
-
*/
|
|
34
|
-
resolveName(this: ResolverClient, name: string): string;
|
|
35
|
-
/**
|
|
36
|
-
* Resolves the output file name for a generated client module.
|
|
37
|
-
*/
|
|
38
|
-
resolvePathName(this: ResolverClient, name: string, type?: 'file' | 'function' | 'type' | 'const'): string;
|
|
39
28
|
/**
|
|
40
29
|
* Resolves the generated class name for class-based clients.
|
|
41
30
|
*/
|
|
42
|
-
|
|
31
|
+
className(this: ResolverClient, name: string): string;
|
|
43
32
|
/**
|
|
44
33
|
* Resolves the generated class name for a tag-based client group. The default appends a
|
|
45
34
|
* `Client` suffix (tag `pet` becomes `PetClient`) so the class never collides with the schema
|
|
46
35
|
* model of the same name in the barrel.
|
|
47
36
|
*
|
|
48
37
|
* @example
|
|
49
|
-
* `resolver.
|
|
38
|
+
* `resolver.groupName('pet') // -> 'PetClient'`
|
|
50
39
|
*/
|
|
51
|
-
|
|
40
|
+
groupName(this: ResolverClient, name: string): string;
|
|
52
41
|
/**
|
|
53
42
|
* Resolves the property name a tag client is exposed under on the composed root SDK
|
|
54
43
|
* (`new PetStore(config).pet`).
|
|
55
44
|
*/
|
|
56
|
-
|
|
45
|
+
propertyName(this: ResolverClient, name: string): string;
|
|
57
46
|
};
|
|
58
47
|
/**
|
|
59
48
|
* The shared options surface for the client plugins. Deliberately small: there is one
|
|
@@ -134,7 +123,7 @@ type Options = OutputOptions & {
|
|
|
134
123
|
/**
|
|
135
124
|
* Override how names and file paths are built. Methods you omit fall back to the default resolver.
|
|
136
125
|
*/
|
|
137
|
-
resolver?:
|
|
126
|
+
resolver?: ResolverPatch<ResolverClient>;
|
|
138
127
|
/**
|
|
139
128
|
* Macros applied to each operation node before code is printed.
|
|
140
129
|
*/
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import "./rolldown-runtime-C0LytTxp.js";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import { ast, defineGenerator, definePlugin
|
|
3
|
+
import { Resolver, ast, createResolver, defineGenerator, definePlugin } from "kubb/kit";
|
|
4
4
|
import { File, Function, jsxRenderer } from "kubb/jsx";
|
|
5
5
|
import { createFunctionParameter, createFunctionParameters, functionPrinter, pluginTsName } from "@kubb/plugin-ts";
|
|
6
6
|
import { Fragment, jsx, jsxs } from "kubb/jsx/jsx-runtime";
|
|
@@ -45,31 +45,6 @@ function pascalCase(text, { prefix = "", suffix = "" } = {}) {
|
|
|
45
45
|
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true);
|
|
46
46
|
}
|
|
47
47
|
//#endregion
|
|
48
|
-
//#region ../../internals/utils/src/fs.ts
|
|
49
|
-
/**
|
|
50
|
-
* Builds a nested file path from a dotted name. Splits on dots that precede a letter
|
|
51
|
-
* (so version numbers embedded in operationIds like `v2025.0` stay intact), camelCases
|
|
52
|
-
* every earlier segment, applies `caseLast` to the final segment, and joins with `/`.
|
|
53
|
-
*
|
|
54
|
-
* Empty segments are dropped before joining. They arise when the name starts with a dot
|
|
55
|
-
* followed by a letter (e.g. `..Schema` splits into `['..', 'Schema']` and `'..'` cases to
|
|
56
|
-
* an empty string). Without this a leading `/` would form, which `path.resolve` reads as an
|
|
57
|
-
* absolute path, letting generated files escape the configured output directory.
|
|
58
|
-
*
|
|
59
|
-
* @example Nested path from a dotted name
|
|
60
|
-
* `toFilePath('pet.petId') // 'pet/petId'`
|
|
61
|
-
*
|
|
62
|
-
* @example PascalCase the final segment
|
|
63
|
-
* `toFilePath('pet.Pet', pascalCase) // 'pet/Pet'`
|
|
64
|
-
*
|
|
65
|
-
* @example Suffix applied to the final segment only
|
|
66
|
-
* `toFilePath('tag.tag', (part) => camelCase(part, { suffix: 'schema' })) // 'tag/tagSchema'`
|
|
67
|
-
*/
|
|
68
|
-
function toFilePath(name, caseLast = camelCase) {
|
|
69
|
-
const parts = name.split(/\.(?=[a-zA-Z])/);
|
|
70
|
-
return parts.map((part, i) => i === parts.length - 1 ? caseLast(part) : camelCase(part)).filter(Boolean).join("/");
|
|
71
|
-
}
|
|
72
|
-
//#endregion
|
|
73
48
|
//#region ../../internals/utils/src/reserved.ts
|
|
74
49
|
/**
|
|
75
50
|
* JavaScript and Java reserved words.
|
|
@@ -170,7 +145,7 @@ const reservedWords = /* @__PURE__ */ new Set([
|
|
|
170
145
|
*/
|
|
171
146
|
function isValidVarName(name) {
|
|
172
147
|
if (!name || reservedWords.has(name)) return false;
|
|
173
|
-
return
|
|
148
|
+
return isIdentifier(name);
|
|
174
149
|
}
|
|
175
150
|
/**
|
|
176
151
|
* Returns `name` when it's a syntactically valid JavaScript variable name,
|
|
@@ -192,6 +167,39 @@ function ensureValidVarName(name) {
|
|
|
192
167
|
if (!name || isValidVarName(name)) return name;
|
|
193
168
|
return `_${name}`;
|
|
194
169
|
}
|
|
170
|
+
/**
|
|
171
|
+
* Returns `true` when `name` is syntactically a valid identifier, ignoring reserved words.
|
|
172
|
+
*
|
|
173
|
+
* Reserved words and globals (`class`, `name`, `Date`, …) are valid as bare object-literal keys
|
|
174
|
+
* even though they are not valid variable names, so use this (not {@link isValidVarName}) when
|
|
175
|
+
* deciding whether an object key needs quoting.
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* ```ts
|
|
179
|
+
* isIdentifier('name') // true
|
|
180
|
+
* isIdentifier('x-total')// false
|
|
181
|
+
* ```
|
|
182
|
+
*/
|
|
183
|
+
function isIdentifier(name) {
|
|
184
|
+
return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
|
|
185
|
+
}
|
|
186
|
+
//#endregion
|
|
187
|
+
//#region ../../internals/utils/src/codegen.ts
|
|
188
|
+
/**
|
|
189
|
+
* Builds a JSDoc comment block from an array of lines. Returns `fallback` when there are no
|
|
190
|
+
* comments.
|
|
191
|
+
*
|
|
192
|
+
* @example
|
|
193
|
+
* ```ts
|
|
194
|
+
* buildJSDoc(['@type string', '@example hello'])
|
|
195
|
+
* // '/**\n * @type string\n * @example hello\n *\/\n '
|
|
196
|
+
* ```
|
|
197
|
+
*/
|
|
198
|
+
function buildJSDoc(comments, options = {}) {
|
|
199
|
+
const { indent = " * ", suffix = "\n ", fallback = " " } = options;
|
|
200
|
+
if (comments.length === 0) return fallback;
|
|
201
|
+
return `/**\n${comments.map((c) => `${indent}${c}`).join("\n")}\n */${suffix}`;
|
|
202
|
+
}
|
|
195
203
|
//#endregion
|
|
196
204
|
//#region ../../internals/utils/src/url.ts
|
|
197
205
|
function transformParam(raw, casing) {
|
|
@@ -373,13 +381,13 @@ function buildParamsRemapExpression({ source, mapping }) {
|
|
|
373
381
|
//#region ../../internals/shared/src/operation.ts
|
|
374
382
|
/**
|
|
375
383
|
* Builds the `ResolverFileParams` every operation generator passes to
|
|
376
|
-
* `resolver.
|
|
384
|
+
* `resolver.file`: a file named `name`, tagged by the operation's first
|
|
377
385
|
* tag (or `'default'`), at the operation's path. Centralizes the entry object
|
|
378
386
|
* that was repeated at dozens of call sites across the client and query plugins.
|
|
379
387
|
*
|
|
380
388
|
* @example
|
|
381
389
|
* ```ts
|
|
382
|
-
* resolver.
|
|
390
|
+
* resolver.file(operationFileEntry(node, node.operationId), { root, output, group })
|
|
383
391
|
* ```
|
|
384
392
|
*/
|
|
385
393
|
function operationFileEntry(node, name, extname = ".ts") {
|
|
@@ -396,8 +404,11 @@ function getOperationLink(node, link) {
|
|
|
396
404
|
if (link === "urlPath") return node.path ? `{@link ${Url.toPath(node.path)}}` : null;
|
|
397
405
|
return node.path ? `{@link ${node.path.replaceAll("{", ":").replaceAll("}", "")}}` : null;
|
|
398
406
|
}
|
|
399
|
-
|
|
400
|
-
|
|
407
|
+
/**
|
|
408
|
+
* Derives the shared `ContentTypeInfo` shape from a list of content types, tracking whether several
|
|
409
|
+
* are present and the union, default, and form-data flags the client uses to pick one.
|
|
410
|
+
*/
|
|
411
|
+
function buildContentTypeInfo(contentTypes) {
|
|
401
412
|
const isMultipleContentTypes = contentTypes.length > 1;
|
|
402
413
|
return {
|
|
403
414
|
contentTypes,
|
|
@@ -407,20 +418,15 @@ function getContentTypeInfo(node) {
|
|
|
407
418
|
hasFormData: contentTypes.some((ct) => ct === "multipart/form-data")
|
|
408
419
|
};
|
|
409
420
|
}
|
|
421
|
+
function getContentTypeInfo(node) {
|
|
422
|
+
return buildContentTypeInfo(node.requestBody?.content?.map((e) => e.contentType) ?? []);
|
|
423
|
+
}
|
|
410
424
|
/**
|
|
411
425
|
* The request-body counterpart for the primary success response: the content types it documents and
|
|
412
426
|
* whether several are present, so the client can let a caller pick which one to accept.
|
|
413
427
|
*/
|
|
414
428
|
function getResponseContentTypeInfo(node) {
|
|
415
|
-
|
|
416
|
-
const isMultipleContentTypes = contentTypes.length > 1;
|
|
417
|
-
return {
|
|
418
|
-
contentTypes,
|
|
419
|
-
isMultipleContentTypes,
|
|
420
|
-
contentTypeUnion: isMultipleContentTypes ? contentTypes.map((ct) => JSON.stringify(ct)).join(" | ") : "",
|
|
421
|
-
defaultContentType: contentTypes[0] ?? "application/json",
|
|
422
|
-
hasFormData: contentTypes.some((ct) => ct === "multipart/form-data")
|
|
423
|
-
};
|
|
429
|
+
return buildContentTypeInfo(getPrimarySuccessResponse(node)?.content?.map((e) => e.contentType) ?? []);
|
|
424
430
|
}
|
|
425
431
|
/**
|
|
426
432
|
* Reads the single base content type of an operation's primary success response, lowercased and
|
|
@@ -602,7 +608,7 @@ function resolveResponseValidator(validator) {
|
|
|
602
608
|
* `<operation>ResponseSchema` is used; error bodies are never zod-parsed.
|
|
603
609
|
*/
|
|
604
610
|
function buildZodResponseParse(node, zodResolver) {
|
|
605
|
-
const name = zodResolver.
|
|
611
|
+
const name = zodResolver.response.response(node);
|
|
606
612
|
return name ? {
|
|
607
613
|
expression: name,
|
|
608
614
|
importNames: [name]
|
|
@@ -615,7 +621,7 @@ function buildZodResponseParse(node, zodResolver) {
|
|
|
615
621
|
*/
|
|
616
622
|
function buildZodErrorParse(node, zodResolver) {
|
|
617
623
|
if (!node.responses.some((res) => !isSuccessStatusCode(res.statusCode) && res.content?.some((entry) => entry.schema))) return null;
|
|
618
|
-
const name = zodResolver.
|
|
624
|
+
const name = zodResolver.response.error?.(node);
|
|
619
625
|
return name ? {
|
|
620
626
|
expression: name,
|
|
621
627
|
importNames: [name]
|
|
@@ -732,7 +738,7 @@ function buildParamsRemap({ node }) {
|
|
|
732
738
|
* `buildRequestResultGenerics({ node, tsResolver }) // 'AddPetResponses, ThrowOnError'`
|
|
733
739
|
*/
|
|
734
740
|
function buildRequestResultGenerics({ node, tsResolver }) {
|
|
735
|
-
return `${tsResolver.
|
|
741
|
+
return `${tsResolver.response.responses(node)}, ThrowOnError`;
|
|
736
742
|
}
|
|
737
743
|
//#endregion
|
|
738
744
|
//#region ../../internals/client/src/builders/returnStatement.ts
|
|
@@ -755,30 +761,30 @@ function buildReturnStatement({ node, tsResolver, callConfig }) {
|
|
|
755
761
|
const declarationPrinter = functionPrinter({ mode: "declaration" });
|
|
756
762
|
/**
|
|
757
763
|
* Builds the grouped-options signature for one operation: a single `options` object whose `TData`
|
|
758
|
-
* is the plugin-ts `<Name>
|
|
764
|
+
* is the plugin-ts `<Name>Options` (carrying a literal `url`), and a `RequestResult` return type
|
|
759
765
|
* keyed to the plugin-ts per-status responses record. There are no positional arguments.
|
|
760
766
|
*
|
|
761
|
-
* The generated file imports `<Name>
|
|
767
|
+
* The generated file imports `<Name>Options` and `<Name>Responses` and uses them directly, so no
|
|
762
768
|
* per-operation input type has to be emitted.
|
|
763
769
|
*/
|
|
764
770
|
function buildGroupedOptionsSignature({ node, tsResolver }) {
|
|
765
|
-
const
|
|
766
|
-
const responsesName = tsResolver.
|
|
771
|
+
const optionsName = tsResolver.response.options(node);
|
|
772
|
+
const responsesName = tsResolver.response.responses(node);
|
|
767
773
|
const resultGenerics = buildRequestResultGenerics({
|
|
768
774
|
node,
|
|
769
775
|
tsResolver
|
|
770
776
|
});
|
|
771
777
|
const { isOptional } = getRequestGroupOptionality(node);
|
|
772
778
|
return {
|
|
773
|
-
dataTypeName:
|
|
779
|
+
dataTypeName: optionsName,
|
|
774
780
|
paramsSignature: declarationPrinter.print(createFunctionParameters({ params: [createFunctionParameter({
|
|
775
781
|
name: "options",
|
|
776
|
-
type: `Options<${
|
|
782
|
+
type: `Options<${optionsName}, ThrowOnError>`,
|
|
777
783
|
...isOptional ? { default: "{}" } : {}
|
|
778
784
|
})] })) ?? "",
|
|
779
785
|
returnType: `Promise<RequestResult<${resultGenerics}>>`,
|
|
780
786
|
generics: ["ThrowOnError extends boolean = true"],
|
|
781
|
-
importedTypeNames: [
|
|
787
|
+
importedTypeNames: [optionsName, responsesName]
|
|
782
788
|
};
|
|
783
789
|
}
|
|
784
790
|
//#endregion
|
|
@@ -844,7 +850,7 @@ function buildStyles({ node }) {
|
|
|
844
850
|
function buildValidatorHooks({ node, validator, zodResolver }) {
|
|
845
851
|
const importedZodNames = [];
|
|
846
852
|
const hasRequestBody = Boolean(node.requestBody?.content?.[0]?.schema);
|
|
847
|
-
const zodRequestName = zodResolver && resolveRequestValidator(validator) === "zod" && hasRequestBody ? zodResolver.
|
|
853
|
+
const zodRequestName = zodResolver && resolveRequestValidator(validator) === "zod" && hasRequestBody ? zodResolver.response.body(node) : null;
|
|
848
854
|
const request = zodRequestName ?? null;
|
|
849
855
|
if (zodRequestName) importedZodNames.push(zodRequestName);
|
|
850
856
|
const responseParse = zodResolver && resolveResponseValidator(validator) === "zod" ? buildZodResponseParse(node, zodResolver) : null;
|
|
@@ -904,7 +910,7 @@ function Operation({ name, node, tsResolver, zodResolver, validator, security, i
|
|
|
904
910
|
"...config",
|
|
905
911
|
...buildParamsRemap({ node })
|
|
906
912
|
].filter(Boolean).join(", ")} }`;
|
|
907
|
-
const eventType = `SuccessOf<${tsResolver.
|
|
913
|
+
const eventType = `SuccessOf<${tsResolver.response.responses(node)}>`;
|
|
908
914
|
const returnType = eventStream ? `Promise<EventStreamResult<${eventType}>>` : signature.returnType;
|
|
909
915
|
const returnStatement = eventStream ? `return toEventStream<${eventType}>(request(${callConfig}))` : buildReturnStatement({
|
|
910
916
|
node,
|
|
@@ -982,7 +988,7 @@ function buildSdkMethod({ node, name, tsResolver, zodResolver, validator, securi
|
|
|
982
988
|
})
|
|
983
989
|
});
|
|
984
990
|
const generics = signature.generics.length ? `<${signature.generics.join(", ")}>` : "";
|
|
985
|
-
const jsdoc =
|
|
991
|
+
const jsdoc = buildJSDoc(buildOperationComments(node, {
|
|
986
992
|
link: "urlPath",
|
|
987
993
|
linkPosition: "beforeDeprecated",
|
|
988
994
|
splitLines: true
|
|
@@ -1052,15 +1058,15 @@ function SdkFacade({ name, isExportable = true, isIndexable = true, members, chi
|
|
|
1052
1058
|
//#endregion
|
|
1053
1059
|
//#region ../../internals/client/src/generators/sdkGenerator.tsx
|
|
1054
1060
|
function resolveTypeImportNames(node, tsResolver) {
|
|
1055
|
-
return [tsResolver.
|
|
1061
|
+
return [tsResolver.response.options(node), tsResolver.response.responses(node)];
|
|
1056
1062
|
}
|
|
1057
1063
|
function resolveZodImportNames(node, zodResolver, validator) {
|
|
1058
1064
|
const { query: queryParams } = getOperationParameters(node, { paramsCasing: "original" });
|
|
1059
1065
|
return [
|
|
1060
|
-
resolveResponseValidator(validator) === "zod" ? zodResolver.
|
|
1066
|
+
resolveResponseValidator(validator) === "zod" ? zodResolver.response.response(node) : null,
|
|
1061
1067
|
resolveResponseValidator(validator) === "zod" ? buildZodErrorParse(node, zodResolver)?.expression ?? null : null,
|
|
1062
|
-
resolveRequestValidator(validator) === "zod" && node.requestBody?.content?.[0]?.schema ? zodResolver.
|
|
1063
|
-
resolveQueryParamsValidator(validator) === "zod" && queryParams.length > 0 ? zodResolver.
|
|
1068
|
+
resolveRequestValidator(validator) === "zod" && node.requestBody?.content?.[0]?.schema ? zodResolver.response.body(node) : null,
|
|
1069
|
+
resolveQueryParamsValidator(validator) === "zod" && queryParams.length > 0 ? zodResolver.param.query(node, queryParams[0]) : null
|
|
1064
1070
|
].filter((n) => Boolean(n));
|
|
1065
1071
|
}
|
|
1066
1072
|
/**
|
|
@@ -1077,12 +1083,14 @@ function buildControllers(nodes, ctx) {
|
|
|
1077
1083
|
const zodResolver = pluginZod ? driver.getResolver(pluginZodName) : null;
|
|
1078
1084
|
const document = ctx.adapter.document;
|
|
1079
1085
|
function buildOperationData(node) {
|
|
1080
|
-
const typeFile = tsResolver.
|
|
1086
|
+
const typeFile = tsResolver.file({
|
|
1087
|
+
...operationFileEntry(node, node.operationId),
|
|
1081
1088
|
root,
|
|
1082
1089
|
output: tsPluginOptions?.output ?? output,
|
|
1083
1090
|
group: tsPluginOptions?.group
|
|
1084
1091
|
});
|
|
1085
|
-
const zodFile = zodResolver && pluginZod?.options ? zodResolver.
|
|
1092
|
+
const zodFile = zodResolver && pluginZod?.options ? zodResolver.file({
|
|
1093
|
+
...operationFileEntry(node, node.operationId),
|
|
1086
1094
|
root,
|
|
1087
1095
|
output: pluginZod.options?.output ?? output,
|
|
1088
1096
|
group: pluginZod.options?.group ?? void 0
|
|
@@ -1094,7 +1102,7 @@ function buildControllers(nodes, ctx) {
|
|
|
1094
1102
|
}) : void 0;
|
|
1095
1103
|
return {
|
|
1096
1104
|
node,
|
|
1097
|
-
name: resolver.
|
|
1105
|
+
name: resolver.name(node.operationId),
|
|
1098
1106
|
tsResolver,
|
|
1099
1107
|
zodResolver,
|
|
1100
1108
|
typeFile,
|
|
@@ -1105,12 +1113,11 @@ function buildControllers(nodes, ctx) {
|
|
|
1105
1113
|
return nodes.reduce((acc, operationNode) => {
|
|
1106
1114
|
if (!ast.isHttpOperationNode(operationNode)) return acc;
|
|
1107
1115
|
const tag = operationNode.tags[0];
|
|
1108
|
-
const name = tag ? group?.name?.({ group: camelCase(tag) }) ?? resolver.
|
|
1109
|
-
const file = resolver.
|
|
1116
|
+
const name = tag ? group?.name?.({ group: camelCase(tag) }) ?? resolver.groupName(tag) : resolver.className("ApiClient");
|
|
1117
|
+
const file = resolver.file({
|
|
1110
1118
|
name,
|
|
1111
1119
|
extname: ".ts",
|
|
1112
|
-
tag
|
|
1113
|
-
}, {
|
|
1120
|
+
tag,
|
|
1114
1121
|
root,
|
|
1115
1122
|
output,
|
|
1116
1123
|
group: group ?? void 0
|
|
@@ -1164,7 +1171,7 @@ function createSdkGenerator() {
|
|
|
1164
1171
|
if (!ctx.driver.getPlugin(pluginTsName) || !sdk) return null;
|
|
1165
1172
|
const controllers = buildControllers(nodes, ctx);
|
|
1166
1173
|
const clientPath = path.resolve(root, ".kubb/client.ts");
|
|
1167
|
-
const banner = (file) => resolver.
|
|
1174
|
+
const banner = (file) => resolver.default.banner(ctx.meta, {
|
|
1168
1175
|
output,
|
|
1169
1176
|
config,
|
|
1170
1177
|
file: {
|
|
@@ -1172,7 +1179,7 @@ function createSdkGenerator() {
|
|
|
1172
1179
|
baseName: file.baseName
|
|
1173
1180
|
}
|
|
1174
1181
|
});
|
|
1175
|
-
const footer = (file) => resolver.
|
|
1182
|
+
const footer = (file) => resolver.default.footer(ctx.meta, {
|
|
1176
1183
|
output,
|
|
1177
1184
|
config,
|
|
1178
1185
|
file: {
|
|
@@ -1239,28 +1246,26 @@ function createSdkGenerator() {
|
|
|
1239
1246
|
]
|
|
1240
1247
|
}, file.path);
|
|
1241
1248
|
};
|
|
1242
|
-
if (sdk.mode === "flat") return renderClassFile(resolver.
|
|
1249
|
+
if (sdk.mode === "flat") return renderClassFile(resolver.className(sdk.name ?? "sdk"), resolver.file({
|
|
1243
1250
|
name: sdk.name ?? "sdk",
|
|
1244
|
-
extname: ".ts"
|
|
1245
|
-
}, {
|
|
1251
|
+
extname: ".ts",
|
|
1246
1252
|
root,
|
|
1247
1253
|
output,
|
|
1248
1254
|
group: group ?? void 0
|
|
1249
1255
|
}), controllers.flatMap((controller) => controller.operations));
|
|
1250
1256
|
const classFiles = controllers.map(({ name, file, operations: ops }) => renderClassFile(name, file, ops));
|
|
1251
1257
|
if (!sdk.name) return /* @__PURE__ */ jsx(Fragment, { children: classFiles });
|
|
1252
|
-
const sdkFile = resolver.
|
|
1258
|
+
const sdkFile = resolver.file({
|
|
1253
1259
|
name: sdk.name,
|
|
1254
|
-
extname: ".ts"
|
|
1255
|
-
}, {
|
|
1260
|
+
extname: ".ts",
|
|
1256
1261
|
root,
|
|
1257
1262
|
output,
|
|
1258
1263
|
group: group ?? void 0
|
|
1259
1264
|
});
|
|
1260
|
-
const facadeName = resolver.
|
|
1265
|
+
const facadeName = resolver.className(sdk.name);
|
|
1261
1266
|
const members = controllers.map(({ name, tag }) => ({
|
|
1262
1267
|
className: name,
|
|
1263
|
-
propName: resolver.
|
|
1268
|
+
propName: resolver.propertyName(tag ?? name)
|
|
1264
1269
|
}));
|
|
1265
1270
|
return /* @__PURE__ */ jsxs(Fragment, { children: [classFiles, /* @__PURE__ */ jsxs(File, {
|
|
1266
1271
|
baseName: sdkFile.baseName,
|
|
@@ -1300,38 +1305,27 @@ const defaultMacros = [ast.macroSimplifyUnion];
|
|
|
1300
1305
|
//#endregion
|
|
1301
1306
|
//#region ../../internals/client/src/resolver.ts
|
|
1302
1307
|
/**
|
|
1303
|
-
* Default resolver shared by the client plugins. Functions and files
|
|
1304
|
-
* tag groups use PascalCase.
|
|
1308
|
+
* Default resolver shared by the client plugins. Functions and files inherit the built-in camelCase
|
|
1309
|
+
* `name` and `file`; classes and tag groups use PascalCase.
|
|
1305
1310
|
*
|
|
1306
1311
|
* @example
|
|
1307
1312
|
* ```ts
|
|
1308
|
-
* resolverClient.
|
|
1309
|
-
* resolverClient.
|
|
1313
|
+
* resolverClient.name('show pet by id') // 'showPetById'
|
|
1314
|
+
* resolverClient.groupName('pet') // 'PetClient'
|
|
1310
1315
|
* ```
|
|
1311
1316
|
*/
|
|
1312
|
-
const resolverClient =
|
|
1313
|
-
name: "default",
|
|
1317
|
+
const resolverClient = createResolver({
|
|
1314
1318
|
pluginName: "plugin-contract-client",
|
|
1315
|
-
|
|
1316
|
-
if (type === "file") return toFilePath(name);
|
|
1317
|
-
return ensureValidVarName(camelCase(name));
|
|
1318
|
-
},
|
|
1319
|
-
resolveName(name) {
|
|
1320
|
-
return this.default(name, "function");
|
|
1321
|
-
},
|
|
1322
|
-
resolvePathName(name, type) {
|
|
1323
|
-
return this.default(name, type);
|
|
1324
|
-
},
|
|
1325
|
-
resolveClassName(name) {
|
|
1319
|
+
className(name) {
|
|
1326
1320
|
return ensureValidVarName(pascalCase(name));
|
|
1327
1321
|
},
|
|
1328
|
-
|
|
1322
|
+
groupName(name) {
|
|
1329
1323
|
return ensureValidVarName(pascalCase(`${name} Client`));
|
|
1330
1324
|
},
|
|
1331
|
-
|
|
1325
|
+
propertyName(name) {
|
|
1332
1326
|
return ensureValidVarName(camelCase(name));
|
|
1333
1327
|
}
|
|
1334
|
-
})
|
|
1328
|
+
});
|
|
1335
1329
|
//#endregion
|
|
1336
1330
|
//#region src/generators/clientGenerator.tsx
|
|
1337
1331
|
/**
|
|
@@ -1352,25 +1346,28 @@ const clientGenerator = defineGenerator({
|
|
|
1352
1346
|
const pluginZod = resolveResponseValidator(validator) === "zod" || resolveRequestValidator(validator) === "zod" ? driver.getPlugin(pluginZodName) : null;
|
|
1353
1347
|
const zodResolver = pluginZod ? driver.getResolver(pluginZodName) : null;
|
|
1354
1348
|
const hasRequestBody = Boolean(node.requestBody?.content?.[0]?.schema);
|
|
1355
|
-
const importedTypeNames = [tsResolver.
|
|
1349
|
+
const importedTypeNames = [tsResolver.response.options(node), tsResolver.response.responses(node)];
|
|
1356
1350
|
const importedZodNames = zodResolver ? [
|
|
1357
|
-
resolveResponseValidator(validator) === "zod" ? zodResolver.
|
|
1351
|
+
resolveResponseValidator(validator) === "zod" ? zodResolver.response.response?.(node) : null,
|
|
1358
1352
|
resolveResponseValidator(validator) === "zod" ? buildZodErrorParse(node, zodResolver)?.expression ?? null : null,
|
|
1359
|
-
resolveRequestValidator(validator) === "zod" && hasRequestBody ? zodResolver.
|
|
1353
|
+
resolveRequestValidator(validator) === "zod" && hasRequestBody ? zodResolver.response.body?.(node) : null
|
|
1360
1354
|
].filter((name) => Boolean(name)) : [];
|
|
1361
1355
|
const meta = {
|
|
1362
|
-
name: resolver.
|
|
1363
|
-
file: resolver.
|
|
1356
|
+
name: resolver.name(node.operationId),
|
|
1357
|
+
file: resolver.file({
|
|
1358
|
+
...operationFileEntry(node, node.operationId),
|
|
1364
1359
|
root,
|
|
1365
1360
|
output,
|
|
1366
1361
|
group: group ?? void 0
|
|
1367
1362
|
}),
|
|
1368
|
-
fileTs: tsResolver.
|
|
1363
|
+
fileTs: tsResolver.file({
|
|
1364
|
+
...operationFileEntry(node, node.operationId),
|
|
1369
1365
|
root,
|
|
1370
1366
|
output: pluginTs.options?.output ?? output,
|
|
1371
1367
|
group: pluginTs.options?.group ?? void 0
|
|
1372
1368
|
}),
|
|
1373
|
-
fileZod: zodResolver && pluginZod?.options ? zodResolver.
|
|
1369
|
+
fileZod: zodResolver && pluginZod?.options ? zodResolver.file({
|
|
1370
|
+
...operationFileEntry(node, node.operationId),
|
|
1374
1371
|
root,
|
|
1375
1372
|
output: pluginZod.options.output ?? output,
|
|
1376
1373
|
group: pluginZod.options?.group ?? void 0
|
|
@@ -1387,7 +1384,7 @@ const clientGenerator = defineGenerator({
|
|
|
1387
1384
|
baseName: meta.file.baseName,
|
|
1388
1385
|
path: meta.file.path,
|
|
1389
1386
|
meta: meta.file.meta,
|
|
1390
|
-
banner: resolver.
|
|
1387
|
+
banner: resolver.default.banner(ctx.meta, {
|
|
1391
1388
|
output,
|
|
1392
1389
|
config,
|
|
1393
1390
|
file: {
|
|
@@ -1395,7 +1392,7 @@ const clientGenerator = defineGenerator({
|
|
|
1395
1392
|
baseName: meta.file.baseName
|
|
1396
1393
|
}
|
|
1397
1394
|
}),
|
|
1398
|
-
footer: resolver.
|
|
1395
|
+
footer: resolver.default.footer(ctx.meta, {
|
|
1399
1396
|
output,
|
|
1400
1397
|
config,
|
|
1401
1398
|
file: {
|
|
@@ -1499,10 +1496,7 @@ const pluginFetch = definePlugin((options) => {
|
|
|
1499
1496
|
mode: sdk.mode ?? "tag",
|
|
1500
1497
|
name: sdk.name
|
|
1501
1498
|
} : void 0,
|
|
1502
|
-
resolver: userResolver ?
|
|
1503
|
-
...resolverClient,
|
|
1504
|
-
...userResolver
|
|
1505
|
-
} : resolverClient
|
|
1499
|
+
resolver: userResolver ? Resolver.merge(resolverClient, userResolver) : resolverClient
|
|
1506
1500
|
};
|
|
1507
1501
|
const selectedGenerators = resolved.sdk ? [createSdkGenerator()] : [clientGenerator];
|
|
1508
1502
|
return {
|