@kubb/plugin-client 5.0.0-beta.56 → 5.0.0-beta.64

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/src/types.ts DELETED
@@ -1,276 +0,0 @@
1
- import type { ast, Exclude, Generator, Group, Include, Output, OutputOptions, Override, PluginFactoryOptions, Resolver } from '@kubb/core'
2
-
3
- /**
4
- * The concrete resolver type for `@kubb/plugin-client`.
5
- * Extends the base `Resolver` with a `resolveName` helper for client function names.
6
- */
7
- export type ResolverClient = Resolver & {
8
- /**
9
- * Resolves the function name for a given raw operation name.
10
- *
11
- * @example Resolving operation names
12
- * `resolver.resolveName('show pet by id') // -> 'showPetById'`
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
43
- }
44
-
45
- /**
46
- * Use either a preset `client` type OR a custom `importPath`, not both.
47
- * `importPath` will override the default `client` preset when both are provided.
48
- * These options are mutually exclusive. `bundle` and `importPath` are also
49
- * mutually exclusive since `bundle` only has effect when `importPath` is not set.
50
- */
51
- export type ClientImportPath =
52
- | {
53
- /**
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
- *
58
- * @default 'axios'
59
- */
60
- client?: 'axios' | 'fetch'
61
- importPath?: never
62
- }
63
- | {
64
- client?: never
65
- /**
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.
72
- */
73
- importPath: string
74
- /**
75
- * `bundle` has no effect when `importPath` is set.
76
- * Use either `bundle` (with `client`) or `importPath`, not both.
77
- */
78
- bundle?: never
79
- }
80
-
81
- /**
82
- * Discriminated union that ties `pathParamsType` to the `paramsType` values where it is meaningful.
83
- *
84
- * - `paramsType: 'object'` — all parameters (including path params) are merged into a single
85
- * destructured object. `pathParamsType` is never reached in this code path and has no effect.
86
- * - `paramsType?: 'inline'` (or omitted) — each parameter group is a separate function argument.
87
- * `pathParamsType` controls whether the path-param group itself is destructured (`'object'`)
88
- * or spread as individual arguments (`'inline'`).
89
- */
90
- type ParamsTypeOptions =
91
- | {
92
- /**
93
- * Every operation parameter (path, query, headers, body) is wrapped in a single
94
- * destructured object argument.
95
- */
96
- paramsType: 'object'
97
- /**
98
- * `pathParamsType` has no effect when `paramsType` is `'object'`.
99
- * Path params already live inside the single destructured object.
100
- */
101
- pathParamsType?: never
102
- }
103
- | {
104
- /**
105
- * Each parameter group is emitted as a separate positional function argument.
106
- *
107
- * @default 'inline'
108
- */
109
- paramsType?: 'inline'
110
- /**
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
- *
115
- * @default 'inline'
116
- */
117
- pathParamsType?: 'object' | 'inline'
118
- }
119
-
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 & {
127
- /**
128
- * Skip operations matching at least one entry in the list.
129
- */
130
- exclude?: Array<Exclude>
131
- /**
132
- * Restrict generation to operations matching at least one entry in the list.
133
- */
134
- include?: Array<Include>
135
- /**
136
- * Apply a different options object to operations matching a pattern.
137
- */
138
- override?: Array<Override<ResolvedOptions>>
139
- /**
140
- * Emit an `operations.ts` file that re-exports every generated function grouped by HTTP method.
141
- *
142
- * @default false
143
- */
144
- operations?: boolean
145
- /**
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
- *
150
- * @default false
151
- */
152
- urlType?: 'export' | false
153
- /**
154
- * Base URL prepended to every request. When omitted, falls back to the adapter's
155
- * server URL (typically `servers[0].url`).
156
- */
157
- baseURL?: string
158
- /**
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
- *
165
- * @default 'data'
166
- */
167
- dataReturnType?: 'data' | 'full'
168
- /**
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.
173
- */
174
- paramsCasing?: 'camelcase'
175
- /**
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' }`
187
- */
188
- parser?: false | 'zod' | { request?: 'zod'; response?: 'zod' }
189
- /**
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
- *
195
- * @default 'function'
196
- * @note Only `'function'` is compatible with query plugins.
197
- */
198
- clientType?: 'function' | 'class' | 'staticClass'
199
- /**
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
- *
204
- * @default false
205
- */
206
- bundle?: boolean
207
- /**
208
- * Generate a single SDK class composing every tag-based client into one entry point.
209
- * Automatically enables `clientType: 'class'`.
210
- *
211
- * @example
212
- * ```ts
213
- * pluginClient({
214
- * sdk: { className: 'PetStoreSDK' },
215
- * })
216
- * // class PetStoreSDK {
217
- * // readonly petClient: PetClient
218
- * // readonly storeClient: StoreClient
219
- * // constructor(config = {}) { ... }
220
- * // }
221
- * ```
222
- */
223
- sdk?: {
224
- /**
225
- * Name of the generated SDK facade class. Also the file name.
226
- */
227
- className: string
228
- }
229
- /**
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.
233
- */
234
- resolver?: Partial<ResolverClient> & ThisType<ResolverClient>
235
- /**
236
- * AST visitor applied to each operation node before code is printed.
237
- * Return `null` or `undefined` to leave the node unchanged.
238
- */
239
- transformer?: ast.Visitor
240
- /**
241
- * Custom generators that run alongside the built-in client generators.
242
- */
243
- generators?: Array<Generator<PluginClient>>
244
- } & ClientImportPath &
245
- ParamsTypeOptions
246
-
247
- type ResolvedOptions = {
248
- output: Output
249
- exclude: Array<Exclude>
250
- include: Array<Include> | undefined
251
- override: Array<Override<ResolvedOptions>>
252
- group: Group | null
253
- client: Options['client']
254
- clientType: NonNullable<Options['clientType']>
255
- bundle: NonNullable<Options['bundle']>
256
- parser: NonNullable<Options['parser']>
257
- urlType: NonNullable<Options['urlType']>
258
- importPath: Options['importPath']
259
- baseURL: Options['baseURL']
260
- dataReturnType: NonNullable<Options['dataReturnType']>
261
- pathParamsType: NonNullable<NonNullable<Options['pathParamsType']>>
262
- paramsType: NonNullable<Options['paramsType']>
263
- paramsCasing: Options['paramsCasing']
264
- sdk: Options['sdk']
265
- resolver: ResolverClient
266
- }
267
-
268
- export type PluginClient = PluginFactoryOptions<'plugin-client', Options, ResolvedOptions, ResolverClient>
269
-
270
- declare global {
271
- namespace Kubb {
272
- interface PluginRegistry {
273
- 'plugin-client': PluginClient
274
- }
275
- }
276
- }
package/src/utils.ts DELETED
@@ -1,259 +0,0 @@
1
- import { buildStatusUnionType, getOperationParameters, getResponseType, resolveSuccessNames } from '@internals/shared'
2
- import { ast } from '@kubb/core'
3
- import type { ResolverTs } from '@kubb/plugin-ts'
4
- import type { ResolverZod } from '@kubb/plugin-zod'
5
- import { createFunctionParams } from './functionParams.ts'
6
- import type { PluginClient } from './types.ts'
7
-
8
- type ParserOption = PluginClient['resolvedOptions']['parser']
9
-
10
- /**
11
- * Returns `true` when any direction of the parser uses Zod (used for dependency checks).
12
- */
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)
17
- }
18
-
19
- /**
20
- * Returns `'zod'` when request body parsing is enabled, `null` otherwise.
21
- * The string shorthand `'zod'` also enables request body parsing (existing behavior).
22
- */
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
37
- }
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
-
51
- /**
52
- * Builds HTTP headers array for a client request.
53
- * Includes Content-Type (if not default) and spreads header parameters if present.
54
- */
55
- export function buildHeaders(contentType: string, hasHeaderParams: boolean): Array<string> {
56
- return [
57
- contentType !== 'application/json' && contentType !== 'multipart/form-data' ? `'Content-Type': '${contentType}'` : null,
58
- hasHeaderParams ? '...headers' : null,
59
- ].filter(Boolean) as Array<string>
60
- }
61
-
62
- /**
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).
69
- */
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
90
- const errorNames = node.responses.filter((r) => Number.parseInt(r.statusCode, 10) >= 400).map((r) => tsResolver.resolveResponseStatusName(node, r.statusCode))
91
- const TError = `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(' | ') : 'Error'}>`
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)
99
- }
100
-
101
- /**
102
- * Builds the parameters object for a class-based client method.
103
- * Includes URL, method, base URL, headers, and request/response data.
104
- */
105
- export function buildClassClientParams({
106
- node,
107
- url,
108
- baseURL,
109
- tsResolver,
110
- isFormData,
111
- isMultipleContentTypes,
112
- hasFormData,
113
- headers,
114
- zodQueryParamsName,
115
- }: {
116
- node: ast.OperationNode
117
- url: string
118
- baseURL: string | null | undefined
119
- tsResolver: ResolverTs
120
- isFormData: boolean
121
- isMultipleContentTypes: boolean
122
- hasFormData: boolean
123
- headers: Array<string>
124
- zodQueryParamsName?: string | null
125
- }) {
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)
130
-
131
- return createFunctionParams({
132
- config: {
133
- mode: 'object',
134
- children: {
135
- requestConfig: {
136
- mode: 'inlineSpread',
137
- },
138
- method: {
139
- value: JSON.stringify(ast.isHttpOperationNode(node) ? node.method.toUpperCase() : ''),
140
- },
141
- url: {
142
- value: url,
143
- },
144
- baseURL: baseURL
145
- ? {
146
- value: JSON.stringify(baseURL),
147
- }
148
- : null,
149
- params: queryParamsName ? (zodQueryParamsName ? { value: 'requestParams' } : {}) : null,
150
- data: requestName
151
- ? {
152
- value:
153
- isMultipleContentTypes && hasFormData
154
- ? "contentType === 'multipart/form-data' ? formData as FormData : requestData"
155
- : isFormData
156
- ? 'formData as FormData'
157
- : 'requestData',
158
- }
159
- : null,
160
- contentType: isMultipleContentTypes ? {} : null,
161
- responseType: responseType ? { value: JSON.stringify(responseType) } : null,
162
- headers: headers.length
163
- ? {
164
- value: `{ ${headers.join(', ')}, ...requestConfig.headers }`,
165
- }
166
- : null,
167
- },
168
- },
169
- })
170
- }
171
-
172
- /**
173
- * Builds the request data parsing line for client methods.
174
- * Applies Zod validation when `parser.request === 'zod'`, otherwise assigns data directly.
175
- */
176
- export function buildRequestDataLine({
177
- parser,
178
- node,
179
- zodResolver,
180
- }: {
181
- parser: PluginClient['resolvedOptions']['parser'] | undefined
182
- node: ast.OperationNode
183
- zodResolver?: ResolverZod | null
184
- }): string {
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) {
188
- return `const requestData = ${zodRequestName}.parse(data)`
189
- }
190
- if (node.requestBody?.content?.[0]?.schema) {
191
- return 'const requestData = data'
192
- }
193
- return ''
194
- }
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
-
218
- /**
219
- * Builds the form data conversion line for file upload requests.
220
- * Returns empty string if not applicable.
221
- */
222
- export function buildFormDataLine(isFormData: boolean, hasRequest: boolean): string {
223
- return isFormData && hasRequest ? 'const formData = buildFormData(requestData)' : ''
224
- }
225
-
226
- /**
227
- * Builds the return statement for a client method.
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.
230
- */
231
- export function buildReturnStatement({
232
- dataReturnType,
233
- parser,
234
- node,
235
- zodResolver,
236
- tsResolver,
237
- }: {
238
- dataReturnType: PluginClient['resolvedOptions']['dataReturnType']
239
- parser: PluginClient['resolvedOptions']['parser'] | undefined
240
- node: ast.OperationNode
241
- zodResolver?: ResolverZod | null
242
- tsResolver?: ResolverTs | null
243
- }): string {
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}`
253
- }
254
-
255
- if (dataReturnType === 'data' && responseParser === 'zod' && zodResponseName) {
256
- return `return ${zodResponseName}.parse(res.data)`
257
- }
258
- return 'return res.data'
259
- }