{-# OPTIONS --safe --cubical #-}
module OWL2.OBOGraph.Schema where
open import Agda.Builtin.Nat using (zero; suc)
open import Agda.Builtin.String using (primShowNat; primStringAppend)
open import OWL2.Prelude
import FF.Json.Native as JSON
import OWL2.OBOGraph.Decode as Decode
infixr 5 _<>_
_<>_ : String → String → String
_<>_ =
primStringAppend
showNat : ℕ → String
showNat =
primShowNat
indexPath : String → ℕ → String
indexPath path n =
path <> "[" <> showNat n <> "]"
data SchemaSeverity : Type₀ where
schemaError schemaWarning : SchemaSeverity
data StringFieldState : Type₀ where
stringFieldMissing stringFieldMalformed stringFieldValid : StringFieldState
record SchemaDiagnostic : Type₀ where
constructor schemaDiagnostic
field
diagnosticSeverity : SchemaSeverity
diagnosticPath : String
diagnosticMessage : String
open SchemaDiagnostic public
schemaErrorAt : String → String → SchemaDiagnostic
schemaErrorAt =
schemaDiagnostic schemaError
schemaWarningAt : String → String → SchemaDiagnostic
schemaWarningAt =
schemaDiagnostic schemaWarning
schemaDiagnosticCount : List SchemaDiagnostic → ℕ
schemaDiagnosticCount [] =
zero
schemaDiagnosticCount (x ∷ xs) =
suc (schemaDiagnosticCount xs)
NoSchemaDiagnostics : List SchemaDiagnostic → Type₀
NoSchemaDiagnostics diagnostics =
diagnostics ≡ []
fieldPath : String → String → String
fieldPath path key =
path <> "." <> key
unknownFieldDiagnostics :
String → String → List String → List (String × JSON.JsonValue) →
List SchemaDiagnostic
unknownFieldDiagnostics path label known [] =
[]
unknownFieldDiagnostics path label known ((key , value) ∷ fields)
with Decode.stringIn key known
... | true =
unknownFieldDiagnostics path label known fields
... | false =
schemaWarningAt (fieldPath path key) ("ignored " <> label <> " field " <> key) ∷
unknownFieldDiagnostics path label known fields
duplicateFieldDiagnostics :
String → List (String × JSON.JsonValue) → List SchemaDiagnostic
duplicateFieldDiagnostics path [] =
[]
duplicateFieldDiagnostics path ((key , value) ∷ fields) with Decode.lookupField key fields
... | present laterValue =
schemaWarningAt (fieldPath path key) ("duplicate object field " <> key) ∷
duplicateFieldDiagnostics path fields
... | absent =
duplicateFieldDiagnostics path fields
expectStringField :
String → String → List (String × JSON.JsonValue) → List SchemaDiagnostic
expectStringField path key fields with Decode.lookupField key fields
... | absent =
[]
... | present value with Decode.asString value
... | present text =
[]
... | absent =
schemaWarningAt (fieldPath path key) "expected string field" ∷ []
expectStringEnumField :
String → String → List String → String →
List (String × JSON.JsonValue) → List SchemaDiagnostic
expectStringEnumField path key allowed message fields with Decode.lookupField key fields
... | absent =
[]
... | present value with Decode.asString value
... | absent =
schemaWarningAt (fieldPath path key) "expected string field" ∷ []
... | present text with Decode.stringIn text allowed
... | true =
[]
... | false =
schemaWarningAt (fieldPath path key) message ∷ []
nodeTypeValues : List String
nodeTypeValues =
"CLASS" ∷ "INDIVIDUAL" ∷ "PROPERTY" ∷ []
propertyTypeValues : List String
propertyTypeValues =
"OBJECT" ∷ "DATA" ∷ "ANNOTATION" ∷ []
stringFieldState : String → List (String × JSON.JsonValue) → StringFieldState
stringFieldState key fields with Decode.lookupField key fields
... | absent =
stringFieldMissing
... | present value with Decode.asString value
... | present text =
stringFieldValid
... | absent =
stringFieldMalformed
requireStringField :
String → String → List (String × JSON.JsonValue) → List SchemaDiagnostic
requireStringField path key fields with Decode.lookupField key fields
... | absent =
schemaWarningAt (fieldPath path key) "missing required string field" ∷ []
... | present value with Decode.asString value
... | present text =
[]
... | absent =
schemaWarningAt (fieldPath path key) "expected required string field" ∷ []
expectBoolField :
String → String → List (String × JSON.JsonValue) → List SchemaDiagnostic
expectBoolField path key fields with Decode.lookupField key fields
... | absent =
[]
... | present value with Decode.asBool value
... | present b =
[]
... | absent =
schemaWarningAt (fieldPath path key) "expected boolean field" ∷ []
expectObjectField :
String → String → List (String × JSON.JsonValue) →
(String → List (String × JSON.JsonValue) → List SchemaDiagnostic) →
List SchemaDiagnostic
expectObjectField path key fields validate with Decode.lookupField key fields
... | absent =
[]
... | present value with Decode.asObject value
... | present objectFields =
validate (fieldPath path key) objectFields
... | absent =
schemaWarningAt (fieldPath path key) "expected object field" ∷ []
expectStringArrayItems :
String → ℕ → List JSON.JsonValue → List SchemaDiagnostic
expectStringArrayItems path n [] =
[]
expectStringArrayItems path n (value ∷ values) with Decode.asString value
... | present text =
expectStringArrayItems path (suc n) values
... | absent =
schemaWarningAt (indexPath path n) "expected string array item" ∷
expectStringArrayItems path (suc n) values
expectStringArrayField :
String → String → List (String × JSON.JsonValue) → List SchemaDiagnostic
expectStringArrayField path key fields with Decode.lookupField key fields
... | absent =
[]
... | present value with Decode.asArray value
... | present values =
expectStringArrayItems (fieldPath path key) zero values
... | absent =
schemaWarningAt (fieldPath path key) "expected string array field" ∷ []
validateXrefObjectItem : String → JSON.JsonValue → List SchemaDiagnostic
validateXrefObjectItem path value with Decode.asObject value
... | present fields =
duplicateFieldDiagnostics path fields ++
requireStringField path "val" fields ++
expectStringField path "lbl" fields ++
expectStringField path "pred" fields ++
expectStringArrayField path "xrefs" fields ++
expectObjectField path "meta" fields (λ path fields → []) ++
unknownFieldDiagnostics
path
"xref"
("lbl" ∷ "pred" ∷ "val" ∷ "xrefs" ∷ "meta" ∷ [])
fields
... | absent =
schemaWarningAt path "expected xref object" ∷ []
validateXrefObjectItems : String → ℕ → List JSON.JsonValue → List SchemaDiagnostic
validateXrefObjectItems path n [] =
[]
validateXrefObjectItems path n (value ∷ values) =
validateXrefObjectItem (indexPath path n) value ++
validateXrefObjectItems path (suc n) values
expectXrefObjectArrayField :
String → String → List (String × JSON.JsonValue) → List SchemaDiagnostic
expectXrefObjectArrayField path key fields with Decode.lookupField key fields
... | absent =
[]
... | present value with Decode.asArray value
... | present values =
validateXrefObjectItems (fieldPath path key) zero values
... | absent =
schemaWarningAt (fieldPath path key) "expected xref array field" ∷ []
expectArrayField :
String → String → List (String × JSON.JsonValue) →
(String → ℕ → List JSON.JsonValue → List SchemaDiagnostic) →
List SchemaDiagnostic
expectArrayField path key fields validate with Decode.lookupField key fields
... | absent =
[]
... | present value with Decode.asArray value
... | present values =
validate (fieldPath path key) zero values
... | absent =
schemaWarningAt (fieldPath path key) "expected array field" ∷ []
validateMetaPropertyValue : String → List (String × JSON.JsonValue) → List SchemaDiagnostic
validateMetaPropertyValue path fields =
duplicateFieldDiagnostics path fields ++
requireStringField path "pred" fields ++
requireStringField path "val" fields ++
expectStringArrayField path "xrefs" fields ++
expectObjectField path "meta" fields (λ path fields → []) ++
expectStringField path "valType" fields ++
unknownFieldDiagnostics
path
"property value"
("pred" ∷ "val" ∷ "xrefs" ∷ "meta" ∷ "valType" ∷ [])
fields
validateMetaPropertyValues :
String → ℕ → List JSON.JsonValue → List SchemaDiagnostic
validateMetaPropertyValues path n [] =
[]
validateMetaPropertyValues path n (value ∷ values) with Decode.asObject value
... | present fields =
validateMetaPropertyValue (indexPath path n) fields ++
validateMetaPropertyValues path (suc n) values
... | absent =
schemaWarningAt (indexPath path n) "expected property value object" ∷
validateMetaPropertyValues path (suc n) values
validateSynonym : String → List (String × JSON.JsonValue) → List SchemaDiagnostic
validateSynonym path fields =
duplicateFieldDiagnostics path fields ++
expectStringField path "synonymType" fields ++
expectStringField path "pred" fields ++
requireStringField path "val" fields ++
expectStringArrayField path "xrefs" fields ++
expectObjectField path "meta" fields (λ path fields → []) ++
unknownFieldDiagnostics
path
"synonym"
("synonymType" ∷ "pred" ∷ "val" ∷ "xrefs" ∷ "meta" ∷ [])
fields
validateSynonyms : String → ℕ → List JSON.JsonValue → List SchemaDiagnostic
validateSynonyms path n [] =
[]
validateSynonyms path n (value ∷ values) with Decode.asObject value
... | present fields =
validateSynonym (indexPath path n) fields ++
validateSynonyms path (suc n) values
... | absent =
schemaWarningAt (indexPath path n) "expected synonym object" ∷
validateSynonyms path (suc n) values
validateDefinition : String → JSON.JsonValue → List SchemaDiagnostic
validateDefinition path value with Decode.asString value
... | present text =
[]
... | absent with Decode.asObject value
... | present fields =
duplicateFieldDiagnostics path fields ++
expectStringField path "pred" fields ++
requireStringField path "val" fields ++
expectStringArrayField path "xrefs" fields ++
expectObjectField path "meta" fields (λ path fields → []) ++
unknownFieldDiagnostics
path
"definition"
("pred" ∷ "val" ∷ "xrefs" ∷ "meta" ∷ [])
fields
... | absent =
schemaWarningAt path "expected definition string or object" ∷ []
validateMetaFields : String → List (String × JSON.JsonValue) → List SchemaDiagnostic
validateMetaFields path fields =
duplicateFieldDiagnostics path fields ++
validateDefinitionField ++
expectStringArrayField path "comments" fields ++
expectXrefObjectArrayField path "xrefs" fields ++
expectStringArrayField path "subsets" fields ++
expectArrayField path "synonyms" fields validateSynonyms ++
expectArrayField path "basicPropertyValues" fields validateMetaPropertyValues ++
expectStringField path "version" fields ++
expectBoolField path "deprecated" fields ++
unknownFieldDiagnostics
path
"meta"
("definition" ∷ "comments" ∷ "xrefs" ∷ "subsets" ∷ "synonyms" ∷
"basicPropertyValues" ∷ "version" ∷ "deprecated" ∷ [])
fields
where
validateDefinitionField : List SchemaDiagnostic
validateDefinitionField with Decode.lookupField "definition" fields
... | absent =
[]
... | present value =
validateDefinition (fieldPath path "definition") value
validateMetaValue : String → JSON.JsonValue → List SchemaDiagnostic
validateMetaValue path value with Decode.asObject value
... | present fields =
validateMetaFields path fields
... | absent =
schemaWarningAt path "expected meta object" ∷ []
expectMetaField :
String → String → List (String × JSON.JsonValue) → List SchemaDiagnostic
expectMetaField path key fields with Decode.lookupField key fields
... | absent =
[]
... | present value =
validateMetaValue (fieldPath path key) value
validateNode : String → List (String × JSON.JsonValue) → List SchemaDiagnostic
validateNode path fields =
duplicateFieldDiagnostics path fields ++
requireStringField path "id" fields ++
expectStringField path "lbl" fields ++
expectStringEnumField
path
"type"
nodeTypeValues
"expected node type CLASS/INDIVIDUAL/PROPERTY"
fields ++
expectStringEnumField
path
"propertyType"
propertyTypeValues
"expected property type OBJECT/DATA/ANNOTATION"
fields ++
expectMetaField path "meta" fields ++
unknownFieldDiagnostics
path
"node"
("id" ∷ "lbl" ∷ "type" ∷ "propertyType" ∷ "meta" ∷ [])
fields
validateNodes : String → ℕ → List JSON.JsonValue → List SchemaDiagnostic
validateNodes path n [] =
[]
validateNodes path n (value ∷ values) with Decode.asObject value
... | present fields =
validateNode (indexPath path n) fields ++
validateNodes path (suc n) values
... | absent =
schemaWarningAt (indexPath path n) "expected node object" ∷
validateNodes path (suc n) values
requireEdgeSubject : String → List (String × JSON.JsonValue) → List SchemaDiagnostic
requireEdgeSubject path fields with stringFieldState "sub" fields
... | stringFieldValid =
[]
... | stringFieldMalformed =
schemaWarningAt (fieldPath path "sub") "expected required string field" ∷ []
... | stringFieldMissing with stringFieldState "subj" fields
... | stringFieldValid =
[]
... | stringFieldMalformed =
schemaWarningAt (fieldPath path "subj") "expected required string field" ∷ []
... | stringFieldMissing =
schemaWarningAt path "missing required edge subject field sub/subj" ∷ []
validateEdge : String → List (String × JSON.JsonValue) → List SchemaDiagnostic
validateEdge path fields =
duplicateFieldDiagnostics path fields ++
requireEdgeSubject path fields ++
requireStringField path "pred" fields ++
requireStringField path "obj" fields ++
expectMetaField path "meta" fields ++
unknownFieldDiagnostics
path
"edge"
("sub" ∷ "subj" ∷ "pred" ∷ "obj" ∷ "meta" ∷ [])
fields
validateEdges : String → ℕ → List JSON.JsonValue → List SchemaDiagnostic
validateEdges path n [] =
[]
validateEdges path n (value ∷ values) with Decode.asObject value
... | present fields =
validateEdge (indexPath path n) fields ++
validateEdges path (suc n) values
... | absent =
schemaWarningAt (indexPath path n) "expected edge object" ∷
validateEdges path (suc n) values
validateRestriction : String → List (String × JSON.JsonValue) → List SchemaDiagnostic
validateRestriction path fields =
duplicateFieldDiagnostics path fields ++
requireStringField path "propertyId" fields ++
requireStringField path "fillerId" fields ++
unknownFieldDiagnostics
path
"restriction"
("propertyId" ∷ "fillerId" ∷ [])
fields
validateRestrictions : String → ℕ → List JSON.JsonValue → List SchemaDiagnostic
validateRestrictions path n [] =
[]
validateRestrictions path n (value ∷ values) with Decode.asObject value
... | present fields =
validateRestriction (indexPath path n) fields ++
validateRestrictions path (suc n) values
... | absent =
schemaWarningAt (indexPath path n) "expected restriction object" ∷
validateRestrictions path (suc n) values
validateLogicalDefinitionAxiom :
String → List (String × JSON.JsonValue) → List SchemaDiagnostic
validateLogicalDefinitionAxiom path fields =
duplicateFieldDiagnostics path fields ++
requireStringField path "definedClassId" fields ++
expectStringArrayField path "genusIds" fields ++
expectArrayField path "restrictions" fields validateRestrictions ++
expectMetaField path "meta" fields ++
unknownFieldDiagnostics
path
"logical definition axiom"
("definedClassId" ∷ "genusIds" ∷ "restrictions" ∷ "meta" ∷ [])
fields
validateLogicalDefinitionAxioms :
String → ℕ → List JSON.JsonValue → List SchemaDiagnostic
validateLogicalDefinitionAxioms path n [] =
[]
validateLogicalDefinitionAxioms path n (value ∷ values) with Decode.asObject value
... | present fields =
validateLogicalDefinitionAxiom (indexPath path n) fields ++
validateLogicalDefinitionAxioms path (suc n) values
... | absent =
schemaWarningAt (indexPath path n) "expected logical definition axiom object" ∷
validateLogicalDefinitionAxioms path (suc n) values
validateDomainRangeAxiom :
String → List (String × JSON.JsonValue) → List SchemaDiagnostic
validateDomainRangeAxiom path fields =
duplicateFieldDiagnostics path fields ++
requireStringField path "predicateId" fields ++
expectStringArrayField path "domainClassIds" fields ++
expectStringArrayField path "rangeClassIds" fields ++
expectArrayField path "allValuesFromEdges" fields validateEdges ++
expectMetaField path "meta" fields ++
unknownFieldDiagnostics
path
"domain/range axiom"
("predicateId" ∷ "domainClassIds" ∷ "rangeClassIds" ∷
"allValuesFromEdges" ∷ "meta" ∷ [])
fields
validateDomainRangeAxioms :
String → ℕ → List JSON.JsonValue → List SchemaDiagnostic
validateDomainRangeAxioms path n [] =
[]
validateDomainRangeAxioms path n (value ∷ values) with Decode.asObject value
... | present fields =
validateDomainRangeAxiom (indexPath path n) fields ++
validateDomainRangeAxioms path (suc n) values
... | absent =
schemaWarningAt (indexPath path n) "expected domain/range axiom object" ∷
validateDomainRangeAxioms path (suc n) values
validatePropertyChainAxiom :
String → List (String × JSON.JsonValue) → List SchemaDiagnostic
validatePropertyChainAxiom path fields =
duplicateFieldDiagnostics path fields ++
requireStringField path "predicateId" fields ++
expectStringArrayField path "chainPredicateIds" fields ++
expectMetaField path "meta" fields ++
unknownFieldDiagnostics
path
"property-chain axiom"
("predicateId" ∷ "chainPredicateIds" ∷ "meta" ∷ [])
fields
validatePropertyChainAxioms :
String → ℕ → List JSON.JsonValue → List SchemaDiagnostic
validatePropertyChainAxioms path n [] =
[]
validatePropertyChainAxioms path n (value ∷ values) with Decode.asObject value
... | present fields =
validatePropertyChainAxiom (indexPath path n) fields ++
validatePropertyChainAxioms path (suc n) values
... | absent =
schemaWarningAt (indexPath path n) "expected property-chain axiom object" ∷
validatePropertyChainAxioms path (suc n) values
validateEquivalentNodesSet :
String → List (String × JSON.JsonValue) → List SchemaDiagnostic
validateEquivalentNodesSet path fields =
duplicateFieldDiagnostics path fields ++
expectStringField path "representativeNodeId" fields ++
expectStringArrayField path "nodeIds" fields ++
expectMetaField path "meta" fields ++
unknownFieldDiagnostics
path
"equivalent nodes set"
("representativeNodeId" ∷ "nodeIds" ∷ "meta" ∷ [])
fields
validateEquivalentNodesSets :
String → ℕ → List JSON.JsonValue → List SchemaDiagnostic
validateEquivalentNodesSets path n [] =
[]
validateEquivalentNodesSets path n (value ∷ values) with Decode.asObject value
... | present fields =
validateEquivalentNodesSet (indexPath path n) fields ++
validateEquivalentNodesSets path (suc n) values
... | absent =
schemaWarningAt (indexPath path n) "expected equivalent nodes set object" ∷
validateEquivalentNodesSets path (suc n) values
validateGraph : String → List (String × JSON.JsonValue) → List SchemaDiagnostic
validateGraph path fields =
duplicateFieldDiagnostics path fields ++
expectStringField path "id" fields ++
expectStringField path "lbl" fields ++
expectMetaField path "meta" fields ++
expectArrayField path "nodes" fields validateNodes ++
expectArrayField path "edges" fields validateEdges ++
expectArrayField path "equivalentNodesSets" fields validateEquivalentNodesSets ++
expectArrayField path "logicalDefinitionAxioms" fields validateLogicalDefinitionAxioms ++
expectArrayField path "domainRangeAxioms" fields validateDomainRangeAxioms ++
expectArrayField path "propertyChainAxioms" fields validatePropertyChainAxioms ++
unknownFieldDiagnostics
path
"graph"
("id" ∷ "lbl" ∷ "meta" ∷ "nodes" ∷ "edges" ∷
"equivalentNodesSets" ∷ "logicalDefinitionAxioms" ∷
"domainRangeAxioms" ∷ "propertyChainAxioms" ∷ [])
fields
validateGraphs : String → ℕ → List JSON.JsonValue → List SchemaDiagnostic
validateGraphs path n [] =
[]
validateGraphs path n (value ∷ values) with Decode.asObject value
... | present fields =
validateGraph (indexPath path n) fields ++
validateGraphs path (suc n) values
... | absent =
schemaWarningAt (indexPath path n) "expected graph object" ∷
validateGraphs path (suc n) values
schemaDiagnostics : JSON.JsonValue → List SchemaDiagnostic
schemaDiagnostics value with Decode.asObject value
... | absent =
schemaErrorAt "$" "expected top-level object" ∷ []
... | present fields =
duplicateFieldDiagnostics "$" fields ++
expectObjectField "$" "meta" fields validateMetaFields ++
validateGraphDocumentGraphs fields ++
unknownFieldDiagnostics
"$"
"document"
("@context" ∷ "meta" ∷ "graphs" ∷ [])
fields
where
validateGraphDocumentGraphs :
List (String × JSON.JsonValue) → List SchemaDiagnostic
validateGraphDocumentGraphs fields with Decode.lookupField "graphs" fields
... | absent =
schemaWarningAt "$.graphs" "missing required top-level graphs array" ∷ []
... | present graphsValue with Decode.asArray graphsValue
... | absent =
schemaErrorAt "$.graphs" "expected top-level graphs array" ∷ []
... | present graphs =
validateGraphs "$.graphs" zero graphs
SchemaClean : JSON.JsonValue → Type₀
SchemaClean value =
NoSchemaDiagnostics (schemaDiagnostics value)