@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kubb/plugin-zod",
3
- "version": "5.0.0-beta.56",
3
+ "version": "5.0.0-beta.64",
4
4
  "description": "Generate Zod validation schemas from your OpenAPI specification for runtime data parsing and type safety. Pairs perfectly with @kubb/plugin-ts for end-to-end type coverage.",
5
5
  "keywords": [
6
6
  "code-generation",
@@ -23,7 +23,6 @@
23
23
  "directory": "packages/plugin-zod"
24
24
  },
25
25
  "files": [
26
- "src",
27
26
  "templates",
28
27
  "dist",
29
28
  "!/**/**.test.**",
@@ -47,16 +46,16 @@
47
46
  "registry": "https://registry.npmjs.org/"
48
47
  },
49
48
  "dependencies": {
50
- "@kubb/ast": "5.0.0-beta.55",
51
- "@kubb/core": "5.0.0-beta.55",
52
- "@kubb/renderer-jsx": "5.0.0-beta.55"
49
+ "@kubb/ast": "5.0.0-beta.63",
50
+ "@kubb/core": "5.0.0-beta.63",
51
+ "@kubb/renderer-jsx": "5.0.0-beta.63"
53
52
  },
54
53
  "devDependencies": {
55
- "@internals/utils": "0.0.0",
56
- "@internals/shared": "0.0.0"
54
+ "@internals/shared": "0.0.0",
55
+ "@internals/utils": "0.0.0"
57
56
  },
58
57
  "peerDependencies": {
59
- "@kubb/renderer-jsx": "5.0.0-beta.55"
58
+ "@kubb/renderer-jsx": "5.0.0-beta.63"
60
59
  },
