From cda8bcc0023ec6094bf55a95a51ab3b6f2f71870 Mon Sep 17 00:00:00 2001 From: Giacomo Citi Date: Mon, 16 Oct 2023 16:09:13 +0200 Subject: [PATCH 1/5] use a copy of cube.link shapes --- cli/lib/commands/publish.ts | 1 + cli/pipelines/publish.ttl | 51 +++++- cli/shapes.ttl | 80 +-------- cli/standalone-constraint-constraint.ttl | 217 +++++++++++++++++++++++ 4 files changed, 269 insertions(+), 80 deletions(-) create mode 100644 cli/standalone-constraint-constraint.ttl diff --git a/cli/lib/commands/publish.ts b/cli/lib/commands/publish.ts index e8d4a8292..e99b6a9ca 100644 --- a/cli/lib/commands/publish.ts +++ b/cli/lib/commands/publish.ts @@ -43,6 +43,7 @@ export default runner.create({ variable.set('metadata', $rdf.dataset()) // this should be possible as relative path in pipeline ttl but does not work variable.set('shapesPath', path.resolve(__dirname, '../../shapes.ttl')) + variable.set('cubeShapesPath', path.resolve(__dirname, '../../standalone-constraint-constraint.ttl')) if (cubeCreatorVersion) { variable.set('cubeCreatorVersion', cubeCreatorVersion) diff --git a/cli/pipelines/publish.ttl b/cli/pipelines/publish.ttl index 4f91e5070..43546694a 100644 --- a/cli/pipelines/publish.ttl +++ b/cli/pipelines/publish.ttl @@ -59,7 +59,7 @@ code:link ] ; code:arguments - [ code:name "shape" ; code:value <#loadShapes> ] , + [ code:name "shape" ; code:value <#concatShapes> ] , [ code:name "maxErrors" ; code:value 100 ] , [ code:name "onViolation" ; @@ -67,6 +67,29 @@ ] ; . +<#concatShapes> a :Pipeline, :ReadableObjectMode ; + :steps [ + :stepList + ( + <#loadAllShapes> + ) + ]. + + +<#loadAllShapes> + a :Step ; + code:implementedBy + [ + a code:EcmaScriptModule ; + code:link + ] ; + code:arguments + ( + <#loadShapes> + <#loadCubeShapes> + ) +. + <#loadShapes> a :Pipeline, :ReadableObjectMode ; :steps @@ -93,6 +116,32 @@ ) ] . +<#loadCubeShapes> + a :Pipeline, :ReadableObjectMode ; + :steps + [ + :stepList + ( + [ + a :Step ; + code:implementedBy + [ + code:link ; + a code:EcmaScriptModule ; + ] ; + code:arguments ( "cubeShapesPath"^^:VariableName ) + ] + [ + a :Step ; + code:implementedBy + [ + code:link ; + a code:EcmaScriptModule ; + ] ; + ] + ) + ] . + <#flatten> a :Step ; code:implementedBy [ diff --git a/cli/shapes.ttl b/cli/shapes.ttl index 952a250e1..2b5f2aaaa 100644 --- a/cli/shapes.ttl +++ b/cli/shapes.ttl @@ -25,7 +25,7 @@ base sh:message "cube:Cube needs at least one cube:ObservationSet" ; ] , [ sh:path cube:observationConstraint ; - sh:node ; + sh:node ; # from cube.link sh:message "cube:Cube must point to a valid cube:Constraint" ; ] ; . @@ -60,84 +60,6 @@ base ] ; . - - a sh:NodeShape ; - sh:property [ - # we assume at least 3 dimensions, otherwise we would have an empty list of dimensions - # one for cube:observedBy, one for rdf:type and at least one cube dimension - sh:path sh:property ; - sh:minCount 3 ; - sh:message "cube:Constraint needs at least {$minCount} sh:properties" ; - ] , [ - sh:path sh:property ; - sh:node ; - ] , [ - sh:path sh:closed ; - sh:hasValue true ; - ] ; -. - - a sh:NodeShape; - sh:property [ - sh:path qudt:scaleType ; - sh:in ( qudt:IntervalScale qudt:NominalScale qudt:EnumerationScale qudt:RatioScale qudt:OrdinalScale) ; - sh:message "If qudt:scale is used it needs to be within" ; - ] , [ - sh:path sh:path ; - sh:minCount 1 ; - sh:maxCount 1 ; - sh:message "a sh:path is needed on a property" ; - ] , [ - sh:path sh:in ; - sh:node ; - sh:message "sh:in needs to be a list" ; - ] , [ - sh:message "needs a schema:name" ; - sh:or ( - [ - sh:path schema:name ; - sh:minCount 1 ; - sh:datatype xsd:string ; - ] - [ - sh:path schema:name ; - sh:minCount 1 ; - sh:datatype rdf:langString ; - ] - [ - sh:path sh:path ; - sh:in (rdf:type cube:observedBy) ; - ] - ) ; - ] , [ - sh:message "needs a sh:datatype or sh:nodeKind" ; - sh:or ( - [ - sh:path sh:datatype ; - sh:minCount 1 ; - ] - [ - sh:path sh:nodeKind ; - sh:minCount 1 ; - ] - ) ; - ] ; -. - -# Testing proper rdf:list construction - a sh:NodeShape ; - sh:property [ - sh:path rdf:first ; - sh:minCount 1 ; - sh:maxCount 1 ; - ] , [ - sh:path rdf:rest ; - sh:minCount 1 ; - sh:maxCount 1 ; - sh:message "a rdf:List can only have one rdf:rest node, multiples nodes need to be linked" ; - #sh:node ; - ] ; -. a sh:NodeShape ; diff --git a/cli/standalone-constraint-constraint.ttl b/cli/standalone-constraint-constraint.ttl new file mode 100644 index 000000000..0766ddeed --- /dev/null +++ b/cli/standalone-constraint-constraint.ttl @@ -0,0 +1,217 @@ +@base . +@prefix dash: . +@prefix rdf: . +@prefix rdfs: . +@prefix schema: . +@prefix sh: . +@prefix xsd: . +@prefix cube: . +@prefix meta: . +@prefix qudt: . + +# +# This is the bare minimal SHACL shape for validating a Cube Constraint. +# All Cube Constraints should pass this validation. +# + + + a sh:NodeShape ; + sh:targetClass cube:Constraint ; + sh:property [ + # we assume at least 3 dimensions, otherwise we would have an empty list of dimensions + # one for cube:observedBy, one for rdf:type and at least one cube dimension + sh:path sh:property ; + sh:minCount 3 ; + sh:message "cube:Constraint needs at least a certain amount of sh:properties" + ] ; + sh:property [ + sh:path sh:property ; + sh:node ; + sh:message "The constraints do not validate" + ] ; + sh:property [ + sh:path sh:closed; + sh:hasValue true; + ] ; + sh:property [ + sh:path meta:inHierarchy; + sh:node ; + sh:message "meta:inHierarchy does not validate" + ] ; + . + + a sh:NodeShape; + sh:property [ + sh:path qudt:scaleType; + sh:in ( qudt:IntervalScale qudt:NominalScale qudt:EnumerationScale qudt:RatioScale qudt:OrdinalScale) ; + sh:maxCount 1; + sh:message "If qudt:scaleType is used it needs to be within ( qudt:IntervalScale qudt:NominalScale qudt:EnumerationScale qudt:RatioScale qudt:OrdinalScale )" + ]; + sh:property [ + sh:path sh:path; + sh:minCount 1; + sh:maxCount 1; + sh:message "a sh:path is needed on a property" + ]; + sh:property [ + sh:path sh:minInclusive; + sh:nodeType sh:Literal; + sh:message "sh:minInclusive needs to be a literal" + ]; + sh:property [ + sh:path sh:in; + sh:node ; + sh:message "sh:in needs to be a list" + ]; + sh:property [ + sh:path sh:maxInclusive; + sh:nodeType sh:Literal; + sh:message "sh:maxInclusive needs to be a literal" + ]; + sh:property [ + sh:path meta:dimensionRelation; + sh:node ; + sh:message "meta:dimensionRelation does not validate" + ]; + + sh:property [ + sh:message "needs a schema:name" ; + sh:or( + [ + sh:path schema:name; + sh:minCount 1; + sh:or ( [ sh:datatype xsd:string ] [ sh:datatype rdf:langString ] ) ; + ] + [ + sh:path sh:path; + sh:in (rdf:type cube:observedBy); + ] + ); + ]; + + sh:property [ + sh:message "needs a sh:datatype, sh:nodeKind or sh:datatype within sh:or (...)" ; + sh:or( + [ + sh:path sh:datatype; + sh:minCount 1; + ] + [ + sh:path sh:nodeKind; + sh:minCount 1; + ] + [ + sh:path sh:or; + sh:minCount 1; + sh:node ; + sh:node [ + sh:path ( [ sh:zeroOrMorePath rdf:rest ] rdf:first ) ; # all list elements + sh:property [ sh:path sh:datatype ; sh:minCount 1 ] ; # have at least one datatype + ] + ] + ); + ] ; + +. + + + a sh:NodeShape ; + sh:property [ + sh:path meta:relatesTo; + sh:nodeKind sh:IRI ; + sh:minCount 1; + sh:message "meta:dimensionRelation requires at least one meta:relatesTo"; + ] . + + +# Testing proper rdf:list construction + a sh:NodeShape ; + sh:targetClass rdf:List ; + sh:property [ + sh:path rdf:first; + sh:minCount 1; + sh:maxCount 1; + ]; + sh:property [ + sh:path rdf:rest; + sh:minCount 1; + sh:maxCount 1; + sh:or ( + [ + sh:node ; + ] + [ + sh:hasValue rdf:nil; + ] + ) ; + sh:message "a rdf:List can only have one rdf:rest node, multiples nodes need to be linked" + #sh:node ; + ] + . + + a sh:NodeShape ; + sh:property [ + sh:path sh:inversePath; + sh:nodeKind sh:IRI; + sh:minCount 1; + sh:maxCount 1; + sh:message "nextInHierarchy requires sh:path to be IRI or [ sh:inversePath ... ]" + ] . + + a sh:NodeShape ; + sh:property [ + sh:path sh:path; + sh:minCount 1; + sh:maxCount 1; + sh:message "nextInHierarchy requires exactly one sh:path" + ], + [ + sh:path schema:name; + sh:minCount 1; + sh:message "nextInHierarchy requires schema:name" + ], + [ + sh:path sh:targetClass; + sh:nodeKind sh:IRI; + sh:message "meta:nextInHierarchy/sh:targetClass must be an IRI" + ], + [ + sh:path meta:nextInHierarchy; + sh:node ; + sh:severity sh:Info; + sh:message "nextInHierarchy can have nested nodes" + ] ; + sh:or ( + [ + sh:path sh:path; + sh:nodeKind sh:IRI; + sh:message "nextInHierarchy requires sh:path to be IRI or [ sh:inversePath ... ]" + ] + [ + sh:path sh:path; + sh:nodeKind sh:BlankNode; + sh:node ; + sh:message "nextInHierarchy requires sh:path to be IRI or [ sh:inversePath ... ]" + ] + ) + . + + a sh:NodeShape ; + sh:targetClass meta:Hierarchy ; + sh:property [ + sh:path meta:hierarchyRoot; + sh:minCount 1; + sh:nodeKind sh:IRI; + sh:message "inHierarchy requires hierarchyRoot"; + ], + [ + sh:path schema:name; + sh:minCount 1; + sh:message "inHierarchy requires schema:name" + ], + [ + sh:path meta:nextInHierarchy; + sh:node ; + sh:minCount 1; + sh:message "inHierarchy requires a conform nextInHierarchy" + ] . \ No newline at end of file From ec0f6d0fb0d19055e157aa8e538b5af14d41b287 Mon Sep 17 00:00:00 2001 From: Giacomo Citi Date: Fri, 20 Oct 2023 10:19:44 +0200 Subject: [PATCH 2/5] dereference cube.link shapes --- cli/lib/commands/publish.ts | 1 - cli/package.json | 1 + cli/pipelines/publish.ttl | 72 ++++++++++++++++++++++++++++--------- 3 files changed, 56 insertions(+), 18 deletions(-) diff --git a/cli/lib/commands/publish.ts b/cli/lib/commands/publish.ts index e99b6a9ca..e8d4a8292 100644 --- a/cli/lib/commands/publish.ts +++ b/cli/lib/commands/publish.ts @@ -43,7 +43,6 @@ export default runner.create({ variable.set('metadata', $rdf.dataset()) // this should be possible as relative path in pipeline ttl but does not work variable.set('shapesPath', path.resolve(__dirname, '../../shapes.ttl')) - variable.set('cubeShapesPath', path.resolve(__dirname, '../../standalone-constraint-constraint.ttl')) if (cubeCreatorVersion) { variable.set('cubeCreatorVersion', cubeCreatorVersion) diff --git a/cli/package.json b/cli/package.json index 53b5d6445..0da89c734 100644 --- a/cli/package.json +++ b/cli/package.json @@ -46,6 +46,7 @@ "barnard59-base": "^1.1.0", "barnard59-formats": "^1.1.0", "barnard59-graph-store": "^1.0.0", + "barnard59-http": "^1.1.1", "barnard59-rdf": "^1.0.0", "barnard59-validate-shacl": "^0.3.8", "body-parser": "^1.19.0", diff --git a/cli/pipelines/publish.ttl b/cli/pipelines/publish.ttl index 43546694a..4c697a7c0 100644 --- a/cli/pipelines/publish.ttl +++ b/cli/pipelines/publish.ttl @@ -122,26 +122,64 @@ [ :stepList ( - [ - a :Step ; - code:implementedBy - [ - code:link ; - a code:EcmaScriptModule ; - ] ; - code:arguments ( "cubeShapesPath"^^:VariableName ) - ] - [ - a :Step ; - code:implementedBy - [ - code:link ; - a code:EcmaScriptModule ; - ] ; - ] + <#shapeURLs> + <#getShapes> ) ] . +<#shapeURLs> a :Step ; + code:implementedBy [ + a code:EcmaScriptModule ; + code:link ; + ] ; + code:arguments ( + """[ + 'https://cube.link/v0.0.5/shape/standalone-constraint-constraint', + // 'https://cube.link/v0.0.5/shape/datacatalog-constraint', + ]"""^^code:EcmaScript + ) + . + +<#getShapes> a :Step ; + code:implementedBy [ + a code:EcmaScriptModule ; + code:link ; + ] ; + code:arguments ( <#getShape> "shapeURL" ) + . + +<#getShape> a :Pipeline , :ReadableObjectMode; + :steps + [ + :stepList + ( + <#fetch> + <#parse> + ) + ] . + +<#fetch> a :Step ; + code:implementedBy + [ + a code:EcmaScriptModule ; + code:link + ] ; + code:arguments + [ + code:name "url"; + code:value "shapeURL"^^:VariableName ; + ] +. + +<#parse> a :Step ; + code:implementedBy + [ + code:link ; + a code:EcmaScriptModule ; + ] + . + + <#flatten> a :Step ; code:implementedBy [ From a56948fe4fcb5877aebf62c856a3d80dd058a5ab Mon Sep 17 00:00:00 2001 From: Giacomo Citi Date: Mon, 23 Oct 2023 08:56:07 +0200 Subject: [PATCH 3/5] remove copy of cube.link shapes --- cli/standalone-constraint-constraint.ttl | 217 ----------------------- 1 file changed, 217 deletions(-) delete mode 100644 cli/standalone-constraint-constraint.ttl diff --git a/cli/standalone-constraint-constraint.ttl b/cli/standalone-constraint-constraint.ttl deleted file mode 100644 index 0766ddeed..000000000 --- a/cli/standalone-constraint-constraint.ttl +++ /dev/null @@ -1,217 +0,0 @@ -@base . -@prefix dash: . -@prefix rdf: . -@prefix rdfs: . -@prefix schema: . -@prefix sh: . -@prefix xsd: . -@prefix cube: . -@prefix meta: . -@prefix qudt: . - -# -# This is the bare minimal SHACL shape for validating a Cube Constraint. -# All Cube Constraints should pass this validation. -# - - - a sh:NodeShape ; - sh:targetClass cube:Constraint ; - sh:property [ - # we assume at least 3 dimensions, otherwise we would have an empty list of dimensions - # one for cube:observedBy, one for rdf:type and at least one cube dimension - sh:path sh:property ; - sh:minCount 3 ; - sh:message "cube:Constraint needs at least a certain amount of sh:properties" - ] ; - sh:property [ - sh:path sh:property ; - sh:node ; - sh:message "The constraints do not validate" - ] ; - sh:property [ - sh:path sh:closed; - sh:hasValue true; - ] ; - sh:property [ - sh:path meta:inHierarchy; - sh:node ; - sh:message "meta:inHierarchy does not validate" - ] ; - . - - a sh:NodeShape; - sh:property [ - sh:path qudt:scaleType; - sh:in ( qudt:IntervalScale qudt:NominalScale qudt:EnumerationScale qudt:RatioScale qudt:OrdinalScale) ; - sh:maxCount 1; - sh:message "If qudt:scaleType is used it needs to be within ( qudt:IntervalScale qudt:NominalScale qudt:EnumerationScale qudt:RatioScale qudt:OrdinalScale )" - ]; - sh:property [ - sh:path sh:path; - sh:minCount 1; - sh:maxCount 1; - sh:message "a sh:path is needed on a property" - ]; - sh:property [ - sh:path sh:minInclusive; - sh:nodeType sh:Literal; - sh:message "sh:minInclusive needs to be a literal" - ]; - sh:property [ - sh:path sh:in; - sh:node ; - sh:message "sh:in needs to be a list" - ]; - sh:property [ - sh:path sh:maxInclusive; - sh:nodeType sh:Literal; - sh:message "sh:maxInclusive needs to be a literal" - ]; - sh:property [ - sh:path meta:dimensionRelation; - sh:node ; - sh:message "meta:dimensionRelation does not validate" - ]; - - sh:property [ - sh:message "needs a schema:name" ; - sh:or( - [ - sh:path schema:name; - sh:minCount 1; - sh:or ( [ sh:datatype xsd:string ] [ sh:datatype rdf:langString ] ) ; - ] - [ - sh:path sh:path; - sh:in (rdf:type cube:observedBy); - ] - ); - ]; - - sh:property [ - sh:message "needs a sh:datatype, sh:nodeKind or sh:datatype within sh:or (...)" ; - sh:or( - [ - sh:path sh:datatype; - sh:minCount 1; - ] - [ - sh:path sh:nodeKind; - sh:minCount 1; - ] - [ - sh:path sh:or; - sh:minCount 1; - sh:node ; - sh:node [ - sh:path ( [ sh:zeroOrMorePath rdf:rest ] rdf:first ) ; # all list elements - sh:property [ sh:path sh:datatype ; sh:minCount 1 ] ; # have at least one datatype - ] - ] - ); - ] ; - -. - - - a sh:NodeShape ; - sh:property [ - sh:path meta:relatesTo; - sh:nodeKind sh:IRI ; - sh:minCount 1; - sh:message "meta:dimensionRelation requires at least one meta:relatesTo"; - ] . - - -# Testing proper rdf:list construction - a sh:NodeShape ; - sh:targetClass rdf:List ; - sh:property [ - sh:path rdf:first; - sh:minCount 1; - sh:maxCount 1; - ]; - sh:property [ - sh:path rdf:rest; - sh:minCount 1; - sh:maxCount 1; - sh:or ( - [ - sh:node ; - ] - [ - sh:hasValue rdf:nil; - ] - ) ; - sh:message "a rdf:List can only have one rdf:rest node, multiples nodes need to be linked" - #sh:node ; - ] - . - - a sh:NodeShape ; - sh:property [ - sh:path sh:inversePath; - sh:nodeKind sh:IRI; - sh:minCount 1; - sh:maxCount 1; - sh:message "nextInHierarchy requires sh:path to be IRI or [ sh:inversePath ... ]" - ] . - - a sh:NodeShape ; - sh:property [ - sh:path sh:path; - sh:minCount 1; - sh:maxCount 1; - sh:message "nextInHierarchy requires exactly one sh:path" - ], - [ - sh:path schema:name; - sh:minCount 1; - sh:message "nextInHierarchy requires schema:name" - ], - [ - sh:path sh:targetClass; - sh:nodeKind sh:IRI; - sh:message "meta:nextInHierarchy/sh:targetClass must be an IRI" - ], - [ - sh:path meta:nextInHierarchy; - sh:node ; - sh:severity sh:Info; - sh:message "nextInHierarchy can have nested nodes" - ] ; - sh:or ( - [ - sh:path sh:path; - sh:nodeKind sh:IRI; - sh:message "nextInHierarchy requires sh:path to be IRI or [ sh:inversePath ... ]" - ] - [ - sh:path sh:path; - sh:nodeKind sh:BlankNode; - sh:node ; - sh:message "nextInHierarchy requires sh:path to be IRI or [ sh:inversePath ... ]" - ] - ) - . - - a sh:NodeShape ; - sh:targetClass meta:Hierarchy ; - sh:property [ - sh:path meta:hierarchyRoot; - sh:minCount 1; - sh:nodeKind sh:IRI; - sh:message "inHierarchy requires hierarchyRoot"; - ], - [ - sh:path schema:name; - sh:minCount 1; - sh:message "inHierarchy requires schema:name" - ], - [ - sh:path meta:nextInHierarchy; - sh:node ; - sh:minCount 1; - sh:message "inHierarchy requires a conform nextInHierarchy" - ] . \ No newline at end of file From 20676f486896206bcf5e8e890eb654ddc8e2516d Mon Sep 17 00:00:00 2001 From: Tomasz Pluskiewicz Date: Tue, 7 Nov 2023 20:55:23 +0100 Subject: [PATCH 4/5] Create violet-dogs-help.md --- .changeset/violet-dogs-help.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/violet-dogs-help.md diff --git a/.changeset/violet-dogs-help.md b/.changeset/violet-dogs-help.md new file mode 100644 index 000000000..14342dbb1 --- /dev/null +++ b/.changeset/violet-dogs-help.md @@ -0,0 +1,5 @@ +--- +"@cube-creator/cli": major +--- + +Use [cube.link shapes](https://github.com/zazuko/cube-link/tree/main/validation) for validation From 2fbd704dafb52aa965492c4027293823b6f6e043 Mon Sep 17 00:00:00 2001 From: Giacomo Citi Date: Wed, 8 Nov 2023 17:19:07 +0100 Subject: [PATCH 5/5] use cube.link shapes v0.1.0 --- cli/pipelines/publish.ttl | 4 ++-- cli/shapes.ttl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cli/pipelines/publish.ttl b/cli/pipelines/publish.ttl index 4c697a7c0..bed836bda 100644 --- a/cli/pipelines/publish.ttl +++ b/cli/pipelines/publish.ttl @@ -134,8 +134,8 @@ ] ; code:arguments ( """[ - 'https://cube.link/v0.0.5/shape/standalone-constraint-constraint', - // 'https://cube.link/v0.0.5/shape/datacatalog-constraint', + 'https://cube.link/v0.1.0/shape/standalone-constraint-constraint', + // 'https://cube.link/v0.1.0/shape/datacatalog-constraint', ]"""^^code:EcmaScript ) . diff --git a/cli/shapes.ttl b/cli/shapes.ttl index 2b5f2aaaa..e316c4497 100644 --- a/cli/shapes.ttl +++ b/cli/shapes.ttl @@ -25,7 +25,7 @@ base sh:message "cube:Cube needs at least one cube:ObservationSet" ; ] , [ sh:path cube:observationConstraint ; - sh:node ; # from cube.link + sh:node ; # from cube.link sh:message "cube:Cube must point to a valid cube:Constraint" ; ] ; .