@kubb/plugin-zod 3.0.0-alpha.9 → 3.0.0-beta.10

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 (89) hide show
  1. package/README.md +14 -5
  2. package/dist/chunk-37OP7TSO.cjs +354 -0
  3. package/dist/chunk-37OP7TSO.cjs.map +1 -0
  4. package/dist/chunk-OOAUU32I.js +235 -0
  5. package/dist/chunk-OOAUU32I.js.map +1 -0
  6. package/dist/chunk-QEYWJ6VH.cjs +244 -0
  7. package/dist/chunk-QEYWJ6VH.cjs.map +1 -0
  8. package/dist/chunk-SSOO3TXR.js +347 -0
  9. package/dist/chunk-SSOO3TXR.js.map +1 -0
  10. package/dist/components.cjs +11 -10
  11. package/dist/components.cjs.map +1 -1
  12. package/dist/components.d.cts +20 -19
  13. package/dist/components.d.ts +20 -19
  14. package/dist/components.js +2 -14
  15. package/dist/components.js.map +1 -1
  16. package/dist/generators.cjs +17 -0
  17. package/dist/generators.cjs.map +1 -0
  18. package/dist/generators.d.cts +10 -0
  19. package/dist/generators.d.ts +10 -0
  20. package/dist/generators.js +4 -0
  21. package/dist/generators.js.map +1 -0
  22. package/dist/index.cjs +12 -8
  23. package/dist/index.cjs.map +1 -1
  24. package/dist/index.d.cts +4 -137
  25. package/dist/index.d.ts +4 -137
  26. package/dist/index.js +3 -12
  27. package/dist/index.js.map +1 -1
  28. package/dist/types-L1fXCZAs.d.cts +100 -0
  29. package/dist/types-L1fXCZAs.d.ts +100 -0
  30. package/package.json +19 -21
  31. package/src/components/Operations.tsx +12 -98
  32. package/src/components/Zod.tsx +68 -0
  33. package/src/components/index.ts +1 -2
  34. package/src/generators/__snapshots__/anyof.ts +3 -0
  35. package/src/generators/__snapshots__/coercion.ts +3 -0
  36. package/src/generators/__snapshots__/coercionDates.ts +3 -0
  37. package/src/generators/__snapshots__/coercionNumbers.ts +3 -0
  38. package/src/generators/__snapshots__/coercionStrings.ts +3 -0
  39. package/src/generators/__snapshots__/createPet.ts +15 -0
  40. package/src/generators/__snapshots__/createPetWithUnknownTypeAny.ts +13 -0
  41. package/src/generators/__snapshots__/createPetWithUnknownTypeUnknown.ts +15 -0
  42. package/src/generators/__snapshots__/deletePet.ts +3 -0
  43. package/src/generators/__snapshots__/discriminator.ts +3 -0
  44. package/src/generators/__snapshots__/enumBooleanLiteral.ts +3 -0
  45. package/src/generators/__snapshots__/enumNamesType.ts +3 -0
  46. package/src/generators/__snapshots__/enumNullable.ts +3 -0
  47. package/src/generators/__snapshots__/enumSingleLiteral.ts +3 -0
  48. package/src/generators/__snapshots__/enumVarNamesType.ts +3 -0
  49. package/src/generators/__snapshots__/example.ts +3 -0
  50. package/src/generators/__snapshots__/getPets.ts +15 -0
  51. package/src/generators/__snapshots__/mixedValueTypeConst.ts +6 -0
  52. package/src/generators/__snapshots__/nullableString.ts +3 -0
  53. package/src/generators/__snapshots__/nullableStringUuid.ts +3 -0
  54. package/src/generators/__snapshots__/nullableStringWithAnyOf.ts +3 -0
  55. package/src/generators/__snapshots__/numberValueConst.ts +6 -0
  56. package/src/generators/__snapshots__/oneof.ts +3 -0
  57. package/src/generators/__snapshots__/operations.ts +43 -0
  58. package/src/generators/__snapshots__/optionalPetInfer.ts +5 -0
  59. package/src/generators/__snapshots__/optionalPetTyped.ts +3 -0
  60. package/src/generators/__snapshots__/order.ts +3 -0
  61. package/src/generators/__snapshots__/orderDateTyeString.ts +10 -0
  62. package/src/generators/__snapshots__/orderDateTypeFalse.ts +3 -0
  63. package/src/generators/__snapshots__/orderDateTypeString.ts +3 -0
  64. package/src/generators/__snapshots__/pet.ts +3 -0
  65. package/src/generators/__snapshots__/petArray.ts +6 -0
  66. package/src/generators/__snapshots__/petCoercion.ts +3 -0
  67. package/src/generators/__snapshots__/petTupleObject.ts +6 -0
  68. package/src/generators/__snapshots__/petWithMapper.ts +3 -0
  69. package/src/generators/__snapshots__/pets.ts +3 -0
  70. package/src/generators/__snapshots__/recursive.ts +3 -0
  71. package/src/generators/__snapshots__/showPetById.ts +15 -0
  72. package/src/generators/__snapshots__/stringValueConst.ts +6 -0
  73. package/src/generators/__snapshots__/uuidSchema.ts +3 -0
  74. package/src/generators/index.ts +2 -0
  75. package/src/generators/operationsGenerator.tsx +39 -0
  76. package/src/generators/zodGenerator.tsx +121 -0
  77. package/src/parser/index.ts +59 -31
  78. package/src/plugin.ts +30 -39
  79. package/src/types.ts +50 -89
  80. package/dist/Operations-BG26e_MW.d.cts +0 -47
  81. package/dist/Operations-BG26e_MW.d.ts +0 -47
  82. package/dist/chunk-57AHBVYK.cjs +0 -3502
  83. package/dist/chunk-57AHBVYK.cjs.map +0 -1
  84. package/dist/chunk-CUPQVLRZ.js +0 -3502
  85. package/dist/chunk-CUPQVLRZ.js.map +0 -1
  86. package/src/SchemaGenerator.tsx +0 -22
  87. package/src/components/OperationSchema.tsx +0 -60
  88. package/src/components/Schema.tsx +0 -166
  89. package/src/components/__snapshots__/operations.ts +0 -53
