WIP
This commit is contained in:
5
node_modules/n3/.babelrc
generated
vendored
Normal file
5
node_modules/n3/.babelrc
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
presets: [
|
||||
"@babel/env",
|
||||
],
|
||||
}
|
||||
9
node_modules/n3/LICENSE.md
generated
vendored
Normal file
9
node_modules/n3/LICENSE.md
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
# License
|
||||
The MIT License (MIT)
|
||||
Copyright ©2012–present Ruben Verborgh
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
471
node_modules/n3/README.md
generated
vendored
Normal file
471
node_modules/n3/README.md
generated
vendored
Normal file
@@ -0,0 +1,471 @@
|
||||
# Lightning fast, asynchronous, streaming RDF for JavaScript
|
||||
[](https://github.com/rdfjs/N3.js/actions)
|
||||
[](https://coveralls.io/github/rdfjs/N3.js)
|
||||
[](https://www.npmjs.com/package/n3)
|
||||
[](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](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/),
|
||||
[RDF-star](https://www.w3.org/2021/12/rdf-star.html)
|
||||
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/),
|
||||
[N-Quads](https://www.w3.org/TR/n-quads/)
|
||||
and [RDF-star](https://www.w3.org/2021/12/rdf-star.html)
|
||||
- [**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:
|
||||
```html
|
||||
<script src="https://unpkg.com/n3/browser/n3.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
|
||||
```
|
||||
|
||||
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/' });
|
||||
```
|
||||
|
||||
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 });
|
||||
```
|
||||
|
||||
### 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.
|
||||
|
||||
## 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' });
|
||||
```
|
||||
|
||||
### 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(rules);
|
||||
```
|
||||
|
||||
**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/).
|
||||
|
||||
## 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)
|
||||
|
||||
In addition, the N3.js parser also supports [Notation3 (N3)](https://www.w3.org/TeamSubmission/n3/) (no official specification yet).
|
||||
|
||||
The N3.js parser and writer are also fully compatible with the RDF-star variants
|
||||
of the W3C specifications.
|
||||
|
||||
The default mode is permissive
|
||||
and allows a mixture of different syntaxes, including RDF-star.
|
||||
Pass a `format` option to the constructor with the name or MIME type of a format
|
||||
for strict, fault-intolerant behavior.
|
||||
If a format string contains `star` or `*`
|
||||
(e.g., `turtlestar` or `TriG*`),
|
||||
RDF-star support for that format will be enabled.
|
||||
|
||||
### 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
|
||||
The N3.js library is copyrighted by [Ruben Verborgh](https://ruben.verborgh.org/)
|
||||
and 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 me first.
|
||||
1
node_modules/n3/browser/n3.min.js
generated
vendored
Normal file
1
node_modules/n3/browser/n3.min.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
93
node_modules/n3/lib/BaseIRI.js
generated
vendored
Normal file
93
node_modules/n3/lib/BaseIRI.js
generated
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = void 0;
|
||||
var _Util = require("./Util");
|
||||
// Do not handle base IRIs without scheme, and currently unsupported cases:
|
||||
// - file: IRIs (which could also use backslashes)
|
||||
// - IRIs containing /. or /.. or //
|
||||
const BASE_UNSUPPORTED = /^:?[^:?#]*(?:[?#]|$)|^file:|^[^:]*:\/*[^?#]+?\/(?:\.\.?(?:\/|$)|\/)/i;
|
||||
const SUFFIX_SUPPORTED = /^(?:(?:[^/?#]{3,}|\.?[^/?#.]\.?)(?:\/[^/?#]{3,}|\.?[^/?#.]\.?)*\/?)?(?:[?#]|$)/;
|
||||
const CURRENT = './';
|
||||
const PARENT = '../';
|
||||
const QUERY = '?';
|
||||
const FRAGMENT = '#';
|
||||
class BaseIRI {
|
||||
constructor(base) {
|
||||
this.base = base;
|
||||
this._baseLength = 0;
|
||||
this._baseMatcher = null;
|
||||
this._pathReplacements = new Array(base.length + 1);
|
||||
}
|
||||
static supports(base) {
|
||||
return !BASE_UNSUPPORTED.test(base);
|
||||
}
|
||||
_getBaseMatcher() {
|
||||
if (this._baseMatcher) return this._baseMatcher;
|
||||
if (!BaseIRI.supports(this.base)) return this._baseMatcher = /.^/;
|
||||
|
||||
// Extract the scheme
|
||||
const scheme = /^[^:]*:\/*/.exec(this.base)[0];
|
||||
const regexHead = ['^', (0, _Util.escapeRegex)(scheme)];
|
||||
const regexTail = [];
|
||||
|
||||
// Generate a regex for every path segment
|
||||
const segments = [],
|
||||
segmenter = /[^/?#]*([/?#])/y;
|
||||
let segment,
|
||||
query = 0,
|
||||
fragment = 0,
|
||||
last = segmenter.lastIndex = scheme.length;
|
||||
while (!query && !fragment && (segment = segmenter.exec(this.base))) {
|
||||
// Truncate base resolution path at fragment start
|
||||
if (segment[1] === FRAGMENT) fragment = segmenter.lastIndex - 1;else {
|
||||
// Create regex that matches the segment
|
||||
regexHead.push((0, _Util.escapeRegex)(segment[0]), '(?:');
|
||||
regexTail.push(')?');
|
||||
|
||||
// Create dedicated query string replacement
|
||||
if (segment[1] !== QUERY) segments.push(last = segmenter.lastIndex);else {
|
||||
query = last = segmenter.lastIndex;
|
||||
fragment = this.base.indexOf(FRAGMENT, query);
|
||||
this._pathReplacements[query] = QUERY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Precalculate parent path substitutions
|
||||
for (let i = 0; i < segments.length; i++) this._pathReplacements[segments[i]] = PARENT.repeat(segments.length - i - 1);
|
||||
this._pathReplacements[segments[segments.length - 1]] = CURRENT;
|
||||
|
||||
// Add the remainder of the base IRI (without fragment) to the regex
|
||||
this._baseLength = fragment > 0 ? fragment : this.base.length;
|
||||
regexHead.push((0, _Util.escapeRegex)(this.base.substring(last, this._baseLength)), query ? '(?:#|$)' : '(?:[?#]|$)');
|
||||
return this._baseMatcher = new RegExp([...regexHead, ...regexTail].join(''));
|
||||
}
|
||||
toRelative(iri) {
|
||||
// Unsupported or non-matching base IRI
|
||||
const match = this._getBaseMatcher().exec(iri);
|
||||
if (!match) return iri;
|
||||
|
||||
// Exact base IRI match
|
||||
const length = match[0].length;
|
||||
if (length === this._baseLength && length === iri.length) return '';
|
||||
|
||||
// Parent path match
|
||||
const parentPath = this._pathReplacements[length];
|
||||
if (parentPath) {
|
||||
const suffix = iri.substring(length);
|
||||
// Don't abbreviate unsupported path
|
||||
if (parentPath !== QUERY && !SUFFIX_SUPPORTED.test(suffix)) return iri;
|
||||
// Omit ./ with fragment or query string
|
||||
if (parentPath === CURRENT && /^[^?#]/.test(suffix)) return suffix;
|
||||
// Append suffix to relative parent path
|
||||
return parentPath + suffix;
|
||||
}
|
||||
|
||||
// Fragment or query string, so include delimiter
|
||||
return iri.substring(length - 1);
|
||||
}
|
||||
}
|
||||
exports.default = BaseIRI;
|
||||
36
node_modules/n3/lib/IRIs.js
generated
vendored
Normal file
36
node_modules/n3/lib/IRIs.js
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = void 0;
|
||||
const RDF = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
|
||||
XSD = 'http://www.w3.org/2001/XMLSchema#',
|
||||
SWAP = 'http://www.w3.org/2000/10/swap/';
|
||||
var _default = exports.default = {
|
||||
xsd: {
|
||||
decimal: `${XSD}decimal`,
|
||||
boolean: `${XSD}boolean`,
|
||||
double: `${XSD}double`,
|
||||
integer: `${XSD}integer`,
|
||||
string: `${XSD}string`
|
||||
},
|
||||
rdf: {
|
||||
type: `${RDF}type`,
|
||||
nil: `${RDF}nil`,
|
||||
first: `${RDF}first`,
|
||||
rest: `${RDF}rest`,
|
||||
langString: `${RDF}langString`
|
||||
},
|
||||
owl: {
|
||||
sameAs: 'http://www.w3.org/2002/07/owl#sameAs'
|
||||
},
|
||||
r: {
|
||||
forSome: `${SWAP}reify#forSome`,
|
||||
forAll: `${SWAP}reify#forAll`
|
||||
},
|
||||
log: {
|
||||
implies: `${SWAP}log#implies`,
|
||||
isImpliedBy: `${SWAP}log#isImpliedBy`
|
||||
}
|
||||
};
|
||||
399
node_modules/n3/lib/N3DataFactory.js
generated
vendored
Normal file
399
node_modules/n3/lib/N3DataFactory.js
generated
vendored
Normal file
@@ -0,0 +1,399 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = exports.Variable = exports.Triple = exports.Term = exports.Quad = exports.NamedNode = exports.Literal = exports.DefaultGraph = exports.BlankNode = void 0;
|
||||
exports.escapeQuotes = escapeQuotes;
|
||||
exports.fromQuad = fromQuad;
|
||||
exports.fromTerm = fromTerm;
|
||||
exports.termFromId = termFromId;
|
||||
exports.termToId = termToId;
|
||||
exports.unescapeQuotes = unescapeQuotes;
|
||||
var _IRIs = _interopRequireDefault(require("./IRIs"));
|
||||
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
||||
// N3.js implementations of the RDF/JS core data types
|
||||
// See http://rdf.js.org/data-model-spec/
|
||||
|
||||
const {
|
||||
rdf,
|
||||
xsd
|
||||
} = _IRIs.default;
|
||||
|
||||
// eslint-disable-next-line prefer-const
|
||||
let DEFAULTGRAPH;
|
||||
let _blankNodeCounter = 0;
|
||||
const escapedLiteral = /^"(.*".*)(?="[^"]*$)/;
|
||||
|
||||
// ## DataFactory singleton
|
||||
const DataFactory = {
|
||||
namedNode,
|
||||
blankNode,
|
||||
variable,
|
||||
literal,
|
||||
defaultGraph,
|
||||
quad,
|
||||
triple: quad,
|
||||
fromTerm,
|
||||
fromQuad
|
||||
};
|
||||
var _default = exports.default = DataFactory; // ## Term constructor
|
||||
class Term {
|
||||
constructor(id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
// ### The value of this term
|
||||
get value() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
// ### Returns whether this object represents the same term as the other
|
||||
equals(other) {
|
||||
// If both terms were created by this library,
|
||||
// equality can be computed through ids
|
||||
if (other instanceof Term) return this.id === other.id;
|
||||
// Otherwise, compare term type and value
|
||||
return !!other && this.termType === other.termType && this.value === other.value;
|
||||
}
|
||||
|
||||
// ### Implement hashCode for Immutable.js, since we implement `equals`
|
||||
// https://immutable-js.com/docs/v4.0.0/ValueObject/#hashCode()
|
||||
hashCode() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ### Returns a plain object representation of this term
|
||||
toJSON() {
|
||||
return {
|
||||
termType: this.termType,
|
||||
value: this.value
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// ## NamedNode constructor
|
||||
exports.Term = Term;
|
||||
class NamedNode extends Term {
|
||||
// ### The term type of this term
|
||||
get termType() {
|
||||
return 'NamedNode';
|
||||
}
|
||||
}
|
||||
|
||||
// ## Literal constructor
|
||||
exports.NamedNode = NamedNode;
|
||||
class Literal extends Term {
|
||||
// ### The term type of this term
|
||||
get termType() {
|
||||
return 'Literal';
|
||||
}
|
||||
|
||||
// ### The text value of this literal
|
||||
get value() {
|
||||
return this.id.substring(1, this.id.lastIndexOf('"'));
|
||||
}
|
||||
|
||||
// ### The language of this literal
|
||||
get language() {
|
||||
// Find the last quotation mark (e.g., '"abc"@en-us')
|
||||
const id = this.id;
|
||||
let atPos = id.lastIndexOf('"') + 1;
|
||||
// If "@" it follows, return the remaining substring; empty otherwise
|
||||
return atPos < id.length && id[atPos++] === '@' ? id.substr(atPos).toLowerCase() : '';
|
||||
}
|
||||
|
||||
// ### The datatype IRI of this literal
|
||||
get datatype() {
|
||||
return new NamedNode(this.datatypeString);
|
||||
}
|
||||
|
||||
// ### The datatype string of this literal
|
||||
get datatypeString() {
|
||||
// Find the last quotation mark (e.g., '"abc"^^http://ex.org/types#t')
|
||||
const id = this.id,
|
||||
dtPos = id.lastIndexOf('"') + 1;
|
||||
const char = dtPos < id.length ? id[dtPos] : '';
|
||||
// If "^" it follows, return the remaining substring
|
||||
return char === '^' ? id.substr(dtPos + 2) :
|
||||
// If "@" follows, return rdf:langString; xsd:string otherwise
|
||||
char !== '@' ? xsd.string : rdf.langString;
|
||||
}
|
||||
|
||||
// ### Returns whether this object represents the same term as the other
|
||||
equals(other) {
|
||||
// If both literals were created by this library,
|
||||
// equality can be computed through ids
|
||||
if (other instanceof Literal) return this.id === other.id;
|
||||
// Otherwise, compare term type, value, language, and datatype
|
||||
return !!other && !!other.datatype && this.termType === other.termType && this.value === other.value && this.language === other.language && this.datatype.value === other.datatype.value;
|
||||
}
|
||||
toJSON() {
|
||||
return {
|
||||
termType: this.termType,
|
||||
value: this.value,
|
||||
language: this.language,
|
||||
datatype: {
|
||||
termType: 'NamedNode',
|
||||
value: this.datatypeString
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// ## BlankNode constructor
|
||||
exports.Literal = Literal;
|
||||
class BlankNode extends Term {
|
||||
constructor(name) {
|
||||
super(`_:${name}`);
|
||||
}
|
||||
|
||||
// ### The term type of this term
|
||||
get termType() {
|
||||
return 'BlankNode';
|
||||
}
|
||||
|
||||
// ### The name of this blank node
|
||||
get value() {
|
||||
return this.id.substr(2);
|
||||
}
|
||||
}
|
||||
exports.BlankNode = BlankNode;
|
||||
class Variable extends Term {
|
||||
constructor(name) {
|
||||
super(`?${name}`);
|
||||
}
|
||||
|
||||
// ### The term type of this term
|
||||
get termType() {
|
||||
return 'Variable';
|
||||
}
|
||||
|
||||
// ### The name of this variable
|
||||
get value() {
|
||||
return this.id.substr(1);
|
||||
}
|
||||
}
|
||||
|
||||
// ## DefaultGraph constructor
|
||||
exports.Variable = Variable;
|
||||
class DefaultGraph extends Term {
|
||||
constructor() {
|
||||
super('');
|
||||
return DEFAULTGRAPH || this;
|
||||
}
|
||||
|
||||
// ### The term type of this term
|
||||
get termType() {
|
||||
return 'DefaultGraph';
|
||||
}
|
||||
|
||||
// ### Returns whether this object represents the same term as the other
|
||||
equals(other) {
|
||||
// If both terms were created by this library,
|
||||
// equality can be computed through strict equality;
|
||||
// otherwise, compare term types.
|
||||
return this === other || !!other && this.termType === other.termType;
|
||||
}
|
||||
}
|
||||
|
||||
// ## DefaultGraph singleton
|
||||
exports.DefaultGraph = DefaultGraph;
|
||||
DEFAULTGRAPH = new DefaultGraph();
|
||||
|
||||
// ### Constructs a term from the given internal string ID
|
||||
// The third 'nested' parameter of this function is to aid
|
||||
// with recursion over nested terms. It should not be used
|
||||
// by consumers of this library.
|
||||
// See https://github.com/rdfjs/N3.js/pull/311#discussion_r1061042725
|
||||
function termFromId(id, factory, nested) {
|
||||
factory = factory || DataFactory;
|
||||
|
||||
// Falsy value or empty string indicate the default graph
|
||||
if (!id) return factory.defaultGraph();
|
||||
|
||||
// Identify the term type based on the first character
|
||||
switch (id[0]) {
|
||||
case '?':
|
||||
return factory.variable(id.substr(1));
|
||||
case '_':
|
||||
return factory.blankNode(id.substr(2));
|
||||
case '"':
|
||||
// Shortcut for internal literals
|
||||
if (factory === DataFactory) return new Literal(id);
|
||||
// Literal without datatype or language
|
||||
if (id[id.length - 1] === '"') return factory.literal(id.substr(1, id.length - 2));
|
||||
// Literal with datatype or language
|
||||
const endPos = id.lastIndexOf('"', id.length - 1);
|
||||
return factory.literal(id.substr(1, endPos - 1), id[endPos + 1] === '@' ? id.substr(endPos + 2) : factory.namedNode(id.substr(endPos + 3)));
|
||||
case '[':
|
||||
id = JSON.parse(id);
|
||||
break;
|
||||
default:
|
||||
if (!nested || !Array.isArray(id)) {
|
||||
return factory.namedNode(id);
|
||||
}
|
||||
}
|
||||
return factory.quad(termFromId(id[0], factory, true), termFromId(id[1], factory, true), termFromId(id[2], factory, true), id[3] && termFromId(id[3], factory, true));
|
||||
}
|
||||
|
||||
// ### Constructs an internal string ID from the given term or ID string
|
||||
// The third 'nested' parameter of this function is to aid
|
||||
// with recursion over nested terms. It should not be used
|
||||
// by consumers of this library.
|
||||
// See https://github.com/rdfjs/N3.js/pull/311#discussion_r1061042725
|
||||
function termToId(term, nested) {
|
||||
if (typeof term === 'string') return term;
|
||||
if (term instanceof Term && term.termType !== 'Quad') return term.id;
|
||||
if (!term) return DEFAULTGRAPH.id;
|
||||
|
||||
// Term instantiated with another library
|
||||
switch (term.termType) {
|
||||
case 'NamedNode':
|
||||
return term.value;
|
||||
case 'BlankNode':
|
||||
return `_:${term.value}`;
|
||||
case 'Variable':
|
||||
return `?${term.value}`;
|
||||
case 'DefaultGraph':
|
||||
return '';
|
||||
case 'Literal':
|
||||
return `"${term.value}"${term.language ? `@${term.language}` : term.datatype && term.datatype.value !== xsd.string ? `^^${term.datatype.value}` : ''}`;
|
||||
case 'Quad':
|
||||
const res = [termToId(term.subject, true), termToId(term.predicate, true), termToId(term.object, true)];
|
||||
if (term.graph && term.graph.termType !== 'DefaultGraph') {
|
||||
res.push(termToId(term.graph, true));
|
||||
}
|
||||
return nested ? res : JSON.stringify(res);
|
||||
default:
|
||||
throw new Error(`Unexpected termType: ${term.termType}`);
|
||||
}
|
||||
}
|
||||
|
||||
// ## Quad constructor
|
||||
class Quad extends Term {
|
||||
constructor(subject, predicate, object, graph) {
|
||||
super('');
|
||||
this._subject = subject;
|
||||
this._predicate = predicate;
|
||||
this._object = object;
|
||||
this._graph = graph || DEFAULTGRAPH;
|
||||
}
|
||||
|
||||
// ### The term type of this term
|
||||
get termType() {
|
||||
return 'Quad';
|
||||
}
|
||||
get subject() {
|
||||
return this._subject;
|
||||
}
|
||||
get predicate() {
|
||||
return this._predicate;
|
||||
}
|
||||
get object() {
|
||||
return this._object;
|
||||
}
|
||||
get graph() {
|
||||
return this._graph;
|
||||
}
|
||||
|
||||
// ### Returns a plain object representation of this quad
|
||||
toJSON() {
|
||||
return {
|
||||
termType: this.termType,
|
||||
subject: this._subject.toJSON(),
|
||||
predicate: this._predicate.toJSON(),
|
||||
object: this._object.toJSON(),
|
||||
graph: this._graph.toJSON()
|
||||
};
|
||||
}
|
||||
|
||||
// ### Returns whether this object represents the same quad as the other
|
||||
equals(other) {
|
||||
return !!other && this._subject.equals(other.subject) && this._predicate.equals(other.predicate) && this._object.equals(other.object) && this._graph.equals(other.graph);
|
||||
}
|
||||
}
|
||||
exports.Triple = exports.Quad = Quad;
|
||||
// ### Escapes the quotes within the given literal
|
||||
function escapeQuotes(id) {
|
||||
return id.replace(escapedLiteral, (_, quoted) => `"${quoted.replace(/"/g, '""')}`);
|
||||
}
|
||||
|
||||
// ### Unescapes the quotes within the given literal
|
||||
function unescapeQuotes(id) {
|
||||
return id.replace(escapedLiteral, (_, quoted) => `"${quoted.replace(/""/g, '"')}`);
|
||||
}
|
||||
|
||||
// ### Creates an IRI
|
||||
function namedNode(iri) {
|
||||
return new NamedNode(iri);
|
||||
}
|
||||
|
||||
// ### Creates a blank node
|
||||
function blankNode(name) {
|
||||
return new BlankNode(name || `n3-${_blankNodeCounter++}`);
|
||||
}
|
||||
|
||||
// ### Creates a literal
|
||||
function literal(value, languageOrDataType) {
|
||||
// Create a language-tagged string
|
||||
if (typeof languageOrDataType === 'string') return new Literal(`"${value}"@${languageOrDataType.toLowerCase()}`);
|
||||
|
||||
// Automatically determine datatype for booleans and numbers
|
||||
let datatype = languageOrDataType ? languageOrDataType.value : '';
|
||||
if (datatype === '') {
|
||||
// Convert a boolean
|
||||
if (typeof value === 'boolean') datatype = xsd.boolean;
|
||||
// Convert an integer or double
|
||||
else if (typeof value === 'number') {
|
||||
if (Number.isFinite(value)) datatype = Number.isInteger(value) ? xsd.integer : xsd.double;else {
|
||||
datatype = xsd.double;
|
||||
if (!Number.isNaN(value)) value = value > 0 ? 'INF' : '-INF';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create a datatyped literal
|
||||
return datatype === '' || datatype === xsd.string ? new Literal(`"${value}"`) : new Literal(`"${value}"^^${datatype}`);
|
||||
}
|
||||
|
||||
// ### Creates a variable
|
||||
function variable(name) {
|
||||
return new Variable(name);
|
||||
}
|
||||
|
||||
// ### Returns the default graph
|
||||
function defaultGraph() {
|
||||
return DEFAULTGRAPH;
|
||||
}
|
||||
|
||||
// ### Creates a quad
|
||||
function quad(subject, predicate, object, graph) {
|
||||
return new Quad(subject, predicate, object, graph);
|
||||
}
|
||||
function fromTerm(term) {
|
||||
if (term instanceof Term) return term;
|
||||
|
||||
// Term instantiated with another library
|
||||
switch (term.termType) {
|
||||
case 'NamedNode':
|
||||
return namedNode(term.value);
|
||||
case 'BlankNode':
|
||||
return blankNode(term.value);
|
||||
case 'Variable':
|
||||
return variable(term.value);
|
||||
case 'DefaultGraph':
|
||||
return DEFAULTGRAPH;
|
||||
case 'Literal':
|
||||
return literal(term.value, term.language || term.datatype);
|
||||
case 'Quad':
|
||||
return fromQuad(term);
|
||||
default:
|
||||
throw new Error(`Unexpected termType: ${term.termType}`);
|
||||
}
|
||||
}
|
||||
function fromQuad(inQuad) {
|
||||
if (inQuad instanceof Quad) return inQuad;
|
||||
if (inQuad.termType !== 'Quad') throw new Error(`Unexpected termType: ${inQuad.termType}`);
|
||||
return quad(fromTerm(inQuad.subject), fromTerm(inQuad.predicate), fromTerm(inQuad.object), fromTerm(inQuad.graph));
|
||||
}
|
||||
519
node_modules/n3/lib/N3Lexer.js
generated
vendored
Normal file
519
node_modules/n3/lib/N3Lexer.js
generated
vendored
Normal file
@@ -0,0 +1,519 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = void 0;
|
||||
var _buffer = require("buffer");
|
||||
var _IRIs = _interopRequireDefault(require("./IRIs"));
|
||||
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
||||
// **N3Lexer** tokenizes N3 documents.
|
||||
|
||||
const {
|
||||
xsd
|
||||
} = _IRIs.default;
|
||||
|
||||
// Regular expression and replacement string to escape N3 strings
|
||||
const escapeSequence = /\\u([a-fA-F0-9]{4})|\\U([a-fA-F0-9]{8})|\\([^])/g;
|
||||
const escapeReplacements = {
|
||||
'\\': '\\',
|
||||
"'": "'",
|
||||
'"': '"',
|
||||
'n': '\n',
|
||||
'r': '\r',
|
||||
't': '\t',
|
||||
'f': '\f',
|
||||
'b': '\b',
|
||||
'_': '_',
|
||||
'~': '~',
|
||||
'.': '.',
|
||||
'-': '-',
|
||||
'!': '!',
|
||||
'$': '$',
|
||||
'&': '&',
|
||||
'(': '(',
|
||||
')': ')',
|
||||
'*': '*',
|
||||
'+': '+',
|
||||
',': ',',
|
||||
';': ';',
|
||||
'=': '=',
|
||||
'/': '/',
|
||||
'?': '?',
|
||||
'#': '#',
|
||||
'@': '@',
|
||||
'%': '%'
|
||||
};
|
||||
const illegalIriChars = /[\x00-\x20<>\\"\{\}\|\^\`]/;
|
||||
const lineModeRegExps = {
|
||||
_iri: true,
|
||||
_unescapedIri: true,
|
||||
_simpleQuotedString: true,
|
||||
_langcode: true,
|
||||
_blank: true,
|
||||
_newline: true,
|
||||
_comment: true,
|
||||
_whitespace: true,
|
||||
_endOfFile: true
|
||||
};
|
||||
const invalidRegExp = /$0^/;
|
||||
|
||||
// ## Constructor
|
||||
class N3Lexer {
|
||||
constructor(options) {
|
||||
// ## Regular expressions
|
||||
// It's slightly faster to have these as properties than as in-scope variables
|
||||
this._iri = /^<((?:[^ <>{}\\]|\\[uU])+)>[ \t]*/; // IRI with escape sequences; needs sanity check after unescaping
|
||||
this._unescapedIri = /^<([^\x00-\x20<>\\"\{\}\|\^\`]*)>[ \t]*/; // IRI without escape sequences; no unescaping
|
||||
this._simpleQuotedString = /^"([^"\\\r\n]*)"(?=[^"])/; // string without escape sequences
|
||||
this._simpleApostropheString = /^'([^'\\\r\n]*)'(?=[^'])/;
|
||||
this._langcode = /^@([a-z]+(?:-[a-z0-9]+)*)(?=[^a-z0-9\-])/i;
|
||||
this._prefix = /^((?:[A-Za-z\xc0-\xd6\xd8-\xf6\xf8-\u02ff\u0370-\u037d\u037f-\u1fff\u200c\u200d\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])(?:\.?[\-0-9A-Z_a-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u037f-\u1fff\u200c\u200d\u203f\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])*)?:(?=[#\s<])/;
|
||||
this._prefixed = /^((?:[A-Za-z\xc0-\xd6\xd8-\xf6\xf8-\u02ff\u0370-\u037d\u037f-\u1fff\u200c\u200d\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])(?:\.?[\-0-9A-Z_a-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u037f-\u1fff\u200c\u200d\u203f\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])*)?:((?:(?:[0-:A-Z_a-z\xc0-\xd6\xd8-\xf6\xf8-\u02ff\u0370-\u037d\u037f-\u1fff\u200c\u200d\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff]|%[0-9a-fA-F]{2}|\\[!#-\/;=?\-@_~])(?:(?:[\.\-0-:A-Z_a-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u037f-\u1fff\u200c\u200d\u203f\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff]|%[0-9a-fA-F]{2}|\\[!#-\/;=?\-@_~])*(?:[\-0-:A-Z_a-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u037f-\u1fff\u200c\u200d\u203f\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff]|%[0-9a-fA-F]{2}|\\[!#-\/;=?\-@_~]))?)?)(?:[ \t]+|(?=\.?[,;!\^\s#()\[\]\{\}"'<>]))/;
|
||||
this._variable = /^\?(?:(?:[A-Z_a-z\xc0-\xd6\xd8-\xf6\xf8-\u02ff\u0370-\u037d\u037f-\u1fff\u200c\u200d\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])(?:[\-0-:A-Z_a-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u037f-\u1fff\u200c\u200d\u203f\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])*)(?=[.,;!\^\s#()\[\]\{\}"'<>])/;
|
||||
this._blank = /^_:((?:[0-9A-Z_a-z\xc0-\xd6\xd8-\xf6\xf8-\u02ff\u0370-\u037d\u037f-\u1fff\u200c\u200d\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])(?:\.?[\-0-9A-Z_a-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u037f-\u1fff\u200c\u200d\u203f\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])*)(?:[ \t]+|(?=\.?[,;:\s#()\[\]\{\}"'<>]))/;
|
||||
this._number = /^[\-+]?(?:(\d+\.\d*|\.?\d+)[eE][\-+]?|\d*(\.)?)\d+(?=\.?[,;:\s#()\[\]\{\}"'<>])/;
|
||||
this._boolean = /^(?:true|false)(?=[.,;\s#()\[\]\{\}"'<>])/;
|
||||
this._keyword = /^@[a-z]+(?=[\s#<:])/i;
|
||||
this._sparqlKeyword = /^(?:PREFIX|BASE|GRAPH)(?=[\s#<])/i;
|
||||
this._shortPredicates = /^a(?=[\s#()\[\]\{\}"'<>])/;
|
||||
this._newline = /^[ \t]*(?:#[^\n\r]*)?(?:\r\n|\n|\r)[ \t]*/;
|
||||
this._comment = /#([^\n\r]*)/;
|
||||
this._whitespace = /^[ \t]+/;
|
||||
this._endOfFile = /^(?:#[^\n\r]*)?$/;
|
||||
options = options || {};
|
||||
|
||||
// Whether the log:isImpliedBy predicate is supported
|
||||
this._isImpliedBy = options.isImpliedBy;
|
||||
|
||||
// In line mode (N-Triples or N-Quads), only simple features may be parsed
|
||||
if (this._lineMode = !!options.lineMode) {
|
||||
this._n3Mode = false;
|
||||
// Don't tokenize special literals
|
||||
for (const key in this) {
|
||||
if (!(key in lineModeRegExps) && this[key] instanceof RegExp) this[key] = invalidRegExp;
|
||||
}
|
||||
}
|
||||
// When not in line mode, enable N3 functionality by default
|
||||
else {
|
||||
this._n3Mode = options.n3 !== false;
|
||||
}
|
||||
// Don't output comment tokens by default
|
||||
this.comments = !!options.comments;
|
||||
// Cache the last tested closing position of long literals
|
||||
this._literalClosingPos = 0;
|
||||
}
|
||||
|
||||
// ## Private methods
|
||||
|
||||
// ### `_tokenizeToEnd` tokenizes as for as possible, emitting tokens through the callback
|
||||
_tokenizeToEnd(callback, inputFinished) {
|
||||
// Continue parsing as far as possible; the loop will return eventually
|
||||
let input = this._input;
|
||||
let currentLineLength = input.length;
|
||||
while (true) {
|
||||
// Count and skip whitespace lines
|
||||
let whiteSpaceMatch, comment;
|
||||
while (whiteSpaceMatch = this._newline.exec(input)) {
|
||||
// Try to find a comment
|
||||
if (this.comments && (comment = this._comment.exec(whiteSpaceMatch[0]))) emitToken('comment', comment[1], '', this._line, whiteSpaceMatch[0].length);
|
||||
// Advance the input
|
||||
input = input.substr(whiteSpaceMatch[0].length, input.length);
|
||||
currentLineLength = input.length;
|
||||
this._line++;
|
||||
}
|
||||
// Skip whitespace on current line
|
||||
if (!whiteSpaceMatch && (whiteSpaceMatch = this._whitespace.exec(input))) input = input.substr(whiteSpaceMatch[0].length, input.length);
|
||||
|
||||
// Stop for now if we're at the end
|
||||
if (this._endOfFile.test(input)) {
|
||||
// If the input is finished, emit EOF
|
||||
if (inputFinished) {
|
||||
// Try to find a final comment
|
||||
if (this.comments && (comment = this._comment.exec(input))) emitToken('comment', comment[1], '', this._line, input.length);
|
||||
input = null;
|
||||
emitToken('eof', '', '', this._line, 0);
|
||||
}
|
||||
return this._input = input;
|
||||
}
|
||||
|
||||
// Look for specific token types based on the first character
|
||||
const line = this._line,
|
||||
firstChar = input[0];
|
||||
let type = '',
|
||||
value = '',
|
||||
prefix = '',
|
||||
match = null,
|
||||
matchLength = 0,
|
||||
inconclusive = false;
|
||||
switch (firstChar) {
|
||||
case '^':
|
||||
// We need at least 3 tokens lookahead to distinguish ^^<IRI> and ^^pre:fixed
|
||||
if (input.length < 3) break;
|
||||
// Try to match a type
|
||||
else if (input[1] === '^') {
|
||||
this._previousMarker = '^^';
|
||||
// Move to type IRI or prefixed name
|
||||
input = input.substr(2);
|
||||
if (input[0] !== '<') {
|
||||
inconclusive = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If no type, it must be a path expression
|
||||
else {
|
||||
if (this._n3Mode) {
|
||||
matchLength = 1;
|
||||
type = '^';
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Fall through in case the type is an IRI
|
||||
case '<':
|
||||
// Try to find a full IRI without escape sequences
|
||||
if (match = this._unescapedIri.exec(input)) type = 'IRI', value = match[1];
|
||||
// Try to find a full IRI with escape sequences
|
||||
else if (match = this._iri.exec(input)) {
|
||||
value = this._unescape(match[1]);
|
||||
if (value === null || illegalIriChars.test(value)) return reportSyntaxError(this);
|
||||
type = 'IRI';
|
||||
}
|
||||
// Try to find a nested triple
|
||||
else if (input.length > 1 && input[1] === '<') type = '<<', matchLength = 2;
|
||||
// Try to find a backwards implication arrow
|
||||
else if (this._n3Mode && input.length > 1 && input[1] === '=') {
|
||||
matchLength = 2;
|
||||
if (this._isImpliedBy) type = 'abbreviation', value = '<';else type = 'inverse', value = '>';
|
||||
}
|
||||
break;
|
||||
case '>':
|
||||
if (input.length > 1 && input[1] === '>') type = '>>', matchLength = 2;
|
||||
break;
|
||||
case '_':
|
||||
// Try to find a blank node. Since it can contain (but not end with) a dot,
|
||||
// we always need a non-dot character before deciding it is a blank node.
|
||||
// Therefore, try inserting a space if we're at the end of the input.
|
||||
if ((match = this._blank.exec(input)) || inputFinished && (match = this._blank.exec(`${input} `))) type = 'blank', prefix = '_', value = match[1];
|
||||
break;
|
||||
case '"':
|
||||
// Try to find a literal without escape sequences
|
||||
if (match = this._simpleQuotedString.exec(input)) value = match[1];
|
||||
// Try to find a literal wrapped in three pairs of quotes
|
||||
else {
|
||||
({
|
||||
value,
|
||||
matchLength
|
||||
} = this._parseLiteral(input));
|
||||
if (value === null) return reportSyntaxError(this);
|
||||
}
|
||||
if (match !== null || matchLength !== 0) {
|
||||
type = 'literal';
|
||||
this._literalClosingPos = 0;
|
||||
}
|
||||
break;
|
||||
case "'":
|
||||
if (!this._lineMode) {
|
||||
// Try to find a literal without escape sequences
|
||||
if (match = this._simpleApostropheString.exec(input)) value = match[1];
|
||||
// Try to find a literal wrapped in three pairs of quotes
|
||||
else {
|
||||
({
|
||||
value,
|
||||
matchLength
|
||||
} = this._parseLiteral(input));
|
||||
if (value === null) return reportSyntaxError(this);
|
||||
}
|
||||
if (match !== null || matchLength !== 0) {
|
||||
type = 'literal';
|
||||
this._literalClosingPos = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '?':
|
||||
// Try to find a variable
|
||||
if (this._n3Mode && (match = this._variable.exec(input))) type = 'var', value = match[0];
|
||||
break;
|
||||
case '@':
|
||||
// Try to find a language code
|
||||
if (this._previousMarker === 'literal' && (match = this._langcode.exec(input))) type = 'langcode', value = match[1];
|
||||
// Try to find a keyword
|
||||
else if (match = this._keyword.exec(input)) type = match[0];
|
||||
break;
|
||||
case '.':
|
||||
// Try to find a dot as punctuation
|
||||
if (input.length === 1 ? inputFinished : input[1] < '0' || input[1] > '9') {
|
||||
type = '.';
|
||||
matchLength = 1;
|
||||
break;
|
||||
}
|
||||
// Fall through to numerical case (could be a decimal dot)
|
||||
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
case '+':
|
||||
case '-':
|
||||
// Try to find a number. Since it can contain (but not end with) a dot,
|
||||
// we always need a non-dot character before deciding it is a number.
|
||||
// Therefore, try inserting a space if we're at the end of the input.
|
||||
if (match = this._number.exec(input) || inputFinished && (match = this._number.exec(`${input} `))) {
|
||||
type = 'literal', value = match[0];
|
||||
prefix = typeof match[1] === 'string' ? xsd.double : typeof match[2] === 'string' ? xsd.decimal : xsd.integer;
|
||||
}
|
||||
break;
|
||||
case 'B':
|
||||
case 'b':
|
||||
case 'p':
|
||||
case 'P':
|
||||
case 'G':
|
||||
case 'g':
|
||||
// Try to find a SPARQL-style keyword
|
||||
if (match = this._sparqlKeyword.exec(input)) type = match[0].toUpperCase();else inconclusive = true;
|
||||
break;
|
||||
case 'f':
|
||||
case 't':
|
||||
// Try to match a boolean
|
||||
if (match = this._boolean.exec(input)) type = 'literal', value = match[0], prefix = xsd.boolean;else inconclusive = true;
|
||||
break;
|
||||
case 'a':
|
||||
// Try to find an abbreviated predicate
|
||||
if (match = this._shortPredicates.exec(input)) type = 'abbreviation', value = 'a';else inconclusive = true;
|
||||
break;
|
||||
case '=':
|
||||
// Try to find an implication arrow or equals sign
|
||||
if (this._n3Mode && input.length > 1) {
|
||||
type = 'abbreviation';
|
||||
if (input[1] !== '>') matchLength = 1, value = '=';else matchLength = 2, value = '>';
|
||||
}
|
||||
break;
|
||||
case '!':
|
||||
if (!this._n3Mode) break;
|
||||
case ',':
|
||||
case ';':
|
||||
case '[':
|
||||
case ']':
|
||||
case '(':
|
||||
case ')':
|
||||
case '}':
|
||||
if (!this._lineMode) {
|
||||
matchLength = 1;
|
||||
type = firstChar;
|
||||
}
|
||||
break;
|
||||
case '{':
|
||||
// We need at least 2 tokens lookahead to distinguish "{|" and "{ "
|
||||
if (!this._lineMode && input.length >= 2) {
|
||||
// Try to find a quoted triple annotation start
|
||||
if (input[1] === '|') type = '{|', matchLength = 2;else type = firstChar, matchLength = 1;
|
||||
}
|
||||
break;
|
||||
case '|':
|
||||
// We need 2 tokens lookahead to parse "|}"
|
||||
// Try to find a quoted triple annotation end
|
||||
if (input.length >= 2 && input[1] === '}') type = '|}', matchLength = 2;
|
||||
break;
|
||||
default:
|
||||
inconclusive = true;
|
||||
}
|
||||
|
||||
// Some first characters do not allow an immediate decision, so inspect more
|
||||
if (inconclusive) {
|
||||
// Try to find a prefix
|
||||
if ((this._previousMarker === '@prefix' || this._previousMarker === 'PREFIX') && (match = this._prefix.exec(input))) type = 'prefix', value = match[1] || '';
|
||||
// Try to find a prefixed name. Since it can contain (but not end with) a dot,
|
||||
// we always need a non-dot character before deciding it is a prefixed name.
|
||||
// Therefore, try inserting a space if we're at the end of the input.
|
||||
else if ((match = this._prefixed.exec(input)) || inputFinished && (match = this._prefixed.exec(`${input} `))) type = 'prefixed', prefix = match[1] || '', value = this._unescape(match[2]);
|
||||
}
|
||||
|
||||
// A type token is special: it can only be emitted after an IRI or prefixed name is read
|
||||
if (this._previousMarker === '^^') {
|
||||
switch (type) {
|
||||
case 'prefixed':
|
||||
type = 'type';
|
||||
break;
|
||||
case 'IRI':
|
||||
type = 'typeIRI';
|
||||
break;
|
||||
default:
|
||||
type = '';
|
||||
}
|
||||
}
|
||||
|
||||
// What if nothing of the above was found?
|
||||
if (!type) {
|
||||
// We could be in streaming mode, and then we just wait for more input to arrive.
|
||||
// Otherwise, a syntax error has occurred in the input.
|
||||
// One exception: error on an unaccounted linebreak (= not inside a triple-quoted literal).
|
||||
if (inputFinished || !/^'''|^"""/.test(input) && /\n|\r/.test(input)) return reportSyntaxError(this);else return this._input = input;
|
||||
}
|
||||
|
||||
// Emit the parsed token
|
||||
const length = matchLength || match[0].length;
|
||||
const token = emitToken(type, value, prefix, line, length);
|
||||
this.previousToken = token;
|
||||
this._previousMarker = type;
|
||||
|
||||
// Advance to next part to tokenize
|
||||
input = input.substr(length, input.length);
|
||||
}
|
||||
|
||||
// Emits the token through the callback
|
||||
function emitToken(type, value, prefix, line, length) {
|
||||
const start = input ? currentLineLength - input.length : currentLineLength;
|
||||
const end = start + length;
|
||||
const token = {
|
||||
type,
|
||||
value,
|
||||
prefix,
|
||||
line,
|
||||
start,
|
||||
end
|
||||
};
|
||||
callback(null, token);
|
||||
return token;
|
||||
}
|
||||
// Signals the syntax error through the callback
|
||||
function reportSyntaxError(self) {
|
||||
callback(self._syntaxError(/^\S*/.exec(input)[0]));
|
||||
}
|
||||
}
|
||||
|
||||
// ### `_unescape` replaces N3 escape codes by their corresponding characters
|
||||
_unescape(item) {
|
||||
let invalid = false;
|
||||
const replaced = item.replace(escapeSequence, (sequence, unicode4, unicode8, escapedChar) => {
|
||||
// 4-digit unicode character
|
||||
if (typeof unicode4 === 'string') return String.fromCharCode(Number.parseInt(unicode4, 16));
|
||||
// 8-digit unicode character
|
||||
if (typeof unicode8 === 'string') {
|
||||
let charCode = Number.parseInt(unicode8, 16);
|
||||
return charCode <= 0xFFFF ? String.fromCharCode(Number.parseInt(unicode8, 16)) : String.fromCharCode(0xD800 + ((charCode -= 0x10000) >> 10), 0xDC00 + (charCode & 0x3FF));
|
||||
}
|
||||
// fixed escape sequence
|
||||
if (escapedChar in escapeReplacements) return escapeReplacements[escapedChar];
|
||||
// invalid escape sequence
|
||||
invalid = true;
|
||||
return '';
|
||||
});
|
||||
return invalid ? null : replaced;
|
||||
}
|
||||
|
||||
// ### `_parseLiteral` parses a literal into an unescaped value
|
||||
_parseLiteral(input) {
|
||||
// Ensure we have enough lookahead to identify triple-quoted strings
|
||||
if (input.length >= 3) {
|
||||
// Identify the opening quote(s)
|
||||
const opening = input.match(/^(?:"""|"|'''|'|)/)[0];
|
||||
const openingLength = opening.length;
|
||||
|
||||
// Find the next candidate closing quotes
|
||||
let closingPos = Math.max(this._literalClosingPos, openingLength);
|
||||
while ((closingPos = input.indexOf(opening, closingPos)) > 0) {
|
||||
// Count backslashes right before the closing quotes
|
||||
let backslashCount = 0;
|
||||
while (input[closingPos - backslashCount - 1] === '\\') backslashCount++;
|
||||
|
||||
// An even number of backslashes (in particular 0)
|
||||
// means these are actual, non-escaped closing quotes
|
||||
if (backslashCount % 2 === 0) {
|
||||
// Extract and unescape the value
|
||||
const raw = input.substring(openingLength, closingPos);
|
||||
const lines = raw.split(/\r\n|\r|\n/).length - 1;
|
||||
const matchLength = closingPos + openingLength;
|
||||
// Only triple-quoted strings can be multi-line
|
||||
if (openingLength === 1 && lines !== 0 || openingLength === 3 && this._lineMode) break;
|
||||
this._line += lines;
|
||||
return {
|
||||
value: this._unescape(raw),
|
||||
matchLength
|
||||
};
|
||||
}
|
||||
closingPos++;
|
||||
}
|
||||
this._literalClosingPos = input.length - openingLength + 1;
|
||||
}
|
||||
return {
|
||||
value: '',
|
||||
matchLength: 0
|
||||
};
|
||||
}
|
||||
|
||||
// ### `_syntaxError` creates a syntax error for the given issue
|
||||
_syntaxError(issue) {
|
||||
this._input = null;
|
||||
const err = new Error(`Unexpected "${issue}" on line ${this._line}.`);
|
||||
err.context = {
|
||||
token: undefined,
|
||||
line: this._line,
|
||||
previousToken: this.previousToken
|
||||
};
|
||||
return err;
|
||||
}
|
||||
|
||||
// ### Strips off any starting UTF BOM mark.
|
||||
_readStartingBom(input) {
|
||||
return input.startsWith('\ufeff') ? input.substr(1) : input;
|
||||
}
|
||||
|
||||
// ## Public methods
|
||||
|
||||
// ### `tokenize` starts the transformation of an N3 document into an array of tokens.
|
||||
// The input can be a string or a stream.
|
||||
tokenize(input, callback) {
|
||||
this._line = 1;
|
||||
|
||||
// If the input is a string, continuously emit tokens through the callback until the end
|
||||
if (typeof input === 'string') {
|
||||
this._input = this._readStartingBom(input);
|
||||
// If a callback was passed, asynchronously call it
|
||||
if (typeof callback === 'function') queueMicrotask(() => this._tokenizeToEnd(callback, true));
|
||||
// If no callback was passed, tokenize synchronously and return
|
||||
else {
|
||||
const tokens = [];
|
||||
let error;
|
||||
this._tokenizeToEnd((e, t) => e ? error = e : tokens.push(t), true);
|
||||
if (error) throw error;
|
||||
return tokens;
|
||||
}
|
||||
}
|
||||
// Otherwise, the input must be a stream
|
||||
else {
|
||||
this._pendingBuffer = null;
|
||||
if (typeof input.setEncoding === 'function') input.setEncoding('utf8');
|
||||
// Adds the data chunk to the buffer and parses as far as possible
|
||||
input.on('data', data => {
|
||||
if (this._input !== null && data.length !== 0) {
|
||||
// Prepend any previous pending writes
|
||||
if (this._pendingBuffer) {
|
||||
data = _buffer.Buffer.concat([this._pendingBuffer, data]);
|
||||
this._pendingBuffer = null;
|
||||
}
|
||||
// Hold if the buffer ends in an incomplete unicode sequence
|
||||
if (data[data.length - 1] & 0x80) {
|
||||
this._pendingBuffer = data;
|
||||
}
|
||||
// Otherwise, tokenize as far as possible
|
||||
else {
|
||||
// Only read a BOM at the start
|
||||
if (typeof this._input === 'undefined') this._input = this._readStartingBom(typeof data === 'string' ? data : data.toString());else this._input += data;
|
||||
this._tokenizeToEnd(callback, false);
|
||||
}
|
||||
}
|
||||
});
|
||||
// Parses until the end
|
||||
input.on('end', () => {
|
||||
if (typeof this._input === 'string') this._tokenizeToEnd(callback, true);
|
||||
});
|
||||
input.on('error', callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.default = N3Lexer;
|
||||
1030
node_modules/n3/lib/N3Parser.js
generated
vendored
Normal file
1030
node_modules/n3/lib/N3Parser.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
226
node_modules/n3/lib/N3Reasoner.js
generated
vendored
Normal file
226
node_modules/n3/lib/N3Reasoner.js
generated
vendored
Normal file
@@ -0,0 +1,226 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = void 0;
|
||||
exports.getRulesFromDataset = getRulesFromDataset;
|
||||
var _N3DataFactory = _interopRequireDefault(require("./N3DataFactory"));
|
||||
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
||||
/**
|
||||
* Gets rules from a dataset. This will only collect horn rules declared using log:implies.
|
||||
*/
|
||||
function getRulesFromDataset(dataset) {
|
||||
const rules = [];
|
||||
for (const {
|
||||
subject,
|
||||
object
|
||||
} of dataset.match(null, _N3DataFactory.default.namedNode('http://www.w3.org/2000/10/swap/log#implies'), null, _N3DataFactory.default.defaultGraph())) {
|
||||
const premise = [...dataset.match(null, null, null, subject)];
|
||||
const conclusion = [...dataset.match(null, null, null, object)];
|
||||
rules.push({
|
||||
premise,
|
||||
conclusion
|
||||
});
|
||||
}
|
||||
return rules;
|
||||
}
|
||||
class N3Reasoner {
|
||||
constructor(store) {
|
||||
this._store = store;
|
||||
}
|
||||
_add(subject, predicate, object, graphItem, cb) {
|
||||
// Only add to the remaining indexes if there is not already a value in the index
|
||||
if (!this._store._addToIndex(graphItem.subjects, subject, predicate, object)) return;
|
||||
this._store._addToIndex(graphItem.predicates, predicate, object, subject);
|
||||
this._store._addToIndex(graphItem.objects, object, subject, predicate);
|
||||
cb();
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-warning-comments
|
||||
_evaluatePremise(rule, content, cb, i = 0) {
|
||||
let v1, v2, value, index1, index2;
|
||||
const [val0, val1, val2] = rule.premise[i].value,
|
||||
index = content[rule.premise[i].content];
|
||||
const v0 = !(value = val0.value);
|
||||
for (value in v0 ? index : {
|
||||
[value]: index[value]
|
||||
}) {
|
||||
if (index1 = index[value]) {
|
||||
if (v0) val0.value = Number(value);
|
||||
v1 = !(value = val1.value);
|
||||
for (value in v1 ? index1 : {
|
||||
[value]: index1[value]
|
||||
}) {
|
||||
if (index2 = index1[value]) {
|
||||
if (v1) val1.value = Number(value);
|
||||
v2 = !(value = val2.value);
|
||||
for (value in v2 ? index2 : {
|
||||
[value]: index2[value]
|
||||
}) {
|
||||
if (v2) val2.value = Number(value);
|
||||
if (i === rule.premise.length - 1) rule.conclusion.forEach(c => {
|
||||
// eslint-disable-next-line max-nested-callbacks
|
||||
this._add(c.subject.value, c.predicate.value, c.object.value, content, () => {
|
||||
cb(c);
|
||||
});
|
||||
});else this._evaluatePremise(rule, content, cb, i + 1);
|
||||
}
|
||||
if (v2) val2.value = null;
|
||||
}
|
||||
}
|
||||
if (v1) val1.value = null;
|
||||
}
|
||||
}
|
||||
if (v0) val0.value = null;
|
||||
}
|
||||
_evaluateRules(rules, content, cb) {
|
||||
for (let i = 0; i < rules.length; i++) {
|
||||
this._evaluatePremise(rules[i], content, cb);
|
||||
}
|
||||
}
|
||||
|
||||
// A naive reasoning algorithm where rules are just applied by repeatedly applying rules
|
||||
// until no more evaluations are made
|
||||
_reasonGraphNaive(rules, content) {
|
||||
const newRules = [];
|
||||
function addRule(conclusion) {
|
||||
if (conclusion.next) conclusion.next.forEach(rule => {
|
||||
newRules.push([conclusion.subject.value, conclusion.predicate.value, conclusion.object.value, rule]);
|
||||
});
|
||||
}
|
||||
|
||||
// eslint-disable-next-line func-style
|
||||
const addConclusions = conclusion => {
|
||||
conclusion.forEach(c => {
|
||||
// eslint-disable-next-line max-nested-callbacks
|
||||
this._add(c.subject.value, c.predicate.value, c.object.value, content, () => {
|
||||
addRule(c);
|
||||
});
|
||||
});
|
||||
};
|
||||
this._evaluateRules(rules, content, addRule);
|
||||
let r;
|
||||
while ((r = newRules.pop()) !== undefined) {
|
||||
const [subject, predicate, object, rule] = r;
|
||||
const v1 = rule.basePremise.subject.value;
|
||||
if (!v1) rule.basePremise.subject.value = subject;
|
||||
const v2 = rule.basePremise.predicate.value;
|
||||
if (!v2) rule.basePremise.predicate.value = predicate;
|
||||
const v3 = rule.basePremise.object.value;
|
||||
if (!v3) rule.basePremise.object.value = object;
|
||||
if (rule.premise.length === 0) {
|
||||
addConclusions(rule.conclusion);
|
||||
} else {
|
||||
this._evaluatePremise(rule, content, addRule);
|
||||
}
|
||||
if (!v1) rule.basePremise.subject.value = null;
|
||||
if (!v2) rule.basePremise.predicate.value = null;
|
||||
if (!v3) rule.basePremise.object.value = null;
|
||||
}
|
||||
}
|
||||
_createRule({
|
||||
premise,
|
||||
conclusion
|
||||
}) {
|
||||
const varMapping = {};
|
||||
const toId = value => value.termType === 'Variable' ?
|
||||
// If the term is a variable, then create an empty object that values can be placed into
|
||||
varMapping[value.value] = varMapping[value.value] || {} :
|
||||
// If the term is not a variable, then set the ID value
|
||||
{
|
||||
value: this._store._termToNewNumericId(value)
|
||||
};
|
||||
|
||||
// eslint-disable-next-line func-style
|
||||
const t = term => ({
|
||||
subject: toId(term.subject),
|
||||
predicate: toId(term.predicate),
|
||||
object: toId(term.object)
|
||||
});
|
||||
return {
|
||||
premise: premise.map(p => t(p)),
|
||||
conclusion: conclusion.map(p => t(p)),
|
||||
variables: Object.values(varMapping)
|
||||
};
|
||||
}
|
||||
reason(rules) {
|
||||
if (!Array.isArray(rules)) {
|
||||
rules = getRulesFromDataset(rules);
|
||||
}
|
||||
rules = rules.map(rule => this._createRule(rule));
|
||||
for (const r1 of rules) {
|
||||
for (const r2 of rules) {
|
||||
for (let i = 0; i < r2.premise.length; i++) {
|
||||
const p = r2.premise[i];
|
||||
for (const c of r1.conclusion) {
|
||||
if (termEq(p.subject, c.subject) && termEq(p.predicate, c.predicate) && termEq(p.object, c.object)) {
|
||||
const set = new Set();
|
||||
const premise = [];
|
||||
|
||||
// Since these *will* be substituted when we apply the rule,
|
||||
// we need to do this, so that we index correctly in the subsequent section
|
||||
p.subject.value = p.subject.value || 1;
|
||||
p.object.value = p.object.value || 1;
|
||||
p.predicate.value = p.predicate.value || 1;
|
||||
for (let j = 0; j < r2.premise.length; j++) {
|
||||
if (j !== i) {
|
||||
premise.push(getIndex(r2.premise[j], set));
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-warning-comments
|
||||
// TODO: Create new rule, with new indexing
|
||||
// Future, 'collapse' the next statements when they share a premise/base-premise
|
||||
(c.next = c.next || []).push({
|
||||
premise,
|
||||
conclusion: r2.conclusion,
|
||||
// This is a single premise of the form { subject, predicate, object },
|
||||
// which we can use to instantiate the rule using the new data that was emitted
|
||||
basePremise: p
|
||||
});
|
||||
}
|
||||
r2.variables.forEach(v => {
|
||||
v.value = null;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const rule of rules) {
|
||||
const set = new Set();
|
||||
rule.premise = rule.premise.map(p => getIndex(p, set));
|
||||
}
|
||||
const graphs = this._store._getGraphs();
|
||||
for (const graphId in graphs) {
|
||||
this._reasonGraphNaive(rules, graphs[graphId]);
|
||||
}
|
||||
this._store._size = null;
|
||||
}
|
||||
}
|
||||
exports.default = N3Reasoner;
|
||||
function getIndex({
|
||||
subject,
|
||||
predicate,
|
||||
object
|
||||
}, set) {
|
||||
const s = subject.value || set.has(subject) || (set.add(subject), false);
|
||||
const p = predicate.value || set.has(predicate) || (set.add(predicate), false);
|
||||
const o = object.value || set.has(object) || (set.add(object), false);
|
||||
return !s && p ? {
|
||||
content: 'predicates',
|
||||
value: [predicate, object, subject]
|
||||
} : o ? {
|
||||
content: 'objects',
|
||||
value: [object, subject, predicate]
|
||||
} : {
|
||||
content: 'subjects',
|
||||
value: [subject, predicate, object]
|
||||
};
|
||||
}
|
||||
function termEq(t1, t2) {
|
||||
if (t1.value === null) {
|
||||
t1.value = t2.value;
|
||||
}
|
||||
return t1.value === t2.value;
|
||||
}
|
||||
1199
node_modules/n3/lib/N3Store.js
generated
vendored
Normal file
1199
node_modules/n3/lib/N3Store.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
14
node_modules/n3/lib/N3StoreFactory.js
generated
vendored
Normal file
14
node_modules/n3/lib/N3StoreFactory.js
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = void 0;
|
||||
var _N3Store = _interopRequireDefault(require("./N3Store"));
|
||||
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
||||
class N3DatasetCoreFactory {
|
||||
dataset(quads) {
|
||||
return new _N3Store.default(quads);
|
||||
}
|
||||
}
|
||||
exports.default = N3DatasetCoreFactory;
|
||||
74
node_modules/n3/lib/N3StreamParser.js
generated
vendored
Normal file
74
node_modules/n3/lib/N3StreamParser.js
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = void 0;
|
||||
var _readableStream = require("readable-stream");
|
||||
var _N3Parser = _interopRequireDefault(require("./N3Parser"));
|
||||
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
||||
// **N3StreamParser** parses a text stream into a quad stream.
|
||||
|
||||
// ## Constructor
|
||||
class N3StreamParser extends _readableStream.Transform {
|
||||
constructor(options) {
|
||||
super({
|
||||
decodeStrings: true
|
||||
});
|
||||
this._readableState.objectMode = true;
|
||||
|
||||
// Set up parser with dummy stream to obtain `data` and `end` callbacks
|
||||
const parser = new _N3Parser.default(options);
|
||||
let onData, onEnd;
|
||||
const callbacks = {
|
||||
// Handle quads by pushing them down the pipeline
|
||||
onQuad: (error, quad) => {
|
||||
error && this.emit('error', error) || quad && this.push(quad);
|
||||
},
|
||||
// Emit prefixes through the `prefix` event
|
||||
onPrefix: (prefix, uri) => {
|
||||
this.emit('prefix', prefix, uri);
|
||||
}
|
||||
};
|
||||
if (options && options.comments) callbacks.onComment = comment => {
|
||||
this.emit('comment', comment);
|
||||
};
|
||||
parser.parse({
|
||||
on: (event, callback) => {
|
||||
switch (event) {
|
||||
case 'data':
|
||||
onData = callback;
|
||||
break;
|
||||
case 'end':
|
||||
onEnd = callback;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}, callbacks);
|
||||
|
||||
// Implement Transform methods through parser callbacks
|
||||
this._transform = (chunk, encoding, done) => {
|
||||
onData(chunk);
|
||||
done();
|
||||
};
|
||||
this._flush = done => {
|
||||
onEnd();
|
||||
done();
|
||||
};
|
||||
}
|
||||
|
||||
// ### Parses a stream of strings
|
||||
import(stream) {
|
||||
stream.on('data', chunk => {
|
||||
this.write(chunk);
|
||||
});
|
||||
stream.on('end', () => {
|
||||
this.end();
|
||||
});
|
||||
stream.on('error', error => {
|
||||
this.emit('error', error);
|
||||
});
|
||||
return this;
|
||||
}
|
||||
}
|
||||
exports.default = N3StreamParser;
|
||||
58
node_modules/n3/lib/N3StreamWriter.js
generated
vendored
Normal file
58
node_modules/n3/lib/N3StreamWriter.js
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = void 0;
|
||||
var _readableStream = require("readable-stream");
|
||||
var _N3Writer = _interopRequireDefault(require("./N3Writer"));
|
||||
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
||||
// **N3StreamWriter** serializes a quad stream into a text stream.
|
||||
|
||||
// ## Constructor
|
||||
class N3StreamWriter extends _readableStream.Transform {
|
||||
constructor(options) {
|
||||
super({
|
||||
encoding: 'utf8',
|
||||
writableObjectMode: true
|
||||
});
|
||||
|
||||
// Set up writer with a dummy stream object
|
||||
const writer = this._writer = new _N3Writer.default({
|
||||
write: (quad, encoding, callback) => {
|
||||
this.push(quad);
|
||||
callback && callback();
|
||||
},
|
||||
end: callback => {
|
||||
this.push(null);
|
||||
callback && callback();
|
||||
}
|
||||
}, options);
|
||||
|
||||
// Implement Transform methods on top of writer
|
||||
this._transform = (quad, encoding, done) => {
|
||||
writer.addQuad(quad, done);
|
||||
};
|
||||
this._flush = done => {
|
||||
writer.end(done);
|
||||
};
|
||||
}
|
||||
|
||||
// ### Serializes a stream of quads
|
||||
import(stream) {
|
||||
stream.on('data', quad => {
|
||||
this.write(quad);
|
||||
});
|
||||
stream.on('end', () => {
|
||||
this.end();
|
||||
});
|
||||
stream.on('error', error => {
|
||||
this.emit('error', error);
|
||||
});
|
||||
stream.on('prefix', (prefix, iri) => {
|
||||
this._writer.addPrefix(prefix, iri);
|
||||
});
|
||||
return this;
|
||||
}
|
||||
}
|
||||
exports.default = N3StreamWriter;
|
||||
85
node_modules/n3/lib/N3Util.js
generated
vendored
Normal file
85
node_modules/n3/lib/N3Util.js
generated
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.inDefaultGraph = inDefaultGraph;
|
||||
exports.isBlankNode = isBlankNode;
|
||||
exports.isDefaultGraph = isDefaultGraph;
|
||||
exports.isLiteral = isLiteral;
|
||||
exports.isNamedNode = isNamedNode;
|
||||
exports.isQuad = isQuad;
|
||||
exports.isVariable = isVariable;
|
||||
exports.prefix = prefix;
|
||||
exports.prefixes = prefixes;
|
||||
var _N3DataFactory = _interopRequireDefault(require("./N3DataFactory"));
|
||||
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
||||
// **N3Util** provides N3 utility functions.
|
||||
|
||||
// Tests whether the given term represents an IRI
|
||||
function isNamedNode(term) {
|
||||
return !!term && term.termType === 'NamedNode';
|
||||
}
|
||||
|
||||
// Tests whether the given term represents a blank node
|
||||
function isBlankNode(term) {
|
||||
return !!term && term.termType === 'BlankNode';
|
||||
}
|
||||
|
||||
// Tests whether the given term represents a literal
|
||||
function isLiteral(term) {
|
||||
return !!term && term.termType === 'Literal';
|
||||
}
|
||||
|
||||
// Tests whether the given term represents a variable
|
||||
function isVariable(term) {
|
||||
return !!term && term.termType === 'Variable';
|
||||
}
|
||||
|
||||
// Tests whether the given term represents a quad
|
||||
function isQuad(term) {
|
||||
return !!term && term.termType === 'Quad';
|
||||
}
|
||||
|
||||
// Tests whether the given term represents the default graph
|
||||
function isDefaultGraph(term) {
|
||||
return !!term && term.termType === 'DefaultGraph';
|
||||
}
|
||||
|
||||
// Tests whether the given quad is in the default graph
|
||||
function inDefaultGraph(quad) {
|
||||
return isDefaultGraph(quad.graph);
|
||||
}
|
||||
|
||||
// Creates a function that prepends the given IRI to a local name
|
||||
function prefix(iri, factory) {
|
||||
return prefixes({
|
||||
'': iri.value || iri
|
||||
}, factory)('');
|
||||
}
|
||||
|
||||
// Creates a function that allows registering and expanding prefixes
|
||||
function prefixes(defaultPrefixes, factory) {
|
||||
// Add all of the default prefixes
|
||||
const prefixes = Object.create(null);
|
||||
for (const prefix in defaultPrefixes) processPrefix(prefix, defaultPrefixes[prefix]);
|
||||
// Set the default factory if none was specified
|
||||
factory = factory || _N3DataFactory.default;
|
||||
|
||||
// Registers a new prefix (if an IRI was specified)
|
||||
// or retrieves a function that expands an existing prefix (if no IRI was specified)
|
||||
function processPrefix(prefix, iri) {
|
||||
// Create a new prefix if an IRI is specified or the prefix doesn't exist
|
||||
if (typeof iri === 'string') {
|
||||
// Create a function that expands the prefix
|
||||
const cache = Object.create(null);
|
||||
prefixes[prefix] = local => {
|
||||
return cache[local] || (cache[local] = factory.namedNode(iri + local));
|
||||
};
|
||||
} else if (!(prefix in prefixes)) {
|
||||
throw new Error(`Unknown prefix: ${prefix}`);
|
||||
}
|
||||
return prefixes[prefix];
|
||||
}
|
||||
return processPrefix;
|
||||
}
|
||||
384
node_modules/n3/lib/N3Writer.js
generated
vendored
Normal file
384
node_modules/n3/lib/N3Writer.js
generated
vendored
Normal file
@@ -0,0 +1,384 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = void 0;
|
||||
var _IRIs = _interopRequireDefault(require("./IRIs"));
|
||||
var _N3DataFactory = _interopRequireWildcard(require("./N3DataFactory"));
|
||||
var _N3Util = require("./N3Util");
|
||||
var _BaseIRI = _interopRequireDefault(require("./BaseIRI"));
|
||||
var _Util = require("./Util");
|
||||
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
||||
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
||||
// **N3Writer** writes N3 documents.
|
||||
|
||||
const DEFAULTGRAPH = _N3DataFactory.default.defaultGraph();
|
||||
const {
|
||||
rdf,
|
||||
xsd
|
||||
} = _IRIs.default;
|
||||
|
||||
// Characters in literals that require escaping
|
||||
const escape = /["\\\t\n\r\b\f\u0000-\u0019\ud800-\udbff]/,
|
||||
escapeAll = /["\\\t\n\r\b\f\u0000-\u0019]|[\ud800-\udbff][\udc00-\udfff]/g,
|
||||
escapedCharacters = {
|
||||
'\\': '\\\\',
|
||||
'"': '\\"',
|
||||
'\t': '\\t',
|
||||
'\n': '\\n',
|
||||
'\r': '\\r',
|
||||
'\b': '\\b',
|
||||
'\f': '\\f'
|
||||
};
|
||||
|
||||
// ## Placeholder class to represent already pretty-printed terms
|
||||
class SerializedTerm extends _N3DataFactory.Term {
|
||||
// Pretty-printed nodes are not equal to any other node
|
||||
// (e.g., [] does not equal [])
|
||||
equals(other) {
|
||||
return other === this;
|
||||
}
|
||||
}
|
||||
|
||||
// ## Constructor
|
||||
class N3Writer {
|
||||
constructor(outputStream, options) {
|
||||
// ### `_prefixRegex` matches a prefixed name or IRI that begins with one of the added prefixes
|
||||
this._prefixRegex = /$0^/;
|
||||
|
||||
// Shift arguments if the first argument is not a stream
|
||||
if (outputStream && typeof outputStream.write !== 'function') options = outputStream, outputStream = null;
|
||||
options = options || {};
|
||||
this._lists = options.lists;
|
||||
|
||||
// If no output stream given, send the output as string through the end callback
|
||||
if (!outputStream) {
|
||||
let output = '';
|
||||
this._outputStream = {
|
||||
write(chunk, encoding, done) {
|
||||
output += chunk;
|
||||
done && done();
|
||||
},
|
||||
end: done => {
|
||||
done && done(null, output);
|
||||
}
|
||||
};
|
||||
this._endStream = true;
|
||||
} else {
|
||||
this._outputStream = outputStream;
|
||||
this._endStream = options.end === undefined ? true : !!options.end;
|
||||
}
|
||||
|
||||
// Initialize writer, depending on the format
|
||||
this._subject = null;
|
||||
if (!/triple|quad/i.test(options.format)) {
|
||||
this._lineMode = false;
|
||||
this._graph = DEFAULTGRAPH;
|
||||
this._prefixIRIs = Object.create(null);
|
||||
options.prefixes && this.addPrefixes(options.prefixes);
|
||||
if (options.baseIRI) {
|
||||
this._baseIri = new _BaseIRI.default(options.baseIRI);
|
||||
}
|
||||
} else {
|
||||
this._lineMode = true;
|
||||
this._writeQuad = this._writeQuadLine;
|
||||
}
|
||||
}
|
||||
|
||||
// ## Private methods
|
||||
|
||||
// ### Whether the current graph is the default graph
|
||||
get _inDefaultGraph() {
|
||||
return DEFAULTGRAPH.equals(this._graph);
|
||||
}
|
||||
|
||||
// ### `_write` writes the argument to the output stream
|
||||
_write(string, callback) {
|
||||
this._outputStream.write(string, 'utf8', callback);
|
||||
}
|
||||
|
||||
// ### `_writeQuad` writes the quad to the output stream
|
||||
_writeQuad(subject, predicate, object, graph, done) {
|
||||
try {
|
||||
// Write the graph's label if it has changed
|
||||
if (!graph.equals(this._graph)) {
|
||||
// Close the previous graph and start the new one
|
||||
this._write((this._subject === null ? '' : this._inDefaultGraph ? '.\n' : '\n}\n') + (DEFAULTGRAPH.equals(graph) ? '' : `${this._encodeIriOrBlank(graph)} {\n`));
|
||||
this._graph = graph;
|
||||
this._subject = null;
|
||||
}
|
||||
// Don't repeat the subject if it's the same
|
||||
if (subject.equals(this._subject)) {
|
||||
// Don't repeat the predicate if it's the same
|
||||
if (predicate.equals(this._predicate)) this._write(`, ${this._encodeObject(object)}`, done);
|
||||
// Same subject, different predicate
|
||||
else this._write(`;\n ${this._encodePredicate(this._predicate = predicate)} ${this._encodeObject(object)}`, done);
|
||||
}
|
||||
// Different subject; write the whole quad
|
||||
else this._write(`${(this._subject === null ? '' : '.\n') + this._encodeSubject(this._subject = subject)} ${this._encodePredicate(this._predicate = predicate)} ${this._encodeObject(object)}`, done);
|
||||
} catch (error) {
|
||||
done && done(error);
|
||||
}
|
||||
}
|
||||
|
||||
// ### `_writeQuadLine` writes the quad to the output stream as a single line
|
||||
_writeQuadLine(subject, predicate, object, graph, done) {
|
||||
// Write the quad without prefixes
|
||||
delete this._prefixMatch;
|
||||
this._write(this.quadToString(subject, predicate, object, graph), done);
|
||||
}
|
||||
|
||||
// ### `quadToString` serializes a quad as a string
|
||||
quadToString(subject, predicate, object, graph) {
|
||||
return `${this._encodeSubject(subject)} ${this._encodeIriOrBlank(predicate)} ${this._encodeObject(object)}${graph && graph.value ? ` ${this._encodeIriOrBlank(graph)} .\n` : ' .\n'}`;
|
||||
}
|
||||
|
||||
// ### `quadsToString` serializes an array of quads as a string
|
||||
quadsToString(quads) {
|
||||
let quadsString = '';
|
||||
for (const quad of quads) quadsString += this.quadToString(quad.subject, quad.predicate, quad.object, quad.graph);
|
||||
return quadsString;
|
||||
}
|
||||
|
||||
// ### `_encodeSubject` represents a subject
|
||||
_encodeSubject(entity) {
|
||||
return entity.termType === 'Quad' ? this._encodeQuad(entity) : this._encodeIriOrBlank(entity);
|
||||
}
|
||||
|
||||
// ### `_encodeIriOrBlank` represents an IRI or blank node
|
||||
_encodeIriOrBlank(entity) {
|
||||
// A blank node or list is represented as-is
|
||||
if (entity.termType !== 'NamedNode') {
|
||||
// If it is a list head, pretty-print it
|
||||
if (this._lists && entity.value in this._lists) entity = this.list(this._lists[entity.value]);
|
||||
return 'id' in entity ? entity.id : `_:${entity.value}`;
|
||||
}
|
||||
let iri = entity.value;
|
||||
// Use relative IRIs if requested and possible
|
||||
if (this._baseIri) {
|
||||
iri = this._baseIri.toRelative(iri);
|
||||
}
|
||||
// Escape special characters
|
||||
if (escape.test(iri)) iri = iri.replace(escapeAll, characterReplacer);
|
||||
// Try to represent the IRI as prefixed name
|
||||
const prefixMatch = this._prefixRegex.exec(iri);
|
||||
return !prefixMatch ? `<${iri}>` : !prefixMatch[1] ? iri : this._prefixIRIs[prefixMatch[1]] + prefixMatch[2];
|
||||
}
|
||||
|
||||
// ### `_encodeLiteral` represents a literal
|
||||
_encodeLiteral(literal) {
|
||||
// Escape special characters
|
||||
let value = literal.value;
|
||||
if (escape.test(value)) value = value.replace(escapeAll, characterReplacer);
|
||||
|
||||
// Write a language-tagged literal
|
||||
if (literal.language) return `"${value}"@${literal.language}`;
|
||||
|
||||
// Write dedicated literals per data type
|
||||
if (this._lineMode) {
|
||||
// Only abbreviate strings in N-Triples or N-Quads
|
||||
if (literal.datatype.value === xsd.string) return `"${value}"`;
|
||||
} else {
|
||||
// Use common datatype abbreviations in Turtle or TriG
|
||||
switch (literal.datatype.value) {
|
||||
case xsd.string:
|
||||
return `"${value}"`;
|
||||
case xsd.boolean:
|
||||
if (value === 'true' || value === 'false') return value;
|
||||
break;
|
||||
case xsd.integer:
|
||||
if (/^[+-]?\d+$/.test(value)) return value;
|
||||
break;
|
||||
case xsd.decimal:
|
||||
if (/^[+-]?\d*\.\d+$/.test(value)) return value;
|
||||
break;
|
||||
case xsd.double:
|
||||
if (/^[+-]?(?:\d+\.\d*|\.?\d+)[eE][+-]?\d+$/.test(value)) return value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Write a regular datatyped literal
|
||||
return `"${value}"^^${this._encodeIriOrBlank(literal.datatype)}`;
|
||||
}
|
||||
|
||||
// ### `_encodePredicate` represents a predicate
|
||||
_encodePredicate(predicate) {
|
||||
return predicate.value === rdf.type ? 'a' : this._encodeIriOrBlank(predicate);
|
||||
}
|
||||
|
||||
// ### `_encodeObject` represents an object
|
||||
_encodeObject(object) {
|
||||
switch (object.termType) {
|
||||
case 'Quad':
|
||||
return this._encodeQuad(object);
|
||||
case 'Literal':
|
||||
return this._encodeLiteral(object);
|
||||
default:
|
||||
return this._encodeIriOrBlank(object);
|
||||
}
|
||||
}
|
||||
|
||||
// ### `_encodeQuad` encodes an RDF-star quad
|
||||
_encodeQuad({
|
||||
subject,
|
||||
predicate,
|
||||
object,
|
||||
graph
|
||||
}) {
|
||||
return `<<${this._encodeSubject(subject)} ${this._encodePredicate(predicate)} ${this._encodeObject(object)}${(0, _N3Util.isDefaultGraph)(graph) ? '' : ` ${this._encodeIriOrBlank(graph)}`}>>`;
|
||||
}
|
||||
|
||||
// ### `_blockedWrite` replaces `_write` after the writer has been closed
|
||||
_blockedWrite() {
|
||||
throw new Error('Cannot write because the writer has been closed.');
|
||||
}
|
||||
|
||||
// ### `addQuad` adds the quad to the output stream
|
||||
addQuad(subject, predicate, object, graph, done) {
|
||||
// The quad was given as an object, so shift parameters
|
||||
if (object === undefined) this._writeQuad(subject.subject, subject.predicate, subject.object, subject.graph, predicate);
|
||||
// The optional `graph` parameter was not provided
|
||||
else if (typeof graph === 'function') this._writeQuad(subject, predicate, object, DEFAULTGRAPH, graph);
|
||||
// The `graph` parameter was provided
|
||||
else this._writeQuad(subject, predicate, object, graph || DEFAULTGRAPH, done);
|
||||
}
|
||||
|
||||
// ### `addQuads` adds the quads to the output stream
|
||||
addQuads(quads) {
|
||||
for (let i = 0; i < quads.length; i++) this.addQuad(quads[i]);
|
||||
}
|
||||
|
||||
// ### `addPrefix` adds the prefix to the output stream
|
||||
addPrefix(prefix, iri, done) {
|
||||
const prefixes = {};
|
||||
prefixes[prefix] = iri;
|
||||
this.addPrefixes(prefixes, done);
|
||||
}
|
||||
|
||||
// ### `addPrefixes` adds the prefixes to the output stream
|
||||
addPrefixes(prefixes, done) {
|
||||
// Ignore prefixes if not supported by the serialization
|
||||
if (!this._prefixIRIs) return done && done();
|
||||
|
||||
// Write all new prefixes
|
||||
let hasPrefixes = false;
|
||||
for (let prefix in prefixes) {
|
||||
let iri = prefixes[prefix];
|
||||
if (typeof iri !== 'string') iri = iri.value;
|
||||
hasPrefixes = true;
|
||||
// Finish a possible pending quad
|
||||
if (this._subject !== null) {
|
||||
this._write(this._inDefaultGraph ? '.\n' : '\n}\n');
|
||||
this._subject = null, this._graph = '';
|
||||
}
|
||||
// Store and write the prefix
|
||||
this._prefixIRIs[iri] = prefix += ':';
|
||||
this._write(`@prefix ${prefix} <${iri}>.\n`);
|
||||
}
|
||||
// Recreate the prefix matcher
|
||||
if (hasPrefixes) {
|
||||
let IRIlist = '',
|
||||
prefixList = '';
|
||||
for (const prefixIRI in this._prefixIRIs) {
|
||||
IRIlist += IRIlist ? `|${prefixIRI}` : prefixIRI;
|
||||
prefixList += (prefixList ? '|' : '') + this._prefixIRIs[prefixIRI];
|
||||
}
|
||||
IRIlist = (0, _Util.escapeRegex)(IRIlist, /[\]\/\(\)\*\+\?\.\\\$]/g, '\\$&');
|
||||
this._prefixRegex = new RegExp(`^(?:${prefixList})[^\/]*$|` + `^(${IRIlist})([_a-zA-Z0-9][\\-_a-zA-Z0-9]*)$`);
|
||||
}
|
||||
// End a prefix block with a newline
|
||||
this._write(hasPrefixes ? '\n' : '', done);
|
||||
}
|
||||
|
||||
// ### `blank` creates a blank node with the given content
|
||||
blank(predicate, object) {
|
||||
let children = predicate,
|
||||
child,
|
||||
length;
|
||||
// Empty blank node
|
||||
if (predicate === undefined) children = [];
|
||||
// Blank node passed as blank(Term("predicate"), Term("object"))
|
||||
else if (predicate.termType) children = [{
|
||||
predicate: predicate,
|
||||
object: object
|
||||
}];
|
||||
// Blank node passed as blank({ predicate: predicate, object: object })
|
||||
else if (!('length' in predicate)) children = [predicate];
|
||||
switch (length = children.length) {
|
||||
// Generate an empty blank node
|
||||
case 0:
|
||||
return new SerializedTerm('[]');
|
||||
// Generate a non-nested one-triple blank node
|
||||
case 1:
|
||||
child = children[0];
|
||||
if (!(child.object instanceof SerializedTerm)) return new SerializedTerm(`[ ${this._encodePredicate(child.predicate)} ${this._encodeObject(child.object)} ]`);
|
||||
// Generate a multi-triple or nested blank node
|
||||
default:
|
||||
let contents = '[';
|
||||
// Write all triples in order
|
||||
for (let i = 0; i < length; i++) {
|
||||
child = children[i];
|
||||
// Write only the object is the predicate is the same as the previous
|
||||
if (child.predicate.equals(predicate)) contents += `, ${this._encodeObject(child.object)}`;
|
||||
// Otherwise, write the predicate and the object
|
||||
else {
|
||||
contents += `${(i ? ';\n ' : '\n ') + this._encodePredicate(child.predicate)} ${this._encodeObject(child.object)}`;
|
||||
predicate = child.predicate;
|
||||
}
|
||||
}
|
||||
return new SerializedTerm(`${contents}\n]`);
|
||||
}
|
||||
}
|
||||
|
||||
// ### `list` creates a list node with the given content
|
||||
list(elements) {
|
||||
const length = elements && elements.length || 0,
|
||||
contents = new Array(length);
|
||||
for (let i = 0; i < length; i++) contents[i] = this._encodeObject(elements[i]);
|
||||
return new SerializedTerm(`(${contents.join(' ')})`);
|
||||
}
|
||||
|
||||
// ### `end` signals the end of the output stream
|
||||
end(done) {
|
||||
// Finish a possible pending quad
|
||||
if (this._subject !== null) {
|
||||
this._write(this._inDefaultGraph ? '.\n' : '\n}\n');
|
||||
this._subject = null;
|
||||
}
|
||||
// Disallow further writing
|
||||
this._write = this._blockedWrite;
|
||||
|
||||
// Try to end the underlying stream, ensuring done is called exactly one time
|
||||
let singleDone = done && ((error, result) => {
|
||||
singleDone = null, done(error, result);
|
||||
});
|
||||
if (this._endStream) {
|
||||
try {
|
||||
return this._outputStream.end(singleDone);
|
||||
} catch (error) {/* error closing stream */}
|
||||
}
|
||||
singleDone && singleDone();
|
||||
}
|
||||
}
|
||||
|
||||
// Replaces a character by its escaped version
|
||||
exports.default = N3Writer;
|
||||
function characterReplacer(character) {
|
||||
// Replace a single character by its escaped version
|
||||
let result = escapedCharacters[character];
|
||||
if (result === undefined) {
|
||||
// Replace a single character with its 4-bit unicode escape sequence
|
||||
if (character.length === 1) {
|
||||
result = character.charCodeAt(0).toString(16);
|
||||
result = '\\u0000'.substr(0, 6 - result.length) + result;
|
||||
}
|
||||
// Replace a surrogate pair with its 8-bit unicode escape sequence
|
||||
else {
|
||||
result = ((character.charCodeAt(0) - 0xD800) * 0x400 + character.charCodeAt(1) + 0x2400).toString(16);
|
||||
result = '\\U00000000'.substr(0, 10 - result.length) + result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
9
node_modules/n3/lib/Util.js
generated
vendored
Normal file
9
node_modules/n3/lib/Util.js
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.escapeRegex = escapeRegex;
|
||||
function escapeRegex(regex) {
|
||||
return regex.replace(/[\]\/\(\)\*\+\?\.\\\$]/g, '\\$&');
|
||||
}
|
||||
179
node_modules/n3/lib/index.js
generated
vendored
Normal file
179
node_modules/n3/lib/index.js
generated
vendored
Normal file
@@ -0,0 +1,179 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
Object.defineProperty(exports, "BaseIRI", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _BaseIRI.default;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "BlankNode", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _N3DataFactory.BlankNode;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "DataFactory", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _N3DataFactory.default;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "DefaultGraph", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _N3DataFactory.DefaultGraph;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "EntityIndex", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _N3Store.N3EntityIndex;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "Lexer", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _N3Lexer.default;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "Literal", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _N3DataFactory.Literal;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "NamedNode", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _N3DataFactory.NamedNode;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "Parser", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _N3Parser.default;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "Quad", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _N3DataFactory.Quad;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "Reasoner", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _N3Reasoner.default;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "Store", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _N3Store.default;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "StoreFactory", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _N3StoreFactory.default;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "StreamParser", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _N3StreamParser.default;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "StreamWriter", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _N3StreamWriter.default;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "Term", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _N3DataFactory.Term;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "Triple", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _N3DataFactory.Triple;
|
||||
}
|
||||
});
|
||||
exports.Util = void 0;
|
||||
Object.defineProperty(exports, "Variable", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _N3DataFactory.Variable;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "Writer", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _N3Writer.default;
|
||||
}
|
||||
});
|
||||
exports.default = void 0;
|
||||
Object.defineProperty(exports, "getRulesFromDataset", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _N3Reasoner.getRulesFromDataset;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "termFromId", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _N3DataFactory.termFromId;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "termToId", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _N3DataFactory.termToId;
|
||||
}
|
||||
});
|
||||
var _N3Lexer = _interopRequireDefault(require("./N3Lexer"));
|
||||
var _N3Parser = _interopRequireDefault(require("./N3Parser"));
|
||||
var _N3Writer = _interopRequireDefault(require("./N3Writer"));
|
||||
var _N3Store = _interopRequireWildcard(require("./N3Store"));
|
||||
var _N3StoreFactory = _interopRequireDefault(require("./N3StoreFactory"));
|
||||
var _N3Reasoner = _interopRequireWildcard(require("./N3Reasoner"));
|
||||
var _N3StreamParser = _interopRequireDefault(require("./N3StreamParser"));
|
||||
var _N3StreamWriter = _interopRequireDefault(require("./N3StreamWriter"));
|
||||
var Util = _interopRequireWildcard(require("./N3Util"));
|
||||
exports.Util = Util;
|
||||
var _BaseIRI = _interopRequireDefault(require("./BaseIRI"));
|
||||
var _N3DataFactory = _interopRequireWildcard(require("./N3DataFactory"));
|
||||
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
||||
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
||||
// Named exports
|
||||
// Export all named exports as a default object for backward compatibility
|
||||
var _default = exports.default = {
|
||||
Lexer: _N3Lexer.default,
|
||||
Parser: _N3Parser.default,
|
||||
Writer: _N3Writer.default,
|
||||
Store: _N3Store.default,
|
||||
StoreFactory: _N3StoreFactory.default,
|
||||
EntityIndex: _N3Store.N3EntityIndex,
|
||||
StreamParser: _N3StreamParser.default,
|
||||
StreamWriter: _N3StreamWriter.default,
|
||||
Util,
|
||||
Reasoner: _N3Reasoner.default,
|
||||
BaseIRI: _BaseIRI.default,
|
||||
DataFactory: _N3DataFactory.default,
|
||||
Term: _N3DataFactory.Term,
|
||||
NamedNode: _N3DataFactory.NamedNode,
|
||||
Literal: _N3DataFactory.Literal,
|
||||
BlankNode: _N3DataFactory.BlankNode,
|
||||
Variable: _N3DataFactory.Variable,
|
||||
DefaultGraph: _N3DataFactory.DefaultGraph,
|
||||
Quad: _N3DataFactory.Quad,
|
||||
Triple: _N3DataFactory.Triple,
|
||||
termFromId: _N3DataFactory.termFromId,
|
||||
termToId: _N3DataFactory.termToId
|
||||
};
|
||||
108
node_modules/n3/package.json
generated
vendored
Normal file
108
node_modules/n3/package.json
generated
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
{
|
||||
"name": "n3",
|
||||
"version": "1.26.0",
|
||||
"description": "Lightning fast, asynchronous, streaming Turtle / N3 / RDF library.",
|
||||
"author": "Ruben Verborgh <ruben.verborgh@gmail.com>",
|
||||
"keywords": [
|
||||
"turtle",
|
||||
"rdf",
|
||||
"n3",
|
||||
"streaming",
|
||||
"asynchronous"
|
||||
],
|
||||
"license": "MIT",
|
||||
"main": "./lib/index.js",
|
||||
"module": "./src/index.js",
|
||||
"sideEffects": false,
|
||||
"engines": {
|
||||
"node": ">=12.0"
|
||||
},
|
||||
"files": [
|
||||
".babelrc",
|
||||
"src",
|
||||
"lib",
|
||||
"browser"
|
||||
],
|
||||
"dependencies": {
|
||||
"buffer": "^6.0.3",
|
||||
"readable-stream": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.16.0",
|
||||
"@babel/core": "^7.16.0",
|
||||
"@babel/preset-env": "^7.16.0",
|
||||
"@babel/register": "^7.16.0",
|
||||
"@rdfjs/data-model": "^1",
|
||||
"arrayify-stream": "^3.0.0",
|
||||
"browserify": "^17.0.0",
|
||||
"deep-taxonomy-benchmark": "^2.0.0",
|
||||
"docco": "^0.9.1",
|
||||
"eslint": "^8.57.1",
|
||||
"eslint-plugin-import": "^2.29.1",
|
||||
"eslint-plugin-jest": "^28.8.3",
|
||||
"jest": "^29.7.0",
|
||||
"pre-commit": "^1.2.2",
|
||||
"rdf-isomorphic": "^2.0.0",
|
||||
"rdf-test-suite": "^1.25.0",
|
||||
"streamify-string": "^1.0.1",
|
||||
"uglify-js": "^3.14.3"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "npm run build:node && npm run build:browser",
|
||||
"build:node": "babel src -d lib",
|
||||
"build:browser": "rm -rf browser && mkdir browser && browserify -s N3 lib/index.js | uglifyjs > browser/n3.min.js",
|
||||
"test": "jest",
|
||||
"lint": "eslint src perf test spec",
|
||||
"prepare": "npm run build",
|
||||
"spec": "npm run spec-turtle && npm run spec-ntriples && npm run spec-nquads && npm run spec-trig",
|
||||
"spec-earl": "npm run spec-earl-turtle && npm run spec-earl-ntriples && npm run spec-earl-nquads && npm run spec-earl-trig",
|
||||
"spec-ntriples": "rdf-test-suite spec/parser.js https://w3c.github.io/rdf-tests/rdf/rdf11/rdf-n-triples/manifest.ttl -i '{ \"format\": \"n-triples\" }' -c .rdf-test-suite-cache/",
|
||||
"spec-nquads": "rdf-test-suite spec/parser.js https://w3c.github.io/rdf-tests/rdf/rdf11/rdf-n-quads/manifest.ttl -i '{ \"format\": \"n-quads\" }' -c .rdf-test-suite-cache/",
|
||||
"spec-turtle": "rdf-test-suite spec/parser.js https://w3c.github.io/rdf-tests/rdf/rdf11/rdf-turtle/manifest.ttl -i '{ \"format\": \"turtle\" }' -c .rdf-test-suite-cache/",
|
||||
"spec-trig": "rdf-test-suite spec/parser.js https://w3c.github.io/rdf-tests/rdf/rdf11/rdf-trig/manifest.ttl -i '{ \"format\": \"trig\" }' -c .rdf-test-suite-cache/",
|
||||
"spec-earl-ntriples": "rdf-test-suite spec/parser.js https://w3c.github.io/rdf-tests/rdf/rdf11/rdf-n-triples/manifest.ttl -i '{ \"format\": \"n-triples\" }' -c .rdf-test-suite-cache/ -o earl -p spec/earl-meta.json > spec/earl-ntriples.ttl",
|
||||
"spec-earl-nquads": "rdf-test-suite spec/parser.js https://w3c.github.io/rdf-tests/rdf/rdf11/rdf-n-quads/manifest.ttl -i '{ \"format\": \"n-quads\" }' -c .rdf-test-suite-cache/ -o earl -p spec/earl-meta.json > spec/earl-nquads.ttl",
|
||||
"spec-earl-turtle": "rdf-test-suite spec/parser.js https://w3c.github.io/rdf-tests/rdf/rdf11/rdf-turtle/manifest.ttl -i '{ \"format\": \"turtle\" }' -c .rdf-test-suite-cache/ -o earl -p spec/earl-meta.json > spec/earl-turtle.ttl",
|
||||
"spec-earl-trig": "rdf-test-suite spec/parser.js https://w3c.github.io/rdf-tests/rdf/rdf11/rdf-trig/manifest.ttl -i '{ \"format\": \"trig\" }' -c .rdf-test-suite-cache/ -o earl -p spec/earl-meta.json > spec/earl-trig.ttl",
|
||||
"spec-clean": "rm -r .rdf-test-suite-cache/",
|
||||
"docs": "cd src && docco *.js -o ../docs && cd .."
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/rdfjs/N3.js.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/rdfjs/N3.js/issues"
|
||||
},
|
||||
"pre-commit": [
|
||||
"lint",
|
||||
"test"
|
||||
],
|
||||
"jest": {
|
||||
"testMatch": [
|
||||
"**/test/*-test.js"
|
||||
],
|
||||
"collectCoverage": true,
|
||||
"coverageReporters": [
|
||||
"json-summary",
|
||||
"text",
|
||||
"lcov"
|
||||
],
|
||||
"coverageThreshold": {
|
||||
"global": {
|
||||
"branches": 100,
|
||||
"functions": 100,
|
||||
"lines": 100,
|
||||
"statements": 100
|
||||
}
|
||||
}
|
||||
},
|
||||
"release": {
|
||||
"branches": [
|
||||
"main"
|
||||
]
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
||||
101
node_modules/n3/src/BaseIRI.js
generated
vendored
Normal file
101
node_modules/n3/src/BaseIRI.js
generated
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
import { escapeRegex } from './Util';
|
||||
|
||||
// Do not handle base IRIs without scheme, and currently unsupported cases:
|
||||
// - file: IRIs (which could also use backslashes)
|
||||
// - IRIs containing /. or /.. or //
|
||||
const BASE_UNSUPPORTED = /^:?[^:?#]*(?:[?#]|$)|^file:|^[^:]*:\/*[^?#]+?\/(?:\.\.?(?:\/|$)|\/)/i;
|
||||
const SUFFIX_SUPPORTED = /^(?:(?:[^/?#]{3,}|\.?[^/?#.]\.?)(?:\/[^/?#]{3,}|\.?[^/?#.]\.?)*\/?)?(?:[?#]|$)/;
|
||||
const CURRENT = './';
|
||||
const PARENT = '../';
|
||||
const QUERY = '?';
|
||||
const FRAGMENT = '#';
|
||||
|
||||
export default class BaseIRI {
|
||||
constructor(base) {
|
||||
this.base = base;
|
||||
this._baseLength = 0;
|
||||
this._baseMatcher = null;
|
||||
this._pathReplacements = new Array(base.length + 1);
|
||||
}
|
||||
|
||||
static supports(base) {
|
||||
return !BASE_UNSUPPORTED.test(base);
|
||||
}
|
||||
|
||||
_getBaseMatcher() {
|
||||
if (this._baseMatcher)
|
||||
return this._baseMatcher;
|
||||
if (!BaseIRI.supports(this.base))
|
||||
return this._baseMatcher = /.^/;
|
||||
|
||||
// Extract the scheme
|
||||
const scheme = /^[^:]*:\/*/.exec(this.base)[0];
|
||||
const regexHead = ['^', escapeRegex(scheme)];
|
||||
const regexTail = [];
|
||||
|
||||
// Generate a regex for every path segment
|
||||
const segments = [], segmenter = /[^/?#]*([/?#])/y;
|
||||
let segment, query = 0, fragment = 0, last = segmenter.lastIndex = scheme.length;
|
||||
while (!query && !fragment && (segment = segmenter.exec(this.base))) {
|
||||
// Truncate base resolution path at fragment start
|
||||
if (segment[1] === FRAGMENT)
|
||||
fragment = segmenter.lastIndex - 1;
|
||||
else {
|
||||
// Create regex that matches the segment
|
||||
regexHead.push(escapeRegex(segment[0]), '(?:');
|
||||
regexTail.push(')?');
|
||||
|
||||
// Create dedicated query string replacement
|
||||
if (segment[1] !== QUERY)
|
||||
segments.push(last = segmenter.lastIndex);
|
||||
else {
|
||||
query = last = segmenter.lastIndex;
|
||||
fragment = this.base.indexOf(FRAGMENT, query);
|
||||
this._pathReplacements[query] = QUERY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Precalculate parent path substitutions
|
||||
for (let i = 0; i < segments.length; i++)
|
||||
this._pathReplacements[segments[i]] = PARENT.repeat(segments.length - i - 1);
|
||||
this._pathReplacements[segments[segments.length - 1]] = CURRENT;
|
||||
|
||||
// Add the remainder of the base IRI (without fragment) to the regex
|
||||
this._baseLength = fragment > 0 ? fragment : this.base.length;
|
||||
regexHead.push(
|
||||
escapeRegex(this.base.substring(last, this._baseLength)),
|
||||
query ? '(?:#|$)' : '(?:[?#]|$)',
|
||||
);
|
||||
return this._baseMatcher = new RegExp([...regexHead, ...regexTail].join(''));
|
||||
}
|
||||
|
||||
toRelative(iri) {
|
||||
// Unsupported or non-matching base IRI
|
||||
const match = this._getBaseMatcher().exec(iri);
|
||||
if (!match)
|
||||
return iri;
|
||||
|
||||
// Exact base IRI match
|
||||
const length = match[0].length;
|
||||
if (length === this._baseLength && length === iri.length)
|
||||
return '';
|
||||
|
||||
// Parent path match
|
||||
const parentPath = this._pathReplacements[length];
|
||||
if (parentPath) {
|
||||
const suffix = iri.substring(length);
|
||||
// Don't abbreviate unsupported path
|
||||
if (parentPath !== QUERY && !SUFFIX_SUPPORTED.test(suffix))
|
||||
return iri;
|
||||
// Omit ./ with fragment or query string
|
||||
if (parentPath === CURRENT && /^[^?#]/.test(suffix))
|
||||
return suffix;
|
||||
// Append suffix to relative parent path
|
||||
return parentPath + suffix;
|
||||
}
|
||||
|
||||
// Fragment or query string, so include delimiter
|
||||
return iri.substring(length - 1);
|
||||
}
|
||||
}
|
||||
31
node_modules/n3/src/IRIs.js
generated
vendored
Normal file
31
node_modules/n3/src/IRIs.js
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
const RDF = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
|
||||
XSD = 'http://www.w3.org/2001/XMLSchema#',
|
||||
SWAP = 'http://www.w3.org/2000/10/swap/';
|
||||
|
||||
export default {
|
||||
xsd: {
|
||||
decimal: `${XSD}decimal`,
|
||||
boolean: `${XSD}boolean`,
|
||||
double: `${XSD}double`,
|
||||
integer: `${XSD}integer`,
|
||||
string: `${XSD}string`,
|
||||
},
|
||||
rdf: {
|
||||
type: `${RDF}type`,
|
||||
nil: `${RDF}nil`,
|
||||
first: `${RDF}first`,
|
||||
rest: `${RDF}rest`,
|
||||
langString: `${RDF}langString`,
|
||||
},
|
||||
owl: {
|
||||
sameAs: 'http://www.w3.org/2002/07/owl#sameAs',
|
||||
},
|
||||
r: {
|
||||
forSome: `${SWAP}reify#forSome`,
|
||||
forAll: `${SWAP}reify#forAll`,
|
||||
},
|
||||
log: {
|
||||
implies: `${SWAP}log#implies`,
|
||||
isImpliedBy: `${SWAP}log#isImpliedBy`,
|
||||
},
|
||||
};
|
||||
416
node_modules/n3/src/N3DataFactory.js
generated
vendored
Normal file
416
node_modules/n3/src/N3DataFactory.js
generated
vendored
Normal file
@@ -0,0 +1,416 @@
|
||||
// N3.js implementations of the RDF/JS core data types
|
||||
// See http://rdf.js.org/data-model-spec/
|
||||
|
||||
import namespaces from './IRIs';
|
||||
|
||||
const { rdf, xsd } = namespaces;
|
||||
|
||||
// eslint-disable-next-line prefer-const
|
||||
let DEFAULTGRAPH;
|
||||
let _blankNodeCounter = 0;
|
||||
|
||||
const escapedLiteral = /^"(.*".*)(?="[^"]*$)/;
|
||||
|
||||
// ## DataFactory singleton
|
||||
const DataFactory = {
|
||||
namedNode,
|
||||
blankNode,
|
||||
variable,
|
||||
literal,
|
||||
defaultGraph,
|
||||
quad,
|
||||
triple: quad,
|
||||
fromTerm,
|
||||
fromQuad,
|
||||
};
|
||||
export default DataFactory;
|
||||
|
||||
// ## Term constructor
|
||||
export class Term {
|
||||
constructor(id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
// ### The value of this term
|
||||
get value() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
// ### Returns whether this object represents the same term as the other
|
||||
equals(other) {
|
||||
// If both terms were created by this library,
|
||||
// equality can be computed through ids
|
||||
if (other instanceof Term)
|
||||
return this.id === other.id;
|
||||
// Otherwise, compare term type and value
|
||||
return !!other && this.termType === other.termType &&
|
||||
this.value === other.value;
|
||||
}
|
||||
|
||||
// ### Implement hashCode for Immutable.js, since we implement `equals`
|
||||
// https://immutable-js.com/docs/v4.0.0/ValueObject/#hashCode()
|
||||
hashCode() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ### Returns a plain object representation of this term
|
||||
toJSON() {
|
||||
return {
|
||||
termType: this.termType,
|
||||
value: this.value,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ## NamedNode constructor
|
||||
export class NamedNode extends Term {
|
||||
// ### The term type of this term
|
||||
get termType() {
|
||||
return 'NamedNode';
|
||||
}
|
||||
}
|
||||
|
||||
// ## Literal constructor
|
||||
export class Literal extends Term {
|
||||
// ### The term type of this term
|
||||
get termType() {
|
||||
return 'Literal';
|
||||
}
|
||||
|
||||
// ### The text value of this literal
|
||||
get value() {
|
||||
return this.id.substring(1, this.id.lastIndexOf('"'));
|
||||
}
|
||||
|
||||
// ### The language of this literal
|
||||
get language() {
|
||||
// Find the last quotation mark (e.g., '"abc"@en-us')
|
||||
const id = this.id;
|
||||
let atPos = id.lastIndexOf('"') + 1;
|
||||
// If "@" it follows, return the remaining substring; empty otherwise
|
||||
return atPos < id.length && id[atPos++] === '@' ? id.substr(atPos).toLowerCase() : '';
|
||||
}
|
||||
|
||||
// ### The datatype IRI of this literal
|
||||
get datatype() {
|
||||
return new NamedNode(this.datatypeString);
|
||||
}
|
||||
|
||||
// ### The datatype string of this literal
|
||||
get datatypeString() {
|
||||
// Find the last quotation mark (e.g., '"abc"^^http://ex.org/types#t')
|
||||
const id = this.id, dtPos = id.lastIndexOf('"') + 1;
|
||||
const char = dtPos < id.length ? id[dtPos] : '';
|
||||
// If "^" it follows, return the remaining substring
|
||||
return char === '^' ? id.substr(dtPos + 2) :
|
||||
// If "@" follows, return rdf:langString; xsd:string otherwise
|
||||
(char !== '@' ? xsd.string : rdf.langString);
|
||||
}
|
||||
|
||||
// ### Returns whether this object represents the same term as the other
|
||||
equals(other) {
|
||||
// If both literals were created by this library,
|
||||
// equality can be computed through ids
|
||||
if (other instanceof Literal)
|
||||
return this.id === other.id;
|
||||
// Otherwise, compare term type, value, language, and datatype
|
||||
return !!other && !!other.datatype &&
|
||||
this.termType === other.termType &&
|
||||
this.value === other.value &&
|
||||
this.language === other.language &&
|
||||
this.datatype.value === other.datatype.value;
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
return {
|
||||
termType: this.termType,
|
||||
value: this.value,
|
||||
language: this.language,
|
||||
datatype: { termType: 'NamedNode', value: this.datatypeString },
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// ## BlankNode constructor
|
||||
export class BlankNode extends Term {
|
||||
constructor(name) {
|
||||
super(`_:${name}`);
|
||||
}
|
||||
|
||||
// ### The term type of this term
|
||||
get termType() {
|
||||
return 'BlankNode';
|
||||
}
|
||||
|
||||
// ### The name of this blank node
|
||||
get value() {
|
||||
return this.id.substr(2);
|
||||
}
|
||||
}
|
||||
|
||||
export class Variable extends Term {
|
||||
constructor(name) {
|
||||
super(`?${name}`);
|
||||
}
|
||||
|
||||
// ### The term type of this term
|
||||
get termType() {
|
||||
return 'Variable';
|
||||
}
|
||||
|
||||
// ### The name of this variable
|
||||
get value() {
|
||||
return this.id.substr(1);
|
||||
}
|
||||
}
|
||||
|
||||
// ## DefaultGraph constructor
|
||||
export class DefaultGraph extends Term {
|
||||
constructor() {
|
||||
super('');
|
||||
return DEFAULTGRAPH || this;
|
||||
}
|
||||
|
||||
// ### The term type of this term
|
||||
get termType() {
|
||||
return 'DefaultGraph';
|
||||
}
|
||||
|
||||
// ### Returns whether this object represents the same term as the other
|
||||
equals(other) {
|
||||
// If both terms were created by this library,
|
||||
// equality can be computed through strict equality;
|
||||
// otherwise, compare term types.
|
||||
return (this === other) || (!!other && (this.termType === other.termType));
|
||||
}
|
||||
}
|
||||
|
||||
// ## DefaultGraph singleton
|
||||
DEFAULTGRAPH = new DefaultGraph();
|
||||
|
||||
// ### Constructs a term from the given internal string ID
|
||||
// The third 'nested' parameter of this function is to aid
|
||||
// with recursion over nested terms. It should not be used
|
||||
// by consumers of this library.
|
||||
// See https://github.com/rdfjs/N3.js/pull/311#discussion_r1061042725
|
||||
export function termFromId(id, factory, nested) {
|
||||
factory = factory || DataFactory;
|
||||
|
||||
// Falsy value or empty string indicate the default graph
|
||||
if (!id)
|
||||
return factory.defaultGraph();
|
||||
|
||||
// Identify the term type based on the first character
|
||||
switch (id[0]) {
|
||||
case '?':
|
||||
return factory.variable(id.substr(1));
|
||||
case '_':
|
||||
return factory.blankNode(id.substr(2));
|
||||
case '"':
|
||||
// Shortcut for internal literals
|
||||
if (factory === DataFactory)
|
||||
return new Literal(id);
|
||||
// Literal without datatype or language
|
||||
if (id[id.length - 1] === '"')
|
||||
return factory.literal(id.substr(1, id.length - 2));
|
||||
// Literal with datatype or language
|
||||
const endPos = id.lastIndexOf('"', id.length - 1);
|
||||
return factory.literal(id.substr(1, endPos - 1),
|
||||
id[endPos + 1] === '@' ? id.substr(endPos + 2)
|
||||
: factory.namedNode(id.substr(endPos + 3)));
|
||||
case '[':
|
||||
id = JSON.parse(id);
|
||||
break;
|
||||
default:
|
||||
if (!nested || !Array.isArray(id)) {
|
||||
return factory.namedNode(id);
|
||||
}
|
||||
}
|
||||
return factory.quad(
|
||||
termFromId(id[0], factory, true),
|
||||
termFromId(id[1], factory, true),
|
||||
termFromId(id[2], factory, true),
|
||||
id[3] && termFromId(id[3], factory, true),
|
||||
);
|
||||
}
|
||||
|
||||
// ### Constructs an internal string ID from the given term or ID string
|
||||
// The third 'nested' parameter of this function is to aid
|
||||
// with recursion over nested terms. It should not be used
|
||||
// by consumers of this library.
|
||||
// See https://github.com/rdfjs/N3.js/pull/311#discussion_r1061042725
|
||||
export function termToId(term, nested) {
|
||||
if (typeof term === 'string')
|
||||
return term;
|
||||
if (term instanceof Term && term.termType !== 'Quad')
|
||||
return term.id;
|
||||
if (!term)
|
||||
return DEFAULTGRAPH.id;
|
||||
|
||||
// Term instantiated with another library
|
||||
switch (term.termType) {
|
||||
case 'NamedNode': return term.value;
|
||||
case 'BlankNode': return `_:${term.value}`;
|
||||
case 'Variable': return `?${term.value}`;
|
||||
case 'DefaultGraph': return '';
|
||||
case 'Literal': return `"${term.value}"${
|
||||
term.language ? `@${term.language}` :
|
||||
(term.datatype && term.datatype.value !== xsd.string ? `^^${term.datatype.value}` : '')}`;
|
||||
case 'Quad':
|
||||
const res = [
|
||||
termToId(term.subject, true),
|
||||
termToId(term.predicate, true),
|
||||
termToId(term.object, true),
|
||||
];
|
||||
if (term.graph && term.graph.termType !== 'DefaultGraph') {
|
||||
res.push(termToId(term.graph, true));
|
||||
}
|
||||
return nested ? res : JSON.stringify(res);
|
||||
default: throw new Error(`Unexpected termType: ${term.termType}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ## Quad constructor
|
||||
export class Quad extends Term {
|
||||
constructor(subject, predicate, object, graph) {
|
||||
super('');
|
||||
this._subject = subject;
|
||||
this._predicate = predicate;
|
||||
this._object = object;
|
||||
this._graph = graph || DEFAULTGRAPH;
|
||||
}
|
||||
|
||||
// ### The term type of this term
|
||||
get termType() {
|
||||
return 'Quad';
|
||||
}
|
||||
|
||||
get subject() {
|
||||
return this._subject;
|
||||
}
|
||||
|
||||
get predicate() {
|
||||
return this._predicate;
|
||||
}
|
||||
|
||||
get object() {
|
||||
return this._object;
|
||||
}
|
||||
|
||||
get graph() {
|
||||
return this._graph;
|
||||
}
|
||||
|
||||
// ### Returns a plain object representation of this quad
|
||||
toJSON() {
|
||||
return {
|
||||
termType: this.termType,
|
||||
subject: this._subject.toJSON(),
|
||||
predicate: this._predicate.toJSON(),
|
||||
object: this._object.toJSON(),
|
||||
graph: this._graph.toJSON(),
|
||||
};
|
||||
}
|
||||
|
||||
// ### Returns whether this object represents the same quad as the other
|
||||
equals(other) {
|
||||
return !!other && this._subject.equals(other.subject) &&
|
||||
this._predicate.equals(other.predicate) &&
|
||||
this._object.equals(other.object) &&
|
||||
this._graph.equals(other.graph);
|
||||
}
|
||||
}
|
||||
export { Quad as Triple };
|
||||
|
||||
// ### Escapes the quotes within the given literal
|
||||
export function escapeQuotes(id) {
|
||||
return id.replace(escapedLiteral, (_, quoted) => `"${quoted.replace(/"/g, '""')}`);
|
||||
}
|
||||
|
||||
// ### Unescapes the quotes within the given literal
|
||||
export function unescapeQuotes(id) {
|
||||
return id.replace(escapedLiteral, (_, quoted) => `"${quoted.replace(/""/g, '"')}`);
|
||||
}
|
||||
|
||||
// ### Creates an IRI
|
||||
function namedNode(iri) {
|
||||
return new NamedNode(iri);
|
||||
}
|
||||
|
||||
// ### Creates a blank node
|
||||
function blankNode(name) {
|
||||
return new BlankNode(name || `n3-${_blankNodeCounter++}`);
|
||||
}
|
||||
|
||||
// ### Creates a literal
|
||||
function literal(value, languageOrDataType) {
|
||||
// Create a language-tagged string
|
||||
if (typeof languageOrDataType === 'string')
|
||||
return new Literal(`"${value}"@${languageOrDataType.toLowerCase()}`);
|
||||
|
||||
// Automatically determine datatype for booleans and numbers
|
||||
let datatype = languageOrDataType ? languageOrDataType.value : '';
|
||||
if (datatype === '') {
|
||||
// Convert a boolean
|
||||
if (typeof value === 'boolean')
|
||||
datatype = xsd.boolean;
|
||||
// Convert an integer or double
|
||||
else if (typeof value === 'number') {
|
||||
if (Number.isFinite(value))
|
||||
datatype = Number.isInteger(value) ? xsd.integer : xsd.double;
|
||||
else {
|
||||
datatype = xsd.double;
|
||||
if (!Number.isNaN(value))
|
||||
value = value > 0 ? 'INF' : '-INF';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create a datatyped literal
|
||||
return (datatype === '' || datatype === xsd.string) ?
|
||||
new Literal(`"${value}"`) :
|
||||
new Literal(`"${value}"^^${datatype}`);
|
||||
}
|
||||
|
||||
// ### Creates a variable
|
||||
function variable(name) {
|
||||
return new Variable(name);
|
||||
}
|
||||
|
||||
// ### Returns the default graph
|
||||
function defaultGraph() {
|
||||
return DEFAULTGRAPH;
|
||||
}
|
||||
|
||||
// ### Creates a quad
|
||||
function quad(subject, predicate, object, graph) {
|
||||
return new Quad(subject, predicate, object, graph);
|
||||
}
|
||||
|
||||
export function fromTerm(term) {
|
||||
if (term instanceof Term)
|
||||
return term;
|
||||
|
||||
// Term instantiated with another library
|
||||
switch (term.termType) {
|
||||
case 'NamedNode': return namedNode(term.value);
|
||||
case 'BlankNode': return blankNode(term.value);
|
||||
case 'Variable': return variable(term.value);
|
||||
case 'DefaultGraph': return DEFAULTGRAPH;
|
||||
case 'Literal': return literal(term.value, term.language || term.datatype);
|
||||
case 'Quad': return fromQuad(term);
|
||||
default: throw new Error(`Unexpected termType: ${term.termType}`);
|
||||
}
|
||||
}
|
||||
|
||||
export function fromQuad(inQuad) {
|
||||
if (inQuad instanceof Quad)
|
||||
return inQuad;
|
||||
|
||||
if (inQuad.termType !== 'Quad')
|
||||
throw new Error(`Unexpected termType: ${inQuad.termType}`);
|
||||
|
||||
return quad(fromTerm(inQuad.subject), fromTerm(inQuad.predicate), fromTerm(inQuad.object), fromTerm(inQuad.graph));
|
||||
}
|
||||
527
node_modules/n3/src/N3Lexer.js
generated
vendored
Normal file
527
node_modules/n3/src/N3Lexer.js
generated
vendored
Normal file
@@ -0,0 +1,527 @@
|
||||
// **N3Lexer** tokenizes N3 documents.
|
||||
import { Buffer } from 'buffer';
|
||||
import namespaces from './IRIs';
|
||||
|
||||
const { xsd } = namespaces;
|
||||
|
||||
// Regular expression and replacement string to escape N3 strings
|
||||
const escapeSequence = /\\u([a-fA-F0-9]{4})|\\U([a-fA-F0-9]{8})|\\([^])/g;
|
||||
const escapeReplacements = {
|
||||
'\\': '\\', "'": "'", '"': '"',
|
||||
'n': '\n', 'r': '\r', 't': '\t', 'f': '\f', 'b': '\b',
|
||||
'_': '_', '~': '~', '.': '.', '-': '-', '!': '!', '$': '$', '&': '&',
|
||||
'(': '(', ')': ')', '*': '*', '+': '+', ',': ',', ';': ';', '=': '=',
|
||||
'/': '/', '?': '?', '#': '#', '@': '@', '%': '%',
|
||||
};
|
||||
const illegalIriChars = /[\x00-\x20<>\\"\{\}\|\^\`]/;
|
||||
|
||||
const lineModeRegExps = {
|
||||
_iri: true,
|
||||
_unescapedIri: true,
|
||||
_simpleQuotedString: true,
|
||||
_langcode: true,
|
||||
_blank: true,
|
||||
_newline: true,
|
||||
_comment: true,
|
||||
_whitespace: true,
|
||||
_endOfFile: true,
|
||||
};
|
||||
const invalidRegExp = /$0^/;
|
||||
|
||||
// ## Constructor
|
||||
export default class N3Lexer {
|
||||
constructor(options) {
|
||||
// ## Regular expressions
|
||||
// It's slightly faster to have these as properties than as in-scope variables
|
||||
this._iri = /^<((?:[^ <>{}\\]|\\[uU])+)>[ \t]*/; // IRI with escape sequences; needs sanity check after unescaping
|
||||
this._unescapedIri = /^<([^\x00-\x20<>\\"\{\}\|\^\`]*)>[ \t]*/; // IRI without escape sequences; no unescaping
|
||||
this._simpleQuotedString = /^"([^"\\\r\n]*)"(?=[^"])/; // string without escape sequences
|
||||
this._simpleApostropheString = /^'([^'\\\r\n]*)'(?=[^'])/;
|
||||
this._langcode = /^@([a-z]+(?:-[a-z0-9]+)*)(?=[^a-z0-9\-])/i;
|
||||
this._prefix = /^((?:[A-Za-z\xc0-\xd6\xd8-\xf6\xf8-\u02ff\u0370-\u037d\u037f-\u1fff\u200c\u200d\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])(?:\.?[\-0-9A-Z_a-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u037f-\u1fff\u200c\u200d\u203f\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])*)?:(?=[#\s<])/;
|
||||
this._prefixed = /^((?:[A-Za-z\xc0-\xd6\xd8-\xf6\xf8-\u02ff\u0370-\u037d\u037f-\u1fff\u200c\u200d\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])(?:\.?[\-0-9A-Z_a-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u037f-\u1fff\u200c\u200d\u203f\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])*)?:((?:(?:[0-:A-Z_a-z\xc0-\xd6\xd8-\xf6\xf8-\u02ff\u0370-\u037d\u037f-\u1fff\u200c\u200d\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff]|%[0-9a-fA-F]{2}|\\[!#-\/;=?\-@_~])(?:(?:[\.\-0-:A-Z_a-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u037f-\u1fff\u200c\u200d\u203f\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff]|%[0-9a-fA-F]{2}|\\[!#-\/;=?\-@_~])*(?:[\-0-:A-Z_a-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u037f-\u1fff\u200c\u200d\u203f\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff]|%[0-9a-fA-F]{2}|\\[!#-\/;=?\-@_~]))?)?)(?:[ \t]+|(?=\.?[,;!\^\s#()\[\]\{\}"'<>]))/;
|
||||
this._variable = /^\?(?:(?:[A-Z_a-z\xc0-\xd6\xd8-\xf6\xf8-\u02ff\u0370-\u037d\u037f-\u1fff\u200c\u200d\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])(?:[\-0-:A-Z_a-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u037f-\u1fff\u200c\u200d\u203f\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])*)(?=[.,;!\^\s#()\[\]\{\}"'<>])/;
|
||||
this._blank = /^_:((?:[0-9A-Z_a-z\xc0-\xd6\xd8-\xf6\xf8-\u02ff\u0370-\u037d\u037f-\u1fff\u200c\u200d\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])(?:\.?[\-0-9A-Z_a-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u037f-\u1fff\u200c\u200d\u203f\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])*)(?:[ \t]+|(?=\.?[,;:\s#()\[\]\{\}"'<>]))/;
|
||||
this._number = /^[\-+]?(?:(\d+\.\d*|\.?\d+)[eE][\-+]?|\d*(\.)?)\d+(?=\.?[,;:\s#()\[\]\{\}"'<>])/;
|
||||
this._boolean = /^(?:true|false)(?=[.,;\s#()\[\]\{\}"'<>])/;
|
||||
this._keyword = /^@[a-z]+(?=[\s#<:])/i;
|
||||
this._sparqlKeyword = /^(?:PREFIX|BASE|GRAPH)(?=[\s#<])/i;
|
||||
this._shortPredicates = /^a(?=[\s#()\[\]\{\}"'<>])/;
|
||||
this._newline = /^[ \t]*(?:#[^\n\r]*)?(?:\r\n|\n|\r)[ \t]*/;
|
||||
this._comment = /#([^\n\r]*)/;
|
||||
this._whitespace = /^[ \t]+/;
|
||||
this._endOfFile = /^(?:#[^\n\r]*)?$/;
|
||||
options = options || {};
|
||||
|
||||
// Whether the log:isImpliedBy predicate is supported
|
||||
this._isImpliedBy = options.isImpliedBy;
|
||||
|
||||
// In line mode (N-Triples or N-Quads), only simple features may be parsed
|
||||
if (this._lineMode = !!options.lineMode) {
|
||||
this._n3Mode = false;
|
||||
// Don't tokenize special literals
|
||||
for (const key in this) {
|
||||
if (!(key in lineModeRegExps) && this[key] instanceof RegExp)
|
||||
this[key] = invalidRegExp;
|
||||
}
|
||||
}
|
||||
// When not in line mode, enable N3 functionality by default
|
||||
else {
|
||||
this._n3Mode = options.n3 !== false;
|
||||
}
|
||||
// Don't output comment tokens by default
|
||||
this.comments = !!options.comments;
|
||||
// Cache the last tested closing position of long literals
|
||||
this._literalClosingPos = 0;
|
||||
}
|
||||
|
||||
// ## Private methods
|
||||
|
||||
// ### `_tokenizeToEnd` tokenizes as for as possible, emitting tokens through the callback
|
||||
_tokenizeToEnd(callback, inputFinished) {
|
||||
// Continue parsing as far as possible; the loop will return eventually
|
||||
let input = this._input;
|
||||
let currentLineLength = input.length;
|
||||
while (true) {
|
||||
// Count and skip whitespace lines
|
||||
let whiteSpaceMatch, comment;
|
||||
while (whiteSpaceMatch = this._newline.exec(input)) {
|
||||
// Try to find a comment
|
||||
if (this.comments && (comment = this._comment.exec(whiteSpaceMatch[0])))
|
||||
emitToken('comment', comment[1], '', this._line, whiteSpaceMatch[0].length);
|
||||
// Advance the input
|
||||
input = input.substr(whiteSpaceMatch[0].length, input.length);
|
||||
currentLineLength = input.length;
|
||||
this._line++;
|
||||
}
|
||||
// Skip whitespace on current line
|
||||
if (!whiteSpaceMatch && (whiteSpaceMatch = this._whitespace.exec(input)))
|
||||
input = input.substr(whiteSpaceMatch[0].length, input.length);
|
||||
|
||||
// Stop for now if we're at the end
|
||||
if (this._endOfFile.test(input)) {
|
||||
// If the input is finished, emit EOF
|
||||
if (inputFinished) {
|
||||
// Try to find a final comment
|
||||
if (this.comments && (comment = this._comment.exec(input)))
|
||||
emitToken('comment', comment[1], '', this._line, input.length);
|
||||
input = null;
|
||||
emitToken('eof', '', '', this._line, 0);
|
||||
}
|
||||
return this._input = input;
|
||||
}
|
||||
|
||||
// Look for specific token types based on the first character
|
||||
const line = this._line, firstChar = input[0];
|
||||
let type = '', value = '', prefix = '',
|
||||
match = null, matchLength = 0, inconclusive = false;
|
||||
switch (firstChar) {
|
||||
case '^':
|
||||
// We need at least 3 tokens lookahead to distinguish ^^<IRI> and ^^pre:fixed
|
||||
if (input.length < 3)
|
||||
break;
|
||||
// Try to match a type
|
||||
else if (input[1] === '^') {
|
||||
this._previousMarker = '^^';
|
||||
// Move to type IRI or prefixed name
|
||||
input = input.substr(2);
|
||||
if (input[0] !== '<') {
|
||||
inconclusive = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If no type, it must be a path expression
|
||||
else {
|
||||
if (this._n3Mode) {
|
||||
matchLength = 1;
|
||||
type = '^';
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Fall through in case the type is an IRI
|
||||
case '<':
|
||||
// Try to find a full IRI without escape sequences
|
||||
if (match = this._unescapedIri.exec(input))
|
||||
type = 'IRI', value = match[1];
|
||||
// Try to find a full IRI with escape sequences
|
||||
else if (match = this._iri.exec(input)) {
|
||||
value = this._unescape(match[1]);
|
||||
if (value === null || illegalIriChars.test(value))
|
||||
return reportSyntaxError(this);
|
||||
type = 'IRI';
|
||||
}
|
||||
// Try to find a nested triple
|
||||
else if (input.length > 1 && input[1] === '<')
|
||||
type = '<<', matchLength = 2;
|
||||
// Try to find a backwards implication arrow
|
||||
else if (this._n3Mode && input.length > 1 && input[1] === '=') {
|
||||
matchLength = 2;
|
||||
if (this._isImpliedBy) type = 'abbreviation', value = '<';
|
||||
else type = 'inverse', value = '>';
|
||||
}
|
||||
break;
|
||||
|
||||
case '>':
|
||||
if (input.length > 1 && input[1] === '>')
|
||||
type = '>>', matchLength = 2;
|
||||
break;
|
||||
|
||||
case '_':
|
||||
// Try to find a blank node. Since it can contain (but not end with) a dot,
|
||||
// we always need a non-dot character before deciding it is a blank node.
|
||||
// Therefore, try inserting a space if we're at the end of the input.
|
||||
if ((match = this._blank.exec(input)) ||
|
||||
inputFinished && (match = this._blank.exec(`${input} `)))
|
||||
type = 'blank', prefix = '_', value = match[1];
|
||||
break;
|
||||
|
||||
case '"':
|
||||
// Try to find a literal without escape sequences
|
||||
if (match = this._simpleQuotedString.exec(input))
|
||||
value = match[1];
|
||||
// Try to find a literal wrapped in three pairs of quotes
|
||||
else {
|
||||
({ value, matchLength } = this._parseLiteral(input));
|
||||
if (value === null)
|
||||
return reportSyntaxError(this);
|
||||
}
|
||||
if (match !== null || matchLength !== 0) {
|
||||
type = 'literal';
|
||||
this._literalClosingPos = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case "'":
|
||||
if (!this._lineMode) {
|
||||
// Try to find a literal without escape sequences
|
||||
if (match = this._simpleApostropheString.exec(input))
|
||||
value = match[1];
|
||||
// Try to find a literal wrapped in three pairs of quotes
|
||||
else {
|
||||
({ value, matchLength } = this._parseLiteral(input));
|
||||
if (value === null)
|
||||
return reportSyntaxError(this);
|
||||
}
|
||||
if (match !== null || matchLength !== 0) {
|
||||
type = 'literal';
|
||||
this._literalClosingPos = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case '?':
|
||||
// Try to find a variable
|
||||
if (this._n3Mode && (match = this._variable.exec(input)))
|
||||
type = 'var', value = match[0];
|
||||
break;
|
||||
|
||||
case '@':
|
||||
// Try to find a language code
|
||||
if (this._previousMarker === 'literal' && (match = this._langcode.exec(input)))
|
||||
type = 'langcode', value = match[1];
|
||||
// Try to find a keyword
|
||||
else if (match = this._keyword.exec(input))
|
||||
type = match[0];
|
||||
break;
|
||||
|
||||
case '.':
|
||||
// Try to find a dot as punctuation
|
||||
if (input.length === 1 ? inputFinished : (input[1] < '0' || input[1] > '9')) {
|
||||
type = '.';
|
||||
matchLength = 1;
|
||||
break;
|
||||
}
|
||||
// Fall through to numerical case (could be a decimal dot)
|
||||
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
case '+':
|
||||
case '-':
|
||||
// Try to find a number. Since it can contain (but not end with) a dot,
|
||||
// we always need a non-dot character before deciding it is a number.
|
||||
// Therefore, try inserting a space if we're at the end of the input.
|
||||
if (match = this._number.exec(input) ||
|
||||
inputFinished && (match = this._number.exec(`${input} `))) {
|
||||
type = 'literal', value = match[0];
|
||||
prefix = (typeof match[1] === 'string' ? xsd.double :
|
||||
(typeof match[2] === 'string' ? xsd.decimal : xsd.integer));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'B':
|
||||
case 'b':
|
||||
case 'p':
|
||||
case 'P':
|
||||
case 'G':
|
||||
case 'g':
|
||||
// Try to find a SPARQL-style keyword
|
||||
if (match = this._sparqlKeyword.exec(input))
|
||||
type = match[0].toUpperCase();
|
||||
else
|
||||
inconclusive = true;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
case 't':
|
||||
// Try to match a boolean
|
||||
if (match = this._boolean.exec(input))
|
||||
type = 'literal', value = match[0], prefix = xsd.boolean;
|
||||
else
|
||||
inconclusive = true;
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
// Try to find an abbreviated predicate
|
||||
if (match = this._shortPredicates.exec(input))
|
||||
type = 'abbreviation', value = 'a';
|
||||
else
|
||||
inconclusive = true;
|
||||
break;
|
||||
|
||||
case '=':
|
||||
// Try to find an implication arrow or equals sign
|
||||
if (this._n3Mode && input.length > 1) {
|
||||
type = 'abbreviation';
|
||||
if (input[1] !== '>')
|
||||
matchLength = 1, value = '=';
|
||||
else
|
||||
matchLength = 2, value = '>';
|
||||
}
|
||||
break;
|
||||
|
||||
case '!':
|
||||
if (!this._n3Mode)
|
||||
break;
|
||||
case ',':
|
||||
case ';':
|
||||
case '[':
|
||||
case ']':
|
||||
case '(':
|
||||
case ')':
|
||||
case '}':
|
||||
if (!this._lineMode) {
|
||||
matchLength = 1;
|
||||
type = firstChar;
|
||||
}
|
||||
break;
|
||||
case '{':
|
||||
// We need at least 2 tokens lookahead to distinguish "{|" and "{ "
|
||||
if (!this._lineMode && input.length >= 2) {
|
||||
// Try to find a quoted triple annotation start
|
||||
if (input[1] === '|')
|
||||
type = '{|', matchLength = 2;
|
||||
else
|
||||
type = firstChar, matchLength = 1;
|
||||
}
|
||||
break;
|
||||
case '|':
|
||||
// We need 2 tokens lookahead to parse "|}"
|
||||
// Try to find a quoted triple annotation end
|
||||
if (input.length >= 2 && input[1] === '}')
|
||||
type = '|}', matchLength = 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
inconclusive = true;
|
||||
}
|
||||
|
||||
// Some first characters do not allow an immediate decision, so inspect more
|
||||
if (inconclusive) {
|
||||
// Try to find a prefix
|
||||
if ((this._previousMarker === '@prefix' || this._previousMarker === 'PREFIX') &&
|
||||
(match = this._prefix.exec(input)))
|
||||
type = 'prefix', value = match[1] || '';
|
||||
// Try to find a prefixed name. Since it can contain (but not end with) a dot,
|
||||
// we always need a non-dot character before deciding it is a prefixed name.
|
||||
// Therefore, try inserting a space if we're at the end of the input.
|
||||
else if ((match = this._prefixed.exec(input)) ||
|
||||
inputFinished && (match = this._prefixed.exec(`${input} `)))
|
||||
type = 'prefixed', prefix = match[1] || '', value = this._unescape(match[2]);
|
||||
}
|
||||
|
||||
// A type token is special: it can only be emitted after an IRI or prefixed name is read
|
||||
if (this._previousMarker === '^^') {
|
||||
switch (type) {
|
||||
case 'prefixed': type = 'type'; break;
|
||||
case 'IRI': type = 'typeIRI'; break;
|
||||
default: type = '';
|
||||
}
|
||||
}
|
||||
|
||||
// What if nothing of the above was found?
|
||||
if (!type) {
|
||||
// We could be in streaming mode, and then we just wait for more input to arrive.
|
||||
// Otherwise, a syntax error has occurred in the input.
|
||||
// One exception: error on an unaccounted linebreak (= not inside a triple-quoted literal).
|
||||
if (inputFinished || (!/^'''|^"""/.test(input) && /\n|\r/.test(input)))
|
||||
return reportSyntaxError(this);
|
||||
else
|
||||
return this._input = input;
|
||||
}
|
||||
|
||||
// Emit the parsed token
|
||||
const length = matchLength || match[0].length;
|
||||
const token = emitToken(type, value, prefix, line, length);
|
||||
this.previousToken = token;
|
||||
this._previousMarker = type;
|
||||
|
||||
// Advance to next part to tokenize
|
||||
input = input.substr(length, input.length);
|
||||
}
|
||||
|
||||
// Emits the token through the callback
|
||||
function emitToken(type, value, prefix, line, length) {
|
||||
const start = input ? currentLineLength - input.length : currentLineLength;
|
||||
const end = start + length;
|
||||
const token = { type, value, prefix, line, start, end };
|
||||
callback(null, token);
|
||||
return token;
|
||||
}
|
||||
// Signals the syntax error through the callback
|
||||
function reportSyntaxError(self) { callback(self._syntaxError(/^\S*/.exec(input)[0])); }
|
||||
}
|
||||
|
||||
// ### `_unescape` replaces N3 escape codes by their corresponding characters
|
||||
_unescape(item) {
|
||||
let invalid = false;
|
||||
const replaced = item.replace(escapeSequence, (sequence, unicode4, unicode8, escapedChar) => {
|
||||
// 4-digit unicode character
|
||||
if (typeof unicode4 === 'string')
|
||||
return String.fromCharCode(Number.parseInt(unicode4, 16));
|
||||
// 8-digit unicode character
|
||||
if (typeof unicode8 === 'string') {
|
||||
let charCode = Number.parseInt(unicode8, 16);
|
||||
return charCode <= 0xFFFF ? String.fromCharCode(Number.parseInt(unicode8, 16)) :
|
||||
String.fromCharCode(0xD800 + ((charCode -= 0x10000) >> 10), 0xDC00 + (charCode & 0x3FF));
|
||||
}
|
||||
// fixed escape sequence
|
||||
if (escapedChar in escapeReplacements)
|
||||
return escapeReplacements[escapedChar];
|
||||
// invalid escape sequence
|
||||
invalid = true;
|
||||
return '';
|
||||
});
|
||||
return invalid ? null : replaced;
|
||||
}
|
||||
|
||||
// ### `_parseLiteral` parses a literal into an unescaped value
|
||||
_parseLiteral(input) {
|
||||
// Ensure we have enough lookahead to identify triple-quoted strings
|
||||
if (input.length >= 3) {
|
||||
// Identify the opening quote(s)
|
||||
const opening = input.match(/^(?:"""|"|'''|'|)/)[0];
|
||||
const openingLength = opening.length;
|
||||
|
||||
// Find the next candidate closing quotes
|
||||
let closingPos = Math.max(this._literalClosingPos, openingLength);
|
||||
while ((closingPos = input.indexOf(opening, closingPos)) > 0) {
|
||||
// Count backslashes right before the closing quotes
|
||||
let backslashCount = 0;
|
||||
while (input[closingPos - backslashCount - 1] === '\\')
|
||||
backslashCount++;
|
||||
|
||||
// An even number of backslashes (in particular 0)
|
||||
// means these are actual, non-escaped closing quotes
|
||||
if (backslashCount % 2 === 0) {
|
||||
// Extract and unescape the value
|
||||
const raw = input.substring(openingLength, closingPos);
|
||||
const lines = raw.split(/\r\n|\r|\n/).length - 1;
|
||||
const matchLength = closingPos + openingLength;
|
||||
// Only triple-quoted strings can be multi-line
|
||||
if (openingLength === 1 && lines !== 0 ||
|
||||
openingLength === 3 && this._lineMode)
|
||||
break;
|
||||
this._line += lines;
|
||||
return { value: this._unescape(raw), matchLength };
|
||||
}
|
||||
closingPos++;
|
||||
}
|
||||
this._literalClosingPos = input.length - openingLength + 1;
|
||||
}
|
||||
return { value: '', matchLength: 0 };
|
||||
}
|
||||
|
||||
// ### `_syntaxError` creates a syntax error for the given issue
|
||||
_syntaxError(issue) {
|
||||
this._input = null;
|
||||
const err = new Error(`Unexpected "${issue}" on line ${this._line}.`);
|
||||
err.context = {
|
||||
token: undefined,
|
||||
line: this._line,
|
||||
previousToken: this.previousToken,
|
||||
};
|
||||
return err;
|
||||
}
|
||||
|
||||
// ### Strips off any starting UTF BOM mark.
|
||||
_readStartingBom(input) {
|
||||
return input.startsWith('\ufeff') ? input.substr(1) : input;
|
||||
}
|
||||
|
||||
// ## Public methods
|
||||
|
||||
// ### `tokenize` starts the transformation of an N3 document into an array of tokens.
|
||||
// The input can be a string or a stream.
|
||||
tokenize(input, callback) {
|
||||
this._line = 1;
|
||||
|
||||
// If the input is a string, continuously emit tokens through the callback until the end
|
||||
if (typeof input === 'string') {
|
||||
this._input = this._readStartingBom(input);
|
||||
// If a callback was passed, asynchronously call it
|
||||
if (typeof callback === 'function')
|
||||
queueMicrotask(() => this._tokenizeToEnd(callback, true));
|
||||
// If no callback was passed, tokenize synchronously and return
|
||||
else {
|
||||
const tokens = [];
|
||||
let error;
|
||||
this._tokenizeToEnd((e, t) => e ? (error = e) : tokens.push(t), true);
|
||||
if (error) throw error;
|
||||
return tokens;
|
||||
}
|
||||
}
|
||||
// Otherwise, the input must be a stream
|
||||
else {
|
||||
this._pendingBuffer = null;
|
||||
if (typeof input.setEncoding === 'function')
|
||||
input.setEncoding('utf8');
|
||||
// Adds the data chunk to the buffer and parses as far as possible
|
||||
input.on('data', data => {
|
||||
if (this._input !== null && data.length !== 0) {
|
||||
// Prepend any previous pending writes
|
||||
if (this._pendingBuffer) {
|
||||
data = Buffer.concat([this._pendingBuffer, data]);
|
||||
this._pendingBuffer = null;
|
||||
}
|
||||
// Hold if the buffer ends in an incomplete unicode sequence
|
||||
if (data[data.length - 1] & 0x80) {
|
||||
this._pendingBuffer = data;
|
||||
}
|
||||
// Otherwise, tokenize as far as possible
|
||||
else {
|
||||
// Only read a BOM at the start
|
||||
if (typeof this._input === 'undefined')
|
||||
this._input = this._readStartingBom(typeof data === 'string' ? data : data.toString());
|
||||
else
|
||||
this._input += data;
|
||||
this._tokenizeToEnd(callback, false);
|
||||
}
|
||||
}
|
||||
});
|
||||
// Parses until the end
|
||||
input.on('end', () => {
|
||||
if (typeof this._input === 'string')
|
||||
this._tokenizeToEnd(callback, true);
|
||||
});
|
||||
input.on('error', callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
1105
node_modules/n3/src/N3Parser.js
generated
vendored
Normal file
1105
node_modules/n3/src/N3Parser.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
206
node_modules/n3/src/N3Reasoner.js
generated
vendored
Normal file
206
node_modules/n3/src/N3Reasoner.js
generated
vendored
Normal file
@@ -0,0 +1,206 @@
|
||||
import DF from './N3DataFactory';
|
||||
|
||||
/**
|
||||
* Gets rules from a dataset. This will only collect horn rules declared using log:implies.
|
||||
*/
|
||||
export function getRulesFromDataset(dataset) {
|
||||
const rules = [];
|
||||
for (const { subject, object } of dataset.match(null, DF.namedNode('http://www.w3.org/2000/10/swap/log#implies'), null, DF.defaultGraph())) {
|
||||
const premise = [...dataset.match(null, null, null, subject)];
|
||||
const conclusion = [...dataset.match(null, null, null, object)];
|
||||
rules.push({ premise, conclusion });
|
||||
}
|
||||
return rules;
|
||||
}
|
||||
|
||||
export default class N3Reasoner {
|
||||
constructor(store) {
|
||||
this._store = store;
|
||||
}
|
||||
|
||||
_add(subject, predicate, object, graphItem, cb) {
|
||||
// Only add to the remaining indexes if there is not already a value in the index
|
||||
if (!this._store._addToIndex(graphItem.subjects, subject, predicate, object)) return;
|
||||
this._store._addToIndex(graphItem.predicates, predicate, object, subject);
|
||||
this._store._addToIndex(graphItem.objects, object, subject, predicate);
|
||||
cb();
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-warning-comments
|
||||
_evaluatePremise(rule, content, cb, i = 0) {
|
||||
let v1, v2, value, index1, index2;
|
||||
const [val0, val1, val2] = rule.premise[i].value, index = content[rule.premise[i].content];
|
||||
const v0 = !(value = val0.value);
|
||||
for (value in v0 ? index : { [value]: index[value] }) {
|
||||
if (index1 = index[value]) {
|
||||
if (v0) val0.value = Number(value);
|
||||
v1 = !(value = val1.value);
|
||||
for (value in v1 ? index1 : { [value]: index1[value] }) {
|
||||
if (index2 = index1[value]) {
|
||||
if (v1) val1.value = Number(value);
|
||||
v2 = !(value = val2.value);
|
||||
for (value in v2 ? index2 : { [value]: index2[value] }) {
|
||||
if (v2) val2.value = Number(value);
|
||||
|
||||
if (i === rule.premise.length - 1)
|
||||
rule.conclusion.forEach(c => {
|
||||
// eslint-disable-next-line max-nested-callbacks
|
||||
this._add(c.subject.value, c.predicate.value, c.object.value, content, () => { cb(c); });
|
||||
});
|
||||
else
|
||||
this._evaluatePremise(rule, content, cb, i + 1);
|
||||
}
|
||||
if (v2) val2.value = null;
|
||||
}
|
||||
}
|
||||
if (v1) val1.value = null;
|
||||
}
|
||||
}
|
||||
if (v0) val0.value = null;
|
||||
}
|
||||
|
||||
_evaluateRules(rules, content, cb) {
|
||||
for (let i = 0; i < rules.length; i++) {
|
||||
this._evaluatePremise(rules[i], content, cb);
|
||||
}
|
||||
}
|
||||
|
||||
// A naive reasoning algorithm where rules are just applied by repeatedly applying rules
|
||||
// until no more evaluations are made
|
||||
_reasonGraphNaive(rules, content) {
|
||||
const newRules = [];
|
||||
|
||||
function addRule(conclusion) {
|
||||
if (conclusion.next)
|
||||
conclusion.next.forEach(rule => {
|
||||
newRules.push([conclusion.subject.value, conclusion.predicate.value, conclusion.object.value, rule]);
|
||||
});
|
||||
}
|
||||
|
||||
// eslint-disable-next-line func-style
|
||||
const addConclusions = conclusion => {
|
||||
conclusion.forEach(c => {
|
||||
// eslint-disable-next-line max-nested-callbacks
|
||||
this._add(c.subject.value, c.predicate.value, c.object.value, content, () => { addRule(c); });
|
||||
});
|
||||
};
|
||||
|
||||
this._evaluateRules(rules, content, addRule);
|
||||
|
||||
let r;
|
||||
while ((r = newRules.pop()) !== undefined) {
|
||||
const [subject, predicate, object, rule] = r;
|
||||
const v1 = rule.basePremise.subject.value;
|
||||
if (!v1) rule.basePremise.subject.value = subject;
|
||||
const v2 = rule.basePremise.predicate.value;
|
||||
if (!v2) rule.basePremise.predicate.value = predicate;
|
||||
const v3 = rule.basePremise.object.value;
|
||||
if (!v3) rule.basePremise.object.value = object;
|
||||
|
||||
if (rule.premise.length === 0) {
|
||||
addConclusions(rule.conclusion);
|
||||
}
|
||||
else {
|
||||
this._evaluatePremise(rule, content, addRule);
|
||||
}
|
||||
|
||||
if (!v1) rule.basePremise.subject.value = null;
|
||||
if (!v2) rule.basePremise.predicate.value = null;
|
||||
if (!v3) rule.basePremise.object.value = null;
|
||||
}
|
||||
}
|
||||
|
||||
_createRule({ premise, conclusion }) {
|
||||
const varMapping = {};
|
||||
|
||||
const toId = value => value.termType === 'Variable' ?
|
||||
// If the term is a variable, then create an empty object that values can be placed into
|
||||
(varMapping[value.value] = varMapping[value.value] || {}) :
|
||||
// If the term is not a variable, then set the ID value
|
||||
{ value: this._store._termToNewNumericId(value) };
|
||||
|
||||
// eslint-disable-next-line func-style
|
||||
const t = term => ({ subject: toId(term.subject), predicate: toId(term.predicate), object: toId(term.object) });
|
||||
|
||||
return {
|
||||
premise: premise.map(p => t(p)),
|
||||
conclusion: conclusion.map(p => t(p)),
|
||||
variables: Object.values(varMapping),
|
||||
};
|
||||
}
|
||||
|
||||
reason(rules) {
|
||||
if (!Array.isArray(rules)) {
|
||||
rules = getRulesFromDataset(rules);
|
||||
}
|
||||
rules = rules.map(rule => this._createRule(rule));
|
||||
|
||||
for (const r1 of rules) {
|
||||
for (const r2 of rules) {
|
||||
for (let i = 0; i < r2.premise.length; i++) {
|
||||
const p = r2.premise[i];
|
||||
for (const c of r1.conclusion) {
|
||||
if (termEq(p.subject, c.subject) && termEq(p.predicate, c.predicate) && termEq(p.object, c.object)) {
|
||||
const set = new Set();
|
||||
|
||||
const premise = [];
|
||||
|
||||
// Since these *will* be substituted when we apply the rule,
|
||||
// we need to do this, so that we index correctly in the subsequent section
|
||||
p.subject.value = p.subject.value || 1;
|
||||
p.object.value = p.object.value || 1;
|
||||
p.predicate.value = p.predicate.value || 1;
|
||||
|
||||
for (let j = 0; j < r2.premise.length; j++) {
|
||||
if (j !== i) {
|
||||
premise.push(getIndex(r2.premise[j], set));
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-warning-comments
|
||||
// TODO: Create new rule, with new indexing
|
||||
// Future, 'collapse' the next statements when they share a premise/base-premise
|
||||
(c.next = c.next || []).push({
|
||||
premise,
|
||||
conclusion: r2.conclusion,
|
||||
// This is a single premise of the form { subject, predicate, object },
|
||||
// which we can use to instantiate the rule using the new data that was emitted
|
||||
basePremise: p,
|
||||
});
|
||||
}
|
||||
r2.variables.forEach(v => { v.value = null; });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const rule of rules) {
|
||||
const set = new Set();
|
||||
rule.premise = rule.premise.map(p => getIndex(p, set));
|
||||
}
|
||||
|
||||
const graphs = this._store._getGraphs();
|
||||
for (const graphId in graphs) {
|
||||
this._reasonGraphNaive(rules, graphs[graphId]);
|
||||
}
|
||||
|
||||
this._store._size = null;
|
||||
}
|
||||
}
|
||||
|
||||
function getIndex({ subject, predicate, object }, set) {
|
||||
const s = subject.value || set.has(subject) || (set.add(subject), false);
|
||||
const p = predicate.value || set.has(predicate) || (set.add(predicate), false);
|
||||
const o = object.value || set.has(object) || (set.add(object), false);
|
||||
|
||||
return (!s && p) ? { content: 'predicates', value: [predicate, object, subject] } :
|
||||
o ? { content: 'objects', value: [object, subject, predicate] } :
|
||||
{ content: 'subjects', value: [subject, predicate, object] };
|
||||
}
|
||||
|
||||
function termEq(t1, t2) {
|
||||
if (t1.value === null) {
|
||||
t1.value = t2.value;
|
||||
}
|
||||
return t1.value === t2.value;
|
||||
}
|
||||
1278
node_modules/n3/src/N3Store.js
generated
vendored
Normal file
1278
node_modules/n3/src/N3Store.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
7
node_modules/n3/src/N3StoreFactory.js
generated
vendored
Normal file
7
node_modules/n3/src/N3StoreFactory.js
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
import N3Store from './N3Store';
|
||||
|
||||
export default class N3DatasetCoreFactory {
|
||||
dataset(quads) {
|
||||
return new N3Store(quads);
|
||||
}
|
||||
}
|
||||
46
node_modules/n3/src/N3StreamParser.js
generated
vendored
Normal file
46
node_modules/n3/src/N3StreamParser.js
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
// **N3StreamParser** parses a text stream into a quad stream.
|
||||
import { Transform } from 'readable-stream';
|
||||
import N3Parser from './N3Parser';
|
||||
|
||||
// ## Constructor
|
||||
export default class N3StreamParser extends Transform {
|
||||
constructor(options) {
|
||||
super({ decodeStrings: true });
|
||||
this._readableState.objectMode = true;
|
||||
|
||||
// Set up parser with dummy stream to obtain `data` and `end` callbacks
|
||||
const parser = new N3Parser(options);
|
||||
let onData, onEnd;
|
||||
|
||||
const callbacks = {
|
||||
// Handle quads by pushing them down the pipeline
|
||||
onQuad: (error, quad) => { error && this.emit('error', error) || quad && this.push(quad); },
|
||||
// Emit prefixes through the `prefix` event
|
||||
onPrefix: (prefix, uri) => { this.emit('prefix', prefix, uri); },
|
||||
};
|
||||
|
||||
if (options && options.comments)
|
||||
callbacks.onComment = comment => { this.emit('comment', comment); };
|
||||
|
||||
parser.parse({
|
||||
on: (event, callback) => {
|
||||
switch (event) {
|
||||
case 'data': onData = callback; break;
|
||||
case 'end': onEnd = callback; break;
|
||||
}
|
||||
},
|
||||
}, callbacks);
|
||||
|
||||
// Implement Transform methods through parser callbacks
|
||||
this._transform = (chunk, encoding, done) => { onData(chunk); done(); };
|
||||
this._flush = done => { onEnd(); done(); };
|
||||
}
|
||||
|
||||
// ### Parses a stream of strings
|
||||
import(stream) {
|
||||
stream.on('data', chunk => { this.write(chunk); });
|
||||
stream.on('end', () => { this.end(); });
|
||||
stream.on('error', error => { this.emit('error', error); });
|
||||
return this;
|
||||
}
|
||||
}
|
||||
29
node_modules/n3/src/N3StreamWriter.js
generated
vendored
Normal file
29
node_modules/n3/src/N3StreamWriter.js
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
// **N3StreamWriter** serializes a quad stream into a text stream.
|
||||
import { Transform } from 'readable-stream';
|
||||
import N3Writer from './N3Writer';
|
||||
|
||||
// ## Constructor
|
||||
export default class N3StreamWriter extends Transform {
|
||||
constructor(options) {
|
||||
super({ encoding: 'utf8', writableObjectMode: true });
|
||||
|
||||
// Set up writer with a dummy stream object
|
||||
const writer = this._writer = new N3Writer({
|
||||
write: (quad, encoding, callback) => { this.push(quad); callback && callback(); },
|
||||
end: callback => { this.push(null); callback && callback(); },
|
||||
}, options);
|
||||
|
||||
// Implement Transform methods on top of writer
|
||||
this._transform = (quad, encoding, done) => { writer.addQuad(quad, done); };
|
||||
this._flush = done => { writer.end(done); };
|
||||
}
|
||||
|
||||
// ### Serializes a stream of quads
|
||||
import(stream) {
|
||||
stream.on('data', quad => { this.write(quad); });
|
||||
stream.on('end', () => { this.end(); });
|
||||
stream.on('error', error => { this.emit('error', error); });
|
||||
stream.on('prefix', (prefix, iri) => { this._writer.addPrefix(prefix, iri); });
|
||||
return this;
|
||||
}
|
||||
}
|
||||
71
node_modules/n3/src/N3Util.js
generated
vendored
Normal file
71
node_modules/n3/src/N3Util.js
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
// **N3Util** provides N3 utility functions.
|
||||
|
||||
import N3DataFactory from './N3DataFactory';
|
||||
|
||||
// Tests whether the given term represents an IRI
|
||||
export function isNamedNode(term) {
|
||||
return !!term && term.termType === 'NamedNode';
|
||||
}
|
||||
|
||||
// Tests whether the given term represents a blank node
|
||||
export function isBlankNode(term) {
|
||||
return !!term && term.termType === 'BlankNode';
|
||||
}
|
||||
|
||||
// Tests whether the given term represents a literal
|
||||
export function isLiteral(term) {
|
||||
return !!term && term.termType === 'Literal';
|
||||
}
|
||||
|
||||
// Tests whether the given term represents a variable
|
||||
export function isVariable(term) {
|
||||
return !!term && term.termType === 'Variable';
|
||||
}
|
||||
|
||||
// Tests whether the given term represents a quad
|
||||
export function isQuad(term) {
|
||||
return !!term && term.termType === 'Quad';
|
||||
}
|
||||
|
||||
// Tests whether the given term represents the default graph
|
||||
export function isDefaultGraph(term) {
|
||||
return !!term && term.termType === 'DefaultGraph';
|
||||
}
|
||||
|
||||
// Tests whether the given quad is in the default graph
|
||||
export function inDefaultGraph(quad) {
|
||||
return isDefaultGraph(quad.graph);
|
||||
}
|
||||
|
||||
// Creates a function that prepends the given IRI to a local name
|
||||
export function prefix(iri, factory) {
|
||||
return prefixes({ '': iri.value || iri }, factory)('');
|
||||
}
|
||||
|
||||
// Creates a function that allows registering and expanding prefixes
|
||||
export function prefixes(defaultPrefixes, factory) {
|
||||
// Add all of the default prefixes
|
||||
const prefixes = Object.create(null);
|
||||
for (const prefix in defaultPrefixes)
|
||||
processPrefix(prefix, defaultPrefixes[prefix]);
|
||||
// Set the default factory if none was specified
|
||||
factory = factory || N3DataFactory;
|
||||
|
||||
// Registers a new prefix (if an IRI was specified)
|
||||
// or retrieves a function that expands an existing prefix (if no IRI was specified)
|
||||
function processPrefix(prefix, iri) {
|
||||
// Create a new prefix if an IRI is specified or the prefix doesn't exist
|
||||
if (typeof iri === 'string') {
|
||||
// Create a function that expands the prefix
|
||||
const cache = Object.create(null);
|
||||
prefixes[prefix] = local => {
|
||||
return cache[local] || (cache[local] = factory.namedNode(iri + local));
|
||||
};
|
||||
}
|
||||
else if (!(prefix in prefixes)) {
|
||||
throw new Error(`Unknown prefix: ${prefix}`);
|
||||
}
|
||||
return prefixes[prefix];
|
||||
}
|
||||
return processPrefix;
|
||||
}
|
||||
397
node_modules/n3/src/N3Writer.js
generated
vendored
Normal file
397
node_modules/n3/src/N3Writer.js
generated
vendored
Normal file
@@ -0,0 +1,397 @@
|
||||
// **N3Writer** writes N3 documents.
|
||||
import namespaces from './IRIs';
|
||||
import { default as N3DataFactory, Term } from './N3DataFactory';
|
||||
import { isDefaultGraph } from './N3Util';
|
||||
import BaseIRI from './BaseIRI';
|
||||
import { escapeRegex } from './Util';
|
||||
|
||||
const DEFAULTGRAPH = N3DataFactory.defaultGraph();
|
||||
|
||||
const { rdf, xsd } = namespaces;
|
||||
|
||||
// Characters in literals that require escaping
|
||||
const escape = /["\\\t\n\r\b\f\u0000-\u0019\ud800-\udbff]/,
|
||||
escapeAll = /["\\\t\n\r\b\f\u0000-\u0019]|[\ud800-\udbff][\udc00-\udfff]/g,
|
||||
escapedCharacters = {
|
||||
'\\': '\\\\', '"': '\\"', '\t': '\\t',
|
||||
'\n': '\\n', '\r': '\\r', '\b': '\\b', '\f': '\\f',
|
||||
};
|
||||
|
||||
// ## Placeholder class to represent already pretty-printed terms
|
||||
class SerializedTerm extends Term {
|
||||
// Pretty-printed nodes are not equal to any other node
|
||||
// (e.g., [] does not equal [])
|
||||
equals(other) {
|
||||
return other === this;
|
||||
}
|
||||
}
|
||||
|
||||
// ## Constructor
|
||||
export default class N3Writer {
|
||||
constructor(outputStream, options) {
|
||||
// ### `_prefixRegex` matches a prefixed name or IRI that begins with one of the added prefixes
|
||||
this._prefixRegex = /$0^/;
|
||||
|
||||
// Shift arguments if the first argument is not a stream
|
||||
if (outputStream && typeof outputStream.write !== 'function')
|
||||
options = outputStream, outputStream = null;
|
||||
options = options || {};
|
||||
this._lists = options.lists;
|
||||
|
||||
// If no output stream given, send the output as string through the end callback
|
||||
if (!outputStream) {
|
||||
let output = '';
|
||||
this._outputStream = {
|
||||
write(chunk, encoding, done) { output += chunk; done && done(); },
|
||||
end: done => { done && done(null, output); },
|
||||
};
|
||||
this._endStream = true;
|
||||
}
|
||||
else {
|
||||
this._outputStream = outputStream;
|
||||
this._endStream = options.end === undefined ? true : !!options.end;
|
||||
}
|
||||
|
||||
// Initialize writer, depending on the format
|
||||
this._subject = null;
|
||||
if (!(/triple|quad/i).test(options.format)) {
|
||||
this._lineMode = false;
|
||||
this._graph = DEFAULTGRAPH;
|
||||
this._prefixIRIs = Object.create(null);
|
||||
options.prefixes && this.addPrefixes(options.prefixes);
|
||||
if (options.baseIRI) {
|
||||
this._baseIri = new BaseIRI(options.baseIRI);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this._lineMode = true;
|
||||
this._writeQuad = this._writeQuadLine;
|
||||
}
|
||||
}
|
||||
|
||||
// ## Private methods
|
||||
|
||||
// ### Whether the current graph is the default graph
|
||||
get _inDefaultGraph() {
|
||||
return DEFAULTGRAPH.equals(this._graph);
|
||||
}
|
||||
|
||||
// ### `_write` writes the argument to the output stream
|
||||
_write(string, callback) {
|
||||
this._outputStream.write(string, 'utf8', callback);
|
||||
}
|
||||
|
||||
// ### `_writeQuad` writes the quad to the output stream
|
||||
_writeQuad(subject, predicate, object, graph, done) {
|
||||
try {
|
||||
// Write the graph's label if it has changed
|
||||
if (!graph.equals(this._graph)) {
|
||||
// Close the previous graph and start the new one
|
||||
this._write((this._subject === null ? '' : (this._inDefaultGraph ? '.\n' : '\n}\n')) +
|
||||
(DEFAULTGRAPH.equals(graph) ? '' : `${this._encodeIriOrBlank(graph)} {\n`));
|
||||
this._graph = graph;
|
||||
this._subject = null;
|
||||
}
|
||||
// Don't repeat the subject if it's the same
|
||||
if (subject.equals(this._subject)) {
|
||||
// Don't repeat the predicate if it's the same
|
||||
if (predicate.equals(this._predicate))
|
||||
this._write(`, ${this._encodeObject(object)}`, done);
|
||||
// Same subject, different predicate
|
||||
else
|
||||
this._write(`;\n ${
|
||||
this._encodePredicate(this._predicate = predicate)} ${
|
||||
this._encodeObject(object)}`, done);
|
||||
}
|
||||
// Different subject; write the whole quad
|
||||
else
|
||||
this._write(`${(this._subject === null ? '' : '.\n') +
|
||||
this._encodeSubject(this._subject = subject)} ${
|
||||
this._encodePredicate(this._predicate = predicate)} ${
|
||||
this._encodeObject(object)}`, done);
|
||||
}
|
||||
catch (error) { done && done(error); }
|
||||
}
|
||||
|
||||
// ### `_writeQuadLine` writes the quad to the output stream as a single line
|
||||
_writeQuadLine(subject, predicate, object, graph, done) {
|
||||
// Write the quad without prefixes
|
||||
delete this._prefixMatch;
|
||||
this._write(this.quadToString(subject, predicate, object, graph), done);
|
||||
}
|
||||
|
||||
// ### `quadToString` serializes a quad as a string
|
||||
quadToString(subject, predicate, object, graph) {
|
||||
return `${this._encodeSubject(subject)} ${
|
||||
this._encodeIriOrBlank(predicate)} ${
|
||||
this._encodeObject(object)
|
||||
}${graph && graph.value ? ` ${this._encodeIriOrBlank(graph)} .\n` : ' .\n'}`;
|
||||
}
|
||||
|
||||
// ### `quadsToString` serializes an array of quads as a string
|
||||
quadsToString(quads) {
|
||||
let quadsString = '';
|
||||
for (const quad of quads)
|
||||
quadsString += this.quadToString(quad.subject, quad.predicate, quad.object, quad.graph);
|
||||
return quadsString;
|
||||
}
|
||||
|
||||
// ### `_encodeSubject` represents a subject
|
||||
_encodeSubject(entity) {
|
||||
return entity.termType === 'Quad' ?
|
||||
this._encodeQuad(entity) : this._encodeIriOrBlank(entity);
|
||||
}
|
||||
|
||||
// ### `_encodeIriOrBlank` represents an IRI or blank node
|
||||
_encodeIriOrBlank(entity) {
|
||||
// A blank node or list is represented as-is
|
||||
if (entity.termType !== 'NamedNode') {
|
||||
// If it is a list head, pretty-print it
|
||||
if (this._lists && (entity.value in this._lists))
|
||||
entity = this.list(this._lists[entity.value]);
|
||||
return 'id' in entity ? entity.id : `_:${entity.value}`;
|
||||
}
|
||||
let iri = entity.value;
|
||||
// Use relative IRIs if requested and possible
|
||||
if (this._baseIri) {
|
||||
iri = this._baseIri.toRelative(iri);
|
||||
}
|
||||
// Escape special characters
|
||||
if (escape.test(iri))
|
||||
iri = iri.replace(escapeAll, characterReplacer);
|
||||
// Try to represent the IRI as prefixed name
|
||||
const prefixMatch = this._prefixRegex.exec(iri);
|
||||
return !prefixMatch ? `<${iri}>` :
|
||||
(!prefixMatch[1] ? iri : this._prefixIRIs[prefixMatch[1]] + prefixMatch[2]);
|
||||
}
|
||||
|
||||
// ### `_encodeLiteral` represents a literal
|
||||
_encodeLiteral(literal) {
|
||||
// Escape special characters
|
||||
let value = literal.value;
|
||||
if (escape.test(value))
|
||||
value = value.replace(escapeAll, characterReplacer);
|
||||
|
||||
// Write a language-tagged literal
|
||||
if (literal.language)
|
||||
return `"${value}"@${literal.language}`;
|
||||
|
||||
// Write dedicated literals per data type
|
||||
if (this._lineMode) {
|
||||
// Only abbreviate strings in N-Triples or N-Quads
|
||||
if (literal.datatype.value === xsd.string)
|
||||
return `"${value}"`;
|
||||
}
|
||||
else {
|
||||
// Use common datatype abbreviations in Turtle or TriG
|
||||
switch (literal.datatype.value) {
|
||||
case xsd.string:
|
||||
return `"${value}"`;
|
||||
case xsd.boolean:
|
||||
if (value === 'true' || value === 'false')
|
||||
return value;
|
||||
break;
|
||||
case xsd.integer:
|
||||
if (/^[+-]?\d+$/.test(value))
|
||||
return value;
|
||||
break;
|
||||
case xsd.decimal:
|
||||
if (/^[+-]?\d*\.\d+$/.test(value))
|
||||
return value;
|
||||
break;
|
||||
case xsd.double:
|
||||
if (/^[+-]?(?:\d+\.\d*|\.?\d+)[eE][+-]?\d+$/.test(value))
|
||||
return value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Write a regular datatyped literal
|
||||
return `"${value}"^^${this._encodeIriOrBlank(literal.datatype)}`;
|
||||
}
|
||||
|
||||
// ### `_encodePredicate` represents a predicate
|
||||
_encodePredicate(predicate) {
|
||||
return predicate.value === rdf.type ? 'a' : this._encodeIriOrBlank(predicate);
|
||||
}
|
||||
|
||||
// ### `_encodeObject` represents an object
|
||||
_encodeObject(object) {
|
||||
switch (object.termType) {
|
||||
case 'Quad':
|
||||
return this._encodeQuad(object);
|
||||
case 'Literal':
|
||||
return this._encodeLiteral(object);
|
||||
default:
|
||||
return this._encodeIriOrBlank(object);
|
||||
}
|
||||
}
|
||||
|
||||
// ### `_encodeQuad` encodes an RDF-star quad
|
||||
_encodeQuad({ subject, predicate, object, graph }) {
|
||||
return `<<${
|
||||
this._encodeSubject(subject)} ${
|
||||
this._encodePredicate(predicate)} ${
|
||||
this._encodeObject(object)}${
|
||||
isDefaultGraph(graph) ? '' : ` ${this._encodeIriOrBlank(graph)}`}>>`;
|
||||
}
|
||||
|
||||
// ### `_blockedWrite` replaces `_write` after the writer has been closed
|
||||
_blockedWrite() {
|
||||
throw new Error('Cannot write because the writer has been closed.');
|
||||
}
|
||||
|
||||
// ### `addQuad` adds the quad to the output stream
|
||||
addQuad(subject, predicate, object, graph, done) {
|
||||
// The quad was given as an object, so shift parameters
|
||||
if (object === undefined)
|
||||
this._writeQuad(subject.subject, subject.predicate, subject.object, subject.graph, predicate);
|
||||
// The optional `graph` parameter was not provided
|
||||
else if (typeof graph === 'function')
|
||||
this._writeQuad(subject, predicate, object, DEFAULTGRAPH, graph);
|
||||
// The `graph` parameter was provided
|
||||
else
|
||||
this._writeQuad(subject, predicate, object, graph || DEFAULTGRAPH, done);
|
||||
}
|
||||
|
||||
// ### `addQuads` adds the quads to the output stream
|
||||
addQuads(quads) {
|
||||
for (let i = 0; i < quads.length; i++)
|
||||
this.addQuad(quads[i]);
|
||||
}
|
||||
|
||||
// ### `addPrefix` adds the prefix to the output stream
|
||||
addPrefix(prefix, iri, done) {
|
||||
const prefixes = {};
|
||||
prefixes[prefix] = iri;
|
||||
this.addPrefixes(prefixes, done);
|
||||
}
|
||||
|
||||
// ### `addPrefixes` adds the prefixes to the output stream
|
||||
addPrefixes(prefixes, done) {
|
||||
// Ignore prefixes if not supported by the serialization
|
||||
if (!this._prefixIRIs)
|
||||
return done && done();
|
||||
|
||||
// Write all new prefixes
|
||||
let hasPrefixes = false;
|
||||
for (let prefix in prefixes) {
|
||||
let iri = prefixes[prefix];
|
||||
if (typeof iri !== 'string')
|
||||
iri = iri.value;
|
||||
hasPrefixes = true;
|
||||
// Finish a possible pending quad
|
||||
if (this._subject !== null) {
|
||||
this._write(this._inDefaultGraph ? '.\n' : '\n}\n');
|
||||
this._subject = null, this._graph = '';
|
||||
}
|
||||
// Store and write the prefix
|
||||
this._prefixIRIs[iri] = (prefix += ':');
|
||||
this._write(`@prefix ${prefix} <${iri}>.\n`);
|
||||
}
|
||||
// Recreate the prefix matcher
|
||||
if (hasPrefixes) {
|
||||
let IRIlist = '', prefixList = '';
|
||||
for (const prefixIRI in this._prefixIRIs) {
|
||||
IRIlist += IRIlist ? `|${prefixIRI}` : prefixIRI;
|
||||
prefixList += (prefixList ? '|' : '') + this._prefixIRIs[prefixIRI];
|
||||
}
|
||||
IRIlist = escapeRegex(IRIlist, /[\]\/\(\)\*\+\?\.\\\$]/g, '\\$&');
|
||||
this._prefixRegex = new RegExp(`^(?:${prefixList})[^\/]*$|` +
|
||||
`^(${IRIlist})([_a-zA-Z0-9][\\-_a-zA-Z0-9]*)$`);
|
||||
}
|
||||
// End a prefix block with a newline
|
||||
this._write(hasPrefixes ? '\n' : '', done);
|
||||
}
|
||||
|
||||
// ### `blank` creates a blank node with the given content
|
||||
blank(predicate, object) {
|
||||
let children = predicate, child, length;
|
||||
// Empty blank node
|
||||
if (predicate === undefined)
|
||||
children = [];
|
||||
// Blank node passed as blank(Term("predicate"), Term("object"))
|
||||
else if (predicate.termType)
|
||||
children = [{ predicate: predicate, object: object }];
|
||||
// Blank node passed as blank({ predicate: predicate, object: object })
|
||||
else if (!('length' in predicate))
|
||||
children = [predicate];
|
||||
|
||||
switch (length = children.length) {
|
||||
// Generate an empty blank node
|
||||
case 0:
|
||||
return new SerializedTerm('[]');
|
||||
// Generate a non-nested one-triple blank node
|
||||
case 1:
|
||||
child = children[0];
|
||||
if (!(child.object instanceof SerializedTerm))
|
||||
return new SerializedTerm(`[ ${this._encodePredicate(child.predicate)} ${
|
||||
this._encodeObject(child.object)} ]`);
|
||||
// Generate a multi-triple or nested blank node
|
||||
default:
|
||||
let contents = '[';
|
||||
// Write all triples in order
|
||||
for (let i = 0; i < length; i++) {
|
||||
child = children[i];
|
||||
// Write only the object is the predicate is the same as the previous
|
||||
if (child.predicate.equals(predicate))
|
||||
contents += `, ${this._encodeObject(child.object)}`;
|
||||
// Otherwise, write the predicate and the object
|
||||
else {
|
||||
contents += `${(i ? ';\n ' : '\n ') +
|
||||
this._encodePredicate(child.predicate)} ${
|
||||
this._encodeObject(child.object)}`;
|
||||
predicate = child.predicate;
|
||||
}
|
||||
}
|
||||
return new SerializedTerm(`${contents}\n]`);
|
||||
}
|
||||
}
|
||||
|
||||
// ### `list` creates a list node with the given content
|
||||
list(elements) {
|
||||
const length = elements && elements.length || 0, contents = new Array(length);
|
||||
for (let i = 0; i < length; i++)
|
||||
contents[i] = this._encodeObject(elements[i]);
|
||||
return new SerializedTerm(`(${contents.join(' ')})`);
|
||||
}
|
||||
|
||||
// ### `end` signals the end of the output stream
|
||||
end(done) {
|
||||
// Finish a possible pending quad
|
||||
if (this._subject !== null) {
|
||||
this._write(this._inDefaultGraph ? '.\n' : '\n}\n');
|
||||
this._subject = null;
|
||||
}
|
||||
// Disallow further writing
|
||||
this._write = this._blockedWrite;
|
||||
|
||||
// Try to end the underlying stream, ensuring done is called exactly one time
|
||||
let singleDone = done && ((error, result) => { singleDone = null, done(error, result); });
|
||||
if (this._endStream) {
|
||||
try { return this._outputStream.end(singleDone); }
|
||||
catch (error) { /* error closing stream */ }
|
||||
}
|
||||
singleDone && singleDone();
|
||||
}
|
||||
}
|
||||
|
||||
// Replaces a character by its escaped version
|
||||
function characterReplacer(character) {
|
||||
// Replace a single character by its escaped version
|
||||
let result = escapedCharacters[character];
|
||||
if (result === undefined) {
|
||||
// Replace a single character with its 4-bit unicode escape sequence
|
||||
if (character.length === 1) {
|
||||
result = character.charCodeAt(0).toString(16);
|
||||
result = '\\u0000'.substr(0, 6 - result.length) + result;
|
||||
}
|
||||
// Replace a surrogate pair with its 8-bit unicode escape sequence
|
||||
else {
|
||||
result = ((character.charCodeAt(0) - 0xD800) * 0x400 +
|
||||
character.charCodeAt(1) + 0x2400).toString(16);
|
||||
result = '\\U00000000'.substr(0, 10 - result.length) + result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
3
node_modules/n3/src/Util.js
generated
vendored
Normal file
3
node_modules/n3/src/Util.js
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
export function escapeRegex(regex) {
|
||||
return regex.replace(/[\]\/\(\)\*\+\?\.\\\$]/g, '\\$&');
|
||||
}
|
||||
85
node_modules/n3/src/index.js
generated
vendored
Normal file
85
node_modules/n3/src/index.js
generated
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
import Lexer from './N3Lexer';
|
||||
import Parser from './N3Parser';
|
||||
import Writer from './N3Writer';
|
||||
import Store, { N3EntityIndex as EntityIndex } from './N3Store';
|
||||
import StoreFactory from './N3StoreFactory';
|
||||
import Reasoner, { getRulesFromDataset } from './N3Reasoner';
|
||||
import StreamParser from './N3StreamParser';
|
||||
import StreamWriter from './N3StreamWriter';
|
||||
import * as Util from './N3Util';
|
||||
import BaseIRI from './BaseIRI';
|
||||
|
||||
import {
|
||||
default as DataFactory,
|
||||
|
||||
Term,
|
||||
NamedNode,
|
||||
Literal,
|
||||
BlankNode,
|
||||
Variable,
|
||||
DefaultGraph,
|
||||
Quad,
|
||||
Triple,
|
||||
|
||||
termFromId,
|
||||
termToId,
|
||||
} from './N3DataFactory';
|
||||
|
||||
// Named exports
|
||||
export {
|
||||
Lexer,
|
||||
Parser,
|
||||
Writer,
|
||||
Store,
|
||||
StoreFactory,
|
||||
EntityIndex,
|
||||
StreamParser,
|
||||
StreamWriter,
|
||||
Util,
|
||||
Reasoner,
|
||||
BaseIRI,
|
||||
|
||||
DataFactory,
|
||||
|
||||
Term,
|
||||
NamedNode,
|
||||
Literal,
|
||||
BlankNode,
|
||||
Variable,
|
||||
DefaultGraph,
|
||||
Quad,
|
||||
Triple,
|
||||
|
||||
termFromId,
|
||||
termToId,
|
||||
getRulesFromDataset,
|
||||
};
|
||||
|
||||
// Export all named exports as a default object for backward compatibility
|
||||
export default {
|
||||
Lexer,
|
||||
Parser,
|
||||
Writer,
|
||||
Store,
|
||||
StoreFactory,
|
||||
EntityIndex,
|
||||
StreamParser,
|
||||
StreamWriter,
|
||||
Util,
|
||||
Reasoner,
|
||||
BaseIRI,
|
||||
|
||||
DataFactory,
|
||||
|
||||
Term,
|
||||
NamedNode,
|
||||
Literal,
|
||||
BlankNode,
|
||||
Variable,
|
||||
DefaultGraph,
|
||||
Quad,
|
||||
Triple,
|
||||
|
||||
termFromId,
|
||||
termToId,
|
||||
};
|
||||
Reference in New Issue
Block a user