@kubb/plugin-client 5.0.0-beta.22 → 5.0.0-beta.25

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 CHANGED
@@ -46,9 +46,10 @@ export type ResolverClient = Resolver & {
46
46
  export type ClientImportPath =
47
47
  | {
48
48
  /**
49
- * Which client should be used to do the HTTP calls.
50
- * - 'axios' uses axios client for HTTP requests.
51
- * - 'fetch' uses native fetch API for HTTP requests.
49
+ * HTTP client used by the generated code.
50
+ * - `'axios'` imports from `@kubb/plugin-client/clients/axios`. Requires `axios` at runtime.
51
+ * - `'fetch'` imports from `@kubb/plugin-client/clients/fetch`. Uses the global `fetch`.
52
+ *
52
53
  * @default 'axios'
53
54
  */
54
55
  client?: 'axios' | 'fetch'
@@ -57,9 +58,12 @@ export type ClientImportPath =
57
58
  | {
58
59
  client?: never
59
60
  /**
60
- * Client import path for API calls.
61
- * Used as `import client from '${importPath}'`.
62
- * Accepts relative and absolute paths; path changes are not performed.
61
+ * Path to a custom client module. Generated files import their HTTP runtime from here
62
+ * instead of `@kubb/plugin-client/clients/{client}`. Accepts both relative paths and
63
+ * bare module specifiers; the value is used as-is.
64
+ *
65
+ * @note When combined with a query plugin, the module must export `Client`,
66
+ * `RequestConfig`, and `ResponseErrorConfig` types.
63
67
  */
64
68
  importPath: string
65
69
  /**
@@ -81,29 +85,28 @@ export type ClientImportPath =
81
85
  type ParamsTypeOptions =
82
86
  | {
83
87
  /**
84
- * All parameters path, query, headers, and body are merged into a single
88
+ * Every operation parameter (path, query, headers, body) is wrapped in a single
85
89
  * destructured object argument.
86
- * - 'object' returns the params and pathParams as an object.
87
- * @default 'inline'
88
90
  */
89
91
  paramsType: 'object'
90
92
  /**
91
93
  * `pathParamsType` has no effect when `paramsType` is `'object'`.
92
- * Path params are already inside the single destructured object.
94
+ * Path params already live inside the single destructured object.
93
95
  */
94
96
  pathParamsType?: never
95
97
  }
96
98
  | {
97
99
  /**
98
- * Each parameter group is emitted as a separate function argument.
99
- * - 'inline' returns the params as comma separated params.
100
+ * Each parameter group is emitted as a separate positional function argument.
101
+ *
100
102
  * @default 'inline'
101
103
  */
102
104
  paramsType?: 'inline'
103
105
  /**
104
- * Controls how path parameters are arranged within the inline argument list.
105
- * - 'object' groups path params into a destructured object: `{ petId }: PathParams`.
106
- * - 'inline' emits each path param as its own argument: `petId: string`.
106
+ * How URL path parameters are arranged inside the inline argument list.
107
+ * - `'object'` groups them into one destructured object: `{ petId }: PathParams`.
108
+ * - `'inline'` emits each path param as its own argument: `petId: string`.
109
+ *
107
110
  * @default 'inline'
108
111
  */
109
112
  pathParamsType?: 'object' | 'inline'
@@ -111,87 +114,96 @@ type ParamsTypeOptions =
111
114
 
112
115
  export type Options = {
113
116
  /**
114
- * Specify the export location for the files and define the behavior of the output.
115
- * @default { path: 'clients', barrelType: 'named' }
117
+ * Where the generated client files are written and how they are exported.
118
+ *
119
+ * @default { path: 'clients', barrel: { type: 'named' } }
116
120
  */
117
121
  output?: Output
118
122
  /**
119
- * Group the clients based on the provided name.
123
+ * Split generated files into subfolders based on the operation's tag.
120
124
  */
121
125
  group?: Group
122
126
  /**
123
- * Array containing exclude parameters to exclude/skip tags/operations/methods/paths.
127
+ * Skip operations matching at least one entry in the list.
124
128
  */
125
129
  exclude?: Array<Exclude>
126
130
  /**
127
- * Array containing include parameters to include tags/operations/methods/paths.
131
+ * Restrict generation to operations matching at least one entry in the list.
128
132
  */
129
133
  include?: Array<Include>
130
134
  /**
131
- * Array containing override parameters to override `options` based on tags/operations/methods/paths.
135
+ * Apply a different options object to operations matching a pattern.
132
136
  */
133
137
  override?: Array<Override<ResolvedOptions>>
134
138
  /**
135
- * Create `operations.ts` file with all operations grouped by methods.
139
+ * Emit an `operations.ts` file that re-exports every generated function grouped by HTTP method.
140
+ *
136
141
  * @default false
137
142
  */
138
143
  operations?: boolean
139
144
  /**
140
- * Export urls that are used by operation x.
141
- * - 'export' makes them part of your barrel file.
142
- * - false does not make them exportable.
145
+ * Whether to also export the URL builder helpers (`get<Operation>Url`).
146
+ * - `'export'` exposes them via the barrel.
147
+ * - `false` keeps them private.
148
+ *
143
149
  * @default false
144
- * @example getGetPetByIdUrl
145
150
  */
146
151
  urlType?: 'export' | false
147
152
  /**
148
- * Allows you to set a custom base url for all generated calls.
153
+ * Base URL prepended to every request. When omitted, falls back to the adapter's
154
+ * server URL (typically `servers[0].url`).
149
155
  */
150
156
  baseURL?: string
151
157
  /**
152
- * ReturnType that is used when calling the client.
153
- * - 'data' returns ResponseConfig[data].
154
- * - 'full' returns ResponseConfig.
158
+ * Shape of the value returned by each generated client function.
159
+ * - `'data'` only the response body.
160
+ * - `'full'` the full response config (body, status, headers, request).
161
+ *
155
162
  * @default 'data'
156
163
  */
157
164
  dataReturnType?: 'data' | 'full'
158
165
  /**
159
- * How to style your params, by default no casing is applied.
160
- * - 'camelcase' uses camelCase for pathParams, queryParams and headerParams names
161
- * @note response types (data/body) are not affected by this option
166
+ * Rename parameter properties in the generated client (path, query, headers).
167
+ * The HTTP request still uses the original spec names; Kubb writes the mapping for you.
168
+ *
169
+ * @note Use the same value on `@kubb/plugin-ts` so types stay compatible.
162
170
  */
163
171
  paramsCasing?: 'camelcase'
164
172
  /**
165
- * Which parser can be used before returning the data.
166
- * - 'client' returns the data as-is from the client.
167
- * - 'zod' uses @kubb/plugin-zod to parse the data.
173
+ * Validator applied to response bodies before they are returned to the caller.
174
+ * - `'client'` no validation. Trusts the API.
175
+ * - `'zod'` pipes responses through schemas from `@kubb/plugin-zod`.
176
+ *
168
177
  * @default 'client'
169
178
  */
170
179
  parser?: 'client' | 'zod'
171
180
  /**
172
- * How to generate the client code.
173
- * - 'function' generates standalone functions for each operation.
174
- * - 'class' generates a class with methods for each operation.
175
- * - 'staticClass' generates a class with static methods for each operation.
181
+ * Shape of the generated client.
182
+ * - `'function'` one standalone async function per operation.
183
+ * - `'class'` one class per tag with instance methods.
184
+ * - `'staticClass'` one class per tag with static methods.
185
+ *
176
186
  * @default 'function'
187
+ * @note Only `'function'` is compatible with query plugins.
177
188
  */
178
189
  clientType?: 'function' | 'class' | 'staticClass'
179
190
  /**
180
- * Bundle the selected client into the generated `.kubb` directory.
181
- * When disabled the generated clients will import the shared runtime from `@kubb/plugin-client/clients/*`.
191
+ * Copy the HTTP client runtime into the generated output so consumers do not need
192
+ * `@kubb/plugin-client` at runtime. When `false`, generated files import from
193
+ * `@kubb/plugin-client/clients/{client}`.
194
+ *
182
195
  * @default false
183
- * In version 5 of Kubb this is by default true
184
196
  */
185
197
  bundle?: boolean
186
198
  /**
187
- * Generate an SDK facade class that composes all tag-based client classes into a single entry point.
188
- * Setting this option automatically enables `clientType: 'class'`.
199
+ * Generate a single SDK class composing every tag-based client into one entry point.
200
+ * Automatically enables `clientType: 'class'`.
201
+ *
189
202
  * @example
190
203
  * ```ts
191
204
  * pluginClient({
192
205
  * sdk: { className: 'PetStoreSDK' },
193
206
  * })
194
- * // Generates a class with a shared constructor config and one property per tag:
195
207
  * // class PetStoreSDK {
196
208
  * // readonly petController: petController
197
209
  * // readonly storeController: storeController
@@ -201,22 +213,23 @@ export type Options = {
201
213
  */
202
214
  sdk?: {
203
215
  /**
204
- * Name of the generated SDK facade class.
216
+ * Name of the generated SDK facade class. Also the file name.
205
217
  */
206
218
  className: string
207
219
  }
208
220
  /**
209
- * Override individual resolver methods. Any method you omit falls back to the
210
- * preset resolver's implementation. Use `this.default(...)` to call it.
221
+ * Override how names and file paths are built for the generated client.
222
+ * Methods you omit fall back to the default resolver. `this` is bound to the
223
+ * full resolver, so `this.default(name)` delegates to the built-in implementation.
211
224
  */
212
225
  resolver?: Partial<ResolverClient> & ThisType<ResolverClient>
213
226
  /**
214
- * Single AST visitor applied to each node before printing.
215
- * Return `null` or `undefined` from a method to leave the node unchanged.
227
+ * AST visitor applied to each operation node before code is printed.
228
+ * Return `null` or `undefined` to leave the node unchanged.
216
229
  */
217
230
  transformer?: ast.Visitor
218
231
  /**
219
- * Define some generators next to the client generators.
232
+ * Custom generators that run alongside the built-in client generators.
220
233
  */
221
234
  generators?: Array<Generator<PluginClient>>
222
235
  } & ClientImportPath &
@@ -227,7 +240,7 @@ type ResolvedOptions = {
227
240
  exclude: Array<Exclude>
228
241
  include: Array<Include> | undefined
229
242
  override: Array<Override<ResolvedOptions>>
230
- group: Group | undefined
243
+ group: Group | null
231
244
  client: Options['client']
232
245
  clientType: NonNullable<Options['clientType']>
233
246
  bundle: NonNullable<Options['bundle']>
package/src/utils.ts CHANGED
@@ -12,8 +12,8 @@ import type { PluginClient } from './types.ts'
12
12
  */
13
13
  export function buildHeaders(contentType: string, hasHeaderParams: boolean): Array<string> {
14
14
  return [
15
- contentType !== 'application/json' && contentType !== 'multipart/form-data' ? `'Content-Type': '${contentType}'` : undefined,
16
- hasHeaderParams ? '...headers' : undefined,
15
+ contentType !== 'application/json' && contentType !== 'multipart/form-data' ? `'Content-Type': '${contentType}'` : null,
16
+ hasHeaderParams ? '...headers' : null,
17
17
  ].filter(Boolean) as Array<string>
18
18
  }
19
19
 
@@ -23,7 +23,7 @@ export function buildHeaders(contentType: string, hasHeaderParams: boolean): Arr
23
23
  */
24
24
  export function buildGenerics(node: ast.OperationNode, tsResolver: ResolverTs): Array<string> {
25
25
  const responseName = tsResolver.resolveResponseName(node)
26
- const requestName = node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : undefined
26
+ const requestName = node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : null
27
27
  const errorNames = node.responses.filter((r) => Number.parseInt(r.statusCode, 10) >= 400).map((r) => tsResolver.resolveResponseStatusName(node, r.statusCode))
28
28
  const TError = `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(' | ') : 'Error'}>`
29
29
  return [responseName, TError, requestName || 'unknown'].filter(Boolean)
@@ -53,8 +53,8 @@ export function buildClassClientParams({
53
53
  headers: Array<string>
54
54
  }) {
55
55
  const { query: queryParams } = getOperationParameters(node)
56
- const queryParamsName = queryParams.length > 0 ? tsResolver.resolveQueryParamsName(node, queryParams[0]!) : undefined
57
- const requestName = node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : undefined
56
+ const queryParamsName = queryParams.length > 0 ? tsResolver.resolveQueryParamsName(node, queryParams[0]!) : null
57
+ const requestName = node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : null
58
58
 
59
59
  return createFunctionParams({
60
60
  config: {
@@ -73,8 +73,8 @@ export function buildClassClientParams({
73
73
  ? {
74
74
  value: JSON.stringify(baseURL),
75
75
  }
76
- : undefined,
77
- params: queryParamsName ? {} : undefined,
76
+ : null,
77
+ params: queryParamsName ? {} : null,
78
78
  data: requestName
79
79
  ? {
80
80
  value:
@@ -84,13 +84,13 @@ export function buildClassClientParams({
84
84
  ? 'formData as FormData'
85
85
  : 'requestData',
86
86
  }
87
- : undefined,
88
- contentType: isMultipleContentTypes ? {} : undefined,
87
+ : null,
88
+ contentType: isMultipleContentTypes ? {} : null,
89
89
  headers: headers.length
90
90
  ? {
91
91
  value: `{ ${headers.join(', ')}, ...requestConfig.headers }`,
92
92
  }
93
- : undefined,
93
+ : null,
94
94
  },
95
95
  },
96
96
  })
@@ -107,9 +107,9 @@ export function buildRequestDataLine({
107
107
  }: {
108
108
  parser: PluginClient['resolvedOptions']['parser'] | undefined
109
109
  node: ast.OperationNode
110
- zodResolver?: ResolverZod
110
+ zodResolver?: ResolverZod | null
111
111
  }): string {
112
- const zodRequestName = zodResolver && parser === 'zod' && node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : undefined
112
+ const zodRequestName = zodResolver && parser === 'zod' && node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : null
113
113
  if (parser === 'zod' && zodRequestName) {
114
114
  return `const requestData = ${zodRequestName}.parse(data)`
115
115
  }
@@ -140,9 +140,9 @@ export function buildReturnStatement({
140
140
  dataReturnType: PluginClient['resolvedOptions']['dataReturnType']
141
141
  parser: PluginClient['resolvedOptions']['parser'] | undefined
142
142
  node: ast.OperationNode
143
- zodResolver?: ResolverZod
143
+ zodResolver?: ResolverZod | null
144
144
  }): string {
145
- const zodResponseName = zodResolver && parser === 'zod' ? zodResolver.resolveResponseName?.(node) : undefined
145
+ const zodResponseName = zodResolver && parser === 'zod' ? zodResolver.resolveResponseName?.(node) : null
146
146
  if (dataReturnType === 'full' && parser === 'zod' && zodResponseName) {
147
147
  return `return {...res, data: ${zodResponseName}.parse(res.data)}`
148
148
  }