@kubb/plugin-zod 5.0.0-alpha.9 → 5.0.0-beta.4

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.
Files changed (46) hide show
  1. package/LICENSE +17 -10
  2. package/README.md +1 -3
  3. package/dist/index.cjs +1061 -105
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.ts +369 -4
  6. package/dist/index.js +1053 -104
  7. package/dist/index.js.map +1 -1
  8. package/extension.yaml +502 -0
  9. package/package.json +44 -70
  10. package/src/components/Operations.tsx +25 -18
  11. package/src/components/Zod.tsx +21 -121
  12. package/src/constants.ts +5 -0
  13. package/src/generators/zodGenerator.tsx +174 -160
  14. package/src/index.ts +11 -2
  15. package/src/plugin.ts +67 -156
  16. package/src/printers/printerZod.ts +339 -0
  17. package/src/printers/printerZodMini.ts +295 -0
  18. package/src/resolvers/resolverZod.ts +57 -0
  19. package/src/types.ts +130 -115
  20. package/src/utils.ts +222 -0
  21. package/dist/components-B7zUFnAm.cjs +0 -890
  22. package/dist/components-B7zUFnAm.cjs.map +0 -1
  23. package/dist/components-eECfXVou.js +0 -842
  24. package/dist/components-eECfXVou.js.map +0 -1
  25. package/dist/components.cjs +0 -4
  26. package/dist/components.d.ts +0 -56
  27. package/dist/components.js +0 -2
  28. package/dist/generators-BjPDdJUz.cjs +0 -301
  29. package/dist/generators-BjPDdJUz.cjs.map +0 -1
  30. package/dist/generators-lTWPS6oN.js +0 -290
  31. package/dist/generators-lTWPS6oN.js.map +0 -1
  32. package/dist/generators.cjs +0 -4
  33. package/dist/generators.d.ts +0 -508
  34. package/dist/generators.js +0 -2
  35. package/dist/templates/ToZod.source.cjs +0 -7
  36. package/dist/templates/ToZod.source.cjs.map +0 -1
  37. package/dist/templates/ToZod.source.d.ts +0 -7
  38. package/dist/templates/ToZod.source.js +0 -6
  39. package/dist/templates/ToZod.source.js.map +0 -1
  40. package/dist/types-CoCoOc2u.d.ts +0 -172
  41. package/src/components/index.ts +0 -2
  42. package/src/generators/index.ts +0 -2
  43. package/src/generators/operationsGenerator.tsx +0 -50
  44. package/src/parser.ts +0 -909
  45. package/src/templates/ToZod.source.ts +0 -4
  46. package/templates/ToZod.ts +0 -61
