# n3

> Lightning fast, asynchronous, streaming Turtle / N3 / RDF library.

Latest version **2.7.12** (published 2026-09-06) · MIT license · 0 weekly downloads

## Install

```sh
npm install n3
pnpm add n3
yarn add n3
bun add n3
```

## Health

**Score 73/100 (B)** — status: active.

Positive: has types package; esm support; no vulnerabilities; has provenance; recently updated; high maintenance score; high quality score.

Warnings: low downloads.

## Facts

| | |
|---|---|
| Version | 2.7.12 |
| Published | 2026-09-06 |
| First published | 2011-12-27 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | separate (@types/n3) |
| Module format | ESM + CommonJS |
| Node | >=12.0 |
| Dependencies | 2 |
| Unpacked size | 806.7 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Provenance | attested (GitHub Actions) |
| GitHub stars | 796 |
| Author | Ruben Verborgh |
| Maintainers | rubenverborgh, rubensworks |
| Keywords | turtle, rdf, n3, streaming, asynchronous |

## Links

- npm: https://www.npmjs.com/package/n3
- Repository: https://github.com/rdfjs/N3.js
- Homepage: https://github.com/rdfjs/N3.js#readme
- Issues: https://github.com/rdfjs/N3.js/issues
- npm.io page: https://npm.io/package/n3

## Dependencies (2)

