@kubb/plugin-cypress 5.0.0-beta.15 → 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/extension.yaml CHANGED
@@ -2,7 +2,7 @@ $schema: https://kubb.dev/schemas/extension.json
2
2
  kind: plugin
3
3
  id: plugin-cypress
4
4
  name: Cypress
5
- description: Generate Cypress end-to-end tests from OpenAPI specifications.
5
+ description: Generate typed `cy.request()` wrappers from OpenAPI so end-to-end tests reuse one source of truth for API calls.
6
6
  category: testing
7
7
  type: official
8
8
  npmPackage: '@kubb/plugin-cypress'
@@ -35,76 +35,297 @@ icon:
35
35
  intro: |
36
36
  # @kubb/plugin-cypress
37
37
 
38
- Generate typed `cy.request()` wrappers from your OpenAPI schema. Each API operation becomes a reusable function you can call in Cypress tests, with full TypeScript support.
38
+ Generate one typed `cy.request()` wrapper per OpenAPI operation. Each helper has typed path params, body, query, and a typed response so failing API calls in Cypress show up at compile time instead of inside the test runner.
39
+
40
+ Use these helpers in `before`/`beforeEach` hooks to seed data, in custom commands, or in API-only test specs.
39
41
  options:
40
42
  - name: output
41
43
  type: Output
42
44
  required: false
43
45
  default: "{ path: 'cypress', barrel: { type: 'named' } }"
44
- description: Specify the export location for the files and define the behavior of the output.
46
+ description: Where the generated Cypress helpers are written and how they are exported.
45
47
  properties:
46
48
  - name: path
47
49
  type: string
48
50
  required: true
49
- description: Output directory or file for the generated code, relative to the global `output.path`.
51
+ description: |
52
+ Folder (or single file) where the plugin writes its generated code. The path is resolved against the global `output.path` set on `defineConfig`.
53
+
54
+ Use a folder to keep each generator's output isolated (`'types'`, `'clients'`, `'hooks'`). Use a single file when you want everything in one place, for example `'api.ts'`.
50
55
  tip: |
51
- if `output.path` is a file, `group` cannot be used.
56
+ When `output.path` points to a single file, the `group` option cannot be used because every operation ends up in the same file.
57
+ examples:
58
+ - name: kubb.config.ts
59
+ files:
60
+ - lang: typescript
61
+ twoslash: false
62
+ code: |
63
+ import { defineConfig } from 'kubb'
64
+ import { pluginTs } from '@kubb/plugin-ts'
65
+
66
+ export default defineConfig({
67
+ input: { path: './petStore.yaml' },
68
+ output: { path: './src/gen' },
69
+ plugins: [
70
+ pluginTs({
71
+ output: { path: './types' },
72
+ }),
73
+ ],
74
+ })
75
+ - name: Resulting tree
76
+ files:
77
+ - lang: text
78
+ twoslash: false
79
+ code: |
80
+ src/
81
+ └── gen/
82
+ └── types/
83
+ ├── Pet.ts
84
+ └── Store.ts
52
85
  default: "'cypress'"
53
86
  - name: barrel
54
87
  type: "{ type: 'named' | 'all', nested?: boolean } | false"
55
88
  required: false
56
89
  default: "{ type: 'named' }"
57
- description: 'Configure barrel file export strategy. Use `type` to control named vs. wildcard exports; set `nested: true` to generate hierarchical barrels in subdirectories.'
90
+ description: |
91
+ Controls how the generated `index.ts` (barrel) file re-exports the plugin's output.
92
+
93
+ - `{ type: 'named' }` re-exports each symbol by name. Best for tree-shaking and explicit imports.
94
+ - `{ type: 'all' }` uses `export *`. Smaller barrel file, but exports everything.
95
+ - `{ nested: true }` creates a barrel in every subdirectory, so callers can import from any depth.
96
+ - `false` skips the barrel entirely. The plugin's files are also excluded from the root `index.ts`.
97
+ tip: |
98
+ Pick `'named'` when consumers care about which symbols they import (better tree-shaking, friendlier auto-import). Pick `'all'` when the file count is small and you want a one-line barrel.
58
99
  examples:
59
- - name: all
100
+ - name: "'named' (default)"
60
101
  files:
61
- - lang: typescript
102
+ - name: kubb.config.ts
103
+ lang: typescript
104
+ twoslash: false
62
105
  code: |
63
- export * from './gen/petService.ts'
106
+ import { defineConfig } from 'kubb'
107
+ import { pluginTs } from '@kubb/plugin-ts'
108
+
109
+ export default defineConfig({
110
+ input: { path: './petStore.yaml' },
111
+ output: { path: './src/gen' },
112
+ plugins: [
113
+ pluginTs({
114
+ output: { barrel: { type: 'named' } },
115
+ }),
116
+ ],
117
+ })
118
+ - name: src/gen/types/index.ts
119
+ lang: typescript
64
120
  twoslash: false
65
- - name: named
121
+ code: |
122
+ export { Pet, PetStatus } from './Pet'
123
+ export { Store } from './Store'
124
+ - name: "'all'"
66
125
  files:
