This document defines a JavaScript-based extension mechanism for the Shapes Constraint Language (SHACL). It defines a syntax for declaring constraints, constraint components, functions, rules and targets in JavaScript. Using this syntax, SHACL shapes can benefit from the rich expressive power of JavaScript. In order to ensure that the resulting JavaScript code can be executed across platforms, this document defines a (minimalistic) JavaScript API that needs to be implemented by supporting engines.
Future revisions of this document may be produced by a SHACL W3C Community Group.
Some examples in this document use Turtle [[!turtle]]. The reader is expected to be familiar with SHACL [[!shacl]] and the SHACL Advanced Features [[!shacl-af]].
Within this document, the following namespace prefix bindings are used:
Prefix | Namespace |
---|---|
rdf: |
http://www.w3.org/1999/02/22-rdf-syntax-ns# |
rdfs: |
http://www.w3.org/2000/01/rdf-schema# |
sh: |
http://www.w3.org/ns/shacl# |
xsd: |
http://www.w3.org/2001/XMLSchema# |
ex: |
http://example.com/ns# |
Throughout the document, color-coded boxes containing RDF graphs in Turtle will appear. These fragments of Turtle documents use the prefix bindings given above.
# This box represents a shapes graph <s> <p> <o> .
// This box contains JavaScript code
# This box represents a data graph.
# This box represents an output results graph
Formal definitions appear in blue boxes:
# This box contains textual definitions.
Grey boxes such as this include syntax rules that apply to the shapes graph.
true
denotes the RDF term "true"^^xsd:boolean
.
false
denotes the RDF term "false"^^xsd:boolean
.
The terminology used throughout this document is consistent with the definitions in the main SHACL [[!shacl]] specification, which references terms from RDF [[!rdf11-concepts]]. This includes the terms blank node, conformance, constraint, constraint component, data graph, datatype, failure, focus node, RDF graph, ill-formed, IRI, literal, local name, node, node shape, object, parameter, predicate, property shape, RDF term, SHACL instance, shape, shapes graph, subject, target, triple, validation, validation report, validation result, validator, value, value node. Additional terms are defined in the SHACL Advanced Features document [[!shacl-af]]: custom target, rule type, rule, SHACL function.
The Shapes Constraint Language (SHACL) [[!shacl]] is a language for validating RDF graphs against a set of conditions.
These conditions are provided as shapes and other constructs expressed in the form of an RDF graph.
SHACL is represented in RDF and consists of a SHACL Core RDF vocabulary with terms such as sh:minCount
to express the most frequently needed constraint kinds.
However, in order to express more complex constraints, the SHACL Core vocabulary is often not sufficient.
SHACL-SPARQL [[!shacl]] is one extension mechanism for SHACL to express constraints in SPARQL, allowing shape definitions
to point at executable SPARQL [[sparql11-query]] queries to perform the validation checks.
This document defines the SHACL JavaScript Extensions (SHACL-JS), allowing users to express
SHACL constraints and the advanced features of custom targets, functions and rules with the help of JavaScript.
SHACL-JS is based on a similar design to SHACL-SPARQL, but for JavaScript instead of SPARQL. The basic idea is that SHACL shapes can point at JavaScript functions in specified JavaScript files that can be resolved from the web. When shapes get evaluated, a SHACL-JS engine calls those functions with a predefined set of arguments and constructs validation results from the values and objects returned by these JavaScript function calls. The JavaScript code can access RDF triples from both the shapes graph and the data graph where needed, through the JavaScript API that is defined in this document, or a higher-level JavaScript API that uses the specified API under the hood.
As a result of this design, SHACL shape definitions can be augmented with JavaScript and executed either within web browsers (assuming the SHACL engine operates on the client), or on servers that support JavaScript execution.
This section defines an API that JavaScript-based SHACL functions can use to operate on RDF terms and to query triples in graphs. The JavaScript code behind SHACL-JS constraints and constraint components can directly access those functions or go through a higher-level layer of convenience functions that use these functions under the hood.
Note that the API expects these JavaScript Objects to be immutable, i.e. neither the values of an RDF term nor triples nor graphs can be modified during SHACL validation.
All RDF terms (IRIs, blank nodes and literals) are represented using JavaScript Objects that have attributes as described in the following three subsections. The following table summarizes key functions to create and operate on RDF term Objects:
Node Kind | Factory Function | Test Function | Attributes |
---|---|---|---|
IRIs | TermFactory.namedNode(uri) |
.isURI() |
uri |
Blank Nodes | TermFactory.blankNode(id) or TermFactory.blankNode() |
.isBlankNode() |
id |
Literals | TermFactory.literal(lex, languageOrDatatype) |
.isLiteral() |
datatype , language , lex |
Note that the attributes in the table above are only defined for Objects that have matching types.
For example, the result of querying the uri
of a blank node is undefined.
Each of these Objects must have a function .equals(other)
that takes another term Object as its only parameter and returns true
exactly if the underlying RDF terms are equal, and false
otherwise.
An IRI is represented by a JavaScript NamedNode
Object
where .isURI()
returns true
while .isBlankNode()
and .isLiteral()
return false
.
The value of the read-only attribute uri
is the IRI string.
A blank node is represented by a JavaScript BlankNode
Object
where .isBlankNode()
returns true
while .isURI()
and .isLiteral()
return false
.
The value of the read-only attribute id
is the blank node identifier as a string.
That string is must be consistent for the same RDF node for the duration of a SHACL validation
and processing of validation results.
A literal is represented by a JavaScript Literal
Object
where .isLiteral()
returns true
while .isURI()
and .isBlankNode()
return false
.
The value of the read-only attribute language
is a lowercase BCP-47 [[!BCP47]]
string (for example, en
, en-gb
), or an empty string if the literal has no language.
The value of the read-only attribute datatype
is a NamedNode representing the datatype IRI of the literal.
Note that this datatype
is never undefined, and language-tagged strings have rdf:langString
as their datatype.
The value of the read-only attribute lex
is the lexical form of the literal, e.g. "042"
for the
RDF node "042"^^xsd:integer
.
During the execution of JavaScript code, the SHACL engine MUST provide an Object
accessible via the variable TermFactory
that can be used to create
JavaScript Objects for RDF terms.
The TermFactory
provides the following three functions:
namedNode(uri)
returns a NamedNode with the
IRI provided as a string via uri
.
blankNode(id)
returns a BlankNode
with an optional identifier provided as a string via id
.
If the id
is omitted then the system generates a unique identifier.
literal(lex, languageOrDatatype)
returns a Literal
with the lexical form provided as a string via lex
.
The second argument languageOrDatatype
must be either a non-empty string,
in which case the literal will have that value as its language tag,
or a JavaScript NamedNode Object representing a datatype other than
rdf:langString
.
An RDF triple is represented by a JavaScript Triple
Object with three
read-only attributes subject
, predicate
and object
,
each of which has exactly one RDF term as its value.
Furthermore, triples must provide an equals
function that takes an
Object other
as its only parameter and returns a boolean.
equals
returns true
exactly if other
has values for its attributes subject
, predicate
and object
that return true
when compared using equals()
against the corresponding
attribute values of the first triple, and false
otherwise.
An RDF graph is represented by a JavaScript Graph
Object that
has a function find
which takes three parameters of type Object,
all of which are optional.
The result of the find
function is an Iterator
object with two functions:
next()
either returns a Triple
or null
if the iteration has been exhausted.
close()
terminates the Iterator and releases any resources allocated by it.
Once close()
has been called, further calls to next()
cause an exception.
The close()
function MUST always be called unless the iterator has already been walked to completion.
The following JavaScript snippet assumes that the current data graph is represented by
the variable $data
and gets the first label of a given resource
where the label is an english literal.
function getEnglishLabel(resource) { var labelProperty = TermFactory.namedNode("http://www.w3.org/2000/01/rdf-schema#label"); var labels = $data.find(resource, labelProperty, null); for(;;) { var labelTriple = labels.next(); if(!labelTriple) { return null; } var label = labelTriple.object; if(label.isLiteral() && label.language.startsWith("en")) { labels.close(); return label.value; } } }
During a validation process, the variable $data
points at the
JavaScript Graph
Object representing the SHACL data graph.
During a validation process, the variable $shapes
points at the
JavaScript Graph Object representing the SHACL shapes graph.
This may be identical to the data graph.
The iterators produced by the find
function described in this section are expected to be
operating synchronously, i.e. the triples are available immediately to the caller.
Since many of the constraints that users want to express in SHACL can be quite complex,
a synchronous API contract typically leads to more maintainable code than an asynchronous one (with callbacks or promises).
If data needs to be loaded on demand from a remote server, then solutions such as pre-caching or
the await
keyword may be used as a work-around.
More sophisticated handling of asynchronous query scenarios may be defined by future versions of SHACL-JS.
SHACL-JS processors must provide a JavaScript function with the following signature:
SHACL.nodeConformsToShape(node, shape)
node
: The RDF term Object of the node to validateshape
: The RDF term Object of the shape to validate the node against
The result of this function is true
if and only if node
conforms to the shape
,
and false
otherwise.
This function is needed because the implementation of some of the constraint components
such as sh:NotConstraintComponent
requires the ability to spawn off a new
SHACL validation process.
It may also be used as entry point into the validation engine by custom code.
This section defines some general RDF terms used by SHACL-JS to represent JavaScript code and libraries as part of a declarative shapes graph.
The SHACL-JS vocabulary includes the class sh:JSExecutable
.
SHACL instances of this class are called JavaScript executables
and may have values for the properties sh:jsFunctionName
and sh:jsLibrary
.
Every JavaScript executable must have exactly one value for the property sh:jsFunctionName
.
The values of sh:jsFunctionName
are literals with datatype xsd:string
.
The semantics of how arguments are passed into the provided function depend on the specific type of executable, as described in later sections.
Every JavaScript executable must have at least one value for the property sh:jsLibrary
.
The values of the property sh:jsLibrary
are IRIs or blank nodes.
The values of the property sh:jsLibrary
are well-formed SHACL instances of the class sh:JSLibrary
.
The class sh:JSLibrary
can be used to declare JavaScript libraries.
A library can be understood as a pointer to zero or more JavaScript files that need to be executed before a JavaScript executable can be evaluated.
Libraries may depend on each other by declaring further sh:jsLibrary
triples.
The values of the property sh:jsLibraryURL
are literals with datatype xsd:anyURI
.
This section defines general rules for the execution of JavaScript declared in RDF, by a SHACL engine.
args
be a mapping of variable names to RDF nodes.
The result of the execution of a JavaScript function using args
is the result of the invocation of the JavaScript function, matching each variable name in args
to parameter values in the function's signature.
A JavaScript parameter matches a variable name if its name is equal to the concatenation of "$"
and the variable name.
For the above definition, consider an example function myFunction($arg1, $arg2, $arg3) { ... }
and a variable mapping { "arg1" : ex:Instance1, "arg2" : 42 }
.
The JavaScript function would be called with
the JavaScript NamedNode
object representing ex:Instance1
as value for $arg1
,
the JavaScript Literal
object representing 42
as value for $arg2
,
and undefined
as value for $arg3
.
sh:jsLibrary
(including
the libraries referenced by those libraries), followed
by the execution of the JavaScript function that has the same name as the
value of sh:jsFunctionName
.
The result of the latter is the result of executing the executable.
sh:jsLibraryURL
must be resolved into JavaScript code.
By default this resolution mechanism MUST be performing an HTTP GET request against the given script URL.
A failure MUST be reported if the SHACL processor encounters a cyclic dependency between libraries.
In practice, SHACL implementations may redirect the resolution of URLs to local files or cached copies.
SHACL-JS supports constraints that can be used to express restrictions based on JavaScript.
In a nutshell, whenever a SHACL validation engine encounters a shape with a sh:js
constraint,
it will execute the provided JavaScript function and use the returned result to create validation results.
Constraint Component IRI: sh:JSConstraintComponent
Property | Summary |
---|---|
sh:js |
A JavaScript-based constraint declaring the JavaScript function to evaluate. |
The values of sh:js
at a shape are called JavaScript-based constraints.
Each JavaScript-based constraint is also a JavaScript executable.
The syntax rules and validation process for JavaScript-based constraints are defined in the rest of this section.
The following example illustrates the syntax of a JavaScript-based constraint.
ex:ValidCountry a ex:Country ;
ex:germanLabel "Spanien"@de .
ex:InvalidCountry a ex:Country ;
ex:germanLabel "Spain"@en .
function validateGermanLabel($this) { var results = []; var p = TermFactory.namedNode("http://example.org/ns#germanLabel"); var s = $data.find($this, p, null); for(var t = s.next(); t; t = s.next()) { var object = t.object; if(!object.isLiteral() || !object.language.startsWith("de")) { results.push({ value : object }); } } return results; }
ex:LanguageExampleShape a sh:NodeShape ; sh:targetClass ex:Country ; sh:js [ # _:b1 a sh:JSConstraint ; # This triple is optional sh:message "Values are literals with German language tag." ; sh:jsLibrary [ sh:jsLibraryURL "http://example.org/js/germanLabel.js" ] ; sh:jsFunctionName "validateGermanLabel" ; ] .
The target of the shape above includes all SHACL instances of ex:Country
.
For those nodes (represented by the variable $this
),
the JavaScript code walks through the values of the property ex:germanLabel
at $this
and verifies that they are literals with a German language tag.
The validation report for the aforementioned data graph is shown below:
[ a sh:ValidationReport ; sh:conforms false ; sh:result [ a sh:ValidationResult ; sh:resultSeverity sh:Violation ; sh:focusNode ex:InvalidCountry ; sh:resultMessage "Values are literals with German language tag." ; sh:resultPath ex:germanLabel ; sh:value "Spain"@en ; sh:sourceConstraint _:b1 ; sh:sourceConstraintComponent sh:JSConstraintComponent ; sh:sourceShape ex:LanguageExampleShape ; ] ] .
This section defines the validator of sh:JSConstraintComponent
.
true
as a value for the property sh:deactivated
.
Otherwise, for each focus node F
and each value node V
for F
,
execute the constraint's JavaScript function
using the argument mapping { "this" : F, "value" : V }
.
Construct validation results for each result returned by these function calls.
Report a failure if the execution of the JavaScript function results in an exception.
The following rules define how to construct validation results from a given JavaScript function
result R
in the context of a given constraint C
in a shape S
,
a focus node F
and a value node V
.
R
is a JavaScript String
:
Create a validation result ?r
.
Add a triple ?r sh:resultMessage ?s
where ?s
is an xsd:string
literal
with the JavaScript String
as its lexical form.
Add a triple ?r sh:value ?v
where ?v
is the current value node V
.
R
is a JavaScript Array:
For each member of the Array R
apply the rule for JavaScript Objects.
R
is a JavaScript Object
(not a String
):
Create a validation result ?r
.
If R.value
is an RDF term object ?v
, add a triple ?r sh:value ?v
.
If R.message
is a JavaScript String
, add a triple ?r sh:resultMessage ?s
where ?s
is an xsd:string
literal with the given String
as its lexical form.
Otherwise, add triples ?r sh:resultMessage ?m
from the shape S
following the rules defined by [[!shacl]].
If the shape S
is a node shape
and R.path
is an RDF
NamedNode
object ?path
, add a triple ?r sh:resultPath ?path
.
R
is the JavaScript Boolean
false
:
Create a validation result ?r
.
Add a triple ?r sh:value ?v
where ?v
is the current value node V
.
Add triples ?r sh:resultMessage ?m
from the shape S
following the rules defined by [[!shacl]].
To create a validation result ?r
, create a triple ?r rdf:type sh:ValidationResult
using the provided focus node F
as value for sh:focusNode
,
deriving sh:resultSeverity
from the sh:severity
of the shape S
in the
shapes graph (using sh:Violation
as default),
and setting the sh:resultPath
, sh:sourceConstraintComponent
and sh:sourceShape
following the rules defined by [[!shacl]].
If the result is produced by a JavaScript-based constraint, then set sh:sourceConstraint
to the value of sh:js
of the constraint C
in the shapes graph.
SHACL is based on constraint components, which can be used to express constraints in a declarative, high-level vocabulary.
For example, the constraint component sh:MinCountConstraintComponent
defines a parameter sh:minCount
.
When a shape uses one of these constraint parameters, a SHACL engine finds a suitable validator that can produce validation results.
SHACL-SPARQL [[!shacl]] defines how SPARQL queries can be used as validators.
SHACL-JS defines a class sh:JSValidator
which can be used to declare validators using JavaScript.
The following example demonstrates how JavaScript can be used to specify new constraint components using SHACL-JS.
The example implements sh:maxLength
using a JavaScript-based validator to validate that the string representation of each value node
has at most a given number of characters.
Note that this is only an example implementation and should not be considered normative.
function hasMaxLength($value, $maxLength) { if($value.isLiteral()) { return $value.lex.length <= $maxLength.lex; } else if($value.isURI()) { return $value.uri.length <= $maxLength.lex; } else { // Blank node return false; } }
sh:MaxLengthConstraintComponent a sh:ConstraintComponent ; sh:parameter [ sh:path sh:maxLength ; sh:datatype xsd:integer ; ] ; sh:validator ex:hasMaxLength . ex:hasMaxLength a sh:JSValidator ; sh:message "Value has more than {$maxLength} characters" ; rdfs:comment """ Note that $value and $maxLength are RDF nodes expressed in JavaScript Objects. Their string value is accessed via the .lex and .uri attributes. The function returns true if no violation has been found. """ ; sh:jsLibrary [ sh:jsLibraryURL "http://example.org/ns/hasMaxLength.js"^^xsd:anyURI ] ; sh:jsFunctionName "hasMaxLength" .
The declaration of JavaScript-based Constraint Components in a shapes graph
is very similar to SPARQL-based Constraint Components.
In particular, components declare their parameters using sh:parameter
.
In fact, the same constraint component may serve as a declaration of both a SPARQL-based
and a JavaScript-based constraint component, assuming that validators have been declared for both cases.
Where SHACL-SPARQL uses the classes sh:SPARQLSelectValidator
and sh:SPARQLAskValidator
,
SHACL-JS uses the class sh:JSValidator
, which is a subclass of sh:JSExecutable
.
Each SHACL-JS validator is also a JavaScript executable and therefore has a value for sh:jsFunctionName
.
This section defines the validator of JavaScript-based constraint components.
?E
be the JavaScript executable selected for the constraint component
?C
based on the rules outlined in
section 6.2.3 of [[!shacl]].
If the shape is a property shape and the shapes graph contains a triple
?C sh:propertyValidator ?E
then let path
be the value of sh:path
at the shape in the shapes graph, and execute
?E
for each focus node F
using a mapping { "this" : F, "path" : path }
.
(The validator's JavaScript function can access the path
structure in the shapes graph $shapes
,
assuming the function declares $path
as one of its parameters.)
Otherwise, for each focus node F
and each value node V
,
execute ?E
using a mapping { "this" : F, "value" : V }
.
Construct validation results for each result returned by these function calls.
Report a failure if the execution of the JavaScript function results in an exception.
The SHACL Advanced Features includes a generic mechanism to declare new SHACL functions.
In particular this is used to declare new SPARQL functions, using the class sh:SPARQLFunction
.
SHACL-JS includes a very similar mechanism, allowing users to declare new functions in an RDF vocabulary
so that certain engines can use them.
Functions declared using the SHACL-JS vocabulary can, among others, be used by function calls
in SPARQL FILTER or BIND clauses and in SHACL rules.
The following example demonstrates how JavaScript can be used to specify new SHACL function.
The function can be used, for example in SPARQL using BIND (ex:square(4) AS ?s)
.
function square($number) { return $number.lex * $number.lex; }
ex:square a sh:JSFunction ; sh:parameter [ sh:path ex:number ; sh:datatype xsd:integer ; ] ; sh:returnType xsd:integer ; sh:jsLibrary [ sh:jsLibraryURL "http://example.org/js/square.js"^^xsd:anyURI ] ; sh:jsFunctionName "square" .
The syntax of JavaScript-based functions is very similar to SPARQL-based functions.
Each SHACL instance of sh:JSFunction
in a shapes graph,
that is an IRI, declares one function.
The IRI identifies the function, for example, in SPARQL queries.
The function parameters are declared using sh:parameter
in the same
way as the parameters of constraint components are declared.
The optional property sh:returnType
can be used to specify the type of results
produced by the function.
Finally, sh:JSFunction
is a subclass of sh:JSExecutable
, and
the syntax rules of JavaScript executables apply to functions, too.
In particular, each JavaScript-based function has one value of sh:jsFunctionName
.
This is the name of the JavaScript function that is executed whenever the (SHACL) function is called.
The JavaScript result R
of the execution of the function is turned into
an RDF node using the following rules:
R
is a String
:
return an xsd:string
literal with the string as its lexical form
R
is an Object
representing an RDF node:
return R
R
is a Number
and the function declares a sh:returnType
T
and the Number can be converted to a well-formed literal with datatype T
:
return a literal with datatype T
and the given value as lexical form
R
is a Number
that can be converted to a well-formed literal with datatype xsd:decimal
:
return an xsd:decimal
literal with the given value as lexical form
R
is a Boolean:
return an xsd:boolean
literal with the given value as lexical form
During the execution of a JavaScript function, the variable $data
can be used to access the
current query graph, while the variable $shapes
is undefined.
The SHACL Advanced Features document introduced the concept of SHACL-based rules which included an extension mechanism that can be used to define new rule types. This section defines a rule type called JavaScript rules.
Rule Type IRI | Key Property | Other Properties |
---|---|---|
sh:JSRule |
sh:jsFunctionName |
sh:jsLibrary |
The following example illustrates the use of a JavaScript rule to compute the area of a rectangle, by multiplying width and height.
var NS = "http://datashapes.org/js/tests/rules/rectangle.test#"; function computeArea($this) { var width = getProperty($this, "width"); var height = getProperty($this, "height"); var area = TermFactory.literal(width.lex * height.lex, width.datatype); var areaProperty = TermFactory.namedNode(NS + "area"); return [ [$this, areaProperty, area] ]; } function getProperty($this, name) { var it = $data.find($this, TermFactory.namedNode(NS + name), null); var result = it.next().object; it.close(); return result; }
Note that this code is quite verbose because it uses only the very basic SHACL JavaScript API. In real-world examples, a higher level API with convenience methods is likely used.
ex:RectangleShape a sh:NodeShape ; sh:targetClass ex:Rectangle ; sh:rule [ a sh:JSRule ; # This triple is optional sh:jsFunctionName "computeArea" ; sh:jsLibrary [ sh:jsLibraryURL "http://example.org/js/rectangle.js"^^xsd:anyURI ] ; ] .
For the following data graph, the triples below would be produced.
ex:ExampleRectangle a ex:Rectangle ; ex:width 7 ; ex:height 8 .
Inferred triples:
ex:ExampleRectangle ex:area 56 .
sh:jsLibrary
)
have been executed.
For each focus node, execute the JavaScript function specified as the value of
sh:jsFunctionName
at the rule in the shapes graph, using the focus node
as the first (and only) argument into the function.
If the result R
of the function call is an Array then for each member O
of this Array apply the instructions below.
O
is an Array: Infer a new triple with subject O[0]
,
predicate O[1]
and object O[2]
.
O
is another Object
:
Infer a new triple with subject O.subject
, predicate O.predicate
and object O.object
.
In other words, each member of the Array returned by the JavaScript function must either
be another Array with three members (for subject, predicate and object),
of a JavaScript Object with three fields subject
, predicate
and object
.
As one of the SHACL Advanced Features, custom targets define a mechanism to compute target nodes by more flexible means than the built-in target types. Similar to SPARQL-based targets, this section introduces custom targets based on JavaScript.
Custom targets that are SHACL instances of sh:JSTarget
are called
JavaScript-based targets.
JavaScript-based targets have the same syntax rules as
JavaScript executables (e.g., requires a sh:jsFunctionName
).
The function must return a JavaScript Array where each member is an RDF term Object.
T
be a JavaScript-based target.
The target nodes of T
are the nodes in the Array returned by its
execution against the data graph.
Very similar to SPARQL-based target types,
there is a class sh:JSTargetType
declared as rdfs:subClassOf sh:TargetType
for JavaScript-based target types.
JavaScript-based target types have the same syntax rules as
JavaScript executables (e.g., requires a sh:jsFunctionName
).
The function must return a JavaScript Array where each member is an RDF term Object.
T
be a JavaScript-based target of target type Y
.
The target nodes of T
are the nodes in the Array returned by the
execution of Y
against the data graph.
Similar to JavaScript-based constraint components,
for the execution of the JavaScript function, all parameter values of T
are mapped to the JavaScript arguments by the local name of the parameter property
(for example, ex:country
is passed into the function as values of $country
).
This section enumerates all normative syntax rules of SHACL-JS. This section is automatically generated from other parts of this spec and hyperlinks are provided back into the prose if the context of the rule in unclear. Nodes that violate these rules in a shapes graph are ill-formed.
Syntax Rule Id | Syntax Rule Text |
---|
SHACL-JS shares certain security and privacy considerations with those mentioned in [[!shacl]]. In addition, JavaScript opens a whole new range of topics that are outside of the scope of this document. The general advice is for users to only use trusted and controlled shape graphs.