@kubb/plugin-zod 5.0.0-beta.10 → 5.0.0-beta.15
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 +73 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +74 -32
- package/dist/index.js.map +1 -1
- package/extension.yaml +21 -1
- package/package.json +5 -5
- package/src/generators/zodGenerator.tsx +52 -19
- package/src/printers/printerZod.ts +4 -1
- package/src/printers/printerZodMini.ts +4 -1
|
@@ -1,20 +1,27 @@
|
|
|
1
1
|
import type { Adapter } from '@kubb/core'
|
|
2
2
|
import { ast, defineGenerator } from '@kubb/core'
|
|
3
3
|
import type { AdapterOas } from '@kubb/adapter-oas'
|
|
4
|
-
import { File,
|
|
4
|
+
import { File, jsxRendererSync } from '@kubb/renderer-jsx'
|
|
5
5
|
import { Operations } from '../components/Operations.tsx'
|
|
6
6
|
import { Zod } from '../components/Zod.tsx'
|
|
7
7
|
import { ZOD_NAMESPACE_IMPORTS } from '../constants.ts'
|
|
8
8
|
import { printerZod } from '../printers/printerZod.ts'
|
|
9
9
|
import { printerZodMini } from '../printers/printerZodMini.ts'
|
|
10
|
-
import type { PluginZod } from '../types'
|
|
10
|
+
import type { PluginZod, ResolverZod } from '../types'
|
|
11
11
|
import { buildSchemaNames } from '../utils.ts'
|
|
12
12
|
|
|
13
|
+
type ZodPrinterEntry = { printer: ReturnType<typeof printerZod>; coercion: unknown; guidType: unknown; dateType: unknown }
|
|
14
|
+
type ZodMiniPrinterEntry = { printer: ReturnType<typeof printerZodMini>; guidType: unknown }
|
|
15
|
+
|
|
16
|
+
// Per-build caches: keyed on resolver (unique per plugin instance per build, GC'd when released)
|
|
17
|
+
const zodPrinterCache = new WeakMap<ResolverZod, ZodPrinterEntry>()
|
|
18
|
+
const zodMiniPrinterCache = new WeakMap<ResolverZod, ZodMiniPrinterEntry>()
|
|
19
|
+
|
|
13
20
|
export const zodGenerator = defineGenerator<PluginZod>({
|
|
14
21
|
name: 'zod',
|
|
15
|
-
renderer:
|
|
22
|
+
renderer: jsxRendererSync,
|
|
16
23
|
schema(node, ctx) {
|
|
17
|
-
const { adapter, config, resolver, root } = ctx
|
|
24
|
+
const { adapter, config, resolver, root, inputNode } = ctx
|
|
18
25
|
const { output, coercion, guidType, mini, wrapOutput, inferred, importPath, group, printer } = ctx.options
|
|
19
26
|
const dateType = (adapter as Adapter<AdapterOas>).options.dateType
|
|
20
27
|
|
|
@@ -37,19 +44,35 @@ export const zodGenerator = defineGenerator<PluginZod>({
|
|
|
37
44
|
|
|
38
45
|
const inferTypeName = inferred ? resolver.resolveSchemaTypeName(node.name) : undefined
|
|
39
46
|
|
|
40
|
-
const cyclicSchemas =
|
|
47
|
+
const cyclicSchemas = ast.findCircularSchemas(inputNode.schemas)
|
|
41
48
|
|
|
42
|
-
const schemaPrinter = mini
|
|
43
|
-
|
|
44
|
-
|
|
49
|
+
const schemaPrinter = mini ? getCachedMiniPrinter() : getCachedStdPrinter()
|
|
50
|
+
function getCachedStdPrinter() {
|
|
51
|
+
const cached = zodPrinterCache.get(resolver)
|
|
52
|
+
if (cached && cached.coercion === coercion && cached.guidType === guidType && cached.dateType === dateType) {
|
|
53
|
+
return cached.printer
|
|
54
|
+
}
|
|
55
|
+
const p = printerZod({ coercion, guidType, dateType, wrapOutput, resolver, cyclicSchemas, nodes: printer?.nodes })
|
|
56
|
+
zodPrinterCache.set(resolver, { printer: p, coercion, guidType, dateType })
|
|
57
|
+
return p
|
|
58
|
+
}
|
|
59
|
+
function getCachedMiniPrinter() {
|
|
60
|
+
const cached = zodMiniPrinterCache.get(resolver)
|
|
61
|
+
if (cached && cached.guidType === guidType) {
|
|
62
|
+
return cached.printer
|
|
63
|
+
}
|
|
64
|
+
const p = printerZodMini({ guidType, wrapOutput, resolver, cyclicSchemas, nodes: printer?.nodes })
|
|
65
|
+
zodMiniPrinterCache.set(resolver, { printer: p, guidType })
|
|
66
|
+
return p
|
|
67
|
+
}
|
|
45
68
|
|
|
46
69
|
return (
|
|
47
70
|
<File
|
|
48
71
|
baseName={meta.file.baseName}
|
|
49
72
|
path={meta.file.path}
|
|
50
73
|
meta={meta.file.meta}
|
|
51
|
-
banner={resolver.resolveBanner(
|
|
52
|
-
footer={resolver.resolveFooter(
|
|
74
|
+
banner={resolver.resolveBanner(inputNode, { output, config })}
|
|
75
|
+
footer={resolver.resolveFooter(inputNode, { output, config })}
|
|
53
76
|
>
|
|
54
77
|
<File.Import name={isZodImport ? 'z' : ['z']} path={importPath} isNameSpace={isZodImport} />
|
|
55
78
|
{mode === 'split' && imports.map((imp) => <File.Import key={[node.name, imp.path].join('-')} root={meta.file.path} path={imp.path} name={imp.name} />)}
|
|
@@ -59,7 +82,7 @@ export const zodGenerator = defineGenerator<PluginZod>({
|
|
|
59
82
|
)
|
|
60
83
|
},
|
|
61
84
|
operation(node, ctx) {
|
|
62
|
-
const { adapter, config, resolver, root } = ctx
|
|
85
|
+
const { adapter, config, resolver, root, inputNode } = ctx
|
|
63
86
|
const { output, coercion, guidType, mini, wrapOutput, inferred, importPath, group, paramsCasing, printer } = ctx.options
|
|
64
87
|
const dateType = (adapter as Adapter<AdapterOas>).options.dateType
|
|
65
88
|
|
|
@@ -72,7 +95,7 @@ export const zodGenerator = defineGenerator<PluginZod>({
|
|
|
72
95
|
file: resolver.resolveFile({ name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path }, { root, output, group }),
|
|
73
96
|
} as const
|
|
74
97
|
|
|
75
|
-
const cyclicSchemas =
|
|
98
|
+
const cyclicSchemas = ast.findCircularSchemas(inputNode.schemas)
|
|
76
99
|
|
|
77
100
|
function renderSchemaEntry({ schema, name, keysToOmit }: { schema: ast.SchemaNode | null; name: string; keysToOmit?: Array<string> }) {
|
|
78
101
|
if (!schema) return null
|
|
@@ -84,9 +107,19 @@ export const zodGenerator = defineGenerator<PluginZod>({
|
|
|
84
107
|
path: resolver.resolveFile({ name: schemaName, extname: '.ts' }, { root, output, group }).path,
|
|
85
108
|
}))
|
|
86
109
|
|
|
110
|
+
const cachedStd = zodPrinterCache.get(resolver)
|
|
111
|
+
const cachedMini = zodMiniPrinterCache.get(resolver)
|
|
87
112
|
const schemaPrinter = mini
|
|
88
|
-
?
|
|
89
|
-
|
|
113
|
+
? keysToOmit?.length
|
|
114
|
+
? printerZodMini({ guidType, wrapOutput, resolver, keysToOmit, cyclicSchemas, nodes: printer?.nodes })
|
|
115
|
+
: cachedMini?.guidType === guidType
|
|
116
|
+
? cachedMini.printer
|
|
117
|
+
: printerZodMini({ guidType, wrapOutput, resolver, cyclicSchemas, nodes: printer?.nodes })
|
|
118
|
+
: keysToOmit?.length
|
|
119
|
+
? printerZod({ coercion, guidType, dateType, wrapOutput, resolver, keysToOmit, cyclicSchemas, nodes: printer?.nodes })
|
|
120
|
+
: cachedStd?.coercion === coercion && cachedStd?.guidType === guidType && cachedStd?.dateType === dateType
|
|
121
|
+
? cachedStd.printer
|
|
122
|
+
: printerZod({ coercion, guidType, dateType, wrapOutput, resolver, cyclicSchemas, nodes: printer?.nodes })
|
|
90
123
|
|
|
91
124
|
return (
|
|
92
125
|
<>
|
|
@@ -159,8 +192,8 @@ export const zodGenerator = defineGenerator<PluginZod>({
|
|
|
159
192
|
baseName={meta.file.baseName}
|
|
160
193
|
path={meta.file.path}
|
|
161
194
|
meta={meta.file.meta}
|
|
162
|
-
banner={resolver.resolveBanner(
|
|
163
|
-
footer={resolver.resolveFooter(
|
|
195
|
+
banner={resolver.resolveBanner(inputNode, { output, config })}
|
|
196
|
+
footer={resolver.resolveFooter(inputNode, { output, config })}
|
|
164
197
|
>
|
|
165
198
|
<File.Import name={isZodImport ? 'z' : ['z']} path={importPath} isNameSpace={isZodImport} />
|
|
166
199
|
{paramSchemas}
|
|
@@ -171,7 +204,7 @@ export const zodGenerator = defineGenerator<PluginZod>({
|
|
|
171
204
|
)
|
|
172
205
|
},
|
|
173
206
|
operations(nodes, ctx) {
|
|
174
|
-
const {
|
|
207
|
+
const { config, resolver, root, inputNode } = ctx
|
|
175
208
|
const { output, importPath, group, operations, paramsCasing } = ctx.options
|
|
176
209
|
|
|
177
210
|
if (!operations) {
|
|
@@ -204,8 +237,8 @@ export const zodGenerator = defineGenerator<PluginZod>({
|
|
|
204
237
|
baseName={meta.file.baseName}
|
|
205
238
|
path={meta.file.path}
|
|
206
239
|
meta={meta.file.meta}
|
|
207
|
-
banner={resolver.resolveBanner(
|
|
208
|
-
footer={resolver.resolveFooter(
|
|
240
|
+
banner={resolver.resolveBanner(inputNode, { output, config })}
|
|
241
|
+
footer={resolver.resolveFooter(inputNode, { output, config })}
|
|
209
242
|
>
|
|
210
243
|
<File.Import isTypeOnly name={isZodImport ? 'z' : ['z']} path={importPath} isNameSpace={isZodImport} />
|
|
211
244
|
{imports}
|
|
@@ -208,9 +208,12 @@ export const printerZod = ast.definePrinter<PrinterZodFactory>((options) => {
|
|
|
208
208
|
const hasSelfRef = this.options.cyclicSchemas != null && ast.containsCircularRef(schema, { circularSchemas: this.options.cyclicSchemas })
|
|
209
209
|
// Inside a getter the getter itself defers evaluation, so suppress
|
|
210
210
|
// z.lazy() wrapping on nested refs by temporarily clearing cyclicSchemas.
|
|
211
|
+
// Save before clearing: this.options === options (same reference via definePrinter),
|
|
212
|
+
// so reading options.cyclicSchemas after mutation would return undefined.
|
|
213
|
+
const savedCyclicSchemas = this.options.cyclicSchemas
|
|
211
214
|
if (hasSelfRef) this.options.cyclicSchemas = undefined
|
|
212
215
|
const baseOutput = this.transform(schema) ?? this.transform(ast.createSchema({ type: 'unknown' }))!
|
|
213
|
-
if (hasSelfRef) this.options.cyclicSchemas =
|
|
216
|
+
if (hasSelfRef) this.options.cyclicSchemas = savedCyclicSchemas
|
|
214
217
|
|
|
215
218
|
const wrappedOutput = this.options.wrapOutput ? this.options.wrapOutput({ output: baseOutput, schema }) || baseOutput : baseOutput
|
|
216
219
|
|
|
@@ -177,9 +177,12 @@ export const printerZodMini = ast.definePrinter<PrinterZodMiniFactory>((options)
|
|
|
177
177
|
const hasSelfRef = this.options.cyclicSchemas != null && ast.containsCircularRef(schema, { circularSchemas: this.options.cyclicSchemas })
|
|
178
178
|
// Inside a getter the getter itself defers evaluation, so suppress
|
|
179
179
|
// z.lazy() wrapping on nested refs by temporarily clearing cyclicSchemas.
|
|
180
|
+
// Save before clearing: this.options === options (same reference via definePrinter),
|
|
181
|
+
// so reading options.cyclicSchemas after mutation would return undefined.
|
|
182
|
+
const savedCyclicSchemas = this.options.cyclicSchemas
|
|
180
183
|
if (hasSelfRef) this.options.cyclicSchemas = undefined
|
|
181
184
|
const baseOutput = this.transform(schema) ?? this.transform(ast.createSchema({ type: 'unknown' }))!
|
|
182
|
-
if (hasSelfRef) this.options.cyclicSchemas =
|
|
185
|
+
if (hasSelfRef) this.options.cyclicSchemas = savedCyclicSchemas
|
|
183
186
|
|
|
184
187
|
const wrappedOutput = this.options.wrapOutput ? this.options.wrapOutput({ output: baseOutput, schema }) || baseOutput : baseOutput
|
|
185
188
|
|