@kubb/plugin-zod 5.0.0-beta.3 → 5.0.0-beta.4

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.
Files changed (2) hide show
  1. package/extension.yaml +502 -0
  2. package/package.json +5 -5
package/extension.yaml ADDED
@@ -0,0 +1,502 @@
1
+ $schema: https://kubb.dev/schemas/extension.json
2
+ kind: plugin
3
+ id: plugin-zod
4
+ name: Zod
5
+ description: Generate Zod validation schemas from OpenAPI specifications for runtime data validation.
6
+ category: validation
7
+ type: official
8
+ npmPackage: "@kubb/plugin-zod"
9
+ docsPath: /plugins/plugin-zod
10
+ repo: https://github.com/kubb-labs/plugins
11
+ maintainers:
12
+ - name: Stijn Van Hulle
13
+ github: stijnvanhulle
14
+ compatibility:
15
+ kubb: ">=5.0.0"
16
+ node: ">=22"
17
+ tags:
18
+ - zod
19
+ - validation
20
+ - schema
21
+ - runtime-validation
22
+ - codegen
23
+ - openapi
24
+ dependencies: []
25
+ resources:
26
+ documentation: https://kubb.dev/plugins/plugin-zod
27
+ repository: https://github.com/kubb-labs/plugins
28
+ issues: https://github.com/kubb-labs/plugins/issues
29
+ changelog: https://github.com/kubb-labs/plugins/blob/main/packages/plugin-zod/CHANGELOG.md
30
+ codesandbox: https://codesandbox.io/p/github/kubb-labs/plugins/main/examples/zod
31
+ featured: true
32
+ icon:
33
+ light: https://kubb.dev/feature/zod.svg
34
+ intro: |
35
+ # @kubb/plugin-zod
36
+
37
+ Generate [Zod](https://zod.dev/) validation schemas from your OpenAPI schema for runtime validation. Kubb generates Zod v4 schemas.
38
+ options:
39
+ - name: output
40
+ type: Output
41
+ required: false
42
+ default: "{ path: 'zod', barrelType: 'named' }"
43
+ description: Specify the export location for the files and define the behavior of the output.
44
+ properties:
45
+ - name: path
46
+ type: string
47
+ required: true
48
+ description: Output directory or file for the generated code, relative to the global `output.path`.
49
+ tip: |
50
+ if `output.path` is a file, `group` cannot be used.
51
+ default: "'zod'"
52
+ - name: barrelType
53
+ type: "'all' | 'named' | 'propagate' | false"
54
+ required: false
55
+ default: "'named'"
56
+ description: Specify what to export and optionally disable barrel-file generation.
57
+ tip: |
58
+ Using `propagate` will prevent a plugin from creating a barrel file, but it will still propagate, allowing [`output.barrelType`](https://kubb.dev/docs/5.x/configuration#output-barreltype) to export the specific function or type.
59
+ examples:
60
+ - name: all
61
+ files:
62
+ - lang: typescript
63
+ code: |
64
+ export * from './gen/petService.ts'
65
+ twoslash: false
66
+ - name: named
67
+ files:
68
+ - lang: typescript
69
+ code: |
70
+ export { PetService } from './gen/petService.ts'
71
+ twoslash: false
72
+ - name: propagate
73
+ files:
74
+ - lang: typescript
75
+ code: ""
76
+ twoslash: false
77
+ - name: "false"
78
+ files:
79
+ - lang: typescript
80
+ code: ""
81
+ twoslash: false
82
+ - name: banner
83
+ type: "string | ((node: RootNode) => string)"
84
+ required: false
85
+ 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.
86
+ - name: footer
87
+ type: "string | ((node: RootNode) => string)"
88
+ required: false
89
+ 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.
90
+ - name: override
91
+ type: boolean
92
+ required: false
93
+ default: "false"
94
+ description: Whether Kubb overrides existing external files that can be generated if they already exist.
95
+ - name: resolver
96
+ type: Partial<ResolverZod> & ThisType<ResolverZod>
97
+ required: false
98
+ description: |
99
+ 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.
100
+
101
+ `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.
102
+ body: |
103
+ Each plugin ships a built-in resolver:
104
+
105
+ | Plugin | Default resolver |
106
+ | --- | --- |
107
+ | `@kubb/plugin-ts` | `resolverTs` |
108
+ | `@kubb/plugin-zod` | `resolverZod` |
109
+ | `@kubb/plugin-cypress` | `resolverCypress` |
110
+ | `@kubb/plugin-mcp` | `resolverMcp` |
111
+ codeBlock:
112
+ lang: typescript
113
+ title: Custom resolver (plugin-ts example)
114
+ code: |
115
+ import { pluginTs } from '@kubb/plugin-ts'
116
+
117
+ pluginTs({
118
+ resolver: {
119
+ resolveName(name) {
120
+ // Prefix every operation-derived name; falls back for names where
121
+ // this returns null/undefined.
122
+ return `Api${this.default(name, 'function')}`
123
+ },
124
+ },
125
+ })
126
+ tip: |
127
+ Use `resolver` for fine-grained control over naming conventions.
128
+ - name: group
129
+ type: Group
130
+ required: false
131
+ description: |
132
+ Grouping combines files in a folder based on a specific `type`.
133
+ examples:
134
+ - name: kubb.config.ts
135
+ files:
136
+ - lang: typescript
137
+ code: |
138
+ group: {
139
+ type: 'tag',
140
+ name({ group }) {
141
+ return `${group}Controller`
142
+ }
143
+ }
144
+ twoslash: false
145
+ body: |
146
+ With the configuration above, the generator emits:
147
+
148
+ ```text
149
+ .
150
+ ├── src/
151
+ │ └── petController/
152
+ │ │ ├── addPet.ts
153
+ │ │ └── getPet.ts
154
+ │ └── storeController/
155
+ │ ├── createStore.ts
156
+ │ └── getStoreById.ts
157
+ ├── petStore.yaml
158
+ ├── kubb.config.ts
159
+ └── package.json
160
+ ```
161
+ properties:
162
+ - name: type
163
+ type: "'tag'"
164
+ required: true
165
+ description: Specify the property to group files by. Required when `group` is defined.
166
+ note: |
167
+ `Required: true*` means this is required only when the `group` option is used. The `group` option itself is optional.
168
+ body: |
169
+ - `'tag'`: Uses the first tag from `operation.getTags().at(0)?.name`
170
+ - name: name
171
+ type: "(context: GroupContext) => string"
172
+ required: false
173
+ default: (ctx) => `${ctx.group}Controller`
174
+ description: Return the name of a group based on the group name. This is used for file and identifier generation.
175
+ - name: importPath
176
+ type: string
177
+ required: false
178
+ default: "'zod'"
179
+ description: |
180
+ Import path for Zod. Use `'zod/mini'` to import from Zod's mini bundle.
181
+ - name: typed
182
+ type: boolean
183
+ required: false
184
+ default: "false"
185
+ description: Annotate schemas with their TypeScript types from `@kubb/plugin-ts`. Requires `@kubb/plugin-ts` in the plugins array.
186
+ important: |
187
+ We rely on [`ToZod`](https://github.com/colinhacks/tozod) from the creator of Zod to create a schema based on a type.
188
+ Kubb contains its own version to those kind of conversions.
189
+ - name: inferred
190
+ type: boolean
191
+ required: false
192
+ default: "false"
193
+ description: Export a `z.infer<typeof schema>` type alias for each schema to keep types in sync with validation.
194
+ codeBlock:
195
+ lang: typescript
196
+ title: "inferred: true"
197
+ code: |
198
+ import { z } from 'zod'
199
+
200
+ export const petSchema = z.object({
201
+ name: z.string(),
202
+ status: z.enum(['available', 'pending', 'sold']).optional(),
203
+ })
204
+
205
+ // Inferred type export
206
+ export type Pet = z.infer<typeof petSchema>
207
+ - name: integerType
208
+ warning: |
209
+ This option has been moved to [`adapterOas`](/adapters/adapter-oas#integerType). Use `adapterOas({ integerType })` instead.
210
+ - name: unknownType
211
+ warning: |
212
+ This option has been moved to [`adapterOas`](/adapters/adapter-oas#unknownType). Use `adapterOas({ unknownType })` instead.
213
+ - name: emptySchemaType
214
+ warning: |
215
+ This option has been moved to [`adapterOas`](/adapters/adapter-oas#emptySchemaType). Use `adapterOas({ emptySchemaType })` instead.
216
+ - name: coercion
217
+ type: "boolean | { dates?: boolean, strings?: boolean, numbers?: boolean }"
218
+ required: false
219
+ default: "false"
220
+ description: Apply `z.coerce` to automatically convert input values to the expected type before validation. Pass `true` to coerce all primitives, or an object to selectively enable coercion for `dates`, `strings`, and `numbers`. See [Coercion for primitives](https://zod.dev/?id=coercion-for-primitives).
221
+ examples:
222
+ - name: "true"
223
+ files:
224
+ - lang: typescript
225
+ code: |
226
+ z.coerce.string();
227
+ z.coerce.date();
228
+ z.coerce.number();
229
+ twoslash: false
230
+ - name: "false"
231
+ files:
232
+ - lang: typescript
233
+ code: |
234
+ z.string();
235
+ z.date();
236
+ z.number();
237
+ twoslash: false
238
+ - name: "{numbers: true, strings: false, dates: false}"
239
+ files:
240
+ - lang: typescript
241
+ code: |
242
+ z.string();
243
+ z.date();
244
+ z.coerce.number();
245
+ twoslash: false
246
+ - name: operations
247
+ type: boolean
248
+ required: false
249
+ default: "false"
250
+ description: Generate an `operations.ts` file with schemas for each operation, including request and response data.
251
+ - name: paramsCasing
252
+ type: "'camelcase'"
253
+ required: false
254
+ description: Transform parameter property names to camelCase.
255
+ codeBlock:
256
+ lang: typescript
257
+ title: "'camelcase'"
258
+ code: |
259
+ // OpenAPI spec uses: pet_id, X-Api-Key
260
+
261
+ type GetPetPathParams = {
262
+ petId: string // ✓ camelCase
263
+ }
264
+
265
+ type GetPetHeaderParams = {
266
+ xApiKey?: string // ✓ camelCase
267
+ }
268
+ - name: guidType
269
+ type: "'uuid' | 'guid'"
270
+ required: false
271
+ default: "'uuid'"
272
+ description: |
273
+ Validator to use for OpenAPI properties with `format: uuid`. Use `'guid'` to generate `.guid()` validation instead of the default `.uuid()`.
274
+ examples:
275
+ - name: "'uuid' (default)"
276
+ files:
277
+ - lang: typescript
278
+ code: |
279
+ z.uuid()
280
+ twoslash: false
281
+ - name: "'guid'"
282
+ files:
283
+ - lang: typescript
284
+ code: |
285
+ z.guid()
286
+ twoslash: false
287
+ - name: mini
288
+ type: boolean
289
+ required: false
290
+ default: "false"
291
+ badge:
292
+ type: tip
293
+ text: beta
294
+ description: |
295
+ Use Zod Mini's functional API for better tree-shaking support.
296
+
297
+ When enabled, generates functional syntax (e.g., `z.optional(z.string())`) instead of chainable methods (e.g., `z.string().optional()`).
298
+
299
+ When `mini: true`, `importPath` will default to `'zod/mini'`.
300
+ warning: |
301
+ This feature is currently in beta. The API may change in future releases.
302
+ tip: |
303
+ Zod Mini provides a smaller bundle size with better tree-shaking. See [Zod Mini documentation](https://zod.dev/packages/mini) for more details.
304
+ examples:
305
+ - name: "mini: true"
306
+ files:
307
+ - lang: typescript
308
+ code: |
309
+ // Import from zod/mini
310
+ import { z } from 'zod/mini'
311
+
312
+ // Functional syntax for better tree-shaking
313
+ z.optional(z.string())
314
+ z.nullable(z.number())
315
+ z.array(z.string()).check(z.minLength(1), z.maxLength(10))
316
+ twoslash: false
317
+ - name: "mini: false (default)"
318
+ files:
319
+ - lang: typescript
320
+ code: |
321
+ // Import from zod or zod/v4
322
+ import { z } from 'zod'
323
+
324
+ // Chainable method syntax
325
+ z.string().optional()
326
+ z.number().nullable()
327
+ z.array(z.string()).min(1).max(10)
328
+ twoslash: false
329
+ - name: include
330
+ type: Array<Include>
331
+ required: false
332
+ description: Array containing include parameters to include tags, operations, methods, paths, or content types.
333
+ codeBlock:
334
+ lang: typescript
335
+ title: Include
336
+ code: |
337
+ export type Include = {
338
+ type: 'tag' | 'operationId' | 'path' | 'method' | 'contentType'
339
+ pattern: string | RegExp
340
+ }
341
+ - name: exclude
342
+ type: Array<Exclude>
343
+ required: false
344
+ description: Array containing exclude parameters to exclude or skip tags, operations, methods, paths, or content types.
345
+ codeBlock:
346
+ lang: typescript
347
+ title: Exclude
348
+ code: |
349
+ export type Exclude = {
350
+ type: 'tag' | 'operationId' | 'path' | 'method' | 'contentType'
351
+ pattern: string | RegExp
352
+ }
353
+ - name: override
354
+ type: Array<Override>
355
+ required: false
356
+ description: Array containing override parameters to override `options` based on tags, operations, methods, paths, or content types.
357
+ codeBlock:
358
+ lang: typescript
359
+ title: Override
360
+ code: |
361
+ export type Override = {
362
+ type: 'tag' | 'operationId' | 'path' | 'method' | 'contentType'
363
+ pattern: string | RegExp
364
+ options: PluginOptions
365
+ }
366
+ - name: generators
367
+ type: Array<Generator<PluginZod>>
368
+ required: false
369
+ experimental: true
370
+ description: |
371
+ Define additional generators next to the built-in generators.
372
+
373
+ See [Generators](https://kubb.dev/docs/5.x/guides/creating-plugins) for more information on how to use generators.
374
+ - name: transformer
375
+ type: Visitor
376
+ required: false
377
+ description: |
378
+ 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.
379
+
380
+ Visitor methods receive the node and a context object. Return a modified node to replace it, or return `undefined`/`void` to leave it unchanged.
381
+ examples:
382
+ - name: Strip descriptions before printing
383
+ files:
384
+ - lang: typescript
385
+ code: |
386
+ import { pluginTs } from '@kubb/plugin-ts'
387
+
388
+ pluginTs({
389
+ transformer: {
390
+ schema(node) {
391
+ return { ...node, description: undefined }
392
+ },
393
+ },
394
+ })
395
+ twoslash: false
396
+ - name: Prefix every operationId
397
+ files:
398
+ - lang: typescript
399
+ code: |
400
+ import { pluginTs } from '@kubb/plugin-ts'
401
+
402
+ pluginTs({
403
+ transformer: {
404
+ operation(node) {
405
+ return { ...node, operationId: `api_${node.operationId}` }
406
+ },
407
+ },
408
+ })
409
+ twoslash: false
410
+ tip: |
411
+ Use `transformer` to rewrite node properties before printing. For output naming customization, use `resolver` instead.
412
+ - name: printer
413
+ type: "{ nodes?: PrinterZodNodes | PrinterZodMiniNodes }"
414
+ required: false
415
+ description: |
416
+ Override individual printer node handlers to customize how specific schema types are rendered. When `mini: true` the overrides apply to the Zod Mini printer.
417
+
418
+ Each key is a `SchemaType` (e.g. `'integer'`, `'date'`). The function you provide replaces the built-in handler for that type. Use `this.transform` to recurse into nested schema nodes.
419
+ examples:
420
+ - name: Override integer to z.number()
421
+ files:
422
+ - lang: typescript
423
+ code: |
424
+ import { pluginZod } from '@kubb/plugin-zod'
425
+
426
+ pluginZod({
427
+ printer: {
428
+ nodes: {
429
+ integer() {
430
+ return 'z.number()'
431
+ },
432
+ },
433
+ },
434
+ })
435
+ twoslash: false
436
+ - name: Override date to z.string().date()
437
+ files:
438
+ - lang: typescript
439
+ code: |
440
+ import { pluginZod } from '@kubb/plugin-zod'
441
+
442
+ pluginZod({
443
+ printer: {
444
+ nodes: {
445
+ date(node) {
446
+ return 'z.string().date()'
447
+ },
448
+ },
449
+ },
450
+ })
451
+ twoslash: false
452
+ - name: wrapOutput
453
+ type: "(arg: { output: string; schema: SchemaNode }) => string | undefined"
454
+ required: false
455
+ description: Wrap the generated Zod schema string with additional validation or metadata. The callback receives the schema's output string and the `SchemaNode` AST node, and returns the modified schema string.
456
+ tip: |
457
+ This is useful for cases where you need to extend the generated zod output with additional properties from an OpenAPI schema. E.g. in the case of `OpenAPI -> Zod -> OpenAPI`, you could include the examples from the schema for a given property and then ultimately provide a modified schema to a router that supports zod and OpenAPI spec generation.
458
+ codeBlock:
459
+ lang: typescript
460
+ title: Conditionally append .openapi() to the generated schema
461
+ code: |
462
+ wrapOutput: ({ output, schema }) => {
463
+ const metadata: Record<string, unknown> = {};
464
+
465
+ if (schema.keywords?.includes('example')) {
466
+ // access SchemaNode properties
467
+ }
468
+
469
+ if (Object.keys(metadata).length > 0) {
470
+ return `${output}.openapi(${JSON.stringify(metadata)})`;
471
+ }
472
+ };
473
+ examples:
474
+ - name: kubb.config.ts
475
+ files:
476
+ - lang: typescript
477
+ code: |
478
+ import { defineConfig } from 'kubb';
479
+ import { pluginTs } from '@kubb/plugin-ts';
480
+ import { pluginZod } from '@kubb/plugin-zod';
481
+
482
+ export default defineConfig({
483
+ input: {
484
+ path: './petStore.yaml',
485
+ },
486
+ output: {
487
+ path: './src/gen',
488
+ },
489
+ plugins: [
490
+ pluginTs(),
491
+ pluginZod({
492
+ output: {
493
+ path: './zod',
494
+ },
495
+ group: { type: 'tag', name: ({ group }) => `${group}Schemas` },
496
+ typed: true,
497
+ dateType: 'stringOffset',
498
+ importPath: 'zod',
499
+ }),
500
+ ],
501
+ });
502
+ twoslash: false
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kubb/plugin-zod",
3
- "version": "5.0.0-beta.3",
3
+ "version": "5.0.0-beta.4",
4
4
  "description": "Zod schema generator plugin for Kubb, creating type-safe validation schemas from OpenAPI specifications for runtime data validation.",
5
5
  "keywords": [
6
6
  "code-generator",
@@ -30,7 +30,7 @@
30
30
  "src",
31
31
  "templates",
32
32
  "dist",
33
- "plugin.json",
33
+ "extension.yaml",
34
34
  "!/**/**.test.**",
35
35
  "!/**/__tests__/**",
36
36
  "!/**/__snapshots__/**"
@@ -52,15 +52,15 @@
52
52
  "registry": "https://registry.npmjs.org/"
53
53
  },
54
54
  "dependencies": {
55
- "@kubb/core": "5.0.0-beta.3",
56
- "@kubb/renderer-jsx": "5.0.0-beta.3",
55
+ "@kubb/core": "5.0.0-beta.4",
56
+ "@kubb/renderer-jsx": "5.0.0-beta.4",
57
57
  "remeda": "^2.34.0"
58
58
  },
59
59
  "devDependencies": {
60
60
  "@internals/utils": "0.0.0"
61
61
  },
62
62
  "peerDependencies": {
63
- "@kubb/renderer-jsx": "5.0.0-beta.3"
63
+ "@kubb/renderer-jsx": "5.0.0-beta.4"
64
64
  },
65
65
  "size-limit": [
66
66
  {