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.

Document Conventions

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

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.

JavaScript API for RDF

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.

RDF Terms

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.

IRIs / Named Nodes

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.

Blank Nodes

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.

The TermFactory

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:

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("");
	var labels = $data.find(resource, labelProperty, null);
	for(;;) {
		var labelTriple =;
		if(!labelTriple) {
			return null;
		var label = labelTriple.object;
		if(label.isLiteral() && label.language.startsWith("en")) {
			return label.value;

Accessing the Data Graph via $data

During a validation process, the variable $data points at the JavaScript Graph Object representing the SHACL data graph.

Accessing the Shapes Graph via $shapes

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.

Synchronous versus Asynchronous Queries

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.

Validating Nodes via JavaScript

SHACL-JS processors must provide a JavaScript function with the following signature:

SHACL.nodeConformsToShape(node, shape)
  1. node: The RDF term Object of the node to validate
  2. shape: 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.

Representing JavaScript in RDF

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.

Executing JavaScript

This section defines general rules for the execution of JavaScript declared in RDF, by a SHACL engine.

Execution of a JavaScript function
Let 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.

Execution of a JavaScript executable
The execution of a JavaScript executable consists of executing any JavaScript libraries that are values of 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.
Execution of a JavaScript library
Within the same JavaScript engine, the same JavaScript library MUST NOT be executed more than once. When a JavaScript library is executed, all its values for 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.

JavaScript-based Constraints

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.

An Example JavaScript-based Constraint

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("");
	var s = $data.find($this, p, null);
	for(var t =; t; t = {
		var object = t.object;
		if(!object.isLiteral() || !object.language.startsWith("de")) {
				value : object
	return results;
	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 "" ] ;
		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 ;
] .

Validation with JavaScript-based Constraints

This section defines the validator of sh:JSConstraintComponent.

There are no validation results if the JavaScript-based constraint has 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.

Mapping of JavaScript Results to Result Properties

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.

  1. If 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.
  2. If R is a JavaScript Array: For each member of the Array R apply the rule for JavaScript Objects.
  3. If 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.
  4. If 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.

JavaScript-based Constraint Components

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.

An Example JavaScript-based Constraint Component

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;
	a sh:ConstraintComponent ;
	sh:parameter [
		sh:path sh:maxLength ;
		sh:datatype xsd:integer ;
	] ;
	sh:validator 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 ""^^xsd:anyURI ] ;
	sh:jsFunctionName "hasMaxLength" .

Syntax of JavaScript-based Constraint Components

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.

Validation of JavaScript-based Constraint Components

This section defines the validator of JavaScript-based constraint components.

Let ?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.

JavaScript-based Functions

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.

An Example JavaScript-based Function

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;
	a sh:JSFunction ;
	sh:parameter [
		sh:path ex:number ;
		sh:datatype xsd:integer ;
	] ;
	sh:returnType xsd:integer ;
	sh:jsLibrary [ sh:jsLibraryURL ""^^xsd:anyURI ] ;
	sh:jsFunctionName "square" .

Syntax and Semantics of JavaScript-based Functions

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:

  1. If R is a String: return an xsd:string literal with the string as its lexical form
  2. If R is an Object representing an RDF node: return R
  3. If 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
  4. If 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
  5. If R is a Boolean: return an xsd:boolean literal with the given value as lexical form
  6. Otherwise: return no result

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.

JavaScript Rules

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

An Example JavaScript Rule

The following example illustrates the use of a JavaScript rule to compute the area of a rectangle, by multiplying width and height.

var NS = "";

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 =;
	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.

	a sh:NodeShape ;
	sh:targetClass ex:Rectangle ;
	sh:rule [
		a sh:JSRule ;    # This triple is optional
		sh:jsFunctionName "computeArea" ;
		sh:jsLibrary [ sh:jsLibraryURL ""^^xsd:anyURI ] ;
    ] .

For the following data graph, the triples below would be produced.

	a ex:Rectangle ;
	ex:width 7 ;
	ex:height 8 .

Inferred triples:

	ex:ExampleRectangle ex:area 56 .

Execution Instructions for JavaScript Rules

Prior to execution, ensure that all JavaScript libraries for the rule (specified via 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.
  1. If O is an Array: Infer a new triple with subject O[0], predicate O[1] and object O[2].
  2. If 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.

JavaScript-based Custom Targets

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.

JavaScript-based Targets (sh:JSTarget)

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.

Let 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.

JavaScript-based Target Types (sh:JSTargetType)

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.

Let 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).


Summary of SHACL-JS Syntax Rules

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

Security and Privacy Considerations

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.