67
- - lang: typescript
126
+ - name: kubb.config.ts
127
+ lang: typescript
128
+ twoslash: false
68
129
  code: |
69
- export { PetService } from './gen/petService.ts'
130
+ import { defineConfig } from 'kubb'
131
+ import { pluginTs } from '@kubb/plugin-ts'
132
+
133
+ export default defineConfig({
134
+ input: { path: './petStore.yaml' },
135
+ output: { path: './src/gen' },
136
+ plugins: [
137
+ pluginTs({
138
+ output: { barrel: { type: 'all' } },
139
+ }),
140
+ ],
141
+ })
142
+ - name: src/gen/types/index.ts
143
+ lang: typescript
70
144
  twoslash: false
145
+ code: |
146
+ export * from './Pet'
147
+ export * from './Store'
71
148
  - name: nested
72
149
  files:
73
150
  - name: kubb.config.ts
74
151
  lang: typescript
152
+ twoslash: false
75
153
  code: |
76
- output: {
77
- path: './gen',
78
- barrel: { type: 'named', nested: true },
79
- }
154
+ import { defineConfig } from 'kubb'
155
+ import { pluginTs } from '@kubb/plugin-ts'
156
+
157
+ export default defineConfig({
158
+ input: { path: './petStore.yaml' },
159
+ output: { path: './src/gen' },
160
+ plugins: [
161
+ pluginTs({
162
+ output: { barrel: { type: 'named', nested: true } },
163
+ }),
164
+ ],
165
+ })
166
+ - name: Generated tree
167
+ lang: text
80
168
  twoslash: false
169
+ code: |
170
+ src/gen/types/
171
+ ├── index.ts # re-exports ./petController and ./storeController
172
+ ├── petController/
173
+ │ ├── index.ts # re-exports Pet, Store, ...
174
+ │ └── Pet.ts
175
+ └── storeController/
176
+ ├── index.ts
177
+ └── Store.ts
81
178
  - name: 'false'
82
179
  files:
83
- - lang: typescript
84
- code: ''
180
+ - name: kubb.config.ts
181
+ lang: typescript
182
+ twoslash: false
183
+ code: |
184
+ import { defineConfig } from 'kubb'
185
+ import { pluginTs } from '@kubb/plugin-ts'
186
+
187
+ export default defineConfig({
188
+ input: { path: './petStore.yaml' },
189
+ output: { path: './src/gen' },
190
+ plugins: [
191
+ pluginTs({
192
+ output: { barrel: false },
193
+ }),
194
+ ],
195
+ })
196
+ - name: Result
197
+ lang: text
85
198
  twoslash: false
199
+ code: |
200
+ # No index.ts is generated for this plugin.
201
+ # Its files are also excluded from the root index.ts.
86
202
  - name: banner
87
203
  type: 'string | ((node: RootNode) => string)'
88
204
  required: false
89
- description: Add a banner comment at the top of every generated file. Accepts a static string or a function that receives the `RootNode` and returns a string.
205
+ description: |
206
+ Text prepended to every generated file. Useful for license headers, lint disables, or `@ts-nocheck` directives.
207
+
208
+ Pass a string for a static banner. Pass a function to compute the banner from each file's `RootNode` (the AST root containing path, schema, and operation context).
209
+ examples:
210
+ - name: Static banner
211
+ files:
212
+ - name: kubb.config.ts
213
+ lang: typescript
214
+ twoslash: false
215
+ code: |
216
+ import { defineConfig } from 'kubb'
217
+ import { pluginTs } from '@kubb/plugin-ts'
218
+
219
+ export default defineConfig({
220
+ input: { path: './petStore.yaml' },
221
+ output: { path: './src/gen' },
222
+ plugins: [
223
+ pluginTs({
224
+ output: {
225
+ banner: '/* eslint-disable */\n// @ts-nocheck',
226
+ },
227
+ }),
228
+ ],
229
+ })
230
+ - name: Generated file
231
+ lang: typescript
232
+ twoslash: false
233
+ code: |
234
+ /* eslint-disable */
235
+ // @ts-nocheck
236
+ export type Pet = {
237
+ id: number
238
+ name: string
239
+ }
240
+ - name: Dynamic banner
241
+ files:
242
+ - name: kubb.config.ts
243
+ lang: typescript
244
+ twoslash: false
245
+ code: |
246
+ import { defineConfig } from 'kubb'
247
+ import { pluginTs } from '@kubb/plugin-ts'
248
+
249
+ export default defineConfig({
250
+ input: { path: './petStore.yaml' },
251
+ output: { path: './src/gen' },
252
+ plugins: [
253
+ pluginTs({
254
+ output: {
255
+ banner: (node) => `// Source: ${node.path}\n// Generated at ${new Date().toISOString()}`,
256
+ },
257
+ }),
258
+ ],
259
+ })
90
260
  - name: footer
91
261
  type: 'string | ((node: RootNode) => string)'
92
262
  required: false
