@kubb/plugin-zod 5.0.0-beta.56 → 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.
- package/dist/index.cjs +58 -53
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +59 -54
- package/dist/index.js.map +1 -1
- package/package.json +7 -8
- package/src/components/Operations.tsx +0 -78
- package/src/components/Zod.tsx +0 -42
- package/src/constants.ts +0 -5
- package/src/generators/zodGenerator.tsx +0 -367
- package/src/index.ts +0 -11
- package/src/plugin.ts +0 -97
- package/src/printers/printerZod.ts +0 -360
- package/src/printers/printerZodMini.ts +0 -290
- package/src/resolvers/resolverZod.ts +0 -71
- package/src/types.ts +0 -219
- package/src/utils.ts +0 -299
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { camelCase, ensureValidVarName, pascalCase, toFilePath } 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
|
-
* with a `SchemaType` suffix (`PetSchemaType`), so the value and the type
|
|
10
|
-
* never share an identifier even when the schema name is all-uppercase.
|
|
11
|
-
*
|
|
12
|
-
* @example Resolve schema and type names
|
|
13
|
-
* ```ts
|
|
14
|
-
* import { resolverZod } from '@kubb/plugin-zod'
|
|
15
|
-
*
|
|
16
|
-
* resolverZod.default('list pets', 'function') // 'listPetsSchema'
|
|
17
|
-
* resolverZod.resolveSchemaTypeName('pet') // 'PetSchemaType'
|
|
18
|
-
* ```
|
|
19
|
-
*/
|
|
20
|
-
export const resolverZod = defineResolver<PluginZod>(() => {
|
|
21
|
-
return {
|
|
22
|
-
name: 'default',
|
|
23
|
-
pluginName: 'plugin-zod',
|
|
24
|
-
default(name, type) {
|
|
25
|
-
if (type === 'file') return toFilePath(name, (part) => camelCase(part, { suffix: 'schema' }))
|
|
26
|
-
return ensureValidVarName(camelCase(name, { suffix: type ? 'schema' : undefined }))
|
|
27
|
-
},
|
|
28
|
-
resolveSchemaName(name) {
|
|
29
|
-
return ensureValidVarName(camelCase(name, { suffix: 'schema' }))
|
|
30
|
-
},
|
|
31
|
-
resolveSchemaTypeName(name) {
|
|
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`)
|
|
39
|
-
},
|
|
40
|
-
resolveTypeName(name) {
|
|
41
|
-
return ensureValidVarName(pascalCase(name, { suffix: 'type' }))
|
|
42
|
-
},
|
|
43
|
-
resolvePathName(name, type) {
|
|
44
|
-
return this.default(name, type)
|
|
45
|
-
},
|
|
46
|
-
resolveParamName(node, param) {
|
|
47
|
-
return this.resolveSchemaName(`${node.operationId} ${param.in} ${param.name}`)
|
|
48
|
-
},
|
|
49
|
-
resolveResponseStatusName(node, statusCode) {
|
|
50
|
-
return this.resolveSchemaName(`${node.operationId} Status ${statusCode}`)
|
|
51
|
-
},
|
|
52
|
-
resolveDataName(node) {
|
|
53
|
-
return this.resolveSchemaName(`${node.operationId} Data`)
|
|
54
|
-
},
|
|
55
|
-
resolveResponsesName(node) {
|
|
56
|
-
return this.resolveSchemaName(`${node.operationId} Responses`)
|
|
57
|
-
},
|
|
58
|
-
resolveResponseName(node) {
|
|
59
|
-
return this.resolveSchemaName(`${node.operationId} Response`)
|
|
60
|
-
},
|
|
61
|
-
resolvePathParamsName(node, param) {
|
|
62
|
-
return this.resolveParamName(node, param)
|
|
63
|
-
},
|
|
64
|
-
resolveQueryParamsName(node, param) {
|
|
65
|
-
return this.resolveParamName(node, param)
|
|
66
|
-
},
|
|
67
|
-
resolveHeaderParamsName(node, param) {
|
|
68
|
-
return this.resolveParamName(node, param)
|
|
69
|
-
},
|
|
70
|
-
}
|
|
71
|
-
})
|
package/src/types.ts
DELETED
|
@@ -1,219 +0,0 @@
|
|
|
1
|
-
import type { ast, Exclude, Generator, Group, Include, Output, OutputOptions, 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') // → 'PetSchemaType'`
|
|
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') // → 'OrderInputSchemaType'`
|
|
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('petSchema') // → 'PetSchemaType'`
|
|
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
|
-
/**
|
|
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 & {
|
|
98
|
-
/**
|
|
99
|
-
* Skip operations matching at least one entry in the list.
|
|
100
|
-
*/
|
|
101
|
-
exclude?: Array<Exclude>
|
|
102
|
-
/**
|
|
103
|
-
* Restrict generation to operations matching at least one entry in the list.
|
|
104
|
-
*/
|
|
105
|
-
include?: Array<Include>
|
|
106
|
-
/**
|
|
107
|
-
* Apply a different options object to operations matching a pattern.
|
|
108
|
-
*/
|
|
109
|
-
override?: Array<Override<ResolvedOptions>>
|
|
110
|
-
/**
|
|
111
|
-
* Module specifier used in the `import { z } from '...'` statement.
|
|
112
|
-
* Use `'zod/mini'` for the tree-shakeable bundle.
|
|
113
|
-
*
|
|
114
|
-
* @default mini ? 'zod/mini' : 'zod'
|
|
115
|
-
*/
|
|
116
|
-
importPath?: 'zod' | 'zod/mini' | (string & {})
|
|
117
|
-
/**
|
|
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.
|
|
121
|
-
*/
|
|
122
|
-
typed?: boolean
|
|
123
|
-
/**
|
|
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.
|
|
126
|
-
*/
|
|
127
|
-
inferred?: boolean
|
|
128
|
-
/**
|
|
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
|
|
136
|
-
*/
|
|
137
|
-
coercion?: boolean | { dates?: boolean; strings?: boolean; numbers?: boolean }
|
|
138
|
-
/**
|
|
139
|
-
* Emit an `operations.ts` file with request body, query/path params, and per-status
|
|
140
|
-
* response schemas grouped by operation.
|
|
141
|
-
*/
|
|
142
|
-
operations?: boolean
|
|
143
|
-
/**
|
|
144
|
-
* Validator for `format: uuid` properties.
|
|
145
|
-
* - `'uuid'` — `z.uuid()`. Standard RFC 4122.
|
|
146
|
-
* - `'guid'` — `z.guid()`. Accepts Microsoft-style GUIDs.
|
|
147
|
-
*
|
|
148
|
-
* @default 'uuid'
|
|
149
|
-
*/
|
|
150
|
-
guidType?: 'uuid' | 'guid'
|
|
151
|
-
/**
|
|
152
|
-
* Switch to Zod Mini's functional API for better tree-shaking. Also defaults
|
|
153
|
-
* `importPath` to `'zod/mini'`.
|
|
154
|
-
*
|
|
155
|
-
* @default false
|
|
156
|
-
* @beta
|
|
157
|
-
*/
|
|
158
|
-
mini?: boolean
|
|
159
|
-
/**
|
|
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(...)`).
|
|
163
|
-
*/
|
|
164
|
-
wrapOutput?: (arg: { output: string; schema: ast.SchemaNode }) => string | undefined
|
|
165
|
-
/**
|
|
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`.
|
|
169
|
-
*/
|
|
170
|
-
paramsCasing?: 'camelcase'
|
|
171
|
-
/**
|
|
172
|
-
* Custom generators that run alongside the built-in Zod generators.
|
|
173
|
-
*/
|
|
174
|
-
generators?: Array<Generator<PluginZod>>
|
|
175
|
-
/**
|
|
176
|
-
* Override how schema and operation names are built. Methods you omit fall back
|
|
177
|
-
* to the default `resolverZod`.
|
|
178
|
-
*/
|
|
179
|
-
resolver?: Partial<ResolverZod> & ThisType<ResolverZod>
|
|
180
|
-
/**
|
|
181
|
-
* Replace the Zod handler for a specific schema type (`'integer'`, `'date'`, ...).
|
|
182
|
-
* When `mini: true`, overrides target the Zod Mini printer instead.
|
|
183
|
-
*/
|
|
184
|
-
printer?: {
|
|
185
|
-
nodes?: PrinterZodNodes | PrinterZodMiniNodes
|
|
186
|
-
}
|
|
187
|
-
/**
|
|
188
|
-
* AST visitor applied to each schema or operation node before printing.
|
|
189
|
-
*/
|
|
190
|
-
transformer?: ast.Visitor
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
type ResolvedOptions = {
|
|
194
|
-
output: Output
|
|
195
|
-
exclude: Array<Exclude>
|
|
196
|
-
include: Array<Include> | undefined
|
|
197
|
-
override: Array<Override<ResolvedOptions>>
|
|
198
|
-
group: Group | null
|
|
199
|
-
typed: NonNullable<Options['typed']>
|
|
200
|
-
inferred: NonNullable<Options['inferred']>
|
|
201
|
-
importPath: NonNullable<Options['importPath']>
|
|
202
|
-
coercion: NonNullable<Options['coercion']>
|
|
203
|
-
operations: NonNullable<Options['operations']>
|
|
204
|
-
guidType: NonNullable<Options['guidType']>
|
|
205
|
-
mini: NonNullable<Options['mini']>
|
|
206
|
-
wrapOutput: Options['wrapOutput']
|
|
207
|
-
paramsCasing: Options['paramsCasing']
|
|
208
|
-
printer: Options['printer']
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
export type PluginZod = PluginFactoryOptions<'plugin-zod', Options, ResolvedOptions, ResolverZod>
|
|
212
|
-
|
|
213
|
-
declare global {
|
|
214
|
-
namespace Kubb {
|
|
215
|
-
interface PluginRegistry {
|
|
216
|
-
'plugin-zod': PluginZod
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
}
|
package/src/utils.ts
DELETED
|
@@ -1,299 +0,0 @@
|
|
|
1
|
-
import { extractRefName, stringify, toRegExpString } from '@kubb/ast/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 = 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
|
-
}
|