@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,78 +0,0 @@
1
- import { stringifyObject } from '@internals/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,366 +0,0 @@
1
- import { resolveContentTypeVariants } from '@internals/shared'
2
- import type { Adapter } from '@kubb/core'
3
- import { ast, defineGenerator } from '@kubb/core'
4
- import type { AdapterOas } from '@kubb/adapter-oas'
5
- import { File, jsxRendererSync } from '@kubb/renderer-jsx'
6
- import { Operations } from '../components/Operations.tsx'
7
- import { Zod } from '../components/Zod.tsx'
8
- import { ZOD_NAMESPACE_IMPORTS } from '../constants.ts'
9
- import { printerZod } from '../printers/printerZod.ts'
10
- import { printerZodMini } from '../printers/printerZodMini.ts'
11
- import type { PluginZod, ResolverZod } from '../types'
12
- import { buildSchemaNames, containsCodec } from '../utils.ts'
13
-
14
- type StdPrinters = { output: ReturnType<typeof printerZod>; input: ReturnType<typeof printerZod> }
15
- type ZodPrinterEntry = StdPrinters & { coercion: unknown; guidType: unknown; dateType: unknown }
16
- type ZodMiniPrinterEntry = { printer: ReturnType<typeof printerZodMini>; guidType: unknown }
17
-
18
- // Per-build caches: keyed on resolver (unique per plugin instance per build, GC'd when released)
19
- const zodPrinterCache = new WeakMap<ResolverZod, ZodPrinterEntry>()
20
- const zodMiniPrinterCache = new WeakMap<ResolverZod, ZodMiniPrinterEntry>()
21
-
22
- type StdPrinterParams = { coercion: unknown; guidType: unknown; dateType: unknown; wrapOutput: unknown; cyclicSchemas: ReadonlySet<string>; nodes: unknown }
23
-
24
- /**
25
- * Returns the cached `output`/`input` direction printers for a resolver, building them on
26
- * first use. The `input` printer encodes `Date → string` for request bodies; `output` decodes
27
- * `string → Date` for responses. Schemas without `dateType: 'date'` fields print identically.
28
- */
29
- function getStdPrinters(resolver: ResolverZod, params: StdPrinterParams): StdPrinters {
30
- const cached = zodPrinterCache.get(resolver)
31
- if (cached && cached.coercion === params.coercion && cached.guidType === params.guidType && cached.dateType === params.dateType) {
32
- return { output: cached.output, input: cached.input }
33
- }
34
- const base = { ...params, resolver } as Parameters<typeof printerZod>[0]
35
- const output = printerZod({ ...base, direction: 'output' })
36
- const input = printerZod({ ...base, direction: 'input' })
37
- zodPrinterCache.set(resolver, { output, input, coercion: params.coercion, guidType: params.guidType, dateType: params.dateType })
38
- return { output, input }
39
- }
40
-
41
- function getMiniPrinter(resolver: ResolverZod, params: { guidType: unknown; wrapOutput: unknown; cyclicSchemas: ReadonlySet<string>; nodes: unknown }) {
42
- const cached = zodMiniPrinterCache.get(resolver)
43
- if (cached && cached.guidType === params.guidType) return cached.printer
44
- const p = printerZodMini({ ...params, resolver } as Parameters<typeof printerZodMini>[0])
45
- zodMiniPrinterCache.set(resolver, { printer: p, guidType: params.guidType })
46
- return p
47
- }
48
-
49
- /**
50
- * Built-in generator for `@kubb/plugin-zod`. Emits one Zod schema per
51
- * schema in the spec plus per-operation request/response/parameter schemas.
52
- * When `mini: true`, schemas use the Zod Mini functional API instead of
53
- * chainable methods.
54
- */
55
- export const zodGenerator = defineGenerator<PluginZod>({
56
- name: 'zod',
57
- renderer: jsxRendererSync,
58
- schema(node, ctx) {
59
- const { adapter, config, resolver, root } = ctx
60
- const { output, coercion, guidType, mini, wrapOutput, inferred, importPath, group, printer } = ctx.options
61
- const dateType = (adapter as Adapter<AdapterOas>).options.dateType
62
-
63
- if (!node.name) {
64
- return
65
- }
66
-
67
- const mode = ctx.getMode(output)
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) ? (ast.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
- {mode === 'split' &&
120
- imports.map((imp) => <File.Import key={[node.name, imp.path, imp.name].join('-')} root={meta.file.path} path={imp.path} name={imp.name} />)}
121
-
122
- <Zod name={meta.name} node={node} printer={schemaPrinter} inferTypeName={inferTypeName} />
123
- {hasCodec && stdPrinters && (
124
- <Zod
125
- name={resolver.resolveInputSchemaName(node.name)}
126
- node={node}
127
- printer={stdPrinters.input}
128
- inferTypeName={inferred ? resolver.resolveInputSchemaTypeName(node.name) : null}
129
- />
130
- )}
131
- </File>
132
- )
133
- },
134
- operation(node, ctx) {
135
- if (!ast.isHttpOperationNode(node)) return null
136
- const { adapter, config, resolver, root } = ctx
137
- const { output, coercion, guidType, mini, wrapOutput, inferred, importPath, group, paramsCasing, printer } = ctx.options
138
- const dateType = (adapter as Adapter<AdapterOas>).options.dateType
139
-
140
- const mode = ctx.getMode(output)
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) ? (ast.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
- {mode === 'split' &&
194
- imports.map((imp) => <File.Import key={[name, imp.path, imp.name].join('-')} root={meta.file.path} path={imp.path} name={imp.name} />)}
195
- <Zod name={name} node={schema} printer={schemaPrinter} inferTypeName={inferTypeName} />
196
- </>
197
- )
198
- }
199
-
200
- // Multiple content types for a single name — emit one schema per content type plus a union alias.
201
- function buildContentTypeVariants(
202
- entries: Array<{ contentType: string; schema?: ast.SchemaNode | null; keysToOmit?: Array<string> | null }>,
203
- baseName: string,
204
- decorate?: (schema: ast.SchemaNode) => ast.SchemaNode,
205
- direction?: 'input' | 'output',
206
- ) {
207
- const variants = resolveContentTypeVariants(entries, baseName)
208
- const unionSchema = ast.createSchema({
209
- type: 'union',
210
- members: variants.map((variant) => ast.createSchema({ type: 'ref', name: variant.name })),
211
- })
212
- return (
213
- <>
214
- {variants.map((variant) =>
215
- renderSchemaEntry({
216
- schema: decorate ? decorate(variant.schema) : variant.schema,
217
- name: variant.name,
218
- keysToOmit: variant.keysToOmit,
219
- direction,
220
- }),
221
- )}
222
- {renderSchemaEntry({ schema: unionSchema, name: baseName, direction })}
223
- </>
224
- )
225
- }
226
-
227
- const paramSchemas = params.map((param) => renderSchemaEntry({ schema: param.schema, name: resolver.resolveParamName(node, param), direction: 'input' }))
228
-
229
- const responseSchemas = node.responses.map((res) => {
230
- const variants = (res.content ?? []).filter((entry) => entry.schema)
231
- if (variants.length > 1) {
232
- return buildContentTypeVariants(res.content!, resolver.resolveResponseStatusName(node, res.statusCode))
233
- }
234
- const primary = variants[0] ?? res.content?.[0]
235
- return renderSchemaEntry({
236
- schema: primary?.schema ?? null,
237
- name: resolver.resolveResponseStatusName(node, res.statusCode),
238
- keysToOmit: primary?.keysToOmit,
239
- })
240
- })
241
-
242
- const responsesWithSchema = node.responses.filter((res) => res.content?.some((entry) => entry.schema))
243
- const responseUnionSchema =
244
- responsesWithSchema.length > 0
245
- ? (() => {
246
- const responseUnionName = resolver.resolveResponseName(node)
247
-
248
- // Collect all import names from response schemas to detect naming collisions.
249
- // When a response is a $ref to a component schema whose resolved name matches
250
- // the response union name, skip generation to avoid redeclaration errors.
251
- const importedNames = new Set(
252
- responsesWithSchema.flatMap((res) =>
253
- (res.content ?? []).flatMap((entry) =>
254
- entry.schema
255
- ? adapter
256
- .getImports(entry.schema, (schemaName) => ({
257
- name: resolver.resolveSchemaName(schemaName),
258
- path: '',
259
- }))
260
- .flatMap((imp) => (Array.isArray(imp.name) ? imp.name : [imp.name]))
261
- : [],
262
- ),
263
- ),
264
- )
265
-
266
- if (importedNames.has(responseUnionName)) {
267
- return null
268
- }
269
-
270
- const members = responsesWithSchema.map((res) => ast.createSchema({ type: 'ref', name: resolver.resolveResponseStatusName(node, res.statusCode) }))
271
- const unionNode = members.length === 1 ? members[0]! : ast.createSchema({ type: 'union', members })
272
-
273
- return renderSchemaEntry({
274
- schema: unionNode,
275
- name: responseUnionName,
276
- })
277
- })()
278
- : null
279
-
280
- const requestBodyContent = node.requestBody?.content ?? []
281
- const requestSchema = (() => {
282
- if (requestBodyContent.length === 0) return null
283
- if (requestBodyContent.length === 1) {
284
- const entry = requestBodyContent[0]!
285
- if (!entry.schema) return null
286
- return renderSchemaEntry({
287
- schema: { ...entry.schema, description: node.requestBody!.description ?? entry.schema.description },
288
- name: resolver.resolveDataName(node),
289
- keysToOmit: entry.keysToOmit,
290
- direction: 'input',
291
- })
292
- }
293
- return buildContentTypeVariants(
294
- requestBodyContent,
295
- resolver.resolveDataName(node),
296
- (schema) => ({
297
- ...schema,
298
- description: node.requestBody!.description ?? schema.description,
299
- }),
300
- 'input',
301
- )
302
- })()
303
-
304
- return (
305
- <File
306
- baseName={meta.file.baseName}
307
- path={meta.file.path}
308
- meta={meta.file.meta}
309
- banner={resolver.resolveBanner(ctx.meta, { output, config, file: { path: meta.file.path, baseName: meta.file.baseName } })}
310
- footer={resolver.resolveFooter(ctx.meta, { output, config, file: { path: meta.file.path, baseName: meta.file.baseName } })}
311
- >
312
- <File.Import name={isZodImport ? 'z' : ['z']} path={importPath} isNameSpace={isZodImport} />
313
- {paramSchemas}
314
- {responseSchemas}
315
- {responseUnionSchema}
316
- {requestSchema}
317
- </File>
318
- )
319
- },
320
- operations(nodes, ctx) {
321
- const { config, resolver, root } = ctx
322
- const { output, importPath, group, operations, paramsCasing } = ctx.options
323
-
324
- if (!operations) {
325
- return
326
- }
327
- const isZodImport = ZOD_NAMESPACE_IMPORTS.has(importPath as 'zod' | 'zod/mini')
328
-
329
- const meta = {
330
- file: resolver.resolveFile({ name: 'operations', extname: '.ts' }, { root, output, group: group ?? undefined }),
331
- } as const
332
-
333
- const transformedOperations = nodes.filter(ast.isHttpOperationNode).map((node) => {
334
- const params = ast.caseParams(node.parameters, paramsCasing)
335
-
336
- return {
337
- node,
338
- data: buildSchemaNames(node, { params, resolver }),
339
- }
340
- })
341
-
342
- const imports = transformedOperations.flatMap(({ node, data }) => {
343
- const names = [data.request, ...Object.values(data.responses), ...Object.values(data.parameters)].filter(Boolean) as Array<string>
344
- const opFile = resolver.resolveFile(
345
- { name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
346
- { root, output, group: group ?? undefined },
347
- )
348
-
349
- return names.map((name) => <File.Import key={[name, opFile.path].join('-')} name={[name]} root={meta.file.path} path={opFile.path} />)
350
- })
351
-
352
- return (
353
- <File
354
- baseName={meta.file.baseName}
355
- path={meta.file.path}
356
- meta={meta.file.meta}
357
- banner={resolver.resolveBanner(ctx.meta, { output, config, file: { path: meta.file.path, baseName: meta.file.baseName } })}
358
- footer={resolver.resolveFooter(ctx.meta, { output, config, file: { path: meta.file.path, baseName: meta.file.baseName } })}
359
- >
360
- <File.Import isTypeOnly name={isZodImport ? 'z' : ['z']} path={importPath} isNameSpace={isZodImport} />
361
- {imports}
362
- <Operations name="operations" operations={transformedOperations} />
363
- </File>
364
- )
365
- },
366
- })
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', barrelType: '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, { suffix: 'Controller' })
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