@kubb/plugin-zod 4.4.0 → 4.5.0

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 (54) hide show
  1. package/dist/{components-DUJ6Xkpc.js → components-BtBB23cQ.js} +85 -75
  2. package/dist/components-BtBB23cQ.js.map +1 -0
  3. package/dist/{components-BiOh-7_I.cjs → components-DIUzzW4k.cjs} +82 -72
  4. package/dist/components-DIUzzW4k.cjs.map +1 -0
  5. package/dist/components.cjs +1 -1
  6. package/dist/components.d.cts +4 -3
  7. package/dist/components.d.ts +4 -3
  8. package/dist/components.js +1 -1
  9. package/dist/{generators-CwEOtNXG.js → generators-9upbJt-4.js} +116 -122
  10. package/dist/generators-9upbJt-4.js.map +1 -0
  11. package/dist/{generators-B2hD7k6l.cjs → generators-T3e_E7Uy.cjs} +115 -120
  12. package/dist/generators-T3e_E7Uy.cjs.map +1 -0
  13. package/dist/generators.cjs +2 -2
  14. package/dist/generators.d.cts +4 -4
  15. package/dist/generators.d.ts +4 -4
  16. package/dist/generators.js +2 -2
  17. package/dist/index.cjs +12 -2
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.d.cts +1 -1
  20. package/dist/index.d.ts +1 -1
  21. package/dist/index.js +11 -2
  22. package/dist/index.js.map +1 -1
  23. package/dist/{types-CENqfJvI.d.cts → types-CQSK_Scm.d.cts} +145 -265
  24. package/dist/{types-DRKJPaUn.d.ts → types-DcQBOr_-.d.ts} +145 -265
  25. package/package.json +18 -20
  26. package/src/components/Zod.tsx +7 -13
  27. package/src/generators/__snapshots__/createPet.ts +2 -2
  28. package/src/generators/__snapshots__/createPetWithUnknownTypeUnknown.ts +2 -2
  29. package/src/generators/__snapshots__/createPetWithUnknownTypeUnknown_wrapOutput.ts +7 -9
  30. package/src/generators/__snapshots__/createPetWithUnknownTypeUnknown_wrapOutput_entire_.ts +7 -10
  31. package/src/generators/__snapshots__/createPet_wrapOutput.ts +7 -9
  32. package/src/generators/__snapshots__/discriminator.ts +20 -28
  33. package/src/generators/__snapshots__/getPets.ts +3 -3
  34. package/src/generators/__snapshots__/getPets_wrapOutput.ts +8 -10
  35. package/src/generators/__snapshots__/petArray.ts +1 -5
  36. package/src/generators/__snapshots__/queryAllDefaulted.ts +1 -1
  37. package/src/generators/__snapshots__/queryAllDefaulted_wrapOutput.ts +2 -2
  38. package/src/generators/__snapshots__/showPetById.ts +3 -3
  39. package/src/generators/__snapshots__/showPetById_wrapOutput.ts +8 -10
  40. package/src/generators/index.ts +1 -1
  41. package/src/generators/operationsGenerator.tsx +5 -5
  42. package/src/generators/zodGenerator.tsx +24 -21
  43. package/src/parser.ts +37 -36
  44. package/src/plugin.ts +15 -0
  45. package/dist/components-BiOh-7_I.cjs.map +0 -1
  46. package/dist/components-DUJ6Xkpc.js.map +0 -1
  47. package/dist/generators-B2hD7k6l.cjs.map +0 -1
  48. package/dist/generators-CwEOtNXG.js.map +0 -1
  49. package/dist/utils.cjs +0 -0
  50. package/dist/utils.d.cts +0 -28
  51. package/dist/utils.d.ts +0 -28
  52. package/dist/utils.js +0 -1
  53. package/src/utils/index.ts +0 -1
  54. /package/{src/utils → templates}/ToZod.ts +0 -0
@@ -12,18 +12,16 @@ export const createPets201 = z.unknown()
12
12
  /**
13
13
  * @description unexpected error
14
14
  */
15
- export const createPetsError = z
16
- .lazy(() => error)
17
- .openapi({
18
- examples: [
19
- { sample: { summary: 'A sample error', value: { code: 1, message: 'A sample error message' } } },
20
- { other_example: { summary: 'Another sample error', value: { code: 2, message: 'A totally specific message' } } },
21
- ],
22
- })
15
+ export const createPetsError = error.openapi({
16
+ examples: [
17
+ { sample: { summary: 'A sample error', value: { code: 1, message: 'A sample error message' } } },
18
+ { other_example: { summary: 'Another sample error', value: { code: 2, message: 'A totally specific message' } } },
19
+ ],
20
+ })
23
21
 
