@kubb/plugin-zod 5.0.0-beta.3 → 5.0.0-beta.30
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 +25 -5
- package/dist/index.cjs +390 -177
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +79 -34
- package/dist/index.js +386 -179
- package/dist/index.js.map +1 -1
- package/extension.yaml +966 -0
- package/package.json +9 -13
- package/src/components/Operations.tsx +4 -4
- package/src/components/Zod.tsx +1 -1
- package/src/generators/zodGenerator.tsx +77 -32
- package/src/plugin.ts +21 -8
- package/src/printers/printerZod.ts +67 -63
- package/src/printers/printerZodMini.ts +46 -49
- package/src/resolvers/resolverZod.ts +25 -19
- package/src/types.ts +42 -21
- package/src/utils.ts +20 -36
|
@@ -45,7 +45,7 @@ export type PrinterZodMiniOptions = {
|
|
|
45
45
|
/**
|
|
46
46
|
* Properties to exclude using `.omit({ key: true })`.
|
|
47
47
|
*/
|
|
48
|
-
keysToOmit?: Array<string>
|
|
48
|
+
keysToOmit?: Array<string> | null
|
|
49
49
|
/**
|
|
50
50
|
* Schema names that form circular dependency chains.
|
|
51
51
|
* Properties referencing these emit lazy getters wrapping refs in `z.lazy(() => …)`.
|
|
@@ -61,6 +61,22 @@ export type PrinterZodMiniOptions = {
|
|
|
61
61
|
* Factory options for the Zod Mini printer, defining input/output types and configuration.
|
|
62
62
|
*/
|
|
63
63
|
export type PrinterZodMiniFactory = ast.PrinterFactoryOptions<'zod-mini', PrinterZodMiniOptions, string, string>
|
|
64
|
+
|
|
65
|
+
function strictOneOfMember(member: string, node: ast.SchemaNode): string {
|
|
66
|
+
if (node.type === 'object' && (node.additionalProperties === undefined || node.additionalProperties === false)) {
|
|
67
|
+
return member.replace(/^z\.object\(/, 'z.strictObject(')
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return member
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function getMemberConstraintMini(member: ast.SchemaNode): string | undefined {
|
|
74
|
+
if (member.primitive === 'string') return lengthChecksMini(ast.narrowSchema(member, 'string') ?? {}) || undefined
|
|
75
|
+
if (member.primitive === 'number' || member.primitive === 'integer')
|
|
76
|
+
return numberChecksMini(ast.narrowSchema(member, 'number') ?? ast.narrowSchema(member, 'integer') ?? {}) || undefined
|
|
77
|
+
if (member.primitive === 'array') return lengthChecksMini(ast.narrowSchema(member, 'array') ?? {}) || undefined
|
|
78
|
+
}
|
|
79
|
+
|
|
64
80
|
/**
|
|
65
81
|
* Zod v4 **Mini** printer built with `definePrinter`.
|
|
66
82
|
*
|
|
@@ -144,7 +160,7 @@ export const printerZodMini = ast.definePrinter<PrinterZodMiniFactory>((options)
|
|
|
144
160
|
},
|
|
145
161
|
|
|
146
162
|
ref(node) {
|
|
147
|
-
if (!node.name) return
|
|
163
|
+
if (!node.name) return null
|
|
148
164
|
const refName = node.ref ? (ast.extractRefName(node.ref) ?? node.name) : node.name
|
|
149
165
|
const resolvedName = node.ref ? (this.options.resolver?.default(refName, 'function') ?? refName) : node.name
|
|
150
166
|
|
|
@@ -168,9 +184,12 @@ export const printerZodMini = ast.definePrinter<PrinterZodMiniFactory>((options)
|
|
|
168
184
|
const hasSelfRef = this.options.cyclicSchemas != null && ast.containsCircularRef(schema, { circularSchemas: this.options.cyclicSchemas })
|
|
169
185
|
// Inside a getter the getter itself defers evaluation, so suppress
|
|
170
186
|
// z.lazy() wrapping on nested refs by temporarily clearing cyclicSchemas.
|
|
187
|
+
// Save before clearing: this.options === options (same reference via definePrinter),
|
|
188
|
+
// so reading options.cyclicSchemas after mutation would return undefined.
|
|
189
|
+
const savedCyclicSchemas = this.options.cyclicSchemas
|
|
171
190
|
if (hasSelfRef) this.options.cyclicSchemas = undefined
|
|
172
191
|
const baseOutput = this.transform(schema) ?? this.transform(ast.createSchema({ type: 'unknown' }))!
|
|
173
|
-
if (hasSelfRef) this.options.cyclicSchemas =
|
|
192
|
+
if (hasSelfRef) this.options.cyclicSchemas = savedCyclicSchemas
|
|
174
193
|
|
|
175
194
|
const wrappedOutput = this.options.wrapOutput ? this.options.wrapOutput({ output: baseOutput, schema }) || baseOutput : baseOutput
|
|
176
195
|
|
|
@@ -194,13 +213,9 @@ export const printerZodMini = ast.definePrinter<PrinterZodMiniFactory>((options)
|
|
|
194
213
|
array(node) {
|
|
195
214
|
const items = (node.items ?? []).map((item) => this.transform(item)).filter(Boolean)
|
|
196
215
|
const inner = items.join(', ') || this.transform(ast.createSchema({ type: 'unknown' }))!
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
if (node.unique) {
|
|
200
|
-
result += `.refine(items => new Set(items).size === items.length, { message: "Array entries must be unique" })`
|
|
201
|
-
}
|
|
216
|
+
const base = `z.array(${inner})${lengthChecksMini(node)}`
|
|
202
217
|
|
|
203
|
-
return
|
|
218
|
+
return node.unique ? `${base}.refine(items => new Set(items).size === items.length, { message: "Array entries must be unique" })` : base
|
|
204
219
|
},
|
|
205
220
|
tuple(node) {
|
|
206
221
|
const items = (node.items ?? []).map((item) => this.transform(item)).filter(Boolean)
|
|
@@ -209,7 +224,13 @@ export const printerZodMini = ast.definePrinter<PrinterZodMiniFactory>((options)
|
|
|
209
224
|
},
|
|
210
225
|
union(node) {
|
|
211
226
|
const nodeMembers = node.members ?? []
|
|
212
|
-
const members = nodeMembers
|
|
227
|
+
const members = nodeMembers
|
|
228
|
+
.map((memberNode) => {
|
|
229
|
+
const member = this.transform(memberNode)
|
|
230
|
+
|
|
231
|
+
return member && node.strategy === 'one' ? strictOneOfMember(member, memberNode) : member
|
|
232
|
+
})
|
|
233
|
+
.filter(Boolean)
|
|
213
234
|
if (members.length === 0) return ''
|
|
214
235
|
if (members.length === 1) return members[0]!
|
|
215
236
|
if (node.discriminatorPropertyName && !nodeMembers.some((m) => m.type === 'intersection')) {
|
|
@@ -227,61 +248,37 @@ export const printerZodMini = ast.definePrinter<PrinterZodMiniFactory>((options)
|
|
|
227
248
|
const [first, ...rest] = members
|
|
228
249
|
if (!first) return ''
|
|
229
250
|
|
|
230
|
-
|
|
231
|
-
if (!
|
|
251
|
+
const firstBase = this.transform(first)
|
|
252
|
+
if (!firstBase) return ''
|
|
232
253
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
const c = lengthChecksMini(s ?? {})
|
|
237
|
-
if (c) {
|
|
238
|
-
base += c
|
|
239
|
-
continue
|
|
240
|
-
}
|
|
241
|
-
} else if (member.primitive === 'number' || member.primitive === 'integer') {
|
|
242
|
-
const n = ast.narrowSchema(member, 'number') ?? ast.narrowSchema(member, 'integer')
|
|
243
|
-
const c = numberChecksMini(n ?? {})
|
|
244
|
-
if (c) {
|
|
245
|
-
base += c
|
|
246
|
-
continue
|
|
247
|
-
}
|
|
248
|
-
} else if (member.primitive === 'array') {
|
|
249
|
-
const a = ast.narrowSchema(member, 'array')
|
|
250
|
-
const c = lengthChecksMini(a ?? {})
|
|
251
|
-
if (c) {
|
|
252
|
-
base += c
|
|
253
|
-
continue
|
|
254
|
-
}
|
|
255
|
-
}
|
|
254
|
+
return rest.reduce((acc, member) => {
|
|
255
|
+
const constraint = getMemberConstraintMini(member)
|
|
256
|
+
if (constraint) return acc + constraint
|
|
256
257
|
const transformed = this.transform(member)
|
|
257
|
-
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
return base
|
|
258
|
+
return transformed ? `z.intersection(${acc}, ${transformed})` : acc
|
|
259
|
+
}, firstBase)
|
|
261
260
|
},
|
|
262
261
|
...options.nodes,
|
|
263
262
|
},
|
|
264
263
|
print(node) {
|
|
265
264
|
const { keysToOmit } = this.options
|
|
266
265
|
|
|
267
|
-
|
|
268
|
-
if (!
|
|
266
|
+
const transformed = this.transform(node)
|
|
267
|
+
if (!transformed) return null
|
|
269
268
|
|
|
270
269
|
const meta = ast.syncSchemaRef(node)
|
|
271
270
|
|
|
272
|
-
|
|
271
|
+
const base = (() => {
|
|
272
|
+
if (!keysToOmit?.length || meta.primitive !== 'object' || (meta.type === 'union' && meta.discriminatorPropertyName)) return transformed
|
|
273
273
|
// Mirror printerTs `nonNullable: true`: when omitting keys, the resulting
|
|
274
274
|
// schema is a new non-nullable object type — skip optional/nullable/nullish.
|
|
275
275
|
// Discriminated unions (z.discriminatedUnion) do not support .omit(), so skip them.
|
|
276
276
|
|
|
277
277
|
// If this is a lazy reference, apply omit inside the lazy function
|
|
278
|
-
const lazyMatch =
|
|
279
|
-
if (lazyMatch) {
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
base = `${base}.omit({ ${keysToOmit.map((k: string) => `"${k}": true`).join(', ')} })`
|
|
283
|
-
}
|
|
284
|
-
}
|
|
278
|
+
const lazyMatch = transformed.match(/^z\.lazy\(\(\)\s*=>\s*(.+)\)$/)
|
|
279
|
+
if (lazyMatch) return `z.lazy(() => ${lazyMatch[1]}.omit({ ${keysToOmit.map((k: string) => `"${k}": true`).join(', ')} }))`
|
|
280
|
+
return `${transformed}.omit({ ${keysToOmit.map((k: string) => `"${k}": true`).join(', ')} })`
|
|
281
|
+
})()
|
|
285
282
|
|
|
286
283
|
return applyMiniModifiers({
|
|
287
284
|
value: base,
|
|
@@ -1,57 +1,63 @@
|
|
|
1
|
-
import { camelCase, pascalCase } from '@internals/utils'
|
|
1
|
+
import { camelCase, ensureValidVarName, pascalCase } 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.
|
|
7
9
|
*
|
|
8
|
-
*
|
|
10
|
+
* @example Resolve schema and type names
|
|
11
|
+
* ```ts
|
|
12
|
+
* import { resolverZod } from '@kubb/plugin-zod'
|
|
9
13
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
14
|
+
* resolverZod.default('list pets', 'function') // 'listPetsSchema'
|
|
15
|
+
* resolverZod.resolveSchemaTypeName('pet') // 'PetSchema'
|
|
16
|
+
* ```
|
|
12
17
|
*/
|
|
13
|
-
export const resolverZod = defineResolver<PluginZod>((
|
|
18
|
+
export const resolverZod = defineResolver<PluginZod>(() => {
|
|
14
19
|
return {
|
|
15
20
|
name: 'default',
|
|
16
21
|
pluginName: 'plugin-zod',
|
|
17
22
|
default(name, type) {
|
|
18
|
-
|
|
23
|
+
const resolved = camelCase(name, { isFile: type === 'file', suffix: type ? 'schema' : undefined })
|
|
24
|
+
return type === 'file' ? resolved : ensureValidVarName(resolved)
|
|
19
25
|
},
|
|
20
26
|
resolveSchemaName(name) {
|
|
21
|
-
return camelCase(name, { suffix: 'schema' })
|
|
27
|
+
return ensureValidVarName(camelCase(name, { suffix: 'schema' }))
|
|
22
28
|
},
|
|
23
29
|
resolveSchemaTypeName(name) {
|
|
24
|
-
return pascalCase(name, { suffix: 'schema' })
|
|
30
|
+
return ensureValidVarName(pascalCase(name, { suffix: 'schema' }))
|
|
25
31
|
},
|
|
26
32
|
resolveTypeName(name) {
|
|
27
|
-
return pascalCase(name)
|
|
33
|
+
return ensureValidVarName(pascalCase(name))
|
|
28
34
|
},
|
|
29
35
|
resolvePathName(name, type) {
|
|
30
|
-
return
|
|
36
|
+
return this.default(name, type)
|
|
31
37
|
},
|
|
32
38
|
resolveParamName(node, param) {
|
|
33
|
-
return
|
|
39
|
+
return this.resolveSchemaName(`${node.operationId} ${param.in} ${param.name}`)
|
|
34
40
|
},
|
|
35
41
|
resolveResponseStatusName(node, statusCode) {
|
|
36
|
-
return
|
|
42
|
+
return this.resolveSchemaName(`${node.operationId} Status ${statusCode}`)
|
|
37
43
|
},
|
|
38
44
|
resolveDataName(node) {
|
|
39
|
-
return
|
|
45
|
+
return this.resolveSchemaName(`${node.operationId} Data`)
|
|
40
46
|
},
|
|
41
47
|
resolveResponsesName(node) {
|
|
42
|
-
return
|
|
48
|
+
return this.resolveSchemaName(`${node.operationId} Responses`)
|
|
43
49
|
},
|
|
44
50
|
resolveResponseName(node) {
|
|
45
|
-
return
|
|
51
|
+
return this.resolveSchemaName(`${node.operationId} Response`)
|
|
46
52
|
},
|
|
47
53
|
resolvePathParamsName(node, param) {
|
|
48
|
-
return
|
|
54
|
+
return this.resolveParamName(node, param)
|
|
49
55
|
},
|
|
50
56
|
resolveQueryParamsName(node, param) {
|
|
51
|
-
return
|
|
57
|
+
return this.resolveParamName(node, param)
|
|
52
58
|
},
|
|
53
59
|
resolveHeaderParamsName(node, param) {
|
|
54
|
-
return
|
|
60
|
+
return this.resolveParamName(node, param)
|
|
55
61
|
},
|
|
56
62
|
}
|
|
57
63
|
})
|
package/src/types.ts
CHANGED
|
@@ -75,85 +75,106 @@ export type ResolverZod = Resolver &
|
|
|
75
75
|
|
|
76
76
|
export type Options = {
|
|
77
77
|
/**
|
|
78
|
-
*
|
|
78
|
+
* Where the generated Zod schemas are written and how they are exported.
|
|
79
|
+
*
|
|
80
|
+
* @default { path: 'zod', barrel: { type: 'named' } }
|
|
79
81
|
*/
|
|
80
82
|
output?: Output
|
|
81
83
|
/**
|
|
82
|
-
*
|
|
84
|
+
* Split generated files into subfolders based on the operation's tag.
|
|
83
85
|
*/
|
|
84
86
|
group?: Group
|
|
85
87
|
/**
|
|
86
|
-
*
|
|
88
|
+
* Skip operations matching at least one entry in the list.
|
|
87
89
|
*/
|
|
88
90
|
exclude?: Array<Exclude>
|
|
89
91
|
/**
|
|
90
|
-
*
|
|
92
|
+
* Restrict generation to operations matching at least one entry in the list.
|
|
91
93
|
*/
|
|
92
94
|
include?: Array<Include>
|
|
93
95
|
/**
|
|
94
|
-
*
|
|
96
|
+
* Apply a different options object to operations matching a pattern.
|
|
95
97
|
*/
|
|
96
98
|
override?: Array<Override<ResolvedOptions>>
|
|
97
99
|
/**
|
|
98
|
-
*
|
|
100
|
+
* Module specifier used in the `import { z } from '...'` statement.
|
|
101
|
+
* Use `'zod/mini'` for the tree-shakeable bundle.
|
|
99
102
|
*
|
|
100
103
|
* @default 'zod'
|
|
101
104
|
*/
|
|
102
105
|
importPath?: 'zod' | 'zod/mini' | (string & {})
|
|
103
106
|
/**
|
|
104
|
-
*
|
|
107
|
+
* Tie each Zod schema to its TypeScript type from `@kubb/plugin-ts`. Requires
|
|
108
|
+
* `@kubb/plugin-ts` in the plugins list. TypeScript fails compilation when the
|
|
109
|
+
* schema drifts from the type.
|
|
105
110
|
*/
|
|
106
111
|
typed?: boolean
|
|
107
112
|
/**
|
|
108
|
-
*
|
|
113
|
+
* Export a `z.infer<typeof schema>` type alias next to every generated schema.
|
|
114
|
+
* Lets the Zod schema act as the single source of truth.
|
|
109
115
|
*/
|
|
110
116
|
inferred?: boolean
|
|
111
117
|
/**
|
|
112
|
-
*
|
|
118
|
+
* Wrap schemas in `z.coerce` so input is coerced before validation. Useful for
|
|
119
|
+
* form data and query params where everything arrives as a string.
|
|
120
|
+
* - `true` coerces strings, numbers, and dates.
|
|
121
|
+
* - Object form picks per-primitive coercion.
|
|
122
|
+
*
|
|
123
|
+
* @default false
|
|
124
|
+
* @see https://zod.dev/?id=coercion-for-primitives
|
|
113
125
|
*/
|
|
114
126
|
coercion?: boolean | { dates?: boolean; strings?: boolean; numbers?: boolean }
|
|
115
127
|
/**
|
|
116
|
-
*
|
|
128
|
+
* Emit an `operations.ts` file with request body, query/path params, and per-status
|
|
129
|
+
* response schemas grouped by operation.
|
|
117
130
|
*/
|
|
118
131
|
operations?: boolean
|
|
119
132
|
/**
|
|
120
|
-
* Validator
|
|
133
|
+
* Validator for `format: uuid` properties.
|
|
134
|
+
* - `'uuid'` — `z.uuid()`. Standard RFC 4122.
|
|
135
|
+
* - `'guid'` — `z.guid()`. Accepts Microsoft-style GUIDs.
|
|
121
136
|
*
|
|
122
137
|
* @default 'uuid'
|
|
123
138
|
*/
|
|
124
139
|
guidType?: 'uuid' | 'guid'
|
|
125
140
|
/**
|
|
126
|
-
*
|
|
141
|
+
* Switch to Zod Mini's functional API for better tree-shaking. Also defaults
|
|
142
|
+
* `importPath` to `'zod/mini'`.
|
|
127
143
|
*
|
|
128
144
|
* @default false
|
|
145
|
+
* @beta
|
|
129
146
|
*/
|
|
130
147
|
mini?: boolean
|
|
131
148
|
/**
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
149
|
+
* Wrap the generated Zod schema string with extra calls. Receives the raw output
|
|
150
|
+
* and the originating `SchemaNode`. Useful for round-tripping OpenAPI metadata
|
|
151
|
+
* back into Zod (e.g. `.openapi(...)`).
|
|
135
152
|
*/
|
|
136
153
|
wrapOutput?: (arg: { output: string; schema: ast.SchemaNode }) => string | undefined
|
|
137
154
|
/**
|
|
138
|
-
*
|
|
155
|
+
* Rename properties inside path/query/header schemas. Body schemas are unaffected.
|
|
156
|
+
*
|
|
157
|
+
* @note Must match the value of `paramsCasing` on `@kubb/plugin-ts`.
|
|
139
158
|
*/
|
|
140
159
|
paramsCasing?: 'camelcase'
|
|
141
160
|
/**
|
|
142
|
-
*
|
|
161
|
+
* Custom generators that run alongside the built-in Zod generators.
|
|
143
162
|
*/
|
|
144
163
|
generators?: Array<Generator<PluginZod>>
|
|
145
164
|
/**
|
|
146
|
-
* Override
|
|
165
|
+
* Override how schema and operation names are built. Methods you omit fall back
|
|
166
|
+
* to the default `resolverZod`.
|
|
147
167
|
*/
|
|
148
168
|
resolver?: Partial<ResolverZod> & ThisType<ResolverZod>
|
|
149
169
|
/**
|
|
150
|
-
*
|
|
170
|
+
* Replace the Zod handler for a specific schema type (`'integer'`, `'date'`, ...).
|
|
171
|
+
* When `mini: true`, overrides target the Zod Mini printer instead.
|
|
151
172
|
*/
|
|
152
173
|
printer?: {
|
|
153
174
|
nodes?: PrinterZodNodes | PrinterZodMiniNodes
|
|
154
175
|
}
|
|
155
176
|
/**
|
|
156
|
-
* AST visitor to
|
|
177
|
+
* AST visitor applied to each schema or operation node before printing.
|
|
157
178
|
*/
|
|
158
179
|
transformer?: ast.Visitor
|
|
159
180
|
}
|
|
@@ -163,7 +184,7 @@ type ResolvedOptions = {
|
|
|
163
184
|
exclude: Array<Exclude>
|
|
164
185
|
include: Array<Include> | undefined
|
|
165
186
|
override: Array<Override<ResolvedOptions>>
|
|
166
|
-
group: Group |
|
|
187
|
+
group: Group | null
|
|
167
188
|
typed: NonNullable<Options['typed']>
|
|
168
189
|
inferred: NonNullable<Options['inferred']>
|
|
169
190
|
importPath: NonNullable<Options['importPath']>
|
package/src/utils.ts
CHANGED
|
@@ -39,11 +39,11 @@ export function buildSchemaNames(node: ast.OperationNode, { params, resolver }:
|
|
|
39
39
|
responses['default'] = resolver.resolveResponseName(node)
|
|
40
40
|
|
|
41
41
|
return {
|
|
42
|
-
request: node.requestBody?.content?.[0]?.schema ? resolver.resolveDataName(node) :
|
|
42
|
+
request: node.requestBody?.content?.[0]?.schema ? resolver.resolveDataName(node) : null,
|
|
43
43
|
parameters: {
|
|
44
|
-
path: pathParam ? resolver.resolvePathParamsName(node, pathParam) :
|
|
45
|
-
query: queryParam ? resolver.resolveQueryParamsName(node, queryParam) :
|
|
46
|
-
header: headerParam ? resolver.resolveHeaderParamsName(node, headerParam) :
|
|
44
|
+
path: pathParam ? resolver.resolvePathParamsName(node, pathParam) : null,
|
|
45
|
+
query: queryParam ? resolver.resolveQueryParamsName(node, queryParam) : null,
|
|
46
|
+
header: headerParam ? resolver.resolveHeaderParamsName(node, headerParam) : null,
|
|
47
47
|
},
|
|
48
48
|
responses,
|
|
49
49
|
errors,
|
|
@@ -133,7 +133,7 @@ export function lengthConstraints({ min, max, pattern }: LengthConstraints): str
|
|
|
133
133
|
* Build `.check(z.minimum(), z.maximum())` for `zod/mini` numeric constraints.
|
|
134
134
|
*/
|
|
135
135
|
export function numberChecksMini({ min, max, exclusiveMinimum, exclusiveMaximum, multipleOf }: NumericConstraints): string {
|
|
136
|
-
const checks: string
|
|
136
|
+
const checks: Array<string> = []
|
|
137
137
|
if (min !== undefined) checks.push(`z.minimum(${min})`)
|
|
138
138
|
if (max !== undefined) checks.push(`z.maximum(${max})`)
|
|
139
139
|
if (exclusiveMinimum !== undefined) checks.push(`z.minimum(${exclusiveMinimum}, { exclusive: true })`)
|
|
@@ -146,7 +146,7 @@ export function numberChecksMini({ min, max, exclusiveMinimum, exclusiveMaximum,
|
|
|
146
146
|
* Build `.check(z.minLength(), z.maxLength(), z.regex())` for `zod/mini` length constraints.
|
|
147
147
|
*/
|
|
148
148
|
export function lengthChecksMini({ min, max, pattern }: LengthConstraints): string {
|
|
149
|
-
const checks: string
|
|
149
|
+
const checks: Array<string> = []
|
|
150
150
|
if (min !== undefined) checks.push(`z.minLength(${min})`)
|
|
151
151
|
if (max !== undefined) checks.push(`z.maxLength(${max})`)
|
|
152
152
|
if (pattern !== undefined) checks.push(`z.regex(${toRegExpString(pattern, null)})`)
|
|
@@ -158,21 +158,14 @@ export function lengthChecksMini({ min, max, pattern }: LengthConstraints): stri
|
|
|
158
158
|
* to a schema value string using the chainable Zod v4 API.
|
|
159
159
|
*/
|
|
160
160
|
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
|
|
161
|
+
const withModifier = (() => {
|
|
162
|
+
if (nullish || (nullable && optional)) return `${value}.nullish()`
|
|
163
|
+
if (optional) return `${value}.optional()`
|
|
164
|
+
if (nullable) return `${value}.nullable()`
|
|
165
|
+
return value
|
|
166
|
+
})()
|
|
167
|
+
const withDefault = defaultValue !== undefined ? `${withModifier}.default(${formatDefault(defaultValue)})` : withModifier
|
|
168
|
+
return description ? `${withDefault}.describe(${stringify(description)})` : withDefault
|
|
176
169
|
}
|
|
177
170
|
|
|
178
171
|
/**
|
|
@@ -180,21 +173,12 @@ export function applyModifiers({ value, nullable, optional, nullish, defaultValu
|
|
|
180
173
|
* (`z.nullable()`, `z.optional()`, `z.nullish()`).
|
|
181
174
|
*/
|
|
182
175
|
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
|
|
176
|
+
const withModifier = (() => {
|
|
177
|
+
if (nullish) return `z.nullish(${value})`
|
|
178
|
+
const withNullable = nullable ? `z.nullable(${value})` : value
|
|
179
|
+
return optional ? `z.optional(${withNullable})` : withNullable
|
|
180
|
+
})()
|
|
181
|
+
return defaultValue !== undefined ? `z._default(${withModifier}, ${formatDefault(defaultValue)})` : withModifier
|
|
198
182
|
}
|
|
199
183
|
|
|
200
184
|
type BuildGroupedParamsSchemaOptions = {
|