@@ -193,18 +193,42 @@ export const onIntersection: Overrider = ({ jsonSchema }) => {
193193export const onNullable : Overrider = ( { jsonSchema } ) => {
194194 if ( ! jsonSchema . anyOf ) return ;
195195 const original = jsonSchema . anyOf [ 0 ] ;
196- Object . assign ( original , { type : makeNullableType ( original ) } ) ;
196+ Object . assign ( original , { type : makeNullableType ( original . type ) } ) ;
197197 Object . assign ( jsonSchema , original ) ;
198198 delete jsonSchema . anyOf ;
199199} ;
200200
201201const isSupportedType = ( subject : string ) : subject is SchemaObjectType =>
202202 subject in samples ;
203203
204+ const ensureCompliance = ( {
205+ $ref,
206+ type,
207+ allOf,
208+ oneOf,
209+ anyOf,
210+ not,
211+ ...rest
212+ } : JSONSchema . BaseSchema ) : SchemaObject | ReferenceObject => {
213+ if ( $ref ) return { $ref } ;
214+ const valid : SchemaObject = {
215+ type : Array . isArray ( type )
216+ ? type . filter ( isSupportedType )
217+ : type && isSupportedType ( type )
218+ ? type
219+ : undefined ,
220+ ...rest ,
221+ } ;
222+ if ( allOf ) valid . allOf = allOf . map ( ensureCompliance ) ;
223+ if ( oneOf ) valid . oneOf = oneOf . map ( ensureCompliance ) ;
224+ if ( anyOf ) valid . anyOf = anyOf . map ( ensureCompliance ) ;
225+ if ( not ) valid . not = ensureCompliance ( not ) ;
226+ return valid ;
227+ } ;
228+
204229export const onDateIn : Overrider = ( { jsonSchema } , ctx ) => {
205230 if ( ctx . isResponse )
206231 throw new DocumentationError ( "Please use ez.dateOut() for output." , ctx ) ;
207- unref ( jsonSchema ) ;
208232 delete jsonSchema . anyOf ; // undo default
209233 Object . assign ( jsonSchema , {
210234 description : "YYYY-MM-DDTHH:mm:ss.sssZ" ,
@@ -254,15 +278,18 @@ const makeSample = (depicted: SchemaObject) => {
254278 return samples ?. [ firstType ] ;
255279} ;
256280
257- const makeNullableType = ( {
258- type,
259- } : JSONSchema . BaseSchema | SchemaObject ) :
260- | SchemaObjectType
261- | SchemaObjectType [ ] => {
262- if ( type === "null" ) return type ;
263- if ( typeof type === "string" )
264- return isSupportedType ( type ) ? [ type , "null" ] : "null" ;
265- return type ? [ ...new Set ( type ) . add ( "null" ) ] : "null" ;
281+ /** @since v24.0.0 does not return null for undefined */
282+ const makeNullableType = (
283+ current :
284+ | JSONSchema . BaseSchema [ "type" ]
285+ | Array < NonNullable < JSONSchema . BaseSchema [ "type" ] > > ,
286+ ) : typeof current => {
287+ if ( current === ( "null" satisfies SchemaObjectType ) ) return current ;
288+ if ( typeof current === "string" )
289+ return [ current , "null" satisfies SchemaObjectType ] ;
290+ return (
291+ current && [ ...new Set ( current ) . add ( "null" satisfies SchemaObjectType ) ]
292+ ) ;
266293} ;
267294
268295export const onPipeline : Overrider = ( { zodSchema, jsonSchema } , ctx ) => {
@@ -296,7 +323,6 @@ export const onPipeline: Overrider = ({ zodSchema, jsonSchema }, ctx) => {
296323} ;
297324
298325export const onRaw : Overrider = ( { jsonSchema } ) => {
299- unref ( jsonSchema ) ;
300326 if ( jsonSchema . type !== "object" ) return ;
301327 const objSchema = jsonSchema as JSONSchema . ObjectSchema ;
302328 if ( ! objSchema . properties ) return ;
@@ -437,12 +463,8 @@ const overrides: Partial<Record<FirstPartyKind | ProprietaryBrand, Overrider>> =
437463 } ;
438464
439465const onEach : Overrider = ( { zodSchema, jsonSchema } , { isResponse } ) => {
440- if (
441- ! isResponse &&
442- jsonSchema . type !== undefined &&
443- doesAccept ( zodSchema , null )
444- )
445- Object . assign ( jsonSchema , { type : makeNullableType ( jsonSchema ) } ) ;
466+ if ( ! isResponse && doesAccept ( zodSchema , null ) )
467+ Object . assign ( jsonSchema , { type : makeNullableType ( jsonSchema . type ) } ) ;
446468 const examples = getExamples ( {
447469 schema : zodSchema ,
448470 variant : isResponse ? "parsed" : "original" ,
@@ -468,14 +490,14 @@ const fixReferences = (
468490 const actualName = entry . $ref . split ( "/" ) . pop ( ) ! ;
469491 const depiction = defs [ actualName ] ;
470492 if ( depiction )
471- entry . $ref = ctx . makeRef ( depiction , depiction as SchemaObject ) . $ref ; // @todo see below
493+ entry . $ref = ctx . makeRef ( depiction , ensureCompliance ( depiction ) ) . $ref ;
472494 continue ;
473495 }
474496 stack . push ( ...R . values ( entry ) ) ;
475497 }
476498 if ( R . is ( Array , entry ) ) stack . push ( ...R . values ( entry ) ) ;
477499 }
478- return subject as SchemaObject ; // @todo ideally, there should be a method to ensure that
500+ return ensureCompliance ( subject ) ;
479501} ;
480502
481503/** @link https://github.com/colinhacks/zod/issues/4275 */
@@ -500,6 +522,7 @@ const depict = (
500522 unrepresentable : "any" ,
501523 io : ctx . isResponse ? "output" : "input" ,
502524 override : ( zodCtx ) => {
525+ unref ( zodCtx . jsonSchema ) ;
503526 const { brand } =
504527 globalRegistry . get ( zodCtx . zodSchema ) ?. [ metaSymbol ] ?? { } ;
505528 rules [
0 commit comments