93
- description: Add a footer comment at the end of every generated file. Accepts a static string or a function that receives the `RootNode` and returns a string.
263
+ description: |
264
+ Text appended at the end of every generated file. The mirror of `banner` — use it for closing comments, re-enabling lint rules, or marker lines.
265
+
266
+ Pass a string for a static footer, or a function that receives the file's `RootNode` and returns the footer text.
267
+ examples:
268
+ - name: Re-enable lint after a banner disable
269
+ files:
270
+ - name: kubb.config.ts
271
+ lang: typescript
272
+ twoslash: false
273
+ code: |
274
+ import { defineConfig } from 'kubb'
275
+ import { pluginTs } from '@kubb/plugin-ts'
276
+
277
+ export default defineConfig({
278
+ input: { path: './petStore.yaml' },
279
+ output: { path: './src/gen' },
280
+ plugins: [
281
+ pluginTs({
282
+ output: {
283
+ banner: '/* eslint-disable */',
284
+ footer: '/* eslint-enable */',
285
+ },
286
+ }),
287
+ ],
288
+ })
94
289
  - name: override
95
290
  type: boolean
96
291
  required: false
97
292
  default: 'false'
98
- description: Whether Kubb overrides existing external files that can be generated if they already exist.
293
+ description: |
294
+ Allows the plugin to overwrite hand-written files that share a name with a generated file.
295
+
296
+ - `false` (default): Kubb skips a file if it already exists and is not marked as generated. This protects manual edits.
297
+ - `true`: Kubb overwrites any file at the target path, including hand-written ones.
298
+ warning: |
299
+ Enable this only when you are sure the target folder contains nothing you need to keep. Local edits are lost on the next generation.
300
+ examples:
301
+ - name: kubb.config.ts
302
+ files:
303
+ - lang: typescript
304
+ twoslash: false
305
+ code: |
306
+ import { defineConfig } from 'kubb'
307
+ import { pluginTs } from '@kubb/plugin-ts'
308
+
309
+ export default defineConfig({
310
+ input: { path: './petStore.yaml' },
311
+ output: { path: './src/gen' },
312
+ plugins: [
313
+ pluginTs({
314
+ output: { override: true },
315
+ }),
316
+ ],
317
+ })
99
318
  - name: resolver
100
319
  type: Partial<ResolverCypress> & ThisType<ResolverCypress>
101
320
  required: false
102
321
  description: |
103
- A single resolver that overrides the naming and path-resolution conventions. Each method you provide replaces the corresponding built-in one. When a method returns `null` or `undefined`, the resolver's result is used as the fallback, so you only need to supply the methods you want to change.
322
+ Overrides how the plugin builds names and paths for generated files and symbols. Use this to add prefixes, suffixes, or to swap the casing strategy without forking the plugin.
104
323
 
105
- `this` inside each method is bound to the **full** resolver, so you can call other resolver methods (e.g. `this.default(name, 'function')`) without losing context.
324
+ Only override the methods you want to change. Anything you omit falls back to the plugin's default resolver. A method that returns `null` or `undefined` also falls back.
325
+
326
+ Inside each method, `this` is bound to the full resolver, so you can call `this.default(name, 'function')` to delegate to the built-in implementation.
106
327
  body: |
107
- Each plugin ships a built-in resolver:
328
+ Each plugin ships with a default resolver:
108
329
 
109
330
  | Plugin | Default resolver |
110
331
  | --- | --- |
@@ -112,37 +333,64 @@ options:
112
333
  | `@kubb/plugin-zod` | `resolverZod` |
113
334
  | `@kubb/plugin-cypress` | `resolverCypress` |
114
335
  | `@kubb/plugin-mcp` | `resolverMcp` |
336
+ | `@kubb/plugin-client` | `resolverClient` |
115
337
  codeBlock:
116
338
  lang: typescript
117
- title: Custom resolver (plugin-ts example)
339
+ title: Add an Api prefix to every name
118
340
  code: |
341
+ import { defineConfig } from 'kubb'
119
342
  import { pluginTs } from '@kubb/plugin-ts'
120
343
 
