@@ -19,13 +19,15 @@ import Data.Profunctor (Profunctor (..))
1919
2020import JSONSchema.Draft4 (ValidatorFailure(..),
2121 metaSchemaBytes)
22−import JSONSchema.Fetch (ReferencedSchemas(..),
23− SchemaWithURI(..))
22+import JSONSchema.Fetch (SchemaWithURI(..),
23+ URISchemaMap(..))
2424import qualified JSONSchema.Fetch as FE
2525import JSONSchema.Types (Schema(..), Spec(..))
2626import qualified JSONSchema.Types as JT
2727import qualified JSONSchema.Validator.Draft4 as D4
28−import JSONSchema.Validator.Reference (updateResolutionScope)
28+import JSONSchema.Validator.Reference (BaseURI(..),
29+ Scope(..),
30+ updateResolutionScope)
2931
3032--------------------------------------------------
3133-- * Basic fetching tools
@@ -45,22 +47,38 @@ draft4FetchInfo = FE.FetchInfo embedded (lookup "id") (lookup "$ref")
4547 Just (String t) -> Just t
4648 _ -> Nothing
4749
50+-- | An implementation of 'JT.embedded'.
4851embedded :: Schema -> ([Schema], [Schema])
49−embedded s = JT.embedded (d4Spec (ReferencedSchemas s mempty) mempty Nothing) s
52+embedded s =
53+ JT.embedded (d4Spec mempty mempty (Scope s Nothing (BaseURI Nothing))) s
5054
5155--------------------------------------------------
5256-- * Main API
5357--------------------------------------------------
5458
5559validate
56− :: ReferencedSchemas Schema
57− -> Maybe Text
58− -> Schema
60+ :: URISchemaMap Schema
61+ -> SchemaWithURI Schema
5962 -> Value
6063 -> [ValidatorFailure]
61−validate rs = continueValidating rs (D4.VisitedSchemas [(Nothing, Nothing)])
64+validate schemaMap sw =
65+ JT.validate (d4Spec schemaMap visited scope) (_swSchema sw)
66+ where
67+ visited :: D4.VisitedSchemas
68+ visited = D4.VisitedSchemas [(Nothing, Nothing)]
69+
70+ schemaId :: Maybe Text
71+ schemaId = FE._fiId draft4FetchInfo (_swSchema sw)
6272
63−-- A schema for schemas themselves, using @src/draft4.json@ which is loaded
73+ scope :: Scope Schema
74+ scope = Scope
75+ { _topLevelDocument = _swSchema sw
76+ , _documentURI = _swURI sw
77+ , _currentBaseURI = updateResolutionScope (BaseURI (_swURI sw))
78+ schemaId
79+ }
80+
81+-- | A schema for schemas themselves. Uses @src/draft4.json@ which is loaded
6482-- at compile time.
6583metaSchema :: Schema
6684metaSchema =
@@ -69,47 +87,57 @@ metaSchema =
6987 $ metaSchemaBytes
7088
7189checkSchema :: Schema -> [ValidatorFailure]
72−checkSchema = validate referenced Nothing metaSchema . Object . _unSchema
90+checkSchema = validate schemaMap (SchemaWithURI metaSchema Nothing)
91+ . Object
92+ . _unSchema
7393 where
74− referenced :: ReferencedSchemas Schema
75− referenced = ReferencedSchemas
76− metaSchema
77− (HM.singleton "http://json-schema.org/draft-04/schema"
94+ schemaMap :: URISchemaMap Schema
95+ schemaMap =
96+ URISchemaMap (HM.singleton "http://json-schema.org/draft-04/schema"
7897 metaSchema)
7998
8099--------------------------------------------------
81100-- * Spec
82101--------------------------------------------------
83102
84−continueValidating
85− :: ReferencedSchemas Schema
103+validateSubschema
104+ :: URISchemaMap Schema
86105 -> D4.VisitedSchemas
87− -> Maybe Text
106+ -> Scope Schema
88107 -> Schema
89108 -> Value
90109 -> [ValidatorFailure]
91−continueValidating referenced visited mURI sc =
92− JT.validate (d4Spec referenced visited newScope) sc
110+validateSubschema schemaMap visited scope schema =
111+ JT.validate (d4Spec schemaMap visited newScope) schema
93112 where
94113 schemaId :: Maybe Text
95− schemaId = case HM.lookup "id" (_unSchema sc) of
96− Just (String t) -> Just t
97− _ -> Nothing
114+ schemaId = FE._fiId draft4FetchInfo schema
98115
99− newScope :: Maybe Text
100− newScope = updateResolutionScope mURI schemaId
116+ newScope :: Scope Schema
117+ newScope = scope
118+ { _currentBaseURI = updateResolutionScope (_currentBaseURI scope)
119+ schemaId
120+ }
101121
102122d4Spec
103− :: ReferencedSchemas Schema
123+ :: URISchemaMap Schema
104124 -> D4.VisitedSchemas
105− -> Maybe Text
125+ -> Scope Schema
106126 -> Spec Schema ValidatorFailure
107127 -- ^ Here we reuses 'ValidatorFailure' from
108128 -- 'JSONSchema.Draft4.Failure'. If your validators have different
109129 -- failure possibilities you'll need to create your own validator
110130 -- failure type.
111−d4Spec referenced visited scope =
112− Spec
131+d4Spec schemaMap visited scope =
132+ Spec $
133+ [ dimap
134+ f
135+ FailureRef
136+ (D4.refValidator (FE.getReference schemaMap) updateScope
137+ valRef visited scope)
138+ ]
139+
140+ <> fmap (lmap disableIfRefPresent)
113141 [ dimap f FailureMultipleOf D4.multipleOfValidator
114142 , dimap f FailureMaximum D4.maximumValidator
115143 , dimap f FailureMinimum D4.minimumValidator
@@ -127,6 +155,7 @@ d4Spec referenced visited scope =
127155 D4.IRInvalidItems e -> FailureItems e
128156 D4.IRInvalidAdditional e -> FailureAdditionalItems e)
129157 (D4.itemsRelatedValidator descend)
158+ , lmap f D4.definitionsEmbedded
130159
131160 , dimap f FailureMaxProperties D4.maxPropertiesValidator
132161 , dimap f FailureMinProperties D4.minPropertiesValidator
@@ -137,10 +166,6 @@ d4Spec referenced visited scope =
137166 FailurePropertiesRelated
138167 (D4.propertiesRelatedValidator descend)
139168
140− , dimap
141− f
142− FailureRef
143− (D4.refValidator visited scope (FE.getReference referenced) getRef)
144169 , dimap f FailureEnum D4.enumValidator
145170 , dimap f FailureType D4.typeValidator
146171 , dimap f FailureAllOf (D4.allOfValidator lateral)
@@ -150,22 +175,31 @@ d4Spec referenced visited scope =
150175 ]
151176 where
152177 f :: FromJSON a => Schema -> Maybe a
153− f (Schema a) = case AE.fromJSON (Object a) of
154− AE.Error _ -> Nothing
155− AE.Success b -> Just b
156−
157− -- 'Maybe Text' is the URI the referenced schema is fetched from,
158− -- this probably needs a 'newtype' wrapper.
159− getRef
178+ f (Schema a) =
179+ case AE.fromJSON (Object a) of
180+ AE.Error _ -> Nothing
181+ AE.Success b -> Just b
182+
183+ disableIfRefPresent :: Schema -> Schema
184+ disableIfRefPresent schema =
185+ case FE._fiRef draft4FetchInfo schema of
186+ Nothing -> schema
187+ Just _ -> Schema mempty
188+
189+ updateScope :: BaseURI -> Schema -> BaseURI
190+ updateScope uri schema =
191+ updateResolutionScope uri (FE._fiId draft4FetchInfo schema)
192+
193+ valRef
160194 :: D4.VisitedSchemas
161− -> Maybe Text
195+ -> Scope Schema
162196 -> Schema
163197 -> Value
164198 -> [ValidatorFailure]
165− getRef = continueValidating referenced
199+ valRef vis sc = JT.validate (d4Spec schemaMap vis sc)
166200
167201 descend :: Schema -> Value -> [ValidatorFailure]
168− descend = continueValidating referenced mempty scope
202+ descend = validateSubschema schemaMap mempty scope
169203
170204 lateral :: Schema -> Value -> [ValidatorFailure]
171− lateral = continueValidating referenced visited scope
205+ lateral = validateSubschema schemaMap visited scope