@@ -0,0 +1,121 @@
1
+ import { type OperationSchema as OperationSchemaType, SchemaGenerator, createReactGenerator, schemaKeywords } from '@kubb/plugin-oas'
2
+ import { Oas } from '@kubb/plugin-oas/components'
3
+ import { useOas, useOperationManager, useSchemaManager } from '@kubb/plugin-oas/hooks'
4
+ import { pluginTsName } from '@kubb/plugin-ts'
5
+ import { File, useApp } from '@kubb/react'
6
+ import { Zod } from '../components'
7
+ import type { PluginZod } from '../types'
8
+
9
+ export const zodGenerator = createReactGenerator<PluginZod>({
10
+ name: 'zod',
11
+ Operation({ operation, options }) {
12
+ const { coercion, inferred, typed, mapper } = options
13
+
14
+ const { plugin, pluginManager, mode } = useApp<PluginZod>()
15
+ const oas = useOas()
16
+ const { getSchemas, getFile } = useOperationManager()
17
+ const schemaManager = useSchemaManager()
18
+
19
+ const file = getFile(operation)
20
+ const schemas = getSchemas(operation)
21
+ const schemaGenerator = new SchemaGenerator(options, {
22
+ oas,
23
+ plugin,
24
+ pluginManager,
25
+ mode,
26
+ override: options.override,
27
+ })
28
+
29
+ const operationSchemas = [schemas.pathParams, schemas.queryParams, schemas.headerParams, schemas.statusCodes, schemas.request, schemas.response]
30
+ .flat()
31
+ .filter(Boolean)
32
+
33
+ const mapOperationSchema = ({ name, schema, description, keysToOmit, ...options }: OperationSchemaType, i: number) => {
34
+ // hack so Params can be optional when needed
35
+ const required = Array.isArray(schema?.required) ? !!schema.required.length : !!schema?.required
36
+ const optional = !required && !!name.includes('Params')
37
+ const tree = [...schemaGenerator.parse({ schema, name }), optional ? { keyword: schemaKeywords.optional } : undefined].filter(Boolean)
38
+ const imports = schemaManager.getImports(tree)
39
+
40
+ const zod = {
41
+ name: schemaManager.getName(name, { type: 'function' }),
42
+ inferTypeName: schemaManager.getName(name, { type: 'type' }),
43
+ file: schemaManager.getFile(name),
44
+ }
45
+
46
+ const type = {
47
+ name: schemaManager.getName(name, { type: 'type', pluginKey: [pluginTsName] }),
48
+ file: schemaManager.getFile(options.operationName || name, { pluginKey: [pluginTsName], tag: options.operation?.getTags()[0]?.name }),
49
+ }
50
+
51
+ return (
52
+ <Oas.Schema key={i} name={name} value={schema} tree={tree}>
53
+ {typed && <File.Import isTypeOnly root={file.path} path={type.file.path} name={[type.name]} />}
54
+ {imports.map((imp, index) => (
55
+ <File.Import key={index} root={file.path} path={imp.path} name={imp.name} />
56
+ ))}
57
+ <Zod
58
+ name={zod.name}
59
+ typeName={typed ? type.name : undefined}
60
+ inferTypeName={inferred ? zod.inferTypeName : undefined}
61
+ description={description}
62
+ tree={tree}
63
+ mapper={mapper}
64
+ coercion={coercion}
65
+ keysToOmit={keysToOmit}
66
+ />
67
+ </Oas.Schema>
68
+ )
69
+ }
70
+
71
+ return (
72
+ <File baseName={file.baseName} path={file.path} meta={file.meta} banner={plugin.options.output?.banner} footer={plugin.options.output?.footer}>
73
+ <File.Import name={['z']} path={plugin.options.importPath} />
74
+ {operationSchemas.map(mapOperationSchema)}
75
+ </File>
76
+ )
77
+ },
78
+ Schema({ schema, options }) {
79
+ const { coercion, inferred, typed, mapper, importPath } = options
80
+
81
+ const { getName, getFile, getImports } = useSchemaManager()
82
+ const {
83
+ plugin: {
84
+ options: { output },
85
+ },
86
+ } = useApp<PluginZod>()
87
+
88
+ const imports = getImports(schema.tree)
89
+
90
+ const zod = {
91
+ name: getName(schema.name, { type: 'function' }),
92
+ inferTypeName: getName(schema.name, { type: 'type' }),
93
+ file: getFile(schema.name),
94
+ }
95
+
96
+ const type = {
97
+ name: getName(schema.name, { type: 'type', pluginKey: [pluginTsName] }),
98
+ file: getFile(schema.name, { pluginKey: [pluginTsName] }),
99
+ }
100
+
101
+ return (
102
+ <File baseName={zod.file.baseName} path={zod.file.path} meta={zod.file.meta} banner={output?.banner} footer={output?.footer}>
103
+ <File.Import name={['z']} path={importPath} />
104
+ {typed && <File.Import isTypeOnly root={zod.file.path} path={type.file.path} name={[type.name]} />}
105
+ {imports.map((imp, index) => (
106
+ <File.Import key={index} root={zod.file.path} path={imp.path} name={imp.name} />
107
+ ))}
108
+
109
+ <Zod
110
+ name={zod.name}
111
+ typeName={typed ? type.name : undefined}
112
+ inferTypeName={inferred ? zod.inferTypeName : undefined}
113
+ description={schema.value.description}
114
+ tree={schema.tree}
115
+ mapper={mapper}
116
+ coercion={coercion}
117
+ />
118
+ </File>
119
+ )
120
+ },
121
+ })
@@ -1,9 +1,9 @@
1
1
  import transformers, { createJSDocBlockText } from '@kubb/core/transformers'
