git.iko.soy/typeable/compaREST
on master help sign in
Tuple items (#108)
dcd32cbmniip
src/OpenAPI/Checker/Report.hs+2
@@ -233,10 +233,12 @@ jets =
233 showParts (SingletonUnion (OfType Object) : xs@((SingletonUnion (InProperty _)) : _)) = showParts xs
233 showParts (SingletonUnion (OfType Object) : xs@((SingletonUnion (InProperty _)) : _)) = showParts xs
234 showParts (SingletonUnion (OfType Object) : xs@((SingletonUnion InAdditionalProperty) : _)) = showParts xs
234 showParts (SingletonUnion (OfType Object) : xs@((SingletonUnion InAdditionalProperty) : _)) = showParts xs
235 showParts (SingletonUnion (OfType Array) : xs@(SingletonUnion InItems : _)) = showParts xs
235 showParts (SingletonUnion (OfType Array) : xs@(SingletonUnion InItems : _)) = showParts xs
236+ showParts (SingletonUnion (OfType Array) : xs@(SingletonUnion (InItem _) : _)) = showParts xs
236 showParts (y : ys) =
237 showParts (y : ys) =
237 ((\(OfType t) -> "(" <> describeJSONType t <> ")")
238 ((\(OfType t) -> "(" <> describeJSONType t <> ")")
238 @@> (\case
239 @@> (\case
239 InItems -> "[*]"
240 InItems -> "[*]"
241+ InItem i -> "[" <> T.pack (show i) <> "]"
240 InProperty p -> "." <> p
242 InProperty p -> "." <> p
241 InAdditionalProperty -> ".*")
243 InAdditionalProperty -> ".*")
242 @@> typesExhausted)
244 @@> typesExhausted)
src/OpenAPI/Checker/Validate/Schema.hs+70−13
@@ -7,15 +7,17 @@ where
7import Control.Monad.Writer
7import Control.Monad.Writer
8import qualified Data.Aeson as A
8import qualified Data.Aeson as A
9import Data.Coerce
9import Data.Coerce
10−import Data.Foldable (for_)
10+import Data.Foldable (for_, toList)
11import Data.Functor
11import Data.Functor
12import Data.HList
12import Data.HList
13import qualified Data.List.NonEmpty as NE
13import qualified Data.List.NonEmpty as NE
14import qualified Data.Map as M
14import qualified Data.Map as M
15+import Data.List (group, genericLength, genericIndex)
15import Data.Maybe
16import Data.Maybe
16import Data.OpenApi
17import Data.OpenApi
17import Data.Ord
18import Data.Ord
18import Data.Ratio
19import Data.Ratio
20+import Data.Semigroup
19import qualified Data.Set as S
21import qualified Data.Set as S
20import Data.Text (Text)
22import Data.Text (Text)
21import OpenAPI.Checker.Behavior
23import OpenAPI.Checker.Behavior
@@ -34,10 +36,11 @@ checkFormulas
34 :: (ReassembleHList xs (CheckEnv (Referenced Schema)))
36 :: (ReassembleHList xs (CheckEnv (Referenced Schema)))
35 => HList xs
37 => HList xs
36 -> Behavior 'SchemaLevel
38 -> Behavior 'SchemaLevel
39+ -> ProdCons (Trace Schema)
37 -> ProdCons (Traced (Definitions Schema))
40 -> ProdCons (Traced (Definitions Schema))
38 -> ProdCons (ForeachType JsonFormula, P.PathsPrefixTree Behave AnIssue 'SchemaLevel)
41 -> ProdCons (ForeachType JsonFormula, P.PathsPrefixTree Behave AnIssue 'SchemaLevel)
39 -> SemanticCompatFormula ()
42 -> SemanticCompatFormula ()
40−checkFormulas env beh defs (ProdCons (fp, ep) (fc, ec)) =
43+checkFormulas env beh trs defs (ProdCons (fp, ep) (fc, ec)) =
41 case P.toList ep ++ P.toList ec of
44 case P.toList ep ++ P.toList ec of
42 issues@(_ : _) -> for_ issues $ embedFormula beh . anItem
45 issues@(_ : _) -> for_ issues $ embedFormula beh . anItem
43 [] -> do
46 [] -> do
@@ -105,25 +108,25 @@ checkFormulas env beh defs (ProdCons (fp, ep) (fc, ec)) =
105 -- don't repeat the TypesRestricted issue
108 -- don't repeat the TypesRestricted issue
106 for_ pss $ \(Disjunct ps) -> checkContradiction beh' Nothing ps
109 for_ pss $ \(Disjunct ps) -> checkContradiction beh' Nothing ps
107 (DNF pss, SingleDisjunct (Disjunct cs)) -> for_ pss $ \(Disjunct ps) -> do
110 (DNF pss, SingleDisjunct (Disjunct cs)) -> for_ pss $ \(Disjunct ps) -> do
108− for_ cs $ checkImplication env beh' ps -- avoid disjunction if there's only one conjunct
111+ for_ cs $ checkImplication env beh' trs ps -- avoid disjunction if there's only one conjunct
109 (TopDNF, DNF css) ->
112 (TopDNF, DNF css) ->
110 -- producer is "open" (allows any value), but consumer has restrictions.
113 -- producer is "open" (allows any value), but consumer has restrictions.
111 -- In this case we want to show which restrictions were added. (instead
114 -- In this case we want to show which restrictions were added. (instead
112 -- of showing an empty list restrictions that couldn't be satisfied.)
115 -- of showing an empty list restrictions that couldn't be satisfied.)
113− for_ css $ \(Disjunct cs) -> for_ cs $ checkImplication env beh' S.empty
116+ for_ css $ \(Disjunct cs) -> for_ cs $ checkImplication env beh' trs S.empty
114 (pss', css') -> for_ (tryPartition defs $ ProdCons (JsonFormula pss') (JsonFormula css')) $ \case
117 (pss', css') -> for_ (tryPartition defs $ ProdCons (JsonFormula pss') (JsonFormula css')) $ \case
115 (mPart, ProdCons pf cf) -> do
118 (mPart, ProdCons pf cf) -> do
116 let beh'' = foldr ((<<<) . step . InPartition) beh' mPart
119 let beh'' = foldr ((<<<) . step . InPartition) beh' mPart
117 case (getJsonFormula pf, getJsonFormula cf) of
120 case (getJsonFormula pf, getJsonFormula cf) of
118 (DNF pss, BottomDNF) -> for_ pss $ \(Disjunct ps) -> checkContradiction beh' mPart ps
121 (DNF pss, BottomDNF) -> for_ pss $ \(Disjunct ps) -> checkContradiction beh' mPart ps
119 (DNF pss, SingleDisjunct (Disjunct cs)) -> for_ pss $ \(Disjunct ps) -> do
122 (DNF pss, SingleDisjunct (Disjunct cs)) -> for_ pss $ \(Disjunct ps) -> do
120− for_ cs $ checkImplication env beh'' ps
123+ for_ cs $ checkImplication env beh'' trs ps
121 -- unlucky:
124 -- unlucky:
122 (DNF pss, DNF css) -> for_ pss $ \(Disjunct ps) -> do
125 (DNF pss, DNF css) -> for_ pss $ \(Disjunct ps) -> do
123 anyOfAt
126 anyOfAt
124 beh'
127 beh'
125 (issueFromDisjunct Nothing ps)
128 (issueFromDisjunct Nothing ps)
126− [for_ cs $ checkImplication env beh' ps | Disjunct cs <- S.toList css]
129+ [for_ cs $ checkImplication env beh' trs ps | Disjunct cs <- S.toList css]
127 pure ()
130 pure ()
128 where
131 where
129 anyBottomTypes f = getAny $
132 anyBottomTypes f = getAny $
@@ -151,10 +154,11 @@ checkImplication
151 :: (ReassembleHList xs (CheckEnv (Referenced Schema)))
154 :: (ReassembleHList xs (CheckEnv (Referenced Schema)))
152 => HList xs
155 => HList xs
153 -> Behavior 'TypedSchemaLevel
156 -> Behavior 'TypedSchemaLevel
157+ -> ProdCons (Trace Schema) -- the traces of the root schemas used in this comparison
154 -> S.Set (Condition t)
158 -> S.Set (Condition t)
155 -> Condition t
159 -> Condition t
156 -> SemanticCompatFormula ()
160 -> SemanticCompatFormula ()
157−checkImplication env beh prods cons = case findExactly prods of
161+checkImplication env beh trs prods cons = case findExactly prods of
158 Just e
162 Just e
159 | all (satisfiesTyped e) prods ->
163 | all (satisfiesTyped e) prods ->
160 if satisfiesTyped e cons
164 if satisfiesTyped e cons
@@ -208,24 +212,69 @@ checkImplication env beh prods cons = case findExactly prods of
208 False -> issueAt beh (NoMatchingFormat f)
212 False -> issueAt beh (NoMatchingFormat f)
209
213
210 Items _ cons' -> case foldSome (<>) prods $ \case
214 Items _ cons' -> case foldSome (<>) prods $ \case
211− Items _ rs -> Just (rs NE.:| [])
215+ Items _ rs -> Just (Just (rs NE.:| []), mempty)
216+ TupleItems (map snd -> fs) -> Just (mempty, Just (fs NE.:| []))
212 _ -> Nothing
217 _ -> Nothing
213 of
218 of
219+ Just (mItems, Just pfs)
220+ | not $ allSame (length <$> pfs) -> pure () -- vacuously
221+ | let plen = genericLength (NE.head pfs)
222+ -> clarifyIssue (AnItem beh (anIssue TupleToArray)) $ for_ [0 .. plen - 1] $ \i -> do
223+ let prod' = tracedConjunct $ case mItems of
224+ Just prods' -> ((`genericIndex` i) <$> pfs) <> prods'
225+ Nothing -> (`genericIndex` i) <$> pfs
226+ checkCompatibility (beh >>> step (InItem i)) env $ ProdCons prod' cons'
227+ Just (Just prods', Nothing) -> do
228+ let prod' = tracedConjunct prods'
214− Just (tracedConjunct -> rs) -> checkCompatibility (beh >>> step InItems) env $ ProdCons rs cons'
229+ checkCompatibility (beh >>> step InItems) env $ ProdCons prod' cons'
215− Nothing -> issueAt beh NoMatchingItems
230+ _ -> clarifyIssue (AnItem beh (anIssue NoMatchingItems)) $ do
231+ checkCompatibility (beh >>> step InItems) env $ ProdCons prodTopSchema cons'
232+
233+ TupleItems (map snd -> fs) -> case foldSome (<>) prods $ \case
234+ TupleItems (map snd -> fs') -> Just (Just $ fs' NE.:| [], Just . Max $ genericLength fs', Just . Min $ genericLength fs', mempty)
235+ MinItems m' -> Just (mempty, Just . Max $ m', mempty, mempty)
236+ MaxItems m' -> Just (mempty, mempty, Just . Min $ m', mempty)
237+ Items _ rs -> Just (mempty, mempty, mempty, Just (rs NE.:| []))
238+ _ -> Nothing
239+ of
240+ -- if the length constraints in the producer are contradictory:
241+ Just (_, Just (Max lowest), Just (Min highest), _) | lowest > highest -> pure ()
242+ -- We have an explicit tuple items clause...
243+ Just (Just pfs, Just (Max plen), _, _)
244+ | plen /= genericLength fs -- ...of wrong length
245+ -> issueAt beh (TupleItemsLengthChanged ProdCons {producer = plen, consumer = genericLength fs})
246+ | otherwise
247+ -> for_ [0 .. plen - 1] $ \i -> do
248+ checkCompatibility (beh >>> step (InItem i)) env $ ProdCons (tracedConjunct $ (`genericIndex` i) <$> pfs) (fs `genericIndex` i)
249+ -- We have a fixed length array in the producer...
250+ Just (Nothing, Just (Max plen), Just (Min plen'), mProd)
251+ | plen == plen'
252+ -> clarifyIssue (AnItem beh (anIssue ArrayToTuple)) $ case mProd of
253+ _ | plen /= genericLength fs -> -- ...of wrong length
254+ issueAt beh (TupleItemsLengthChanged ProdCons {producer = plen, consumer = genericLength fs})
255+ Just rs -> for_ [0 .. plen - 1] $ \i -> do
256+ checkCompatibility (beh >>> step (InItem i)) env $ ProdCons (tracedConjunct rs) (fs `genericIndex` i)
257+ -- ...and no "items" schema
258+ Nothing -> clarifyIssue (AnItem beh (anIssue NoMatchingTupleItems)) $ do
259+ for_ [0 .. plen - 1] $ \i -> do
260+ checkCompatibility (beh >>> step (InItem i)) env $ ProdCons prodTopSchema (fs `genericIndex` i)
261+ _ -> issueAt beh NoMatchingTupleItems
216
262
217 MaxItems m -> foldCheck min m NoMatchingMaxItems MatchingMaxItemsWeak $ \case
263 MaxItems m -> foldCheck min m NoMatchingMaxItems MatchingMaxItemsWeak $ \case
218 MaxItems m' -> Just m'
264 MaxItems m' -> Just m'
265+ TupleItems fs -> Just $ toInteger $ length fs
219 _ -> Nothing
266 _ -> Nothing
220
267
221 MinItems m -> foldCheck max m NoMatchingMinItems MatchingMinItemsWeak $ \case
268 MinItems m -> foldCheck max m NoMatchingMinItems MatchingMinItemsWeak $ \case
222 MinItems m' -> Just m'
269 MinItems m' -> Just m'
270+ TupleItems fs -> Just $ toInteger $ length fs
223− _ -> Nothing -- TODO: tuple items
271+ _ -> Nothing
224
272
225 UniqueItems -> case flip any prods $ \case
273 UniqueItems -> case flip any prods $ \case
226 UniqueItems -> True
274 UniqueItems -> True
227 MaxItems 1 -> True
275 MaxItems 1 -> True
276+ TupleItems fs | length fs == 1 -> True
228− _ -> False -- TODO: tuple items
277+ _ -> False
229 of
278 of
230 True -> pure ()
279 True -> pure ()
231 False -> issueAt beh NoMatchingUniqueItems
280 False -> issueAt beh NoMatchingUniqueItems
@@ -290,6 +339,14 @@ checkImplication env beh prods cons = case findExactly prods of
290 | otherwise -> issueAt beh (weak ProdCons {producer = m', consumer = m})
339 | otherwise -> issueAt beh (weak ProdCons {producer = m', consumer = m})
291 Nothing -> issueAt beh (missing m)
340 Nothing -> issueAt beh (missing m)
292
341
342+ prodTopSchema = traced (producer trs >>> step ImplicitTopSchema) $ Inline mempty
343+
344+allSame :: (Foldable f, Eq a) => f a -> Bool
345+allSame xs = case group (toList xs) of
346+ [] -> True
347+ [_] -> True
348+ _ -> False
349+
293foldSome :: (b -> b -> b) -> S.Set a -> (a -> Maybe b) -> Maybe b
350foldSome :: (b -> b -> b) -> S.Set a -> (a -> Maybe b) -> Maybe b
294foldSome combine xs extr =
351foldSome combine xs extr =
295 fmap (foldr1 combine) . NE.nonEmpty . mapMaybe extr . S.toList $ xs
352 fmap (foldr1 combine) . NE.nonEmpty . mapMaybe extr . S.toList $ xs
@@ -353,7 +410,7 @@ instance Subtree Schema where
353 structuralItems _ = structuralIssue
410 structuralItems _ = structuralIssue
354 checkSemanticCompatibility env beh schs = do
411 checkSemanticCompatibility env beh schs = do
355 let defs = getH env
412 let defs = getH env
356− checkFormulas env beh defs $ schemaToFormula <$> defs <*> schs
413+ checkFormulas env beh (ask <$> schs) defs $ schemaToFormula <$> defs <*> schs
357
414
358parseDiscriminatorValue :: Text -> Referenced Schema
415parseDiscriminatorValue :: Text -> Referenced Schema
359parseDiscriminatorValue v = case A.fromJSON @(Referenced Schema) $ A.object ["$ref" A..= v] of
416parseDiscriminatorValue v = case A.fromJSON @(Referenced Schema) $ A.object ["$ref" A..= v] of
src/OpenAPI/Checker/Validate/Schema/Issues.hs+17
@@ -50,6 +50,14 @@ instance Issuable 'TypedSchemaLevel where
50 NoMatchingPattern Pattern
50 NoMatchingPattern Pattern
51 | -- | consumer declares the items of an array must satisfy some condition, producer doesn't
51 | -- | consumer declares the items of an array must satisfy some condition, producer doesn't
52 NoMatchingItems
52 NoMatchingItems
53+ | -- | producer and consumer declare that an array must be a tuple of a fixed length, but the lengths don't match
54+ TupleItemsLengthChanged (ProdCons Integer)
55+ | -- | consumer declares that the array is a tuple, but the producer doesn't, the length constraints match, but there were issues with the components
56+ ArrayToTuple
57+ | -- | producer declares that the array is a tuple, but the consumer doesn't, and there were issues with the components
58+ TupleToArray
59+ | -- | consumer declares that the array is a tuple, but the producer doesn't, and there aren't sufficient length constraints
60+ NoMatchingTupleItems
53 | -- | consumer declares a maximum length of the array ($1), producer doesn't.
61 | -- | consumer declares a maximum length of the array ($1), producer doesn't.
54 NoMatchingMaxItems Integer
62 NoMatchingMaxItems Integer
55 | -- | consumer declares a maximum length of the array ($1), producer declares a weaker (higher) limit ($2)
63 | -- | consumer declares a maximum length of the array ($1), producer declares a weaker (higher) limit ($2)
@@ -105,6 +113,13 @@ instance Issuable 'TypedSchemaLevel where
105 describeIssue Backward (NoMatchingPattern p) = para "Pattern (regular expression) removed: " <> codeBlock p
113 describeIssue Backward (NoMatchingPattern p) = para "Pattern (regular expression) removed: " <> codeBlock p
106 describeIssue Forward NoMatchingItems = para "Array item schema has been added."
114 describeIssue Forward NoMatchingItems = para "Array item schema has been added."
107 describeIssue Backward NoMatchingItems = para "Array item schema has been removed."
115 describeIssue Backward NoMatchingItems = para "Array item schema has been removed."
116+ describeIssue _ (TupleItemsLengthChanged (ProdCons p c)) = para $ "Tuple length changed from " <> show' p <> " to " <> show' c <> "."
117+ describeIssue Forward ArrayToTuple = para "The array is now explicitly defined as a tuple."
118+ describeIssue Backward ArrayToTuple = para "The array is no longer explicitly defined as a tuple."
119+ describeIssue Forward TupleToArray = para "The array is no longer explicitly defined as a tuple."
120+ describeIssue Backward TupleToArray = para "The array is now explicitly defined as a tuple."
121+ describeIssue Forward NoMatchingTupleItems = para "The array is now explicitly defined as a tuple."
122+ describeIssue Backward NoMatchingTupleItems = para "The array is no longer explicitly defined as a tuple."
108 describeIssue Forward (NoMatchingMaxItems n) = para $ "Maximum length of the array has been added " <> show' n <> "."
123 describeIssue Forward (NoMatchingMaxItems n) = para $ "Maximum length of the array has been added " <> show' n <> "."
109 describeIssue Backward (NoMatchingMaxItems n) = para $ "Maximum length of the array has been removed " <> show' n <> "."
124 describeIssue Backward (NoMatchingMaxItems n) = para $ "Maximum length of the array has been removed " <> show' n <> "."
110 describeIssue _ (MatchingMaxItemsWeak (ProdCons p c)) = para $ "Maximum length of the array changed from " <> show' p <> " to " <> show' c <> "."
125 describeIssue _ (MatchingMaxItemsWeak (ProdCons p c)) = para $ "Maximum length of the array changed from " <> show' p <> " to " <> show' c <> "."
@@ -213,10 +228,12 @@ instance Behavable 'TypedSchemaLevel 'TypedSchemaLevel where
213instance Behavable 'TypedSchemaLevel 'SchemaLevel where
228instance Behavable 'TypedSchemaLevel 'SchemaLevel where
214 data Behave 'TypedSchemaLevel 'SchemaLevel
229 data Behave 'TypedSchemaLevel 'SchemaLevel
215 = InItems
230 = InItems
231+ | InItem Integer
216 | InProperty Text
232 | InProperty Text
217 | InAdditionalProperty
233 | InAdditionalProperty
218 deriving stock (Eq, Ord, Show)
234 deriving stock (Eq, Ord, Show)
219
235
220 describeBehaviour InItems = "Items"
236 describeBehaviour InItems = "Items"
237+ describeBehaviour (InItem i) = "Item " <> show' i
221 describeBehaviour (InProperty p) = "Property " <> code p
238 describeBehaviour (InProperty p) = "Property " <> code p
222 describeBehaviour InAdditionalProperty = "Additional properties"
239 describeBehaviour InAdditionalProperty = "Additional properties"
src/OpenAPI/Checker/Validate/Schema/JsonFormula.hs+5
@@ -80,6 +80,9 @@ data Condition :: JsonType -> Type where
80 :: !(ForeachType JsonFormula)
80 :: !(ForeachType JsonFormula)
81 -> !(Traced (Referenced Schema))
81 -> !(Traced (Referenced Schema))
82 -> Condition 'Array
82 -> Condition 'Array
83+ TupleItems
84+ :: ![(ForeachType JsonFormula, Traced (Referenced Schema))]
85+ -> Condition 'Array
83 MaxItems :: !Integer -> Condition 'Array
86 MaxItems :: !Integer -> Condition 'Array
84 MinItems :: !Integer -> Condition 'Array
87 MinItems :: !Integer -> Condition 'Array
85 UniqueItems :: Condition 'Array
88 UniqueItems :: Condition 'Array
@@ -109,6 +112,7 @@ showCondition = \case
109 (MaxLength p) -> para $ "The length of the string should be less than or equal to " <> show' p <> "."
112 (MaxLength p) -> para $ "The length of the string should be less than or equal to " <> show' p <> "."
110 (MinLength p) -> para $ "The length of the string should be more than or equal to " <> show' p <> "."
113 (MinLength p) -> para $ "The length of the string should be more than or equal to " <> show' p <> "."
111 (Items i _) -> para "The items of the array should satisfy:" <> showForEachJsonFormula i
114 (Items i _) -> para "The items of the array should satisfy:" <> showForEachJsonFormula i
115+ (TupleItems is) -> para ("There should be " <> show' (length is) <> " items in the array:") <> bulletList (showForEachJsonFormula . fst <$> is)
112 (MaxItems n) -> para $ "The length of the array should be less than or equal to " <> show' n <> "."
116 (MaxItems n) -> para $ "The length of the array should be less than or equal to " <> show' n <> "."
113 (MinItems n) -> para $ "The length of the array should be more than or equal to " <> show' n <> "."
117 (MinItems n) -> para $ "The length of the array should be more than or equal to " <> show' n <> "."
114 UniqueItems -> para "The elements in the array should be unique."
118 UniqueItems -> para "The elements in the array should be unique."
@@ -161,6 +165,7 @@ satisfiesTyped (TString s) (MinLength m) = fromIntegral (T.length s) >= m
161satisfiesTyped (TString s) (Pattern p) = isJust $ match p s -- TODO: regex stuff #32
165satisfiesTyped (TString s) (Pattern p) = isJust $ match p s -- TODO: regex stuff #32
162satisfiesTyped (TString s) (StringFormat f) = checkStringFormat f s
166satisfiesTyped (TString s) (StringFormat f) = checkStringFormat f s
163satisfiesTyped (TArray a) (Items f _) = all (`satisfies` f) a
167satisfiesTyped (TArray a) (Items f _) = all (`satisfies` f) a
168+satisfiesTyped (TArray a) (TupleItems fs) = length fs == F.length a && and (zipWith satisfies (F.toList a) (fst <$> fs))
164satisfiesTyped (TArray a) (MaxItems m) = fromIntegral (F.length a) <= m
169satisfiesTyped (TArray a) (MaxItems m) = fromIntegral (F.length a) <= m
165satisfiesTyped (TArray a) (MinItems m) = fromIntegral (F.length a) >= m
170satisfiesTyped (TArray a) (MinItems m) = fromIntegral (F.length a) >= m
166satisfiesTyped (TArray a) UniqueItems = S.size (S.fromList $ F.toList a) == F.length a -- TODO: could be better #36
171satisfiesTyped (TArray a) UniqueItems = S.size (S.fromList $ F.toList a) == F.length a -- TODO: could be better #36
src/OpenAPI/Checker/Validate/Schema/Process.hs+5−1
@@ -245,7 +245,11 @@ processSchema sch@(extract -> Schema {..}) = do
245 Just (Left rs) -> do
245 Just (Left rs) -> do
246 f <- silently $ processRefSchema rs
246 f <- silently $ processRefSchema rs
247 pure top {forArray = singletonFormula $ Items f rs}
247 pure top {forArray = singletonFormula $ Items f rs}
248− Just (Right _) -> top <$ warn (NotSupported "array in items is not supported")
248+ Just (Right rss) -> do
249+ fsrs <- forM rss $ \rs -> do
250+ f <- silently $ processRefSchema rs
251+ pure (f, rs)
252+ pure top {forArray = singletonFormula $ TupleItems fsrs}
249
253
250 let maxItemsClause = case _schemaMaxItems of
254 let maxItemsClause = case _schemaMaxItems of
251 Nothing -> top
255 Nothing -> top
src/OpenAPI/Checker/Validate/Schema/Traced.hs+1
@@ -46,6 +46,7 @@ instance Steppable Schema (Referenced Schema) where
46 | ItemsArrayStep Int
46 | ItemsArrayStep Int
47 | AdditionalPropertiesStep
47 | AdditionalPropertiesStep
48 | NotStep
48 | NotStep
49+ | ImplicitTopSchema
49 deriving stock (Eq, Ord, Show)
50 deriving stock (Eq, Ord, Show)
50
51
51instance Steppable (Referenced Schema) (Referenced Schema) where
52instance Steppable (Referenced Schema) (Referenced Schema) where
test/golden/common/tuple-items/heterogeneous-component-mismatch/a.yamlnew file+28
@@ -0,0 +1,28 @@
1+openapi: "3.0.0"
2+info:
3+ version: 1.0.0
4+ title: Test
5+servers:
6+ - url: http://localhost/
7+paths:
8+ /test:
9+ post:
10+ requestBody:
11+ content:
12+ application/json:
13+ schema:
14+ $ref: "#/components/schemas/Test"
15+ responses:
16+ '200':
17+ description: test
18+ content:
19+ application/json:
20+ schema:
21+ $ref: "#/components/schemas/Test"
22+components:
23+ schemas:
24+ Test:
25+ type: array
26+ items:
27+ - type: number
28+ - type: string
test/golden/common/tuple-items/heterogeneous-component-mismatch/b.yamlnew file+28
@@ -0,0 +1,28 @@
1+openapi: "3.0.0"
2+info:
3+ version: 1.0.0
4+ title: Test
5+servers:
6+ - url: http://localhost/
7+paths:
8+ /test:
9+ post:
10+ requestBody:
11+ content:
12+ application/json:
13+ schema:
14+ $ref: "#/components/schemas/Test"
15+ responses:
16+ '200':
17+ description: test
18+ content:
19+ application/json:
20+ schema:
21+ $ref: "#/components/schemas/Test"
22+components:
23+ schemas:
24+ Test:
25+ type: array
26+ items:
27+ - type: number
28+ - type: object
test/golden/common/tuple-items/heterogeneous-component-mismatch/report.mdnew file+37
@@ -0,0 +1,37 @@
1+# Summary
2+
3+| [⚠️ Breaking changes](#breaking-changes) | [🙆 Non-breaking changes](#non-breaking-changes) | 🤷 Unsupported feature changes |
4+|------------------------------------------|-------------------------------------------------|-------------------------------|
5+| 2 | 2 | 0 |
6+
7+# <span id="breaking-changes"></span>⚠️ Breaking changes
8+
9+## **POST** /test
10+
11+### 📱➡️ JSON Request
12+
13+#### `$[1](String)`
14+
15+The type has been removed.
16+
17+### 📱⬅️ JSON Response – 200
18+
19+#### `$[1](Object)`
20+
21+The type has been added.
22+
23+# <span id="non-breaking-changes"></span>🙆 Non-breaking changes
24+
25+## **POST** /test
26+
27+### 📱➡️ JSON Request
28+
29+#### `$[1](Object)`
30+
31+The type has been added.
32+
33+### 📱⬅️ JSON Response – 200
34+
35+#### `$[1](String)`
36+
37+The type has been removed.
test/golden/common/tuple-items/heterogeneous-component-mismatch/trace-tree.yamlnew file+30
@@ -0,0 +1,30 @@
1+breakingChanges:
2+ AtPath "/test":
3+ InOperation PostMethod:
4+ InRequest:
5+ InPayload:
6+ PayloadSchema:
7+ OfType Array:
8+ InItem 1:
9+ OfType String: TypeBecomesEmpty
10+ WithStatusCode 200:
11+ ResponsePayload:
12+ PayloadSchema:
13+ OfType Array:
14+ InItem 1:
15+ OfType Object: TypeBecomesEmpty
16+nonBreakingChanges:
17+ AtPath "/test":
18+ InOperation PostMethod:
19+ InRequest:
20+ InPayload:
21+ PayloadSchema:
22+ OfType Array:
23+ InItem 1:
24+ OfType Object: TypeBecomesEmpty
25+ WithStatusCode 200:
26+ ResponsePayload:
27+ PayloadSchema:
28+ OfType Array:
29+ InItem 1:
30+ OfType String: TypeBecomesEmpty
test/golden/common/tuple-items/heterogeneous-length-mismatch/a.yamlnew file+29
@@ -0,0 +1,29 @@
1+openapi: "3.0.0"
2+info:
3+ version: 1.0.0
4+ title: Test
5+servers:
6+ - url: http://localhost/
7+paths:
8+ /test:
9+ post:
10+ requestBody:
11+ content:
12+ application/json:
13+ schema:
14+ $ref: "#/components/schemas/Test"
15+ responses:
16+ '200':
17+ description: test
18+ content:
19+ application/json:
20+ schema:
21+ $ref: "#/components/schemas/Test"
22+components:
23+ schemas:
24+ Test:
25+ type: array
26+ items:
27+ - type: number
28+ - type: string
29+ - type: object
test/golden/common/tuple-items/heterogeneous-length-mismatch/b.yamlnew file+28
@@ -0,0 +1,28 @@
1+openapi: "3.0.0"
2+info:
3+ version: 1.0.0
4+ title: Test
5+servers:
6+ - url: http://localhost/
7+paths:
8+ /test:
9+ post:
10+ requestBody:
11+ content:
12+ application/json:
13+ schema:
14+ $ref: "#/components/schemas/Test"
15+ responses:
16+ '200':
17+ description: test
18+ content:
19+ application/json:
20+ schema:
21+ $ref: "#/components/schemas/Test"
22+components:
23+ schemas:
24+ Test:
25+ type: array
26+ items:
27+ - type: number
28+ - type: object
test/golden/common/tuple-items/heterogeneous-length-mismatch/report.mdnew file+37
@@ -0,0 +1,37 @@
1+# Summary
2+
3+| [⚠️ Breaking changes](#breaking-changes) | [🙆 Non-breaking changes](#non-breaking-changes) | 🤷 Unsupported feature changes |
4+|------------------------------------------|-------------------------------------------------|-------------------------------|
5+| 2 | 2 | 0 |
6+
7+# <span id="breaking-changes"></span>⚠️ Breaking changes
8+
9+## **POST** /test
10+
11+### 📱➡️ JSON Request
12+
13+#### `$(Array)`
14+
15+Tuple length changed from 3 to 2.
16+
17+### 📱⬅️ JSON Response – 200
18+
19+#### `$(Array)`
20+
21+Tuple length changed from 2 to 3.
22+
23+# <span id="non-breaking-changes"></span>🙆 Non-breaking changes
24+
25+## **POST** /test
26+
27+### 📱➡️ JSON Request
28+
29+#### `$(Array)`
30+
31+Tuple length changed from 2 to 3.
32+
33+### 📱⬅️ JSON Response – 200
34+
35+#### `$(Array)`
36+
37+Tuple length changed from 3 to 2.
test/golden/common/tuple-items/heterogeneous-length-mismatch/trace-tree.yamlnew file+26
@@ -0,0 +1,26 @@
1+breakingChanges:
2+ AtPath "/test":
3+ InOperation PostMethod:
4+ InRequest:
5+ InPayload:
6+ PayloadSchema:
7+ OfType Array: TupleItemsLengthChanged (ProdCons {producer = 3, consumer
8+ = 2})
9+ WithStatusCode 200:
10+ ResponsePayload:
11+ PayloadSchema:
12+ OfType Array: TupleItemsLengthChanged (ProdCons {producer = 2, consumer
13+ = 3})
14+nonBreakingChanges:
15+ AtPath "/test":
16+ InOperation PostMethod:
17+ InRequest:
18+ InPayload:
19+ PayloadSchema:
20+ OfType Array: TupleItemsLengthChanged (ProdCons {producer = 2, consumer
21+ = 3})
22+ WithStatusCode 200:
23+ ResponsePayload:
24+ PayloadSchema:
25+ OfType Array: TupleItemsLengthChanged (ProdCons {producer = 3, consumer
26+ = 2})
test/golden/common/tuple-items/homogeneous-component-mismatch/a.yamlnew file+28
@@ -0,0 +1,28 @@
1+openapi: "3.0.0"
2+info:
3+ version: 1.0.0
4+ title: Test
5+servers:
6+ - url: http://localhost/
7+paths:
8+ /test:
9+ post:
10+ requestBody:
11+ content:
12+ application/json:
13+ schema:
14+ $ref: "#/components/schemas/Test"
15+ responses:
16+ '200':
17+ description: test
18+ content:
19+ application/json:
20+ schema:
21+ $ref: "#/components/schemas/Test"
22+components:
23+ schemas:
24+ Test:
25+ type: array
26+ items:
27+ - type: string
28+ - type: number
test/golden/common/tuple-items/homogeneous-component-mismatch/b.yamlnew file+29
@@ -0,0 +1,29 @@
1+openapi: "3.0.0"
2+info:
3+ version: 1.0.0
4+ title: Test
5+servers:
6+ - url: http://localhost/
7+paths:
8+ /test:
9+ post:
10+ requestBody:
11+ content:
12+ application/json:
13+ schema:
14+ $ref: "#/components/schemas/Test"
15+ responses:
16+ '200':
17+ description: test
18+ content:
19+ application/json:
20+ schema:
21+ $ref: "#/components/schemas/Test"
22+components:
23+ schemas:
24+ Test:
25+ type: array
26+ minItems: 2
27+ maxItems: 2
28+ items:
29+ type: number
test/golden/common/tuple-items/homogeneous-component-mismatch/report.mdnew file+53
@@ -0,0 +1,53 @@
1+# Summary
2+
3+| [⚠️ Breaking changes](#breaking-changes) | [🙆 Non-breaking changes](#non-breaking-changes) | 🤷 Unsupported feature changes |
4+|------------------------------------------|-------------------------------------------------|-------------------------------|
5+| 4 | 4 | 0 |
6+
7+# <span id="breaking-changes"></span>⚠️ Breaking changes
8+
9+## **POST** /test
10+
11+### 📱➡️ JSON Request
12+
13+#### `$(Array)`
14+
15+The array is no longer explicitly defined as a tuple.
16+
17+#### `$[0](String)`
18+
19+The type has been removed.
20+
21+### 📱⬅️ JSON Response – 200
22+
23+#### `$(Array)`
24+
25+The array is no longer explicitly defined as a tuple.
26+
27+#### `$[0](Number)`
28+
29+The type has been added.
30+
31+# <span id="non-breaking-changes"></span>🙆 Non-breaking changes
32+
33+## **POST** /test
34+
35+### 📱➡️ JSON Request
36+
37+#### `$(Array)`
38+
39+The array is no longer explicitly defined as a tuple.
40+
41+#### `$[0](Number)`
42+
43+The type has been added.
44+
45+### 📱⬅️ JSON Response – 200
46+
47+#### `$(Array)`
48+
49+The array is no longer explicitly defined as a tuple.
50+
51+#### `$[0](String)`
52+
53+The type has been removed.
test/golden/common/tuple-items/homogeneous-component-mismatch/trace-tree.yamlnew file+34
@@ -0,0 +1,34 @@
1+breakingChanges:
2+ AtPath "/test":
3+ InOperation PostMethod:
4+ InRequest:
5+ InPayload:
6+ PayloadSchema:
7+ OfType Array:
8+ - TupleToArray
9+ - InItem 0:
10+ OfType String: TypeBecomesEmpty
11+ WithStatusCode 200:
12+ ResponsePayload:
13+ PayloadSchema:
14+ OfType Array:
15+ - ArrayToTuple
16+ - InItem 0:
17+ OfType Number: TypeBecomesEmpty
18+nonBreakingChanges:
19+ AtPath "/test":
20+ InOperation PostMethod:
21+ InRequest:
22+ InPayload:
23+ PayloadSchema:
24+ OfType Array:
25+ - ArrayToTuple
26+ - InItem 0:
27+ OfType Number: TypeBecomesEmpty
28+ WithStatusCode 200:
29+ ResponsePayload:
30+ PayloadSchema:
31+ OfType Array:
32+ - TupleToArray
33+ - InItem 0:
34+ OfType String: TypeBecomesEmpty
test/golden/common/tuple-items/homogeneous-length-mismatch/a.yamlnew file+56
@@ -0,0 +1,56 @@
1+openapi: "3.0.0"
2+info:
3+ version: 1.0.0
4+ title: Test
5+servers:
6+ - url: http://localhost/
7+paths:
8+ /test1:
9+ post:
10+ requestBody:
11+ content:
12+ application/json:
13+ schema:
14+ $ref: "#/components/schemas/Test"
15+ responses:
16+ '200':
17+ description: test
18+ content:
19+ application/json:
20+ schema:
21+ $ref: "#/components/schemas/Test"
22+ /test2:
23+ post:
24+ requestBody:
25+ content:
26+ application/json:
27+ schema:
28+ $ref: "#/components/schemas/Test"
29+ responses:
30+ '200':
31+ description: test
32+ content:
33+ application/json:
34+ schema:
35+ $ref: "#/components/schemas/Test"
36+ /test3:
37+ post:
38+ requestBody:
39+ content:
40+ application/json:
41+ schema:
42+ $ref: "#/components/schemas/Test"
43+ responses:
44+ '200':
45+ description: test
46+ content:
47+ application/json:
48+ schema:
49+ $ref: "#/components/schemas/Test"
50+components:
51+ schemas:
52+ Test:
53+ type: array
54+ items:
55+ - type: number
56+ - type: number
test/golden/common/tuple-items/homogeneous-length-mismatch/b.yamlnew file+67
@@ -0,0 +1,67 @@
1+openapi: "3.0.0"
2+info:
3+ version: 1.0.0
4+ title: Test
5+servers:
6+ - url: http://localhost/
7+paths:
8+ /test1:
9+ post:
10+ requestBody:
11+ content:
12+ application/json:
13+ schema:
14+ $ref: "#/components/schemas/Test1"
15+ responses:
16+ '200':
17+ description: test
18+ content:
19+ application/json:
20+ schema:
21+ $ref: "#/components/schemas/Test1"
22+ /test2:
23+ post:
24+ requestBody:
25+ content:
26+ application/json:
27+ schema:
28+ $ref: "#/components/schemas/Test2"
29+ responses:
30+ '200':
31+ description: test
32+ content:
33+ application/json:
34+ schema:
35+ $ref: "#/components/schemas/Test2"
36+ /test3:
37+ post:
38+ requestBody:
39+ content:
40+ application/json:
41+ schema:
42+ $ref: "#/components/schemas/Test3"
43+ responses:
44+ '200':
45+ description: test
46+ content:
47+ application/json:
48+ schema:
49+ $ref: "#/components/schemas/Test3"
50+components:
51+ schemas:
52+ Test1:
53+ type: array
54+ maxItems: 2
55+ items:
56+ type: number
57+ Test2:
58+ type: array
59+ minItems: 2
60+ items:
61+ type: number
62+ Test3:
63+ type: array
64+ minItems: 3
65+ maxItems: 3
66+ items:
67+ type: number
test/golden/common/tuple-items/homogeneous-length-mismatch/report.mdnew file+73
@@ -0,0 +1,73 @@
1+# Summary
2+
3+| [⚠️ Breaking changes](#breaking-changes) | [🙆 Non-breaking changes](#non-breaking-changes) | 🤷 Unsupported feature changes |
4+|------------------------------------------|-------------------------------------------------|-------------------------------|
5+| 5 | 5 | 0 |
6+
7+# <span id="breaking-changes"></span>⚠️ Breaking changes
8+
9+## **POST** /test1
10+
11+### 📱⬅️ JSON Response – 200
12+
13+#### `$(Array)`
14+
15+The array is no longer explicitly defined as a tuple.
16+
17+## **POST** /test2
18+
19+### 📱⬅️ JSON Response – 200
20+
21+#### `$(Array)`
22+
23+The array is no longer explicitly defined as a tuple.
24+
25+## **POST** /test3
26+
27+### 📱➡️ JSON Request
28+
29+#### `$(Array)`
30+
31+Minimum length of the array changed from 2 to 3.
32+
33+### 📱⬅️ JSON Response – 200
34+
35+#### `$(Array)`
36+
37+1. Tuple length changed from 3 to 2.
38+
39+2. The array is no longer explicitly defined as a tuple.
40+
41+# <span id="non-breaking-changes"></span>🙆 Non-breaking changes
42+
43+## **POST** /test1
44+
45+### 📱➡️ JSON Request
46+
47+#### `$(Array)`
48+
49+The array is no longer explicitly defined as a tuple.
50+
51+## **POST** /test2
52+
53+### 📱➡️ JSON Request
54+
55+#### `$(Array)`
56+
57+The array is no longer explicitly defined as a tuple.
58+
59+## **POST** /test3
60+
61+### 📱➡️ JSON Request
62+
63+#### `$(Array)`
64+
65+1. Tuple length changed from 3 to 2.
66+
67+2. The array is no longer explicitly defined as a tuple.
68+
69+### 📱⬅️ JSON Response – 200
70+
71+#### `$(Array)`
72+
73+Minimum length of the array changed from 2 to 3.
test/golden/common/tuple-items/homogeneous-length-mismatch/trace-tree.yamlnew file+52
@@ -0,0 +1,52 @@
1+breakingChanges:
2+ AtPath "/test3":
3+ InOperation PostMethod:
4+ InRequest:
5+ InPayload:
6+ PayloadSchema:
7+ OfType Array: MatchingMinItemsWeak (ProdCons {producer = 2, consumer =
8+ 3})
9+ WithStatusCode 200:
10+ ResponsePayload:
11+ PayloadSchema:
12+ OfType Array:
13+ - TupleItemsLengthChanged (ProdCons {producer = 3, consumer = 2})
14+ - ArrayToTuple
15+ AtPath "/test1":
16+ InOperation PostMethod:
17+ WithStatusCode 200:
18+ ResponsePayload:
19+ PayloadSchema:
20+ OfType Array: NoMatchingTupleItems
21+ AtPath "/test2":
22+ InOperation PostMethod:
23+ WithStatusCode 200:
24+ ResponsePayload:
25+ PayloadSchema:
26+ OfType Array: NoMatchingTupleItems
27+nonBreakingChanges:
28+ AtPath "/test3":
29+ InOperation PostMethod:
30+ InRequest:
31+ InPayload:
32+ PayloadSchema:
33+ OfType Array:
34+ - TupleItemsLengthChanged (ProdCons {producer = 3, consumer = 2})
35+ - ArrayToTuple
36+ WithStatusCode 200:
37+ ResponsePayload:
38+ PayloadSchema:
39+ OfType Array: MatchingMinItemsWeak (ProdCons {producer = 2, consumer =
40+ 3})
41+ AtPath "/test1":
42+ InOperation PostMethod:
43+ InRequest:
44+ InPayload:
45+ PayloadSchema:
46+ OfType Array: NoMatchingTupleItems
47+ AtPath "/test2":
48+ InOperation PostMethod:
49+ InRequest:
50+ InPayload:
51+ PayloadSchema:
52+ OfType Array: NoMatchingTupleItems
test/golden/common/tuple-items/homogeneous-vector/a.yamlnew file+28
@@ -0,0 +1,28 @@
1+openapi: "3.0.0"
2+info:
3+ version: 1.0.0
4+ title: Test
5+servers:
6+ - url: http://localhost/
7+paths:
8+ /test:
9+ post:
10+ requestBody:
11+ content:
12+ application/json:
13+ schema:
14+ $ref: "#/components/schemas/Test"
15+ responses:
16+ '200':
17+ description: test
18+ content:
19+ application/json:
20+ schema:
21+ $ref: "#/components/schemas/Test"
22+components:
23+ schemas:
24+ Test:
25+ type: array
26+ items:
27+ - type: number
28+ - type: number
test/golden/common/tuple-items/homogeneous-vector/b.yamlnew file+29
@@ -0,0 +1,29 @@
1+openapi: "3.0.0"
2+info:
3+ version: 1.0.0
4+ title: Test
5+servers:
6+ - url: http://localhost/
7+paths:
8+ /test:
9+ post:
10+ requestBody:
11+ content:
12+ application/json:
13+ schema:
14+ $ref: "#/components/schemas/Test"
15+ responses:
16+ '200':
17+ description: test
18+ content:
19+ application/json:
20+ schema:
21+ $ref: "#/components/schemas/Test"
22+components:
23+ schemas:
24+ Test:
25+ type: array
26+ minItems: 2
27+ maxItems: 2
28+ items:
29+ type: number
test/golden/common/tuple-items/homogeneous-vector/report.mdnew file+5
@@ -0,0 +1,5 @@
1+# Summary
2+
3+| ⚠️ Breaking changes | 🙆 Non-breaking changes | 🤷 Unsupported feature changes |
4+|---------------------|------------------------|-------------------------------|
5+| 0 | 0 | 0 |
test/golden/common/tuple-items/homogeneous-vector/trace-tree.yamlnew file+2
@@ -0,0 +1,2 @@
1+breakingChanges: {}
2+nonBreakingChanges: {}