@kubb/plugin-zod 5.4.5 → 5.4.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/index.cjs +10 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +11 -4
- package/dist/index.js.map +1 -1
- package/docs/guides/customization.md +148 -0
- package/docs/options.md +273 -0
- package/docs/overview.md +40 -0
- package/kubb-extension.json +210 -0
- package/package.json +8 -5
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# Customize generated schemas
|
|
2
|
+
|
|
3
|
+
Prefix inferred types, change Zod validators, and encode custom request types.
|
|
4
|
+
|
|
5
|
+
Start with the [Zod plugin configuration](https://kubb.dev/extensions/kubb-labs/plugin-zod#example). Apply these changes to `pluginZod()` in that configuration.
|
|
6
|
+
|
|
7
|
+
## Prefix inferred types
|
|
8
|
+
|
|
9
|
+
Enable `inferred` and override `resolver.schema.typeName`.
|
|
10
|
+
|
|
11
|
+
```typescript [kubb.config.ts]
|
|
12
|
+
import { pluginZod } from '@kubb/plugin-zod'
|
|
13
|
+
|
|
14
|
+
pluginZod({
|
|
15
|
+
inferred: true,
|
|
16
|
+
resolver: {
|
|
17
|
+
schema: {
|
|
18
|
+
typeName(name) {
|
|
19
|
+
return 'Api' + name
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
})
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
The type becomes `ApiPet`. The schema constant stays `petSchema`. The callback receives the cased type name, so no additional casing helper is needed.
|
|
27
|
+
|
|
28
|
+
## Use numbers for int64 fields
|
|
29
|
+
|
|
30
|
+
Replace the `bigint` printer handler to validate `int64` fields with `z.int()`.
|
|
31
|
+
|
|
32
|
+
```typescript [kubb.config.ts]
|
|
33
|
+
import { pluginZod } from '@kubb/plugin-zod'
|
|
34
|
+
|
|
35
|
+
pluginZod({
|
|
36
|
+
printer: {
|
|
37
|
+
nodes: {
|
|
38
|
+
bigint() {
|
|
39
|
+
return 'z.int()'
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
})
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The `integer` handler controls `int32` fields separately. To change integer representation across all plugins, use the adapter's [`integerType`](https://kubb.dev/extensions/kubb-labs/adapter-oas/options#integertype).
|
|
47
|
+
|
|
48
|
+
## Remove descriptions
|
|
49
|
+
|
|
50
|
+
Use the [description-removal macro](https://kubb.dev/extensions/kubb-labs/plugin-ts/guides/customization#remove-descriptions) with `pluginZod({ macros: [dropDescriptions] })`. Generated schemas omit description metadata.
|
|
51
|
+
|
|
52
|
+
## Encode custom types
|
|
53
|
+
|
|
54
|
+
A direction-aware printer decodes response values and encodes request values. This example converts ISO time strings to `Temporal.PlainTime`.
|
|
55
|
+
|
|
56
|
+
```typescript [kubb.config.ts]
|
|
57
|
+
import { pluginZod, type PrinterZodNodes } from '@kubb/plugin-zod'
|
|
58
|
+
|
|
59
|
+
const nodes: PrinterZodNodes = {
|
|
60
|
+
time() {
|
|
61
|
+
return this.options.direction === 'encode'
|
|
62
|
+
? 'z.instanceof(Temporal.PlainTime).transform((value) => value.toString())'
|
|
63
|
+
: 'z.iso.time().transform((value) => Temporal.PlainTime.from(value))'
|
|
64
|
+
},
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
pluginZod({ inferred: true, printer: { nodes } })
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Use a runtime that provides `Temporal`, or add its polyfill through a generated import or banner. Match the OpenAPI format: `time`, `date`, and `date-time` use `time`, `date`, and `datetime` handlers.
|
|
71
|
+
|
|
72
|
+
The generator emits separate response and input schemas, including through `$ref`:
|
|
73
|
+
|
|
74
|
+
```typescript [src/gen/zod/slotSchema.ts]
|
|
75
|
+
export const slotSchema = z.object({
|
|
76
|
+
startsAt: z.iso.time().transform((value) => Temporal.PlainTime.from(value)),
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
export const slotInputSchema = z.object({
|
|
80
|
+
startsAt: z.instanceof(Temporal.PlainTime).transform((value) => value.toString()),
|
|
81
|
+
})
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
> [!IMPORTANT]
|
|
85
|
+
> Use `inferred: true` without `pluginTs` so the client types follow these conversions. Types from `pluginTs` describe the wire format.
|
|
86
|
+
|
|
87
|
+
For built-in date conversion, set `dateType: 'date'` on the adapter. Generated response schemas convert ISO datetimes to `Date`. Request schemas convert them back with `toISOString()`.
|
|
88
|
+
|
|
89
|
+
## Import a custom codec
|
|
90
|
+
|
|
91
|
+
Override a printer node and register the package import with `this.import`. For example, use your package's `myCodec.uint64()` for `int64` fields:
|
|
92
|
+
|
|
93
|
+
```typescript [kubb.config.ts]
|
|
94
|
+
import { ast } from 'kubb/kit'
|
|
95
|
+
import { pluginZod } from '@kubb/plugin-zod'
|
|
96
|
+
|
|
97
|
+
pluginZod({
|
|
98
|
+
printer: {
|
|
99
|
+
nodes: {
|
|
100
|
+
bigint() {
|
|
101
|
+
this.import(ast.factory.createImport({
|
|
102
|
+
name: ['myCodec'],
|
|
103
|
+
path: 'my-codec/zod',
|
|
104
|
+
}))
|
|
105
|
+
return 'myCodec.uint64()'
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
})
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Generated files import `myCodec` from `my-codec/zod`. Leave `root` unset on this import to preserve the package specifier. Setting `root` rewrites it as a relative file path.
|
|
113
|
+
|
|
114
|
+
## Format and type mappings
|
|
115
|
+
|
|
116
|
+
`@kubb/plugin-zod` maps OpenAPI types and formats to Zod v4:
|
|
117
|
+
|
|
118
|
+
| OpenAPI type and format | Zod | Zod Mini | Notes |
|
|
119
|
+
| :----------------------------------------- | :------------------------------------ | :------------------------------------ | :---------------------------------------------------------------------- |
|
|
120
|
+
| `integer` | `z.int()` | `z.int()` | Coerces to `z.coerce.number().int()` when `coercion.numbers` is enabled |
|
|
121
|
+
| `integer`, `format: int32` | `z.int32()` | `z.int32()` | 32-bit signed integer |
|
|
122
|
+
| `integer`, `format: uint32` | `z.uint32()` | `z.uint32()` | 32-bit unsigned integer |
|
|
123
|
+
| `integer`, `format: int64` | `z.bigint()` | `z.bigint()` | 64-bit integer |
|
|
124
|
+
| `string`, `format: byte` / `base64` | `z.base64()` | `z.base64()` | Base64 string validation |
|
|
125
|
+
| `string`, `format: base64url` | `z.base64url()` | `z.base64url()` | URL-safe base64 string validation |
|
|
126
|
+
| `string`, `format: jwt` | `z.jwt()` | `z.jwt()` | JSON Web Token format |
|
|
127
|
+
| `string`, `format: ulid` | `z.ulid()` | `z.ulid()` | ULID format |
|
|
128
|
+
| `string`, `format: iban` | `z.iban()` | `z.iban()` | International Bank Account Number |
|
|
129
|
+
| `string`, `format: duration` | `z.iso.duration()` | `z.iso.duration()` | ISO 8601 duration format |
|
|
130
|
+
| `string`, `format: uuid` | `z.uuid()` (or `z.guid()`) | `z.uuid()` (or `z.guid()`) | Configured via `guidType` |
|
|
131
|
+
| `string`, `format: email` | `z.email()` | `z.email()` | Email format |
|
|
132
|
+
| `string`, `format: uri` / `url` | `z.url()` | `z.url()` | URL format |
|
|
133
|
+
| `string`, `format: ipv4` / `ipv6` | `z.ipv4()` / `z.ipv6()` | `z.ipv4()` / `z.ipv6()` | IP address format |
|
|
134
|
+
| `string`, `format: date` | `z.iso.date()` | `z.iso.date()` | ISO 8601 date |
|
|
135
|
+
| `string`, `format: date-time` | `z.iso.datetime()` | `z.string()` | ISO 8601 date-time |
|
|
136
|
+
| `string`, `format: time` | `z.iso.time()` | `z.iso.time()` | ISO 8601 time |
|
|
137
|
+
| `object`, `additionalProperties: <schema>` | `z.record(z.string(), schema)` | `z.record(z.string(), schema)` | Dictionary with no fixed properties |
|
|
138
|
+
| `object`, `additionalProperties: true` | `z.looseObject(shape)` | `z.looseObject(shape)` | Open/passthrough object allowing extra keys |
|
|
139
|
+
| `object`, `propertyNames: <schema>` | `z.record(keySchema, schema)` | `z.record(keySchema, schema)` | Dynamic map with validated key schema (e.g. pattern, format) |
|
|
140
|
+
| `object`, `propertyNames: <enum>` | `z.partialRecord(enumSchema, schema)` | `z.partialRecord(enumSchema, schema)` | Enum keys may be missing |
|
|
141
|
+
|
|
142
|
+
## Dictionaries, open objects, and key schemas
|
|
143
|
+
|
|
144
|
+
OpenAPI 3.1 `propertyNames` validates dictionary keys. Open key schemas use `z.record(keySchema, valueSchema)`, including regex, UUID, and length constraints. Closed keys, such as enums, literals, or unions of enums, use `z.partialRecord` so only present keys are validated. Keys may be missing, as in OpenAPI, and the inferred type is `Partial<Record<Keys, Value>>`.
|
|
145
|
+
|
|
146
|
+
`patternProperties` combines key regex patterns into an alternation and emits `z.record(z.string().regex(...), valueSchema)`. Zod Mini uses `z.string().check(z.regex(...))` for the key schema.
|
|
147
|
+
|
|
148
|
+
An `additionalProperties` schema without fixed properties produces a dictionary. With fixed properties, it produces `.catchall(valueSchema)` to preserve that declared shape. `additionalProperties: true` emits `z.looseObject(shape)` to allow undeclared keys.
|
package/docs/options.md
ADDED
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
# Options
|
|
2
|
+
|
|
3
|
+
Pass these options to `pluginZod()`. Shared options link to [Shared plugin options](https://kubb.dev/docs/5.x/reference/plugin-options) for details.
|
|
4
|
+
|
|
5
|
+
## Options overview
|
|
6
|
+
|
|
7
|
+
| Option | Purpose | Default |
|
|
8
|
+
| ------------------------------------------------------------------------- | ---------------------------------------------------------------------- | -------------------------------------------- |
|
|
9
|
+
| [`output`](https://kubb.dev/docs/5.x/reference/plugin-options#output) | Where files are written: `path`, `mode`, `barrel`, `banner`, `footer`. | `{ path: 'zod', barrel: { type: 'named' } }` |
|
|
10
|
+
| [`group`](https://kubb.dev/docs/5.x/reference/plugin-options#group) | Split output by tag or path: `type`, `name`. | None |
|
|
11
|
+
| [`importPath`](#importpath) | Module the generated files import `z` from. | `'zod'`, or `'zod/mini'` with `mini` |
|
|
12
|
+
| [`inferred`](#inferred) | Emit a `z.infer` alias next to each schema. | `false` |
|
|
13
|
+
| [`coercion`](#coercion) | Coerce input before validation. | `false` |
|
|
14
|
+
| [`guidType`](#guidtype) | Validator for `format: uuid` properties. | `'uuid'` |
|
|
15
|
+
| [`regexType`](#regextype) | How an OpenAPI `pattern` is written. | `'literal'` |
|
|
16
|
+
| [`compile`](#compile) | Wrap schemas in `z.compile` for fast-path validation. | `false` |
|
|
17
|
+
| [`mini`](#mini) | Generate Zod Mini schemas. | `false` |
|
|
18
|
+
| [`typeGuards`](#typeguards) | Generate `is*` type guards and `assert*` assertions. | `false` |
|
|
19
|
+
| [`include`](https://kubb.dev/docs/5.x/reference/plugin-options#include) | Keep only operations and schemas that match. | None |
|
|
20
|
+
| [`exclude`](https://kubb.dev/docs/5.x/reference/plugin-options#exclude) | Skip operations and schemas that match. | `[]` |
|
|
21
|
+
| [`override`](https://kubb.dev/docs/5.x/reference/plugin-options#override) | Apply different options per pattern. | `[]` |
|
|
22
|
+
| [`resolver`](#resolver) | Customize generated names and file paths. | `resolverZod` |
|
|
23
|
+
| [`macros`](https://kubb.dev/docs/5.x/reference/plugin-options#macros) | Rewrite AST nodes before printing. | `[]` |
|
|
24
|
+
| [`printer`](#printer) | Replace the handler for a schema type. | None |
|
|
25
|
+
|
|
26
|
+
## Option details
|
|
27
|
+
|
|
28
|
+
### importPath
|
|
29
|
+
|
|
30
|
+
Module the generated files import `z` from. Point it at your own module to re-export Zod.
|
|
31
|
+
|
|
32
|
+
| | |
|
|
33
|
+
| -------- | --------------------------- |
|
|
34
|
+
| Type | `string` |
|
|
35
|
+
| Required | `false` |
|
|
36
|
+
| Default | `mini ? 'zod/mini' : 'zod'` |
|
|
37
|
+
|
|
38
|
+
`'zod'` and `'zod/mini'` are imported as `import * as z`. A custom module is imported as `import { z }`, so export `z` by name.
|
|
39
|
+
|
|
40
|
+
### inferred
|
|
41
|
+
|
|
42
|
+
Exports a `z.infer<typeof schema>` type next to each schema, so you do not need `@kubb/plugin-ts`. The type takes the PascalCase schema name plus `SchemaType`, so `petSchema` gets `PetSchemaType`.
|
|
43
|
+
|
|
44
|
+
| | |
|
|
45
|
+
| -------- | --------- |
|
|
46
|
+
| Type | `boolean` |
|
|
47
|
+
| Required | `false` |
|
|
48
|
+
| Default | `false` |
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
export type PetSchemaType = z.infer<typeof petSchema>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
It also writes a `ResponsesSchema` for each operation (one schema per status code) and its inferred type. [`@kubb/plugin-fetch`](https://kubb.dev/extensions/kubb-labs/plugin-fetch) and [`@kubb/plugin-axios`](https://kubb.dev/extensions/kubb-labs/plugin-axios) key their `RequestResult` on it when `@kubb/plugin-ts` is absent.
|
|
55
|
+
|
|
56
|
+
### coercion
|
|
57
|
+
|
|
58
|
+
Wraps schemas in `z.coerce` so input is coerced before validation, for form data, query params, and similar string sources. See [Coercion for primitives](https://zod.dev/?id=coercion-for-primitives).
|
|
59
|
+
|
|
60
|
+
| | |
|
|
61
|
+
| -------- | ---------------------------------------------------------------------- |
|
|
62
|
+
| Type | `boolean \| { dates?: boolean, strings?: boolean, numbers?: boolean }` |
|
|
63
|
+
| Required | `false` |
|
|
64
|
+
| Default | `false` |
|
|
65
|
+
|
|
66
|
+
::field-group
|
|
67
|
+
|
|
68
|
+
:::field{name="false"}
|
|
69
|
+
Coerces nothing and validates strictly, except `bigint` fields (`format: int64`), which always use `z.coerce.bigint()`.
|
|
70
|
+
:::
|
|
71
|
+
|
|
72
|
+
:::field{name="true"}
|
|
73
|
+
Coerces strings, numbers, and dates with `z.coerce.string()`, `z.coerce.number()` and `z.coerce.date()`.
|
|
74
|
+
:::
|
|
75
|
+
|
|
76
|
+
:::field{name="{ dates?, strings?, numbers? }"}
|
|
77
|
+
Chooses which primitives to coerce.
|
|
78
|
+
:::
|
|
79
|
+
|
|
80
|
+
::
|
|
81
|
+
|
|
82
|
+
> [!NOTE]
|
|
83
|
+
> `dates` coerces only `Date`-typed fields (from `dateType: 'date'`). ISO-string fields are never coerced, and neither are `format: time` fields, because `new Date()` cannot parse a bare `HH:mm:ss`. For a time-of-day type such as `Temporal.PlainTime`, see [Encode custom types](https://kubb.dev/extensions/kubb-labs/plugin-zod/guides/customization#encode-custom-types).
|
|
84
|
+
|
|
85
|
+
### guidType
|
|
86
|
+
|
|
87
|
+
Validator used for OpenAPI properties with `format: uuid`.
|
|
88
|
+
|
|
89
|
+
| | |
|
|
90
|
+
| -------- | ------------------ |
|
|
91
|
+
| Type | `'uuid' \| 'guid'` |
|
|
92
|
+
| Required | `false` |
|
|
93
|
+
| Default | `'uuid'` |
|
|
94
|
+
|
|
95
|
+
::field-group
|
|
96
|
+
|
|
97
|
+
:::field{name="'uuid'"}
|
|
98
|
+
Generates `z.uuid()`, a standard RFC 4122 UUID.
|
|
99
|
+
:::
|
|
100
|
+
|
|
101
|
+
:::field{name="'guid'"}
|
|
102
|
+
Generates `z.guid()`, which is looser and accepts Microsoft-style GUIDs.
|
|
103
|
+
:::
|
|
104
|
+
|
|
105
|
+
::
|
|
106
|
+
|
|
107
|
+
### regexType
|
|
108
|
+
|
|
109
|
+
Controls how an OpenAPI `pattern` is written inside `.regex(...)`. Use `'constructor'` when a regex literal breaks your build or you need a string pattern.
|
|
110
|
+
|
|
111
|
+
| | |
|
|
112
|
+
| -------- | ---------------------------- |
|
|
113
|
+
| Type | `'literal' \| 'constructor'` |
|
|
114
|
+
| Required | `false` |
|
|
115
|
+
| Default | `'literal'` |
|
|
116
|
+
|
|
117
|
+
::field-group
|
|
118
|
+
|
|
119
|
+
:::field{name="'literal'"}
|
|
120
|
+
Emits a regex literal, such as `.regex(/^[a-z]+$/)`.
|
|
121
|
+
:::
|
|
122
|
+
|
|
123
|
+
:::field{name="'constructor'"}
|
|
124
|
+
Emits the `RegExp` constructor, such as `.regex(new RegExp('^[a-z]+$'))`.
|
|
125
|
+
:::
|
|
126
|
+
|
|
127
|
+
::
|
|
128
|
+
|
|
129
|
+
### compile
|
|
130
|
+
|
|
131
|
+
Wraps schemas in `z.compile(...)` to generate validation code instead of interpreting the schema on each call. Needs Zod v4.5.0 or higher.
|
|
132
|
+
|
|
133
|
+
| | |
|
|
134
|
+
| -------- | --------------------------------- |
|
|
135
|
+
| Type | `boolean \| { strict?: boolean }` |
|
|
136
|
+
| Required | `false` |
|
|
137
|
+
| Default | `false` |
|
|
138
|
+
|
|
139
|
+
::field-group
|
|
140
|
+
|
|
141
|
+
:::field{name="false"}
|
|
142
|
+
Leaves schemas uncompiled.
|
|
143
|
+
:::
|
|
144
|
+
|
|
145
|
+
:::field{name="true"}
|
|
146
|
+
Compiles schemas using `z.compile(...)`.
|
|
147
|
+
:::
|
|
148
|
+
|
|
149
|
+
:::field{name="{ strict: true }"}
|
|
150
|
+
Passes `{ strict: true }` to `z.compile(...)`, which throws when any part of the schema cannot be compiled into flat JavaScript instead of falling back to the interpreter.
|
|
151
|
+
:::
|
|
152
|
+
|
|
153
|
+
::
|
|
154
|
+
|
|
155
|
+
Schemas with circular references (`z.lazy`) and bare `$ref` response aliases stay uncompiled to prevent runtime errors.
|
|
156
|
+
|
|
157
|
+
### mini
|
|
158
|
+
|
|
159
|
+
Generates [Zod Mini](https://zod.dev/packages/mini) schemas. They use functions (`z.optional(z.string())`) instead of method chains (`z.string().optional()`), so bundlers can drop unused validators. Also sets the `importPath` default to `'zod/mini'`.
|
|
160
|
+
|
|
161
|
+
| | |
|
|
162
|
+
| -------- | --------- |
|
|
163
|
+
| Type | `boolean` |
|
|
164
|
+
| Required | `false` |
|
|
165
|
+
| Default | `false` |
|
|
166
|
+
|
|
167
|
+
### typeGuards
|
|
168
|
+
|
|
169
|
+
Generates TypeScript type guards (`is*`) and assertion functions (`assert*`) with Zod's `validate` API. Needs Zod v4.6.0 or higher.
|
|
170
|
+
|
|
171
|
+
| | |
|
|
172
|
+
| -------- | ----------------------------------------------- |
|
|
173
|
+
| Type | `boolean \| { is?: boolean, assert?: boolean }` |
|
|
174
|
+
| Required | `false` |
|
|
175
|
+
| Default | `false` |
|
|
176
|
+
|
|
177
|
+
::field-group
|
|
178
|
+
|
|
179
|
+
:::field{name="false"}
|
|
180
|
+
Generates only the Zod schemas.
|
|
181
|
+
:::
|
|
182
|
+
|
|
183
|
+
:::field{name="true"}
|
|
184
|
+
Generates both `is<Schema>` type guards and `assert<Schema>` assertion functions.
|
|
185
|
+
:::
|
|
186
|
+
|
|
187
|
+
:::field{name="{ is?: boolean; assert?: boolean }"}
|
|
188
|
+
Enables type guards or assertions separately.
|
|
189
|
+
:::
|
|
190
|
+
|
|
191
|
+
::
|
|
192
|
+
|
|
193
|
+
When [`inferred`](#inferred) is `true`, the guards narrow to the generated type alias such as `PetSchemaType`. When [`mini`](#mini) is `true`, they route through `z.validate` and `z.parse`.
|
|
194
|
+
|
|
195
|
+
::code-collapse{name="Guards added to petSchema.ts with typeGuards: true"}
|
|
196
|
+
|
|
197
|
+
```typescript [src/gen/zod/petSchema.ts]
|
|
198
|
+
export const isPet = (data: unknown): data is z.infer<typeof petSchema> => petSchema.validate(data)
|
|
199
|
+
|
|
200
|
+
export function assertPet(data: unknown): asserts data is z.infer<typeof petSchema> {
|
|
201
|
+
if (!petSchema.validate(data)) {
|
|
202
|
+
petSchema.parse(data)
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
::
|
|
208
|
+
|
|
209
|
+
### resolver
|
|
210
|
+
|
|
211
|
+
Overrides generated file and symbol names. Omitted members keep `resolverZod`. The shared members (`name`, `file`, `imports`) and the `this` context are described under [`resolver`](https://kubb.dev/docs/5.x/reference/plugin-options#resolver).
|
|
212
|
+
|
|
213
|
+
| | |
|
|
214
|
+
| -------- | ---------------------------- |
|
|
215
|
+
| Type | `ResolverPatch<ResolverZod>` |
|
|
216
|
+
| Required | `false` |
|
|
217
|
+
|
|
218
|
+
::code-collapse{name="ResolverZod patch members"}
|
|
219
|
+
|
|
220
|
+
```typescript [Partial override]
|
|
221
|
+
type ResolverZodPatch = {
|
|
222
|
+
// plus the shared name, file, and imports members
|
|
223
|
+
schema?: {
|
|
224
|
+
typeName?(name: string): string
|
|
225
|
+
type?(name: string): string
|
|
226
|
+
inputName?(name: string): string
|
|
227
|
+
inputTypeName?(name: string): string
|
|
228
|
+
isName?(name: string): string
|
|
229
|
+
assertName?(name: string): string
|
|
230
|
+
}
|
|
231
|
+
param?: {
|
|
232
|
+
name?(node: OperationNode, param: ParameterNode): string
|
|
233
|
+
path?(node: OperationNode, param: ParameterNode): string
|
|
234
|
+
query?(node: OperationNode, param: ParameterNode): string
|
|
235
|
+
headers?(node: OperationNode, param: ParameterNode): string
|
|
236
|
+
}
|
|
237
|
+
response?: {
|
|
238
|
+
status?(node: OperationNode, statusCode: StatusCode): string
|
|
239
|
+
body?(node: OperationNode): string
|
|
240
|
+
responses?(node: OperationNode): string
|
|
241
|
+
response?(node: OperationNode): string
|
|
242
|
+
error?(node: OperationNode): string
|
|
243
|
+
options?(node: OperationNode): string
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
::
|
|
249
|
+
|
|
250
|
+
### printer
|
|
251
|
+
|
|
252
|
+
Replaces the handler for a schema type such as `'integer'` or `'string'`. Each handler returns the Zod expression as a string, in Zod Mini syntax when `mini: true`. Inside a handler, `this.base(node)` returns the built-in output to wrap and `this.transform(node)` recurses into nested nodes. See the [printer guide](https://kubb.dev/docs/5.x/how-to/printers).
|
|
253
|
+
|
|
254
|
+
| | |
|
|
255
|
+
| -------- | ---------------------------------------------------- |
|
|
256
|
+
| Type | `{ nodes?: PrinterZodNodes \| PrinterZodMiniNodes }` |
|
|
257
|
+
| Required | `false` |
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
import { pluginZod } from '@kubb/plugin-zod'
|
|
261
|
+
|
|
262
|
+
pluginZod({
|
|
263
|
+
printer: {
|
|
264
|
+
nodes: {
|
|
265
|
+
integer() {
|
|
266
|
+
return 'z.number()'
|
|
267
|
+
},
|
|
268
|
+
},
|
|
269
|
+
},
|
|
270
|
+
})
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
A handler can read `this.options.direction`, which is `'decode'` for responses and `'encode'` for request bodies and parameters. If it returns a different expression per direction, Kubb also writes an `${name}InputSchema`. Request bodies use it, including bodies that reach the schema through a `$ref`. See [Encode custom types](https://kubb.dev/extensions/kubb-labs/plugin-zod/guides/customization#encode-custom-types).
|
package/docs/overview.md
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Zod
|
|
2
|
+
|
|
3
|
+
Generates Zod v4 schemas from your OpenAPI spec. Use them to validate API responses, form input, and query params at runtime.
|
|
4
|
+
|
|
5
|
+
The schemas need no other plugin. With `inferred: true`, the plugin also exports a `z.infer` type next to each schema, so you can skip `@kubb/plugin-ts`. Client plugins such as `@kubb/plugin-fetch` and `@kubb/plugin-axios` use these schemas when you set their `validator` option.
|
|
6
|
+
|
|
7
|
+
## Setup
|
|
8
|
+
|
|
9
|
+
Install Zod v4 or higher in the app that uses the generated code. No other plugins are needed.
|
|
10
|
+
|
|
11
|
+
## Options worth knowing
|
|
12
|
+
|
|
13
|
+
- `mini` generates Zod Mini schemas for smaller bundles, and switches `importPath` to `zod/mini`.
|
|
14
|
+
- `importPath` sets the module the files import `z` from. The default is `zod`.
|
|
15
|
+
- `inferred` exports a `z.infer` type alias next to each schema.
|
|
16
|
+
- `coercion` wraps schemas in `z.coerce`, so input is converted before validation. Pass an object to coerce only dates, strings, or numbers.
|
|
17
|
+
- `guidType` picks `z.uuid()` (default) or `z.guid()` for `format: uuid`.
|
|
18
|
+
- `regexType` writes a `pattern` as a regex literal (default) or a `RegExp` constructor.
|
|
19
|
+
- `typeGuards` adds `is*` type guards and `assert*` assertions.
|
|
20
|
+
- `compile` wraps schemas in `z.compile` for faster validation.
|
|
21
|
+
|
|
22
|
+
## Example
|
|
23
|
+
|
|
24
|
+
```typescript [kubb.config.ts]
|
|
25
|
+
import { defineConfig } from 'kubb/config'
|
|
26
|
+
import { pluginZod } from '@kubb/plugin-zod'
|
|
27
|
+
|
|
28
|
+
export default defineConfig({
|
|
29
|
+
input: './petStore.yaml',
|
|
30
|
+
output: { path: './src/gen' },
|
|
31
|
+
plugins: [
|
|
32
|
+
pluginZod({ inferred: true }),
|
|
33
|
+
],
|
|
34
|
+
})
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## See also
|
|
38
|
+
|
|
39
|
+
- [Zod](https://zod.dev/)
|
|
40
|
+
- [Zod Mini](https://zod.dev/packages/mini)
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://kubb.dev/schemas/kubb-extension.json",
|
|
3
|
+
"kind": "plugin",
|
|
4
|
+
"name": "plugin-zod",
|
|
5
|
+
"export": "pluginZod",
|
|
6
|
+
"displayName": "Zod",
|
|
7
|
+
"description": "Generates Zod v4 schemas from your OpenAPI spec so you validate API responses, form input, and query params at runtime.",
|
|
8
|
+
"category": "validation",
|
|
9
|
+
"icon": {
|
|
10
|
+
"light": "https://kubb.dev/feature/zod.svg"
|
|
11
|
+
},
|
|
12
|
+
"tags": ["zod", "validation", "schema", "runtime-validation", "codegen", "openapi"],
|
|
13
|
+
"docs": "https://kubb.dev/extensions/kubb-labs/plugin-zod",
|
|
14
|
+
"maintainers": [
|
|
15
|
+
{
|
|
16
|
+
"name": "Stijn Van Hulle",
|
|
17
|
+
"github": "stijnvanhulle"
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
"compatibility": {
|
|
21
|
+
"kubb": ">=5.8.3",
|
|
22
|
+
"node": ">=22"
|
|
23
|
+
},
|
|
24
|
+
"options": [
|
|
25
|
+
{
|
|
26
|
+
"key": "outputPath",
|
|
27
|
+
"path": ["output", "path"],
|
|
28
|
+
"label": "Output Path",
|
|
29
|
+
"description": "Output folder for generated files",
|
|
30
|
+
"type": "text",
|
|
31
|
+
"default": "zod"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"key": "barrel",
|
|
35
|
+
"path": ["output", "barrel"],
|
|
36
|
+
"label": "Barrel",
|
|
37
|
+
"description": "How index.ts barrel files are generated",
|
|
38
|
+
"type": "select",
|
|
39
|
+
"default": {
|
|
40
|
+
"type": "named"
|
|
41
|
+
},
|
|
42
|
+
"choices": [
|
|
43
|
+
{
|
|
44
|
+
"label": "named",
|
|
45
|
+
"value": {
|
|
46
|
+
"type": "named"
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"label": "named (nested)",
|
|
51
|
+
"value": {
|
|
52
|
+
"type": "named",
|
|
53
|
+
"nested": true
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"label": "all",
|
|
58
|
+
"value": {
|
|
59
|
+
"type": "all"
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"label": "all (nested)",
|
|
64
|
+
"value": {
|
|
65
|
+
"type": "all",
|
|
66
|
+
"nested": true
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"label": "false (disabled)",
|
|
71
|
+
"value": false
|
|
72
|
+
}
|
|
73
|
+
]
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"key": "outputMode",
|
|
77
|
+
"path": ["output", "mode"],
|
|
78
|
+
"label": "Output Mode",
|
|
79
|
+
"description": "How the plugin consolidates its code into files. File mode writes everything into a single file, so the output path must include a file extension and cannot be grouped.",
|
|
80
|
+
"type": "select",
|
|
81
|
+
"default": "directory",
|
|
82
|
+
"choices": [
|
|
83
|
+
{
|
|
84
|
+
"label": "directory (one file per schema)",
|
|
85
|
+
"value": "directory"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"label": "file (single file)",
|
|
89
|
+
"value": "file"
|
|
90
|
+
}
|
|
91
|
+
]
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"key": "group",
|
|
95
|
+
"path": ["group"],
|
|
96
|
+
"label": "Group",
|
|
97
|
+
"description": "Group generated operations by OpenAPI tag or path",
|
|
98
|
+
"type": "select",
|
|
99
|
+
"default": null,
|
|
100
|
+
"choices": [
|
|
101
|
+
{
|
|
102
|
+
"label": "none",
|
|
103
|
+
"value": null
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"label": "by tag",
|
|
107
|
+
"value": {
|
|
108
|
+
"type": "tag"
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"label": "by path",
|
|
113
|
+
"value": {
|
|
114
|
+
"type": "path"
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
]
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"key": "excludeTags",
|
|
121
|
+
"path": ["exclude"],
|
|
122
|
+
"label": "Exclude Tags",
|
|
123
|
+
"description": "Comma-separated OpenAPI tags to exclude from generation",
|
|
124
|
+
"type": "list",
|
|
125
|
+
"item": {
|
|
126
|
+
"type": "tag",
|
|
127
|
+
"pattern": "$item"
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
"key": "includeTags",
|
|
132
|
+
"path": ["include"],
|
|
133
|
+
"label": "Include Tags",
|
|
134
|
+
"description": "Comma-separated OpenAPI tags to include. Only operations with these tags are generated",
|
|
135
|
+
"type": "list",
|
|
136
|
+
"item": {
|
|
137
|
+
"type": "tag",
|
|
138
|
+
"pattern": "$item"
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
"key": "mini",
|
|
143
|
+
"path": ["mini"],
|
|
144
|
+
"label": "Zod Mini",
|
|
145
|
+
"description": "Use Zod Mini functional API for better tree-shaking",
|
|
146
|
+
"type": "boolean",
|
|
147
|
+
"default": false
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
"key": "importPath",
|
|
151
|
+
"path": ["importPath"],
|
|
152
|
+
"label": "Import Path",
|
|
153
|
+
"description": "Module specifier used in the import statement",
|
|
154
|
+
"type": "text",
|
|
155
|
+
"default": "zod"
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
"key": "guidType",
|
|
159
|
+
"path": ["guidType"],
|
|
160
|
+
"label": "GUID Type",
|
|
161
|
+
"description": "Validator used for OpenAPI format: uuid",
|
|
162
|
+
"type": "select",
|
|
163
|
+
"default": "uuid",
|
|
164
|
+
"choices": [
|
|
165
|
+
{
|
|
166
|
+
"label": "uuid",
|
|
167
|
+
"value": "uuid"
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
"label": "guid",
|
|
171
|
+
"value": "guid"
|
|
172
|
+
}
|
|
173
|
+
]
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
"key": "regexType",
|
|
177
|
+
"path": ["regexType"],
|
|
178
|
+
"label": "Regex Type",
|
|
179
|
+
"description": "Output form for an OpenAPI pattern inside .regex(...)",
|
|
180
|
+
"type": "select",
|
|
181
|
+
"default": "literal",
|
|
182
|
+
"choices": [
|
|
183
|
+
{
|
|
184
|
+
"label": "literal",
|
|
185
|
+
"value": "literal"
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
"label": "constructor",
|
|
189
|
+
"value": "constructor"
|
|
190
|
+
}
|
|
191
|
+
]
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
"key": "inferred",
|
|
195
|
+
"path": ["inferred"],
|
|
196
|
+
"label": "Inferred",
|
|
197
|
+
"description": "Export a z.infer type alias next to every generated schema",
|
|
198
|
+
"type": "boolean",
|
|
199
|
+
"default": false
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
"key": "coercion",
|
|
203
|
+
"path": ["coercion"],
|
|
204
|
+
"label": "Coercion",
|
|
205
|
+
"description": "Wrap schemas in z.coerce so input is coerced before validation",
|
|
206
|
+
"type": "boolean",
|
|
207
|
+
"default": false
|
|
208
|
+
}
|
|
209
|
+
]
|
|
210
|
+
}
|