@@ -6,6 +6,7 @@ import { CodeMeta } from "./CodeMeta";
6
6
import { isReferenceObject } from "./isReferenceObject" ;
7
7
import type { TemplateContext } from "./template-context" ;
8
8
import { escapeControlCharacters , isPrimitiveType , wrapWithQuotesIfNeeded } from "./utils" ;
9
+ import { inferRequiredSchema } from "./inferRequiredOnly" ;
9
10
10
11
type ConversionArgs = {
11
12
schema : SchemaObject | ReferenceObject ;
@@ -23,7 +24,6 @@ export function getZodSchema({ schema, ctx, meta: inheritedMeta, options }: Conv
23
24
if ( ! schema ) {
24
25
throw new Error ( "Schema is required" ) ;
25
26
}
26
-
27
27
const code = new CodeMeta ( schema , ctx , inheritedMeta ) ;
28
28
const meta = {
29
29
parent : code . inherit ( inheritedMeta ?. parent ) ,
@@ -87,14 +87,14 @@ export function getZodSchema({ schema, ctx, meta: inheritedMeta, options }: Conv
87
87
88
88
/* when there are multiple allOf we are unable to use a discriminatedUnion as this library adds an
89
89
* 'z.and' to the schema that it creates which breaks type inference */
90
- const hasMultipleAllOf = schema . oneOf ?. some ( ( obj ) => isSchemaObject ( obj ) && ( obj ?. allOf || [ ] ) . length > 1 )
90
+ const hasMultipleAllOf = schema . oneOf ?. some ( ( obj ) => isSchemaObject ( obj ) && ( obj ?. allOf || [ ] ) . length > 1 ) ;
91
91
if ( schema . discriminator && ! hasMultipleAllOf ) {
92
92
const propertyName = schema . discriminator . propertyName ;
93
93
94
94
return code . assign ( `
95
95
z.discriminatedUnion("${ propertyName } ", [${ schema . oneOf
96
- . map ( ( prop ) => getZodSchema ( { schema : prop , ctx, meta, options } ) )
97
- . join ( ", " ) } ])
96
+ . map ( ( prop ) => getZodSchema ( { schema : prop , ctx, meta, options } ) )
97
+ . join ( ", " ) } ])
98
98
` ) ;
99
99
}
100
100
@@ -136,8 +136,24 @@ export function getZodSchema({ schema, ctx, meta: inheritedMeta, options }: Conv
136
136
const type = getZodSchema ( { schema : schema . allOf [ 0 ] ! , ctx, meta, options } ) ;
137
137
return code . assign ( type . toString ( ) ) ;
138
138
}
139
-
140
- const types = schema . allOf . map ( ( prop ) => getZodSchema ( { schema : prop , ctx, meta, options } ) ) ;
139
+ const { patchRequiredSchemaInLoop, noRequiredOnlyAllof, composedRequiredSchema } = inferRequiredSchema ( schema ) ;
140
+
141
+ const types = noRequiredOnlyAllof . map ( ( prop ) => {
142
+ const zodSchema = getZodSchema ( { schema : prop , ctx, meta, options } ) ;
143
+ ctx ?. resolver && patchRequiredSchemaInLoop ( prop , ctx . resolver ) ;
144
+ return zodSchema ;
145
+ } ) ;
146
+
147
+ if ( composedRequiredSchema . required . length ) {
148
+ types . push (
149
+ getZodSchema ( {
150
+ schema : composedRequiredSchema ,
151
+ ctx,
152
+ meta,
153
+ options,
154
+ } )
155
+ ) ;
156
+ }
141
157
const first = types . at ( 0 ) ! ;
142
158
const rest = types
143
159
. slice ( 1 )
@@ -158,7 +174,9 @@ export function getZodSchema({ schema, ctx, meta: inheritedMeta, options }: Conv
158
174
}
159
175
160
176
// eslint-disable-next-line sonarjs/no-nested-template-literals
161
- return code . assign ( `z.enum([${ schema . enum . map ( ( value ) => value === null ? "null" : `"${ value } "` ) . join ( ", " ) } ])` ) ;
177
+ return code . assign (
178
+ `z.enum([${ schema . enum . map ( ( value ) => ( value === null ? "null" : `"${ value } "` ) ) . join ( ", " ) } ])`
179
+ ) ;
162
180
}
163
181
164
182
if ( schema . enum . some ( ( e ) => typeof e === "string" ) ) {
@@ -200,15 +218,14 @@ export function getZodSchema({ schema, ctx, meta: inheritedMeta, options }: Conv
200
218
return code . assign ( `z.array(z.any())${ readonly } ` ) ;
201
219
}
202
220
203
- if (
204
- schemaType === "object" ||
205
- schema . properties ||
206
- schema . additionalProperties ||
207
- ( schema . required && Array . isArray ( schema . required ) )
208
- ) {
221
+ if ( schemaType === "object" || schema . properties || schema . additionalProperties ) {
209
222
// additional properties default to true if additionalPropertiesDefaultValue not provided
210
- const additionalPropsDefaultValue = options ?. additionalPropertiesDefaultValue !== undefined ? options ?. additionalPropertiesDefaultValue : true ;
211
- const additionalProps = schema . additionalProperties === null || schema . additionalProperties === undefined ? additionalPropsDefaultValue : schema . additionalProperties ;
223
+ const additionalPropsDefaultValue =
224
+ options ?. additionalPropertiesDefaultValue !== undefined ? options ?. additionalPropertiesDefaultValue : true ;
225
+ const additionalProps =
226
+ schema . additionalProperties === null || schema . additionalProperties === undefined
227
+ ? additionalPropsDefaultValue
228
+ : schema . additionalProperties ;
212
229
const additionalPropsSchema = additionalProps === false ? "" : ".passthrough()" ;
213
230
214
231
if ( typeof schema . additionalProperties === "object" && Object . keys ( schema . additionalProperties ) . length > 0 ) {
@@ -235,8 +252,8 @@ export function getZodSchema({ schema, ctx, meta: inheritedMeta, options }: Conv
235
252
isRequired : isPartial
236
253
? true
237
254
: hasRequiredArray
238
- ? schema . required ?. includes ( prop )
239
- : options ?. withImplicitRequiredProps ,
255
+ ? schema . required ?. includes ( prop )
256
+ : options ?. withImplicitRequiredProps ,
240
257
name : prop ,
241
258
} as CodeMetaData ;
242
259
@@ -263,26 +280,7 @@ export function getZodSchema({ schema, ctx, meta: inheritedMeta, options }: Conv
263
280
}
264
281
265
282
const partial = isPartial ? ".partial()" : "" ;
266
-
267
- const schemaRequired = schema . required ;
268
- const schemaProperties = schema . properties ;
269
- // properties in required array but not in properties should be validated seprately, when additional props are allowed
270
- const extraPropertiesFromRequiredArray =
271
- additionalProps !== false && schemaRequired
272
- ? schemaProperties
273
- ? schemaRequired . filter ( ( p ) => ! ( p in schemaProperties ) )
274
- : schemaRequired
275
- : [ ] ;
276
- const extraProperties =
277
- extraPropertiesFromRequiredArray . length > 0
278
- ? "z.object({ " + extraPropertiesFromRequiredArray . map ( ( p ) => `${ p } : z.unknown()` ) . join ( ", " ) + " })"
279
- : "" ;
280
-
281
- return code . assign (
282
- `z.object(${ properties } )${ partial } ${
283
- extraProperties && ".and(" + extraProperties + ")"
284
- } ${ additionalPropsSchema } ${ readonly } `
285
- ) ;
283
+ return code . assign ( `z.object(${ properties } )${ partial } ${ additionalPropsSchema } ${ readonly } ` ) ;
286
284
}
287
285
288
286
if ( ! schemaType ) return code . assign ( "z.unknown()" ) ;
0 commit comments