24
22
  export const createPetsMutationRequest = z.object({
25
23
  name: z.string().openapi({ example: 'Baxter' }),
26
24
  tag: z.string(),
27
25
  })
28
26
 
29
- export const createPetsMutationResponse = z.lazy(() => createPets201)
27
+ export const createPetsMutationResponse = createPets201
@@ -12,19 +12,16 @@ export const createPets201 = z.unknown()
12
12
  /**
13
13
  * @description unexpected error
14
14
  */
15
- export const createPetsError = extendApi(
16
- z.lazy(() => error),
17
- {
18
- examples: [
19
- { sample: { summary: 'A sample error', value: { code: 1, message: 'A sample error message' } } },
20
- { other_example: { summary: 'Another sample error', value: { code: 2, message: 'A totally specific message' } } },
21
- ],
22
- },
23
- )
15
+ export const createPetsError = extendApi(error, {
16
+ examples: [
17
+ { sample: { summary: 'A sample error', value: { code: 1, message: 'A sample error message' } } },
18
+ { other_example: { summary: 'Another sample error', value: { code: 2, message: 'A totally specific message' } } },
19
+ ],
20
+ })
24
21
 
25
22
  export const createPetsMutationRequest = z.object({
26
23
  name: extendApi(z.string(), { example: 'Baxter' }),
27
24
  tag: z.string(),
28
25
  })
29
26
 
30
- export const createPetsMutationResponse = z.lazy(() => createPets201)
27
+ export const createPetsMutationResponse = createPets201
@@ -12,18 +12,16 @@ export const createPets201 = z.unknown()
12
12
  /**
13
13
  * @description unexpected error
14
14
  */
15
- export const createPetsError = z
16
- .lazy(() => error)
17
- .openapi({
18
- examples: [
19
- { sample: { summary: 'A sample error', value: { code: 1, message: 'A sample error message' } } },
20
- { other_example: { summary: 'Another sample error', value: { code: 2, message: 'A totally specific message' } } },
21
- ],
22
- })
15
+ export const createPetsError = error.openapi({
16
+ examples: [
17
+ { sample: { summary: 'A sample error', value: { code: 1, message: 'A sample error message' } } },
18
+ { other_example: { summary: 'Another sample error', value: { code: 2, message: 'A totally specific message' } } },
19
+ ],
20
+ })
23
21
 
24
22
  export const createPetsMutationRequest = z.object({
25
23
  name: z.string().openapi({ example: 'Baxter' }),
26
24
  tag: z.string(),
27
25
  })
28
26
 
29
- export const createPetsMutationResponse = z.lazy(() => createPets201)
27
+ export const createPetsMutationResponse = createPets201
@@ -5,32 +5,24 @@
5
5
  import { z } from 'zod'
6
6
 
7
7
  export const advanced = z.union([
8
- z
9
- .lazy(() => enumerationValueSpecificationDto)
10
- .and(
11
- z.object({
12
- type: z.literal('enum'),
13
- }),
14
- ),
15
- z
16
- .lazy(() => rangeValueSpecificationDto)
17
- .and(
18
- z.object({
19
- type: z.literal('range'),
20
- }),
21
- ),
22
- z
23
- .lazy(() => regexValueSpecificationDto)
24
- .and(
25
- z.object({
26
- type: z.literal('regex'),
27
- }),
28
- ),
29
- z
30
- .lazy(() => sliderValueSpecificationDto)
31
- .and(
32
- z.object({
33
- type: z.literal('slider'),
34
- }),
35
- ),
8
+ enumerationValueSpecificationDto.and(
9
+ z.object({
10
+ type: z.literal('enum'),
11
+ }),
12
+ ),
13
+ rangeValueSpecificationDto.and(
14
+ z.object({
15
+ type: z.literal('range'),
16
+ }),
17
+ ),
18
+ regexValueSpecificationDto.and(
19
+ z.object({
20
+ type: z.literal('regex'),
21
+ }),
22
+ ),
23
+ sliderValueSpecificationDto.and(
24
+ z.object({
25
+ type: z.literal('slider'),
26
+ }),
27
+ ),
36
28
  ])
