@@ -1,4 +1,5 @@
1{-# OPTIONS_GHC -fno-warn-orphans #-}
1{-# OPTIONS_GHC -fno-warn-orphans #-}
2module OpenAPI.Checker.Validate.Schema
3module OpenAPI.Checker.Validate.Schema
3 ( JsonType (..)
4 ( JsonType (..)
4 , ForeachType (..)
5 , ForeachType (..)
@@ -10,7 +11,7 @@ module OpenAPI.Checker.Validate.Schema
10 , schemaToFormula
11 , schemaToFormula
11 , foldLattice
12 , foldLattice
15import Algebra.Lattice
16import Algebra.Lattice
16import Control.Applicative
17import Control.Applicative
@@ -23,9 +24,9 @@ import Control.Monad.Writer
23import qualified Data.Aeson as A
24import qualified Data.Aeson as A
24import Data.Coerce
25import Data.Coerce
25import qualified Data.Foldable as F
26import qualified Data.Foldable as F
26import qualified Data.HashMap.Strict as HM
28import qualified Data.HashMap.Strict as HM
27import qualified Data.HashMap.Strict.InsOrd as IOHM
29import qualified Data.HashMap.Strict.InsOrd as IOHM
29import Data.Int
30import Data.Int
30import Data.Kind
31import Data.Kind
31import qualified Data.List.NonEmpty as NE
32import qualified Data.List.NonEmpty as NE
@@ -38,15 +39,13 @@ import Data.Scientific
38import qualified Data.Set as S
39import qualified Data.Set as S
39import Data.Text (Text)
40import Data.Text (Text)
40import qualified Data.Text as T hiding (singleton)
41import qualified Data.Text as T hiding (singleton)
41−import qualified Data.Text.Encoding as T
42import Data.Typeable
42import Data.Typeable
43import OpenAPI.Checker.Behavior
43import OpenAPI.Checker.Behavior
44import OpenAPI.Checker.Orphans ()
44import OpenAPI.Checker.Orphans ()
45−import OpenAPI.Checker.References
46import OpenAPI.Checker.Paths
45import OpenAPI.Checker.Paths
47import qualified OpenAPI.Checker.PathsPrefixTree as P
46import qualified OpenAPI.Checker.PathsPrefixTree as P
47+import OpenAPI.Checker.References
48import OpenAPI.Checker.Subtree
48import OpenAPI.Checker.Subtree
51-- | Type of a JSON value
50-- | Type of a JSON value
52data JsonType
51data JsonType
@@ -68,7 +67,9 @@ data TypedValue :: JsonType -> Type where
68 TObject :: !A.Object -> TypedValue 'Object
67 TObject :: !A.Object -> TypedValue 'Object
70deriving stock instance Eq (TypedValue t)
69deriving stock instance Eq (TypedValue t)
71deriving stock instance Ord (TypedValue t)
71deriving stock instance Ord (TypedValue t)
72deriving stock instance Show (TypedValue t)
73deriving stock instance Show (TypedValue t)
74untypeValue :: TypedValue t -> A.Value
75untypeValue :: TypedValue t -> A.Value
@@ -100,8 +101,9 @@ data Property = Property
100data Condition :: JsonType -> Type where
101data Condition :: JsonType -> Type where
101 Exactly :: TypedValue t -> Condition t
102 Exactly :: TypedValue t -> Condition t
102 Maximum :: !(Bound Scientific) -> Condition 'Number
103 Maximum :: !(Bound Scientific) -> Condition 'Number
103− Minimum :: !(Down (Bound (Down Scientific))) -> Condition 'Number
105+ :: !(Down (Bound (Down Scientific)))
104− -- ^ this has the right Ord
106+ -> Condition 'Number -- ^ this has the right Ord
105 MultipleOf :: !Scientific -> Condition 'Number
107 MultipleOf :: !Scientific -> Condition 'Number
106 NumberFormat :: !Format -> Condition 'Number
108 NumberFormat :: !Format -> Condition 'Number
107 MaxLength :: !Integer -> Condition 'String
109 MaxLength :: !Integer -> Condition 'String
@@ -117,10 +119,8 @@ data Condition :: JsonType -> Type where
117 UniqueItems :: Condition 'Array
119 UniqueItems :: Condition 'Array
118 Properties
120 Properties
119 :: !(M.Map Text Property)
121 :: !(M.Map Text Property)
120− -> !(ForeachType JsonFormula)
121− -- ^ formula for additional properties
122+ -> !(ForeachType JsonFormula) -- ^ formula for additional properties
122− -> !(Maybe (Traced (Referenced Schema)))
123− -- ^ schema for additional properties, Nothing means bottom
123+ -> !(Maybe (Traced (Referenced Schema))) -- ^ schema for additional properties, Nothing means bottom
124 -> Condition 'Object
124 -> Condition 'Object
125 MaxProperties :: !Integer -> Condition 'Object
125 MaxProperties :: !Integer -> Condition 'Object
126 MinProperties :: !Integer -> Condition 'Object
126 MinProperties :: !Integer -> Condition 'Object
@@ -136,28 +136,34 @@ satisfiesTyped (TNumber n) (NumberFormat f) = checkNumberFormat f n
136satisfiesTyped (TString s) (MaxLength m) = fromIntegral (T.length s) <= m
136satisfiesTyped (TString s) (MaxLength m) = fromIntegral (T.length s) <= m
137satisfiesTyped (TString s) (MinLength m) = fromIntegral (T.length s) >= m
137satisfiesTyped (TString s) (MinLength m) = fromIntegral (T.length s) >= m
138satisfiesTyped (TString s) (Pattern p) = undefined s p -- TODO: regex stuff
138satisfiesTyped (TString s) (Pattern p) = undefined s p -- TODO: regex stuff
139−satisfiesTyped (TString s) (StringFormat f) = undefined s f-- TODO: string format
139+satisfiesTyped (TString s) (StringFormat f) = undefined s f -- TODO: string format
140satisfiesTyped (TArray a) (Items f _) = all (`satisfies` f) a
140satisfiesTyped (TArray a) (Items f _) = all (`satisfies` f) a
141satisfiesTyped (TArray a) (MaxItems m) = fromIntegral (F.length a) <= m
141satisfiesTyped (TArray a) (MaxItems m) = fromIntegral (F.length a) <= m
142satisfiesTyped (TArray a) (MinItems m) = fromIntegral (F.length a) >= m
142satisfiesTyped (TArray a) (MinItems m) = fromIntegral (F.length a) >= m
143satisfiesTyped (TArray a) UniqueItems = S.size (S.fromList $ F.toList a) == F.length a -- TODO: could be better
143satisfiesTyped (TArray a) UniqueItems = S.size (S.fromList $ F.toList a) == F.length a -- TODO: could be better
144−satisfiesTyped (TObject o) (Properties props additional _)
144+satisfiesTyped (TObject o) (Properties props additional _) =
145− = all (`HM.member` o) (M.keys (M.filter propRequired props))
145+ all (`HM.member` o) (M.keys (M.filter propRequired props))
146− && all (\(k, v) -> satisfies v $ maybe additional propFormula $ M.lookup k props) (HM.toList o)
146+ && all (\(k, v) -> satisfies v $ maybe additional propFormula $ M.lookup k props) (HM.toList o)
147satisfiesTyped (TObject o) (MaxProperties m) = fromIntegral (HM.size o) <= m
147satisfiesTyped (TObject o) (MaxProperties m) = fromIntegral (HM.size o) <= m
148satisfiesTyped (TObject o) (MinProperties m) = fromIntegral (HM.size o) >= m
148satisfiesTyped (TObject o) (MinProperties m) = fromIntegral (HM.size o) >= m
150checkNumberFormat :: Format -> Scientific -> Bool
150checkNumberFormat :: Format -> Scientific -> Bool
151−checkNumberFormat "int32" (toRational -> n) = denominator n == 1
151+checkNumberFormat "int32" (toRational -> n) =
152− && n >= toRational (minBound :: Int32) && n <= toRational (maxBound :: Int32)
153+ && n >= toRational (minBound :: Int32)
154+ && n <= toRational (maxBound :: Int32)
153−checkNumberFormat "int64" (toRational -> n) = denominator n == 1
155+checkNumberFormat "int64" (toRational -> n) =
154− && n >= toRational (minBound :: Int64) && n <= toRational (maxBound :: Int64)
157+ && n >= toRational (minBound :: Int64)
158+ && n <= toRational (maxBound :: Int64)
155checkNumberFormat "float" _n = True
159checkNumberFormat "float" _n = True
156checkNumberFormat "double" _n = True
160checkNumberFormat "double" _n = True
157checkNumberFormat f _n = error $ "Invalid number format: " <> T.unpack f
161checkNumberFormat f _n = error $ "Invalid number format: " <> T.unpack f
159deriving stock instance Eq (Condition t)
163deriving stock instance Eq (Condition t)
160deriving stock instance Ord (Condition t)
165deriving stock instance Ord (Condition t)
161deriving stock instance Show (Condition t)
167deriving stock instance Show (Condition t)
163data SomeCondition where
169data SomeCondition where
@@ -192,12 +198,15 @@ disjAdd (DNF yss) xs
193instance Lattice (JsonFormula t) where
199instance Lattice (JsonFormula t) where
194 xss \/ DNF yss = S.foldl' disjAdd xss yss
200 xss \/ DNF yss = S.foldl' disjAdd xss yss
201+ DNF xss /\ DNF yss =
195− DNF xss /\ DNF yss = F.foldl' disjAdd bottom $
202+ F.foldl' disjAdd bottom $
196− liftA2 S.union (S.toList xss) (S.toList yss)
203+ liftA2 S.union (S.toList xss) (S.toList yss)
198pattern BottomFormula :: JsonFormula t
205pattern BottomFormula :: JsonFormula t
199−pattern BottomFormula <- DNF (S.null -> True)
206+pattern BottomFormula <-
207+ DNF (S.null -> True)
200− where BottomFormula = DNF S.empty
209+ BottomFormula = DNF S.empty
202isSingleton :: S.Set a -> Maybe a
211isSingleton :: S.Set a -> Maybe a
203isSingleton s
212isSingleton s
@@ -205,17 +214,24 @@ isSingleton s
205 | otherwise = Nothing
214 | otherwise = Nothing
207pattern Conjunct :: [Condition t] -> S.Set (Condition t)
216pattern Conjunct :: [Condition t] -> S.Set (Condition t)
208−pattern Conjunct xs <- (S.toList -> xs)
217+pattern Conjunct xs <-
209− where Conjunct = S.fromList
220+ Conjunct = S.fromList
210{-# COMPLETE Conjunct #-}
222{-# COMPLETE Conjunct #-}
212pattern SingleConjunct :: [Condition t] -> JsonFormula t
224pattern SingleConjunct :: [Condition t] -> JsonFormula t
225+pattern SingleConjunct xs <-
213−pattern SingleConjunct xs <- DNF (isSingleton -> Just (Conjunct xs))
226+ DNF (isSingleton -> Just (Conjunct xs))
214− where SingleConjunct xs = DNF $ S.singleton $ Conjunct xs
228+ SingleConjunct xs = DNF $ S.singleton $ Conjunct xs
216pattern TopFormula :: JsonFormula t
230pattern TopFormula :: JsonFormula t
231+pattern TopFormula <-
217−pattern TopFormula <- DNF (isSingleton -> Just (S.null -> True))
232+ DNF (isSingleton -> Just (S.null -> True))
218− where TopFormula = DNF $ S.singleton S.empty
234+ TopFormula = DNF $ S.singleton S.empty
220instance BoundedJoinSemiLattice (JsonFormula t) where
236instance BoundedJoinSemiLattice (JsonFormula t) where
221 bottom = BottomFormula
237 bottom = BottomFormula
@@ -228,8 +244,12 @@ foldLattice
228 => (Condition t -> l)
244 => (Condition t -> l)
229 -> JsonFormula t
245 -> JsonFormula t
231−foldLattice f (DNF xss) = S.foldl' (\z w ->
247+foldLattice f (DNF xss) =
232− z \/ S.foldl' (\x y -> x /\ f y) top w) bottom xss
250+ z \/ S.foldl' (\x y -> x /\ f y) top w)
234satisfiesFormula :: TypedValue t -> JsonFormula t -> Bool
254satisfiesFormula :: TypedValue t -> JsonFormula t -> Bool
235satisfiesFormula val = foldLattice (satisfiesTyped val)
255satisfiesFormula val = foldLattice (satisfiesTyped val)
@@ -253,7 +273,9 @@ satisfies val p = case val of
253 A.Object o -> satisfiesFormula (TObject o) $ forObject p
273 A.Object o -> satisfiesFormula (TObject o) $ forObject p
255deriving stock instance (forall x. Typeable x => Eq (f x)) => Eq (ForeachType f)
275deriving stock instance (forall x. Typeable x => Eq (f x)) => Eq (ForeachType f)
256deriving stock instance (forall x. Typeable x => Ord (f x)) => Ord (ForeachType f)
277deriving stock instance (forall x. Typeable x => Ord (f x)) => Ord (ForeachType f)
257deriving stock instance (forall x. Typeable x => Show (f x)) => Show (ForeachType f)
279deriving stock instance (forall x. Typeable x => Show (f x)) => Show (ForeachType f)
@@ -261,12 +283,12 @@ foldType
261 => (forall x. Typeable x => JsonType -> (ForeachType f -> f x) -> m)
283 => (forall x. Typeable x => JsonType -> (ForeachType f -> f x) -> m)
263foldType k =
285foldType k =
264− k Null forNull <>
286+ k Null forNull
265− k Boolean forBoolean <>
287+ <> k Boolean forBoolean
266− k Number forNumber <>
288+ <> k Number forNumber
267− k String forString <>
289+ <> k String forString
268− k Array forArray <>
290+ <> k Array forArray
269− k Object forObject
291+ <> k Object forObject
272 :: Applicative m
294 :: Applicative m
@@ -282,44 +304,52 @@ forType_ k = do
284instance (forall x. Lattice (f x)) => Lattice (ForeachType f) where
306instance (forall x. Lattice (f x)) => Lattice (ForeachType f) where
285− f1 \/ f2 = ForeachType
307+ f1 \/ f2 =
286− { forNull = forNull f1 \/ forNull f2
309+ { forNull = forNull f1 \/ forNull f2
287− , forBoolean = forBoolean f1 \/ forBoolean f2
310+ , forBoolean = forBoolean f1 \/ forBoolean f2
288− , forNumber = forNumber f1 \/ forNumber f2
311+ , forNumber = forNumber f1 \/ forNumber f2
289− , forString = forString f1 \/ forString f2
312+ , forString = forString f1 \/ forString f2
290− , forArray = forArray f1 \/ forArray f2
313+ , forArray = forArray f1 \/ forArray f2
291− , forObject = forObject f1 \/ forObject f2
314+ , forObject = forObject f1 \/ forObject f2
293− f1 /\ f2 = ForeachType
317+ ForeachType
294− { forNull = forNull f1 /\ forNull f2
318+ { forNull = forNull f1 /\ forNull f2
295− , forBoolean = forBoolean f1 /\ forBoolean f2
319+ , forBoolean = forBoolean f1 /\ forBoolean f2
296− , forNumber = forNumber f1 /\ forNumber f2
320+ , forNumber = forNumber f1 /\ forNumber f2
297− , forString = forString f1 /\ forString f2
321+ , forString = forString f1 /\ forString f2
298− , forArray = forArray f1 /\ forArray f2
322+ , forArray = forArray f1 /\ forArray f2
299− , forObject = forObject f1 /\ forObject f2
323+ , forObject = forObject f1 /\ forObject f2
302−instance (forall x. BoundedJoinSemiLattice (f x))
327+ (forall x. BoundedJoinSemiLattice (f x))
303− => BoundedJoinSemiLattice (ForeachType f) where
328+ => BoundedJoinSemiLattice (ForeachType f)
304− bottom = ForeachType
330+ bottom =
305− { forNull = bottom
332+ { forNull = bottom
306− , forBoolean = bottom
333+ , forBoolean = bottom
307− , forNumber = bottom
334+ , forNumber = bottom
308− , forString = bottom
335+ , forString = bottom
309− , forArray = bottom
336+ , forArray = bottom
310− , forObject = bottom
337+ , forObject = bottom
313−instance (forall x. BoundedMeetSemiLattice (f x))
341+ (forall x. BoundedMeetSemiLattice (f x))
314− => BoundedMeetSemiLattice (ForeachType f) where
342+ => BoundedMeetSemiLattice (ForeachType f)
315− top = ForeachType
345+ ForeachType
316− { forNull = top
346+ { forNull = top
317− , forBoolean = top
347+ , forBoolean = top
318− , forNumber = top
348+ , forNumber = top
319− , forString = top
349+ , forString = top
320− , forArray = top
350+ , forArray = top
321− , forObject = top
351+ , forObject = top
324{- TODO: remove
354{- TODO: remove
325instance Typeable t => Steppable Schema (Condition t) where
355instance Typeable t => Steppable Schema (Condition t) where
@@ -356,9 +386,26 @@ instance Steppable Schema (Referenced Schema) where
356 | ItemsObjectStep
386 | ItemsObjectStep
357 | ItemsArrayStep Int
387 | ItemsArrayStep Int
358 | AdditionalPropertiesStep
388 | AdditionalPropertiesStep
359− | PropertiesStep Text
389+ | NotStep
390+ deriving (Eq, Ord, Show)
392+instance Steppable Schema (Definitions (Referenced Schema)) where
393+ data Step Schema (Definitions (Referenced Schema)) = PropertiesStep
394+ deriving (Eq, Ord, Show)
396+instance Steppable Schema Discriminator where
397+ data Step Schema Discriminator = DiscriminatorStep
398+ deriving (Eq, Ord, Show)
400+instance Steppable Discriminator (Definitions (Referenced Schema)) where
401+ data Step Discriminator (Definitions (Referenced Schema)) = DiscriminatorMapping
360 deriving (Eq, Ord, Show)
402 deriving (Eq, Ord, Show)
404+parseDiscriminatorValue :: Text -> Referenced Schema
405+parseDiscriminatorValue v = case A.fromJSON @(Referenced Schema) $ A.object ["$ref" A..= v] of
407+ A.Error _ -> Ref $ Reference v
362type ProcessM = ReaderT (Traced (Definitions Schema)) (Writer (P.PathsPrefixTree Behave AnIssue 'SchemaLevel))
409type ProcessM = ReaderT (Traced (Definitions Schema)) (Writer (P.PathsPrefixTree Behave AnIssue 'SchemaLevel))
364warn :: Issue 'SchemaLevel -> ProcessM ()
411warn :: Issue 'SchemaLevel -> ProcessM ()
@@ -372,31 +419,42 @@ processRefSchema x = do
372 processSchema $ dereference defs x
419 processSchema $ dereference defs x
374tracedAllOf :: Traced Schema -> Maybe [Traced (Referenced Schema)]
421tracedAllOf :: Traced Schema -> Maybe [Traced (Referenced Schema)]
375−tracedAllOf sch = _schemaAllOf (extract sch) <&> \xs ->
423+ _schemaAllOf (extract sch) <&> \xs ->
376− [ traced (ask sch >>> step (AllOfStep i)) x | (i, x) <- zip [0..] xs ]
424+ [traced (ask sch >>> step (AllOfStep i)) x | (i, x) <- zip [0 ..] xs]
378tracedAnyOf :: Traced Schema -> Maybe [Traced (Referenced Schema)]
426tracedAnyOf :: Traced Schema -> Maybe [Traced (Referenced Schema)]
379−tracedAnyOf sch = _schemaAnyOf (extract sch) <&> \xs ->
428+ _schemaAnyOf (extract sch) <&> \xs ->
380− [ traced (ask sch >>> step (AnyOfStep i)) x | (i, x) <- zip [0..] xs ]
429+ [traced (ask sch >>> step (AnyOfStep i)) x | (i, x) <- zip [0 ..] xs]
382tracedOneOf :: Traced Schema -> Maybe [Traced (Referenced Schema)]
431tracedOneOf :: Traced Schema -> Maybe [Traced (Referenced Schema)]
383−tracedOneOf sch = _schemaOneOf (extract sch) <&> \xs ->
433+ _schemaOneOf (extract sch) <&> \xs ->
384− [ traced (ask sch >>> step (OneOfStep i)) x | (i, x) <- zip [0..] xs ]
434+ [traced (ask sch >>> step (OneOfStep i)) x | (i, x) <- zip [0 ..] xs]
386tracedItems :: Traced Schema -> Maybe (Either (Traced (Referenced Schema)) [Traced (Referenced Schema)])
436tracedItems :: Traced Schema -> Maybe (Either (Traced (Referenced Schema)) [Traced (Referenced Schema)])
387−tracedItems sch = _schemaItems (extract sch) <&> \case
438+ _schemaItems (extract sch) <&> \case
388− OpenApiItemsObject x -> Left $ traced (ask sch >>> step ItemsObjectStep) x
439+ OpenApiItemsObject x -> Left $ traced (ask sch >>> step ItemsObjectStep) x
389− OpenApiItemsArray xs -> Right
440+ OpenApiItemsArray xs ->
390− [ traced (ask sch >>> step (ItemsArrayStep i)) x | (i, x) <- zip [0..] xs ]
442+ [traced (ask sch >>> step (ItemsArrayStep i)) x | (i, x) <- zip [0 ..] xs]
392tracedAdditionalProperties :: Traced Schema -> Maybe (Either Bool (Traced (Referenced Schema)))
444tracedAdditionalProperties :: Traced Schema -> Maybe (Either Bool (Traced (Referenced Schema)))
445+tracedAdditionalProperties sch =
393−tracedAdditionalProperties sch = _schemaAdditionalProperties (extract sch) <&> \case
446+ _schemaAdditionalProperties (extract sch) <&> \case
394− AdditionalPropertiesAllowed b -> Left b
447+ AdditionalPropertiesAllowed b -> Left b
395− AdditionalPropertiesSchema x -> Right $ traced (ask sch >>> step AdditionalPropertiesStep) x
448+ AdditionalPropertiesSchema x -> Right $ traced (ask sch >>> step AdditionalPropertiesStep) x
450+tracedDiscriminator :: Traced Schema -> Maybe (Traced Discriminator)
451+tracedDiscriminator = sequence . stepTraced DiscriminatorStep . fmap _schemaDiscriminator
397tracedProperties :: Traced Schema -> IOHM.InsOrdHashMap Text (Traced (Referenced Schema))
453tracedProperties :: Traced Schema -> IOHM.InsOrdHashMap Text (Traced (Referenced Schema))
454+tracedProperties sch =
398−tracedProperties sch = IOHM.mapWithKey (\k -> traced (ask sch >>> step (PropertiesStep k)))
456+ (\k -> traced (ask sch >>> step PropertiesStep >>> step (InsOrdHashMapKeyStep k)))
399− $ _schemaProperties $ extract sch
457+ (_schemaProperties $ extract sch)
401-- | Turn a schema into a tuple of 'JsonFormula's that describes the condition
459-- | Turn a schema into a tuple of 'JsonFormula's that describes the condition
402-- for every possible type of a JSON value. The conditions are independent, and
460-- for every possible type of a JSON value. The conditions are independent, and
@@ -404,10 +462,9 @@ tracedProperties sch = IOHM.mapWithKey (\k -> traced (ask sch >>> step (Properti
404processSchema
462processSchema
405 :: Traced Schema
463 :: Traced Schema
406 -> ProcessM (ForeachType JsonFormula)
464 -> ProcessM (ForeachType JsonFormula)
407−processSchema sch@(extract -> Schema{..}) = do
465+processSchema sch@(extract -> Schema {..}) = do
409− singletonFormula :: Condition t -> JsonFormula t
466+ let singletonFormula :: Condition t -> JsonFormula t
410− singletonFormula f = SingleConjunct [f]
467+ singletonFormula f = SingleConjunct [f]
412 allClauses <- case tracedAllOf sch of
469 allClauses <- case tracedAllOf sch of
413 Nothing -> pure []
470 Nothing -> pure []
@@ -432,110 +489,160 @@ processSchema sch@(extract -> Schema{..}) = do
432 Nothing -> pure ()
489 Nothing -> pure ()
433 Just _ -> warn (NotSupported "not clause is unsupported")
490 Just _ -> warn (NotSupported "not clause is unsupported")
436− typeClause = case _schemaType of
492+ let typeClause = case _schemaType of
437− Nothing -> top
493+ Nothing -> top
438− Just OpenApiNull -> bottom
494+ Just OpenApiNull ->
439− { forNull = top }
496+ { forNull = top
440− Just OpenApiBoolean -> bottom
498+ Just OpenApiBoolean ->
441− { forBoolean = top }
500+ { forBoolean = top
442− Just OpenApiNumber -> bottom
502+ Just OpenApiNumber ->
443− { forBoolean = top }
504+ { forBoolean = top
444− Just OpenApiInteger -> bottom
506+ Just OpenApiInteger ->
445− { forNumber = singletonFormula $ MultipleOf 1 }
508+ { forNumber = singletonFormula $ MultipleOf 1
446− Just OpenApiString -> bottom
510+ Just OpenApiString ->
447− { forString = top }
512+ { forString = top
448− Just OpenApiArray -> bottom
514+ Just OpenApiArray ->
449− { forArray = top }
516+ { forArray = top
450− Just OpenApiObject -> bottom
518+ Just OpenApiObject ->
451− { forObject = top }
520+ { forObject = top
454− valueEnum A.Null = bottom
523+ let valueEnum A.Null =
455− { forNull = singletonFormula $ Exactly TNull }
525+ { forNull = singletonFormula $ Exactly TNull
456− valueEnum (A.Bool b) = bottom
527+ valueEnum (A.Bool b) =
457− { forBoolean = singletonFormula $ Exactly $ TBool b }
529+ { forBoolean = singletonFormula $ Exactly $ TBool b
458− valueEnum (A.Number n) = bottom
531+ valueEnum (A.Number n) =
459− { forNumber = singletonFormula $ Exactly $ TNumber n }
533+ { forNumber = singletonFormula $ Exactly $ TNumber n
460− valueEnum (A.String s) = bottom
535+ valueEnum (A.String s) =
461− { forString = singletonFormula $ Exactly $ TString s }
537+ { forString = singletonFormula $ Exactly $ TString s
462− valueEnum (A.Array a) = bottom
539+ valueEnum (A.Array a) =
463− { forArray = singletonFormula $ Exactly $ TArray a }
541+ { forArray = singletonFormula $ Exactly $ TArray a
464− valueEnum (A.Object o) = bottom
543+ valueEnum (A.Object o) =
465− { forObject = singletonFormula $ Exactly $ TObject o }
545+ { forObject = singletonFormula $ Exactly $ TObject o
466 enumClause <- case _schemaEnum of
547 enumClause <- case _schemaEnum of
467 Nothing -> pure top
548 Nothing -> pure top
468 Just [] -> bottom <$ warn (InvalidSchema "no items in enum")
549 Just [] -> bottom <$ warn (InvalidSchema "no items in enum")
469 Just xs -> pure $ joins (valueEnum <$> xs)
550 Just xs -> pure $ joins (valueEnum <$> xs)
472− maximumClause = case _schemaMaximum of
552+ let maximumClause = case _schemaMaximum of
473− Nothing -> top
553+ Nothing -> top
474− Just n -> top
554+ Just n ->
475− { forNumber = singletonFormula $ Maximum $
556+ { forNumber = singletonFormula $
476− case _schemaExclusiveMaximum of
558+ case _schemaExclusiveMaximum of
477− Just True -> Exclusive n
559+ Just True -> Exclusive n
478− _ -> Inclusive n }
560+ _ -> Inclusive n
480− minimumClause = case _schemaMinimum of
563+ minimumClause = case _schemaMinimum of
481− Nothing -> top
564+ Nothing -> top
482− Just n -> top
565+ Just n ->
483− { forNumber = singletonFormula $ Minimum $ Down $
567+ { forNumber = singletonFormula $
484− case _schemaExclusiveMinimum of
570+ case _schemaExclusiveMinimum of
485− Just True -> Exclusive $ Down n
571+ Just True -> Exclusive $ Down n
486− _ -> Inclusive $ Down n }
572+ _ -> Inclusive $ Down n
488− multipleOfClause = case _schemaMultipleOf of
575+ multipleOfClause = case _schemaMultipleOf of
489− Nothing -> top
576+ Nothing -> top
490− Just n -> top
577+ Just n ->
491− { forNumber = singletonFormula $ MultipleOf n }
579+ { forNumber = singletonFormula $ MultipleOf n
493 formatClause <- case _schemaFormat of
582 formatClause <- case _schemaFormat of
494 Nothing -> pure top
583 Nothing -> pure top
495− Just f | f `elem` ["int32", "int64", "float", "double"] -> pure top
585+ | f `elem` ["int32", "int64", "float", "double"] ->
496− { forNumber = singletonFormula $ NumberFormat f }
588+ { forNumber = singletonFormula $ NumberFormat f
497− Just f | f `elem` ["byte", "binary", "date", "date-time", "password"] -> pure top
591+ | f `elem` ["byte", "binary", "date", "date-time", "password"] ->
498− { forString = singletonFormula $ StringFormat f }
594+ { forString = singletonFormula $ StringFormat f
499 Just f -> top <$ warn (NotSupported $ "Unknown format: " <> f)
596 Just f -> top <$ warn (NotSupported $ "Unknown format: " <> f)
502− maxLengthClause = case _schemaMaxLength of
598+ let maxLengthClause = case _schemaMaxLength of
503− Nothing -> top
599+ Nothing -> top
504− Just n -> top
600+ Just n ->
505− { forString = singletonFormula $ MaxLength n }
602+ { forString = singletonFormula $ MaxLength n
507− minLengthClause = case _schemaMinLength of
605+ minLengthClause = case _schemaMinLength of
508− Nothing -> top
606+ Nothing -> top
509− Just n -> top
607+ Just n ->
510− { forString = singletonFormula $ MinLength n }
609+ { forString = singletonFormula $ MinLength n
512− patternClause = case _schemaPattern of
612+ patternClause = case _schemaPattern of
513− Nothing -> top
613+ Nothing -> top
514− Just p -> top
614+ Just p ->
515− { forString = singletonFormula $ Pattern p }
616+ { forString = singletonFormula $ Pattern p
517 itemsClause <- case tracedItems sch of
619 itemsClause <- case tracedItems sch of
518 Nothing -> pure top
620 Nothing -> pure top
519 Just (Left rs) -> do
621 Just (Left rs) -> do
520 f <- processRefSchema rs
622 f <- processRefSchema rs
521− pure top { forArray = singletonFormula $ Items f rs }
623+ pure top {forArray = singletonFormula $ Items f rs}
522 Just (Right _) -> top <$ warn (NotSupported "array in items is not supported")
624 Just (Right _) -> top <$ warn (NotSupported "array in items is not supported")
525− maxItemsClause = case _schemaMaxItems of
626+ let maxItemsClause = case _schemaMaxItems of
526− Nothing -> top
627+ Nothing -> top
527− Just n -> top
628+ Just n ->
528− { forArray = singletonFormula $ MaxItems n }
630+ { forArray = singletonFormula $ MaxItems n
530− minItemsClause = case _schemaMinItems of
633+ minItemsClause = case _schemaMinItems of
531− Nothing -> top
634+ Nothing -> top
532− Just n -> top
635+ Just n ->
533− { forArray = singletonFormula $ MinItems n }
637+ { forArray = singletonFormula $ MinItems n
535− uniqueItemsClause = case _schemaUniqueItems of
640+ uniqueItemsClause = case _schemaUniqueItems of
536− Just True -> top
641+ Just True ->
537− { forArray = singletonFormula UniqueItems }
643+ { forArray = singletonFormula UniqueItems
538− _ -> top
645+ _ -> top
540 (addProps, addPropSchema) <- case tracedAdditionalProperties sch of
647 (addProps, addPropSchema) <- case tracedAdditionalProperties sch of
541 Just (Right rs) -> (,Just rs) <$> processRefSchema rs
648 Just (Right rs) -> (,Just rs) <$> processRefSchema rs
@@ -544,50 +651,79 @@ processSchema sch@(extract -> Schema{..}) = do
544 propList <- forM (S.toList . S.fromList $ IOHM.keys _schemaProperties <> _schemaRequired) $ \k -> do
651 propList <- forM (S.toList . S.fromList $ IOHM.keys _schemaProperties <> _schemaRequired) $ \k -> do
545 (f, psch) <- case IOHM.lookup k $ tracedProperties sch of
652 (f, psch) <- case IOHM.lookup k $ tracedProperties sch of
546 Just rs -> (,rs) <$> processRefSchema rs
653 Just rs -> (,rs) <$> processRefSchema rs
547− Nothing -> let fakeSchema = traced (ask sch `Snoc` AdditionalPropertiesStep) $ Inline mempty
655+ let fakeSchema = traced (ask sch `Snoc` AdditionalPropertiesStep) $ Inline mempty
548− -- The mempty here is incorrect, but if addPropSchema was Nothing, then
656+ in -- The mempty here is incorrect, but if addPropSchema was Nothing, then
549− -- addProps is bottom, and k is in _schemaRequired. We handle this situation
657+ -- addProps is bottom, and k is in _schemaRequired. We handle this situation
550− -- below and short-circuit the entire Properties condition to bottom
658+ -- below and short-circuit the entire Properties condition to bottom
551− in pure (addProps, fromMaybe fakeSchema addPropSchema)
659+ pure (addProps, fromMaybe fakeSchema addPropSchema)
552 pure (k, Property (k `elem` _schemaRequired) f psch)
660 pure (k, Property (k `elem` _schemaRequired) f psch)
553− let
661+ let allBottom f = getAll $
554− allBottom f = getAll $ foldType $ \_ ty -> case ty f of
662+ foldType $ \_ ty -> case ty f of
555− BottomFormula -> All True
663+ BottomFormula -> All True
556− _ -> All False
664+ _ -> All False
557− allTop f = getAll $ foldType $ \_ ty -> case ty f of
666+ foldType $ \_ ty -> case ty f of
558− TopFormula -> All True
667+ TopFormula -> All True
559− _ -> All False
668+ _ -> All False
560− -- remove optional fields whose schemata match that of additional props
669+ -- remove optional fields whose schemata match that of additional props
561− propMap = M.filter (\p -> propRequired p || propFormula p /= addProps) $ M.fromList propList
670+ propMap = M.filter (\p -> propRequired p || propFormula p /= addProps) $ M.fromList propList
562− propertiesClause
671+ propertiesClause
563− | any (\p -> propRequired p && allBottom (propFormula p)) propMap
672+ | any (\p -> propRequired p && allBottom (propFormula p)) propMap =
564− = bottom -- if any required field has unsatisfiable schema
673+ bottom -- if any required field has unsatisfiable schema
565− | M.null propMap, allTop addProps
675+ , allTop addProps =
566− = top -- if all fields are optional and have trivial schemata
676+ top -- if all fields are optional and have trivial schemata
567− | otherwise
677+ | otherwise =
569− { forObject = singletonFormula $ Properties propMap addProps addPropSchema }
679+ { forObject = singletonFormula $ Properties propMap addProps addPropSchema
571− maxPropertiesClause = case _schemaMaxProperties of
682+ maxPropertiesClause = case _schemaMaxProperties of
572− Nothing -> top
683+ Nothing -> top
573− Just n -> top
684+ Just n ->
574− { forObject = singletonFormula $ MaxProperties n }
686+ { forObject = singletonFormula $ MaxProperties n
576− minPropertiesClause = case _schemaMinProperties of
689+ minPropertiesClause = case _schemaMinProperties of
577− Nothing -> top
690+ Nothing -> top
578− Just n -> top
691+ Just n ->
579− { forObject = singletonFormula $ MinProperties n }
693+ { forObject = singletonFormula $ MinProperties n
697+ | Just True <- _schemaNullable =
699+ { forNull = singletonFormula $ Exactly TNull
701+ | otherwise = bottom
581 nullableClause
704 nullableClause
582− | Just True <- _schemaNullable = bottom
705+ \/ meets
583− { forNull = singletonFormula $ Exactly TNull }
584− | otherwise = bottom
586− pure $ nullableClause \/ meets (allClauses <>
706+ (allClauses
587− [ anyClause, oneClause, typeClause, enumClause, maximumClause, minimumClause
707+ <> [ anyClause
588− , multipleOfClause, formatClause, maxLengthClause, minLengthClause
713+ , multipleOfClause
589− , patternClause, itemsClause, maxItemsClause, minItemsClause
719+ , maxItemsClause
590− , uniqueItemsClause, propertiesClause, maxPropertiesClause, minPropertiesClause])
723+ , maxPropertiesClause
724+ , minPropertiesClause
591{- TODO: ReadOnly/WriteOnly -}
727{- TODO: ReadOnly/WriteOnly -}
593checkOneOfDisjoint :: [Traced (Referenced Schema)] -> ProcessM Bool
729checkOneOfDisjoint :: [Traced (Referenced Schema)] -> ProcessM Bool
@@ -607,7 +743,7 @@ checkFormulas
607 -> SemanticCompatFormula ()
743 -> SemanticCompatFormula ()
608checkFormulas env beh (ProdCons (fp, ep) (fc, ec)) =
744checkFormulas env beh (ProdCons (fp, ep) (fc, ec)) =
609 case P.toList ep ++ P.toList ec of
745 case P.toList ep ++ P.toList ec of
610− issues@(_:_) -> F.for_ issues $ \(AnItem t (AnIssue e)) -> issueAt (beh >>> t) e
746+ issues@(_ : _) -> F.for_ issues $ \(AnItem t (AnIssue e)) -> issueAt (beh >>> t) e
612 -- We have the following isomorphisms:
748 -- We have the following isomorphisms:
613 -- (A ⊂ X ∪ Y) = (A ⊂ X) \/ (A ⊂ Y)
749 -- (A ⊂ X ∪ Y) = (A ⊂ X) \/ (A ⊂ Y)
@@ -643,7 +779,9 @@ checkFormulas env beh (ProdCons (fp, ep) (fc, ec)) =
643 (DNF pss, SingleConjunct cs) -> F.for_ pss $ \(Conjunct ps) -> do
779 (DNF pss, SingleConjunct cs) -> F.for_ pss $ \(Conjunct ps) -> do
644 F.for_ cs $ checkImplication env beh' ps -- avoid disjuntion if there's only one conjunct
780 F.for_ cs $ checkImplication env beh' ps -- avoid disjuntion if there's only one conjunct
645 (DNF pss, DNF css) -> F.for_ pss $ \(Conjunct ps) -> do
781 (DNF pss, DNF css) -> F.for_ pss $ \(Conjunct ps) -> do
646− anyOfAt beh' (NoMatchingCondition $ SomeCondition <$> ps)
784+ (NoMatchingCondition $ SomeCondition <$> ps)
647 [F.for_ cs $ checkImplication env beh' ps | Conjunct cs <- S.toList css]
785 [F.for_ cs $ checkImplication env beh' ps | Conjunct cs <- S.toList css]
649checkContradiction
787checkContradiction
@@ -662,54 +800,77 @@ checkImplication
662checkImplication env beh prods cons = case findExactly prods of
800checkImplication env beh prods cons = case findExactly prods of
664 | all (satisfiesTyped e) prods ->
802 | all (satisfiesTyped e) prods ->
665− if satisfiesTyped e cons then pure ()
803+ if satisfiesTyped e cons
666 else issueAt beh (EnumDoesntSatisfy $ untypeValue e)
805 else issueAt beh (EnumDoesntSatisfy $ untypeValue e)
667 | otherwise -> pure () -- vacuously true
806 | otherwise -> pure () -- vacuously true
668 Nothing -> case cons of
807 Nothing -> case cons of
669 -- the above code didn't catch it, so there's no Exactly condition on the lhs
808 -- the above code didn't catch it, so there's no Exactly condition on the lhs
670 Exactly e -> issueAt beh (NoMatchingEnum $ untypeValue e)
809 Exactly e -> issueAt beh (NoMatchingEnum $ untypeValue e)
671 Maximum m -> case findRelevant min (\case Maximum m' -> Just m'; _ -> Nothing) prods of
810 Maximum m -> case findRelevant min (\case Maximum m' -> Just m'; _ -> Nothing) prods of
672− Just m' -> if m' <= m then pure ()
813+ then pure ()
673− else issueAt beh (MatchingMaximumWeak m m')
814+ else issueAt beh (MatchingMaximumWeak m m')
674 Nothing -> issueAt beh (NoMatchingMaximum m)
815 Nothing -> issueAt beh (NoMatchingMaximum m)
675 Minimum m -> case findRelevant max (\case Minimum m' -> Just m'; _ -> Nothing) prods of
816 Minimum m -> case findRelevant max (\case Minimum m' -> Just m'; _ -> Nothing) prods of
676− Just m' -> if m' >= m then pure ()
819+ then pure ()
677− else issueAt beh (MatchingMinimumWeak (coerce m) (coerce m'))
820+ else issueAt beh (MatchingMinimumWeak (coerce m) (coerce m'))
678 Nothing -> issueAt beh (NoMatchingMinimum (coerce m))
821 Nothing -> issueAt beh (NoMatchingMinimum (coerce m))
679 MultipleOf m -> case findRelevant lcmScientific (\case MultipleOf m' -> Just m'; _ -> Nothing) prods of
822 MultipleOf m -> case findRelevant lcmScientific (\case MultipleOf m' -> Just m'; _ -> Nothing) prods of
680− Just m' -> if lcmScientific m m' == m' then pure ()
824+ if lcmScientific m m' == m'
681− else issueAt beh (MatchingMultipleOfWeak m m')
826+ else issueAt beh (MatchingMultipleOfWeak m m')
682 Nothing -> issueAt beh (NoMatchingMultipleOf m)
827 Nothing -> issueAt beh (NoMatchingMultipleOf m)
683− NumberFormat f -> if any (\case NumberFormat f' -> f == f'; _ -> False) prods
829+ if any (\case NumberFormat f' -> f == f'; _ -> False) prods
684− then pure () else issueAt beh (NoMatchingFormat f)
831+ else issueAt beh (NoMatchingFormat f)
685 MaxLength m -> case findRelevant min (\case MaxLength m' -> Just m'; _ -> Nothing) prods of
832 MaxLength m -> case findRelevant min (\case MaxLength m' -> Just m'; _ -> Nothing) prods of
686− Just m' -> if m' <= m then pure ()
835+ then pure ()
687− else issueAt beh (MatchingMaxLengthWeak m m')
836+ else issueAt beh (MatchingMaxLengthWeak m m')
688 Nothing -> issueAt beh (NoMatchingMaxLength m)
837 Nothing -> issueAt beh (NoMatchingMaxLength m)
689 MinLength m -> case findRelevant max (\case MinLength m' -> Just m'; _ -> Nothing) prods of
838 MinLength m -> case findRelevant max (\case MinLength m' -> Just m'; _ -> Nothing) prods of
690− Just m' -> if m' >= m then pure ()
841+ then pure ()
691− else issueAt beh (MatchingMinLengthWeak m m')
842+ else issueAt beh (MatchingMinLengthWeak m m')
692 Nothing -> issueAt beh (NoMatchingMinLength m)
843 Nothing -> issueAt beh (NoMatchingMinLength m)
693− Pattern p -> if any (\case Pattern p' -> p == p'; _ -> False) prods
845+ if any (\case Pattern p' -> p == p'; _ -> False) prods
694− then pure () else issueAt beh (NoMatchingPattern p) -- TODO: regex comparison
847+ else issueAt beh (NoMatchingPattern p) -- TODO: regex comparison
695− StringFormat f -> if any (\case StringFormat f' -> f == f'; _ -> False) prods
849+ if any (\case StringFormat f' -> f == f'; _ -> False) prods
696− then pure () else issueAt beh (NoMatchingFormat f)
851+ else issueAt beh (NoMatchingFormat f)
697 Items _ cons' -> case findRelevant (<>) (\case Items _ rs -> Just (rs NE.:| []); _ -> Nothing) prods of
852 Items _ cons' -> case findRelevant (<>) (\case Items _ rs -> Just (rs NE.:| []); _ -> Nothing) prods of
698 Just (rs NE.:| []) -> checkCompatibility env (beh >>> step InItems) $ ProdCons rs cons'
853 Just (rs NE.:| []) -> checkCompatibility env (beh >>> step InItems) $ ProdCons rs cons'
699 Just rs -> do
854 Just rs -> do
700− let sch = Inline mempty { _schemaAllOf = Just . NE.toList $ extract <$> rs }
855+ let sch = Inline mempty {_schemaAllOf = Just . NE.toList $ extract <$> rs}
701 checkCompatibility env (beh >>> step InItems) $ ProdCons (traced (ask $ NE.head rs) sch) cons' -- TODO: bad trace
856 checkCompatibility env (beh >>> step InItems) $ ProdCons (traced (ask $ NE.head rs) sch) cons' -- TODO: bad trace
702 Nothing -> issueAt beh NoMatchingItems
857 Nothing -> issueAt beh NoMatchingItems
703 MaxItems m -> case findRelevant min (\case MaxItems m' -> Just m'; _ -> Nothing) prods of
858 MaxItems m -> case findRelevant min (\case MaxItems m' -> Just m'; _ -> Nothing) prods of
704− Just m' -> if m' <= m then pure ()
861+ then pure ()
705− else issueAt beh (MatchingMaxItemsWeak m m')
862+ else issueAt beh (MatchingMaxItemsWeak m m')
706 Nothing -> issueAt beh (NoMatchingMaxItems m)
863 Nothing -> issueAt beh (NoMatchingMaxItems m)
707 MinItems m -> case findRelevant max (\case MinItems m' -> Just m'; _ -> Nothing) prods of
864 MinItems m -> case findRelevant max (\case MinItems m' -> Just m'; _ -> Nothing) prods of
708− Just m' -> if m' >= m then pure ()
867+ then pure ()
709− else issueAt beh (MatchingMinItemsWeak m m')
868+ else issueAt beh (MatchingMinItemsWeak m m')
710 Nothing -> issueAt beh (NoMatchingMinItems m)
869 Nothing -> issueAt beh (NoMatchingMinItems m)
711− UniqueItems -> if any (== UniqueItems) $ prods then pure ()
871+ if any (== UniqueItems) $ prods
712− else issueAt beh NoMatchingUniqueItems
873+ else issueAt beh NoMatchingUniqueItems
713 Properties props _ madd -> case findRelevant (<>) (\case Properties props' _ madd' -> Just $ (props', madd') NE.:| []; _ -> Nothing) prods of
874 Properties props _ madd -> case findRelevant (<>) (\case Properties props' _ madd' -> Just $ (props', madd') NE.:| []; _ -> Nothing) prods of
714 Just ((props', madd') NE.:| []) -> do
875 Just ((props', madd') NE.:| []) -> do
715 F.for_ (S.fromList $ M.keys props <> M.keys props') $ \k -> do
876 F.for_ (S.fromList $ M.keys props <> M.keys props') $ \k -> do
@@ -732,21 +893,25 @@ checkImplication env beh prods cons = case findExactly prods of
733 Nothing -> issueAt beh NoMatchingProperties
894 Nothing -> issueAt beh NoMatchingProperties
734 MaxProperties m -> case findRelevant min (\case MaxProperties m' -> Just m'; _ -> Nothing) prods of
895 MaxProperties m -> case findRelevant min (\case MaxProperties m' -> Just m'; _ -> Nothing) prods of
735− Just m' -> if m' <= m then pure ()
898+ then pure ()
736− else issueAt beh (MatchingMaxPropertiesWeak m m')
899+ else issueAt beh (MatchingMaxPropertiesWeak m m')
737 Nothing -> issueAt beh (NoMatchingMaxProperties m)
900 Nothing -> issueAt beh (NoMatchingMaxProperties m)
738 MinProperties m -> case findRelevant max (\case MinProperties m' -> Just m'; _ -> Nothing) prods of
901 MinProperties m -> case findRelevant max (\case MinProperties m' -> Just m'; _ -> Nothing) prods of
739− Just m' -> if m' >= m then pure ()
904+ then pure ()
740− else issueAt beh (MatchingMinPropertiesWeak m m')
905+ else issueAt beh (MatchingMinPropertiesWeak m m')
741 Nothing -> issueAt beh (NoMatchingMinProperties m)
906 Nothing -> issueAt beh (NoMatchingMinProperties m)
743− findExactly (Exactly x:_) = Just x
908+ findExactly (Exactly x : _) = Just x
744− findExactly (_:xs) = findExactly xs
909+ findExactly (_ : xs) = findExactly xs
745 findExactly [] = Nothing
910 findExactly [] = Nothing
746− findRelevant combine extr
911+ findRelevant combine extr =
747− = fmap (foldr1 combine) . NE.nonEmpty . mapMaybe extr
912+ fmap (foldr1 combine) . NE.nonEmpty . mapMaybe extr
748− lcmScientific (toRational -> a) (toRational -> b)
913+ lcmScientific (toRational -> a) (toRational -> b) =
749− = fromRational $ lcm (numerator a) (numerator b) % gcd (denominator a) (denominator b)
914+ fromRational $ lcm (numerator a) (numerator b) % gcd (denominator a) (denominator b)
751instance Issuable 'TypedSchemaLevel where
916instance Issuable 'TypedSchemaLevel where
752 data Issue 'TypedSchemaLevel
917 data Issue 'TypedSchemaLevel
@@ -806,59 +971,52 @@ instance Subtree Schema where
806 type SubtreeLevel Schema = 'SchemaLevel
971 type SubtreeLevel Schema = 'SchemaLevel
807 type CheckEnv Schema = '[ProdCons (Traced (Definitions Schema))]
972 type CheckEnv Schema = '[ProdCons (Traced (Definitions Schema))]
808 checkStructuralCompatibility env pc = do
973 checkStructuralCompatibility env pc = do
810− structuralEq $ _schemaRequired <$> pc
974+ structuralEq $ fmap _schemaRequired <$> pc
811− structuralMaybeWith structuralEq $ _schemaNullable <$> pc
975+ structuralEq $ fmap _schemaNullable <$> pc
812− structuralMaybeWith (structuralList env) $ _schemaAllOf <$> pc
976+ structuralMaybeWith (structuralList env) $ tracedAllOf <$> pc
813− structuralMaybeWith (structuralList env) $ _schemaOneOf <$> pc
977+ structuralMaybeWith (structuralList env) $ tracedOneOf <$> pc
814− structuralMaybe env $ _schemaNot <$> pc
978+ structuralMaybe env $ sequence . stepTraced NotStep . fmap _schemaNot <$> pc
815− structuralMaybeWith (structuralList env) $ _schemaAnyOf <$> pc
979+ structuralMaybeWith (structuralList env) $ tracedAnyOf <$> pc
816− iohmStructural env $ _schemaProperties <$> pc
980+ iohmStructural env $ stepTraced PropertiesStep . fmap _schemaProperties <$> pc
817− structuralMaybeWith structuralAdditionalProperties $ _schemaAdditionalProperties <$> pc
981+ structuralMaybeWith structuralAdditionalProperties $ tracedAdditionalProperties <$> pc
818− structuralMaybeWith structuralDiscriminator $ _schemaDiscriminator <$> pc
982+ structuralMaybeWith structuralDiscriminator $ tracedDiscriminator <$> pc
819− structuralEq $ _schemaReadOnly <$> pc
983+ structuralEq $ fmap _schemaReadOnly <$> pc
820− structuralEq $ _schemaWriteOnly <$> pc
984+ structuralEq $ fmap _schemaWriteOnly <$> pc
821− structuralEq $ _schemaXml <$> pc
985+ structuralEq $ fmap _schemaXml <$> pc
822− structuralEq $ _schemaMaxProperties <$> pc
986+ structuralEq $ fmap _schemaMaxProperties <$> pc
823− structuralEq $ _schemaMinProperties <$> pc
987+ structuralEq $ fmap _schemaMinProperties <$> pc
824− structuralEq $ _schemaDefault <$> pc
988+ structuralEq $ fmap _schemaDefault <$> pc
825− structuralEq $ _schemaType <$> pc
989+ structuralEq $ fmap _schemaType <$> pc
826− structuralEq $ _schemaFormat <$> pc
990+ structuralEq $ fmap _schemaFormat <$> pc
827− structuralMaybeWith structuralItems $ _schemaItems <$> pc
991+ structuralMaybeWith structuralItems $ tracedItems <$> pc
828− structuralEq $ _schemaMaximum <$> pc
992+ structuralEq $ fmap _schemaMaximum <$> pc
829− structuralEq $ _schemaExclusiveMaximum <$> pc
993+ structuralEq $ fmap _schemaExclusiveMaximum <$> pc
830− structuralEq $ _schemaMinimum <$> pc
994+ structuralEq $ fmap _schemaMinimum <$> pc
831− structuralEq $ _schemaExclusiveMinimum <$> pc
995+ structuralEq $ fmap _schemaExclusiveMinimum <$> pc
832− structuralEq $ _schemaMaxLength <$> pc
996+ structuralEq $ fmap _schemaMaxLength <$> pc
833− structuralEq $ _schemaMinLength <$> pc
997+ structuralEq $ fmap _schemaMinLength <$> pc
834− structuralEq $ _schemaPattern <$> pc
998+ structuralEq $ fmap _schemaPattern <$> pc
835− structuralEq $ _schemaMaxItems <$> pc
999+ structuralEq $ fmap _schemaMaxItems <$> pc
836− structuralEq $ _schemaMinItems <$> pc
1000+ structuralEq $ fmap _schemaMinItems <$> pc
837− structuralEq $ _schemaUniqueItems <$> pc
1001+ structuralEq $ fmap _schemaUniqueItems <$> pc
838− structuralEq $ _schemaEnum <$> pc
1002+ structuralEq $ fmap _schemaEnum <$> pc
839− structuralEq $ _schemaMultipleOf <$> pc
1003+ structuralEq $ fmap _schemaMultipleOf <$> pc
842 structuralAdditionalProperties
1006 structuralAdditionalProperties
843− (ProdCons (AdditionalPropertiesAllowed x) (AdditionalPropertiesAllowed y)) =
1007+ (ProdCons (Left x) (Left y)) = unless (x == y) structuralIssue
844− structuralEq $ ProdCons x y
845 structuralAdditionalProperties
1008 structuralAdditionalProperties
846− (ProdCons (AdditionalPropertiesSchema x) (AdditionalPropertiesSchema y)) =
1009+ (ProdCons (Right x) (Right y)) =
847− checkStructuralCompatibility env $ ProdCons x y
1010+ checkSubstructure env $ ProdCons x y
848 structuralAdditionalProperties _ = structuralIssue
1011 structuralAdditionalProperties _ = structuralIssue
849 structuralDiscriminator pc' = do
1012 structuralDiscriminator pc' = do
850− structuralEq $ _discriminatorPropertyName <$> pc'
1013+ structuralEq $ fmap _discriminatorPropertyName <$> pc'
851− iohmStructuralWith
1014+ iohmStructural env $
852− (\_ mappingPC -> case A.decodeStrict @(Referenced Schema) . T.encodeUtf8 <$> mappingPC of
853− ProdCons (Just a) (Just b) -> checkStructuralCompatibility env $ ProdCons a b
854− ProdCons Nothing Nothing -> structuralEq mappingPC
855− _ -> structuralIssue
857− (_discriminatorMapping <$> pc')
1015+ stepTraced DiscriminatorMapping . fmap (fmap parseDiscriminatorValue . _discriminatorMapping) <$> pc'
859− structuralItems (ProdCons (OpenApiItemsObject a) (OpenApiItemsObject b)) =
1017+ structuralItems (ProdCons (Left a) (Left b)) =
860− checkStructuralCompatibility env $ ProdCons a b
1018+ checkSubstructure env $ ProdCons a b
861− structuralItems (ProdCons (OpenApiItemsArray a) (OpenApiItemsArray b)) =
1019+ structuralItems (ProdCons (Right a) (Right b)) =
862 structuralList env $ ProdCons a b
1020 structuralList env $ ProdCons a b
863 structuralItems _ = structuralIssue
1021 structuralItems _ = structuralIssue
864 checkSemanticCompatibility env beh schs = do
1022 checkSemanticCompatibility env beh schs = do