121
- pluginTs({
122
- resolver: {
123
- resolveName(name) {
124
- // Prefix every operation-derived name; falls back for names where
125
- // this returns null/undefined.
126
- return `Api${this.default(name, 'function')}`
127
- },
128
- },
344
+ export default defineConfig({
345
+ input: { path: './petStore.yaml' },
346
+ output: { path: './src/gen' },
347
+ plugins: [
348
+ pluginTs({
349
+ resolver: {
350
+ resolveName(name) {
351
+ return `Api${this.default(name, 'function')}`
352
+ },
353
+ },
354
+ }),
355
+ ],
129
356
  })
130
357
  tip: |
131
- Use `resolver` for fine-grained control over naming conventions.
358
+ Use `resolver` for naming and file-location tweaks. For changing the AST nodes themselves (e.g. stripping descriptions), use `transformer` instead.
132
359
  - name: paramsType
133
360
  type: "'object' | 'inline'"
134
361
  required: false
135
362
  default: "'inline'"
136
- description: Defines how parameters are passed to generated functions. Switch between object-style parameters and inline parameters.
363
+ description: |
364
+ How operation parameters (path, query, headers) are exposed in the generated function signature.
365
+
366
+ - `'inline'` (default) — each parameter is a separate positional argument. Compact for operations with one or two params.
367
+ - `'object'` — every parameter is wrapped in a single object argument. Easier to read for operations with many params and named at the call site.
137
368
  tip: |
138
- When `paramsType` is set to `'object'`, `pathParams` will also be set to `'object'`.
139
- body: |
140
- - `'object'` returns params and pathParams as an object.
141
- - `'inline'` returns params as comma-separated params.
369
+ Setting `paramsType: 'object'` implicitly sets `pathParamsType: 'object'` as well, so call sites are consistent.
142
370
  examples:
143
- - name: object
371
+ - name: "'inline' (default)"
144
372
  files:
145
- - lang: typescript
373
+ - name: Generated client
374
+ lang: typescript
375
+ twoslash: false
376
+ code: |
377
+ export async function deletePet(
378
+ petId: DeletePetPathParams['petId'],
379
+ headers?: DeletePetHeaderParams,
380
+ config: Partial<RequestConfig> = {},
381
+ ) {
382
+ // ...
383
+ }
384
+ - name: Caller
385
+ lang: typescript
386
+ twoslash: false
387
+ code: |
388
+ await deletePet(42)
389
+ - name: "'object'"
390
+ files:
391
+ - name: Generated client
392
+ lang: typescript
393
+ twoslash: false
146
394
  code: |
147
395
  export async function deletePet(
148
396
  {
@@ -154,285 +402,485 @@ options:
154
402
  },
155
403
  config: Partial<RequestConfig> = {},
156
404
  ) {
157
- ...
405
+ // ...
158
406
  }
407
+ - name: Caller
408
+ lang: typescript
159
409
  twoslash: false
160
- - name: inline
161
- files:
162
- - lang: typescript
163
410
  code: |
164
- export async function deletePet(
165
- petId: DeletePetPathParams['petId'],
166
- headers?: DeletePetHeaderParams,
167
- config: Partial<RequestConfig> = {}
168
- ){
169
- ...
170
- }
171
- twoslash: false
411
+ await deletePet({ petId: 42, headers: { 'X-Api-Key': 'secret' } })
172
412
  - name: paramsCasing
173
413
  type: "'camelcase'"
174
414
  required: false
175
- description: Transform parameter names to a specific casing format for path, query, and header parameters in generated client code.
415
+ description: |
416
+ Renames path, query, and header parameters in the generated client to the chosen casing. The HTTP request still uses the original names from the OpenAPI spec — Kubb writes the mapping for you.
417
+
418
+ - `'camelcase'` — turn `pet_id` and `X-Api-Key` into `petId` and `xApiKey` in your TypeScript code. The runtime URL still uses `/pet/{pet_id}` and the header is still sent as `X-Api-Key`.
176
419
  important: |
177
- When using `paramsCasing`, ensure that `@kubb/plugin-ts` also has the same `paramsCasing` setting. This option automatically maps transformed parameter names back to their original API names in HTTP requests.
178
- body: |
179
- - `'camelcase'` transforms parameter names to camelCase.
420
+ Set the same `paramsCasing` on every plugin that touches operation parameters (`@kubb/plugin-ts`, `@kubb/plugin-client`, `@kubb/plugin-react-query`, `@kubb/plugin-faker`, `@kubb/plugin-mcp`). Mismatched casing causes type errors between generated layers.
180
421
  examples:
181
- - name: With paramsCasing camelcase
422
+ - name: "With paramsCasing: 'camelcase'"
182
423
  files:
183
- - lang: typescript
424
+ - name: Generated client
425
+ lang: typescript
426
+ twoslash: false
184
427
  code: |
185
- // Function parameters use camelCase
428
+ // Function takes camelCase parameters
186
429
  export async function deletePet(
187
- petId: DeletePetPathParams['petId'], // ✓ camelCase
430
+ petId: DeletePetPathParams['petId'],
188
431
  headers?: DeletePetHeaderParams,
189
- config: Partial<RequestConfig> = {}
432
+ config: Partial<RequestConfig> = {},
190
433
  ) {
191
- // Automatically maps back to original name for the API
434
+ // ...mapped back to the original API name internally
192
435
  const pet_id = petId
193
436
 
194
437
  return fetch({
195
438
  method: 'DELETE',
196
- url: `/pet/${pet_id}`, // Uses original API parameter name
197
- ...
439
+ url: `/pet/${pet_id}`,
440
+ ...config,
198
441
  })
199
442
  }
443
+ - name: Caller
444
+ lang: typescript
200
445
  twoslash: false
446
+ code: |
447
+ await deletePet(42)
201
448
  - name: Without paramsCasing
202
449
  files:
203
- - lang: typescript
450
+ - name: Generated client
451
+ lang: typescript
452
+ twoslash: false
204
453
  code: |
205
- // Parameters use original API naming
454
+ // Function parameters mirror the OpenAPI spec
206
455
  export async function deletePet(
207
- pet_id: DeletePetPathParams['pet_id'], // Original naming
456
+ pet_id: DeletePetPathParams['pet_id'],
208
457
  headers?: DeletePetHeaderParams,
209
- config: Partial<RequestConfig> = {}
458
+ config: Partial<RequestConfig> = {},
210
459
  ) {
211
460
  return fetch({
212
461
  method: 'DELETE',
213
462
  url: `/pet/${pet_id}`,
214
- ...
463
+ ...config,
215
464
  })
216
465
  }
217
- twoslash: false
218
466
  tip: |
219
- The client automatically generates mapping code to convert camelCase parameter names back to the original API format. You write code with developer-friendly camelCase names, but HTTP requests use the exact parameter names from your OpenAPI specification.
467
+ Callers write friendly camelCase names. The generated client maps them back to whatever the API expects (snake_case path params, kebab-case headers, ...).
220
468
  - name: pathParamsType
221
469
  type: "'object' | 'inline'"
222
470
  required: false
223
471
  default: "'inline'"
224
- description: Defines how pathParams are passed to generated functions.
225
- body: |
226
- - `'object'` returns pathParams as an object.
227
- - `'inline'` returns pathParams as comma-separated params.
472
+ description: |
473
+ How URL path parameters appear in the generated function signature. Affects only path params; query/header params follow `paramsType`.
474
+
475
+ - `'inline'` (default) each path param is a positional argument: `getPetById(petId)`.
476
+ - `'object'` — path params are wrapped in a single object: `getPetById({ petId })`.
228
477
  examples:
229
- - name: object
478
+ - name: "'inline' (default)"
230
479
  files:
231
480
  - lang: typescript
481
+ twoslash: false
232
482
  code: |
233
483
  export async function getPetById(
234
- { petId }: GetPetByIdPathParams,
484
+ petId: GetPetByIdPathParams,
235
485
  ) {
236
- ...
486
+ // ...
237
487
  }
238
- twoslash: false
239
- - name: inline
488
+ - name: "'object'"
240
489
  files:
241
490
  - lang: typescript
491
+ twoslash: false
242
492
  code: |
243
493
  export async function getPetById(
244
- petId: GetPetByIdPathParams,
494
+ { petId }: GetPetByIdPathParams,
245
495
  ) {
246
- ...
496
+ // ...
247
497
  }
248
- twoslash: false
249
498
  - name: dataReturnType
250
499
  type: "'data' | 'full'"
251
500
  required: false
252
501
  default: "'data'"
253
502
  description: |
254
- Return type used when calling the client.
503
+ Shape of the value returned from each generated client function.
255
504
 
256
- - `'data'` returns `ResponseConfig['data']`.
257
- - `'full'` returns the full `ResponseConfig`.
505
+ - `'data'` returns only the response body (`response.data`). Concise and matches what most apps need.
506
+ - `'full'` returns the full response config — body, status code, headers, and the original request. Use this when callers need to inspect headers or status.
258
507
  examples:
259
- - name: data
508
+ - name: "'data' (default)"
260
509
  files:
261
- - lang: typescript
510
+ - name: getPetById.ts
511
+ lang: typescript
512
+ twoslash: false
262
513
  code: |
263
514
  export async function getPetById<TData>(
264
515
  petId: GetPetByIdPathParams,
265
516
  ): Promise<ResponseConfig<TData>['data']> {
266
- ...
517
+ // ...
267
518
  }
519
+ - name: usage.ts
520
+ lang: typescript
268
521
  twoslash: false
269
- - name: full
522
+ code: |
523
+ const pet = await getPetById(1)
524
+ // ^? Pet
525
+ - name: "'full'"
270
526
  files:
271
- - lang: typescript
527
+ - name: getPetById.ts
528
+ lang: typescript
529
+ twoslash: false
272
530
  code: |
273
531
  export async function getPetById<TData>(
274
532
  petId: GetPetByIdPathParams,
275
533
  ): Promise<ResponseConfig<TData>> {
276
- ...
534
+ // ...
277
535
  }
536
+ - name: usage.ts
537
+ lang: typescript
278
538
  twoslash: false
539
+ code: |
540
+ const response = await getPetById(1)
541
+ // ^? ResponseConfig<Pet>
542
+ console.log(response.status, response.headers)
543
+ const pet = response.data
279
544
  - name: baseURL
280
545
  type: string
281
546
  required: false
282
- description: Sets a custom base URL for all generated calls. When not set, the base URL is automatically taken from the OAS spec via the adapter (e.g. the `servers[0].url` field).
547
+ description: |
548
+ Base URL prepended to every request URL in the generated client. When omitted, the URL comes from the OpenAPI spec's `servers[0].url` (or whichever index the adapter is configured to read).
549
+
550
+ Set this when the generated client should point at a different environment (staging, production) than the one written in the spec.
551
+ examples:
552
+ - name: Override the spec's server URL
553
+ files:
554
+ - lang: typescript
555
+ twoslash: false
556
+ code: |
557
+ import { defineConfig } from 'kubb'
558
+ import { pluginClient } from '@kubb/plugin-client'
559
+
560
+ export default defineConfig({
561
+ input: { path: './petStore.yaml' },
562
+ output: { path: './src/gen' },
563
+ plugins: [
564
+ pluginClient({
565
+ baseURL: 'https://petstore.swagger.io/v2',
566
+ }),
567
+ ],
568
+ })
283
569
  - name: group
284
570
  type: Group
285
571
  required: false
286
572
  description: |
287
- Grouping combines files in a folder based on a specific `type`.
573
+ Splits generated files into subfolders based on the operation's tag, so each tag in your OpenAPI spec gets its own directory.
574
+
575
+ Without `group`, every file lands in the plugin's `output.path` folder. With `group`, files are bucketed under `{output.path}/{groupName}/`, where `groupName` is derived from the operation's first tag.
576
+ tip: |
577
+ Use `group` to mirror your API's domain structure (pet, store, user) in the generated code. Combine it with `output.barrel: { type: 'named', nested: true }` to get per-tag barrel files.
288
578
  examples:
289
579
  - name: kubb.config.ts
290
580
  files:
291
581
  - lang: typescript
292
- code: |
293
- group: {
294
- type: 'tag',
295
- name({ group }) {
296
- return `${group}Controller`
297
- }
298
- }
299
582
  twoslash: false
583
+ code: |
584
+ import { defineConfig } from 'kubb'
585
+ import { pluginTs } from '@kubb/plugin-ts'
586
+
587
+ export default defineConfig({
588
+ input: { path: './petStore.yaml' },
589
+ output: { path: './src/gen' },
590
+ plugins: [
591
+ pluginTs({
592
+ group: {
593
+ type: 'tag',
594
+ name: ({ group }) => `${group}Controller`,
595
+ },
596
+ }),
597
+ ],
598
+ })
300
599
  body: |
301
600
  With the configuration above, the generator emits:
302
601
 
303
602
  ```text
304
- .
305
- ├── src/
306
- └── petController/
307
- │ ├── addPet.ts
308
- │ │ └── getPet.ts
309
- │ └── storeController/
310
- │ ├── createStore.ts
311
- │ └── getStoreById.ts
312
- ├── petStore.yaml
313
- ├── kubb.config.ts
314
- └── package.json
603
+ src/gen/
604
+ ├── petController/
605
+ ├── AddPet.ts
606
+ └── GetPet.ts
607
+ └── storeController/
608
+ ├── CreateStore.ts
609
+ └── GetStoreById.ts
315
610
  ```
316
611
  properties:
317
612
  - name: type
318
613
  type: "'tag'"
319
614
  required: true
320
- description: Specify the property to group files by. Required when `group` is defined.
615
+ description: |
616
+ Property used to assign each operation to a group. Required whenever `group` is set.
617
+
618
+ Today only `'tag'` is supported: Kubb reads the first tag on the operation (`operation.getTags().at(0)?.name`) and uses it as the group key. Operations without a tag are placed in a default group.
321
619
  note: |
322
- `Required: true*` means this is required only when the `group` option is used. The `group` option itself is optional.
323
- body: |
324
- - `'tag'`: Uses the first tag from `operation.getTags().at(0)?.name`
620
+ `Required: true*` is conditional only required when the parent `group` option is used. `group` itself stays optional.
325
621
  - name: name
326
622
  type: '(context: GroupContext) => string'
327
623
  required: false
328
624
  default: (ctx) => `${ctx.group}Requests`
329
- description: Return the name of a group based on the group name. This is used for file and identifier generation.
625
+ description: Function that builds the folder/identifier name from a group key (the operation's first tag).
330
626
  - name: include
331
627
  type: Array<Include>
332
628
  required: false
333
- description: Array containing include parameters to include tags, operations, methods, paths, or content types.
629
+ description: |
630
+ Restricts generation to operations that match at least one entry in the list. Anything not matched is skipped.
631
+
632
+ Each entry filters by one of:
633
+
634
+ - `tag` — the operation's first tag in the OpenAPI spec.
635
+ - `operationId` — the operation's `operationId`.
636
+ - `path` — the URL pattern (`'/pet/{petId}'`).
637
+ - `method` — HTTP method (`'get'`, `'post'`, ...).
638
+ - `contentType` — the media type of the request body.
639
+
640
+ `pattern` accepts either a string (exact match) or a `RegExp` for fuzzy matches.
334
641
  codeBlock:
335
642
  lang: typescript
336
- title: Include
643
+ title: Type definition
337
644
  code: |
338
645
  export type Include = {
339
646
  type: 'tag' | 'operationId' | 'path' | 'method' | 'contentType'
340
647
  pattern: string | RegExp
341
648
  }
649
+ examples:
650
+ - name: Only the pet tag
651
+ files:
652
+ - name: kubb.config.ts
653
+ lang: typescript
654
+ twoslash: false
655
+ code: |
656
+ import { defineConfig } from 'kubb'
657
+ import { pluginTs } from '@kubb/plugin-ts'
658
+
659
+ export default defineConfig({
660
+ input: { path: './petStore.yaml' },
661
+ output: { path: './src/gen' },
662
+ plugins: [
663
+ pluginTs({
664
+ include: [
665
+ { type: 'tag', pattern: 'pet' },
666
+ ],
667
+ }),
668
+ ],
669
+ })
670
+ - name: Only GET operations under /pet
671
+ files:
672
+ - name: kubb.config.ts
673
+ lang: typescript
674
+ twoslash: false
675
+ code: |
676
+ import { defineConfig } from 'kubb'
677
+ import { pluginTs } from '@kubb/plugin-ts'
678
+
679
+ export default defineConfig({
680
+ input: { path: './petStore.yaml' },
681
+ output: { path: './src/gen' },
682
+ plugins: [
683
+ pluginTs({
684
+ include: [
685
+ { type: 'method', pattern: 'get' },
686
+ { type: 'path', pattern: /^\/pet/ },
687
+ ],
688
+ }),
689
+ ],
690
+ })
342
691
  - name: exclude
343
692
  type: Array<Exclude>
344
693
  required: false
345
- description: Array containing exclude parameters to exclude or skip tags, operations, methods, paths, or content types.
694
+ description: |
695
+ Skips any operation that matches at least one entry in the list. The opposite of `include`.
696
+
697
+ Each entry filters by one of:
698
+
699
+ - `tag` — the operation's first tag.
700
+ - `operationId` — the operation's `operationId`.
701
+ - `path` — the URL pattern (`'/pet/{petId}'`).
702
+ - `method` — HTTP method (`'get'`, `'post'`, ...).
703
+ - `contentType` — the media type of the request body.
704
+
705
+ `pattern` accepts a plain string or a `RegExp`. When both `include` and `exclude` are set, `exclude` wins.
346
706
  codeBlock:
347
707
  lang: typescript
348
- title: Exclude
708
+ title: Type definition
349
709
  code: |
350
710
  export type Exclude = {
351
711
  type: 'tag' | 'operationId' | 'path' | 'method' | 'contentType'
352
712
  pattern: string | RegExp
353
713
  }
714
+ examples:
715
+ - name: Skip everything under the store tag
716
+ files:
717
+ - name: kubb.config.ts
718
+ lang: typescript
719
+ twoslash: false
720
+ code: |
721
+ import { defineConfig } from 'kubb'
722
+ import { pluginTs } from '@kubb/plugin-ts'
723
+
724
+ export default defineConfig({
725
+ input: { path: './petStore.yaml' },
726
+ output: { path: './src/gen' },
727
+ plugins: [
728
+ pluginTs({
729
+ exclude: [
730
+ { type: 'tag', pattern: 'store' },
731
+ ],
732
+ }),
733
+ ],
734
+ })
735
+ - name: Skip a specific operation and all delete methods
736
+ files:
737
+ - name: kubb.config.ts
738
+ lang: typescript
739
+ twoslash: false
740
+ code: |
741
+ import { defineConfig } from 'kubb'
742
+ import { pluginTs } from '@kubb/plugin-ts'
743
+
744
+ export default defineConfig({
745
+ input: { path: './petStore.yaml' },
746
+ output: { path: './src/gen' },
747
+ plugins: [
748
+ pluginTs({
749
+ exclude: [
750
+ { type: 'operationId', pattern: 'deletePet' },
751
+ { type: 'method', pattern: 'delete' },
752
+ ],
753
+ }),
754
+ ],
755
+ })
354
756
  - name: override
355
757
  type: Array<Override>
356
758
  required: false
357
- description: Array containing override parameters to override `options` based on tags, operations, methods, paths, or content types.
759
+ description: |
760
+ Applies a different set of plugin options to operations that match a pattern. Use this when most of your API should follow the global config, but a handful of endpoints need different treatment.
761
+
762
+ Each entry has the same `type` and `pattern` shape as `include`/`exclude`, plus an `options` object that overrides the plugin's options for matched operations.
763
+
764
+ Entries are evaluated top to bottom. The first matching entry's `options` is merged onto the plugin defaults; later entries do not stack.
358
765
  codeBlock:
359
766
  lang: typescript
360
- title: Override
767
+ title: Type definition
361
768
  code: |
362
769
  export type Override = {
363
770
  type: 'tag' | 'operationId' | 'path' | 'method' | 'contentType'
364
771
  pattern: string | RegExp
365
772
  options: PluginOptions
366
773
  }
774
+ examples:
775
+ - name: Use a different enum style for the user tag
776
+ files:
777
+ - name: kubb.config.ts
778
+ lang: typescript
779
+ twoslash: false
780
+ code: |
781
+ import { defineConfig } from 'kubb'
782
+ import { pluginTs } from '@kubb/plugin-ts'
783
+
784
+ export default defineConfig({
785
+ input: { path: './petStore.yaml' },
786
+ output: { path: './src/gen' },
787
+ plugins: [
788
+ pluginTs({
789
+ enumType: 'asConst',
790
+ override: [
791
+ {
792
+ type: 'tag',
793
+ pattern: 'user',
794
+ options: { enumType: 'literal' },
795
+ },
796
+ ],
797
+ }),
798
+ ],
799
+ })
367
800
  - name: generators
368
801
  type: Array<Generator<PluginCypress>>
369
802
  required: false
370
803
  experimental: true
371
804
  description: |
372
- Define additional generators next to the built-in generators.
805
+ Adds custom generators that run alongside the plugin's built-in generators. Each generator can emit additional files or post-process existing ones using the plugin's AST and options.
373
806
 
374
- See [Generators](https://kubb.dev/docs/5.x/guides/creating-plugins) for more information on how to use generators.
807
+ Use this when you need output the plugin does not produce out of the box (a custom client wrapper, an extra index, a metadata file). For end-to-end guidance, see [Creating plugins](https://kubb.dev/docs/5.x/guides/creating-plugins).
808
+ warning: |
809
+ Generators are an experimental, low-level API. The signature may change between minor releases.
375
810
  - name: transformer
376
811
  type: Visitor
377
812
  required: false
378
813
  description: |
379
- A single AST visitor applied to every node before code is printed. Each method you provide replaces the corresponding built-in one. When a method returns `null` or `undefined`, the preset transformer's result is used as the fallback — so you only need to supply the methods you want to change.
814
+ Modifies AST nodes before they are printed to source code. Use this when you need to rewrite operation IDs, drop descriptions, or change schema metadata without forking the generator.
380
815
 
381
- Visitor methods receive the node and a context object. Return a modified node to replace it, or return `undefined`/`void` to leave it unchanged.
816
+ Each visitor method (e.g. `schema`, `operation`) receives the node and a context object. Return a new node to replace it, or return `undefined` to leave it untouched. Methods you omit keep the plugin's default behavior.
382
817
  examples:
383
818
  - name: Strip descriptions before printing
384
819
  files:
385
- - lang: typescript
820
+ - name: kubb.config.ts
821
+ lang: typescript
822
+ twoslash: false
386
823
  code: |
824
+ import { defineConfig } from 'kubb'
387
825
  import { pluginTs } from '@kubb/plugin-ts'
388
826
 
389
- pluginTs({
390
- transformer: {
391
- schema(node) {
392
- return { ...node, description: undefined }
393
- },
394
- },
827
+ export default defineConfig({
828
+ input: { path: './petStore.yaml' },
829
+ output: { path: './src/gen' },
830
+ plugins: [
831
+ pluginTs({
832
+ transformer: {
833
+ schema(node) {
834
+ return { ...node, description: undefined }
835
+ },
836
+ },
837
+ }),
838
+ ],
395
839
  })
396
- twoslash: false
397
840
  - name: Prefix every operationId
398
841
  files:
399
- - lang: typescript
842
+ - name: kubb.config.ts
843
+ lang: typescript
844
+ twoslash: false
400
845
  code: |
846
+ import { defineConfig } from 'kubb'
401
847
  import { pluginTs } from '@kubb/plugin-ts'
402
848
 
403
- pluginTs({
404
- transformer: {
405
- operation(node) {
406
- return { ...node, operationId: `api_${node.operationId}` }
407
- },
408
- },
849
+ export default defineConfig({
850
+ input: { path: './petStore.yaml' },
851
+ output: { path: './src/gen' },
852
+ plugins: [
853
+ pluginTs({
854
+ transformer: {
855
+ operation(node) {
856
+ return { ...node, operationId: `api_${node.operationId}` }
857
+ },
858
+ },
859
+ }),
860
+ ],
409
861
  })
410
- twoslash: false
411
862
  tip: |
412
- Use `transformer` to rewrite node properties before printing. For output naming customization, use `resolver` instead.
863
+ Use `transformer` to rewrite node properties before printing. For changing the names of generated symbols and files, use `resolver` instead.
413
864
  examples:
414
865
  - name: kubb.config.ts
415
866
  files:
416
867
  - lang: typescript
868
+ twoslash: false
417
869
  code: |
418
870
  import { defineConfig } from 'kubb'
419
871
  import { pluginTs } from '@kubb/plugin-ts'
420
872
  import { pluginCypress } from '@kubb/plugin-cypress'
421
873
 
422
874
  export default defineConfig({
423
- input: {
424
- path: './petStore.yaml',
425
- },
426
- output: {
427
- path: './src/gen',
428
- },
875
+ input: { path: './petStore.yaml' },
876
+ output: { path: './src/gen' },
429
877
  plugins: [
430
878
  pluginTs(),
431
879
  pluginCypress({
432
880
  output: {
433
881
  path: './cypress',
434
882
  barrel: { type: 'named' },
435
- banner: '/* eslint-disable no-alert, no-console */',
883
+ banner: '/* eslint-disable */',
436
884
  },
437
885
  group: {
438
886
  type: 'tag',
@@ -441,4 +889,18 @@ examples:
441
889
  }),
442
890
  ],
443
891
  })
892
+ - name: Using a generated helper
893
+ files:
894
+ - lang: typescript
444
895
  twoslash: false
896
+ code: |
897
+ import { getPetByIdRequest } from '../gen/cypress/petRequests'
898
+
899
+ describe('Pet API', () => {
900
+ it('returns the pet by id', () => {
901
+ getPetByIdRequest(1).then((response) => {
902
+ expect(response.status).to.eq(200)
903
+ expect(response.body.id).to.eq(1)
904
+ })
905
+ })
906
+ })