@kubb/plugin-zod 5.0.0-beta.4 → 5.0.0-beta.56
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 +39 -22
- package/dist/index.cjs +684 -301
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +115 -49
- package/dist/index.js +673 -296
- package/dist/index.js.map +1 -1
- package/package.json +13 -23
- package/src/components/Operations.tsx +7 -6
- package/src/components/Zod.tsx +1 -1
- package/src/generators/zodGenerator.tsx +213 -62
- package/src/plugin.ts +24 -21
- package/src/printers/printerZod.ts +131 -110
- package/src/printers/printerZodMini.ts +82 -87
- package/src/resolvers/resolverZod.ts +33 -19
- package/src/types.ts +64 -32
- package/src/utils.ts +114 -37
- package/extension.yaml +0 -502
- /package/dist/{chunk--u3MIqq1.js → chunk-C0LytTxp.js} +0 -0
|
@@ -1,57 +1,71 @@
|
|
|
1
|
-
import { camelCase, pascalCase } from '@internals/utils'
|
|
1
|
+
import { camelCase, ensureValidVarName, pascalCase, toFilePath } from '@internals/utils'
|
|
2
2
|
import { defineResolver } from '@kubb/core'
|
|
3
3
|
import type { PluginZod } from '../types.ts'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
6
|
+
* Default resolver used by `@kubb/plugin-zod`. Decides the names and file
|
|
7
|
+
* paths for every generated Zod schema. Schemas use camelCase with a
|
|
8
|
+
* `Schema` suffix (`listPetsSchema`); their inferred types use PascalCase
|
|
9
|
+
* with a `SchemaType` suffix (`PetSchemaType`), so the value and the type
|
|
10
|
+
* never share an identifier even when the schema name is all-uppercase.
|
|
7
11
|
*
|
|
8
|
-
*
|
|
12
|
+
* @example Resolve schema and type names
|
|
13
|
+
* ```ts
|
|
14
|
+
* import { resolverZod } from '@kubb/plugin-zod'
|
|
9
15
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
16
|
+
* resolverZod.default('list pets', 'function') // 'listPetsSchema'
|
|
17
|
+
* resolverZod.resolveSchemaTypeName('pet') // 'PetSchemaType'
|
|
18
|
+
* ```
|
|
12
19
|
*/
|
|
13
|
-
export const resolverZod = defineResolver<PluginZod>((
|
|
20
|
+
export const resolverZod = defineResolver<PluginZod>(() => {
|
|
14
21
|
return {
|
|
15
22
|
name: 'default',
|
|
16
23
|
pluginName: 'plugin-zod',
|
|
17
24
|
default(name, type) {
|
|
18
|
-
|
|
25
|
+
if (type === 'file') return toFilePath(name, (part) => camelCase(part, { suffix: 'schema' }))
|
|
26
|
+
return ensureValidVarName(camelCase(name, { suffix: type ? 'schema' : undefined }))
|
|
19
27
|
},
|
|
20
28
|
resolveSchemaName(name) {
|
|
21
|
-
return camelCase(name, { suffix: 'schema' })
|
|
29
|
+
return ensureValidVarName(camelCase(name, { suffix: 'schema' }))
|
|
22
30
|
},
|
|
23
31
|
resolveSchemaTypeName(name) {
|
|
24
|
-
return pascalCase(name, { suffix: 'schema' })
|
|
32
|
+
return ensureValidVarName(pascalCase(name, { suffix: 'schema type' }))
|
|
33
|
+
},
|
|
34
|
+
resolveInputSchemaName(name) {
|
|
35
|
+
return this.resolveSchemaName(`${name} input`)
|
|
36
|
+
},
|
|
37
|
+
resolveInputSchemaTypeName(name) {
|
|
38
|
+
return this.resolveSchemaTypeName(`${name} input`)
|
|
25
39
|
},
|
|
26
40
|
resolveTypeName(name) {
|
|
27
|
-
return pascalCase(name)
|
|
41
|
+
return ensureValidVarName(pascalCase(name, { suffix: 'type' }))
|
|
28
42
|
},
|
|
29
43
|
resolvePathName(name, type) {
|
|
30
|
-
return
|
|
44
|
+
return this.default(name, type)
|
|
31
45
|
},
|
|
32
46
|
resolveParamName(node, param) {
|
|
33
|
-
return
|
|
47
|
+
return this.resolveSchemaName(`${node.operationId} ${param.in} ${param.name}`)
|
|
34
48
|
},
|
|
35
49
|
resolveResponseStatusName(node, statusCode) {
|
|
36
|
-
return
|
|
50
|
+
return this.resolveSchemaName(`${node.operationId} Status ${statusCode}`)
|
|
37
51
|
},
|
|
38
52
|
resolveDataName(node) {
|
|
39
|
-
return
|
|
53
|
+
return this.resolveSchemaName(`${node.operationId} Data`)
|
|
40
54
|
},
|
|
41
55
|
resolveResponsesName(node) {
|
|
42
|
-
return
|
|
56
|
+
return this.resolveSchemaName(`${node.operationId} Responses`)
|
|
43
57
|
},
|
|
44
58
|
resolveResponseName(node) {
|
|
45
|
-
return
|
|
59
|
+
return this.resolveSchemaName(`${node.operationId} Response`)
|
|
46
60
|
},
|
|
47
61
|
resolvePathParamsName(node, param) {
|
|
48
|
-
return
|
|
62
|
+
return this.resolveParamName(node, param)
|
|
49
63
|
},
|
|
50
64
|
resolveQueryParamsName(node, param) {
|
|
51
|
-
return
|
|
65
|
+
return this.resolveParamName(node, param)
|
|
52
66
|
},
|
|
53
67
|
resolveHeaderParamsName(node, param) {
|
|
54
|
-
return
|
|
68
|
+
return this.resolveParamName(node, param)
|
|
55
69
|
},
|
|
56
70
|
}
|
|
57
71
|
})
|
package/src/types.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ast, Exclude, Generator, Group, Include, Output, Override, PluginFactoryOptions, Resolver } from '@kubb/core'
|
|
1
|
+
import type { ast, Exclude, Generator, Group, Include, Output, OutputOptions, Override, PluginFactoryOptions, Resolver } from '@kubb/core'
|
|
2
2
|
import type { PrinterZodNodes } from './printers/printerZod.ts'
|
|
3
3
|
import type { PrinterZodMiniNodes } from './printers/printerZodMini.ts'
|
|
4
4
|
|
|
@@ -15,14 +15,29 @@ export type ResolverZod = Resolver &
|
|
|
15
15
|
* Resolves the schema type name (inferred type from schema).
|
|
16
16
|
*
|
|
17
17
|
* @example Schema type names
|
|
18
|
-
* `resolver.resolveSchemaTypeName('pet') // → '
|
|
18
|
+
* `resolver.resolveSchemaTypeName('pet') // → 'PetSchemaType'`
|
|
19
19
|
*/
|
|
20
20
|
resolveSchemaTypeName(this: ResolverZod, name: string): string
|
|
21
|
+
/**
|
|
22
|
+
* Resolves the schema function name for the request (input) direction of a
|
|
23
|
+
* date-bearing component, where `Date` is encoded back to a wire `string`.
|
|
24
|
+
*
|
|
25
|
+
* @example Input schema names
|
|
26
|
+
* `resolver.resolveInputSchemaName('order') // → 'orderInputSchema'`
|
|
27
|
+
*/
|
|
28
|
+
resolveInputSchemaName(this: ResolverZod, name: string): string
|
|
29
|
+
/**
|
|
30
|
+
* Resolves the inferred type name for the request (input) direction variant.
|
|
31
|
+
*
|
|
32
|
+
* @example Input schema type names
|
|
33
|
+
* `resolver.resolveInputSchemaTypeName('order') // → 'OrderInputSchemaType'`
|
|
34
|
+
*/
|
|
35
|
+
resolveInputSchemaTypeName(this: ResolverZod, name: string): string
|
|
21
36
|
/**
|
|
22
37
|
* Resolves the generated type name from the schema.
|
|
23
38
|
*
|
|
24
39
|
* @example Type names
|
|
25
|
-
* `resolver.resolveTypeName('
|
|
40
|
+
* `resolver.resolveTypeName('petSchema') // → 'PetSchemaType'`
|
|
26
41
|
*/
|
|
27
42
|
resolveTypeName(this: ResolverZod, name: string): string
|
|
28
43
|
/**
|
|
@@ -73,87 +88,104 @@ export type ResolverZod = Resolver &
|
|
|
73
88
|
resolveHeaderParamsName(this: ResolverZod, node: ast.OperationNode, param: ast.ParameterNode): string
|
|
74
89
|
}
|
|
75
90
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
*/
|
|
84
|
-
group?: Group
|
|
91
|
+
/**
|
|
92
|
+
* Where the generated Zod schemas are written and how they are exported, plus the optional
|
|
93
|
+
* `group` strategy. The `group` option organizes `output.mode: 'directory'` output into per-tag or per-path subdirectories.
|
|
94
|
+
*
|
|
95
|
+
* @default { path: 'zod', barrel: { type: 'named' } }
|
|
96
|
+
*/
|
|
97
|
+
export type Options = OutputOptions & {
|
|
85
98
|
/**
|
|
86
|
-
*
|
|
99
|
+
* Skip operations matching at least one entry in the list.
|
|
87
100
|
*/
|
|
88
101
|
exclude?: Array<Exclude>
|
|
89
102
|
/**
|
|
90
|
-
*
|
|
103
|
+
* Restrict generation to operations matching at least one entry in the list.
|
|
91
104
|
*/
|
|
92
105
|
include?: Array<Include>
|
|
93
106
|
/**
|
|
94
|
-
*
|
|
107
|
+
* Apply a different options object to operations matching a pattern.
|
|
95
108
|
*/
|
|
96
109
|
override?: Array<Override<ResolvedOptions>>
|
|
97
110
|
/**
|
|
98
|
-
*
|
|
111
|
+
* Module specifier used in the `import { z } from '...'` statement.
|
|
112
|
+
* Use `'zod/mini'` for the tree-shakeable bundle.
|
|
99
113
|
*
|
|
100
|
-
* @default 'zod'
|
|
114
|
+
* @default mini ? 'zod/mini' : 'zod'
|
|
101
115
|
*/
|
|
102
116
|
importPath?: 'zod' | 'zod/mini' | (string & {})
|
|
103
117
|
/**
|
|
104
|
-
*
|
|
118
|
+
* Tie each Zod schema to its TypeScript type from `@kubb/plugin-ts`. Requires
|
|
119
|
+
* `@kubb/plugin-ts` in the plugins list. TypeScript fails compilation when the
|
|
120
|
+
* schema drifts from the type.
|
|
105
121
|
*/
|
|
106
122
|
typed?: boolean
|
|
107
123
|
/**
|
|
108
|
-
*
|
|
124
|
+
* Export a `z.infer<typeof schema>` type alias next to every generated schema.
|
|
125
|
+
* Lets the Zod schema act as the single source of truth.
|
|
109
126
|
*/
|
|
110
127
|
inferred?: boolean
|
|
111
128
|
/**
|
|
112
|
-
*
|
|
129
|
+
* Wrap schemas in `z.coerce` so input is coerced before validation. Useful for
|
|
130
|
+
* form data and query params where everything arrives as a string.
|
|
131
|
+
* - `true` coerces strings, numbers, and dates.
|
|
132
|
+
* - Object form picks per-primitive coercion.
|
|
133
|
+
*
|
|
134
|
+
* @default false
|
|
135
|
+
* @see https://zod.dev/?id=coercion-for-primitives
|
|
113
136
|
*/
|
|
114
137
|
coercion?: boolean | { dates?: boolean; strings?: boolean; numbers?: boolean }
|
|
115
138
|
/**
|
|
116
|
-
*
|
|
139
|
+
* Emit an `operations.ts` file with request body, query/path params, and per-status
|
|
140
|
+
* response schemas grouped by operation.
|
|
117
141
|
*/
|
|
118
142
|
operations?: boolean
|
|
119
143
|
/**
|
|
120
|
-
* Validator
|
|
144
|
+
* Validator for `format: uuid` properties.
|
|
145
|
+
* - `'uuid'` — `z.uuid()`. Standard RFC 4122.
|
|
146
|
+
* - `'guid'` — `z.guid()`. Accepts Microsoft-style GUIDs.
|
|
121
147
|
*
|
|
122
148
|
* @default 'uuid'
|
|
123
149
|
*/
|
|
124
150
|
guidType?: 'uuid' | 'guid'
|
|
125
151
|
/**
|
|
126
|
-
*
|
|
152
|
+
* Switch to Zod Mini's functional API for better tree-shaking. Also defaults
|
|
153
|
+
* `importPath` to `'zod/mini'`.
|
|
127
154
|
*
|
|
128
155
|
* @default false
|
|
156
|
+
* @beta
|
|
129
157
|
*/
|
|
130
158
|
mini?: boolean
|
|
131
159
|
/**
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
160
|
+
* Wrap the generated Zod schema string with extra calls. Receives the raw output
|
|
161
|
+
* and the originating `SchemaNode`. Useful for round-tripping OpenAPI metadata
|
|
162
|
+
* back into Zod (e.g. `.openapi(...)`).
|
|
135
163
|
*/
|
|
136
164
|
wrapOutput?: (arg: { output: string; schema: ast.SchemaNode }) => string | undefined
|
|
137
165
|
/**
|
|
138
|
-
*
|
|
166
|
+
* Rename properties inside path/query/header schemas. Body schemas are unaffected.
|
|
167
|
+
*
|
|
168
|
+
* @note Must match the value of `paramsCasing` on `@kubb/plugin-ts`.
|
|
139
169
|
*/
|
|
140
170
|
paramsCasing?: 'camelcase'
|
|
141
171
|
/**
|
|
142
|
-
*
|
|
172
|
+
* Custom generators that run alongside the built-in Zod generators.
|
|
143
173
|
*/
|
|
144
174
|
generators?: Array<Generator<PluginZod>>
|
|
145
175
|
/**
|
|
146
|
-
* Override
|
|
176
|
+
* Override how schema and operation names are built. Methods you omit fall back
|
|
177
|
+
* to the default `resolverZod`.
|
|
147
178
|
*/
|
|
148
179
|
resolver?: Partial<ResolverZod> & ThisType<ResolverZod>
|
|
149
180
|
/**
|
|
150
|
-
*
|
|
181
|
+
* Replace the Zod handler for a specific schema type (`'integer'`, `'date'`, ...).
|
|
182
|
+
* When `mini: true`, overrides target the Zod Mini printer instead.
|
|
151
183
|
*/
|
|
152
184
|
printer?: {
|
|
153
185
|
nodes?: PrinterZodNodes | PrinterZodMiniNodes
|
|
154
186
|
}
|
|
155
187
|
/**
|
|
156
|
-
* AST visitor to
|
|
188
|
+
* AST visitor applied to each schema or operation node before printing.
|
|
157
189
|
*/
|
|
158
190
|
transformer?: ast.Visitor
|
|
159
191
|
}
|
|
@@ -163,7 +195,7 @@ type ResolvedOptions = {
|
|
|
163
195
|
exclude: Array<Exclude>
|
|
164
196
|
include: Array<Include> | undefined
|
|
165
197
|
override: Array<Override<ResolvedOptions>>
|
|
166
|
-
group: Group |
|
|
198
|
+
group: Group | null
|
|
167
199
|
typed: NonNullable<Options['typed']>
|
|
168
200
|
inferred: NonNullable<Options['inferred']>
|
|
169
201
|
importPath: NonNullable<Options['importPath']>
|
package/src/utils.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { stringify, toRegExpString } from '@
|
|
1
|
+
import { extractRefName, stringify, toRegExpString } from '@kubb/ast/utils'
|
|
2
2
|
import { ast } from '@kubb/core'
|
|
3
3
|
import type { PluginZod, ResolverZod } from './types.ts'
|
|
4
4
|
|
|
@@ -12,6 +12,99 @@ export function shouldCoerce(coercion: PluginZod['resolvedOptions']['coercion']
|
|
|
12
12
|
return !!coercion[type]
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* A codec for a schema node whose runtime type differs from its JSON wire type:
|
|
17
|
+
* the output (response) schema decodes wire → runtime, and the input (request)
|
|
18
|
+
* variant encodes runtime → wire.
|
|
19
|
+
*
|
|
20
|
+
* To support another codec type, append a `Codec` to `codecs` and route that
|
|
21
|
+
* type's printer node handler through `getCodec`.
|
|
22
|
+
*/
|
|
23
|
+
export type Codec = {
|
|
24
|
+
/**
|
|
25
|
+
* Whether this node is encoded/decoded by this codec.
|
|
26
|
+
*/
|
|
27
|
+
matches(node: ast.SchemaNode): boolean
|
|
28
|
+
/**
|
|
29
|
+
* Output direction (response): decode the wire value into the runtime type.
|
|
30
|
+
*/
|
|
31
|
+
decode(node: ast.SchemaNode): string
|
|
32
|
+
/**
|
|
33
|
+
* Input direction (request): encode the runtime value back to the wire value.
|
|
34
|
+
*/
|
|
35
|
+
encode(node: ast.SchemaNode): string
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* `dateType: 'date'` fields are typed as `Date` but travel as ISO `string`s.
|
|
40
|
+
* Output decodes `string → Date`; input encodes `Date → string`, preserving the
|
|
41
|
+
* `date` (`YYYY-MM-DD`) vs `date-time` precision carried on `node.format`.
|
|
42
|
+
*/
|
|
43
|
+
const dateCodec: Codec = {
|
|
44
|
+
matches(node) {
|
|
45
|
+
return node.type === 'date' && node.representation === 'date'
|
|
46
|
+
},
|
|
47
|
+
decode(node) {
|
|
48
|
+
return node.format === 'date' ? 'z.iso.date().transform((value) => new Date(value))' : 'z.iso.datetime().transform((value) => new Date(value))'
|
|
49
|
+
},
|
|
50
|
+
encode(node) {
|
|
51
|
+
return node.format === 'date' ? 'z.date().transform((value) => value.toISOString().slice(0, 10))' : 'z.date().transform((value) => value.toISOString())'
|
|
52
|
+
},
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Registered codecs, checked in order.
|
|
57
|
+
*/
|
|
58
|
+
const codecs: Array<Codec> = [dateCodec]
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Returns the codec for this node, or `undefined` when the node needs no
|
|
62
|
+
* encode/decode (its wire and runtime types match).
|
|
63
|
+
*/
|
|
64
|
+
export function getCodec(node: ast.SchemaNode | undefined): Codec | undefined {
|
|
65
|
+
if (!node) return undefined
|
|
66
|
+
return codecs.find((codec) => codec.matches(node))
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Returns `true` when the node itself is encoded/decoded by a codec.
|
|
71
|
+
*/
|
|
72
|
+
export function hasCodec(node: ast.SchemaNode | undefined): boolean {
|
|
73
|
+
return getCodec(node) !== undefined
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Returns `true` when the schema transitively contains a codec node —
|
|
78
|
+
* a value whose runtime type differs from its wire type (see {@link hasCodec}),
|
|
79
|
+
* so it must be decoded (response) or encoded (request) at the validation boundary.
|
|
80
|
+
* `$ref`s are followed via their resolved schema; a `seen` set guards cycles.
|
|
81
|
+
*/
|
|
82
|
+
export function containsCodec(node: ast.SchemaNode | undefined, seen: Set<string> = new Set()): boolean {
|
|
83
|
+
if (!node) return false
|
|
84
|
+
|
|
85
|
+
if (hasCodec(node)) return true
|
|
86
|
+
|
|
87
|
+
if (node.type === 'ref') {
|
|
88
|
+
if (!node.ref) return false
|
|
89
|
+
const refName = extractRefName(node.ref)
|
|
90
|
+
if (refName) {
|
|
91
|
+
if (seen.has(refName)) return false
|
|
92
|
+
seen.add(refName)
|
|
93
|
+
}
|
|
94
|
+
const resolved = ast.syncSchemaRef(node)
|
|
95
|
+
if (resolved.type === 'ref') return false
|
|
96
|
+
return containsCodec(resolved, seen)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const children: Array<ast.SchemaNode | undefined> = []
|
|
100
|
+
if ('properties' in node && node.properties) children.push(...node.properties.map((prop) => prop.schema))
|
|
101
|
+
if ('items' in node && node.items) children.push(...node.items)
|
|
102
|
+
if ('members' in node && node.members) children.push(...node.members)
|
|
103
|
+
if ('additionalProperties' in node && node.additionalProperties && node.additionalProperties !== true) children.push(node.additionalProperties)
|
|
104
|
+
|
|
105
|
+
return children.some((child) => containsCodec(child, seen))
|
|
106
|
+
}
|
|
107
|
+
|
|
15
108
|
/**
|
|
16
109
|
* Collects all resolved schema names for an operation's parameters and responses
|
|
17
110
|
* into a single lookup object, useful for building imports and type references.
|
|
@@ -39,11 +132,11 @@ export function buildSchemaNames(node: ast.OperationNode, { params, resolver }:
|
|
|
39
132
|
responses['default'] = resolver.resolveResponseName(node)
|
|
40
133
|
|
|
41
134
|
return {
|
|
42
|
-
request: node.requestBody?.content?.[0]?.schema ? resolver.resolveDataName(node) :
|
|
135
|
+
request: node.requestBody?.content?.[0]?.schema ? resolver.resolveDataName(node) : null,
|
|
43
136
|
parameters: {
|
|
44
|
-
path: pathParam ? resolver.resolvePathParamsName(node, pathParam) :
|
|
45
|
-
query: queryParam ? resolver.resolveQueryParamsName(node, queryParam) :
|
|
46
|
-
header: headerParam ? resolver.resolveHeaderParamsName(node, headerParam) :
|
|
137
|
+
path: pathParam ? resolver.resolvePathParamsName(node, pathParam) : null,
|
|
138
|
+
query: queryParam ? resolver.resolveQueryParamsName(node, queryParam) : null,
|
|
139
|
+
header: headerParam ? resolver.resolveHeaderParamsName(node, headerParam) : null,
|
|
47
140
|
},
|
|
48
141
|
responses,
|
|
49
142
|
errors,
|
|
@@ -133,7 +226,7 @@ export function lengthConstraints({ min, max, pattern }: LengthConstraints): str
|
|
|
133
226
|
* Build `.check(z.minimum(), z.maximum())` for `zod/mini` numeric constraints.
|
|
134
227
|
*/
|
|
135
228
|
export function numberChecksMini({ min, max, exclusiveMinimum, exclusiveMaximum, multipleOf }: NumericConstraints): string {
|
|
136
|
-
const checks: string
|
|
229
|
+
const checks: Array<string> = []
|
|
137
230
|
if (min !== undefined) checks.push(`z.minimum(${min})`)
|
|
138
231
|
if (max !== undefined) checks.push(`z.maximum(${max})`)
|
|
139
232
|
if (exclusiveMinimum !== undefined) checks.push(`z.minimum(${exclusiveMinimum}, { exclusive: true })`)
|
|
@@ -146,7 +239,7 @@ export function numberChecksMini({ min, max, exclusiveMinimum, exclusiveMaximum,
|
|
|
146
239
|
* Build `.check(z.minLength(), z.maxLength(), z.regex())` for `zod/mini` length constraints.
|
|
147
240
|
*/
|
|
148
241
|
export function lengthChecksMini({ min, max, pattern }: LengthConstraints): string {
|
|
149
|
-
const checks: string
|
|
242
|
+
const checks: Array<string> = []
|
|
150
243
|
if (min !== undefined) checks.push(`z.minLength(${min})`)
|
|
151
244
|
if (max !== undefined) checks.push(`z.maxLength(${max})`)
|
|
152
245
|
if (pattern !== undefined) checks.push(`z.regex(${toRegExpString(pattern, null)})`)
|
|
@@ -158,21 +251,14 @@ export function lengthChecksMini({ min, max, pattern }: LengthConstraints): stri
|
|
|
158
251
|
* to a schema value string using the chainable Zod v4 API.
|
|
159
252
|
*/
|
|
160
253
|
export function applyModifiers({ value, nullable, optional, nullish, defaultValue, description }: ModifierOptions): string {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
}
|
|
169
|
-
if (defaultValue !== undefined) {
|
|
170
|
-
result = `${result}.default(${formatDefault(defaultValue)})`
|
|
171
|
-
}
|
|
172
|
-
if (description) {
|
|
173
|
-
result = `${result}.describe(${stringify(description)})`
|
|
174
|
-
}
|
|
175
|
-
return result
|
|
254
|
+
const withModifier = (() => {
|
|
255
|
+
if (nullish || (nullable && optional)) return `${value}.nullish()`
|
|
256
|
+
if (optional) return `${value}.optional()`
|
|
257
|
+
if (nullable) return `${value}.nullable()`
|
|
258
|
+
return value
|
|
259
|
+
})()
|
|
260
|
+
const withDefault = defaultValue !== undefined ? `${withModifier}.default(${formatDefault(defaultValue)})` : withModifier
|
|
261
|
+
return description ? `${withDefault}.describe(${stringify(description)})` : withDefault
|
|
176
262
|
}
|
|
177
263
|
|
|
178
264
|
/**
|
|
@@ -180,21 +266,12 @@ export function applyModifiers({ value, nullable, optional, nullish, defaultValu
|
|
|
180
266
|
* (`z.nullable()`, `z.optional()`, `z.nullish()`).
|
|
181
267
|
*/
|
|
182
268
|
export function applyMiniModifiers({ value, nullable, optional, nullish, defaultValue }: Omit<ModifierOptions, 'description'>): string {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
}
|
|
190
|
-
if (optional) {
|
|
191
|
-
result = `z.optional(${result})`
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
if (defaultValue !== undefined) {
|
|
195
|
-
result = `z._default(${result}, ${formatDefault(defaultValue)})`
|
|
196
|
-
}
|
|
197
|
-
return result
|
|
269
|
+
const withModifier = (() => {
|
|
270
|
+
if (nullish) return `z.nullish(${value})`
|
|
271
|
+
const withNullable = nullable ? `z.nullable(${value})` : value
|
|
272
|
+
return optional ? `z.optional(${withNullable})` : withNullable
|
|
273
|
+
})()
|
|
274
|
+
return defaultValue !== undefined ? `z._default(${withModifier}, ${formatDefault(defaultValue)})` : withModifier
|
|
198
275
|
}
|
|
199
276
|
|
|
200
277
|
type BuildGroupedParamsSchemaOptions = {
|