@@ -12,11 +12,11 @@ export const listPetsQueryParams = z.object({
12
12
  /**
13
13
  * @description A paged array of pets
14
14
  */
15
- export const listPets200 = z.lazy(() => pets)
15
+ export const listPets200 = pets
16
16
 
17
17
  /**
18
18
  * @description unexpected error
19
19
  */
20
- export const listPetsError = z.lazy(() => error)
20
+ export const listPetsError = error
21
21
 
22
- export const listPetsQueryResponse = z.lazy(() => listPets200)
22
+ export const listPetsQueryResponse = listPets200
@@ -12,18 +12,16 @@ export const listPetsQueryParams = z.object({
12
12
  /**
13
13
  * @description A paged array of pets
14
14
  */
15
- export const listPets200 = z.lazy(() => pets)
15
+ export const listPets200 = pets
16
16
 
17
17
  /**
18
18
  * @description unexpected error
19
19
  */
20
- export const listPetsError = z
21
- .lazy(() => error)
22
- .openapi({
23
- examples: [
24
- { sample: { summary: 'A sample error', value: { code: 1, message: 'A sample error message' } } },
25
- { other_example: { summary: 'Another sample error', value: { code: 2, message: 'A totally specific message' } } },
26
- ],
27
- })
20
+ export const listPetsError = error.openapi({
21
+ examples: [
22
+ { sample: { summary: 'A sample error', value: { code: 1, message: 'A sample error message' } } },
23
+ { other_example: { summary: 'Another sample error', value: { code: 2, message: 'A totally specific message' } } },
24
+ ],
25
+ })
28
26
 
29
- export const listPetsQueryResponse = z.lazy(() => listPets200)
27
+ export const listPetsQueryResponse = listPets200
@@ -7,8 +7,4 @@ import { z } from 'zod'
7
7
  /**
8
8
  * @description List of Pet object
9
9
  */
10
- export const petArray = z
11
- .array(z.lazy(() => pet))
12
- .min(1)
13
- .max(3)
14
- .describe('List of Pet object')
10
+ export const petArray = z.array(pet).min(1).max(3).describe('List of Pet object')
@@ -16,4 +16,4 @@ export const getThings200 = z.object({
16
16
  items: z.array(z.lazy(() => thing)),
17
17
  })
18
18
 
19
- export const getThingsQueryResponse = z.lazy(() => getThings200)
19
+ export const getThingsQueryResponse = getThings200
@@ -13,7 +13,7 @@ export const getThingsQueryParams = z.object({
13
13
  * @description A list of things
14
14
  */
15
15
  export const getThings200 = z.object({
16
- items: z.array(z.lazy(() => thing)),
16
+ items: z.array(thing),
17
17
  })
18
18
 
19
- export const getThingsQueryResponse = z.lazy(() => getThings200)
19
+ export const getThingsQueryResponse = getThings200
@@ -12,11 +12,11 @@ export const showPetByIdPathParams = z.object({
12
12
  /**
13
13
  * @description Expected response to a valid request
14
14
  */
15
- export const showPetById200 = z.lazy(() => pet)
15
+ export const showPetById200 = pet
16
16
 
17
17
  /**
18
18
  * @description unexpected error
19
19
  */
20
- export const showPetByIdError = z.lazy(() => error)
20
+ export const showPetByIdError = error
21
21
 
22
- export const showPetByIdQueryResponse = z.lazy(() => showPetById200)
22
+ export const showPetByIdQueryResponse = showPetById200
@@ -12,18 +12,16 @@ export const showPetByIdPathParams = z.object({
12
12
  /**
13
13
  * @description Expected response to a valid request
14
14
  */
15
- export const showPetById200 = z.lazy(() => pet)
15
+ export const showPetById200 = pet
16
16
 
17
17
  /**
18
18
  * @description unexpected error
19
19
  */
20
- export const showPetByIdError = z
21
- .lazy(() => error)
22
- .openapi({
23
- examples: [
24
- { sample: { summary: 'A sample error', value: { code: 1, message: 'A sample error message' } } },
25
- { other_example: { summary: 'Another sample error', value: { code: 2, message: 'A totally specific message' } } },
26
- ],
27
- })
20
+ export const showPetByIdError = error.openapi({
21
+ examples: [
22
+ { sample: { summary: 'A sample error', value: { code: 1, message: 'A sample error message' } } },
23
+ { other_example: { summary: 'Another sample error', value: { code: 2, message: 'A totally specific message' } } },
24
+ ],
25
+ })
28
26
 
29
- export const showPetByIdQueryResponse = z.lazy(() => showPetById200)
27
+ export const showPetByIdQueryResponse = showPetById200
@@ -1,2 +1,2 @@
1
- export { zodGenerator } from './zodGenerator.tsx'
2
1
  export { operationsGenerator } from './operationsGenerator.tsx'
2
+ export { zodGenerator } from './zodGenerator.tsx'
@@ -1,5 +1,5 @@
1
- import { usePlugin, usePluginManager } from '@kubb/core/hooks'
2
- import { createReactGenerator } from '@kubb/plugin-oas'
1
+ import { usePluginManager } from '@kubb/core/hooks'
2
+ import { createReactGenerator } from '@kubb/plugin-oas/generators'
3
3
  import { useOas, useOperationManager } from '@kubb/plugin-oas/hooks'
4
4
  import { getBanner, getFooter } from '@kubb/plugin-oas/utils'
5
5
  import { File } from '@kubb/react-fabric'
@@ -8,15 +8,15 @@ import type { PluginZod } from '../types'
8
8
 
9
9
  export const operationsGenerator = createReactGenerator<PluginZod>({
10
10
  name: 'operations',
11
- Operations({ operations }) {
11
+ Operations({ operations, generator, plugin }) {
12
12
  const {
13
13
  key: pluginKey,
14
14
  options: { output, importPath },
15
- } = usePlugin<PluginZod>()
15
+ } = plugin
16
16
  const pluginManager = usePluginManager()
17
17
 
18
18
  const oas = useOas()
19
- const { getFile, groupSchemasByName } = useOperationManager()
19
+ const { getFile, groupSchemasByName } = useOperationManager(generator)
20
20
 
21
21
  const name = 'operations'
22
22
  const file = pluginManager.getFile({ name, extname: '.ts', pluginKey })
@@ -1,30 +1,33 @@
1
- import { useMode, usePlugin, usePluginManager } from '@kubb/core/hooks'
2
- import { createReactGenerator, type OperationSchema as OperationSchemaType, SchemaGenerator, schemaKeywords } from '@kubb/plugin-oas'
3
- import { Oas } from '@kubb/plugin-oas/components'
1
+ import path from 'node:path'
2
+ import { useMode, usePluginManager } from '@kubb/core/hooks'
3
+ import { type OperationSchema as OperationSchemaType, SchemaGenerator, schemaKeywords } from '@kubb/plugin-oas'
4
+ import { createReactGenerator } from '@kubb/plugin-oas/generators'
4
5
  import { useOas, useOperationManager, useSchemaManager } from '@kubb/plugin-oas/hooks'
5
6
  import { getBanner, getFooter } from '@kubb/plugin-oas/utils'
6
7
  import { pluginTsName } from '@kubb/plugin-ts'
7
- import { File } from '@kubb/react-fabric'
8
+ import { File, Fragment } from '@kubb/react-fabric'
8
9
  import { Zod } from '../components'
9
10
  import type { PluginZod } from '../types'
10
11
 
11
12
  export const zodGenerator = createReactGenerator<PluginZod>({
12
13
  name: 'zod',
13
- Operation({ operation, options, instance }) {
14
- const { coercion: globalCoercion, inferred, typed, mapper, wrapOutput } = options
14
+ Operation({ config, operation, generator, plugin }) {
15
+ const {
16
+ options,
17
+ options: { coercion: globalCoercion, inferred, typed, mapper, wrapOutput, version },
18
+ } = plugin
15
19
 
16
- const plugin = usePlugin<PluginZod>()
17
20
  const mode = useMode()
18
21
  const pluginManager = usePluginManager()
19
22
 
20
23
  const oas = useOas()
21
- const { getSchemas, getFile, getGroup } = useOperationManager()
24
+ const { getSchemas, getFile, getGroup } = useOperationManager(generator)
22
25
  const schemaManager = useSchemaManager()
23
26
 
24
27
  const file = getFile(operation)
25
28
  const schemas = getSchemas(operation)
26
29
  const schemaGenerator = new SchemaGenerator(options, {
27
- fabric: instance.context.fabric,
30
+ fabric: generator.context.fabric,
28
31
  oas,
29
32
  plugin,
30
33
  pluginManager,
@@ -36,7 +39,7 @@ export const zodGenerator = createReactGenerator<PluginZod>({
36
39
  .flat()
37
40
  .filter(Boolean)
38
41
 
39
- const mapOperationSchema = ({ name, schema: schemaObject, description, keysToOmit, ...options }: OperationSchemaType, i: number) => {
42
+ const mapOperationSchema = ({ name, schema: schemaObject, description, keysToOmit, ...options }: OperationSchemaType) => {
40
43
  // hack so Params can be optional when needed
41
44
  const required = Array.isArray(schemaObject?.required) ? !!schemaObject.required.length : !!schemaObject?.required
42
45
  const someDefaults = Object.values(schemaObject.properties || {}).some((property) => Object.hasOwn(property, 'default') && property.default !== undefined)
@@ -66,9 +69,9 @@ export const zodGenerator = createReactGenerator<PluginZod>({
66
69
  }
67
70
 
68
71
  return (
69
- <Oas.Schema key={i} name={name} schemaObject={schemaObject} tree={tree}>
72
+ <Fragment>
70
73
  {typed && <File.Import isTypeOnly root={file.path} path={type.file.path} name={[type.name]} />}
71
- {typed && plugin.options.version === '3' && <File.Import isTypeOnly path={'@kubb/plugin-zod/utils'} name={['ToZod']} />}
74
+ {typed && version === '3' && <File.Import name={['ToZod']} root={file.path} path={path.resolve(config.root, config.output.path, '.kubb/ToZod.ts')} />}
72
75
  {imports.map((imp) => (
73
76
  <File.Import key={[imp.path, imp.name, imp.isTypeOnly].join('-')} root={file.path} path={imp.path} name={imp.name} />
74
77
  ))}
@@ -78,7 +81,7 @@ export const zodGenerator = createReactGenerator<PluginZod>({
78
81
  inferTypeName={inferred ? zod.inferTypeName : undefined}
79
82
  description={description}
80
83
  tree={tree}
81
- rawSchema={schemaObject}
84
+ schema={schemaObject}
82
85
  mapper={mapper}
83
86
  coercion={coercion}
84
87
  keysToOmit={keysToOmit}
@@ -86,7 +89,7 @@ export const zodGenerator = createReactGenerator<PluginZod>({
86
89
  version={plugin.options.version}
87
90
  emptySchemaType={plugin.options.emptySchemaType}
88
91
  />
89
- </Oas.Schema>
92
+ </Fragment>
90
93
  )
91
94
  }
92
95
 
@@ -103,13 +106,11 @@ export const zodGenerator = createReactGenerator<PluginZod>({
103
106
  </File>
104
107
  )
105
108
  },
106
- Schema({ schema, options }) {
107
- const { coercion, inferred, typed, mapper, importPath, wrapOutput, version } = options
108
-
109
+ Schema({ config, schema, plugin }) {
109
110
  const { getName, getFile, getImports } = useSchemaManager()
110
111
  const {
111
- options: { output, emptySchemaType },
112
- } = usePlugin<PluginZod>()
112
+ options: { output, emptySchemaType, coercion, inferred, typed, mapper, importPath, wrapOutput, version },
113
+ } = plugin
113
114
  const pluginManager = usePluginManager()
114
115
  const oas = useOas()
115
116
 
@@ -136,7 +137,9 @@ export const zodGenerator = createReactGenerator<PluginZod>({
136
137
  >
137
138
  <File.Import name={['z']} path={importPath} />
138
139
  {typed && <File.Import isTypeOnly root={zod.file.path} path={type.file.path} name={[type.name]} />}
139
- {typed && <File.Import isTypeOnly path={options.version === '4' ? '@kubb/plugin-zod/utils/v4' : '@kubb/plugin-zod/utils'} name={['ToZod']} />}
140
+ {typed && version === '3' && (
141
+ <File.Import name={['ToZod']} root={zod.file.path} path={path.resolve(config.root, config.output.path, '.kubb/ToZod.ts')} />
142
+ )}
140
143
  {imports.map((imp) => (
141
144
  <File.Import key={[imp.path, imp.name, imp.isTypeOnly].join('-')} root={zod.file.path} path={imp.path} name={imp.name} />
142
145
  ))}
@@ -147,7 +150,7 @@ export const zodGenerator = createReactGenerator<PluginZod>({
147
150
  inferTypeName={inferred ? zod.inferTypeName : undefined}
148
151
  description={schema.value.description}
149
152
  tree={schema.tree}
150
- rawSchema={schema.value}
153
+ schema={schema.value}
151
154
  mapper={mapper}
152
155
  coercion={coercion}
153
156
  wrapOutput={wrapOutput}
package/src/parser.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import transformers from '@kubb/core/transformers'
2
- import type { SchemaObject } from '@kubb/oas'
3
2
 
4
3
  import type { Schema, SchemaKeywordBase, SchemaMapper } from '@kubb/plugin-oas'
5
4
  import { isKeyword, SchemaGenerator, type SchemaKeywordMapper, type SchemaTree, schemaKeywords } from '@kubb/plugin-oas'
@@ -191,12 +190,12 @@ const zodKeywordMapper = {
191
190
  phone: undefined,
192
191
  readOnly: undefined,
193
192
  writeOnly: undefined,
194
- ref: (value?: string, version: '3' | '4' = '3') => {
193
+ ref: (value?: string, lazy = true) => {
195
194
  if (!value) {
196
195
  return undefined
197
196
  }
198
197
 
199
- return version === '4' ? value : `z.lazy(() => ${value})`
198
+ return lazy ? `z.lazy(() => ${value})` : value
200
199
  },
201
200
  blob: () => 'z.instanceof(File)',
202
201
  deprecated: undefined,
@@ -258,18 +257,14 @@ const shouldCoerce = (coercion: ParserOptions['coercion'] | undefined, type: 'da
258
257
  }
259
258
 
260
259
  type ParserOptions = {
261
- name: string
262
- typeName?: string
263
- description?: string
264
- keysToOmit?: string[]
260
+ lazy?: boolean
265
261
  mapper?: Record<string, string>
266
262
  coercion?: boolean | { dates?: boolean; strings?: boolean; numbers?: boolean }
267
263
  wrapOutput?: (opts: { output: string; schema: any }) => string | undefined
268
- rawSchema: SchemaObject
269
264
  version: '3' | '4'
270
265
  }
271
266
 
272
- export function parse({ parent, current, name, siblings }: SchemaTree, options: ParserOptions): string | undefined {
267
+ export function parse({ schema, parent, current, name, siblings }: SchemaTree, options: ParserOptions): string | undefined {
273
268
  const value = zodKeywordMapper[current.keyword as keyof typeof zodKeywordMapper]
274
269
 
275
270
  // Early exit: if siblings contain both matches and ref → skip matches entirely
@@ -287,7 +282,7 @@ export function parse({ parent, current, name, siblings }: SchemaTree, options:
287
282
  if (isKeyword(current, schemaKeywords.union)) {
288
283
  // zod union type needs at least 2 items
289
284
  if (Array.isArray(current.args) && current.args.length === 1) {
290
- return parse({ parent, name: name, current: current.args[0] as Schema, siblings }, options)
285
+ return parse({ schema, parent, name, current: current.args[0] as Schema, siblings }, options)
291
286
  }
292
287
  if (Array.isArray(current.args) && !current.args.length) {
293
288
  return ''
@@ -295,7 +290,7 @@ export function parse({ parent, current, name, siblings }: SchemaTree, options:
295
290
 
296
291
  return zodKeywordMapper.union(
297
292
  sort(current.args)
298
- .map((schema, _index, siblings) => parse({ parent: current, name: name, current: schema, siblings }, options))
293
+ .map((it, _index, siblings) => parse({ schema, parent: current, name, current: it, siblings }, options))
299
294
  .filter(Boolean),
300
295
  )
301
296
  }
@@ -305,7 +300,7 @@ export function parse({ parent, current, name, siblings }: SchemaTree, options:
305
300
  .filter((schema: Schema) => {
306
301
  return ![schemaKeywords.optional, schemaKeywords.describe].includes(schema.keyword as typeof schemaKeywords.describe)
307
302
  })
308
- .map((schema: Schema, _index, siblings) => parse({ parent: current, name: name, current: schema, siblings }, options))
303
+ .map((it: Schema, _index, siblings) => parse({ schema, parent: current, name, current: it, siblings }, options))
309
304
  .filter(Boolean)
310
305
 
311
306
  return `${items.slice(0, 1)}${zodKeywordMapper.and(items.slice(1))}`
@@ -314,7 +309,9 @@ export function parse({ parent, current, name, siblings }: SchemaTree, options:
314
309
  if (isKeyword(current, schemaKeywords.array)) {
315
310
  return zodKeywordMapper.array(
316
311
  sort(current.args.items)
317
- .map((schemas, _index, siblings) => parse({ parent: current, name: name, current: schemas, siblings }, options))
312
+ .map((it, _index, siblings) => {
313
+ return parse({ schema, parent: current, name, current: it, siblings }, options)
314
+ })
318
315
  .filter(Boolean),
319
316
  current.args.min,
320
317
  current.args.max,
@@ -329,7 +326,7 @@ export function parse({ parent, current, name, siblings }: SchemaTree, options:
329
326
  keyword: schemaKeywords.const,
330
327
  args: current.args.items[0],
331
328
  }
332
- return parse({ parent: current, name: name, current: child, siblings: [child] }, options)
329
+ return parse({ schema, parent: current, name, current: child, siblings: [child] }, options)
333
330
  }
334
331
 
335
332
  return zodKeywordMapper.union(
@@ -338,8 +335,8 @@ export function parse({ parent, current, name, siblings }: SchemaTree, options:
338
335
  keyword: schemaKeywords.const,
339
336
  args: schema,
340
337
  }))
341
- .map((schema, _index, siblings) => {
342
- return parse({ parent: current, name: name, current: schema, siblings }, options)
338
+ .map((it, _index, siblings) => {
339
+ return parse({ schema, parent: current, name, current: it, siblings }, options)
343
340
  })
344
341
  .filter(Boolean),
345
342
  )
@@ -360,7 +357,7 @@ export function parse({ parent, current, name, siblings }: SchemaTree, options:
360
357
  }
361
358
 
362
359
  if (isKeyword(current, schemaKeywords.ref)) {
363
- return zodKeywordMapper.ref(current.args?.name, options.version)
360
+ return zodKeywordMapper.ref(current.args?.name, options.lazy ?? name === current.args.name)
364
361
  }
365
362
 
366
363
  if (isKeyword(current, schemaKeywords.object)) {
@@ -370,80 +367,84 @@ export function parse({ parent, current, name, siblings }: SchemaTree, options:
370
367
  })
371
368
 
372
369
  const properties = propertyEntries
373
- .map(([name, schemas]) => {
370
+ .map(([propertyName, schemas]) => {
374
371
  const nameSchema = schemas.find((it) => it.keyword === schemaKeywords.name) as SchemaKeywordMapper['name']
375
372
  const isNullable = schemas.some((it) => isKeyword(it, schemaKeywords.nullable))
376
373
  const isNullish = schemas.some((it) => isKeyword(it, schemaKeywords.nullish))
377
374
  const isOptional = schemas.some((it) => isKeyword(it, schemaKeywords.optional))
375
+ const hasRef = !!SchemaGenerator.find(schemas, schemaKeywords.ref)
378
376
 
379
- const mappedName = nameSchema?.args || name
377
+ const mappedName = nameSchema?.args || propertyName
380
378
 
381
379
  // custom mapper(pluginOptions)
382
380
  if (options.mapper?.[mappedName]) {
383
- return `"${name}": ${options.mapper?.[mappedName]}`
381
+ return `"${propertyName}": ${options.mapper?.[mappedName]}`
384
382
  }
385
383
 
386
384
  const baseSchemaOutput = sort(schemas)
387
385
  .filter((schema) => {
388
386
  return !isKeyword(schema, schemaKeywords.optional) && !isKeyword(schema, schemaKeywords.nullable) && !isKeyword(schema, schemaKeywords.nullish)
389
387
  })
390
- .map((schema) => parse({ parent: current, name, current: schema, siblings: schemas }, options))
388
+ .map((it) => {
389
+ const lazy = !(options.version === '4' && hasRef)
390
+ return parse({ schema, parent: current, name, current: it, siblings: schemas }, { ...options, lazy })
391
+ })
391
392
  .filter(Boolean)
392
393
  .join('')
393
394
 
394
395
  const objectValue = options.wrapOutput
395
- ? options.wrapOutput({ output: baseSchemaOutput, schema: options.rawSchema?.properties?.[name] }) || baseSchemaOutput
396
+ ? options.wrapOutput({ output: baseSchemaOutput, schema: schema?.properties?.[propertyName] }) || baseSchemaOutput
396
397
  : baseSchemaOutput
397
398
 
398
- if (options.version === '4' && SchemaGenerator.find(schemas, schemaKeywords.ref)) {
399
+ if (options.version === '4' && hasRef) {
399
400
  // both optional and nullable
400
401
  if (isNullish) {
401
- return `get "${name}"(){
402
- return ${zodKeywordMapper.nullish(objectValue)}
402
+ return `get "${propertyName}"(){
403
+ return ${objectValue}${zodKeywordMapper.nullish()}
403
404
  }`
404
405
  }
405
406
 
406
407
  // undefined
407
408
  if (isOptional) {
408
- return `get "${name}"(){
409
- return ${zodKeywordMapper.optional(objectValue)}
409
+ return `get "${propertyName}"(){
410
+ return ${objectValue}${zodKeywordMapper.optional()}
410
411
  }`
411
412
  }
412
413
 
413
414
  // null
414
415
  if (isNullable) {
415
- return `get "${name}"(){
416
- return ${zodKeywordMapper.nullable(objectValue)}
416
+ return `get "${propertyName}"(){
417
+ return ${objectValue}${zodKeywordMapper.nullable()}
417
418
  }`
418
419
  }
419
420
 
420
- return `get "${name}"(){
421
+ return `get "${propertyName}"(){
421
422
  return ${objectValue}
422
423
  }`
423
424
  }
424
425
 
425
426
  // both optional and nullable
426
427
  if (isNullish) {
427
- return `"${name}": ${objectValue}${zodKeywordMapper.nullish()}`
428
+ return `"${propertyName}": ${objectValue}${zodKeywordMapper.nullish()}`
428
429
  }
429
430
 
430
431
  // undefined
431
432
  if (isOptional) {
432
- return `"${name}": ${zodKeywordMapper.optional(objectValue)}`
433
+ return `"${propertyName}": ${zodKeywordMapper.optional(objectValue)}`
433
434
  }
434
435
 
435
436
  // null
436
437
  if (isNullable) {
437
- return `"${name}": ${zodKeywordMapper.nullable(objectValue)}`
438
+ return `"${propertyName}": ${zodKeywordMapper.nullable(objectValue)}`
438
439
  }
439
440
 
440
- return `"${name}": ${objectValue}`
441
+ return `"${propertyName}": ${objectValue}`
441
442
  })
442
443
  .join(',\n')
443
444
 
444
445
  const additionalProperties = current.args?.additionalProperties?.length
445
446
  ? current.args.additionalProperties
446
- .map((schema, _index, siblings) => parse({ parent: current, name: name, current: schema, siblings }, options))
447
+ .map((it, _index, siblings) => parse({ schema, parent: current, name, current: it, siblings }, options))
447
448
  .filter(Boolean)
448
449
  .join('')
449
450
  : undefined
@@ -458,7 +459,7 @@ export function parse({ parent, current, name, siblings }: SchemaTree, options:
458
459
 
459
460
  if (isKeyword(current, schemaKeywords.tuple)) {
460
461
  return zodKeywordMapper.tuple(
461
- current.args.items.map((schema, _index, siblings) => parse({ parent: current, name: name, current: schema, siblings }, options)).filter(Boolean),
462
+ current.args.items.map((it, _index, siblings) => parse({ schema, parent: current, name, current: it, siblings }, options)).filter(Boolean),
462
463
  )
463
464
  }
464
465
 
package/src/plugin.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import path from 'node:path'
2
2
  import { createPlugin, type Group, getBarrelFiles, getMode, PackageManager, type Plugin, PluginManager } from '@kubb/core'
3
3
  import { camelCase, pascalCase } from '@kubb/core/transformers'
4
+ import { resolveModuleSource } from '@kubb/core/utils'
4
5
  import type { PluginOas as SwaggerPluginOptions } from '@kubb/plugin-oas'
5
6
  import { OperationGenerator, pluginOasName, SchemaGenerator } from '@kubb/plugin-oas'
6
7
  import { pluginTsName } from '@kubb/plugin-ts'
@@ -112,6 +113,20 @@ export const pluginZod = createPlugin<PluginZod>((options) => {
112
113
  const root = path.resolve(this.config.root, this.config.output.path)
113
114
  const mode = getMode(path.resolve(root, output.path))
114
115
 
116
+ if (this.plugin.options.typed && this.plugin.options.version === '3') {
117
+ // pre add bundled fetcher
118
+ await this.addFile({
119
+ baseName: 'ToZod.ts',
120
+ path: path.resolve(root, '.kubb/ToZod.ts'),
121
+ sources: [
122
+ {
123
+ name: 'ToZod',
124
+ value: resolveModuleSource('@kubb/plugin-zod/templates/ToZod').source,
125
+ },
126
+ ],
127
+ })
128
+ }
129
+
115
130
  const schemaGenerator = new SchemaGenerator(this.plugin.options, {
116
131
  fabric: this.fabric,
117
132
  oas,