From cf194fac12895016f8af45471545606e6c7e711a Mon Sep 17 00:00:00 2001 From: Jesse Wright <63333554+jeswr@users.noreply.github.com> Date: Thu, 2 Jul 2026 11:21:17 +0100 Subject: [PATCH 01/11] docs: document validation scope and external term validation Co-Authored-By: Claude Fable 5 --- README.md | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/README.md b/README.md index bec8efe2..5ed784f9 100644 --- a/README.md +++ b/README.md @@ -434,6 +434,62 @@ and allows a mixture of different syntaxes. Pass a `format` option to the constructor with the name or MIME type of a format for strict, fault-intolerant behavior. +### Validation +The parser validates _syntax_: +it rejects everything that violates the grammar of the selected format, +strictly with the `format` option and as a permissive union of formats by default. +It does not validate the resulting _terms_ beyond that grammar: +- IRIs are not checked for full [RFC 3987](https://www.rfc-editor.org/rfc/rfc3987) well-formedness + (`` parses), + and relative IRIs remain relative when no `baseIRI` option is given; +- literal values are not checked against their datatype (`"abc"^^xsd:integer` parses); +- language tags are checked against the grammar, not against [BCP 47](https://www.rfc-editor.org/rfc/rfc5646); +- the writer trusts the terms it is given: + quads constructed with invalid term values are serialized as-is + and can yield invalid documents. + +For such guarantees, chain a validating transform behind the parser, +composing dedicated validators such as +[`validate-iri`](https://www.npmjs.com/package/validate-iri), +[`rdf-validate-datatype`](https://www.npmjs.com/package/rdf-validate-datatype), +and [`bcp-47`](https://www.npmjs.com/package/bcp-47): +```JavaScript +const { Transform } = require('stream'); +const { validateIri, IriValidationStrategy } = require('validate-iri'); +const { validators } = require('rdf-validate-datatype'); +const { parse: parseLanguageTag } = require('bcp-47'); + +function validateTerm(term) { + switch (term.termType) { + case 'NamedNode': // RDF requires absolute IRIs + return validateIri(term.value, IriValidationStrategy.Strict) || null; + case 'Literal': + if (term.language) { + let invalid = false; + parseLanguageTag(term.language, { warning: () => { invalid = true; } }); + return invalid ? new Error(`Invalid language tag "${term.language}"`) : null; + } + const validate = validators.find(term.datatype); + return validate && !validate(term.value) + ? new Error(`Invalid value "${term.value}" for datatype ${term.datatype.value}`) + : null; // unknown datatypes cannot be judged + default: + return null; + } +} + +const quadStream = fs.createReadStream('data.ttl') + .pipe(new N3.StreamParser()) + .pipe(new Transform({ + objectMode: true, + transform(quad, encoding, done) { + const error = validateTerm(quad.subject) || validateTerm(quad.predicate) || + validateTerm(quad.object) || validateTerm(quad.graph); + done(error, error ? undefined : quad); // or: skip/collect instead of failing + }, + })); +``` + ### Interface specifications The N3.js submodules are compatible with the following [RDF.js](http://rdf.js.org) interfaces: From 8ee1e3f1b1bc1a3213c3b4d059087f1963e60414 Mon Sep 17 00:00:00 2001 From: Jesse Wright <63333554+jeswr@users.noreply.github.com> Date: Thu, 2 Jul 2026 19:58:47 +0100 Subject: [PATCH 02/11] docs: note validation dimensions beyond term-level checks Co-Authored-By: Claude Fable 5 --- README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/README.md b/README.md index 5ed784f9..3d10720b 100644 --- a/README.md +++ b/README.md @@ -490,6 +490,24 @@ const quadStream = fs.createReadStream('data.ttl') })); ``` +Term-level checks are one of several validation dimensions +(the [`rdf-validation`](https://github.com/rdf-ext/rdf-validation) library treats these as composable modules): +- _interface conformance_ — whether objects implement the [RDF/JS interfaces](https://rdf.js.org/data-model-spec/), + a concern of the data factory and the type system + rather than of a parser that constructs its own terms + (see [Interface specifications](#interface-specifications) below); +- _version validity_ — RDF 1.2 documents can contain constructs + that are not valid RDF 1.1 + (such as triple terms and directional language tags), + and RDF 1.2 Basic excludes triple terms; +- _N3 validity_ — formulae, variables, and paths are N3-only + and already gated by the `format` option; +- _shape-level validation_ — checking data against schemas + such as SHACL or ShEx is a separate layer on top of well-formed RDF. + +Parser-level opt-in validation modes covering the term and version dimensions +are proposed in [#634](https://github.com/rdfjs/N3.js/pull/634). + ### Interface specifications The N3.js submodules are compatible with the following [RDF.js](http://rdf.js.org) interfaces: From b82c47d735cd7fa771e083d291691c5f2091be34 Mon Sep 17 00:00:00 2001 From: Jesse Wright <63333554+jeswr@users.noreply.github.com> Date: Sun, 23 Aug 2026 18:31:20 +0100 Subject: [PATCH 03/11] Apply suggestion from @jeswr --- README.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/README.md b/README.md index 3d10720b..c468d22e 100644 --- a/README.md +++ b/README.md @@ -435,10 +435,7 @@ Pass a `format` option to the constructor with the name or MIME type of a form for strict, fault-intolerant behavior. ### Validation -The parser validates _syntax_: -it rejects everything that violates the grammar of the selected format, -strictly with the `format` option and as a permissive union of formats by default. -It does not validate the resulting _terms_ beyond that grammar: +The parser validates _syntax_ of the grammar the grammar of the selected format, with the following exceptions: - IRIs are not checked for full [RFC 3987](https://www.rfc-editor.org/rfc/rfc3987) well-formedness (`` parses), and relative IRIs remain relative when no `baseIRI` option is given; From 55deccbed62c652442d6dca1a2b6ae5a8a7a2510 Mon Sep 17 00:00:00 2001 From: Jesse Wright <63333554+jeswr@users.noreply.github.com> Date: Sun, 23 Aug 2026 18:32:34 +0100 Subject: [PATCH 04/11] Apply suggestion from @jeswr --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c468d22e..caacb100 100644 --- a/README.md +++ b/README.md @@ -441,9 +441,8 @@ The parser validates _syntax_ of the grammar the grammar of the selected format, and relative IRIs remain relative when no `baseIRI` option is given; - literal values are not checked against their datatype (`"abc"^^xsd:integer` parses); - language tags are checked against the grammar, not against [BCP 47](https://www.rfc-editor.org/rfc/rfc5646); -- the writer trusts the terms it is given: - quads constructed with invalid term values are serialized as-is - and can yield invalid documents. + +The **writer** trusts the terms it is given. Quads constructed with invalid term values are serialized as-is and can yield invalid documents. For such guarantees, chain a validating transform behind the parser, composing dedicated validators such as From feea19c7b1b9e1943df77604403295d7b359a1e0 Mon Sep 17 00:00:00 2001 From: Jesse Wright <63333554+jeswr@users.noreply.github.com> Date: Sun, 23 Aug 2026 18:33:11 +0100 Subject: [PATCH 05/11] Apply suggestion from @jeswr --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index caacb100..5156987a 100644 --- a/README.md +++ b/README.md @@ -435,7 +435,7 @@ Pass a `format` option to the constructor with the name or MIME type of a form for strict, fault-intolerant behavior. ### Validation -The parser validates _syntax_ of the grammar the grammar of the selected format, with the following exceptions: +The **parser** validates _syntax_ of the grammar the grammar of the selected format, with the following exceptions: - IRIs are not checked for full [RFC 3987](https://www.rfc-editor.org/rfc/rfc3987) well-formedness (`` parses), and relative IRIs remain relative when no `baseIRI` option is given; From 934c3d89f3c6dcd3df6ae7be800c1ee0ed6576b3 Mon Sep 17 00:00:00 2001 From: Jesse Wright <63333554+jeswr@users.noreply.github.com> Date: Sun, 23 Aug 2026 18:36:41 +0100 Subject: [PATCH 06/11] Apply suggestion from @jeswr --- README.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 5156987a..d7facc3c 100644 --- a/README.md +++ b/README.md @@ -444,11 +444,9 @@ The **parser** validates _syntax_ of the grammar the grammar of the selected for The **writer** trusts the terms it is given. Quads constructed with invalid term values are serialized as-is and can yield invalid documents. -For such guarantees, chain a validating transform behind the parser, -composing dedicated validators such as -[`validate-iri`](https://www.npmjs.com/package/validate-iri), -[`rdf-validate-datatype`](https://www.npmjs.com/package/rdf-validate-datatype), -and [`bcp-47`](https://www.npmjs.com/package/bcp-47): +Therefore, term validation should be done post-parsing to ensure that valid RDF terms should be produced. + +One should also ensure that terms are valid prior to being passed into the writer; either by validation, or ensuring that valid RDF will always be produced by the application logic producing the terms. ```JavaScript const { Transform } = require('stream'); const { validateIri, IriValidationStrategy } = require('validate-iri'); From 46fb4ee11b7056d2031575978dd1572f9ad93033 Mon Sep 17 00:00:00 2001 From: Jesse Wright <63333554+jeswr@users.noreply.github.com> Date: Sun, 23 Aug 2026 18:41:14 +0100 Subject: [PATCH 07/11] Apply suggestion from @jeswr --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index d7facc3c..abdac3df 100644 --- a/README.md +++ b/README.md @@ -447,6 +447,8 @@ The **writer** trusts the terms it is given. Quads constructed with invalid term Therefore, term validation should be done post-parsing to ensure that valid RDF terms should be produced. One should also ensure that terms are valid prior to being passed into the writer; either by validation, or ensuring that valid RDF will always be produced by the application logic producing the terms. + +The following code snipped shows how to validate that NamedNodes and Literals are validly formed. Depending on your application you may wish to apply further validation: such as ensuring that nested Quad terms are valid in RDF 1.2, and ensuring that `termTypes` are only occuring in the positions that is valid for RDF 1.1 and RDF 1.2. ```JavaScript const { Transform } = require('stream'); const { validateIri, IriValidationStrategy } = require('validate-iri'); From c3097954170d0c9235547278575b3519c14739da Mon Sep 17 00:00:00 2001 From: Jesse Wright <63333554+jeswr@users.noreply.github.com> Date: Sun, 23 Aug 2026 18:41:33 +0100 Subject: [PATCH 08/11] Apply suggestion from @jeswr --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index abdac3df..23422058 100644 --- a/README.md +++ b/README.md @@ -448,6 +448,8 @@ Therefore, term validation should be done post-parsing to ensure that valid RDF One should also ensure that terms are valid prior to being passed into the writer; either by validation, or ensuring that valid RDF will always be produced by the application logic producing the terms. +The following code snipped shows how to validate that NamedNodes and Literals are validly formed. Depending on your application you may wish to apply further validation: such as ensuring that nested Quad terms are valid in RDF 1.2, and ensuring that `termTypes` are only occuring in the positions that is valid for RDF 1.1 and RDF 1.2. + The following code snipped shows how to validate that NamedNodes and Literals are validly formed. Depending on your application you may wish to apply further validation: such as ensuring that nested Quad terms are valid in RDF 1.2, and ensuring that `termTypes` are only occuring in the positions that is valid for RDF 1.1 and RDF 1.2. ```JavaScript const { Transform } = require('stream'); From 894cb09a090ff424f46730c08e4d9b49f377fabe Mon Sep 17 00:00:00 2001 From: Jesse Wright <63333554+jeswr@users.noreply.github.com> Date: Sun, 23 Aug 2026 18:42:42 +0100 Subject: [PATCH 09/11] Apply suggestion from @jeswr --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 23422058..abdac3df 100644 --- a/README.md +++ b/README.md @@ -448,8 +448,6 @@ Therefore, term validation should be done post-parsing to ensure that valid RDF One should also ensure that terms are valid prior to being passed into the writer; either by validation, or ensuring that valid RDF will always be produced by the application logic producing the terms. -The following code snipped shows how to validate that NamedNodes and Literals are validly formed. Depending on your application you may wish to apply further validation: such as ensuring that nested Quad terms are valid in RDF 1.2, and ensuring that `termTypes` are only occuring in the positions that is valid for RDF 1.1 and RDF 1.2. - The following code snipped shows how to validate that NamedNodes and Literals are validly formed. Depending on your application you may wish to apply further validation: such as ensuring that nested Quad terms are valid in RDF 1.2, and ensuring that `termTypes` are only occuring in the positions that is valid for RDF 1.1 and RDF 1.2. ```JavaScript const { Transform } = require('stream'); From bfcd94fe3b65ebafb89163eae98e0aafa9c6af41 Mon Sep 17 00:00:00 2001 From: Jesse Wright <63333554+jeswr@users.noreply.github.com> Date: Sun, 23 Aug 2026 18:43:26 +0100 Subject: [PATCH 10/11] Apply suggestion from @jeswr --- README.md | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/README.md b/README.md index abdac3df..4568e052 100644 --- a/README.md +++ b/README.md @@ -486,20 +486,6 @@ const quadStream = fs.createReadStream('data.ttl') })); ``` -Term-level checks are one of several validation dimensions -(the [`rdf-validation`](https://github.com/rdf-ext/rdf-validation) library treats these as composable modules): -- _interface conformance_ — whether objects implement the [RDF/JS interfaces](https://rdf.js.org/data-model-spec/), - a concern of the data factory and the type system - rather than of a parser that constructs its own terms - (see [Interface specifications](#interface-specifications) below); -- _version validity_ — RDF 1.2 documents can contain constructs - that are not valid RDF 1.1 - (such as triple terms and directional language tags), - and RDF 1.2 Basic excludes triple terms; -- _N3 validity_ — formulae, variables, and paths are N3-only - and already gated by the `format` option; -- _shape-level validation_ — checking data against schemas - such as SHACL or ShEx is a separate layer on top of well-formed RDF. Parser-level opt-in validation modes covering the term and version dimensions are proposed in [#634](https://github.com/rdfjs/N3.js/pull/634). From e1ad809e3bb9b1b40f3430e3d4168c3722b7b9d8 Mon Sep 17 00:00:00 2001 From: Jesse Wright <63333554+jeswr@users.noreply.github.com> Date: Sun, 23 Aug 2026 18:47:31 +0100 Subject: [PATCH 11/11] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9257a597..93d6736a 100644 --- a/README.md +++ b/README.md @@ -497,7 +497,7 @@ Pass a `format` option to the constructor with the name or MIME type of a form for strict, fault-intolerant behavior. ### Validation -The **parser** validates _syntax_ of the grammar the grammar of the selected format, with the following exceptions: +The **parser** validates the _syntax_ of the selected format's grammar, with the following exceptions: - IRIs are not checked for full [RFC 3987](https://www.rfc-editor.org/rfc/rfc3987) well-formedness (`` parses), and relative IRIs remain relative when no `baseIRI` option is given;