@kubb/plugin-client 5.0.0-beta.4 → 5.0.0-beta.56
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 +39 -24
- package/dist/clients/axios.cjs +26 -4
- package/dist/clients/axios.cjs.map +1 -1
- package/dist/clients/axios.d.ts +11 -5
- package/dist/clients/axios.js +26 -4
- package/dist/clients/axios.js.map +1 -1
- package/dist/clients/fetch.cjs +77 -9
- package/dist/clients/fetch.cjs.map +1 -1
- package/dist/clients/fetch.d.ts +10 -3
- package/dist/clients/fetch.js +77 -9
- package/dist/clients/fetch.js.map +1 -1
- package/dist/index.cjs +836 -514
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +206 -105
- package/dist/index.js +833 -515
- package/dist/index.js.map +1 -1
- package/dist/templates/clients/axios.source.cjs +1 -1
- package/dist/templates/clients/axios.source.cjs.map +1 -1
- package/dist/templates/clients/axios.source.d.ts +1 -1
- package/dist/templates/clients/axios.source.js +1 -1
- package/dist/templates/clients/axios.source.js.map +1 -1
- package/dist/templates/clients/fetch.source.cjs +1 -1
- package/dist/templates/clients/fetch.source.cjs.map +1 -1
- package/dist/templates/clients/fetch.source.d.ts +1 -1
- package/dist/templates/clients/fetch.source.js +1 -1
- package/dist/templates/clients/fetch.source.js.map +1 -1
- package/dist/templates/config.source.cjs.map +1 -1
- package/dist/templates/config.source.d.ts +1 -1
- package/dist/templates/config.source.js.map +1 -1
- package/package.json +14 -26
- package/src/clients/axios.ts +41 -7
- package/src/clients/fetch.ts +106 -6
- package/src/components/ClassClient.tsx +47 -24
- package/src/components/Client.tsx +100 -71
- package/src/components/StaticClassClient.tsx +47 -24
- package/src/components/Url.tsx +10 -12
- package/src/components/WrapperClient.tsx +9 -5
- package/src/functionParams.ts +8 -8
- package/src/generators/classClientGenerator.tsx +63 -51
- package/src/generators/clientGenerator.tsx +45 -48
- package/src/generators/groupedClientGenerator.tsx +12 -6
- package/src/generators/operationsGenerator.ts +47 -0
- package/src/generators/staticClassClientGenerator.tsx +57 -45
- package/src/index.ts +2 -1
- package/src/plugin.ts +30 -28
- package/src/resolvers/resolverClient.ts +32 -8
- package/src/types.ts +111 -65
- package/src/utils.ts +142 -63
- package/extension.yaml +0 -776
- package/src/components/Operations.tsx +0 -28
- package/src/generators/operationsGenerator.tsx +0 -28
- package/templates/clients/axios.ts +0 -73
- package/templates/clients/fetch.ts +0 -96
- package/templates/config.ts +0 -43
- /package/dist/{chunk-ByKO4r7w.cjs → chunk-Bx3C2hgW.cjs} +0 -0
- /package/dist/{chunk--u3MIqq1.js → chunk-C0LytTxp.js} +0 -0
package/src/types.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ast, Exclude, Generator, Group, Include, Output, Override, PluginFactoryOptions, Resolver } from '@kubb/core'
|
|
1
|
+
import type { ast, Exclude, Generator, Group, Include, Output, OutputOptions, Override, PluginFactoryOptions, Resolver } from '@kubb/core'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* The concrete resolver type for `@kubb/plugin-client`.
|
|
@@ -7,10 +7,39 @@ import type { ast, Exclude, Generator, Group, Include, Output, Override, PluginF
|
|
|
7
7
|
export type ResolverClient = Resolver & {
|
|
8
8
|
/**
|
|
9
9
|
* Resolves the function name for a given raw operation name.
|
|
10
|
+
*
|
|
10
11
|
* @example Resolving operation names
|
|
11
12
|
* `resolver.resolveName('show pet by id') // -> 'showPetById'`
|
|
12
13
|
*/
|
|
13
14
|
resolveName(this: ResolverClient, name: string): string
|
|
15
|
+
/**
|
|
16
|
+
* Resolves the output file name for a client module.
|
|
17
|
+
*/
|
|
18
|
+
resolvePathName(this: ResolverClient, name: string, type?: 'file' | 'function' | 'type' | 'const'): string
|
|
19
|
+
/**
|
|
20
|
+
* Resolves the generated class name for class-based clients.
|
|
21
|
+
*/
|
|
22
|
+
resolveClassName(this: ResolverClient, name: string): string
|
|
23
|
+
/**
|
|
24
|
+
* Resolves the generated class name for tag-based client groups. The default
|
|
25
|
+
* appends a `Client` suffix (tag `pet` becomes `PetClient`) so the class never
|
|
26
|
+
* collides with the schema model of the same name in the barrel.
|
|
27
|
+
*
|
|
28
|
+
* @example Resolving tag-group class names
|
|
29
|
+
* `resolver.resolveGroupName('pet') // -> 'PetClient'`
|
|
30
|
+
*/
|
|
31
|
+
resolveGroupName(this: ResolverClient, name: string): string
|
|
32
|
+
/**
|
|
33
|
+
* Resolves the generated SDK facade property name for a client class.
|
|
34
|
+
*/
|
|
35
|
+
resolveClientPropertyName(this: ResolverClient, name: string): string
|
|
36
|
+
/**
|
|
37
|
+
* Resolves the URL helper function name for an operation.
|
|
38
|
+
*
|
|
39
|
+
* @example Resolving URL helper names
|
|
40
|
+
* `resolver.resolveUrlName(node) // -> 'getShowPetByIdUrl'`
|
|
41
|
+
*/
|
|
42
|
+
resolveUrlName(this: ResolverClient, node: ast.OperationNode): string
|
|
14
43
|
}
|
|
15
44
|
|
|
16
45
|
/**
|
|
@@ -22,9 +51,10 @@ export type ResolverClient = Resolver & {
|
|
|
22
51
|
export type ClientImportPath =
|
|
23
52
|
| {
|
|
24
53
|
/**
|
|
25
|
-
*
|
|
26
|
-
* - 'axios'
|
|
27
|
-
* - 'fetch'
|
|
54
|
+
* HTTP client used by the generated code.
|
|
55
|
+
* - `'axios'` — imports from `@kubb/plugin-client/clients/axios`. Requires `axios` at runtime.
|
|
56
|
+
* - `'fetch'` — imports from `@kubb/plugin-client/clients/fetch`. Uses the global `fetch`.
|
|
57
|
+
*
|
|
28
58
|
* @default 'axios'
|
|
29
59
|
*/
|
|
30
60
|
client?: 'axios' | 'fetch'
|
|
@@ -33,9 +63,12 @@ export type ClientImportPath =
|
|
|
33
63
|
| {
|
|
34
64
|
client?: never
|
|
35
65
|
/**
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
66
|
+
* Path to a custom client module. Generated files import their HTTP runtime from here
|
|
67
|
+
* instead of `@kubb/plugin-client/clients/{client}`. Accepts both relative paths and
|
|
68
|
+
* bare module specifiers; the value is used as-is.
|
|
69
|
+
*
|
|
70
|
+
* @note When combined with a query plugin, the module must export `Client`,
|
|
71
|
+
* `RequestConfig`, and `ResponseErrorConfig` types.
|
|
39
72
|
*/
|
|
40
73
|
importPath: string
|
|
41
74
|
/**
|
|
@@ -57,142 +90,155 @@ export type ClientImportPath =
|
|
|
57
90
|
type ParamsTypeOptions =
|
|
58
91
|
| {
|
|
59
92
|
/**
|
|
60
|
-
*
|
|
93
|
+
* Every operation parameter (path, query, headers, body) is wrapped in a single
|
|
61
94
|
* destructured object argument.
|
|
62
|
-
* - 'object' returns the params and pathParams as an object.
|
|
63
|
-
* @default 'inline'
|
|
64
95
|
*/
|
|
65
96
|
paramsType: 'object'
|
|
66
97
|
/**
|
|
67
98
|
* `pathParamsType` has no effect when `paramsType` is `'object'`.
|
|
68
|
-
* Path params
|
|
99
|
+
* Path params already live inside the single destructured object.
|
|
69
100
|
*/
|
|
70
101
|
pathParamsType?: never
|
|
71
102
|
}
|
|
72
103
|
| {
|
|
73
104
|
/**
|
|
74
|
-
* Each parameter group is emitted as a separate function argument.
|
|
75
|
-
*
|
|
105
|
+
* Each parameter group is emitted as a separate positional function argument.
|
|
106
|
+
*
|
|
76
107
|
* @default 'inline'
|
|
77
108
|
*/
|
|
78
109
|
paramsType?: 'inline'
|
|
79
110
|
/**
|
|
80
|
-
*
|
|
81
|
-
* - 'object' groups
|
|
82
|
-
* - 'inline' emits each path param as its own argument: `petId: string`.
|
|
111
|
+
* How URL path parameters are arranged inside the inline argument list.
|
|
112
|
+
* - `'object'` groups them into one destructured object: `{ petId }: PathParams`.
|
|
113
|
+
* - `'inline'` emits each path param as its own argument: `petId: string`.
|
|
114
|
+
*
|
|
83
115
|
* @default 'inline'
|
|
84
116
|
*/
|
|
85
117
|
pathParamsType?: 'object' | 'inline'
|
|
86
118
|
}
|
|
87
119
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
* Group the clients based on the provided name.
|
|
96
|
-
*/
|
|
97
|
-
group?: Group
|
|
120
|
+
/**
|
|
121
|
+
* Where the generated client files are written and how they are exported, plus the optional
|
|
122
|
+
* `group` strategy. The `group` option organizes `output.mode: 'directory'` output into per-tag or per-path subdirectories.
|
|
123
|
+
*
|
|
124
|
+
* @default { path: 'clients', barrel: { type: 'named' } }
|
|
125
|
+
*/
|
|
126
|
+
export type Options = OutputOptions & {
|
|
98
127
|
/**
|
|
99
|
-
*
|
|
128
|
+
* Skip operations matching at least one entry in the list.
|
|
100
129
|
*/
|
|
101
130
|
exclude?: Array<Exclude>
|
|
102
131
|
/**
|
|
103
|
-
*
|
|
132
|
+
* Restrict generation to operations matching at least one entry in the list.
|
|
104
133
|
*/
|
|
105
134
|
include?: Array<Include>
|
|
106
135
|
/**
|
|
107
|
-
*
|
|
136
|
+
* Apply a different options object to operations matching a pattern.
|
|
108
137
|
*/
|
|
109
138
|
override?: Array<Override<ResolvedOptions>>
|
|
110
139
|
/**
|
|
111
|
-
*
|
|
140
|
+
* Emit an `operations.ts` file that re-exports every generated function grouped by HTTP method.
|
|
141
|
+
*
|
|
112
142
|
* @default false
|
|
113
143
|
*/
|
|
114
144
|
operations?: boolean
|
|
115
145
|
/**
|
|
116
|
-
*
|
|
117
|
-
* - 'export'
|
|
118
|
-
* - false
|
|
146
|
+
* Whether to also export the URL builder helpers (`get<Operation>Url`).
|
|
147
|
+
* - `'export'` exposes them via the barrel.
|
|
148
|
+
* - `false` keeps them private.
|
|
149
|
+
*
|
|
119
150
|
* @default false
|
|
120
|
-
* @example getGetPetByIdUrl
|
|
121
151
|
*/
|
|
122
152
|
urlType?: 'export' | false
|
|
123
153
|
/**
|
|
124
|
-
*
|
|
154
|
+
* Base URL prepended to every request. When omitted, falls back to the adapter's
|
|
155
|
+
* server URL (typically `servers[0].url`).
|
|
125
156
|
*/
|
|
126
157
|
baseURL?: string
|
|
127
158
|
/**
|
|
128
|
-
*
|
|
129
|
-
* - 'data'
|
|
130
|
-
* - 'full'
|
|
159
|
+
* Shape of the value returned by each generated client function.
|
|
160
|
+
* - `'data'` — only the response body.
|
|
161
|
+
* - `'full'` — the full response as a discriminated union keyed by HTTP status code.
|
|
162
|
+
* Each member is `{ status: N; data: StatusNType; statusText: string }`,
|
|
163
|
+
* so narrowing on `res.status` also narrows `res.data` to the matching response type.
|
|
164
|
+
*
|
|
131
165
|
* @default 'data'
|
|
132
166
|
*/
|
|
133
167
|
dataReturnType?: 'data' | 'full'
|
|
134
168
|
/**
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
169
|
+
* Rename parameter properties in the generated client (path, query, headers).
|
|
170
|
+
* The HTTP request still uses the original spec names; Kubb writes the mapping for you.
|
|
171
|
+
*
|
|
172
|
+
* @note Use the same value on `@kubb/plugin-ts` so types stay compatible.
|
|
138
173
|
*/
|
|
139
174
|
paramsCasing?: 'camelcase'
|
|
140
175
|
/**
|
|
141
|
-
*
|
|
142
|
-
* -
|
|
143
|
-
* - 'zod'
|
|
144
|
-
*
|
|
176
|
+
* Validator applied to request and response bodies using schemas from `@kubb/plugin-zod`.
|
|
177
|
+
* - `false` (default): no validation. The response is returned as-is.
|
|
178
|
+
* - `'zod'`: validates response bodies only (backward-compatible shorthand).
|
|
179
|
+
* - `{ request?: 'zod'; response?: 'zod' }`: opt in per direction. `request` validates the
|
|
180
|
+
* request body and query parameters before the call. `response` validates the response body.
|
|
181
|
+
*
|
|
182
|
+
* @default false
|
|
183
|
+
* @example Response only (shorthand)
|
|
184
|
+
* `parser: 'zod'`
|
|
185
|
+
* @example Both directions
|
|
186
|
+
* `parser: { request: 'zod', response: 'zod' }`
|
|
145
187
|
*/
|
|
146
|
-
parser?: '
|
|
188
|
+
parser?: false | 'zod' | { request?: 'zod'; response?: 'zod' }
|
|
147
189
|
/**
|
|
148
|
-
*
|
|
149
|
-
* - 'function'
|
|
150
|
-
* - 'class'
|
|
151
|
-
* - 'staticClass'
|
|
190
|
+
* Shape of the generated client.
|
|
191
|
+
* - `'function'` — one standalone async function per operation.
|
|
192
|
+
* - `'class'` — one class per tag with instance methods.
|
|
193
|
+
* - `'staticClass'` — one class per tag with static methods.
|
|
194
|
+
*
|
|
152
195
|
* @default 'function'
|
|
196
|
+
* @note Only `'function'` is compatible with query plugins.
|
|
153
197
|
*/
|
|
154
198
|
clientType?: 'function' | 'class' | 'staticClass'
|
|
155
199
|
/**
|
|
156
|
-
*
|
|
157
|
-
* When
|
|
200
|
+
* Copy the HTTP client runtime into the generated output so consumers do not need
|
|
201
|
+
* `@kubb/plugin-client` at runtime. When `false`, generated files import from
|
|
202
|
+
* `@kubb/plugin-client/clients/{client}`.
|
|
203
|
+
*
|
|
158
204
|
* @default false
|
|
159
|
-
* In version 5 of Kubb this is by default true
|
|
160
205
|
*/
|
|
161
206
|
bundle?: boolean
|
|
162
207
|
/**
|
|
163
|
-
* Generate
|
|
164
|
-
*
|
|
208
|
+
* Generate a single SDK class composing every tag-based client into one entry point.
|
|
209
|
+
* Automatically enables `clientType: 'class'`.
|
|
210
|
+
*
|
|
165
211
|
* @example
|
|
166
212
|
* ```ts
|
|
167
213
|
* pluginClient({
|
|
168
214
|
* sdk: { className: 'PetStoreSDK' },
|
|
169
215
|
* })
|
|
170
|
-
* // Generates a class with a shared constructor config and one property per tag:
|
|
171
216
|
* // class PetStoreSDK {
|
|
172
|
-
* // readonly
|
|
173
|
-
* // readonly
|
|
217
|
+
* // readonly petClient: PetClient
|
|
218
|
+
* // readonly storeClient: StoreClient
|
|
174
219
|
* // constructor(config = {}) { ... }
|
|
175
220
|
* // }
|
|
176
221
|
* ```
|
|
177
222
|
*/
|
|
178
223
|
sdk?: {
|
|
179
224
|
/**
|
|
180
|
-
* Name of the generated SDK facade class.
|
|
225
|
+
* Name of the generated SDK facade class. Also the file name.
|
|
181
226
|
*/
|
|
182
227
|
className: string
|
|
183
228
|
}
|
|
184
229
|
/**
|
|
185
|
-
* Override
|
|
186
|
-
*
|
|
230
|
+
* Override how names and file paths are built for the generated client.
|
|
231
|
+
* Methods you omit fall back to the default resolver. `this` is bound to the
|
|
232
|
+
* full resolver, so `this.default(name)` delegates to the built-in implementation.
|
|
187
233
|
*/
|
|
188
234
|
resolver?: Partial<ResolverClient> & ThisType<ResolverClient>
|
|
189
235
|
/**
|
|
190
|
-
*
|
|
191
|
-
* Return `null` or `undefined`
|
|
236
|
+
* AST visitor applied to each operation node before code is printed.
|
|
237
|
+
* Return `null` or `undefined` to leave the node unchanged.
|
|
192
238
|
*/
|
|
193
239
|
transformer?: ast.Visitor
|
|
194
240
|
/**
|
|
195
|
-
*
|
|
241
|
+
* Custom generators that run alongside the built-in client generators.
|
|
196
242
|
*/
|
|
197
243
|
generators?: Array<Generator<PluginClient>>
|
|
198
244
|
} & ClientImportPath &
|
|
@@ -203,7 +249,7 @@ type ResolvedOptions = {
|
|
|
203
249
|
exclude: Array<Exclude>
|
|
204
250
|
include: Array<Include> | undefined
|
|
205
251
|
override: Array<Override<ResolvedOptions>>
|
|
206
|
-
group: Group |
|
|
252
|
+
group: Group | null
|
|
207
253
|
client: Options['client']
|
|
208
254
|
clientType: NonNullable<Options['clientType']>
|
|
209
255
|
bundle: NonNullable<Options['bundle']>
|
package/src/utils.ts
CHANGED
|
@@ -1,64 +1,101 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import { buildStatusUnionType, getOperationParameters, getResponseType, resolveSuccessNames } from '@internals/shared'
|
|
2
|
+
import { ast } from '@kubb/core'
|
|
3
3
|
import type { ResolverTs } from '@kubb/plugin-ts'
|
|
4
4
|
import type { ResolverZod } from '@kubb/plugin-zod'
|
|
5
5
|
import { createFunctionParams } from './functionParams.ts'
|
|
6
6
|
import type { PluginClient } from './types.ts'
|
|
7
7
|
|
|
8
|
+
type ParserOption = PluginClient['resolvedOptions']['parser']
|
|
9
|
+
|
|
8
10
|
/**
|
|
9
|
-
*
|
|
10
|
-
* Includes description, summary, link, and deprecation information.
|
|
11
|
+
* Returns `true` when any direction of the parser uses Zod (used for dependency checks).
|
|
11
12
|
*/
|
|
12
|
-
export function
|
|
13
|
-
return
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
node.path && `{@link ${new URLPath(node.path).URL}}`,
|
|
17
|
-
node.deprecated && '@deprecated',
|
|
18
|
-
]
|
|
19
|
-
.filter((x): x is string => Boolean(x))
|
|
20
|
-
.flatMap((text) => text.split(/\r?\n/).map((line) => line.trim()))
|
|
21
|
-
.filter((x): x is string => Boolean(x))
|
|
13
|
+
export function isParserEnabled(parser: ParserOption | undefined | false): boolean {
|
|
14
|
+
if (!parser) return false
|
|
15
|
+
if (parser === 'zod') return true
|
|
16
|
+
return !!(parser.request || parser.response)
|
|
22
17
|
}
|
|
23
18
|
|
|
24
19
|
/**
|
|
25
|
-
*
|
|
26
|
-
*
|
|
20
|
+
* Returns `'zod'` when request body parsing is enabled, `null` otherwise.
|
|
21
|
+
* The string shorthand `'zod'` also enables request body parsing (existing behavior).
|
|
27
22
|
*/
|
|
28
|
-
export function
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
23
|
+
export function resolveRequestParser(parser: ParserOption | undefined | false): 'zod' | null {
|
|
24
|
+
if (!parser) return null
|
|
25
|
+
if (parser === 'zod') return 'zod'
|
|
26
|
+
return parser.request ?? null
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Returns `'zod'` when query-parameters parsing is enabled, `null` otherwise.
|
|
31
|
+
* Only the object form `{ request: 'zod' }` enables query-params parsing.
|
|
32
|
+
* The string shorthand `'zod'` does not, preserving its existing behavior.
|
|
33
|
+
*/
|
|
34
|
+
export function resolveQueryParamsParser(parser: ParserOption | undefined | false): 'zod' | null {
|
|
35
|
+
if (!parser || parser === 'zod') return null
|
|
36
|
+
return parser.request ?? null
|
|
39
37
|
}
|
|
40
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Returns `'zod'` when response-direction parsing is enabled, `null` otherwise.
|
|
41
|
+
* `parser: 'zod'` (string shorthand) maps to response parsing and returns `'zod'`.
|
|
42
|
+
*/
|
|
43
|
+
export function resolveResponseParser(parser: ParserOption | undefined | false): 'zod' | null {
|
|
44
|
+
if (!parser) return null
|
|
45
|
+
if (parser === 'zod') return 'zod'
|
|
46
|
+
return parser.response ?? null
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export { buildStatusUnionType }
|
|
50
|
+
|
|
41
51
|
/**
|
|
42
52
|
* Builds HTTP headers array for a client request.
|
|
43
53
|
* Includes Content-Type (if not default) and spreads header parameters if present.
|
|
44
54
|
*/
|
|
45
55
|
export function buildHeaders(contentType: string, hasHeaderParams: boolean): Array<string> {
|
|
46
56
|
return [
|
|
47
|
-
contentType !== 'application/json' && contentType !== 'multipart/form-data' ? `'Content-Type': '${contentType}'` :
|
|
48
|
-
hasHeaderParams ? '...headers' :
|
|
57
|
+
contentType !== 'application/json' && contentType !== 'multipart/form-data' ? `'Content-Type': '${contentType}'` : null,
|
|
58
|
+
hasHeaderParams ? '...headers' : null,
|
|
49
59
|
].filter(Boolean) as Array<string>
|
|
50
60
|
}
|
|
51
61
|
|
|
52
62
|
/**
|
|
53
|
-
*
|
|
54
|
-
*
|
|
63
|
+
* Returns the generic type arguments — response, error, and request body — for a generated
|
|
64
|
+
* client call.
|
|
65
|
+
*
|
|
66
|
+
* When `dataReturnType` is `'full'`, the response generic widens to a union of all documented
|
|
67
|
+
* status types. When `parser` is `'zod'` and a request body schema exists, the request type
|
|
68
|
+
* uses `z.output<typeof schema>` to reflect post-transform types (e.g. date coercion).
|
|
55
69
|
*/
|
|
56
|
-
export function buildGenerics(
|
|
57
|
-
|
|
58
|
-
|
|
70
|
+
export function buildGenerics(
|
|
71
|
+
node: ast.OperationNode,
|
|
72
|
+
tsResolver: ResolverTs,
|
|
73
|
+
options: {
|
|
74
|
+
dataReturnType?: PluginClient['resolvedOptions']['dataReturnType']
|
|
75
|
+
zodResolver?: ResolverZod | null
|
|
76
|
+
parser?: PluginClient['resolvedOptions']['parser']
|
|
77
|
+
} = {},
|
|
78
|
+
): Array<string> {
|
|
79
|
+
const allStatusNames = node.responses.map((r) => tsResolver.resolveResponseStatusName(node, r.statusCode))
|
|
80
|
+
const successNames = resolveSuccessNames(node, tsResolver)
|
|
81
|
+
const responseName =
|
|
82
|
+
options.dataReturnType === 'full'
|
|
83
|
+
? allStatusNames.length > 0
|
|
84
|
+
? allStatusNames.join(' | ')
|
|
85
|
+
: tsResolver.resolveResponseName(node)
|
|
86
|
+
: successNames.length > 0
|
|
87
|
+
? successNames.join(' | ')
|
|
88
|
+
: tsResolver.resolveResponseName(node)
|
|
89
|
+
const requestName = node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : null
|
|
59
90
|
const errorNames = node.responses.filter((r) => Number.parseInt(r.statusCode, 10) >= 400).map((r) => tsResolver.resolveResponseStatusName(node, r.statusCode))
|
|
60
91
|
const TError = `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(' | ') : 'Error'}>`
|
|
61
|
-
|
|
92
|
+
|
|
93
|
+
const zodRequestName =
|
|
94
|
+
options.parser === 'zod' && options.zodResolver && node.requestBody?.content?.[0]?.schema ? (options.zodResolver.resolveDataName?.(node) ?? null) : null
|
|
95
|
+
|
|
96
|
+
const requestGenericType = zodRequestName ? `z.output<typeof ${zodRequestName}>` : requestName || 'unknown'
|
|
97
|
+
|
|
98
|
+
return [responseName, TError, requestGenericType].filter(Boolean)
|
|
62
99
|
}
|
|
63
100
|
|
|
64
101
|
/**
|
|
@@ -67,24 +104,29 @@ export function buildGenerics(node: ast.OperationNode, tsResolver: ResolverTs):
|
|
|
67
104
|
*/
|
|
68
105
|
export function buildClassClientParams({
|
|
69
106
|
node,
|
|
70
|
-
|
|
107
|
+
url,
|
|
71
108
|
baseURL,
|
|
72
109
|
tsResolver,
|
|
73
110
|
isFormData,
|
|
111
|
+
isMultipleContentTypes,
|
|
112
|
+
hasFormData,
|
|
74
113
|
headers,
|
|
114
|
+
zodQueryParamsName,
|
|
75
115
|
}: {
|
|
76
116
|
node: ast.OperationNode
|
|
77
|
-
|
|
78
|
-
baseURL: string | undefined
|
|
117
|
+
url: string
|
|
118
|
+
baseURL: string | null | undefined
|
|
79
119
|
tsResolver: ResolverTs
|
|
80
120
|
isFormData: boolean
|
|
121
|
+
isMultipleContentTypes: boolean
|
|
122
|
+
hasFormData: boolean
|
|
81
123
|
headers: Array<string>
|
|
124
|
+
zodQueryParamsName?: string | null
|
|
82
125
|
}) {
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
const requestName = node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : undefined
|
|
126
|
+
const { query: queryParams } = getOperationParameters(node)
|
|
127
|
+
const queryParamsName = queryParams.length > 0 ? tsResolver.resolveQueryParamsName(node, queryParams[0]!) : null
|
|
128
|
+
const requestName = node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : null
|
|
129
|
+
const responseType = getResponseType(node)
|
|
88
130
|
|
|
89
131
|
return createFunctionParams({
|
|
90
132
|
config: {
|
|
@@ -94,27 +136,34 @@ export function buildClassClientParams({
|
|
|
94
136
|
mode: 'inlineSpread',
|
|
95
137
|
},
|
|
96
138
|
method: {
|
|
97
|
-
value: JSON.stringify(node.method.toUpperCase()),
|
|
139
|
+
value: JSON.stringify(ast.isHttpOperationNode(node) ? node.method.toUpperCase() : ''),
|
|
98
140
|
},
|
|
99
141
|
url: {
|
|
100
|
-
value:
|
|
142
|
+
value: url,
|
|
101
143
|
},
|
|
102
144
|
baseURL: baseURL
|
|
103
145
|
? {
|
|
104
146
|
value: JSON.stringify(baseURL),
|
|
105
147
|
}
|
|
106
|
-
:
|
|
107
|
-
params: queryParamsName ? {} :
|
|
148
|
+
: null,
|
|
149
|
+
params: queryParamsName ? (zodQueryParamsName ? { value: 'requestParams' } : {}) : null,
|
|
108
150
|
data: requestName
|
|
109
151
|
? {
|
|
110
|
-
value:
|
|
152
|
+
value:
|
|
153
|
+
isMultipleContentTypes && hasFormData
|
|
154
|
+
? "contentType === 'multipart/form-data' ? formData as FormData : requestData"
|
|
155
|
+
: isFormData
|
|
156
|
+
? 'formData as FormData'
|
|
157
|
+
: 'requestData',
|
|
111
158
|
}
|
|
112
|
-
:
|
|
159
|
+
: null,
|
|
160
|
+
contentType: isMultipleContentTypes ? {} : null,
|
|
161
|
+
responseType: responseType ? { value: JSON.stringify(responseType) } : null,
|
|
113
162
|
headers: headers.length
|
|
114
163
|
? {
|
|
115
164
|
value: `{ ${headers.join(', ')}, ...requestConfig.headers }`,
|
|
116
165
|
}
|
|
117
|
-
:
|
|
166
|
+
: null,
|
|
118
167
|
},
|
|
119
168
|
},
|
|
120
169
|
})
|
|
@@ -122,7 +171,7 @@ export function buildClassClientParams({
|
|
|
122
171
|
|
|
123
172
|
/**
|
|
124
173
|
* Builds the request data parsing line for client methods.
|
|
125
|
-
* Applies Zod validation
|
|
174
|
+
* Applies Zod validation when `parser.request === 'zod'`, otherwise assigns data directly.
|
|
126
175
|
*/
|
|
127
176
|
export function buildRequestDataLine({
|
|
128
177
|
parser,
|
|
@@ -131,10 +180,11 @@ export function buildRequestDataLine({
|
|
|
131
180
|
}: {
|
|
132
181
|
parser: PluginClient['resolvedOptions']['parser'] | undefined
|
|
133
182
|
node: ast.OperationNode
|
|
134
|
-
zodResolver?: ResolverZod
|
|
183
|
+
zodResolver?: ResolverZod | null
|
|
135
184
|
}): string {
|
|
136
|
-
const
|
|
137
|
-
|
|
185
|
+
const requestParser = resolveRequestParser(parser)
|
|
186
|
+
const zodRequestName = zodResolver && requestParser === 'zod' && node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : null
|
|
187
|
+
if (requestParser === 'zod' && zodRequestName) {
|
|
138
188
|
return `const requestData = ${zodRequestName}.parse(data)`
|
|
139
189
|
}
|
|
140
190
|
if (node.requestBody?.content?.[0]?.schema) {
|
|
@@ -143,6 +193,28 @@ export function buildRequestDataLine({
|
|
|
143
193
|
return ''
|
|
144
194
|
}
|
|
145
195
|
|
|
196
|
+
/**
|
|
197
|
+
* Builds the query parameters parsing line for client methods.
|
|
198
|
+
* Returns an empty string when no query params exist or query-params parsing is not enabled.
|
|
199
|
+
* Only the object form `parser: { request: 'zod' }` triggers this. `parser: 'zod'` does not.
|
|
200
|
+
*/
|
|
201
|
+
export function buildQueryParamsLine({
|
|
202
|
+
parser,
|
|
203
|
+
node,
|
|
204
|
+
zodResolver,
|
|
205
|
+
}: {
|
|
206
|
+
parser: PluginClient['resolvedOptions']['parser'] | undefined
|
|
207
|
+
node: ast.OperationNode
|
|
208
|
+
zodResolver?: ResolverZod | null
|
|
209
|
+
}): string {
|
|
210
|
+
if (resolveQueryParamsParser(parser) !== 'zod' || !zodResolver) return ''
|
|
211
|
+
const { query: queryParams } = getOperationParameters(node)
|
|
212
|
+
if (queryParams.length === 0) return ''
|
|
213
|
+
const zodQueryParamsName = zodResolver.resolveQueryParamsName?.(node, queryParams[0]!)
|
|
214
|
+
if (!zodQueryParamsName) return ''
|
|
215
|
+
return `const requestParams = ${zodQueryParamsName}.parse(params)`
|
|
216
|
+
}
|
|
217
|
+
|
|
146
218
|
/**
|
|
147
219
|
* Builds the form data conversion line for file upload requests.
|
|
148
220
|
* Returns empty string if not applicable.
|
|
@@ -153,28 +225,35 @@ export function buildFormDataLine(isFormData: boolean, hasRequest: boolean): str
|
|
|
153
225
|
|
|
154
226
|
/**
|
|
155
227
|
* Builds the return statement for a client method.
|
|
156
|
-
*
|
|
228
|
+
* When `dataReturnType` is `'full'`, casts the response to the status-discriminated union type.
|
|
229
|
+
* When `parser.response` is `'zod'`, pipes the response body through the Zod schema before returning.
|
|
157
230
|
*/
|
|
158
231
|
export function buildReturnStatement({
|
|
159
232
|
dataReturnType,
|
|
160
233
|
parser,
|
|
161
234
|
node,
|
|
162
235
|
zodResolver,
|
|
236
|
+
tsResolver,
|
|
163
237
|
}: {
|
|
164
238
|
dataReturnType: PluginClient['resolvedOptions']['dataReturnType']
|
|
165
239
|
parser: PluginClient['resolvedOptions']['parser'] | undefined
|
|
166
240
|
node: ast.OperationNode
|
|
167
|
-
zodResolver?: ResolverZod
|
|
241
|
+
zodResolver?: ResolverZod | null
|
|
242
|
+
tsResolver?: ResolverTs | null
|
|
168
243
|
}): string {
|
|
169
|
-
const
|
|
170
|
-
|
|
171
|
-
|
|
244
|
+
const responseParser = resolveResponseParser(parser)
|
|
245
|
+
const zodResponseName = zodResolver && responseParser === 'zod' ? zodResolver.resolveResponseName?.(node) : null
|
|
246
|
+
|
|
247
|
+
if (dataReturnType === 'full' && tsResolver) {
|
|
248
|
+
const unionType = buildStatusUnionType(node, tsResolver)
|
|
249
|
+
if (responseParser === 'zod' && zodResponseName) {
|
|
250
|
+
return `return {...res, data: ${zodResponseName}.parse(res.data)} as ${unionType}`
|
|
251
|
+
}
|
|
252
|
+
return `return res as ${unionType}`
|
|
172
253
|
}
|
|
173
|
-
|
|
254
|
+
|
|
255
|
+
if (dataReturnType === 'data' && responseParser === 'zod' && zodResponseName) {
|
|
174
256
|
return `return ${zodResponseName}.parse(res.data)`
|
|
175
257
|
}
|
|
176
|
-
if (dataReturnType === 'full' && parser === 'client') {
|
|
177
|
-
return 'return res'
|
|
178
|
-
}
|
|
179
258
|
return 'return res.data'
|
|
180
259
|
}
|