@@ -279,6 +279,18 @@ def canonicalish(schema: JSONType) -> Dict[str, Any]:
279279 elif len (enum_ ) == 1 :
280280 return {"const" : enum_ [0 ]}
281281 return {"enum" : enum_ }
282+ # if/then/else schemas are ignored unless if and another are present
283+ if_ = schema .pop ("if" , None )
284+ then = schema .pop ("then" , schema )
285+ else_ = schema .pop ("else" , schema )
286+ if if_ is not None and (then is not schema or else_ is not schema ):
287+ schema = {
288+ "anyOf" : [
289+ {"allOf" : [if_ , then , schema ]},
290+ {"allOf" : [{"not" : if_ }, else_ , schema ]},
291+ ]
292+ }
293+ assert isinstance (schema , dict )
282294 # Recurse into the value of each keyword with a schema (or list of them) as a value
283295 for key in SCHEMA_KEYS :
284296 if isinstance (schema .get (key ), list ):
@@ -538,12 +550,6 @@ def canonicalish(schema: JSONType) -> Dict[str, Any]:
538550 if (not one_of ) or one_of .count (TRUTHY ) > 1 :
539551 return FALSEY
540552 schema ["oneOf" ] = one_of
541- # if/then/else schemas are ignored unless if and another are present
542- if "if" not in schema :
543- schema .pop ("then" , None )
544- schema .pop ("else" , None )
545- if "then" not in schema and "else" not in schema :
546- schema .pop ("if" , None )
547553 if schema .get ("uniqueItems" ) is False :
548554 del schema ["uniqueItems" ]
549555 return schema
@@ -761,8 +767,6 @@ def merged(schemas: List[Any]) -> Optional[Schema]:
761767 out ["not" ] = {"anyOf" : [out ["not" ], s .pop ("not" )]}
762768
763769 # TODO: merge `items` schemas or lists-of-schemas
764- # TODO: merge if/then/else schemas to the chained form
765- # or maybe canonicalise them to an anyOf instead?
766770 # TODO: merge dependencies
767771
768772 # This loop handles the remaining cases. Notably, we do not attempt to
@@ -772,6 +776,7 @@ def merged(schemas: List[Any]) -> Optional[Schema]:
772776 # - `$ref`; if not already resolved we can't do that here
773777 # - `anyOf`; due to product-like explosion in worst case
774778 # - `oneOf`; which we plan to handle as an anyOf-not composition
779+ # - `if`/`then`/`else`; which is removed by canonicalisation
775780 for k , v in s .items ():
776781 if k not in out :
777782 out [k ] = v
0 commit comments