rdf-validate-shacl
Advanced tools
Comparing version 0.3.0 to 0.3.1
# Changelog | ||
## 0.3.1 (2021-05-03) | ||
* Use provided data factory everywhere | ||
[[#52][https://github.com/zazuko/rdf-validate-shacl/issues/52]] | ||
[[#62][https://github.com/zazuko/rdf-validate-shacl/pull/62]] | ||
## 0.3.0 (2021-04-13) | ||
@@ -14,3 +19,2 @@ | ||
## 0.2.6 (2021-02-22) | ||
@@ -22,3 +26,2 @@ | ||
## 0.2.5 (2020-12-21) | ||
@@ -30,3 +33,2 @@ | ||
## 0.2.4 (2020-10-20) | ||
@@ -36,3 +38,2 @@ | ||
## 0.2.3 (2020-07-28) | ||
@@ -42,3 +43,2 @@ | ||
## 0.2.2 (2020-06-04) | ||
@@ -48,3 +48,2 @@ | ||
## 0.2.1 (2020-05-25) | ||
@@ -54,3 +53,2 @@ | ||
## 0.2.0 (2020-05-25) | ||
@@ -62,3 +60,2 @@ | ||
## 0.1.3 (2020-04-23) | ||
@@ -69,3 +66,2 @@ | ||
## 0.1.2 (2020-04-21) | ||
@@ -79,3 +75,2 @@ | ||
## 0.1.1 (2020-04-07) | ||
@@ -85,5 +80,4 @@ | ||
## 0.1.0 (2020-04-01) | ||
* Initial release |
const clownface = require('clownface') | ||
const DataFactory = require('./src/data-factory') | ||
const { prepareNamespaces } = require('./src/namespaces') | ||
const ShapesGraph = require('./src/shapes-graph') | ||
@@ -20,3 +20,4 @@ const ValidationEngine = require('./src/validation-engine') | ||
this.factory = new DataFactory(options.factory || require('@rdfjs/dataset')) | ||
this.factory = options.factory || require('@rdfjs/dataset') | ||
this.ns = prepareNamespaces(this.factory) | ||
this.loadShapes(shapes) | ||
@@ -23,0 +24,0 @@ this.validationEngine = new ValidationEngine(this, options) |
{ | ||
"name": "rdf-validate-shacl", | ||
"version": "0.3.0", | ||
"version": "0.3.1", | ||
"description": "RDF SHACL validator", | ||
@@ -34,3 +34,3 @@ "main": "index.js", | ||
"@rdfjs/parser-n3": "^1.1.4", | ||
"@zazuko/rdf-vocabularies": "^2020.11.3", | ||
"@zazuko/rdf-vocabularies": "^2021.3.31", | ||
"get-stream": "^6.0.0", | ||
@@ -37,0 +37,0 @@ "mocha": "^8.3.0", |
@@ -8,2 +8,4 @@ | ||
We provide a [SHACL playground](https://zazuko.github.io/shacl-playground/) based on this library. | ||
## Usage | ||
@@ -10,0 +12,0 @@ |
const NodeSet = require('./node-set') | ||
const { rdf, rdfs } = require('./namespaces') | ||
@@ -10,2 +9,3 @@ /** | ||
* @param {Term} startNode | ||
* @returns Array of quads | ||
*/ | ||
@@ -29,13 +29,14 @@ function extractStructure (dataset, startNode) { | ||
* | ||
* @param {Clownface} pointer | ||
* @param {NamedNode} $class | ||
* @param {Clownface} cls - pointer to a class | ||
* @param {Object} ns - namespace | ||
* @returns NodeSet | ||
*/ | ||
function getInstancesOf (pointer, $class) { | ||
const classes = getSubClassesOf(pointer, $class) | ||
classes.add($class) | ||
function getInstancesOf (cls, ns) { | ||
const classes = getSubClassesOf(cls, ns) | ||
classes.add(cls.term) | ||
return [...classes].reduce((acc, cls) => { | ||
const classInstances = pointer | ||
.node(cls) | ||
.in(rdf.type) | ||
return [...classes].reduce((acc, classTerm) => { | ||
const classInstances = cls | ||
.node(classTerm) | ||
.in(ns.rdf.type) | ||
.terms | ||
@@ -52,13 +53,9 @@ | ||
* | ||
* @param {Clownface} pointer | ||
* @param {NamedNode} $class | ||
* @param {Clownface} cls - pointer to a class | ||
*/ | ||
function getSubClassesOf (pointer, $class) { | ||
const subclasses = pointer | ||
.node($class) | ||
.in(rdfs.subClassOf) | ||
.terms | ||
function getSubClassesOf (cls, ns) { | ||
const subclasses = cls.in(ns.rdfs.subClassOf) | ||
const transubclasses = subclasses.reduce((acc, cls) => { | ||
const scs = getSubClassesOf(pointer, cls) | ||
const transubclasses = subclasses.toArray().reduce((acc, subclass) => { | ||
const scs = getSubClassesOf(subclass, ns) | ||
@@ -70,3 +67,3 @@ acc.addAll(scs) | ||
return new NodeSet([...subclasses, ...transubclasses]) | ||
return new NodeSet([...subclasses.terms, ...transubclasses]) | ||
} | ||
@@ -77,15 +74,12 @@ | ||
* | ||
* @param {Clownface} pointer | ||
* @param {Term} $instance | ||
* @param {NamedNode} $class | ||
* @param {Clownface} instance - pointer to a term | ||
* @param {Clownface} cls - pointer to a class | ||
* @param {Object} ns - namespace | ||
* @returns boolean | ||
*/ | ||
function isInstanceOf (pointer, $instance, $class) { | ||
const classes = getSubClassesOf(pointer, $class) | ||
classes.add($class) | ||
function isInstanceOf (instance, cls, ns) { | ||
const classes = getSubClassesOf(cls, ns) | ||
classes.add(cls.term) | ||
const types = pointer | ||
.node($instance) | ||
.out(rdf.type) | ||
.terms | ||
const types = instance.out(ns.rdf.type).terms | ||
@@ -98,9 +92,7 @@ return types.some((type) => classes.has(type)) | ||
* | ||
* @param {Clownface} pointer | ||
* @param {Term} listNode - Start of the list | ||
* @param {Clownface} listNode - pointer to start of the list | ||
* @returns Array | ||
*/ | ||
function rdfListToArray (pointer, listNode) { | ||
const iterator = pointer.node(listNode).list() | ||
return [...iterator].map(({ term }) => term) | ||
function rdfListToArray (listNode) { | ||
return [...listNode.list()].map(({ term }) => term) | ||
} | ||
@@ -107,0 +99,0 @@ |
const NodeSet = require('./node-set') | ||
const { rdf, sh } = require('./namespaces') | ||
const { rdfListToArray } = require('./dataset-utils') | ||
@@ -9,48 +7,45 @@ /** | ||
* | ||
* @param {Clownface} graph | ||
* @param {Term} pathNode - Start node of the path | ||
* @param {Clownface} pathNode - Pointer to the start node of the path | ||
* @return Property path object | ||
*/ | ||
function extractPropertyPath (graph, pathNode) { | ||
if (pathNode.termType === 'NamedNode') { | ||
return pathNode | ||
function extractPropertyPath (pathNode, ns) { | ||
if (pathNode.term.termType === 'NamedNode') { | ||
return pathNode.term | ||
} | ||
if (pathNode.termType === 'BlankNode') { | ||
const pathCf = graph.node(pathNode) | ||
const first = pathCf.out(rdf.first).term | ||
if (pathNode.term.termType === 'BlankNode') { | ||
const first = pathNode.out(ns.rdf.first).term | ||
if (first) { | ||
const paths = rdfListToArray(graph, pathNode) | ||
return paths.map(path => extractPropertyPath(graph, path)) | ||
const paths = [...pathNode.list()] | ||
return paths.map(path => extractPropertyPath(path, ns)) | ||
} | ||
const alternativePath = pathCf.out(sh.alternativePath).term | ||
if (alternativePath) { | ||
const paths = rdfListToArray(graph, alternativePath) | ||
return { or: paths.map(path => extractPropertyPath(graph, path)) } | ||
const alternativePath = pathNode.out(ns.sh.alternativePath) | ||
if (alternativePath.term) { | ||
const paths = [...alternativePath.list()] | ||
return { or: paths.map(path => extractPropertyPath(path, ns)) } | ||
} | ||
const zeroOrMorePath = pathCf.out(sh.zeroOrMorePath).term | ||
if (zeroOrMorePath) { | ||
return { zeroOrMore: extractPropertyPath(graph, zeroOrMorePath) } | ||
const zeroOrMorePath = pathNode.out(ns.sh.zeroOrMorePath) | ||
if (zeroOrMorePath.term) { | ||
return { zeroOrMore: extractPropertyPath(zeroOrMorePath, ns) } | ||
} | ||
const oneOrMorePath = pathCf.out(sh.oneOrMorePath).term | ||
if (oneOrMorePath) { | ||
return { oneOrMore: extractPropertyPath(graph, oneOrMorePath) } | ||
const oneOrMorePath = pathNode.out(ns.sh.oneOrMorePath) | ||
if (oneOrMorePath.term) { | ||
return { oneOrMore: extractPropertyPath(oneOrMorePath, ns) } | ||
} | ||
const zeroOrOnePath = pathCf.out(sh.zeroOrOnePath).term | ||
if (zeroOrOnePath) { | ||
return { zeroOrOne: extractPropertyPath(graph, zeroOrOnePath) } | ||
const zeroOrOnePath = pathNode.out(ns.sh.zeroOrOnePath) | ||
if (zeroOrOnePath.term) { | ||
return { zeroOrOne: extractPropertyPath(zeroOrOnePath, ns) } | ||
} | ||
const inversePath = pathCf.out(sh.inversePath).term | ||
if (inversePath) { | ||
return { inverse: extractPropertyPath(graph, inversePath) } | ||
const inversePath = pathNode.out(ns.sh.inversePath) | ||
if (inversePath.term) { | ||
return { inverse: extractPropertyPath(inversePath, ns) } | ||
} | ||
} | ||
throw new Error(`Unsupported SHACL path: ${pathNode.value}`) | ||
throw new Error(`Unsupported SHACL path: ${pathNode.term.value}`) | ||
} | ||
@@ -57,0 +52,0 @@ |
@@ -23,3 +23,2 @@ // Design: | ||
const { extractPropertyPath, getPathObjects } = require('./property-path') | ||
const { rdfs, sh } = require('./namespaces') | ||
const { getInstancesOf, isInstanceOf } = require('./dataset-utils') | ||
@@ -32,34 +31,35 @@ | ||
// Collect all defined constraint components | ||
const componentNodes = getInstancesOf(context.$shapes, sh.ConstraintComponent) | ||
this.components = [...componentNodes].map((node) => new ConstraintComponent(node, context)) | ||
const { sh } = context.ns | ||
const componentNodes = getInstancesOf(context.$shapes.node(sh.ConstraintComponent), context.ns) | ||
this._components = [...componentNodes].map((node) => new ConstraintComponent(node, context)) | ||
// Build map from parameters to constraint components | ||
this.parametersMap = {} | ||
for (const component of this.components) { | ||
this._parametersMap = new Map() | ||
for (const component of this._components) { | ||
for (const parameter of component.parameters) { | ||
this.parametersMap[parameter.value] = component | ||
this._parametersMap.set(parameter.value, component) | ||
} | ||
} | ||
// Collection of shapes is populated on demand - here we remember the instances | ||
this.shapes = {} // Keys are the URIs/bnode ids of the shape nodes | ||
// Cache of shapes populated on demand | ||
this._shapes = new Map() | ||
} | ||
getComponentWithParameter (parameter) { | ||
return this.parametersMap[parameter.value] | ||
return this._parametersMap.get(parameter.value) | ||
} | ||
getShape (shapeNode) { | ||
let shape = this.shapes[shapeNode.value] | ||
if (!shape) { | ||
shape = new Shape(this.context, shapeNode) | ||
this.shapes[shapeNode.value] = shape | ||
if (!this._shapes.has(shapeNode.value)) { | ||
const shape = new Shape(this.context, shapeNode) | ||
this._shapes.set(shapeNode.value, shape) | ||
} | ||
return shape | ||
return this._shapes.get(shapeNode.value) | ||
} | ||
getShapeNodesWithConstraints () { | ||
if (!this.shapeNodesWithConstraints) { | ||
get shapeNodesWithConstraints () { | ||
if (!this._shapeNodesWithConstraints) { | ||
const set = new NodeSet() | ||
for (const component of this.components) { | ||
for (const component of this._components) { | ||
const params = component.requiredParameters | ||
@@ -73,16 +73,16 @@ for (const param of params) { | ||
} | ||
this.shapeNodesWithConstraints = [...set] | ||
this._shapeNodesWithConstraints = [...set] | ||
} | ||
return this.shapeNodesWithConstraints | ||
return this._shapeNodesWithConstraints | ||
} | ||
getShapesWithTarget () { | ||
const $shapes = this.context.$shapes | ||
get shapesWithTarget () { | ||
const { $shapes, ns } = this.context | ||
const { rdfs, sh } = ns | ||
if (!this.targetShapes) { | ||
this.targetShapes = [] | ||
const shapeNodes = this.getShapeNodesWithConstraints() | ||
for (const shapeNode of shapeNodes) { | ||
if ( | ||
isInstanceOf($shapes, shapeNode, rdfs.Class) || | ||
if (!this._shapesWithTarget) { | ||
this._shapesWithTarget = this.shapeNodesWithConstraints | ||
.filter((shapeNode) => ( | ||
isInstanceOf($shapes.node(shapeNode), $shapes.node(rdfs.Class), ns) || | ||
$shapes.node(shapeNode).out([ | ||
@@ -95,9 +95,7 @@ sh.targetClass, | ||
]).terms.length > 0 | ||
) { | ||
this.targetShapes.push(this.getShape(shapeNode)) | ||
} | ||
} | ||
)) | ||
.map((shapeNode) => this.getShape(shapeNode)) | ||
} | ||
return this.targetShapes | ||
return this._shapesWithTarget | ||
} | ||
@@ -125,5 +123,8 @@ } | ||
constructor (node, context) { | ||
const { $shapes, factory, ns } = context | ||
const { sh, xsd } = ns | ||
this.context = context | ||
this.factory = context.factory | ||
this.node = node | ||
this.nodePointer = $shapes.node(node) | ||
@@ -134,4 +135,4 @@ this.parameters = [] | ||
this.optionals = {} | ||
this.context.$shapes | ||
.node(node) | ||
const trueTerm = factory.literal('true', xsd.boolean) | ||
this.nodePointer | ||
.out(sh.parameter) | ||
@@ -144,3 +145,3 @@ .forEach(parameterCf => { | ||
this.parameterNodes.push(parameter) | ||
if (this.context.$shapes.dataset.match(parameter, sh.optional, this.factory.true).size > 0) { | ||
if ($shapes.dataset.match(parameter, sh.optional, trueTerm).size > 0) { | ||
this.optionals[path.value] = true | ||
@@ -210,11 +211,15 @@ } else { | ||
constructor (context, shapeNode) { | ||
const { $shapes, ns, shapesGraph } = context | ||
const { sh } = ns | ||
this.context = context | ||
this.severity = context.$shapes.node(shapeNode).out(sh.severity).term | ||
this.shapeNodePointer = $shapes.node(shapeNode) | ||
this.severity = this.shapeNodePointer.out(sh.severity).term | ||
if (!this.severity) { | ||
this.severity = context.factory.ns.sh.Violation | ||
this.severity = sh.Violation | ||
} | ||
this.deactivated = context.$shapes.node(shapeNode).out(sh.deactivated).value === 'true' | ||
this.path = context.$shapes.node(shapeNode).out(sh.path).term | ||
this.deactivated = this.shapeNodePointer.out(sh.deactivated).value === 'true' | ||
this.path = this.shapeNodePointer.out(sh.path).term | ||
this._pathObject = undefined | ||
@@ -225,11 +230,11 @@ this.shapeNode = shapeNode | ||
const handled = new NodeSet() | ||
const shapeProperties = [...context.$shapes.dataset.match(shapeNode, null, null)] | ||
const shapeProperties = [...$shapes.dataset.match(shapeNode, null, null)] | ||
shapeProperties.forEach((sol) => { | ||
const component = this.context.shapesGraph.getComponentWithParameter(sol.predicate) | ||
const component = shapesGraph.getComponentWithParameter(sol.predicate) | ||
if (component && !handled.has(component.node)) { | ||
const params = component.parameters | ||
if (params.length === 1) { | ||
this.constraints.push(new Constraint(this, component, sol.object, context.$shapes)) | ||
this.constraints.push(new Constraint(this, component, sol.object, $shapes)) | ||
} else if (component.isComplete(shapeNode)) { | ||
this.constraints.push(new Constraint(this, component, undefined, context.$shapes)) | ||
this.constraints.push(new Constraint(this, component, undefined, $shapes)) | ||
handled.add(component.node) | ||
@@ -245,4 +250,6 @@ } | ||
get pathObject () { | ||
const { $shapes, ns } = this.context | ||
if (this._pathObject === undefined) { | ||
this._pathObject = this.path ? extractPropertyPath(this.context.$shapes, this.path) : null | ||
this._pathObject = this.path ? extractPropertyPath($shapes.node(this.path), ns) : null | ||
} | ||
@@ -257,17 +264,18 @@ | ||
getTargetNodes (dataGraph) { | ||
const { $shapes, ns } = this.context | ||
const { rdfs, sh } = ns | ||
const results = new NodeSet() | ||
if (isInstanceOf(this.context.$shapes, this.shapeNode, rdfs.Class)) { | ||
results.addAll(getInstancesOf(dataGraph, this.shapeNode)) | ||
if (isInstanceOf($shapes.node(this.shapeNode), $shapes.node(rdfs.Class), ns)) { | ||
results.addAll(getInstancesOf(dataGraph.node(this.shapeNode), ns)) | ||
} | ||
const targetClasses = [...this.context.$shapes.dataset.match(this.shapeNode, sh.targetClass, null)] | ||
const targetClasses = [...$shapes.dataset.match(this.shapeNode, sh.targetClass, null)] | ||
targetClasses.forEach(({ object: targetClass }) => { | ||
results.addAll(getInstancesOf(dataGraph, targetClass)) | ||
results.addAll(getInstancesOf(dataGraph.node(targetClass), ns)) | ||
}) | ||
results.addAll(this.context.$shapes.node(this.shapeNode).out(sh.targetNode).terms) | ||
results.addAll(this.shapeNodePointer.out(sh.targetNode).terms) | ||
this.context.$shapes | ||
.node(this.shapeNode) | ||
this.shapeNodePointer | ||
.out(sh.targetSubjectsOf) | ||
@@ -280,4 +288,3 @@ .terms | ||
this.context.$shapes | ||
.node(this.shapeNode) | ||
this.shapeNodePointer | ||
.out(sh.targetObjectsOf) | ||
@@ -284,0 +291,0 @@ .terms |
@@ -25,3 +25,3 @@ const ValidationReport = require('./validation-report') | ||
createResult (constraint, focusNode, valueNode) { | ||
const { rdf, sh } = this.factory.ns | ||
const { rdf, sh } = this.context.ns | ||
const result = this.factory.blankNode() | ||
@@ -58,3 +58,3 @@ const severity = constraint.shape.severity | ||
createResultFromObject (obj, constraint, focusNode, valueNode) { | ||
const { sh, xsd } = this.factory.ns | ||
const { sh, xsd } = this.context.ns | ||
@@ -112,4 +112,4 @@ if (obj === false) { | ||
createResultMessages (result, constraint) { | ||
const $shapes = this.context.$shapes | ||
const { sh } = this.factory.ns | ||
const { $shapes, ns } = this.context | ||
const { sh } = ns | ||
@@ -155,3 +155,3 @@ // 1. Try to get message from the shape itself | ||
let foundError = false | ||
const shapes = this.context.shapesGraph.getShapesWithTarget() | ||
const shapes = this.context.shapesGraph.shapesWithTarget | ||
for (const shape of shapes) { | ||
@@ -195,3 +195,3 @@ const focusNodes = shape.getTargetNodes(dataGraph) | ||
validateNodeAgainstConstraint (focusNode, valueNodes, constraint, dataGraph) { | ||
const { sh } = this.factory.ns | ||
const { sh } = this.context.ns | ||
@@ -303,3 +303,3 @@ if (this.maxErrorsReached()) { | ||
} else { | ||
return new ValidationReport(this.results, { factory: this.factory }) | ||
return new ValidationReport(this.results, { factory: this.factory, ns: this.context.ns }) | ||
} | ||
@@ -306,0 +306,0 @@ } |
const clownface = require('clownface') | ||
const DataFactory = require('./data-factory') | ||
const { sh } = require('./namespaces') | ||
const { prepareNamespaces } = require('./namespaces') | ||
@@ -11,5 +10,7 @@ /** | ||
options = options || {} | ||
this.factory = new DataFactory(options.factory || require('@rdfjs/dataset')) | ||
const { rdf, sh, xsd } = this.factory.ns | ||
this.factory = options.factory || require('@rdfjs/dataset') | ||
this.ns = options.ns || prepareNamespaces(this.factory) | ||
const { rdf, sh, xsd } = this.ns | ||
this.term = this.factory.blankNode('report') | ||
@@ -36,3 +37,3 @@ this.dataset = this.factory.dataset(resultsQuads) | ||
*/ | ||
this.results = resultNodes.map(resultNode => new ValidationResult(resultNode, this.dataset)) | ||
this.results = resultNodes.map(resultNode => new ValidationResult(resultNode, this.dataset, this.ns)) | ||
} | ||
@@ -42,5 +43,6 @@ } | ||
class ValidationResult { | ||
constructor (term, dataset) { | ||
constructor (term, dataset, ns) { | ||
this.term = term | ||
this.dataset = dataset | ||
this.ns = ns | ||
this.cf = clownface({ dataset: dataset }).node(term) | ||
@@ -50,23 +52,23 @@ } | ||
get message () { | ||
return this.cf.out(sh.resultMessage).terms || [] | ||
return this.cf.out(this.ns.sh.resultMessage).terms || [] | ||
} | ||
get path () { | ||
return this.cf.out(sh.resultPath).term || null | ||
return this.cf.out(this.ns.sh.resultPath).term || null | ||
} | ||
get focusNode () { | ||
return this.cf.out(sh.focusNode).term || null | ||
return this.cf.out(this.ns.sh.focusNode).term || null | ||
} | ||
get severity () { | ||
return this.cf.out(sh.resultSeverity).term || null | ||
return this.cf.out(this.ns.sh.resultSeverity).term || null | ||
} | ||
get sourceConstraintComponent () { | ||
return this.cf.out(sh.sourceConstraintComponent).term || null | ||
return this.cf.out(this.ns.sh.sourceConstraintComponent).term || null | ||
} | ||
get sourceShape () { | ||
return this.cf.out(sh.sourceShape).term || null | ||
return this.cf.out(this.ns.sh.sourceShape).term || null | ||
} | ||
@@ -73,0 +75,0 @@ } |
const { validateTerm } = require('rdf-validate-datatype') | ||
const { fromRdf } = require('rdf-literal') | ||
const NodeSet = require('./node-set') | ||
const { rdf, sh, xsd } = require('./namespaces') | ||
const { getPathObjects } = require('./property-path') | ||
@@ -9,4 +8,6 @@ const { isInstanceOf, rdfListToArray } = require('./dataset-utils') | ||
function validateAnd (context, focusNode, valueNode, constraint) { | ||
const { sh } = context.ns | ||
const andNode = constraint.getParameterValue(sh.and) | ||
const shapes = rdfListToArray(context.$shapes, andNode) | ||
const shapes = rdfListToArray(context.$shapes.node(andNode)) | ||
return shapes.every((shape) => context.nodeConformsToShape(valueNode, shape)) | ||
@@ -16,12 +17,16 @@ } | ||
function validateClass (context, focusNode, valueNode, constraint) { | ||
const { sh } = context.ns | ||
const classNode = constraint.getParameterValue(sh.class) | ||
return isInstanceOf(context.$data, valueNode, classNode) | ||
return isInstanceOf(context.$data.node(valueNode), context.$data.node(classNode), context.ns) | ||
} | ||
function validateClosed (context, focusNode, valueNode, constraint) { | ||
const { sh, xsd } = context.ns | ||
const closedNode = constraint.getParameterValue(sh.closed) | ||
const ignoredPropertiesNode = constraint.getParameterValue(sh.ignoredProperties) | ||
const currentShape = constraint.shape.shapeNode | ||
const trueTerm = context.factory.literal('true', xsd.boolean) | ||
if (!context.factory.true.equals(closedNode)) { | ||
if (!trueTerm.equals(closedNode)) { | ||
return | ||
@@ -40,3 +45,3 @@ } | ||
if (ignoredPropertiesNode) { | ||
allowed.addAll(rdfListToArray(context.$shapes, ignoredPropertiesNode)) | ||
allowed.addAll(rdfListToArray(context.$shapes.node(ignoredPropertiesNode))) | ||
} | ||
@@ -51,2 +56,3 @@ | ||
}) | ||
return results | ||
@@ -56,2 +62,3 @@ } | ||
function validateDatatype (context, focusNode, valueNode, constraint) { | ||
const { sh } = context.ns | ||
const datatypeNode = constraint.getParameterValue(sh.datatype) | ||
@@ -67,3 +74,5 @@ | ||
function validateDisjoint (context, focusNode, valueNode, constraint) { | ||
const { sh } = context.ns | ||
const disjointNode = constraint.getParameterValue(sh.disjoint) | ||
return context.$data.dataset.match(focusNode, disjointNode, valueNode).size === 0 | ||
@@ -73,2 +82,3 @@ } | ||
function validateEqualsProperty (context, focusNode, valueNode, constraint) { | ||
const { sh } = context.ns | ||
const path = constraint.shape.pathObject | ||
@@ -91,3 +101,2 @@ const equalsNode = constraint.getParameterValue(sh.equals) | ||
}) | ||
return results | ||
@@ -97,2 +106,3 @@ } | ||
function validateEqualsNode (context, focusNode, valueNode, constraint) { | ||
const { sh } = context.ns | ||
const equalsNode = constraint.getParameterValue(sh.equals) | ||
@@ -104,3 +114,3 @@ const results = [] | ||
solutions++ | ||
if (compareNodes(focusNode, value) !== 0) { | ||
if (compareNodes(focusNode, value, context.ns) !== 0) { | ||
results.push({ value }) | ||
@@ -118,3 +128,5 @@ } | ||
function validateHasValueNode (context, focusNode, valueNode, constraint) { | ||
const { sh } = context.ns | ||
const hasValueNode = constraint.getParameterValue(sh.hasValue) | ||
return focusNode.equals(hasValueNode) | ||
@@ -124,2 +136,3 @@ } | ||
function validateHasValueProperty (context, focusNode, valueNode, constraint) { | ||
const { sh } = context.ns | ||
const path = constraint.shape.pathObject | ||
@@ -133,7 +146,10 @@ const hasValueNode = constraint.getParameterValue(sh.hasValue) | ||
function validateIn (context, focusNode, valueNode, constraint) { | ||
const { sh } = context.ns | ||
const inNode = constraint.getParameterValue(sh.in) | ||
return new NodeSet(rdfListToArray(context.$shapes, inNode)).has(valueNode) | ||
return new NodeSet(rdfListToArray(context.$shapes.node(inNode))).has(valueNode) | ||
} | ||
function validateLanguageIn (context, focusNode, valueNode, constraint) { | ||
const { sh } = context.ns | ||
if (valueNode.termType !== 'Literal') { | ||
@@ -149,3 +165,3 @@ return false | ||
const languageInNode = constraint.getParameterValue(sh.languageIn) | ||
const allowedLanguages = rdfListToArray(context.$shapes, languageInNode) | ||
const allowedLanguages = rdfListToArray(context.$shapes.node(languageInNode)) | ||
@@ -156,2 +172,3 @@ return allowedLanguages.some(allowedLanguage => valueLanguage.startsWith(allowedLanguage.value)) | ||
function validateLessThanProperty (context, focusNode, valueNode, constraint) { | ||
const { sh } = context.ns | ||
const valuePath = constraint.shape.pathObject | ||
@@ -165,3 +182,3 @@ const values = getPathObjects(context.$data, focusNode, valuePath) | ||
for (const referenceValue of referenceValues) { | ||
const c = compareNodes(value, referenceValue) | ||
const c = compareNodes(value, referenceValue, context.ns) | ||
if (c === null || c >= 0) { | ||
@@ -176,2 +193,3 @@ invalidValues.push({ value }) | ||
function validateLessThanOrEqualsProperty (context, focusNode, valueNode, constraint) { | ||
const { sh } = context.ns | ||
const valuePath = constraint.shape.pathObject | ||
@@ -185,3 +203,3 @@ const values = getPathObjects(context.$data, focusNode, valuePath) | ||
for (const referenceValue of referenceValues) { | ||
const c = compareNodes(value, referenceValue) | ||
const c = compareNodes(value, referenceValue, context.ns) | ||
if (c === null || c > 0) { | ||
@@ -196,2 +214,3 @@ invalidValues.push({ value }) | ||
function validateMaxCountProperty (context, focusNode, valueNode, constraint) { | ||
const { sh } = context.ns | ||
const path = constraint.shape.pathObject | ||
@@ -205,2 +224,3 @@ const count = getPathObjects(context.$data, focusNode, path).length | ||
function validateMaxExclusive (context, focusNode, valueNode, constraint) { | ||
const { sh } = context.ns | ||
const maxExclusiveNode = constraint.getParameterValue(sh.maxExclusive) | ||
@@ -210,3 +230,3 @@ | ||
valueNode.termType === 'Literal' && | ||
checkTimezone(valueNode, maxExclusiveNode) && | ||
checkTimezone(valueNode, maxExclusiveNode, context.ns) && | ||
fromRdf(valueNode) < fromRdf(maxExclusiveNode) | ||
@@ -217,2 +237,3 @@ ) | ||
function validateMaxInclusive (context, focusNode, valueNode, constraint) { | ||
const { sh } = context.ns | ||
const maxInclusiveNode = constraint.getParameterValue(sh.maxInclusive) | ||
@@ -222,3 +243,3 @@ | ||
valueNode.termType === 'Literal' && | ||
checkTimezone(valueNode, maxInclusiveNode) && | ||
checkTimezone(valueNode, maxInclusiveNode, context.ns) && | ||
fromRdf(valueNode) <= fromRdf(maxInclusiveNode) | ||
@@ -233,2 +254,3 @@ ) | ||
const { sh } = context.ns | ||
const maxLengthNode = constraint.getParameterValue(sh.maxLength) | ||
@@ -239,2 +261,3 @@ return valueNode.value.length <= Number(maxLengthNode.value) | ||
function validateMinCountProperty (context, focusNode, valueNode, constraint) { | ||
const { sh } = context.ns | ||
const path = constraint.shape.pathObject | ||
@@ -248,2 +271,3 @@ const count = getPathObjects(context.$data, focusNode, path).length | ||
function validateMinExclusive (context, focusNode, valueNode, constraint) { | ||
const { sh } = context.ns | ||
const minExclusiveNode = constraint.getParameterValue(sh.minExclusive) | ||
@@ -253,3 +277,3 @@ | ||
valueNode.termType === 'Literal' && | ||
checkTimezone(valueNode, minExclusiveNode) && | ||
checkTimezone(valueNode, minExclusiveNode, context.ns) && | ||
fromRdf(valueNode) > fromRdf(minExclusiveNode) | ||
@@ -260,2 +284,3 @@ ) | ||
function validateMinInclusive (context, focusNode, valueNode, constraint) { | ||
const { sh } = context.ns | ||
const minInclusiveNode = constraint.getParameterValue(sh.minInclusive) | ||
@@ -265,3 +290,3 @@ | ||
valueNode.termType === 'Literal' && | ||
checkTimezone(valueNode, minInclusiveNode) && | ||
checkTimezone(valueNode, minInclusiveNode, context.ns) && | ||
fromRdf(valueNode) >= fromRdf(minInclusiveNode) | ||
@@ -274,9 +299,9 @@ ) | ||
// with a datetime without a timezone. | ||
function checkTimezone (valueNode, constraintNode) { | ||
return hasTimezone(valueNode) === hasTimezone(constraintNode) | ||
function checkTimezone (valueNode, constraintNode, ns) { | ||
return hasTimezone(valueNode, ns) === hasTimezone(constraintNode, ns) | ||
} | ||
function hasTimezone (node) { | ||
function hasTimezone (node, ns) { | ||
const pattern = /^.*(((\+|-)\d{2}:\d{2})|Z)$/ | ||
return xsd.dateTime.equals(node.datatype) && pattern.test(node.value) | ||
return ns.xsd.dateTime.equals(node.datatype) && pattern.test(node.value) | ||
} | ||
@@ -289,2 +314,3 @@ | ||
const { sh } = context.ns | ||
const minLengthNode = constraint.getParameterValue(sh.minLength) | ||
@@ -295,2 +321,3 @@ return valueNode.value.length >= Number(minLengthNode.value) | ||
function validateNodeKind (context, focusNode, valueNode, constraint) { | ||
const { sh } = context.ns | ||
const nodeKindNode = constraint.getParameterValue(sh.nodeKind) | ||
@@ -314,2 +341,3 @@ | ||
function validateNode (context, focusNode, valueNode, constraint) { | ||
const { sh } = context.ns | ||
const nodeNode = constraint.getParameterValue(sh.node) | ||
@@ -320,2 +348,3 @@ return context.nodeConformsToShape(valueNode, nodeNode) | ||
function validateNot (context, focusNode, valueNode, constraint) { | ||
const { sh } = context.ns | ||
const notNode = constraint.getParameterValue(sh.not) | ||
@@ -326,4 +355,5 @@ return !context.nodeConformsToShape(valueNode, notNode) | ||
function validateOr (context, focusNode, valueNode, constraint) { | ||
const { sh } = context.ns | ||
const orNode = constraint.getParameterValue(sh.or) | ||
const shapes = rdfListToArray(context.$shapes, orNode) | ||
const shapes = rdfListToArray(context.$shapes.node(orNode)) | ||
return shapes.some(shape => context.nodeConformsToShape(valueNode, shape)) | ||
@@ -337,2 +367,3 @@ } | ||
const { sh } = context.ns | ||
const flagsNode = constraint.getParameterValue(sh.flags) | ||
@@ -345,2 +376,3 @@ const patternNode = constraint.getParameterValue(sh.pattern) | ||
function validateQualifiedMaxCountProperty (context, focusNode, valueNode, constraint) { | ||
const { sh } = context.ns | ||
const count = validateQualifiedHelper(context, focusNode, constraint) | ||
@@ -353,2 +385,3 @@ const qualifiedMaxCountNode = constraint.getParameterValue(sh.qualifiedMaxCount) | ||
function validateQualifiedMinCountProperty (context, focusNode, valueNode, constraint) { | ||
const { sh } = context.ns | ||
const count = validateQualifiedHelper(context, focusNode, constraint) | ||
@@ -361,9 +394,11 @@ const qualifiedMinCountNode = constraint.getParameterValue(sh.qualifiedMinCount) | ||
function validateQualifiedHelper (context, focusNode, constraint) { | ||
const { sh, xsd } = context.ns | ||
const currentShapeNode = constraint.shape.shapeNode | ||
const qualifiedValueShapesDisjointNode = constraint.getParameterValue(sh.qualifiedValueShapesDisjoint) | ||
const qualifiedValueShapeNode = constraint.getParameterValue(sh.qualifiedValueShape) | ||
const trueTerm = context.factory.literal('true', xsd.boolean) | ||
const siblingShapes = new NodeSet() | ||
if (context.factory.true.equals(qualifiedValueShapesDisjointNode)) { | ||
if (trueTerm.equals(qualifiedValueShapesDisjointNode)) { | ||
const qualifiedSiblingShapes = context.$shapes | ||
@@ -402,5 +437,7 @@ .node(currentShapeNode) | ||
function validateUniqueLangProperty (context, focusNode, valueNode, constraint) { | ||
const { sh, xsd } = context.ns | ||
const uniqueLangNode = constraint.getParameterValue(sh.uniqueLang) | ||
const trueTerm = context.factory.literal('true', xsd.boolean) | ||
if (!context.factory.true.equals(uniqueLangNode)) { | ||
if (!trueTerm.equals(uniqueLangNode)) { | ||
return | ||
@@ -436,4 +473,5 @@ } | ||
function validateXone (context, focusNode, valueNode, constraint) { | ||
const { sh } = context.ns | ||
const xoneNode = constraint.getParameterValue(sh.xone) | ||
const shapes = rdfListToArray(context.$shapes, xoneNode) | ||
const shapes = rdfListToArray(context.$shapes.node(xoneNode)) | ||
const conformsCount = shapes | ||
@@ -449,3 +487,3 @@ .map(shape => context.nodeConformsToShape(valueNode, shape)) | ||
function compareNodes (node1, node2) { | ||
function compareNodes (node1, node2, ns) { | ||
// TODO: Does not handle the case where nodes cannot be compared | ||
@@ -459,6 +497,6 @@ if (node1 && node1.termType === 'Literal' && node2 && node2.termType === 'Literal') { | ||
} | ||
return compareTerms(node1, node2) | ||
return compareTerms(node1, node2, ns) | ||
} | ||
function compareTerms (t1, t2) { | ||
function compareTerms (t1, t2, ns) { | ||
if (!t1) { | ||
@@ -483,3 +521,3 @@ return !t2 ? 0 : 1 | ||
return bd | ||
} else if (rdf.langString.equals(t1.datatype)) { | ||
} else if (ns.rdf.langString.equals(t1.datatype)) { | ||
return t1.language.localeCompare(t2.language) | ||
@@ -486,0 +524,0 @@ } else { |
399158
92
16
8307