- [buffer](https://npm.io/package/buffer.md) ^6.0.3
- [readable-stream](https://npm.io/package/readable-stream.md) ^4.0.0

## Alternatives

- [byte-size](https://npm.io/package/byte-size.md) — 2.1M weekly downloads
- [speed-limiter](https://npm.io/package/speed-limiter.md) — 16.0K weekly downloads
- [@powersync/node](https://npm.io/package/@powersync/node.md) — 10.9K weekly downloads
- [@ledgerhq/coin-cardano](https://npm.io/package/@ledgerhq/coin-cardano.md) — 1.0K weekly downloads
- [@jayesol/jayeson.lib.streamfinder](https://npm.io/package/@jayesol/jayeson.lib.streamfinder.md) — 1.0K weekly downloads

## Recent versions

- 2.7.12 (latest) — 2026-09-06
- 2.0.0-beta.2 (next) — 2025-11-03
- 2.7.11 — 2026-09-06
- 2.7.10 — 2026-09-06
- 2.7.9 — 2026-09-05
- 2.7.8 — 2026-09-05
- 2.7.7 — 2026-09-05
- 2.7.6 — 2026-09-05
- 2.7.5 — 2026-09-05
- 2.7.4 — 2026-09-03
- 2.7.3 — 2026-09-02
- 2.7.2 — 2026-09-01
- 2.7.1 — 2026-09-01
- 2.7.0 — 2026-09-01
- 2.6.4 — 2026-08-28
- … 166 more at https://npm.io/package/n3/versions

## README

# Lightning fast, asynchronous, streaming RDF for JavaScript
[![Build Status](https://github.com/rdfjs/n3.js/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/rdfjs/N3.js/actions)
[![Coverage Status](https://coveralls.io/repos/github/rdfjs/N3.js/badge.svg)](https://coveralls.io/github/rdfjs/N3.js)
[![npm version](https://badge.fury.io/js/n3.svg)](https://www.npmjs.com/package/n3)
[![DOI](https://zenodo.org/badge/3058202.svg)](https://zenodo.org/badge/latestdoi/3058202)

The N3.js library is an implementation of the [RDF.js low-level specification](http://rdf.js.org/) that lets you handle [RDF 1.2](https://www.w3.org/TR/rdf-primer/) in JavaScript easily.
It offers:

- [**Parsing**](#parsing) triples/quads from
  [Turtle](https://www.w3.org/TR/turtle/),
  [TriG](https://www.w3.org/TR/trig/),
  [N-Triples](https://www.w3.org/TR/n-triples/),
  [N-Quads](https://www.w3.org/TR/n-quads/),
  and [Notation3 (N3)](https://www.w3.org/TeamSubmission/n3/)
- [**Writing**](#writing) triples/quads to
  [Turtle](https://www.w3.org/TR/turtle/),
  [TriG](https://www.w3.org/TR/trig/),
  [N-Triples](https://www.w3.org/TR/n-triples/),
  and [N-Quads](https://www.w3.org/TR/n-quads/)
- [**Storage**](#storing) of triples/quads in memory

Parsing and writing is:
- 🎛 **asynchronous** – triples arrive as soon as possible
- 🚰 **streaming** – streams are parsed as data comes in, so you can parse files larger than memory
- ⚡️ **fast** – triples are flying out at high speeds

## Installation
For Node.js, N3.js comes as an [npm package](https://npmjs.org/package/n3).

```Bash
$ npm install n3
```

```JavaScript
const N3 = require('n3');
```

N3.js seamlessly works in browsers via [webpack](https://webpack.js.org/)
or [browserify](http://browserify.org/).
If you're unfamiliar with these tools,
you can read
[_webpack: Creating a Bundle – getting started_](https://webpack.js.org/guides/getting-started/#creating-a-bundle)
or
[_Introduction to browserify_](https://writingjavascript.org/posts/introduction-to-browserify).
You will need to create a "UMD bundle" and supply a name (e.g. with the `-s N3` option in browserify).

You can also load it via CDN, either as a classic script that exposes a global `N3`:
```html
<script src="https://unpkg.com/n3/browser/n3.min.js"></script>
```
or as an ES module that you can import directly:
```html
<script type="module">
  import { Store, Parser, Writer } from 'https://unpkg.com/n3/browser/n3.esm.min.js';
</script>
```

## Creating triples/quads
N3.js follows the [RDF.js low-level specification](http://rdf.js.org/).

`N3.DataFactory` will give you the [factory](http://rdf.js.org/#datafactory-interface) functions to create triples and quads:

```JavaScript
const { DataFactory } = N3;
const { namedNode, literal, defaultGraph, quad } = DataFactory;
const myQuad = quad(
  namedNode('https://ruben.verborgh.org/profile/#me'), // Subject
  namedNode('http://xmlns.com/foaf/0.1/givenName'),    // Predicate
  literal('Ruben', 'en'),                              // Object
  defaultGraph(),                                      // Graph
);
console.log(myQuad.termType);              // Quad
console.log(myQuad.value);                 // ''
console.log(myQuad.subject.value);         // https://ruben.verborgh.org/profile/#me
console.log(myQuad.object.value);          // Ruben
console.log(myQuad.object.datatype.value); // http://www.w3.org/1999/02/22-rdf-syntax-ns#langString
console.log(myQuad.object.language);       // en
```

When no language or datatype is supplied, `literal` automatically assigns XSD datatypes
to JavaScript booleans, numbers, and valid `Date` objects. Dates are converted to UTC
using `Date.prototype.toISOString()` and receive the `xsd:dateTime` datatype:

```JavaScript
const created = literal(new Date('2017-04-27T14:39:48.901Z'));
console.log(created.value);          // 2017-04-27T14:39:48.901Z
console.log(created.datatype.value); // http://www.w3.org/2001/XMLSchema#dateTime
```

Always create terms through a data factory such as `N3.DataFactory`,
and not by instantiating the term classes directly:
direct construction is deprecated,
because the factory functions are where term validation can be applied.
In line with the [RDF/JS specification](http://rdf.js.org/data-model-spec/),
N3.js assumes that the value of any RDF/JS term it receives —
whether from its own factory or from another implementation —
was already validated when the term was created,
and does not re-validate terms.

In the rest of this document, we will treat “triples” and “quads” equally:
we assume that a quad is simply a triple in a named or default graph.

## Parsing

### From an RDF document to quads

`N3.Parser` transforms Turtle, TriG, N-Triples, or N-Quads document into quads through a callback:
```JavaScript
const tomAndJerry = `PREFIX c: <http://example.org/cartoons#>
  # Tom is a cat
  c:Tom a c:Cat.
  c:Jerry a c:Mouse;
    c:smarterThan c:Tom.`

const parser = new N3.Parser();

parser.parse(tomAndJerry,
  (error, quad, prefixes) => {
    if (quad)
      console.log(quad);
    else
      console.log("# That's all, folks!", prefixes);
  });
```
The callback's first argument is an optional error value, the second is a quad.
If there are no more quads,
the callback is invoked one last time with `null` for `quad`
and a hash of prefixes as third argument.
<br>

Alternatively, an object can be supplied, where `onQuad`, `onPrefix` and `onComment` are used to listen for `quads`, `prefixes` and `comments` as follows:
```JavaScript
const parser = new N3.Parser();

parser.parse(tomAndJerry, {
  // onQuad (required) accepts a listener of type (quad: RDF.Quad) => void
  onQuad: (err, quad) => { console.log(quad); },
  // onPrefix (optional) accepts a listener of type (prefix: string, iri: NamedNode) => void
  onPrefix: (prefix, iri) => { console.log(prefix, 'expands to', iri.value); },
  // onComment (optional) accepts a listener of type (comment: string) => void
  onComment: (comment) => { console.log('#', comment); },
});
```

If no callbacks are provided, parsing happens synchronously returning an array of quads:

```JavaScript
const parser = new N3.Parser();

// An array of resultant Quads
const quadArray = parser.parse(tomAndJerry);
```

By default, `N3.Parser` parses a permissive superset of Turtle, TriG, N-Triples, and N-Quads.
<br>
For strict compatibility with any of those languages, pass a `format` argument upon creation:

```JavaScript
const parser1 = new N3.Parser({ format: 'N-Triples' });
const parser2 = new N3.Parser({ format: 'application/trig' });
```

Notation3 (N3) is supported _only_ through the `format` argument:

```JavaScript
const parser3 = new N3.Parser({ format: 'N3' });
const parser4 = new N3.Parser({ format: 'Notation3' });
const parser5 = new N3.Parser({ format: 'text/n3' });
```

It is possible to provide the base IRI of the document that you want to parse.
This is done by passing a `baseIRI` argument upon creation:
```JavaScript
const parser = new N3.Parser({ baseIRI: 'http://example.org/' });
```

In N3 mode, `implicitEmptyPrefix` can bind an undeclared empty prefix to the
document IRI with a `#` fragment:
```JavaScript
const parser = new N3.Parser({
  format: 'text/n3',
  baseIRI: 'http://example.org/document',
  implicitEmptyPrefix: true,
});
```

By default, `N3.Parser` will prefix blank node labels with a `b{digit}_` prefix.
This is done to prevent collisions of unrelated blank nodes having identical
labels. The `blankNodePrefix` constructor argument can be used to modify the
prefix or, if set to an empty string, completely disable prefixing:
```JavaScript
const parser = new N3.Parser({ blankNodePrefix: '' });
```

The parser can output a backwards chaining rule such as `_:q <= _:p.` in two ways:
- as `_:p log:implies _:q.` (default)
- as `_:q log:isImpliedBy _:p.` (when the `isImpliedBy` flag is set to `true`)
```JavaScript
const parser = new N3.Parser({ isImpliedBy: true });
```

By default, an empty formula `{}` is kept as a blank node graph term.
The [N3 spec tests](https://w3c-cg.github.io/N3/tests/)
(and the direction discussed in [w3c-cg/N3#185](https://github.com/w3c-cg/N3/issues/185))
read it as the boolean literal `"true"^^xsd:boolean` instead;
the `emptyFormulaAsTrue` flag enables that behavior:
```JavaScript
const parser = new N3.Parser({ format: 'text/n3', emptyFormulaAsTrue: true });
```

### From an RDF stream to quads

`N3.Parser` can parse [Node.js streams](http://nodejs.org/api/stream.html) as they grow,
returning quads as soon as they're ready.

```JavaScript
const parser = new N3.Parser(),
      rdfStream = fs.createReadStream('cartoons.ttl');
parser.parse(rdfStream, console.log);
```

`N3.StreamParser` is a [Node.js stream](http://nodejs.org/api/stream.html) and [RDF.js Sink](http://rdf.js.org/#sink-interface) implementation.
This solution is ideal if your consumer is slower,
since source data is only read when the consumer is ready.

```JavaScript
const streamParser = new N3.StreamParser(),
      rdfStream = fs.createReadStream('cartoons.ttl');
rdfStream.pipe(streamParser);
streamParser.pipe(new SlowConsumer());

function SlowConsumer() {
  const writer = new require('stream').Writable({ objectMode: true });
  writer._write = (quad, encoding, done) => {
    console.log(quad);
    setTimeout(done, 1000);
  };
  return writer;
}
```

A dedicated `prefix` event signals every prefix with `prefix` and `term` arguments.
A dedicated `comment` event can be enabled by setting `comments: true` in the N3.StreamParser constructor.

Note that `prefix` and `comment` events are emitted as soon as they are parsed,
whereas quads can remain buffered until the consumer is ready to read them.
The order of these events relative to `data` events is therefore
not guaranteed to match the position of prefixes and comments in the document.
If their position matters,
use `N3.Parser` with the `onQuad`, `onPrefix` and `onComment` callbacks instead,
which are invoked in document order.

### From a Web Stream to quads

N3.js consumes [Node.js streams](http://nodejs.org/api/stream.html) natively,
but sources such as `fetch` produce [Web Streams](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API).
On Node.js 17 or higher, convert such a stream into a Node.js stream:

```JavaScript
const streamParser = new N3.StreamParser(),
      { Readable } = require('stream');
Readable.fromWeb(response.body).pipe(streamParser);
```

In browsers (or anywhere without Node.js streams),
write the chunks to the parser directly,
since `N3.StreamParser` exposes a standard writable stream interface:

```JavaScript
const streamParser = new N3.StreamParser(),
      reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
(async () => {
  for (let result; !(result = await reader.read()).done;)
    if (!streamParser.write(result.value))
      await new Promise(resolve => streamParser.once('drain', resolve));
  streamParser.end();
})();
```

## Writing

### From quads to a string

`N3.Writer` serializes quads as an RDF document.
Write quads through `addQuad`.

```JavaScript
const writer = new N3.Writer({ prefixes: { c: 'http://example.org/cartoons#' } }); // Create a writer which uses `c` as a prefix for the namespace `http://example.org/cartoons#`
writer.addQuad(quad(
  namedNode('http://example.org/cartoons#Tom'),   // Subject
  namedNode('http://example.org/cartoons#name'),  // Predicate
  literal('Tom')                                  // Object
));
writer.end((error, result) => console.log(result));
```

By default, `N3.Writer` writes Turtle (or TriG if some quads are in a named graph).
<br>
To write N-Triples (or N-Quads) instead, pass a `format` argument upon creation:

```JavaScript
const writer1 = new N3.Writer({ format: 'N-Triples' });
const writer2 = new N3.Writer({ format: 'application/trig' });
```

A `baseIRI` argument makes the writer abbreviate IRIs relative to that base in Turtle/TriG serializations. Pass `writeBase: true` to also write the base as an `@base` directive at the top of the document (N-Triples and N-Quads remain directive-free).

```JavaScript
const writer = new N3.Writer({ baseIRI: 'http://example.org/', writeBase: true });
```

### From quads to an RDF stream

`N3.Writer` can also write quads to a Node.js stream through `addQuad`.

```JavaScript
const writer = new N3.Writer(process.stdout, { end: false, prefixes: { c: 'http://example.org/cartoons#' } });
writer.addQuad(
  namedNode('http://example.org/cartoons#Tom'),                   // Subject
  namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'),   // Predicate
  namedNode('http://example.org/cartoons#Cat')                    // Object
);
writer.addQuad(quad(
  namedNode('http://example.org/cartoons#Tom'),     // Subject
  namedNode('http://example.org/cartoons#name'),  // Predicate
  literal('Tom')                                    // Object
));
writer.end();
```

### From a quad stream to an RDF stream

`N3.StreamWriter` is a [Node.js stream](http://nodejs.org/api/stream.html) and [RDF.js Sink](http://rdf.js.org/#sink-interface) implementation.

```JavaScript
const streamParser = new N3.StreamParser(),
      inputStream = fs.createReadStream('cartoons.ttl'),
      streamWriter = new N3.StreamWriter({ prefixes: { c: 'http://example.org/cartoons#' } });
inputStream.pipe(streamParser);
streamParser.pipe(streamWriter);
streamWriter.pipe(process.stdout);
```

### Blank nodes and lists
You might want to use the `[…]` and list `(…)` notations of Turtle and TriG.
However, a streaming writer cannot create these automatically:
the shorthand notations are only possible if blank nodes or list heads are not used later on,
which can only be determined conclusively at the end of the stream.

The `blank` and `list` functions allow you to create them manually instead:
```JavaScript
const writer = new N3.Writer({ prefixes: { c: 'http://example.org/cartoons#',
                                       foaf: 'http://xmlns.com/foaf/0.1/' } });
writer.addQuad(
  writer.blank(
    namedNode('http://xmlns.com/foaf/0.1/givenName'),
    literal('Tom', 'en')),
  namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'),
  namedNode('http://example.org/cartoons#Cat')
);
writer.addQuad(quad(
  namedNode('http://example.org/cartoons#Jerry'),
  namedNode('http://xmlns.com/foaf/0.1/knows'),
  writer.blank([{
    predicate: namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'),
    object:    namedNode('http://example.org/cartoons#Cat'),
  },{
    predicate: namedNode('http://xmlns.com/foaf/0.1/givenName'),
    object:    literal('Tom', 'en'),
  }])
));
writer.addQuad(
  namedNode('http://example.org/cartoons#Mammy'),
  namedNode('http://example.org/cartoons#hasPets'),
  writer.list([
    namedNode('http://example.org/cartoons#Tom'),
    namedNode('http://example.org/cartoons#Jerry'),
  ])
);
writer.end((error, result) => console.log(result));
```

## Storing

`N3.Store` allows you to store triples in memory and find them fast.

In this example, we create a new store and add the triples `:Pluto a :Dog.` and `:Mickey a :Mouse`.
<br>
Then, we find triples with `:Mickey` as subject.

```JavaScript
const store = new N3.Store();
store.add(
  quad(
    namedNode('http://ex.org/Pluto'),
    namedNode('http://ex.org/type'),
    namedNode('http://ex.org/Dog')
  )
);
store.add(
  quad(
    namedNode('http://ex.org/Mickey'),
    namedNode('http://ex.org/type'),
    namedNode('http://ex.org/Mouse')
  )
);

// Retrieve all quads
for (const quad of store)
  console.log(quad);
// Retrieve Mickey's quads
for (const quad of store.match(namedNode('http://ex.org/Mickey'), null, null))
  console.log(quad);
```

If you are using multiple stores, you can reduce memory consumption by allowing them to share an entity index:
```JavaScript
const entityIndex = new N3.EntityIndex();
const store1 = new N3.Store([], { entityIndex });
const store2 = new N3.Store([], { entityIndex });
```

### [`Dataset` Interface](https://rdf.js.org/dataset-spec/#dataset-interface)
This store adheres to the `Dataset` interface which exposes the following properties

Attributes:
 - `size` — A non-negative integer that specifies the number of quads in the set.

Methods:
 - `add` — Adds the specified quad to the dataset. Existing quads, as defined in `Quad.equals`, will be ignored.
 - `delete` — Removes the specified quad from the dataset.
 - `has` — Determines whether a dataset includes a certain quad.
 - `match` — Returns a new dataset that is comprised of all quads in the current instance matching the given arguments.
 - `[Symbol.iterator]` — Implements the iterator protocol to allow iteration over all `quads` in the dataset as in the example above.

### Addition and deletion of quads
The store implements the following manipulation methods in addition to the standard [`Dataset` Interface](https://rdf.js.org/dataset-spec/#dataset-interface)
([documentation](http://rdfjs.github.io/N3.js/docs/N3Store.html)):
- `addQuad` to insert one quad
- `addQuads` to insert an array of quads
- `removeQuad` to remove one quad
- `removeQuads` to remove an array of quads
- `remove` to remove a stream of quads
- `removeMatches` to remove all quads matching the given pattern
- `deleteGraph` to remove all quads with the given graph
- `createBlankNode` returns an unused blank node identifier

### Searching quads or entities
The store provides the following search methods
([documentation](http://rdfjs.github.io/N3.js/docs/N3Store.html)):
- `match` returns a stream and generator of quads matching the given pattern
- `getQuads` returns an array of quads matching the given pattern
- `countQuads` counts the number of quads matching the given pattern
- `forEach` executes a callback on all matching quads
- `every` returns whether a callback on matching quads always returns true
- `some`  returns whether a callback on matching quads returns true at least once
- `getSubjects` returns an array of unique subjects occurring in matching quads
- `forSubjects` executes a callback on unique subjects occurring in matching quads
- `getPredicates` returns an array of unique predicates occurring in matching quad
- `forPredicates` executes a callback on unique predicates occurring in matching quads
- `getObjects` returns an array of unique objects occurring in matching quad
- `forObjects` executes a callback on unique objects occurring in matching quads
- `getGraphs` returns an array of unique graphs occurring in matching quad
- `forGraphs` executes a callback on unique graphs occurring in matching quads

## Reasoning

N3.js supports reasoning as follows:

```JavaScript
import { Reasoner, Store, Parser } from 'n3';

const parser = new Parser({ format: 'text/n3' });
const rules = `
{
  ?s a ?o .
  ?o <http://www.w3.org/2000/01/rdf-schema#subClassOf> ?o2 .
} => {
  ?s a ?o2 .
} .
`

const rulesDataset = new Store(parser.parse(rules));
const dataset = new Store(/* Dataset */)

// Applies the rules to the store; mutating it
const reasoner = new Reasoner(store);
reasoner.reason(rulesDataset);
```

**Note**: N3.js currently only supports rules with [Basic Graph Patterns](https://www.w3.org/TR/sparql11-query/#BasicGraphPattern) in the premise and conclusion. Built-ins and backward-chaining are *not* supported. For an RDF/JS reasoner that supports all Notation3 reasoning features, see [eye-js](https://github.com/eyereasoner/eye-js/).

### Limiting reasoning cost

When reasoning over rules or data that are not fully trusted,
optional budgets bound the work `reason()` may perform:

```JavaScript
const reasoner = new Reasoner(store, {
  maxDerivations: 100000, // maximum number of quads reason() may derive
  maxPremiseDepth: 10,    // maximum number of premise triples per rule
});
reasoner.reason(rulesDataset);
```

Both budgets are unbounded by default;
`reason()` throws when one is exceeded,
leaving any quads derived up to that point in the store.

## Compatibility
### Format specifications
The N3.js parser and writer is fully compatible with the following W3C specifications:
- [RDF 1.1 Turtle](https://www.w3.org/TR/turtle/)
  – [EARL report](https://raw.githubusercontent.com/rdfjs/N3.js/earl/n3js-earl-report-turtle.ttl)
- [RDF 1.1 TriG](https://www.w3.org/TR/trig/)
  – [EARL report](https://raw.githubusercontent.com/rdfjs/N3.js/earl/n3js-earl-report-trig.ttl)
- [RDF 1.1 N-Triples](https://www.w3.org/TR/n-triples/)
  – [EARL report](https://raw.githubusercontent.com/rdfjs/N3.js/earl/n3js-earl-report-ntriples.ttl)
- [RDF 1.1 N-Quads](https://www.w3.org/TR/n-quads/)
  – [EARL report](https://raw.githubusercontent.com/rdfjs/N3.js/earl/n3js-earl-report-nquads.ttl)
- [RDF 1.2 Turtle](https://www.w3.org/TR/rdf12-turtle/)
- [RDF 1.2 TriG](https://www.w3.org/TR/rdf12-trig/)
- [RDF 1.2 N-Triples](https://www.w3.org/TR/rdf12-n-triples/)
- [RDF 1.2 N-Quads](https://www.w3.org/TR/rdf12-n-quads/)

In addition, the N3.js parser also supports [Notation3 (N3)](https://www.w3.org/TeamSubmission/n3/) (no official specification yet).

The default mode is permissive
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 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
  (`<http://example.org/%ZZ>` 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.

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');
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
    },
  }));
```


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:

- `N3.DataFactory` implements
  [`DataFactory`](http://rdf.js.org/data-model-spec/#datafactory-interface)
  - the terms it creates implement [`Term`](http://rdf.js.org/data-model-spec/#term-interface)
    and one of
    [`NamedNode`](http://rdf.js.org/data-model-spec/#namednode-interface),
    [`BlankNode`](http://rdf.js.org/data-model-spec/#blanknode-interface),
    [`Literal`](http://rdf.js.org/data-model-spec/#literal-interface),
    [`Variable`](http://rdf.js.org/data-model-spec/#variable-interface),
    [`DefaultGraph`](http://rdf.js.org/data-model-spec/#defaultgraph-interface)
  - the triples/quads it creates implement
    [`Term`](http://rdf.js.org/data-model-spec/#term-interface),
    [`Triple`](http://rdf.js.org/data-model-spec/#triple-interface)
    and
    [`Quad`](http://rdf.js.org/data-model-spec/#quad-interface)
- `N3.StreamParser` implements
  [`Stream`](http://rdf.js.org/stream-spec/#stream-interface)
  and
  [`Sink`](http://rdf.js.org/stream-spec/#sink-interface)
- `N3.StreamWriter` implements
  [`Stream`](http://rdf.js.org/stream-spec/#stream-interface)
  and
  [`Sink`](http://rdf.js.org/stream-spec/#sink-interface)
- `N3.Store` implements
  [`Store`](http://rdf.js.org/stream-spec/#store-interface)
  [`Source`](http://rdf.js.org/stream-spec/#source-interface)
  [`Sink`](http://rdf.js.org/stream-spec/#sink-interface)
  [`DatasetCore`](https://rdf.js.org/dataset-spec/#datasetcore-interface)

## License and contributions
N3.js is released under the [MIT License](https://github.com/rdfjs/N3.js/blob/master/LICENSE.md).

Contributions are welcome, and bug reports or pull requests are always helpful.
If you plan to implement a larger feature, it's best to contact us first.

---
_Source: https://npm.io/package/n3 · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