package/src/utils.ts ADDED
@@ -0,0 +1,222 @@
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
+ * Collects all resolved schema names for an operation's parameters and responses
17
+ * into a single lookup object, useful for building imports and type references.
18
+ */
19
+ export function buildSchemaNames(node: ast.OperationNode, { params, resolver }: { params: Array<ast.ParameterNode>; resolver: ResolverZod }) {
20
+ const pathParam = params.find((p) => p.in === 'path')
21
+ const queryParam = params.find((p) => p.in === 'query')
22
+ const headerParam = params.find((p) => p.in === 'header')
23
+
24
+ const responses: Record<number | string, string> = {}
25
+ const errors: Record<number | string, string> = {}
26
+
27
+ for (const res of node.responses) {
28
+ const name = resolver.resolveResponseStatusName(node, res.statusCode)
29
+ const statusNum = Number(res.statusCode)
30
+
31
+ if (!Number.isNaN(statusNum)) {
32
+ responses[statusNum] = name
33
+ if (statusNum >= 400) {
34
+ errors[statusNum] = name
35
+ }
36
+ }
37
+ }
38
+
39
+ responses['default'] = resolver.resolveResponseName(node)
40
+
41
+ return {
42
+ request: node.requestBody?.content?.[0]?.schema ? resolver.resolveDataName(node) : undefined,
43
+ parameters: {
44
+ path: pathParam ? resolver.resolvePathParamsName(node, pathParam) : undefined,
45
+ query: queryParam ? resolver.resolveQueryParamsName(node, queryParam) : undefined,
46
+ header: headerParam ? resolver.resolveHeaderParamsName(node, headerParam) : undefined,
47
+ },
48
+ responses,
49
+ errors,
50
+ }
51
+ }
52
+
53
+ /**
54
+ * Format a default value as a code-level literal.
55
+ * Objects become `{}`, primitives become their string representation, strings are quoted.
56
+ */
57
+ export function formatDefault(value: unknown): string {
58
+ if (typeof value === 'string') return stringify(value)
59
+ if (typeof value === 'object' && value !== null) return '{}'
60
+
61
+ return String(value ?? '')
62
+ }
63
+
64
+ /**
65
+ * Format a primitive enum/literal value.
66
+ * Strings are quoted; numbers and booleans are emitted raw.
67
+ */
68
+ export function formatLiteral(v: string | number | boolean): string {
69
+ if (typeof v === 'string') return stringify(v)
70
+
71
+ return String(v)
72
+ }
73
+
74
+ /**
75
+ * Numeric constraint limits for Zod schemas (min, max, and exclusive bounds).
76
+ */
77
+ export type NumericConstraints = {
78
+ min?: number
79
+ max?: number
80
+ exclusiveMinimum?: number
81
+ exclusiveMaximum?: number
82
+ multipleOf?: number
83
+ }
84
+
85
+ /**
86
+ * Length constraint limits for string and array schemas (min, max, and regex pattern).
87
+ */
88
+ export type LengthConstraints = {
89
+ min?: number
90
+ max?: number
91
+ pattern?: string
92
+ }
93
+
94
+ /**
95
+ * Modifier options for applying chainable methods to Zod schema values.
96
+ */
97
+ export type ModifierOptions = {
98
+ value: string
99
+ nullable?: boolean
100
+ optional?: boolean
101
+ nullish?: boolean
102
+ defaultValue?: unknown
103
+ description?: string
104
+ }
105
+
106
+ /**
107
+ * Build `.min()` / `.max()` / `.gt()` / `.lt()` constraint chains for numbers
108
+ * using the standard chainable Zod v4 API.
109
+ */
110
+ export function numberConstraints({ min, max, exclusiveMinimum, exclusiveMaximum, multipleOf }: NumericConstraints): string {
111
+ return [
112
+ min !== undefined ? `.min(${min})` : '',
113
+ max !== undefined ? `.max(${max})` : '',
114
+ exclusiveMinimum !== undefined ? `.gt(${exclusiveMinimum})` : '',
115
+ exclusiveMaximum !== undefined ? `.lt(${exclusiveMaximum})` : '',
116
+ multipleOf !== undefined ? `.multipleOf(${multipleOf})` : '',
117
+ ].join('')
118
+ }
119
+
120
+ /**
121
+ * Build `.min()` / `.max()` / `.regex()` chains for strings/arrays
122
+ * using the standard chainable Zod v4 API.
123
+ */
124
+ export function lengthConstraints({ min, max, pattern }: LengthConstraints): string {
125
+ return [
126
+ min !== undefined ? `.min(${min})` : '',
127
+ max !== undefined ? `.max(${max})` : '',
128
+ pattern !== undefined ? `.regex(${toRegExpString(pattern, null)})` : '',
129
+ ].join('')
130
+ }
131
+
132
+ /**
133
+ * Build `.check(z.minimum(), z.maximum())` for `zod/mini` numeric constraints.
134
+ */
135
+ export function numberChecksMini({ min, max, exclusiveMinimum, exclusiveMaximum, multipleOf }: NumericConstraints): string {
136
+ const checks: string[] = []
137
+ if (min !== undefined) checks.push(`z.minimum(${min})`)
138
+ if (max !== undefined) checks.push(`z.maximum(${max})`)
139
+ if (exclusiveMinimum !== undefined) checks.push(`z.minimum(${exclusiveMinimum}, { exclusive: true })`)
140
+ if (exclusiveMaximum !== undefined) checks.push(`z.maximum(${exclusiveMaximum}, { exclusive: true })`)
141
+ if (multipleOf !== undefined) checks.push(`z.multipleOf(${multipleOf})`)
142
+ return checks.length ? `.check(${checks.join(', ')})` : ''
143
+ }
144
+
145
+ /**
146
+ * Build `.check(z.minLength(), z.maxLength(), z.regex())` for `zod/mini` length constraints.
147
+ */
148
+ export function lengthChecksMini({ min, max, pattern }: LengthConstraints): string {
149
+ const checks: string[] = []
150
+ if (min !== undefined) checks.push(`z.minLength(${min})`)
151
+ if (max !== undefined) checks.push(`z.maxLength(${max})`)
152
+ if (pattern !== undefined) checks.push(`z.regex(${toRegExpString(pattern, null)})`)
153
+ return checks.length ? `.check(${checks.join(', ')})` : ''
154
+ }
155
+
156
+ /**
157
+ * Apply nullable / optional / nullish modifiers and an optional `.describe()` call
158
+ * to a schema value string using the chainable Zod v4 API.
159
+ */
160
+ export function applyModifiers({ value, nullable, optional, nullish, defaultValue, description }: ModifierOptions): string {
161
+ let result = value
162
+ if (nullish || (nullable && optional)) {
163
+ result = `${result}.nullish()`
164
+ } else if (optional) {
165
+ result = `${result}.optional()`
166
+ } else if (nullable) {
167
+ result = `${result}.nullable()`
168
+ }
169
+ if (defaultValue !== undefined) {
170
+ result = `${result}.default(${formatDefault(defaultValue)})`
171
+ }
172
+ if (description) {
173
+ result = `${result}.describe(${stringify(description)})`
174
+ }
175
+ return result
176
+ }
177
+
178
+ /**
179
+ * Apply nullable / optional / nullish modifiers using the functional `zod/mini` API
180
+ * (`z.nullable()`, `z.optional()`, `z.nullish()`).
181
+ */
182
+ export function applyMiniModifiers({ value, nullable, optional, nullish, defaultValue }: Omit<ModifierOptions, 'description'>): string {
183
+ let result = value
184
+ if (nullish) {
185
+ result = `z.nullish(${result})`
186
+ } else {
187
+ if (nullable) {
188
+ result = `z.nullable(${result})`
189
+ }
190
+ if (optional) {
191
+ result = `z.optional(${result})`
192
+ }
193
+ }
194
+ if (defaultValue !== undefined) {
195
+ result = `z._default(${result}, ${formatDefault(defaultValue)})`
196
+ }
197
+ return result
198
+ }
199
+
200
+ type BuildGroupedParamsSchemaOptions = {
201
+ params: Array<ast.ParameterNode>
202
+ optional?: boolean
203
+ }
204
+
205
+ /**
206
+ * Builds an `object` schema node grouping the given parameter nodes.
207
+ * The `primitive: 'object'` marker ensures the Zod printer emits `z.object(…)` rather than a record.
208
+ */
209
+ export function buildGroupedParamsSchema({ params, optional }: BuildGroupedParamsSchemaOptions): ast.SchemaNode {
210
+ return ast.createSchema({
211
+ type: 'object',
212
+ optional,
213
+ primitive: 'object',
214
+ properties: params.map((param) =>
215
+ ast.createProperty({
216
+ name: param.name,
217
+ required: param.required,
218
+ schema: param.schema,
219
+ }),
220
+ ),
221
+ })
222
+ }