@kubb/plugin-zod 5.0.0-alpha.29 → 5.0.0-alpha.30

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,7 +1,6 @@
1
- import path from 'node:path'
2
- import { caseParams, transform } from '@kubb/ast'
1
+ import { caseParams } from '@kubb/ast'
3
2
  import type { SchemaNode } from '@kubb/ast/types'
4
- import { defineGenerator, getMode } from '@kubb/core'
3
+ import { defineGenerator } from '@kubb/core'
5
4
  import { File } from '@kubb/react-fabric'
6
5
  import { Operations } from '../components/Operations.tsx'
7
6
  import { Zod } from '../components/Zod.tsx'
@@ -13,31 +12,28 @@ import { buildSchemaNames } from '../utils.ts'
13
12
 
14
13
  export const zodGenerator = defineGenerator<PluginZod>({
15
14
  name: 'zod',
16
- type: 'react',
17
- Schema({ node, adapter, options, config, resolver, plugin }) {
15
+ schema(node, options) {
16
+ const { adapter, config, resolver, root } = this
18
17
  const { output, coercion, guidType, mini, wrapOutput, inferred, importPath, group, printer } = options
19
18
 
20
- const transformedNode = plugin.transformer ? transform(node, plugin.transformer) : node
21
-
22
- if (!transformedNode.name) {
19
+ if (!node.name) {
23
20
  return
24
21
  }
25
22
 
26
- const root = path.resolve(config.root, config.output.path)
27
- const mode = getMode(path.resolve(root, output.path))
23
+ const mode = this.getMode(output)
28
24
  const isZodImport = ZOD_NAMESPACE_IMPORTS.has(importPath as 'zod' | 'zod/mini')
29
25
 
30
- const imports = adapter.getImports(transformedNode, (schemaName) => ({
26
+ const imports = adapter.getImports(node, (schemaName) => ({
31
27
  name: resolver.resolveSchemaName(schemaName),
32
28
  path: resolver.resolveFile({ name: schemaName, extname: '.ts' }, { root, output, group }).path,
33
29
  }))
34
30
 
35
31
  const meta = {
36
- name: resolver.resolveSchemaName(transformedNode.name),
37
- file: resolver.resolveFile({ name: transformedNode.name, extname: '.ts' }, { root, output, group }),
32
+ name: resolver.resolveSchemaName(node.name),
33
+ file: resolver.resolveFile({ name: node.name, extname: '.ts' }, { root, output, group }),
38
34
  } as const
39
35
 
40
- const inferTypeName = inferred ? resolver.resolveSchemaTypeName(transformedNode.name) : undefined
36
+ const inferTypeName = inferred ? resolver.resolveSchemaTypeName(node.name) : undefined
41
37
 
42
38
  const schemaPrinter = mini
43
39
  ? printerZodMini({ guidType, wrapOutput, resolver, schemaName: meta.name, nodes: printer?.nodes })
@@ -52,29 +48,23 @@ export const zodGenerator = defineGenerator<PluginZod>({
52
48
  footer={resolver.resolveFooter(adapter.rootNode, { output, config })}
53
49
  >
54
50
  <File.Import name={isZodImport ? 'z' : ['z']} path={importPath} isNameSpace={isZodImport} />
55
- {mode === 'split' &&
56
- imports.map((imp) => <File.Import key={[transformedNode.name, imp.path].join('-')} root={meta.file.path} path={imp.path} name={imp.name} />)}
51
+ {mode === 'split' && imports.map((imp) => <File.Import key={[node.name, imp.path].join('-')} root={meta.file.path} path={imp.path} name={imp.name} />)}
57
52
 
58
- <Zod name={meta.name} node={transformedNode} printer={schemaPrinter} inferTypeName={inferTypeName} />
53
+ <Zod name={meta.name} node={node} printer={schemaPrinter} inferTypeName={inferTypeName} />
59
54
  </File>
60
55
  )
61
56
  },
62
- Operation({ node, adapter, options, config, resolver, plugin }) {
57
+ operation(node, options) {
58
+ const { adapter, config, resolver, root } = this
63
59
  const { output, coercion, guidType, mini, wrapOutput, inferred, importPath, group, paramsCasing, printer } = options
64
60
 
65
- const transformedNode = plugin.transformer ? transform(node, plugin.transformer) : node
66
-
67
- const root = path.resolve(config.root, config.output.path)
68
- const mode = getMode(path.resolve(root, output.path))
61
+ const mode = this.getMode(output)
69
62
  const isZodImport = ZOD_NAMESPACE_IMPORTS.has(importPath as 'zod' | 'zod/mini')
70
63
 
71
- const params = caseParams(transformedNode.parameters, paramsCasing)
64
+ const params = caseParams(node.parameters, paramsCasing)
72
65
 
73
66
  const meta = {
74
- file: resolver.resolveFile(
75
- { name: transformedNode.operationId, extname: '.ts', tag: transformedNode.tags[0] ?? 'default', path: transformedNode.path },
76
- { root, output, group },
77
- ),
67
+ file: resolver.resolveFile({ name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path }, { root, output, group }),
78
68
  } as const
79
69
 
80
70
  function renderSchemaEntry({ schema, name, keysToOmit }: { schema: SchemaNode | null; name: string; keysToOmit?: Array<string> }) {
@@ -102,22 +92,22 @@ export const zodGenerator = defineGenerator<PluginZod>({
102
92
 
103
93
  const paramSchemas = params.map((param) => renderSchemaEntry({ schema: param.schema, name: resolver.resolveParamName(node, param) }))
104
94
 
105
- const responseSchemas = transformedNode.responses.map((res) =>
95
+ const responseSchemas = node.responses.map((res) =>
106
96
  renderSchemaEntry({
107
97
  schema: res.schema,
108
- name: resolver.resolveResponseStatusName(transformedNode, res.statusCode),
98
+ name: resolver.resolveResponseStatusName(node, res.statusCode),
109
99
  keysToOmit: res.keysToOmit,
110
100
  }),
111
101
  )
112
102
 
113
- const requestSchema = transformedNode.requestBody?.schema
103
+ const requestSchema = node.requestBody?.schema
114
104
  ? renderSchemaEntry({
115
105
  schema: {
116
- ...transformedNode.requestBody.schema,
117
- description: transformedNode.requestBody.description ?? transformedNode.requestBody.schema.description,
106
+ ...node.requestBody.schema,
107
+ description: node.requestBody.description ?? node.requestBody.schema.description,
118
108
  },
119
- name: resolver.resolveDataName(transformedNode),
120
- keysToOmit: transformedNode.requestBody.keysToOmit,
109
+ name: resolver.resolveDataName(node),
110
+ keysToOmit: node.requestBody.keysToOmit,
121
111
  })
122
112
  : null
123
113
 
@@ -136,14 +126,13 @@ export const zodGenerator = defineGenerator<PluginZod>({
136
126
  </File>
137
127
  )
138
128
  },
139
- Operations({ nodes, adapter, options, config, resolver, plugin }) {
129
+ operations(nodes, options) {
130
+ const { adapter, config, resolver, root } = this
140
131
  const { output, importPath, group, operations, paramsCasing } = options
141
132
 
142
133
  if (!operations) {
143
134
  return
144
135
  }
145
-
146
- const root = path.resolve(config.root, config.output.path)
147
136
  const isZodImport = ZOD_NAMESPACE_IMPORTS.has(importPath as 'zod' | 'zod/mini')
148
137
 
149
138
  const meta = {
@@ -151,13 +140,11 @@ export const zodGenerator = defineGenerator<PluginZod>({
151
140
  } as const
152
141
 
153
142
  const transformedOperations = nodes.map((node) => {
154
- const transformedNode = plugin.transformer ? transform(node, plugin.transformer) : node
155
-
156
- const params = caseParams(transformedNode.parameters, paramsCasing)
143
+ const params = caseParams(node.parameters, paramsCasing)
157
144
 
158
145
  return {
159
- node: transformedNode,
160
- data: buildSchemaNames(transformedNode, { params, resolver }),
146
+ node,
147
+ data: buildSchemaNames(node, { params, resolver }),
161
148
  }
162
149
  })
163
150
 
@@ -1,7 +1,6 @@
1
- import path from 'node:path'
2
- import { caseParams, createProperty, createSchema, transform } from '@kubb/ast'
1
+ import { caseParams, createProperty, createSchema } from '@kubb/ast'
3
2
  import type { OperationNode, ParameterNode, SchemaNode } from '@kubb/ast/types'
4
- import { defineGenerator, getMode } from '@kubb/core'
3
+ import { defineGenerator } from '@kubb/core'
5
4
  import { File } from '@kubb/react-fabric'
6
5
  import { Operations } from '../components/Operations.tsx'
7
6
  import { Zod } from '../components/Zod.tsx'
@@ -167,29 +166,27 @@ function buildLegacySchemaNames(node: OperationNode, params: Array<ParameterNode
167
166
 
168
167
  export const zodGeneratorLegacy = defineGenerator<PluginZod>({
169
168
  name: 'zod-legacy',
170
- type: 'react',
171
- Schema({ node, adapter, options, config, resolver, plugin }) {
169
+ schema(node, options) {
170
+ const { adapter, config, resolver, root } = this
172
171
  const { output, coercion, guidType, mini, wrapOutput, inferred, importPath, group, printer } = options
173
- const transformedNode = plugin.transformer ? transform(node, plugin.transformer) : node
174
172
 
175
- if (!transformedNode.name) {
173
+ if (!node.name) {
176
174
  return
177
175
  }
178
176
 
179
- const root = path.resolve(config.root, config.output.path)
180
- const mode = getMode(path.resolve(root, output.path))
177
+ const mode = this.getMode(output)
181
178
  const isZodImport = ZOD_NAMESPACE_IMPORTS.has(importPath as 'zod' | 'zod/mini')
182
179
 
183
- const imports = adapter.getImports(transformedNode, (schemaName) => ({
180
+ const imports = adapter.getImports(node, (schemaName) => ({
184
181
  name: resolver.resolveSchemaName(schemaName),
185
182
  path: resolver.resolveFile({ name: schemaName, extname: '.ts' }, { root, output, group }).path,
186
183
  }))
187
184
 
188
- const inferTypeName = inferred ? resolver.resolveSchemaTypeName(transformedNode.name) : undefined
185
+ const inferTypeName = inferred ? resolver.resolveSchemaTypeName(node.name) : undefined
189
186
 
190
187
  const meta = {
191
- name: resolver.resolveSchemaName(transformedNode.name),
192
- file: resolver.resolveFile({ name: transformedNode.name, extname: '.ts' }, { root, output, group }),
188
+ name: resolver.resolveSchemaName(node.name),
189
+ file: resolver.resolveFile({ name: node.name, extname: '.ts' }, { root, output, group }),
193
190
  } as const
194
191
 
195
192
  const schemaPrinter = mini
@@ -205,29 +202,23 @@ export const zodGeneratorLegacy = defineGenerator<PluginZod>({
205
202
  footer={resolver.resolveFooter(adapter.rootNode, { output, config })}
206
203
  >
207
204
  <File.Import name={isZodImport ? 'z' : ['z']} path={importPath} isNameSpace={isZodImport} />
208
- {mode === 'split' &&
209
- imports.map((imp) => <File.Import key={[transformedNode.name, imp.path].join('-')} root={meta.file.path} path={imp.path} name={imp.name} />)}
205
+ {mode === 'split' && imports.map((imp) => <File.Import key={[node.name, imp.path].join('-')} root={meta.file.path} path={imp.path} name={imp.name} />)}
210
206
 
211
- <Zod name={meta.name} node={transformedNode} printer={schemaPrinter} inferTypeName={inferTypeName} />
207
+ <Zod name={meta.name} node={node} printer={schemaPrinter} inferTypeName={inferTypeName} />
212
208
  </File>
213
209
  )
214
210
  },
215
- Operation({ node, adapter, options, config, resolver, plugin }) {
211
+ operation(node, options) {
212
+ const { adapter, config, resolver, root } = this
216
213
  const { output, coercion, guidType, mini, wrapOutput, inferred, importPath, group, paramsCasing, printer } = options
217
214
 
218
- const transformedNode = plugin.transformer ? transform(node, plugin.transformer) : node
219
-
220
- const root = path.resolve(config.root, config.output.path)
221
- const mode = getMode(path.resolve(root, output.path))
215
+ const mode = this.getMode(output)
222
216
  const isZodImport = ZOD_NAMESPACE_IMPORTS.has(importPath as 'zod' | 'zod/mini')
223
217
 
224
- const params = caseParams(transformedNode.parameters, paramsCasing)
218
+ const params = caseParams(node.parameters, paramsCasing)
225
219
 
226
220
  const meta = {
227
- file: resolver.resolveFile(
228
- { name: transformedNode.operationId, extname: '.ts', tag: transformedNode.tags[0] ?? 'default', path: transformedNode.path },
229
- { root, output, group },
230
- ),
221
+ file: resolver.resolveFile({ name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path }, { root, output, group }),
231
222
  } as const
232
223
 
233
224
  function renderSchemaEntry({ schema, name, keysToOmit }: { schema: SchemaNode | null; name: string; keysToOmit?: Array<string> }) {
@@ -257,8 +248,8 @@ export const zodGeneratorLegacy = defineGenerator<PluginZod>({
257
248
  const queryParams = params.filter((p) => p.in === 'query')
258
249
  const headerParams = params.filter((p) => p.in === 'header')
259
250
 
260
- const responseSchemas = transformedNode.responses.map((res) => {
261
- const responseName = resolver.resolveResponseStatusName(transformedNode, res.statusCode)
251
+ const responseSchemas = node.responses.map((res) => {
252
+ const responseName = resolver.resolveResponseStatusName(node, res.statusCode)
262
253
  return renderSchemaEntry({
263
254
  schema: {
264
255
  ...res.schema,
@@ -269,14 +260,14 @@ export const zodGeneratorLegacy = defineGenerator<PluginZod>({
269
260
  })
270
261
  })
271
262
 
272
- const requestSchema = transformedNode.requestBody?.schema
263
+ const requestSchema = node.requestBody?.schema
273
264
  ? renderSchemaEntry({
274
265
  schema: {
275
- ...transformedNode.requestBody.schema,
276
- description: transformedNode.requestBody.description ?? transformedNode.requestBody.schema.description,
266
+ ...node.requestBody.schema,
267
+ description: node.requestBody.description ?? node.requestBody.schema.description,
277
268
  },
278
- name: resolver.resolveDataName(transformedNode),
279
- keysToOmit: transformedNode.requestBody.keysToOmit,
269
+ name: resolver.resolveDataName(node),
270
+ keysToOmit: node.requestBody.keysToOmit,
280
271
  })
281
272
  : null
282
273
 
@@ -284,31 +275,31 @@ export const zodGeneratorLegacy = defineGenerator<PluginZod>({
284
275
  pathParams.length > 0
285
276
  ? renderSchemaEntry({
286
277
  schema: buildGroupedParamsSchema({ params: pathParams, optional: pathParams.every((p) => !p.required) }),
287
- name: resolver.resolvePathParamsName(transformedNode, pathParams[0]!),
278
+ name: resolver.resolvePathParamsName(node, pathParams[0]!),
288
279
  })
289
280
  : null,
290
281
  queryParams.length > 0
291
282
  ? renderSchemaEntry({
292
283
  schema: buildGroupedParamsSchema({ params: queryParams, optional: queryParams.every((p) => !p.required) }),
293
- name: resolver.resolveQueryParamsName(transformedNode, queryParams[0]!),
284
+ name: resolver.resolveQueryParamsName(node, queryParams[0]!),
294
285
  })
295
286
  : null,
296
287
  headerParams.length > 0
297
288
  ? renderSchemaEntry({
298
289
  schema: buildGroupedParamsSchema({ params: headerParams, optional: headerParams.every((p) => !p.required) }),
299
- name: resolver.resolveHeaderParamsName(transformedNode, headerParams[0]!),
290
+ name: resolver.resolveHeaderParamsName(node, headerParams[0]!),
300
291
  })
301
292
  : null,
302
293
  ]
303
294
 
304
295
  const legacyResponsesSchema = renderSchemaEntry({
305
- schema: buildLegacyResponsesSchemaNode(transformedNode, { resolver }),
306
- name: resolver.resolveResponsesName(transformedNode),
296
+ schema: buildLegacyResponsesSchemaNode(node, { resolver }),
297
+ name: resolver.resolveResponsesName(node),
307
298
  })
308
299
 
309
300
  const legacyResponseSchema = renderSchemaEntry({
310
- schema: buildLegacyResponseUnionSchemaNode(transformedNode, { resolver }),
311
- name: resolver.resolveResponseName(transformedNode),
301
+ schema: buildLegacyResponseUnionSchemaNode(node, { resolver }),
302
+ name: resolver.resolveResponseName(node),
312
303
  })
313
304
 
314
305
  return (
@@ -328,14 +319,13 @@ export const zodGeneratorLegacy = defineGenerator<PluginZod>({
328
319
  </File>
329
320
  )
330
321
  },
331
- Operations({ nodes, adapter, options, config, resolver, plugin }) {
322
+ operations(nodes, options) {
323
+ const { adapter, config, resolver, root } = this
332
324
  const { output, importPath, group, operations, paramsCasing } = options
333
325
 
334
326
  if (!operations) {
335
327
  return
336
328
  }
337
-
338
- const root = path.resolve(config.root, config.output.path)
339
329
  const isZodImport = ZOD_NAMESPACE_IMPORTS.has(importPath as 'zod' | 'zod/mini')
340
330
 
341
331
  const meta = {
@@ -343,13 +333,11 @@ export const zodGeneratorLegacy = defineGenerator<PluginZod>({
343
333
  } as const
344
334
 
345
335
  const transformedOperations = nodes.map((node) => {
346
- const transformedNode = plugin.transformer ? transform(node, plugin.transformer) : node
347
-
348
- const params = caseParams(transformedNode.parameters, paramsCasing)
336
+ const params = caseParams(node.parameters, paramsCasing)
349
337
 
350
338
  return {
351
- node: transformedNode,
352
- data: buildLegacySchemaNames(transformedNode, params, resolver),
339
+ node,
340
+ data: buildLegacySchemaNames(node, params, resolver),
353
341
  }
354
342
  })
355
343
 
package/src/plugin.ts CHANGED
@@ -1,8 +1,6 @@
1
- import path from 'node:path'
2
1
  import { camelCase } from '@internals/utils'
3
- import { walk } from '@kubb/ast'
4
- import type { OperationNode } from '@kubb/ast/types'
5
- import { createPlugin, type Group, getBarrelFiles, getPreset, runGeneratorOperation, runGeneratorOperations, runGeneratorSchema } from '@kubb/core'
2
+ import { createPlugin, type Group, getPreset, mergeGenerators } from '@kubb/core'
3
+ import { version } from '../package.json'
6
4
  import { presets } from './presets.ts'
7
5
  import type { PluginZod } from './types.ts'
8
6
 
@@ -59,11 +57,15 @@ export const pluginZod = createPlugin<PluginZod>((options) => {
59
57
  generators: userGenerators,
60
58
  })
61
59
 
60
+ const generators = preset.generators ?? []
61
+ const mergedGenerator = mergeGenerators(generators)
62
+
62
63
  let resolveNameWarning = false
63
64
  let resolvePathWarning = false
64
65
 
65
66
  return {
66
67
  name: pluginZodName,
68
+ version,
67
69
  get resolver() {
68
70
  return preset.resolver
69
71
  },
@@ -73,6 +75,9 @@ export const pluginZod = createPlugin<PluginZod>((options) => {
73
75
  get options() {
74
76
  return {
75
77
  output,
78
+ exclude,
79
+ include,
80
+ override,
76
81
  group: group
77
82
  ? ({
78
83
  ...group,
@@ -99,65 +104,34 @@ export const pluginZod = createPlugin<PluginZod>((options) => {
99
104
  },
100
105
  resolvePath(baseName, pathMode, options) {
101
106
  if (!resolvePathWarning) {
102
- this.events.emit('warn', 'Do not use resolvePath for pluginZod, use resolverZod.resolvePath instead')
107
+ this.warn('Do not use resolvePath for pluginZod, use resolverZod.resolvePath instead')
103
108
  resolvePathWarning = true
104
109
  }
105
110
 
106
111
  return this.plugin.resolver.resolvePath(
107
112
  { baseName, pathMode, tag: options?.group?.tag, path: options?.group?.path },
108
- { root: path.resolve(this.config.root, this.config.output.path), output, group: this.plugin.options.group },
113
+ { root: this.root, output, group: this.plugin.options.group },
109
114
  )
110
115
  },
111
116
  resolveName(name, type) {
112
117
  if (!resolveNameWarning) {
113
- this.events.emit('warn', 'Do not use resolveName for pluginZod, use resolverZod.default instead')
118
+ this.warn('Do not use resolveName for pluginZod, use resolverZod.default instead')
114
119
  resolveNameWarning = true
115
120
  }
116
121
 
117
122
  return this.plugin.resolver.default(name, type)
118
123
  },
119
- async install() {
120
- const { config, fabric, plugin, adapter, rootNode, driver, openInStudio, resolver } = this
121
-
122
- const root = path.resolve(config.root, config.output.path)
123
-
124
- if (!adapter) {
125
- throw new Error(`[${pluginZodName}] No adapter found. Add an OAS adapter (e.g. pluginOas()) before this plugin in your Kubb config.`)
126
- }
127
-
128
- await openInStudio({ ast: true })
129
-
130
- const collectedOperations: Array<OperationNode> = []
131
- const generatorContext = { generators: preset.generators, plugin, resolver, exclude, include, override, fabric, adapter, config, driver }
132
-
133
- await walk(rootNode, {
134
- depth: 'shallow',
135
- async schema(schemaNode) {
136
- await runGeneratorSchema(schemaNode, generatorContext)
137
- },
138
- async operation(operationNode) {
139
- const baseOptions = resolver.resolveOptions(operationNode, { options: plugin.options, exclude, include, override })
140
-
141
- if (baseOptions !== null) {
142
- collectedOperations.push(operationNode)
143
- }
144
-
145
- await runGeneratorOperation(operationNode, generatorContext)
146
- },
147
- })
148
-
149
- await runGeneratorOperations(collectedOperations, generatorContext)
150
-
151
- const barrelFiles = await getBarrelFiles(this.fabric.files, {
152
- type: output.barrelType ?? 'named',
153
- root,
154
- output,
155
- meta: {
156
- pluginName: this.plugin.name,
157
- },
158
- })
159
-
160
- await this.upsertFile(...barrelFiles)
124
+ async schema(node, options) {
125
+ return mergedGenerator.schema?.call(this, node, options)
126
+ },
127
+ async operation(node, options) {
128
+ return mergedGenerator.operation?.call(this, node, options)
129
+ },
130
+ async operations(nodes, options) {
131
+ return mergedGenerator.operations?.call(this, nodes, options)
132
+ },
133
+ async buildStart() {
134
+ await this.openInStudio({ ast: true })
161
135
  },
162
136
  }
163
137
  })
package/src/types.ts CHANGED
@@ -192,7 +192,7 @@ export type Options = {
192
192
  */
193
193
  resolver?: Partial<ResolverZod> & ThisType<ResolverZod>
194
194
  /**
195
- * Override individual printer node handlers to customise rendering of specific schema types.
195
+ * Override individual printer node handlers to customize rendering of specific schema types.
196
196
  *
197
197
  * Each key is a `SchemaType` (e.g. `'date'`, `'string'`). The function replaces the
198
198
  * built-in handler for that type. Use `this.transform` to recurse into nested schema nodes.
@@ -223,6 +223,9 @@ export type Options = {
223
223
 
224
224
  type ResolvedOptions = {
225
225
  output: Output
226
+ exclude: Array<Exclude>
227
+ include: Array<Include> | undefined
228
+ override: Array<Override<ResolvedOptions>>
226
229
  group: Group | undefined
227
230
  dateType: NonNullable<Options['dateType']>
228
231
  typed: NonNullable<Options['typed']>
@@ -238,3 +241,11 @@ type ResolvedOptions = {
238
241
  }
239
242
 
240
243
  export type PluginZod = PluginFactoryOptions<'plugin-zod', Options, ResolvedOptions, never, ResolvePathOptions, ResolverZod>
244
+
245
+ declare global {
246
+ namespace Kubb {
247
+ interface PluginRegistry {
248
+ 'plugin-zod': PluginZod
249
+ }
250
+ }
251
+ }