61
60
  "engines": {
62
61
  "node": ">=22"
@@ -1,78 +0,0 @@
1
- import { stringifyObject } from '@kubb/ast/utils'
2
- import { ast } from '@kubb/core'
3
- import { Const, File, Type } from '@kubb/renderer-jsx'
4
- import type { KubbReactNode } from '@kubb/renderer-jsx/types'
5
-
6
- type SchemaNames = {
7
- request: string | null
8
- parameters: {
9
- path: string | null
10
- query: string | null
11
- header: string | null
12
- }
13
- responses: { default?: string } & Record<number | string, string>
14
- errors: Record<number | string, string>
15
- }
16
-
17
- type Props = {
18
- name: string
19
- operations: Array<{ node: ast.OperationNode; data: SchemaNames }>
20
- }
21
-
22
- export function Operations({ name, operations }: Props): KubbReactNode {
23
- const operationsJSON = operations.reduce<Record<string, unknown>>(
24
- (prev, acc) => {
25
- prev[`"${acc.node.operationId}"`] = acc.data
26
-
27
- return prev
28
- },
29
- {} as Record<string, unknown>,
30
- )
31
-
32
- const pathsJSON = operations.reduce<Record<string, Record<string, string>>>((prev, acc) => {
33
- if (!ast.isHttpOperationNode(acc.node)) return prev
34
- prev[`"${acc.node.path}"`] = {
35
- ...(prev[`"${acc.node.path}"`] ?? {}),
36
- [acc.node.method]: `operations["${acc.node.operationId}"]`,
37
- }
38
-
39
- return prev
40
- }, {})
41
-
42
- return (
43
- <>
44
- <File.Source name="OperationSchema" isExportable isIndexable>
45
- <Type name="OperationSchema" export>{`{
46
- readonly request: z.ZodTypeAny | undefined;
47
- readonly parameters: {
48
- readonly path: z.ZodTypeAny | undefined;
49
- readonly query: z.ZodTypeAny | undefined;
50
- readonly header: z.ZodTypeAny | undefined;
51
- };
52
- readonly responses: {
53
- readonly [status: number]: z.ZodTypeAny;
54
- readonly default: z.ZodTypeAny;
55
- };
56
- readonly errors: {
57
- readonly [status: number]: z.ZodTypeAny;
58
- };
59
- }`}</Type>
60
- </File.Source>
61
- <File.Source name="OperationsMap" isExportable isIndexable>
62
- <Type name="OperationsMap" export>
63
- {'Record<string, OperationSchema>'}
64
- </Type>
65
- </File.Source>
66
- <File.Source name={name} isExportable isIndexable>
67
- <Const export name={name} asConst>
68
- {`{${stringifyObject(operationsJSON)}}`}
69
- </Const>
70
- </File.Source>
71
- <File.Source name={'paths'} isExportable isIndexable>
72
- <Const export name={'paths'} asConst>
73
- {`{${stringifyObject(pathsJSON)}}`}
74
- </Const>
75
- </File.Source>
76
- </>
77
- )
78
- }
@@ -1,42 +0,0 @@
1
- import type { ast } from '@kubb/core'
2
- import { Const, File, Type } from '@kubb/renderer-jsx'
3
- import type { KubbReactNode } from '@kubb/renderer-jsx/types'
4
- import type { PrinterZodFactory } from '../printers/printerZod.ts'
5
- import type { PrinterZodMiniFactory } from '../printers/printerZodMini.ts'
6
-
7
- type Props = {
8
- name: string
9
- node: ast.SchemaNode
10
- /**
11
- * Pre-configured printer instance created by the generator.
12
- * The generator selects `printerZod` or `printerZodMini` based on the `mini` option,
13
- * then merges in any user-supplied `printer.nodes` overrides.
14
- */
15
- printer: ast.Printer<PrinterZodFactory> | ast.Printer<PrinterZodMiniFactory>
16
- inferTypeName?: string | null
17
- }
18
-
19
- export function Zod({ name, node, printer, inferTypeName }: Props): KubbReactNode {
20
- const output = printer.print(node)
21
-
22
- if (!output) {
23
- return
24
- }
25
-
26
- return (
27
- <>
28
- <File.Source name={name} isExportable isIndexable>
29
- <Const export name={name}>
30
- {output}
31
- </Const>
32
- </File.Source>
33
- {inferTypeName && (
34
- <File.Source name={inferTypeName} isExportable isIndexable isTypeOnly>
35
- <Type export name={inferTypeName}>
36
- {`z.infer<typeof ${name}>`}
37
- </Type>
38
- </File.Source>
39
- )}
40
- </>
41
- )
42
- }
package/src/constants.ts DELETED
@@ -1,5 +0,0 @@
1
- /**
2
- * Import paths that use a namespace import (`import * as z from '...'`).
3
- * All other import paths use a named import (`import { z } from '...'`).
4
- */
5
- export const ZOD_NAMESPACE_IMPORTS = new Set(['zod', 'zod/mini'] as const)
@@ -1,367 +0,0 @@
1
- import { resolveContentTypeVariants } from '@internals/shared'
2
- import { extractRefName } from '@kubb/ast/utils'
3
- import type { Adapter } from '@kubb/core'
4
- import { ast, defineGenerator } from '@kubb/core'
5
- import type { AdapterOas } from '@kubb/adapter-oas'
6
- import { File, jsxRenderer } from '@kubb/renderer-jsx'
7
- import { Operations } from '../components/Operations.tsx'
8
- import { Zod } from '../components/Zod.tsx'
9
- import { ZOD_NAMESPACE_IMPORTS } from '../constants.ts'
10
- import { printerZod } from '../printers/printerZod.ts'
11
- import { printerZodMini } from '../printers/printerZodMini.ts'
12
- import type { PluginZod, ResolverZod } from '../types'
13
- import { buildSchemaNames, containsCodec } from '../utils.ts'
14
-
15
- type StdPrinters = { output: ReturnType<typeof printerZod>; input: ReturnType<typeof printerZod> }
16
- type ZodPrinterEntry = StdPrinters & { coercion: unknown; guidType: unknown; dateType: unknown }
17
- type ZodMiniPrinterEntry = { printer: ReturnType<typeof printerZodMini>; guidType: unknown }
18
-
19
- // Per-build caches: keyed on resolver (unique per plugin instance per build, GC'd when released)
20
- const zodPrinterCache = new WeakMap<ResolverZod, ZodPrinterEntry>()
21
- const zodMiniPrinterCache = new WeakMap<ResolverZod, ZodMiniPrinterEntry>()
22
-
23
- type StdPrinterParams = { coercion: unknown; guidType: unknown; dateType: unknown; wrapOutput: unknown; cyclicSchemas: ReadonlySet<string>; nodes: unknown }
24
-
25
- /**
26
- * Returns the cached `output`/`input` direction printers for a resolver, building them on
27
- * first use. The `input` printer encodes `Date → string` for request bodies; `output` decodes
28
- * `string → Date` for responses. Schemas without `dateType: 'date'` fields print identically.
29
- */
30
- function getStdPrinters(resolver: ResolverZod, params: StdPrinterParams): StdPrinters {
31
- const cached = zodPrinterCache.get(resolver)
32
- if (cached && cached.coercion === params.coercion && cached.guidType === params.guidType && cached.dateType === params.dateType) {
33
- return { output: cached.output, input: cached.input }
34
- }
35
- const base = { ...params, resolver } as Parameters<typeof printerZod>[0]
36
- const output = printerZod({ ...base, direction: 'output' })
37
- const input = printerZod({ ...base, direction: 'input' })
38
- zodPrinterCache.set(resolver, { output, input, coercion: params.coercion, guidType: params.guidType, dateType: params.dateType })
39
- return { output, input }
40
- }
41
-
42
- function getMiniPrinter(resolver: ResolverZod, params: { guidType: unknown; wrapOutput: unknown; cyclicSchemas: ReadonlySet<string>; nodes: unknown }) {
43
- const cached = zodMiniPrinterCache.get(resolver)
44
- if (cached && cached.guidType === params.guidType) return cached.printer
45
- const p = printerZodMini({ ...params, resolver } as Parameters<typeof printerZodMini>[0])
46
- zodMiniPrinterCache.set(resolver, { printer: p, guidType: params.guidType })
47
- return p
48
- }
49
-
50
- /**
51
- * Built-in generator for `@kubb/plugin-zod`. Emits one Zod schema per
52
- * schema in the spec plus per-operation request/response/parameter schemas.
53
- * When `mini: true`, schemas use the Zod Mini functional API instead of
54
- * chainable methods.
55
- */
56
- export const zodGenerator = defineGenerator<PluginZod>({
57
- name: 'zod',
58
- renderer: jsxRenderer,
59
- schema(node, ctx) {
60
- const { adapter, config, resolver, root } = ctx
61
- const { output, coercion, guidType, mini, wrapOutput, inferred, importPath, group, printer } = ctx.options
62
- const dateType = (adapter as Adapter<AdapterOas>).options.dateType
63
-
64
- if (!node.name) {
65
- return
66
- }
67
-
68
- const isZodImport = ZOD_NAMESPACE_IMPORTS.has(importPath as 'zod' | 'zod/mini')
69
- const cyclicSchemas = new Set<string>(ctx.meta.circularNames)
70
-
71
- // A codec component is rendered twice: the canonical (output) schema decodes
72
- // `string → Date`, and an `${name}InputSchema` variant encodes `Date → string` for requests.
73
- const hasCodec = !mini && containsCodec(node)
74
-
75
- const codecRefNames = new Set(
76
- hasCodec
77
- ? ast.collect<string>(node, {
78
- schema: (n) => (n.type === 'ref' && n.ref && containsCodec(n) ? (extractRefName(n.ref) ?? undefined) : undefined),
79
- })
80
- : [],
81
- )
82
- const importEntries = adapter.getImports(node, (schemaName) => ({
83
- name: resolver.resolveSchemaName(schemaName),
84
- path: resolver.resolveFile({ name: schemaName, extname: '.ts' }, { root, output, group: group ?? undefined }).path,
85
- }))
86
- const inputImportEntries = hasCodec
87
- ? [...codecRefNames].map((schemaName) => ({
88
- name: [resolver.resolveInputSchemaName(schemaName)],
89
- path: resolver.resolveFile({ name: schemaName, extname: '.ts' }, { root, output, group: group ?? undefined }).path,
90
- }))
91
- : []
92
- const seenImports = new Set<string>()
93
- const imports = [...importEntries, ...inputImportEntries].filter((imp) => {
94
- const key = `${Array.isArray(imp.name) ? imp.name.join(',') : imp.name}|${imp.path}`
95
- if (seenImports.has(key)) return false
96
- seenImports.add(key)
97
- return true
98
- })
99
-
100
- const meta = {
101
- name: resolver.resolveSchemaName(node.name),
102
- file: resolver.resolveFile({ name: node.name, extname: '.ts' }, { root, output, group: group ?? undefined }),
103
- } as const
104
-
105
- const inferTypeName = inferred ? resolver.resolveSchemaTypeName(node.name) : null
106
-
107
- const stdPrinters = mini ? null : getStdPrinters(resolver, { coercion, guidType, dateType, wrapOutput, cyclicSchemas, nodes: printer?.nodes })
108
- const schemaPrinter = mini ? getMiniPrinter(resolver, { guidType, wrapOutput, cyclicSchemas, nodes: printer?.nodes }) : stdPrinters!.output
109
-
110
- return (
111
- <File
112
- baseName={meta.file.baseName}
113
- path={meta.file.path}
114
- meta={meta.file.meta}
115
- banner={resolver.resolveBanner(ctx.meta, { output, config, file: { path: meta.file.path, baseName: meta.file.baseName } })}
116
- footer={resolver.resolveFooter(ctx.meta, { output, config, file: { path: meta.file.path, baseName: meta.file.baseName } })}
117
- >
118
- <File.Import name={isZodImport ? 'z' : ['z']} path={importPath} isNameSpace={isZodImport} />
119
- {imports.map((imp) => (
120
- <File.Import key={[node.name, imp.path, imp.name].join('-')} root={meta.file.path} path={imp.path} name={imp.name} />
121
- ))}
122
-
123
- <Zod name={meta.name} node={node} printer={schemaPrinter} inferTypeName={inferTypeName} />
124
- {hasCodec && stdPrinters && (
125
- <Zod
126
- name={resolver.resolveInputSchemaName(node.name)}
127
- node={node}
128
- printer={stdPrinters.input}
129
- inferTypeName={inferred ? resolver.resolveInputSchemaTypeName(node.name) : null}
130
- />
131
- )}
132
- </File>
133
- )
134
- },
135
- operation(node, ctx) {
136
- if (!ast.isHttpOperationNode(node)) return null
137
- const { adapter, config, resolver, root } = ctx
138
- const { output, coercion, guidType, mini, wrapOutput, inferred, importPath, group, paramsCasing, printer } = ctx.options
139
- const dateType = (adapter as Adapter<AdapterOas>).options.dateType
140
-
141
- const isZodImport = ZOD_NAMESPACE_IMPORTS.has(importPath as 'zod' | 'zod/mini')
142
-
143
- const params = ast.caseParams(node.parameters, paramsCasing)
144
-
145
- const meta = {
146
- file: resolver.resolveFile(
147
- { name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
148
- { root, output, group: group ?? undefined },
149
- ),
150
- } as const
151
-
152
- const cyclicSchemas = new Set<string>(ctx.meta.circularNames)
153
-
154
- function renderSchemaEntry({
155
- schema,
156
- name,
157
- keysToOmit,
158
- direction = 'output',
159
- }: {
160
- schema: ast.SchemaNode | null
161
- name: string
162
- keysToOmit?: Array<string> | null
163
- direction?: 'input' | 'output'
164
- }) {
165
- if (!schema) return null
166
-
167
- const inferTypeName = inferred ? resolver.resolveTypeName(name) : null
168
-
169
- // In the input direction, refs to codec components resolve to their input variant.
170
- const codecRefNames =
171
- direction === 'input' && !mini
172
- ? new Set(
173
- ast.collect<string>(schema, {
174
- schema: (n) => (n.type === 'ref' && n.ref && containsCodec(n) ? (extractRefName(n.ref) ?? undefined) : undefined),
175
- }),
176
- )
177
- : null
178
- const imports = adapter.getImports(schema, (schemaName) => ({
179
- name: codecRefNames?.has(schemaName) ? resolver.resolveInputSchemaName(schemaName) : resolver.resolveSchemaName(schemaName),
180
- path: resolver.resolveFile({ name: schemaName, extname: '.ts' }, { root, output, group: group ?? undefined }).path,
181
- }))
182
-
183
- const schemaPrinter = mini
184
- ? keysToOmit?.length
185
- ? printerZodMini({ guidType, wrapOutput, resolver, keysToOmit, cyclicSchemas, nodes: printer?.nodes })
186
- : getMiniPrinter(resolver, { guidType, wrapOutput, cyclicSchemas, nodes: printer?.nodes })
187
- : keysToOmit?.length
188
- ? printerZod({ coercion, guidType, dateType, wrapOutput, resolver, keysToOmit, cyclicSchemas, nodes: printer?.nodes, direction })
189
- : getStdPrinters(resolver, { coercion, guidType, dateType, wrapOutput, cyclicSchemas, nodes: printer?.nodes })[direction]
190
-
191
- return (
192
- <>
193
- {imports.map((imp) => (
194
- <File.Import key={[name, imp.path, imp.name].join('-')} root={meta.file.path} path={imp.path} name={imp.name} />
195
- ))}
196
- <Zod name={name} node={schema} printer={schemaPrinter} inferTypeName={inferTypeName} />
197
- </>
198
- )
199
- }
200
-
201
- // Multiple content types for a single name — emit one schema per content type plus a union alias.
202
- function buildContentTypeVariants(
203
- entries: Array<{ contentType: string; schema?: ast.SchemaNode | null; keysToOmit?: Array<string> | null }>,
204
- baseName: string,
205
- decorate?: (schema: ast.SchemaNode) => ast.SchemaNode,
206
- direction?: 'input' | 'output',
207
- ) {
208
- const variants = resolveContentTypeVariants(entries, baseName)
209
- const unionSchema = ast.createSchema({
210
- type: 'union',
211
- members: variants.map((variant) => ast.createSchema({ type: 'ref', name: variant.name })),
212
- })
213
- return (
214
- <>
215
- {variants.map((variant) =>
216
- renderSchemaEntry({
217
- schema: decorate ? decorate(variant.schema) : variant.schema,
218
- name: variant.name,
219
- keysToOmit: variant.keysToOmit,
220
- direction,
221
- }),
222
- )}
223
- {renderSchemaEntry({ schema: unionSchema, name: baseName, direction })}
224
- </>
225
- )
226
- }
227
-
228
- const paramSchemas = params.map((param) => renderSchemaEntry({ schema: param.schema, name: resolver.resolveParamName(node, param), direction: 'input' }))
229
-
230
- const responseSchemas = node.responses.map((res) => {
231
- const variants = (res.content ?? []).filter((entry) => entry.schema)
232
- if (variants.length > 1) {
233
- return buildContentTypeVariants(res.content!, resolver.resolveResponseStatusName(node, res.statusCode))
234
- }
235
- const primary = variants[0] ?? res.content?.[0]
236
- return renderSchemaEntry({
237
- schema: primary?.schema ?? null,
238
- name: resolver.resolveResponseStatusName(node, res.statusCode),
239
- keysToOmit: primary?.keysToOmit,
240
- })
241
- })
242
-
243
- const responsesWithSchema = node.responses.filter((res) => res.content?.some((entry) => entry.schema))
244
- const responseUnionSchema =
245
- responsesWithSchema.length > 0
246
- ? (() => {
247
- const responseUnionName = resolver.resolveResponseName(node)
248
-
249
- // Collect all import names from response schemas to detect naming collisions.
250
- // When a response is a $ref to a component schema whose resolved name matches
251
- // the response union name, skip generation to avoid redeclaration errors.
252
- const importedNames = new Set(
253
- responsesWithSchema.flatMap((res) =>
254
- (res.content ?? []).flatMap((entry) =>
255
- entry.schema
256
- ? adapter
257
- .getImports(entry.schema, (schemaName) => ({
258
- name: resolver.resolveSchemaName(schemaName),
259
- path: '',
260
- }))
261
- .flatMap((imp) => (Array.isArray(imp.name) ? imp.name : [imp.name]))
262
- : [],
263
- ),
264
- ),
265
- )
266
-
267
- if (importedNames.has(responseUnionName)) {
268
- return null
269
- }
270
-
271
- const members = responsesWithSchema.map((res) => ast.createSchema({ type: 'ref', name: resolver.resolveResponseStatusName(node, res.statusCode) }))
272
- const unionNode = members.length === 1 ? members[0]! : ast.createSchema({ type: 'union', members })
273
-
274
- return renderSchemaEntry({
275
- schema: unionNode,
276
- name: responseUnionName,
277
- })
278
- })()
279
- : null
280
-
281
- const requestBodyContent = node.requestBody?.content ?? []
282
- const requestSchema = (() => {
283
- if (requestBodyContent.length === 0) return null
284
- if (requestBodyContent.length === 1) {
285
- const entry = requestBodyContent[0]!
286
- if (!entry.schema) return null
287
- return renderSchemaEntry({
288
- schema: { ...entry.schema, description: node.requestBody!.description ?? entry.schema.description },
289
- name: resolver.resolveDataName(node),
290
- keysToOmit: entry.keysToOmit,
291
- direction: 'input',
292
- })
293
- }
294
- return buildContentTypeVariants(
295
- requestBodyContent,
296
- resolver.resolveDataName(node),
297
- (schema) => ({
298
- ...schema,
299
- description: node.requestBody!.description ?? schema.description,
300
- }),
301
- 'input',
302
- )
303
- })()
304
-
305
- return (
306
- <File
307
- baseName={meta.file.baseName}
308
- path={meta.file.path}
309
- meta={meta.file.meta}
310
- banner={resolver.resolveBanner(ctx.meta, { output, config, file: { path: meta.file.path, baseName: meta.file.baseName } })}
311
- footer={resolver.resolveFooter(ctx.meta, { output, config, file: { path: meta.file.path, baseName: meta.file.baseName } })}
312
- >
313
- <File.Import name={isZodImport ? 'z' : ['z']} path={importPath} isNameSpace={isZodImport} />
314
- {paramSchemas}
315
- {responseSchemas}
316
- {responseUnionSchema}
317
- {requestSchema}
318
- </File>
319
- )
320
- },
321
- operations(nodes, ctx) {
322
- const { config, resolver, root } = ctx
323
- const { output, importPath, group, operations, paramsCasing } = ctx.options
324
-
325
- if (!operations) {
326
- return
327
- }
328
- const isZodImport = ZOD_NAMESPACE_IMPORTS.has(importPath as 'zod' | 'zod/mini')
329
-
330
- const meta = {
331
- file: resolver.resolveFile({ name: 'operations', extname: '.ts' }, { root, output, group: group ?? undefined }),
332
- } as const
333
-
334
- const transformedOperations = nodes.filter(ast.isHttpOperationNode).map((node) => {
335
- const params = ast.caseParams(node.parameters, paramsCasing)
336
-
337
- return {
338
- node,
339
- data: buildSchemaNames(node, { params, resolver }),
340
- }
341
- })
342
-
343
- const imports = transformedOperations.flatMap(({ node, data }) => {
344
- const names = [data.request, ...Object.values(data.responses), ...Object.values(data.parameters)].filter(Boolean) as Array<string>
345
- const opFile = resolver.resolveFile(
346
- { name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
347
- { root, output, group: group ?? undefined },
348
- )
349
-
350
- return names.map((name) => <File.Import key={[name, opFile.path].join('-')} name={[name]} root={meta.file.path} path={opFile.path} />)
351
- })
352
-
353
- return (
354
- <File
355
- baseName={meta.file.baseName}
356
- path={meta.file.path}
357
- meta={meta.file.meta}
358
- banner={resolver.resolveBanner(ctx.meta, { output, config, file: { path: meta.file.path, baseName: meta.file.baseName } })}
359
- footer={resolver.resolveFooter(ctx.meta, { output, config, file: { path: meta.file.path, baseName: meta.file.baseName } })}
360
- >
361
- <File.Import isTypeOnly name={isZodImport ? 'z' : ['z']} path={importPath} isNameSpace={isZodImport} />
362
- {imports}
363
- <Operations name="operations" operations={transformedOperations} />
364
- </File>
365
- )
366
- },
367
- })
package/src/index.ts DELETED
@@ -1,11 +0,0 @@
1
- export { zodGenerator } from './generators/zodGenerator.tsx'
2
-
3
- export { default, pluginZod, pluginZodName } from './plugin.ts'
4
- export type { PrinterZodFactory, PrinterZodNodes, PrinterZodOptions } from './printers/printerZod.ts'
5
- export { printerZod } from './printers/printerZod.ts'
6
- export type { PrinterZodMiniFactory, PrinterZodMiniNodes, PrinterZodMiniOptions } from './printers/printerZodMini.ts'
7
- export { printerZodMini } from './printers/printerZodMini.ts'
8
-
9
- export { resolverZod } from './resolvers/resolverZod.ts'
10
-
11
- export type { PluginZod, ResolverZod } from './types.ts'
package/src/plugin.ts DELETED
@@ -1,97 +0,0 @@
1
- import { createGroupConfig } from '@internals/shared'
2
- import { definePlugin } from '@kubb/core'
3
- import { zodGenerator } from './generators/zodGenerator.tsx'
4
- import { resolverZod } from './resolvers/resolverZod.ts'
5
- import type { PluginZod } from './types.ts'
6
-
7
- /**
8
- * Canonical plugin name for `@kubb/plugin-zod`. Used for driver lookups and
9
- * cross-plugin dependency references.
10
- */
11
- export const pluginZodName = 'plugin-zod' satisfies PluginZod['name']
12
-
13
- /**
14
- * Generates Zod v4 schemas from an OpenAPI spec. Use them to validate API
15
- * responses at runtime, build form schemas, or feed back into router libraries
16
- * that consume Zod (tRPC, Hono, Elysia). Pair with `@kubb/plugin-client` and
17
- * set the client's `parser: 'zod'` to validate every response automatically.
18
- *
19
- * @example
20
- * ```ts
21
- * import { defineConfig } from 'kubb'
22
- * import { pluginTs } from '@kubb/plugin-ts'
23
- * import { pluginZod } from '@kubb/plugin-zod'
24
- *
25
- * export default defineConfig({
26
- * input: { path: './petStore.yaml' },
27
- * output: { path: './src/gen' },
28
- * plugins: [
29
- * pluginTs(),
30
- * pluginZod({
31
- * output: { path: './zod' },
32
- * typed: true,
33
- * }),
34
- * ],
35
- * })
36
- * ```
37
- */
38
- export const pluginZod = definePlugin<PluginZod>((options) => {
39
- const {
40
- output = { path: 'zod', barrel: { type: 'named' } },
41
- group,
42
- exclude = [],
43
- include,
44
- override = [],
45
- typed = false,
46
- operations = false,
47
- mini = false,
48
- guidType = 'uuid',
49
- importPath = mini ? 'zod/mini' : 'zod',
50
- coercion = false,
51
- inferred = false,
52
- wrapOutput = undefined,
53
- paramsCasing,
54
- printer,
55
- resolver: userResolver,
56
- transformer: userTransformer,
57
- generators: userGenerators = [],
58
- } = options
59
-
60
- const groupConfig = createGroupConfig(group)
61
-
62
- return {
63
- name: pluginZodName,
64
- options,
65
- hooks: {
66
- 'kubb:plugin:setup'(ctx) {
67
- ctx.setOptions({
68
- output,
69
- exclude,
70
- include,
71
- override,
72
- group: groupConfig,
73
- typed,
74
- importPath,
75
- coercion,
76
- operations,
77
- inferred,
78
- guidType,
79
- mini,
80
- wrapOutput,
81
- paramsCasing,
82
- printer,
83
- })
84
- ctx.setResolver(userResolver ? { ...resolverZod, ...userResolver } : resolverZod)
85
- if (userTransformer) {
86
- ctx.setTransformer(userTransformer)
87
- }
88
- ctx.addGenerator(zodGenerator)
89
- for (const gen of userGenerators) {
90
- ctx.addGenerator(gen)
91
- }
92
- },
93
- },
94
- }
95
- })
96
-
97
- export default pluginZod