@kubb/plugin-zod 5.0.0-beta.42 → 5.0.0-beta.64

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.
@@ -1,69 +0,0 @@
1
- import { camelCase, ensureValidVarName, pascalCase } from '@internals/utils'
2
- import { defineResolver } from '@kubb/core'
3
- import type { PluginZod } from '../types.ts'
4
-
5
- /**
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
- *
10
- * @example Resolve schema and type names
11
- * ```ts
12
- * import { resolverZod } from '@kubb/plugin-zod'
13
- *
14
- * resolverZod.default('list pets', 'function') // 'listPetsSchema'
15
- * resolverZod.resolveSchemaTypeName('pet') // 'PetSchema'
16
- * ```
17
- */
18
- export const resolverZod = defineResolver<PluginZod>(() => {
19
- return {
20
- name: 'default',
21
- pluginName: 'plugin-zod',
22
- default(name, type) {
23
- const resolved = camelCase(name, { isFile: type === 'file', suffix: type ? 'schema' : undefined })
24
- return type === 'file' ? resolved : ensureValidVarName(resolved)
25
- },
26
- resolveSchemaName(name) {
27
- return ensureValidVarName(camelCase(name, { suffix: 'schema' }))
28
- },
29
- resolveSchemaTypeName(name) {
30
- return ensureValidVarName(pascalCase(name, { suffix: 'schema' }))
31
- },
32
- resolveInputSchemaName(name) {
33
- return this.resolveSchemaName(`${name} input`)
34
- },
35
- resolveInputSchemaTypeName(name) {
36
- return this.resolveSchemaTypeName(`${name} input`)
37
- },
38
- resolveTypeName(name) {
39
- return ensureValidVarName(pascalCase(name))
40
- },
41
- resolvePathName(name, type) {
42
- return this.default(name, type)
43
- },
44
- resolveParamName(node, param) {
45
- return this.resolveSchemaName(`${node.operationId} ${param.in} ${param.name}`)
46
- },
47
- resolveResponseStatusName(node, statusCode) {
48
- return this.resolveSchemaName(`${node.operationId} Status ${statusCode}`)
49
- },
50
- resolveDataName(node) {
51
- return this.resolveSchemaName(`${node.operationId} Data`)
52
- },
53
- resolveResponsesName(node) {
54
- return this.resolveSchemaName(`${node.operationId} Responses`)
55
- },
56
- resolveResponseName(node) {
57
- return this.resolveSchemaName(`${node.operationId} Response`)
58
- },
59
- resolvePathParamsName(node, param) {
60
- return this.resolveParamName(node, param)
61
- },
62
- resolveQueryParamsName(node, param) {
63
- return this.resolveParamName(node, param)
64
- },
65
- resolveHeaderParamsName(node, param) {
66
- return this.resolveParamName(node, param)
67
- },
68
- }
69
- })
package/src/types.ts DELETED
@@ -1,223 +0,0 @@
1
- import type { ast, Exclude, Generator, Group, Include, Output, Override, PluginFactoryOptions, Resolver } from '@kubb/core'
2
- import type { PrinterZodNodes } from './printers/printerZod.ts'
3
- import type { PrinterZodMiniNodes } from './printers/printerZodMini.ts'
4
-
5
- /**
6
- * Resolver for Zod that provides naming methods for schema types.
7
- */
8
- export type ResolverZod = Resolver &
9
- ast.OperationParamsResolver & {
10
- /**
11
- * Resolves a camelCase schema function name with a `Schema` suffix.
12
- */
13
- resolveSchemaName(this: ResolverZod, name: string): string
14
- /**
15
- * Resolves the schema type name (inferred type from schema).
16
- *
17
- * @example Schema type names
18
- * `resolver.resolveSchemaTypeName('pet') // → 'Pet'`
19
- */
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') // → 'OrderInputSchema'`
34
- */
35
- resolveInputSchemaTypeName(this: ResolverZod, name: string): string
36
- /**
37
- * Resolves the generated type name from the schema.
38
- *
39
- * @example Type names
40
- * `resolver.resolveTypeName('pet') // → 'Pet'`
41
- */
42
- resolveTypeName(this: ResolverZod, name: string): string
43
- /**
44
- * Resolves the output file name for a schema.
45
- */
46
- resolvePathName(this: ResolverZod, name: string, type?: 'file' | 'function' | 'type' | 'const'): string
47
- /**
48
- * Resolves the name for an operation response by status code.
49
- *
50
- * @example Response status names
51
- * `resolver.resolveResponseStatusName(node, 200) // → 'listPetsStatus200Schema'`
52
- */
53
- resolveResponseStatusName(this: ResolverZod, node: ast.OperationNode, statusCode: ast.StatusCode): string
54
- /**
55
- * Resolves the name for the collection of all operation responses.
56
- *
57
- * @example Responses collection names
58
- * `resolver.resolveResponsesName(node) // → 'listPetsResponsesSchema'`
59
- */
60
- resolveResponsesName(this: ResolverZod, node: ast.OperationNode): string
61
- /**
62
- * Resolves the name for the union of all operation responses.
63
- *
64
- * @example Response union names
65
- * `resolver.resolveResponseName(node) // → 'listPetsResponseSchema'`
66
- */
67
- resolveResponseName(this: ResolverZod, node: ast.OperationNode): string
68
- /**
69
- * Resolves the name for an operation's grouped path parameters type.
70
- *
71
- * @example Path parameters names
72
- * `resolver.resolvePathParamsName(node, param) // → 'deletePetPathPetIdSchema'`
73
- */
74
- resolvePathParamsName(this: ResolverZod, node: ast.OperationNode, param: ast.ParameterNode): string
75
- /**
76
- * Resolves the name for an operation's grouped query parameters type.
77
- *
78
- * @example Query parameters names
79
- * `resolver.resolveQueryParamsName(node, param) // → 'findPetsByStatusQueryStatusSchema'`
80
- */
81
- resolveQueryParamsName(this: ResolverZod, node: ast.OperationNode, param: ast.ParameterNode): string
82
- /**
83
- * Resolves the name for an operation's grouped header parameters type.
84
- *
85
- * @example Header parameters names
86
- * `resolver.resolveHeaderParamsName(node, param) // → 'deletePetHeaderApiKeySchema'`
87
- */
88
- resolveHeaderParamsName(this: ResolverZod, node: ast.OperationNode, param: ast.ParameterNode): string
89
- }
90
-
91
- export type Options = {
92
- /**
93
- * Where the generated Zod schemas are written and how they are exported.
94
- *
95
- * @default { path: 'zod', barrel: { type: 'named' } }
96
- */
97
- output?: Output
98
- /**
99
- * Split generated files into subfolders based on the operation's tag.
100
- */
101
- group?: Group
102
- /**
103
- * Skip operations matching at least one entry in the list.
104
- */
105
- exclude?: Array<Exclude>
106
- /**
107
- * Restrict generation to operations matching at least one entry in the list.
108
- */
109
- include?: Array<Include>
110
- /**
111
- * Apply a different options object to operations matching a pattern.
112
- */
113
- override?: Array<Override<ResolvedOptions>>
114
- /**
115
- * Module specifier used in the `import { z } from '...'` statement.
116
- * Use `'zod/mini'` for the tree-shakeable bundle.
117
- *
118
- * @default 'zod'
119
- */
120
- importPath?: 'zod' | 'zod/mini' | (string & {})
121
- /**
122
- * Tie each Zod schema to its TypeScript type from `@kubb/plugin-ts`. Requires
123
- * `@kubb/plugin-ts` in the plugins list. TypeScript fails compilation when the
124
- * schema drifts from the type.
125
- */
126
- typed?: boolean
127
- /**
128
- * Export a `z.infer<typeof schema>` type alias next to every generated schema.
129
- * Lets the Zod schema act as the single source of truth.
130
- */
131
- inferred?: boolean
132
- /**
133
- * Wrap schemas in `z.coerce` so input is coerced before validation. Useful for
134
- * form data and query params where everything arrives as a string.
135
- * - `true` coerces strings, numbers, and dates.
136
- * - Object form picks per-primitive coercion.
137
- *
138
- * @default false
139
- * @see https://zod.dev/?id=coercion-for-primitives
140
- */
141
- coercion?: boolean | { dates?: boolean; strings?: boolean; numbers?: boolean }
142
- /**
143
- * Emit an `operations.ts` file with request body, query/path params, and per-status
144
- * response schemas grouped by operation.
145
- */
146
- operations?: boolean
147
- /**
148
- * Validator for `format: uuid` properties.
149
- * - `'uuid'` — `z.uuid()`. Standard RFC 4122.
150
- * - `'guid'` — `z.guid()`. Accepts Microsoft-style GUIDs.
151
- *
152
- * @default 'uuid'
153
- */
154
- guidType?: 'uuid' | 'guid'
155
- /**
156
- * Switch to Zod Mini's functional API for better tree-shaking. Also defaults
157
- * `importPath` to `'zod/mini'`.
158
- *
159
- * @default false
160
- * @beta
161
- */
162
- mini?: boolean
163
- /**
164
- * Wrap the generated Zod schema string with extra calls. Receives the raw output
165
- * and the originating `SchemaNode`. Useful for round-tripping OpenAPI metadata
166
- * back into Zod (e.g. `.openapi(...)`).
167
- */
168
- wrapOutput?: (arg: { output: string; schema: ast.SchemaNode }) => string | undefined
169
- /**
170
- * Rename properties inside path/query/header schemas. Body schemas are unaffected.
171
- *
172
- * @note Must match the value of `paramsCasing` on `@kubb/plugin-ts`.
173
- */
174
- paramsCasing?: 'camelcase'
175
- /**
176
- * Custom generators that run alongside the built-in Zod generators.
177
- */
178
- generators?: Array<Generator<PluginZod>>
179
- /**
180
- * Override how schema and operation names are built. Methods you omit fall back
181
- * to the default `resolverZod`.
182
- */
183
- resolver?: Partial<ResolverZod> & ThisType<ResolverZod>
184
- /**
185
- * Replace the Zod handler for a specific schema type (`'integer'`, `'date'`, ...).
186
- * When `mini: true`, overrides target the Zod Mini printer instead.
187
- */
188
- printer?: {
189
- nodes?: PrinterZodNodes | PrinterZodMiniNodes
190
- }
191
- /**
192
- * AST visitor applied to each schema or operation node before printing.
193
- */
194
- transformer?: ast.Visitor
195
- }
196
-
197
- type ResolvedOptions = {
198
- output: Output
199
- exclude: Array<Exclude>
200
- include: Array<Include> | undefined
201
- override: Array<Override<ResolvedOptions>>
202
- group: Group | null
203
- typed: NonNullable<Options['typed']>
204
- inferred: NonNullable<Options['inferred']>
205
- importPath: NonNullable<Options['importPath']>
206
- coercion: NonNullable<Options['coercion']>
207
- operations: NonNullable<Options['operations']>
208
- guidType: NonNullable<Options['guidType']>
209
- mini: NonNullable<Options['mini']>
210
- wrapOutput: Options['wrapOutput']
211
- paramsCasing: Options['paramsCasing']
212
- printer: Options['printer']
213
- }
214
-
215
- export type PluginZod = PluginFactoryOptions<'plugin-zod', Options, ResolvedOptions, ResolverZod>
216
-
217
- declare global {
218
- namespace Kubb {
219
- interface PluginRegistry {
220
- 'plugin-zod': PluginZod
221
- }
222
- }
223
- }
package/src/utils.ts DELETED
@@ -1,299 +0,0 @@
1
- import { stringify, toRegExpString } from '@internals/utils'
2
- import { ast } from '@kubb/core'
3
- import type { PluginZod, ResolverZod } from './types.ts'
4
-
5
- /**
6
- * Returns `true` when the given coercion option enables coercion for the specified type.
7
- */
8
- export function shouldCoerce(coercion: PluginZod['resolvedOptions']['coercion'] | undefined, type: 'dates' | 'strings' | 'numbers'): boolean {
9
- if (coercion === undefined || coercion === false) return false
10
- if (coercion === true) return true
11
-
12
- return !!coercion[type]
13
- }
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 = ast.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
-
108
- /**
109
- * Collects all resolved schema names for an operation's parameters and responses
110
- * into a single lookup object, useful for building imports and type references.
111
- */
112
- export function buildSchemaNames(node: ast.OperationNode, { params, resolver }: { params: Array<ast.ParameterNode>; resolver: ResolverZod }) {
113
- const pathParam = params.find((p) => p.in === 'path')
114
- const queryParam = params.find((p) => p.in === 'query')
115
- const headerParam = params.find((p) => p.in === 'header')
116
-
117
- const responses: Record<number | string, string> = {}
118
- const errors: Record<number | string, string> = {}
119
-
120
- for (const res of node.responses) {
121
- const name = resolver.resolveResponseStatusName(node, res.statusCode)
122
- const statusNum = Number(res.statusCode)
123
-
124
- if (!Number.isNaN(statusNum)) {
125
- responses[statusNum] = name
126
- if (statusNum >= 400) {
127
- errors[statusNum] = name
128
- }
129
- }
130
- }
131
-
132
- responses['default'] = resolver.resolveResponseName(node)
133
-
134
- return {
135
- request: node.requestBody?.content?.[0]?.schema ? resolver.resolveDataName(node) : null,
136
- parameters: {
137
- path: pathParam ? resolver.resolvePathParamsName(node, pathParam) : null,
138
- query: queryParam ? resolver.resolveQueryParamsName(node, queryParam) : null,
139
- header: headerParam ? resolver.resolveHeaderParamsName(node, headerParam) : null,
140
- },
141
- responses,
142
- errors,
143
- }
144
- }
145
-
146
- /**
147
- * Format a default value as a code-level literal.
148
- * Objects become `{}`, primitives become their string representation, strings are quoted.
149
- */
150
- export function formatDefault(value: unknown): string {
151
- if (typeof value === 'string') return stringify(value)
152
- if (typeof value === 'object' && value !== null) return '{}'
153
-
154
- return String(value ?? '')
155
- }
156
-
157
- /**
158
- * Format a primitive enum/literal value.
159
- * Strings are quoted; numbers and booleans are emitted raw.
160
- */
161
- export function formatLiteral(v: string | number | boolean): string {
162
- if (typeof v === 'string') return stringify(v)
163
-
164
- return String(v)
165
- }
166
-
167
- /**
168
- * Numeric constraint limits for Zod schemas (min, max, and exclusive bounds).
169
- */
170
- export type NumericConstraints = {
171
- min?: number
172
- max?: number
173
- exclusiveMinimum?: number
174
- exclusiveMaximum?: number
175
- multipleOf?: number
176
- }
177
-
178
- /**
179
- * Length constraint limits for string and array schemas (min, max, and regex pattern).
180
- */
181
- export type LengthConstraints = {
182
- min?: number
183
- max?: number
184
- pattern?: string
185
- }
186
-
187
- /**
188
- * Modifier options for applying chainable methods to Zod schema values.
189
- */
190
- export type ModifierOptions = {
191
- value: string
192
- nullable?: boolean
193
- optional?: boolean
194
- nullish?: boolean
195
- defaultValue?: unknown
196
- description?: string
197
- }
198
-
199
- /**
200
- * Build `.min()` / `.max()` / `.gt()` / `.lt()` constraint chains for numbers
201
- * using the standard chainable Zod v4 API.
202
- */
203
- export function numberConstraints({ min, max, exclusiveMinimum, exclusiveMaximum, multipleOf }: NumericConstraints): string {
204
- return [
205
- min !== undefined ? `.min(${min})` : '',
206
- max !== undefined ? `.max(${max})` : '',
207
- exclusiveMinimum !== undefined ? `.gt(${exclusiveMinimum})` : '',
208
- exclusiveMaximum !== undefined ? `.lt(${exclusiveMaximum})` : '',
209
- multipleOf !== undefined ? `.multipleOf(${multipleOf})` : '',
210
- ].join('')
211
- }
212
-
213
- /**
214
- * Build `.min()` / `.max()` / `.regex()` chains for strings/arrays
215
- * using the standard chainable Zod v4 API.
216
- */
217
- export function lengthConstraints({ min, max, pattern }: LengthConstraints): string {
218
- return [
219
- min !== undefined ? `.min(${min})` : '',
220
- max !== undefined ? `.max(${max})` : '',
221
- pattern !== undefined ? `.regex(${toRegExpString(pattern, null)})` : '',
222
- ].join('')
223
- }
224
-
225
- /**
226
- * Build `.check(z.minimum(), z.maximum())` for `zod/mini` numeric constraints.
227
- */
228
- export function numberChecksMini({ min, max, exclusiveMinimum, exclusiveMaximum, multipleOf }: NumericConstraints): string {
229
- const checks: Array<string> = []
230
- if (min !== undefined) checks.push(`z.minimum(${min})`)
231
- if (max !== undefined) checks.push(`z.maximum(${max})`)
232
- if (exclusiveMinimum !== undefined) checks.push(`z.minimum(${exclusiveMinimum}, { exclusive: true })`)
233
- if (exclusiveMaximum !== undefined) checks.push(`z.maximum(${exclusiveMaximum}, { exclusive: true })`)
234
- if (multipleOf !== undefined) checks.push(`z.multipleOf(${multipleOf})`)
235
- return checks.length ? `.check(${checks.join(', ')})` : ''
236
- }
237
-
238
- /**
239
- * Build `.check(z.minLength(), z.maxLength(), z.regex())` for `zod/mini` length constraints.
240
- */
241
- export function lengthChecksMini({ min, max, pattern }: LengthConstraints): string {
242
- const checks: Array<string> = []
243
- if (min !== undefined) checks.push(`z.minLength(${min})`)
244
- if (max !== undefined) checks.push(`z.maxLength(${max})`)
245
- if (pattern !== undefined) checks.push(`z.regex(${toRegExpString(pattern, null)})`)
246
- return checks.length ? `.check(${checks.join(', ')})` : ''
247
- }
248
-
249
- /**
250
- * Apply nullable / optional / nullish modifiers and an optional `.describe()` call
251
- * to a schema value string using the chainable Zod v4 API.
252
- */
253
- export function applyModifiers({ value, nullable, optional, nullish, defaultValue, description }: ModifierOptions): string {
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
262
- }
263
-
264
- /**
265
- * Apply nullable / optional / nullish modifiers using the functional `zod/mini` API
266
- * (`z.nullable()`, `z.optional()`, `z.nullish()`).
267
- */
268
- export function applyMiniModifiers({ value, nullable, optional, nullish, defaultValue }: Omit<ModifierOptions, 'description'>): string {
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
275
- }
276
-
277
- type BuildGroupedParamsSchemaOptions = {
278
- params: Array<ast.ParameterNode>
279
- optional?: boolean
280
- }
281
-
282
- /**
283
- * Builds an `object` schema node grouping the given parameter nodes.
284
- * The `primitive: 'object'` marker ensures the Zod printer emits `z.object(…)` rather than a record.
285
- */
286
- export function buildGroupedParamsSchema({ params, optional }: BuildGroupedParamsSchemaOptions): ast.SchemaNode {
287
- return ast.createSchema({
288
- type: 'object',
289
- optional,
290
- primitive: 'object',
291
- properties: params.map((param) =>
292
- ast.createProperty({
293
- name: param.name,
294
- required: param.required,
295
- schema: param.schema,
296
- }),
297
- ),
298
- })
299
- }