2
- import { type SchemaKeywordMapper, isKeyword, schemaKeywords } from '@kubb/plugin-oas'
2
+ import { type SchemaKeywordMapper, type SchemaTree, isKeyword, schemaKeywords } from '@kubb/plugin-oas'
3
3
 
4
4
  import type { Schema, SchemaKeywordBase, SchemaMapper } from '@kubb/plugin-oas'
5
5
 
6
- export const zodKeywordMapper = {
6
+ const zodKeywordMapper = {
7
7
  any: () => 'z.any()',
8
8
  unknown: () => 'z.unknown()',
9
9
  number: (coercion?: boolean, min?: number, max?: number) => {
@@ -39,7 +39,7 @@ export const zodKeywordMapper = {
39
39
  tuple: (items: string[] = []) => `z.tuple([${items?.join(', ')}])`,
40
40
  enum: (items: string[] = []) => `z.enum([${items?.join(', ')}])`,
41
41
  union: (items: string[] = []) => `z.union([${items?.join(', ')}])`,
42
- const: (value?: string | number) => `z.literal(${value ?? ''})`,
42
+ const: (value?: string | number | boolean) => `z.literal(${value ?? ''})`,
43
43
  /**
44
44
  * ISO 8601
45
45
  */
@@ -102,6 +102,7 @@ export const zodKeywordMapper = {
102
102
  password: undefined,
103
103
  phone: undefined,
104
104
  readOnly: undefined,
105
+ writeOnly: undefined,
105
106
  ref: (value?: string) => (value ? `z.lazy(() => ${value})` : undefined),
106
107
  blob: () => 'z.string()',
107
108
  deprecated: undefined,
@@ -149,17 +150,27 @@ export function sort(items?: Schema[]): Schema[] {
149
150
  return transformers.orderBy(items, [(v) => order.indexOf(v.keyword)], ['asc'])
150
151
  }
151
152
 
153
+ const shouldCoerce = (coercion: ParserOptions['coercion'] | undefined, type: 'dates' | 'strings' | 'numbers'): boolean => {
154
+ if (coercion === undefined) {
155
+ return false
156
+ }
157
+ if (typeof coercion === 'boolean') {
158
+ return coercion
159
+ }
160
+
161
+ return !!coercion[type]
162
+ }
163
+
152
164
  type ParserOptions = {
153
165
  name: string
154
166
  typeName?: string
155
167
  description?: string
156
-
157
168
  keysToOmit?: string[]
158
169
  mapper?: Record<string, string>
159
- coercion?: boolean
170
+ coercion?: boolean | { dates?: boolean; strings?: boolean; numbers?: boolean }
160
171
  }
161
172
 
162
- export function parse(parent: Schema | undefined, current: Schema, options: ParserOptions): string | undefined {
173
+ export function parse({ parent, current, siblings }: SchemaTree, options: ParserOptions): string | undefined {
163
174
  const value = zodKeywordMapper[current.keyword as keyof typeof zodKeywordMapper]
164
175
 
165
176
  if (!value) {
@@ -169,7 +180,7 @@ export function parse(parent: Schema | undefined, current: Schema, options: Pars
169
180
  if (isKeyword(current, schemaKeywords.union)) {
170
181
  // zod union type needs at least 2 items
171
182
  if (Array.isArray(current.args) && current.args.length === 1) {
172
- return parse(parent, current.args[0] as Schema, options)
183
+ return parse({ parent, current: current.args[0] as Schema, siblings }, options)
173
184
  }
174
185
  if (Array.isArray(current.args) && !current.args.length) {
175
186
  return ''
@@ -177,7 +188,7 @@ export function parse(parent: Schema | undefined, current: Schema, options: Pars
177
188
 
178
189
  return zodKeywordMapper.union(
179
190
  sort(current.args)
180
- .map((schema) => parse(current, schema, options))
191
+ .map((schema, _index, siblings) => parse({ parent: current, current: schema, siblings }, options))
181
192
  .filter(Boolean),
182
193
  )
183
194
  }
@@ -187,7 +198,7 @@ export function parse(parent: Schema | undefined, current: Schema, options: Pars
187
198
  .filter((schema: Schema) => {
188
199
  return ![schemaKeywords.optional, schemaKeywords.describe].includes(schema.keyword as typeof schemaKeywords.describe)
189
200
  })
190
- .map((schema: Schema) => parse(current, schema, options))
201
+ .map((schema: Schema, _index, siblings) => parse({ parent: current, current: schema, siblings }, options))
191
202
  .filter(Boolean)
192
203
 
193
204
  return `${items.slice(0, 1)}${zodKeywordMapper.and(items.slice(1))}`
@@ -196,7 +207,7 @@ export function parse(parent: Schema | undefined, current: Schema, options: Pars
196
207
  if (isKeyword(current, schemaKeywords.array)) {
197
208
  return zodKeywordMapper.array(
198
209
  sort(current.args.items)
199
- .map((schemas) => parse(current, schemas, options))
210
+ .map((schemas, _index, siblings) => parse({ parent: current, current: schemas, siblings }, options))
200
211
  .filter(Boolean),
201
212
  current.args.min,
202
213
  current.args.max,
@@ -205,17 +216,22 @@ export function parse(parent: Schema | undefined, current: Schema, options: Pars
205
216
 
206
217
  if (isKeyword(current, schemaKeywords.enum)) {
207
218
  if (current.args.asConst) {
219
+ if (current.args.items.length === 1) {
220
+ const child = {
221
+ keyword: schemaKeywords.const,
222
+ args: current.args.items[0],
223
+ }
224
+ return parse({ parent: current, current: child, siblings: [child] }, options)
225
+ }
226
+
208
227
  return zodKeywordMapper.union(
209
228
  current.args.items
210
- .map((schema) => {
211
- return parse(
212
- current,
213
- {
214
- keyword: schemaKeywords.const,
215
- args: schema,
216
- },
217
- options,
218
- )
229
+ .map((schema) => ({
230
+ keyword: schemaKeywords.const,
231
+ args: schema,
232
+ }))
233
+ .map((schema, _index, siblings) => {
234
+ return parse({ parent: current, current: schema, siblings }, options)
219
235
  })
220
236
  .filter(Boolean),
221
237
  )
@@ -223,6 +239,10 @@ export function parse(parent: Schema | undefined, current: Schema, options: Pars
223
239
 
224
240
  return zodKeywordMapper.enum(
225
241
  current.args.items.map((schema) => {
242
+ if (schema.format === 'boolean') {
243
+ return transformers.stringify(schema.value)
244
+ }
245
+
226
246
  if (schema.format === 'number') {
227
247
  return transformers.stringify(schema.value)
228
248
  }
@@ -251,8 +271,8 @@ export function parse(parent: Schema | undefined, current: Schema, options: Pars
251
271
  }
252
272
 
253
273
  return `"${name}": ${sort(schemas)
254
- .map((schema, array) => {
255
- return parse(current, schema, options)
274
+ .map((schema, array, siblings) => {
275
+ return parse({ parent: current, current: schema, siblings }, options)
256
276
  })
257
277
  .filter(Boolean)
258
278
  .join('')}`
@@ -261,9 +281,9 @@ export function parse(parent: Schema | undefined, current: Schema, options: Pars
261
281
 
262
282
  const additionalProperties = current.args?.additionalProperties?.length
263
283
  ? current.args.additionalProperties
264
- .map((schema) => parse(current, schema, options))
284
+ .map((schema, _index, siblings) => parse({ parent: current, current: schema, siblings }, options))
265
285
  .filter(Boolean)
266
- .at(0)
286
+ .join('')
267
287
  : undefined
268
288
 
269
289
  const text = [
@@ -277,9 +297,7 @@ export function parse(parent: Schema | undefined, current: Schema, options: Pars
277
297
 
278
298
  if (isKeyword(current, schemaKeywords.tuple)) {
279
299
  return zodKeywordMapper.tuple(
280
- sort(current.args.items)
281
- .map((schema) => parse(current, schema, options))
282
- .filter(Boolean),
300
+ current.args.items.map((schema, _index, siblings) => parse({ parent: current, current: schema, siblings }, options)).filter(Boolean),
283
301
  )
284
302
  }
285
303
 
@@ -287,6 +305,10 @@ export function parse(parent: Schema | undefined, current: Schema, options: Pars
287
305
  if (current.args.format === 'number' && current.args.value !== undefined) {
288
306
  return zodKeywordMapper.const(Number.parseInt(current.args.value?.toString()))
289
307
  }
308
+
309
+ if (current.args.format === 'boolean' && current.args.value !== undefined) {
310
+ return zodKeywordMapper.const(current.args.value)
311
+ }
290
312
  return zodKeywordMapper.const(transformers.stringify(current.args.value))
291
313
  }
292
314
 
@@ -309,15 +331,15 @@ export function parse(parent: Schema | undefined, current: Schema, options: Pars
309
331
  }
310
332
 
311
333
  if (isKeyword(current, schemaKeywords.string)) {
312
- return zodKeywordMapper.string(options.coercion)
334
+ return zodKeywordMapper.string(shouldCoerce(options.coercion, 'strings'))
313
335
  }
314
336
 
315
337
  if (isKeyword(current, schemaKeywords.number)) {
316
- return zodKeywordMapper.number(options.coercion)
338
+ return zodKeywordMapper.number(shouldCoerce(options.coercion, 'numbers'))
317
339
  }
318
340
 
319
341
  if (isKeyword(current, schemaKeywords.integer)) {
320
- return zodKeywordMapper.integer(options.coercion)
342
+ return zodKeywordMapper.integer(shouldCoerce(options.coercion, 'numbers'))
321
343
  }
322
344
 
323
345
  if (isKeyword(current, schemaKeywords.min)) {
@@ -332,11 +354,11 @@ export function parse(parent: Schema | undefined, current: Schema, options: Pars
332
354
  }
333
355
 
334
356
  if (isKeyword(current, schemaKeywords.date)) {
335
- return zodKeywordMapper.date(current.args.type, options.coercion)
357
+ return zodKeywordMapper.date(current.args.type, shouldCoerce(options.coercion, 'dates'))
336
358
  }
337
359
 
338
360
  if (isKeyword(current, schemaKeywords.time)) {
339
- return zodKeywordMapper.time(current.args.type, options.coercion)
361
+ return zodKeywordMapper.time(current.args.type, shouldCoerce(options.coercion, 'dates'))
340
362
  }
341
363
 
342
364
  if (current.keyword in zodKeywordMapper && 'args' in current) {
@@ -345,6 +367,12 @@ export function parse(parent: Schema | undefined, current: Schema, options: Pars
345
367
  return value((current as SchemaKeywordBase<unknown>).args as any)
346
368
  }
347
369
 
370
+ if (isKeyword(current, schemaKeywords.optional)) {
371
+ if (siblings.some((schema) => isKeyword(schema, schemaKeywords.default))) return ''
372
+
373
+ return value()
374
+ }
375
+
348
376
  if (current.keyword in zodKeywordMapper) {
349
377
  return value()
350
378
  }
package/src/plugin.ts CHANGED
@@ -1,23 +1,22 @@
1
1
  import path from 'node:path'
2
2
 
3
- import { FileManager, PluginManager, createPlugin } from '@kubb/core'
3
+ import { FileManager, type Group, PluginManager, createPlugin } from '@kubb/core'
4
4
  import { camelCase, pascalCase } from '@kubb/core/transformers'
5
- import { renderTemplate } from '@kubb/core/utils'
6
5
  import { OperationGenerator, SchemaGenerator, pluginOasName } from '@kubb/plugin-oas'
7
6
 
8
7
  import { pluginTsName } from '@kubb/plugin-ts'
9
8
 
10
9
  import type { Plugin } from '@kubb/core'
11
10
  import type { PluginOas as SwaggerPluginOptions } from '@kubb/plugin-oas'
12
- import { zodParser } from './SchemaGenerator.tsx'
13
- import { Operations } from './components/Operations.tsx'
11
+ import { operationsGenerator } from './generators'
12
+ import { zodGenerator } from './generators/zodGenerator.tsx'
14
13
  import type { PluginZod } from './types.ts'
15
14
 
16
15
  export const pluginZodName = 'plugin-zod' satisfies PluginZod['name']
17
16
 
18
17
  export const pluginZod = createPlugin<PluginZod>((options) => {
19
18
  const {
20
- output = { path: 'zod' },
19
+ output = { path: 'zod', barrelType: 'named' },
21
20
  group,
22
21
  exclude = [],
23
22
  include,
@@ -26,43 +25,42 @@ export const pluginZod = createPlugin<PluginZod>((options) => {
26
25
  dateType = 'string',
27
26
  unknownType = 'any',
28
27
  typed = false,
29
- typedSchema = false,
30
28
  mapper = {},
31
- templates,
29
+ operations = false,
32
30
  importPath = 'zod',
33
31
  coercion = false,
32
+ inferred = false,
33
+ generators = [zodGenerator, operations ? operationsGenerator : undefined].filter(Boolean),
34
34
  } = options
35
- const template = group?.output ? group.output : `${output.path}/{{tag}}Controller`
36
35
 
37
36
  return {
38
37
  name: pluginZodName,
39
- output: {
40
- exportType: 'barrelNamed',
41
- ...output,
42
- },
43
38
  options: {
44
- extName: output.extName,
39
+ output,
45
40
  transformers,
46
41
  include,
47
42
  exclude,
48
43
  override,
49
44
  typed,
50
- typedSchema,
51
45
  dateType,
52
46
  unknownType,
53
47
  mapper,
54
48
  importPath,
55
49
  coercion,
56
- templates: {
57
- operations: Operations.templates,
58
- ...templates,
59
- },
50
+ operations,
51
+ inferred,
60
52
  },
61
53
  pre: [pluginOasName, typed ? pluginTsName : undefined].filter(Boolean),
62
54
  resolvePath(baseName, pathMode, options) {
63
55
  const root = path.resolve(this.config.root, this.config.output.path)
64
56
  const mode = pathMode ?? FileManager.getMode(path.resolve(root, output.path))
65
57
 
58
+ if (options?.tag && group?.type === 'tag') {
59
+ const groupName: Group['name'] = group?.name ? group.name : (ctx) => `${ctx.group}Controller`
60
+
61
+ return path.resolve(root, output.path, groupName({ group: camelCase(options.tag) }), baseName)
62
+ }
63
+
66
64
  if (mode === 'single') {
67
65
  /**
68
66
  * when output is a file then we will always append to the same file(output file), see fileManager.addOrAppend
@@ -71,12 +69,6 @@ export const pluginZod = createPlugin<PluginZod>((options) => {
71
69
  return path.resolve(root, output.path)
72
70
  }
73
71
 
74
- if (options?.tag && group?.type === 'tag') {
75
- const tag = camelCase(options.tag)
76
-
77
- return path.resolve(root, renderTemplate(template, { tag }), baseName)
78
- }
79
-
80
72
  return path.resolve(root, output.path, baseName)
81
73
  },
82
74
  resolveName(name, type) {
@@ -113,7 +105,7 @@ export const pluginZod = createPlugin<PluginZod>((options) => {
113
105
  output: output.path,
114
106
  })
115
107
 
116
- const schemaFiles = await schemaGenerator.build(zodParser)
108
+ const schemaFiles = await schemaGenerator.build(...generators)
117
109
  await this.addFile(...schemaFiles)
118
110
 
119
111
  const operationGenerator = new OperationGenerator(this.plugin.options, {
@@ -127,22 +119,21 @@ export const pluginZod = createPlugin<PluginZod>((options) => {
127
119
  mode,
128
120
  })
129
121
 
130
- const operationFiles = await operationGenerator.build(zodParser)
122
+ const operationFiles = await operationGenerator.build(...generators)
131
123
  await this.addFile(...operationFiles)
132
124
 
133
- if (this.config.output.exportType) {
134
- const barrelFiles = await this.fileManager.getBarrelFiles({
135
- root,
136
- output,
137
- files: this.fileManager.files,
138
- meta: {
139
- pluginKey: this.plugin.key,
140
- },
141
- logger: this.logger,
142
- })
143
-
144
- await this.addFile(...barrelFiles)
145
- }
125
+ const barrelFiles = await this.fileManager.getBarrelFiles({
126
+ type: output.barrelType ?? 'named',
127
+ root,
128
+ output,
129
+ files: this.fileManager.files,
130
+ meta: {
131
+ pluginKey: this.plugin.key,
132
+ },
133
+ logger: this.logger,
134
+ })
135
+
136
+ await this.addFile(...barrelFiles)
146
137
  },
147
138
  }
148
139
  })
package/src/types.ts CHANGED
@@ -1,57 +1,16 @@
1
- import type { Plugin, PluginFactoryOptions, ResolveNameParams } from '@kubb/core'
2
- import type * as KubbFile from '@kubb/fs/types'
1
+ import type { Group, Output, PluginFactoryOptions, ResolveNameParams } from '@kubb/core'
3
2
  import type { SchemaObject } from '@kubb/oas'
4
- import type { Exclude, Include, Override, ResolvePathOptions, Schema } from '@kubb/plugin-oas'
5
- import type { Operations } from './components/Operations'
6
-
7
- type Templates = {
8
- operations?: typeof Operations.templates | false
9
- }
3
+ import type { Exclude, Generator, Include, Override, ResolvePathOptions, Schema } from '@kubb/plugin-oas'
10
4
 
11
5
  export type Options = {
12
- output?: {
13
- /**
14
- * Relative path to save the Zod schemas.
15
- * When output is a file it will save all models inside that file else it will create a file per schema item.
16
- * @default 'zod'
17
- */
18
- path: string
19
- /**
20
- * Name to be used for the `export * as {{exportAs}} from './'`
21
- */
22
- exportAs?: string
23
- /**
24
- * Add an extension to the generated imports and exports, default it will not use an extension
25
- */
26
- extName?: KubbFile.Extname
27
- /**
28
- * Define what needs to exported, here you can also disable the export of barrel files
29
- * @default `'barrel'`
30
- */
31
- exportType?: 'barrel' | 'barrelNamed' | false
32
- }
6
+ /**
7
+ * @default 'zod'
8
+ */
9
+ output?: Output
33
10
  /**
34
11
  * Group the Zod schemas based on the provided name.
35
12
  */
36
- group?: {
37
- /**
38
- * Tag will group based on the operation tag inside the Swagger file
39
- */
40
- type: 'tag'
41
- /**
42
- * Relative path to save the grouped Zod schemas.
43
- *
44
- * `{{tag}}` will be replaced by the current tagName.
45
- * @example `${output}/{{tag}}Controller` => `zod/PetController`
46
- * @default `${output}/{{tag}}Controller`
47
- */
48
- output?: string
49
- /**
50
- * Name to be used for the `export * as {{exportAs}} from './`
51
- * @default `"{{tag}}Schemas"`
52
- */
53
- exportAs?: string
54
- }
13
+ group?: Group
55
14
  /**
56
15
  * Array containing exclude parameters to exclude/skip tags/operations/methods/paths.
57
16
  */
@@ -64,30 +23,15 @@ export type Options = {
64
23
  * Array containing override parameters to override `options` based on tags/operations/methods/paths.
65
24
  */
66
25
  override?: Array<Override<ResolvedOptions>>
67
- transformers?: {
68
- /**
69
- * Customize the names based on the type that is provided by the plugin.
70
- */
71
- name?: (name: ResolveNameParams['name'], type?: ResolveNameParams['type']) => string
72
- /**
73
- * Receive schema and baseName(propertName) and return FakerMeta array
74
- * TODO TODO add docs
75
- * @beta
76
- */
77
- schema?: (
78
- props: {
79
- schema?: SchemaObject
80
- name?: string
81
- parentName?: string
82
- },
83
- defaultSchemas: Schema[],
84
- ) => Schema[] | undefined
85
- }
86
- mapper?: Record<string, string>
87
26
  /**
88
- * Make it possible to override one of the templates
27
+ * Path to Zod
28
+ * It will be used as `import { z } from '${importPath}'`.
29
+ * It allows both relative and absolute path.
30
+ * the path will be applied as is, so relative path should be based on the file being generated.
31
+ * @default 'zod'
89
32
  */
90
- templates?: Partial<Templates>
33
+ importPath?: string
34
+
91
35
  /**
92
36
  * Choose to use `date` or `datetime` as JavaScript `Date` instead of `string`.
93
37
  * False will fallback on a simple z.string() format
@@ -106,40 +50,57 @@ export type Options = {
106
50
  /**
107
51
  * Return Zod generated schema as type with z.infer<TYPE>
108
52
  */
109
- typedSchema?: boolean
53
+ inferred?: boolean
110
54
  /**
111
55
  * Use of z.coerce.string() instead of z.string()
56
+ * can also be an object to enable coercion for dates, strings, and numbers
112
57
  */
113
- coercion?: boolean
58
+ coercion?:
59
+ | boolean
60
+ | {
61
+ dates?: boolean
62
+ strings?: boolean
63
+ numbers?: boolean
64
+ }
65
+ operations?: boolean
66
+ mapper?: Record<string, string>
67
+ transformers?: {
68
+ /**
69
+ * Customize the names based on the type that is provided by the plugin.
70
+ */
71
+ name?: (name: ResolveNameParams['name'], type?: ResolveNameParams['type']) => string
72
+ /**
73
+ * Receive schema and baseName(propertName) and return FakerMeta array
74
+ * TODO TODO add docs
75
+ * @beta
76
+ */
77
+ schema?: (
78
+ props: {
79
+ schema?: SchemaObject
80
+ name?: string
81
+ parentName?: string
82
+ },
83
+ defaultSchemas: Schema[],
84
+ ) => Schema[] | undefined
85
+ }
114
86
  /**
115
- * Path to Zod
116
- * It will be used as `import { z } from '${importPath}'`.
117
- * It allows both relative and absolute path.
118
- * the path will be applied as is, so relative path should be based on the file being generated.
119
- * @default 'zod'
87
+ * Define some generators next to the zod generators
120
88
  */
121
- importPath?: string
89
+ generators?: Array<Generator<PluginZod>>
122
90
  }
123
91
 
124
92
  type ResolvedOptions = {
125
- extName: KubbFile.Extname | undefined
93
+ output: Output
94
+ override: NonNullable<Options['override']>
126
95
  transformers: NonNullable<Options['transformers']>
127
- exclude: Options['exclude']
128
- include: Options['include']
129
- override: Options['override']
130
96
  dateType: NonNullable<Options['dateType']>
131
97
  unknownType: NonNullable<Options['unknownType']>
132
98
  typed: NonNullable<Options['typed']>
133
- typedSchema: NonNullable<Options['typedSchema']>
134
- templates: NonNullable<Templates>
99
+ inferred: NonNullable<Options['inferred']>
135
100
  mapper: NonNullable<Options['mapper']>
136
101
  importPath: NonNullable<Options['importPath']>
137
102
  coercion: NonNullable<Options['coercion']>
138
- }
139
-
140
- export type FileMeta = {
141
- pluginKey?: Plugin['key']
142
- tag?: string
103
+ operations: NonNullable<Options['operations']>
143
104
  }
144
105
 
145
106
  export type PluginZod = PluginFactoryOptions<'plugin-zod', Options, ResolvedOptions, never, ResolvePathOptions>