@kubb/plugin-fetch 5.0.0-beta.84 → 5.0.0-beta.86
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 +148 -104
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +8 -19
- package/dist/index.js +149 -105
- 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.
|
|
@@ -193,6 +168,23 @@ function ensureValidVarName(name) {
|
|
|
193
168
|
return `_${name}`;
|
|
194
169
|
}
|
|
195
170
|
//#endregion
|
|
171
|
+
//#region ../../internals/utils/src/codegen.ts
|
|
172
|
+
/**
|
|
173
|
+
* Builds a JSDoc comment block from an array of lines. Returns `fallback` when there are no
|
|
174
|
+
* comments.
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* ```ts
|
|
178
|
+
* buildJSDoc(['@type string', '@example hello'])
|
|
179
|
+
* // '/**\n * @type string\n * @example hello\n *\/\n '
|
|
180
|
+
* ```
|
|
181
|
+
*/
|
|
182
|
+
function buildJSDoc(comments, options = {}) {
|
|
183
|
+
const { indent = " * ", suffix = "\n ", fallback = " " } = options;
|
|
184
|
+
if (comments.length === 0) return fallback;
|
|
185
|
+
return `/**\n${comments.map((c) => `${indent}${c}`).join("\n")}\n */${suffix}`;
|
|
186
|
+
}
|
|
187
|
+
//#endregion
|
|
196
188
|
//#region ../../internals/utils/src/url.ts
|
|
197
189
|
function transformParam(raw, casing) {
|
|
198
190
|
const param = isValidVarName(raw) ? raw : camelCase(raw);
|
|
@@ -341,17 +333,45 @@ function dedupeByCasedName(params) {
|
|
|
341
333
|
return true;
|
|
342
334
|
});
|
|
343
335
|
}
|
|
336
|
+
function buildParamsMapping(originalParams, mappedParams) {
|
|
337
|
+
const mapping = {};
|
|
338
|
+
let hasChanged = false;
|
|
339
|
+
originalParams.forEach((param, i) => {
|
|
340
|
+
const mappedName = mappedParams[i]?.name ?? param.name;
|
|
341
|
+
mapping[param.name] = mappedName;
|
|
342
|
+
if (param.name !== mappedName) hasChanged = true;
|
|
343
|
+
});
|
|
344
|
+
return hasChanged ? mapping : null;
|
|
345
|
+
}
|
|
346
|
+
function toAccess(object, name) {
|
|
347
|
+
return isValidVarName(name) ? `${object}.${name}` : `${object}[${JSON.stringify(name)}]`;
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Renders the object-literal expression that renames the camelCased keys of a grouped request
|
|
351
|
+
* option back to the names the OpenAPI document declares, guarded so an omitted optional group
|
|
352
|
+
* stays omitted. Shared by the client and cypress generators, which pass a `buildParamsMapping`
|
|
353
|
+
* result and the source expression to read the keys from.
|
|
354
|
+
*
|
|
355
|
+
* @example
|
|
356
|
+
* ```ts
|
|
357
|
+
* buildParamsRemapExpression({ source: 'config.query', mapping: { include_deleted: 'includeDeleted' } })
|
|
358
|
+
* // 'config.query ? { "include_deleted": config.query.includeDeleted } : config.query'
|
|
359
|
+
* ```
|
|
360
|
+
*/
|
|
361
|
+
function buildParamsRemapExpression({ source, mapping }) {
|
|
362
|
+
return `${source} ? { ${Object.entries(mapping).map(([originalName, casedName]) => `${JSON.stringify(originalName)}: ${toAccess(source, casedName)}`).join(", ")} } : ${source}`;
|
|
363
|
+
}
|
|
344
364
|
//#endregion
|
|
345
365
|
//#region ../../internals/shared/src/operation.ts
|
|
346
366
|
/**
|
|
347
367
|
* Builds the `ResolverFileParams` every operation generator passes to
|
|
348
|
-
* `resolver.
|
|
368
|
+
* `resolver.file`: a file named `name`, tagged by the operation's first
|
|
349
369
|
* tag (or `'default'`), at the operation's path. Centralizes the entry object
|
|
350
370
|
* that was repeated at dozens of call sites across the client and query plugins.
|
|
351
371
|
*
|
|
352
372
|
* @example
|
|
353
373
|
* ```ts
|
|
354
|
-
* resolver.
|
|
374
|
+
* resolver.file(operationFileEntry(node, node.operationId), { root, output, group })
|
|
355
375
|
* ```
|
|
356
376
|
*/
|
|
357
377
|
function operationFileEntry(node, name, extname = ".ts") {
|
|
@@ -574,7 +594,7 @@ function resolveResponseValidator(validator) {
|
|
|
574
594
|
* `<operation>ResponseSchema` is used; error bodies are never zod-parsed.
|
|
575
595
|
*/
|
|
576
596
|
function buildZodResponseParse(node, zodResolver) {
|
|
577
|
-
const name = zodResolver.
|
|
597
|
+
const name = zodResolver.response.response(node);
|
|
578
598
|
return name ? {
|
|
579
599
|
expression: name,
|
|
580
600
|
importNames: [name]
|
|
@@ -587,7 +607,7 @@ function buildZodResponseParse(node, zodResolver) {
|
|
|
587
607
|
*/
|
|
588
608
|
function buildZodErrorParse(node, zodResolver) {
|
|
589
609
|
if (!node.responses.some((res) => !isSuccessStatusCode(res.statusCode) && res.content?.some((entry) => entry.schema))) return null;
|
|
590
|
-
const name = zodResolver.
|
|
610
|
+
const name = zodResolver.response.error?.(node);
|
|
591
611
|
return name ? {
|
|
592
612
|
expression: name,
|
|
593
613
|
importNames: [name]
|
|
@@ -662,6 +682,38 @@ function buildSecurityMetadata({ security }) {
|
|
|
662
682
|
return `[${security.map(serializeAuth).join(", ")}]`;
|
|
663
683
|
}
|
|
664
684
|
//#endregion
|
|
685
|
+
//#region ../../internals/client/src/builders/paramsRemap.ts
|
|
686
|
+
/**
|
|
687
|
+
* Builds the call-config entries that rename the camelCased `query` and `headers` keys back to the
|
|
688
|
+
* names the OpenAPI document declares, so the wire format follows the spec while the generated
|
|
689
|
+
* types keep camelCase keys. Returns an empty array when no name changes. Path parameters need no
|
|
690
|
+
* remap because the URL template placeholders are renamed in sync with the `path` keys. Emit the
|
|
691
|
+
* entries after the `...config` spread so they override the camelCased groups the caller passes in.
|
|
692
|
+
*
|
|
693
|
+
* @example
|
|
694
|
+
* ```ts
|
|
695
|
+
* // a query param named include_deleted in the spec
|
|
696
|
+
* buildParamsRemap({ node }) // ['query: config.query ? { "include_deleted": config.query.includeDeleted } : config.query']
|
|
697
|
+
* ```
|
|
698
|
+
*/
|
|
699
|
+
function buildParamsRemap({ node }) {
|
|
700
|
+
if (!ast.isHttpOperationNode(node)) return [];
|
|
701
|
+
const original = getOperationParameters(node, { paramsCasing: "original" });
|
|
702
|
+
const cased = getOperationParameters(node);
|
|
703
|
+
const queryMapping = buildParamsMapping(original.query, cased.query);
|
|
704
|
+
const headerMapping = buildParamsMapping(original.header, cased.header);
|
|
705
|
+
const entries = [];
|
|
706
|
+
if (queryMapping) entries.push(`query: ${buildParamsRemapExpression({
|
|
707
|
+
source: "config.query",
|
|
708
|
+
mapping: queryMapping
|
|
709
|
+
})}`);
|
|
710
|
+
if (headerMapping) entries.push(`headers: ${buildParamsRemapExpression({
|
|
711
|
+
source: "config.headers",
|
|
712
|
+
mapping: headerMapping
|
|
713
|
+
})}`);
|
|
714
|
+
return entries;
|
|
715
|
+
}
|
|
716
|
+
//#endregion
|
|
665
717
|
//#region ../../internals/client/src/builders/generics.ts
|
|
666
718
|
/**
|
|
667
719
|
* Builds the `RequestResult` generic arguments for one operation: the plugin-ts per-status responses
|
|
@@ -672,7 +724,7 @@ function buildSecurityMetadata({ security }) {
|
|
|
672
724
|
* `buildRequestResultGenerics({ node, tsResolver }) // 'AddPetResponses, ThrowOnError'`
|
|
673
725
|
*/
|
|
674
726
|
function buildRequestResultGenerics({ node, tsResolver }) {
|
|
675
|
-
return `${tsResolver.
|
|
727
|
+
return `${tsResolver.response.responses(node)}, ThrowOnError`;
|
|
676
728
|
}
|
|
677
729
|
//#endregion
|
|
678
730
|
//#region ../../internals/client/src/builders/returnStatement.ts
|
|
@@ -695,41 +747,42 @@ function buildReturnStatement({ node, tsResolver, callConfig }) {
|
|
|
695
747
|
const declarationPrinter = functionPrinter({ mode: "declaration" });
|
|
696
748
|
/**
|
|
697
749
|
* Builds the grouped-options signature for one operation: a single `options` object whose `TData`
|
|
698
|
-
* is the plugin-ts `<Name>
|
|
750
|
+
* is the plugin-ts `<Name>Options` (carrying a literal `url`), and a `RequestResult` return type
|
|
699
751
|
* keyed to the plugin-ts per-status responses record. There are no positional arguments.
|
|
700
752
|
*
|
|
701
|
-
* The generated file imports `<Name>
|
|
753
|
+
* The generated file imports `<Name>Options` and `<Name>Responses` and uses them directly, so no
|
|
702
754
|
* per-operation input type has to be emitted.
|
|
703
755
|
*/
|
|
704
756
|
function buildGroupedOptionsSignature({ node, tsResolver }) {
|
|
705
|
-
const
|
|
706
|
-
const responsesName = tsResolver.
|
|
757
|
+
const optionsName = tsResolver.response.options(node);
|
|
758
|
+
const responsesName = tsResolver.response.responses(node);
|
|
707
759
|
const resultGenerics = buildRequestResultGenerics({
|
|
708
760
|
node,
|
|
709
761
|
tsResolver
|
|
710
762
|
});
|
|
711
763
|
const { isOptional } = getRequestGroupOptionality(node);
|
|
712
764
|
return {
|
|
713
|
-
dataTypeName:
|
|
765
|
+
dataTypeName: optionsName,
|
|
714
766
|
paramsSignature: declarationPrinter.print(createFunctionParameters({ params: [createFunctionParameter({
|
|
715
767
|
name: "options",
|
|
716
|
-
type: `Options<${
|
|
768
|
+
type: `Options<${optionsName}, ThrowOnError>`,
|
|
717
769
|
...isOptional ? { default: "{}" } : {}
|
|
718
770
|
})] })) ?? "",
|
|
719
771
|
returnType: `Promise<RequestResult<${resultGenerics}>>`,
|
|
720
772
|
generics: ["ThrowOnError extends boolean = true"],
|
|
721
|
-
importedTypeNames: [
|
|
773
|
+
importedTypeNames: [optionsName, responsesName]
|
|
722
774
|
};
|
|
723
775
|
}
|
|
724
776
|
//#endregion
|
|
725
777
|
//#region ../../internals/client/src/builders/styles.ts
|
|
726
778
|
/**
|
|
727
|
-
* Renders a parameter name as an object-literal key,
|
|
728
|
-
*
|
|
779
|
+
* Renders a parameter name as an object-literal key, quoted when it is not a bare identifier.
|
|
780
|
+
* Path keys are camelCased to match the URL template placeholders. Query, header, and cookie keys
|
|
781
|
+
* keep the spec name, matching the remapped keys the runtime serializes.
|
|
729
782
|
*/
|
|
730
|
-
function toKey(name) {
|
|
731
|
-
const
|
|
732
|
-
return isValidVarName(
|
|
783
|
+
function toKey(name, location) {
|
|
784
|
+
const key = location === "path" ? camelCase(name) : name;
|
|
785
|
+
return isValidVarName(key) ? key : JSON.stringify(key);
|
|
733
786
|
}
|
|
734
787
|
/**
|
|
735
788
|
* Serializes one parameter's metadata into a `{ style, explode }` literal, or `null` when the
|
|
@@ -743,8 +796,9 @@ function serializeParameter(parameter) {
|
|
|
743
796
|
return parts.length > 0 ? `{ ${parts.join(", ")} }` : null;
|
|
744
797
|
}
|
|
745
798
|
/**
|
|
746
|
-
* Builds the per-operation `styles` literal from the operation's parameters, grouped by location
|
|
747
|
-
* keyed by the camelCased
|
|
799
|
+
* Builds the per-operation `styles` literal from the operation's parameters, grouped by location.
|
|
800
|
+
* Path entries are keyed by the camelCased name to match the URL template placeholders; query,
|
|
801
|
+
* header, and cookie entries keep the spec name to match the keys the runtime serializes.
|
|
748
802
|
* Only parameters whose source defines `style` or `explode` are emitted, so calls without
|
|
749
803
|
* serialization metadata keep the runtime defaults and existing output is unchanged. Returns `null`
|
|
750
804
|
* when no parameter carries metadata.
|
|
@@ -766,7 +820,7 @@ function buildStyles({ node }) {
|
|
|
766
820
|
for (const parameter of node.parameters) {
|
|
767
821
|
const literal = serializeParameter(parameter);
|
|
768
822
|
if (!literal) continue;
|
|
769
|
-
groups[parameter.in].push(`${toKey(parameter.name)}: ${literal}`);
|
|
823
|
+
groups[parameter.in].push(`${toKey(parameter.name, parameter.in)}: ${literal}`);
|
|
770
824
|
}
|
|
771
825
|
const locations = Object.keys(groups).filter((location) => groups[location].length > 0);
|
|
772
826
|
if (locations.length === 0) return null;
|
|
@@ -782,7 +836,7 @@ function buildStyles({ node }) {
|
|
|
782
836
|
function buildValidatorHooks({ node, validator, zodResolver }) {
|
|
783
837
|
const importedZodNames = [];
|
|
784
838
|
const hasRequestBody = Boolean(node.requestBody?.content?.[0]?.schema);
|
|
785
|
-
const zodRequestName = zodResolver && resolveRequestValidator(validator) === "zod" && hasRequestBody ? zodResolver.
|
|
839
|
+
const zodRequestName = zodResolver && resolveRequestValidator(validator) === "zod" && hasRequestBody ? zodResolver.response.body(node) : null;
|
|
786
840
|
const request = zodRequestName ?? null;
|
|
787
841
|
if (zodRequestName) importedZodNames.push(zodRequestName);
|
|
788
842
|
const responseParse = zodResolver && resolveResponseValidator(validator) === "zod" ? buildZodResponseParse(node, zodResolver) : null;
|
|
@@ -839,9 +893,10 @@ function Operation({ name, node, tsResolver, zodResolver, validator, security, i
|
|
|
839
893
|
validatorLiteral,
|
|
840
894
|
contentTypeLiteral,
|
|
841
895
|
responseTypeLiteral,
|
|
842
|
-
"...config"
|
|
896
|
+
"...config",
|
|
897
|
+
...buildParamsRemap({ node })
|
|
843
898
|
].filter(Boolean).join(", ")} }`;
|
|
844
|
-
const eventType = `SuccessOf<${tsResolver.
|
|
899
|
+
const eventType = `SuccessOf<${tsResolver.response.responses(node)}>`;
|
|
845
900
|
const returnType = eventStream ? `Promise<EventStreamResult<${eventType}>>` : signature.returnType;
|
|
846
901
|
const returnStatement = eventStream ? `return toEventStream<${eventType}>(request(${callConfig}))` : buildReturnStatement({
|
|
847
902
|
node,
|
|
@@ -892,7 +947,8 @@ function buildCallConfig({ node, validator, zodResolver, security }) {
|
|
|
892
947
|
`url: '${Url.toCasedTemplate(node.path, { casing: "camelcase" })}'`,
|
|
893
948
|
securityLiteral ? `security: ${securityLiteral}` : null,
|
|
894
949
|
validatorLiteral,
|
|
895
|
-
"...config"
|
|
950
|
+
"...config",
|
|
951
|
+
...buildParamsRemap({ node })
|
|
896
952
|
].filter(Boolean).join(", ")} }`;
|
|
897
953
|
}
|
|
898
954
|
/**
|
|
@@ -918,7 +974,7 @@ function buildSdkMethod({ node, name, tsResolver, zodResolver, validator, securi
|
|
|
918
974
|
})
|
|
919
975
|
});
|
|
920
976
|
const generics = signature.generics.length ? `<${signature.generics.join(", ")}>` : "";
|
|
921
|
-
const jsdoc =
|
|
977
|
+
const jsdoc = buildJSDoc(buildOperationComments(node, {
|
|
922
978
|
link: "urlPath",
|
|
923
979
|
linkPosition: "beforeDeprecated",
|
|
924
980
|
splitLines: true
|
|
@@ -988,15 +1044,15 @@ function SdkFacade({ name, isExportable = true, isIndexable = true, members, chi
|
|
|
988
1044
|
//#endregion
|
|
989
1045
|
//#region ../../internals/client/src/generators/sdkGenerator.tsx
|
|
990
1046
|
function resolveTypeImportNames(node, tsResolver) {
|
|
991
|
-
return [tsResolver.
|
|
1047
|
+
return [tsResolver.response.options(node), tsResolver.response.responses(node)];
|
|
992
1048
|
}
|
|
993
1049
|
function resolveZodImportNames(node, zodResolver, validator) {
|
|
994
1050
|
const { query: queryParams } = getOperationParameters(node, { paramsCasing: "original" });
|
|
995
1051
|
return [
|
|
996
|
-
resolveResponseValidator(validator) === "zod" ? zodResolver.
|
|
1052
|
+
resolveResponseValidator(validator) === "zod" ? zodResolver.response.response(node) : null,
|
|
997
1053
|
resolveResponseValidator(validator) === "zod" ? buildZodErrorParse(node, zodResolver)?.expression ?? null : null,
|
|
998
|
-
resolveRequestValidator(validator) === "zod" && node.requestBody?.content?.[0]?.schema ? zodResolver.
|
|
999
|
-
resolveQueryParamsValidator(validator) === "zod" && queryParams.length > 0 ? zodResolver.
|
|
1054
|
+
resolveRequestValidator(validator) === "zod" && node.requestBody?.content?.[0]?.schema ? zodResolver.response.body(node) : null,
|
|
1055
|
+
resolveQueryParamsValidator(validator) === "zod" && queryParams.length > 0 ? zodResolver.param.query(node, queryParams[0]) : null
|
|
1000
1056
|
].filter((n) => Boolean(n));
|
|
1001
1057
|
}
|
|
1002
1058
|
/**
|
|
@@ -1013,12 +1069,14 @@ function buildControllers(nodes, ctx) {
|
|
|
1013
1069
|
const zodResolver = pluginZod ? driver.getResolver(pluginZodName) : null;
|
|
1014
1070
|
const document = ctx.adapter.document;
|
|
1015
1071
|
function buildOperationData(node) {
|
|
1016
|
-
const typeFile = tsResolver.
|
|
1072
|
+
const typeFile = tsResolver.file({
|
|
1073
|
+
...operationFileEntry(node, node.operationId),
|
|
1017
1074
|
root,
|
|
1018
1075
|
output: tsPluginOptions?.output ?? output,
|
|
1019
1076
|
group: tsPluginOptions?.group
|
|
1020
1077
|
});
|
|
1021
|
-
const zodFile = zodResolver && pluginZod?.options ? zodResolver.
|
|
1078
|
+
const zodFile = zodResolver && pluginZod?.options ? zodResolver.file({
|
|
1079
|
+
...operationFileEntry(node, node.operationId),
|
|
1022
1080
|
root,
|
|
1023
1081
|
output: pluginZod.options?.output ?? output,
|
|
1024
1082
|
group: pluginZod.options?.group ?? void 0
|
|
@@ -1030,7 +1088,7 @@ function buildControllers(nodes, ctx) {
|
|
|
1030
1088
|
}) : void 0;
|
|
1031
1089
|
return {
|
|
1032
1090
|
node,
|
|
1033
|
-
name: resolver.
|
|
1091
|
+
name: resolver.name(node.operationId),
|
|
1034
1092
|
tsResolver,
|
|
1035
1093
|
zodResolver,
|
|
1036
1094
|
typeFile,
|
|
@@ -1041,12 +1099,11 @@ function buildControllers(nodes, ctx) {
|
|
|
1041
1099
|
return nodes.reduce((acc, operationNode) => {
|
|
1042
1100
|
if (!ast.isHttpOperationNode(operationNode)) return acc;
|
|
1043
1101
|
const tag = operationNode.tags[0];
|
|
1044
|
-
const name = tag ? group?.name?.({ group: camelCase(tag) }) ?? resolver.
|
|
1045
|
-
const file = resolver.
|
|
1102
|
+
const name = tag ? group?.name?.({ group: camelCase(tag) }) ?? resolver.groupName(tag) : resolver.className("ApiClient");
|
|
1103
|
+
const file = resolver.file({
|
|
1046
1104
|
name,
|
|
1047
1105
|
extname: ".ts",
|
|
1048
|
-
tag
|
|
1049
|
-
}, {
|
|
1106
|
+
tag,
|
|
1050
1107
|
root,
|
|
1051
1108
|
output,
|
|
1052
1109
|
group: group ?? void 0
|
|
@@ -1100,7 +1157,7 @@ function createSdkGenerator() {
|
|
|
1100
1157
|
if (!ctx.driver.getPlugin(pluginTsName) || !sdk) return null;
|
|
1101
1158
|
const controllers = buildControllers(nodes, ctx);
|
|
1102
1159
|
const clientPath = path.resolve(root, ".kubb/client.ts");
|
|
1103
|
-
const banner = (file) => resolver.
|
|
1160
|
+
const banner = (file) => resolver.default.banner(ctx.meta, {
|
|
1104
1161
|
output,
|
|
1105
1162
|
config,
|
|
1106
1163
|
file: {
|
|
@@ -1108,7 +1165,7 @@ function createSdkGenerator() {
|
|
|
1108
1165
|
baseName: file.baseName
|
|
1109
1166
|
}
|
|
1110
1167
|
});
|
|
1111
|
-
const footer = (file) => resolver.
|
|
1168
|
+
const footer = (file) => resolver.default.footer(ctx.meta, {
|
|
1112
1169
|
output,
|
|
1113
1170
|
config,
|
|
1114
1171
|
file: {
|
|
@@ -1175,28 +1232,26 @@ function createSdkGenerator() {
|
|
|
1175
1232
|
]
|
|
1176
1233
|
}, file.path);
|
|
1177
1234
|
};
|
|
1178
|
-
if (sdk.mode === "flat") return renderClassFile(resolver.
|
|
1235
|
+
if (sdk.mode === "flat") return renderClassFile(resolver.className(sdk.name ?? "sdk"), resolver.file({
|
|
1179
1236
|
name: sdk.name ?? "sdk",
|
|
1180
|
-
extname: ".ts"
|
|
1181
|
-
}, {
|
|
1237
|
+
extname: ".ts",
|
|
1182
1238
|
root,
|
|
1183
1239
|
output,
|
|
1184
1240
|
group: group ?? void 0
|
|
1185
1241
|
}), controllers.flatMap((controller) => controller.operations));
|
|
1186
1242
|
const classFiles = controllers.map(({ name, file, operations: ops }) => renderClassFile(name, file, ops));
|
|
1187
1243
|
if (!sdk.name) return /* @__PURE__ */ jsx(Fragment, { children: classFiles });
|
|
1188
|
-
const sdkFile = resolver.
|
|
1244
|
+
const sdkFile = resolver.file({
|
|
1189
1245
|
name: sdk.name,
|
|
1190
|
-
extname: ".ts"
|
|
1191
|
-
}, {
|
|
1246
|
+
extname: ".ts",
|
|
1192
1247
|
root,
|
|
1193
1248
|
output,
|
|
1194
1249
|
group: group ?? void 0
|
|
1195
1250
|
});
|
|
1196
|
-
const facadeName = resolver.
|
|
1251
|
+
const facadeName = resolver.className(sdk.name);
|
|
1197
1252
|
const members = controllers.map(({ name, tag }) => ({
|
|
1198
1253
|
className: name,
|
|
1199
|
-
propName: resolver.
|
|
1254
|
+
propName: resolver.propertyName(tag ?? name)
|
|
1200
1255
|
}));
|
|
1201
1256
|
return /* @__PURE__ */ jsxs(Fragment, { children: [classFiles, /* @__PURE__ */ jsxs(File, {
|
|
1202
1257
|
baseName: sdkFile.baseName,
|
|
@@ -1236,38 +1291,27 @@ const defaultMacros = [ast.macroSimplifyUnion];
|
|
|
1236
1291
|
//#endregion
|
|
1237
1292
|
//#region ../../internals/client/src/resolver.ts
|
|
1238
1293
|
/**
|
|
1239
|
-
* Default resolver shared by the client plugins. Functions and files
|
|
1240
|
-
* tag groups use PascalCase.
|
|
1294
|
+
* Default resolver shared by the client plugins. Functions and files inherit the built-in camelCase
|
|
1295
|
+
* `name` and `file`; classes and tag groups use PascalCase.
|
|
1241
1296
|
*
|
|
1242
1297
|
* @example
|
|
1243
1298
|
* ```ts
|
|
1244
|
-
* resolverClient.
|
|
1245
|
-
* resolverClient.
|
|
1299
|
+
* resolverClient.name('show pet by id') // 'showPetById'
|
|
1300
|
+
* resolverClient.groupName('pet') // 'PetClient'
|
|
1246
1301
|
* ```
|
|
1247
1302
|
*/
|
|
1248
|
-
const resolverClient =
|
|
1249
|
-
name: "default",
|
|
1303
|
+
const resolverClient = createResolver({
|
|
1250
1304
|
pluginName: "plugin-contract-client",
|
|
1251
|
-
|
|
1252
|
-
if (type === "file") return toFilePath(name);
|
|
1253
|
-
return ensureValidVarName(camelCase(name));
|
|
1254
|
-
},
|
|
1255
|
-
resolveName(name) {
|
|
1256
|
-
return this.default(name, "function");
|
|
1257
|
-
},
|
|
1258
|
-
resolvePathName(name, type) {
|
|
1259
|
-
return this.default(name, type);
|
|
1260
|
-
},
|
|
1261
|
-
resolveClassName(name) {
|
|
1305
|
+
className(name) {
|
|
1262
1306
|
return ensureValidVarName(pascalCase(name));
|
|
1263
1307
|
},
|
|
1264
|
-
|
|
1308
|
+
groupName(name) {
|
|
1265
1309
|
return ensureValidVarName(pascalCase(`${name} Client`));
|
|
1266
1310
|
},
|
|
1267
|
-
|
|
1311
|
+
propertyName(name) {
|
|
1268
1312
|
return ensureValidVarName(camelCase(name));
|
|
1269
1313
|
}
|
|
1270
|
-
})
|
|
1314
|
+
});
|
|
1271
1315
|
//#endregion
|
|
1272
1316
|
//#region src/generators/clientGenerator.tsx
|
|
1273
1317
|
/**
|
|
@@ -1288,25 +1332,28 @@ const clientGenerator = defineGenerator({
|
|
|
1288
1332
|
const pluginZod = resolveResponseValidator(validator) === "zod" || resolveRequestValidator(validator) === "zod" ? driver.getPlugin(pluginZodName) : null;
|
|
1289
1333
|
const zodResolver = pluginZod ? driver.getResolver(pluginZodName) : null;
|
|
1290
1334
|
const hasRequestBody = Boolean(node.requestBody?.content?.[0]?.schema);
|
|
1291
|
-
const importedTypeNames = [tsResolver.
|
|
1335
|
+
const importedTypeNames = [tsResolver.response.options(node), tsResolver.response.responses(node)];
|
|
1292
1336
|
const importedZodNames = zodResolver ? [
|
|
1293
|
-
resolveResponseValidator(validator) === "zod" ? zodResolver.
|
|
1337
|
+
resolveResponseValidator(validator) === "zod" ? zodResolver.response.response?.(node) : null,
|
|
1294
1338
|
resolveResponseValidator(validator) === "zod" ? buildZodErrorParse(node, zodResolver)?.expression ?? null : null,
|
|
1295
|
-
resolveRequestValidator(validator) === "zod" && hasRequestBody ? zodResolver.
|
|
1339
|
+
resolveRequestValidator(validator) === "zod" && hasRequestBody ? zodResolver.response.body?.(node) : null
|
|
1296
1340
|
].filter((name) => Boolean(name)) : [];
|
|
1297
1341
|
const meta = {
|
|
1298
|
-
name: resolver.
|
|
1299
|
-
file: resolver.
|
|
1342
|
+
name: resolver.name(node.operationId),
|
|
1343
|
+
file: resolver.file({
|
|
1344
|
+
...operationFileEntry(node, node.operationId),
|
|
1300
1345
|
root,
|
|
1301
1346
|
output,
|
|
1302
1347
|
group: group ?? void 0
|
|
1303
1348
|
}),
|
|
1304
|
-
fileTs: tsResolver.
|
|
1349
|
+
fileTs: tsResolver.file({
|
|
1350
|
+
...operationFileEntry(node, node.operationId),
|
|
1305
1351
|
root,
|
|
1306
1352
|
output: pluginTs.options?.output ?? output,
|
|
1307
1353
|
group: pluginTs.options?.group ?? void 0
|
|
1308
1354
|
}),
|
|
1309
|
-
fileZod: zodResolver && pluginZod?.options ? zodResolver.
|
|
1355
|
+
fileZod: zodResolver && pluginZod?.options ? zodResolver.file({
|
|
1356
|
+
...operationFileEntry(node, node.operationId),
|
|
1310
1357
|
root,
|
|
1311
1358
|
output: pluginZod.options.output ?? output,
|
|
1312
1359
|
group: pluginZod.options?.group ?? void 0
|
|
@@ -1323,7 +1370,7 @@ const clientGenerator = defineGenerator({
|
|
|
1323
1370
|
baseName: meta.file.baseName,
|
|
1324
1371
|
path: meta.file.path,
|
|
1325
1372
|
meta: meta.file.meta,
|
|
1326
|
-
banner: resolver.
|
|
1373
|
+
banner: resolver.default.banner(ctx.meta, {
|
|
1327
1374
|
output,
|
|
1328
1375
|
config,
|
|
1329
1376
|
file: {
|
|
@@ -1331,7 +1378,7 @@ const clientGenerator = defineGenerator({
|
|
|
1331
1378
|
baseName: meta.file.baseName
|
|
1332
1379
|
}
|
|
1333
1380
|
}),
|
|
1334
|
-
footer: resolver.
|
|
1381
|
+
footer: resolver.default.footer(ctx.meta, {
|
|
1335
1382
|
output,
|
|
1336
1383
|
config,
|
|
1337
1384
|
file: {
|
|
@@ -1435,10 +1482,7 @@ const pluginFetch = definePlugin((options) => {
|
|
|
1435
1482
|
mode: sdk.mode ?? "tag",
|
|
1436
1483
|
name: sdk.name
|
|
1437
1484
|
} : void 0,
|
|
1438
|
-
resolver: userResolver ?
|
|
1439
|
-
...resolverClient,
|
|
1440
|
-
...userResolver
|
|
1441
|
-
} : resolverClient
|
|
1485
|
+
resolver: userResolver ? Resolver.merge(resolverClient, userResolver) : resolverClient
|
|
1442
1486
|
};
|
|
1443
1487
|
const selectedGenerators = resolved.sdk ? [createSdkGenerator()] : [clientGenerator];
|
|
1444
1488
|
return {
|