Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

258 shape #277

Merged
merged 11 commits into from
Oct 25, 2023
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,13 @@ docker run \
skohub/skohub-vocabs-docker:latest
```

## Validation of SKOS files

During the build the provided SKOS files are validated against this [SkoHub SHACL shape](https://github.com/skohub-io/shapes/blob/main/skohub.shacl.ttl).
The SkoHub SHACL shape is an opinionated and more restrictive version of the generic SKOS shape you can find in the same repo: https://github.com/skohub-io/shapes

If the SKOS file violates the shape, the build will error and stop.
If you just hit warnings you will see them in the console output.

## Serve from other location than root (`/`)

Expand Down
8 changes: 8 additions & 0 deletions gatsby-node.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const { i18n, getFilePath, parseLanguages } = require("./src/common")
const context = require("./src/context")
const queries = require("./src/queries")
const types = require("./src/types")
const { validate } = require("./src/validate.js")

require("dotenv").config()
require("graceful-fs").gracefulify(require("fs"))
Expand Down Expand Up @@ -104,6 +105,13 @@ exports.onPreBootstrap = async ({ createContentDigest, actions, getNode }) => {
console.info(`Found these turtle files:`)
ttlFiles.forEach((e) => console.info(e))
for (const f of ttlFiles) {
try {
console.info("Validating: ", f)
await validate("shapes/skohub.shacl.ttl", f)
} catch (e) {
console.error(e)
throw e
}
const ttlString = fs.readFileSync(f).toString()
const doc = await jsonld.fromRDF(ttlString, { format: "text/turtle" })
const compacted = await jsonld.compact(doc, context.jsonld)
Expand Down
2,786 changes: 1,674 additions & 1,112 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"dependencies": {
"@emotion/react": "^11.10.5",
"@gatsbyjs/reach-router": "^2.0.0",
"@rdfjs/parser-n3": "^2.0.1",
"crypto-browserify": "^3.12.0",
"dotenv": "^16.0.3",
"flexsearch": "^0.7.31",
Expand All @@ -26,12 +27,15 @@
"n3": "^1.16.3",
"omit-empty": "^1.0.0",
"prop-types": "^15.7.2",
"rdf-ext": "^2.3.0",
"rdf-validate-shacl": "^0.5.1",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"react-helmet": "^6.1.0",
"stream-browserify": "^3.0.0"
},
"devDependencies": {
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@testing-library/cypress": "^9.0.0",
"@testing-library/jest-dom": "^6.0.0",
"@testing-library/react": "^14.0.0",
Expand Down
256 changes: 256 additions & 0 deletions shapes/skohub.shacl.ttl
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
@prefix : <http://skohub.io/skohub-shacl> .
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix xml: <http://www.w3.org/XML/1998/namespace> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix skos: <http://www.w3.org/2004/02/skos/core#> .
@prefix dct: <http://purl.org/dc/terms/> .
@prefix sdo: <https://schema.org> .
@prefix vann: <http://purl.org/vocab/vann/> .

# rdfs:comment holds info with what file under ./tests/invalid/skohub.shacl.ttl
# the constraint is tested

# ConceptScheme
:ConceptSchemeShape
a sh:NodeShape ;
sh:targetClass skos:ConceptScheme ;
sh:property [
sh:path dct:title ;
sh:minCount 1;
sh:datatype rdf:langString ;
sh:message "Concept Scheme has no dct:title with a language tag!" ;
sh:severity sh:Violation ;
rdfs:comment "Tested with 01_cs_no_title.ttl" ;
] ;
sh:property [
sh:path skos:hasTopConcept ;
sh:minCount 1 ;
sh:severity sh:Violation ;
sh:message "A SKOS Concept Scheme should at least have one top Concept" ;
rdfs:comment "Tested with 02_cs_one_top_concept.ttl" ;
] ;
sh:property [
sh:path skos:hasTopConcept ;
sh:class skos:Concept ;
sh:minCount 1 ;
sh:severity sh:Violation ;
sh:message "The target class for hasTopConcept should be skos:Concept" ;
rdfs:comment "Tested with 03_cs_target_class_hasTopConcept.ttl" ;
] ;
sh:property [
sh:path dct:description ;
sh:datatype rdf:langString ;
sh:severity sh:Warning ;
sh:minCount 1 ;
sh:message: "A description of the Concept Scheme should be provided." ;
rdfs:comment "Tested with 04_cs_no_description.ttl" ;
rdfs:comment "Tested with 05_cs_description_no_langstring.ttl" ;
] ;
sh:property [
sh:path dct:license ;
sh:minCount 1 ;
sh:nodeKind sh:IRI ;
sh:severity sh:Warning ;
sh:message "A provided license increases reusability of a vocabulary. Should be an URI." ;
rdfs:comment "Tested with 06_cs_no_license.ttl" ;
rdfs:comment "Tested with 07_cs_license_wrong_nodekind.ttl" ;
] ;
sh:property [
sh:path vann:preferredNamespaceUri ;
sh:minCount 1 ;
sh:datatype xsd:string ;
sh:severity sh:Warning ;
sh:message "A preferred Namespace URI should be given as a string, especially if you want to use your vocabulary in reconciliation services." ;
rdfs:comment "Tested with 08_cs_no_prefNamespaceUri.ttl" ;
rdfs:comment "Tested with 09_cs_prefNamespace_wrong_datatype.ttl" ;
] ;
.

# Concept
:ConceptShape
a sh:NodeShape ;
sh:targetClass skos:Concept ;
sh:property [
sh:path skos:prefLabel ;
sh:minCount 1 ;
sh:datatype rdf:langString ;
sh:uniqueLang true ;
sh:message "Each skos:Concept has to provide a skos:prefLabel in a unique language" ;
sh:severity: sh:Violation ;
rdfs:comment "Tested with 10_c_no_prefLabel.ttl" ;
] ;
sh:property [
sh:path skos:prefLabel ;
sh:severity sh:Violation ;
sh:datatype rdf:langString ;
sh:message "Preferred label should be provided with a language tag." ;
rdfs:comment "Tested with 11_c_no_language.ttl" ;
] ;
sh:property [
sh:path skos:altLabel ;
sh:severity sh:Violation ;
sh:datatype rdf:langString ;
sh:message "Alternative label should be provided with a language tag." ;
rdfs:comment "Tested with 12_c_altLabel_no_language.ttl" ;
] ;
sh:property [
sh:path skos:hiddenLabel ;
sh:severity sh:Violation ;
sh:datatype rdf:langString ;
sh:message "Hidden label should be provided with a language tag." ;
rdfs:comment "Tested with 13_c_hiddenLabel_no_language.ttl" ;
] ;
sh:property [
sh:path skos:definition ;
sh:severity sh:Violation ;
sh:uniqueLang true ;
sh:datatype rdf:langString ;
sh:message "Definition should be provided with a unique language tag." ;
rdfs:comment "Tested with 14_c_definition_no_language.ttl" ;
rdfs:comment "Tested with 15_c_definition_no_unique_language.ttl" ;
] ;
sh:property [
sh:path skos:scopeNote ;
sh:severity sh:Violation ;
sh:datatype rdf:langString ;
sh:message "Scope Note should be provided with a language tag." ;
rdfs:comment "Tested with 16_c_scopeNote_no_language.ttl" ;
] ;
sh:property [
sh:path skos:note ;
sh:severity sh:Violation ;
sh:datatype rdf:langString ;
sh:message "Note should be provided with a language tag." ;
rdfs:comment "Tested with 17_c_note_no_language.ttl" ;
] ;
sh:property [
sh:path skos:notation ;
sh:severity sh:Violation ;
sh:datatype xsd:string ;
sh:message "Notation should be provided as a string." ;
rdfs:comment "Tested with 18_c_notation_no_string.ttl" ;
] ;
sh:property [
sh:path skos:example ;
sh:severity sh:Violation ;
sh:datatype rdf:langString ;
sh:message "Example should be provided with a language tag." ;
rdfs:comment "Tested with 19_c_example_no_language.ttl" ;
] ;
sh:property [
sh:path skos:narrower ;
sh:class skos:Concept ;
sh:severity sh:Violation ;
sh:message "Target class of skos:narrower should be a skos:Concept" ;
rdfs:comment "Tested with 20_c_narrower_target_no_concept.ttl" ;
] ;
sh:property [
sh:class skos:Concept ;
sh:path skos:narrowerTransitive ;
sh:severity sh:Violation ;
sh:message "Target class of skos:narrowerTransitive should be a skos:Concept" ;
rdfs:comment "Tested with 21_c_narrowerTransitive_target_no_concept.ttl" ;
] ;
sh:property [
sh:path skos:narrowMatch ;
sh:nodeKind sh:IRI ;
sh:severity sh:Violation ;
sh:message "Target class of skos:narrowMatch should be a URI" ;
rdfs:comment "Tested with 22_c_narrowMatch_target_no_iri.ttl" ;
] ;
sh:property [
sh:path skos:broader ;
sh:class skos:Concept ;
sh:severity sh:Violation ;
sh:message "Target class of skos:broader should be a skos:Concept" ;
rdfs:comment "Tested with 23_c_broader_no_concept.ttl" ;
] ;
sh:property [
sh:path skos:broaderTransitive ;
sh:class skos:Concept ;
sh:severity sh:Violation ;
sh:message "Target class of skos:broaderTransitive should be a skos:Concept" ;
rdfs:comment "Tested with 24_c_broaderTransitive_no_concept.ttl" ;
] ;
sh:property [
sh:path skos:broadMatch ;
sh:nodeKind sh:IRI ;
sh:severity sh:Violation ;
sh:message "Target class of skos:broadMatch should be a URI" ;
rdfs:comment "Tested with 25_c_broadMatch_no_iri.ttl" ;
] ;
sh:property [
sh:path skos:related ;
sh:class skos:Concept ;
sh:severity sh:Violation ;
sh:message "Target class of skos:related should be a skos:Concept" ;
rdfs:comment "Tested with 26_c_related_no_concept.ttl" ;
] ;
sh:property [
sh:path skos:relatedMatch ;
sh:nodeKind sh:IRI ;
sh:severity sh:Violation ;
sh:message "Target class of skos:relatedMatch should be a URI" ;
rdfs:comment "Tested with 27_c_relatedMatch_no_iri.ttl" ;
] ;
sh:property [
sh:path skos:closeMatch ;
sh:nodeKind sh:IRI ;
sh:severity sh:Violation ;
sh:message "Target class of skos:closeMatch should be a URI" ;
rdfs:comment "Tested with 28_c_closeMatch_no_iri.ttl" ;
] ;
sh:property [
sh:path skos:exactMatch ;
sh:nodeKind sh:IRI ;
sh:severity sh:Violation ;
sh:message "Target class of skos:exactMatch should be a URI" ;
rdfs:comment "Tested with 29_c_exactMatch_no_iri.ttl" ;
] ;
sh:property [
sh:path skos:inScheme ;
sh:class skos:ConceptScheme ;
sh:severity sh:Violation ;
sh:message "Target class of skos:inScheme should be a skos:ConceptScheme" ;
rdfs:comment "Tested with 30_c_inScheme_target_no_cs.ttl" ;
] ;
sh:property [
sh:path skos:topConceptOf ;
sh:class skos:ConceptScheme ;
sh:severity sh:Violation ;
sh:message "Target class of skos:topConceptOf should be a skos:ConceptScheme" ;
rdfs:comment "Tested with 31_c_topConceptOf_target_no_conceptScheme.ttl" ;
] ;
.

:CollectionShape
a sh:NodeShape ;
sh:targetClass skos:Collection ;
sh:property [
sh:path skos:prefLabel ;
sh:severity sh:Violation ;
sh:datatype rdf:langString ;
sh:message "Preferred label should be provided with a language tag." ;
rdfs:comment "Tested with 33_collection_prefLabel_no_language.ttl" ;
] ;
sh:property [
sh:path skos:prefLabel ;
sh:minCount 1 ;
sh:datatype rdf:langString ;
sh:uniqueLang true ;
sh:message "Each skos:Collection has to provide a skos:prefLabel in a unique language" ;
sh:severity: sh:Warning ;
rdfs:comment "Tested with 34_collection_prefLabel_no_unique_language.ttl" ;
] ;
sh:property [
sh:path skos:member ;
sh:class skos:Concept ;
sh:severity sh:Violation ;
sh:message "The object of skos:member should be a skos:Concept" ;
rdfs:comment "Tested with 35_collection_member_no_concept.ttl" ;
]
.

Loading