n3.js-messages 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +218 -0
- package/index.d.ts +115 -0
- package/lib/MessageParser.js +76 -0
- package/lib/MessageParserCore.js +162 -0
- package/lib/MessageScanner.js +395 -0
- package/lib/MessageStreamParser.js +44 -0
- package/lib/MessageStreamWriter.js +35 -0
- package/lib/MessageWriter.js +178 -0
- package/lib/formats.js +55 -0
- package/lib/index.js +47 -0
- package/lib/package.json +1 -0
- package/package.json +107 -0
- package/src/MessageParser.js +71 -0
- package/src/MessageParserCore.js +197 -0
- package/src/MessageScanner.js +390 -0
- package/src/MessageStreamParser.js +33 -0
- package/src/MessageStreamWriter.js +22 -0
- package/src/MessageWriter.js +194 -0
- package/src/formats.js +39 -0
- package/src/index.js +4 -0
package/lib/formats.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.baseVersion = baseVersion;
|
|
7
|
+
exports.isMessagesVersion = isMessagesVersion;
|
|
8
|
+
exports.isSupportedVersion = isSupportedVersion;
|
|
9
|
+
exports.resolveFormat = resolveFormat;
|
|
10
|
+
// **formats** describes the RDF syntaxes that support RDF Messages.
|
|
11
|
+
|
|
12
|
+
const FORMATS = {
|
|
13
|
+
turtle: {
|
|
14
|
+
name: 'Turtle',
|
|
15
|
+
lineMode: false
|
|
16
|
+
},
|
|
17
|
+
trig: {
|
|
18
|
+
name: 'TriG',
|
|
19
|
+
lineMode: false
|
|
20
|
+
},
|
|
21
|
+
ntriples: {
|
|
22
|
+
name: 'N-Triples',
|
|
23
|
+
lineMode: true
|
|
24
|
+
},
|
|
25
|
+
nquads: {
|
|
26
|
+
name: 'N-Quads',
|
|
27
|
+
lineMode: true
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// The version labels of RDF 1.2 syntaxes, as accepted by N3.js
|
|
32
|
+
const BASE_VERSIONS = ['1.2', '1.2-basic', '1.1'];
|
|
33
|
+
|
|
34
|
+
// ### `resolveFormat` maps a format name or media type to a supported syntax
|
|
35
|
+
function resolveFormat(format = 'TriG') {
|
|
36
|
+
const key = String(format).toLowerCase().split(';')[0].trim().replace(/^(?:text|application)\//, '').replace(/^x-/, '').replace(/[-_ ]/g, '');
|
|
37
|
+
const resolved = FORMATS[key];
|
|
38
|
+
if (!resolved) throw new TypeError(`Unsupported RDF Messages format: "${format}". ` + 'Supported formats are Turtle, TriG, N-Triples and N-Quads.');
|
|
39
|
+
return resolved;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// ### `isMessagesVersion` checks whether a version label announces RDF Messages
|
|
43
|
+
function isMessagesVersion(version) {
|
|
44
|
+
return typeof version === 'string' && version.endsWith('-messages');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// ### `baseVersion` strips the `-messages` suffix of a version label
|
|
48
|
+
function baseVersion(version) {
|
|
49
|
+
return isMessagesVersion(version) ? version.slice(0, -'-messages'.length) : version;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ### `isSupportedVersion` checks whether a (base) version label is supported
|
|
53
|
+
function isSupportedVersion(version, supported = BASE_VERSIONS) {
|
|
54
|
+
return supported.includes(version);
|
|
55
|
+
}
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
Object.defineProperty(exports, "MessageParser", {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: function () {
|
|
9
|
+
return _MessageParser.default;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
Object.defineProperty(exports, "MessageStreamParser", {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
get: function () {
|
|
15
|
+
return _MessageStreamParser.default;
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
Object.defineProperty(exports, "MessageStreamWriter", {
|
|
19
|
+
enumerable: true,
|
|
20
|
+
get: function () {
|
|
21
|
+
return _MessageStreamWriter.default;
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
Object.defineProperty(exports, "MessageWriter", {
|
|
25
|
+
enumerable: true,
|
|
26
|
+
get: function () {
|
|
27
|
+
return _MessageWriter.default;
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
Object.defineProperty(exports, "parseMessages", {
|
|
31
|
+
enumerable: true,
|
|
32
|
+
get: function () {
|
|
33
|
+
return _MessageParser.parseMessages;
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
Object.defineProperty(exports, "writeMessages", {
|
|
37
|
+
enumerable: true,
|
|
38
|
+
get: function () {
|
|
39
|
+
return _MessageWriter.writeMessages;
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
var _MessageParser = _interopRequireWildcard(require("./MessageParser.js"));
|
|
43
|
+
var _MessageStreamParser = _interopRequireDefault(require("./MessageStreamParser.js"));
|
|
44
|
+
var _MessageWriter = _interopRequireWildcard(require("./MessageWriter.js"));
|
|
45
|
+
var _MessageStreamWriter = _interopRequireDefault(require("./MessageStreamWriter.js"));
|
|
46
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
47
|
+
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); }
|
package/lib/package.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "type": "commonjs" }
|
package/package.json
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "n3.js-messages",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "RDF Messages (message-delimited Turtle, TriG, N-Triples and N-Quads) for N3.js: message-aware parser, streaming parser and writer.",
|
|
5
|
+
"author": "Pieter Colpaert",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"rdf",
|
|
9
|
+
"rdf-messages",
|
|
10
|
+
"n3",
|
|
11
|
+
"turtle",
|
|
12
|
+
"trig",
|
|
13
|
+
"n-triples",
|
|
14
|
+
"n-quads",
|
|
15
|
+
"streaming",
|
|
16
|
+
"rdfjs"
|
|
17
|
+
],
|
|
18
|
+
"type": "module",
|
|
19
|
+
"main": "./lib/index.js",
|
|
20
|
+
"module": "./src/index.js",
|
|
21
|
+
"types": "./index.d.ts",
|
|
22
|
+
"exports": {
|
|
23
|
+
".": {
|
|
24
|
+
"types": "./index.d.ts",
|
|
25
|
+
"import": "./src/index.js",
|
|
26
|
+
"require": "./lib/index.js"
|
|
27
|
+
},
|
|
28
|
+
"./package.json": "./package.json"
|
|
29
|
+
},
|
|
30
|
+
"sideEffects": false,
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">=18"
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"src",
|
|
36
|
+
"lib",
|
|
37
|
+
"index.d.ts"
|
|
38
|
+
],
|
|
39
|
+
"peerDependencies": {
|
|
40
|
+
"n3": ">=2.0.0 <3"
|
|
41
|
+
},
|
|
42
|
+
"repository": {
|
|
43
|
+
"type": "git",
|
|
44
|
+
"url": "git+https://github.com/pietercolpaert/n3.js-messages.git"
|
|
45
|
+
},
|
|
46
|
+
"bugs": {
|
|
47
|
+
"url": "https://github.com/pietercolpaert/n3.js-messages/issues"
|
|
48
|
+
},
|
|
49
|
+
"homepage": "https://github.com/pietercolpaert/n3.js-messages#readme",
|
|
50
|
+
"scripts": {
|
|
51
|
+
"build": "babel src -d lib --copy-files --no-copy-ignored && node scripts/write-lib-package.js",
|
|
52
|
+
"prepack": "npm run build",
|
|
53
|
+
"test": "jest",
|
|
54
|
+
"coverage": "jest --coverage",
|
|
55
|
+
"lint": "eslint src test spec perf scripts",
|
|
56
|
+
"test:spec": "node spec/runner.js",
|
|
57
|
+
"test:spec:earl": "node spec/runner.js --earl > spec/earl-report.ttl",
|
|
58
|
+
"test:types": "tsc -p test/types/tsconfig.json",
|
|
59
|
+
"test:package": "node scripts/test-package.js",
|
|
60
|
+
"perf": "node perf/run.js",
|
|
61
|
+
"perf:compare": "node perf/compare.js",
|
|
62
|
+
"spec:update": "node scripts/update-spec.js"
|
|
63
|
+
},
|
|
64
|
+
"devDependencies": {
|
|
65
|
+
"@babel/cli": "^7.29.7",
|
|
66
|
+
"@babel/core": "^7.29.7",
|
|
67
|
+
"@babel/preset-env": "^7.29.7",
|
|
68
|
+
"@types/n3": "^1.26.4",
|
|
69
|
+
"@types/node": "^26.6.4",
|
|
70
|
+
"babel-jest": "^30.5.2",
|
|
71
|
+
"eslint": "^10.12.0",
|
|
72
|
+
"eslint-plugin-import-x": "^4.17.1",
|
|
73
|
+
"eslint-plugin-jest": "^29.16.6",
|
|
74
|
+
"globals": "^17.13.0",
|
|
75
|
+
"jest": "^30.5.2",
|
|
76
|
+
"n3": "^2.10.6",
|
|
77
|
+
"rdf-isomorphic": "^2.0.1",
|
|
78
|
+
"rdf-parser-ts": "^0.4.0",
|
|
79
|
+
"rdf-writer-ts": "^0.2.1",
|
|
80
|
+
"typescript": "^6.0.3"
|
|
81
|
+
},
|
|
82
|
+
"jest": {
|
|
83
|
+
"testMatch": [
|
|
84
|
+
"**/test/**/*-test.js"
|
|
85
|
+
],
|
|
86
|
+
"collectCoverage": true,
|
|
87
|
+
"collectCoverageFrom": [
|
|
88
|
+
"src/**/*.js"
|
|
89
|
+
],
|
|
90
|
+
"coverageReporters": [
|
|
91
|
+
"json-summary",
|
|
92
|
+
"text",
|
|
93
|
+
"lcov"
|
|
94
|
+
],
|
|
95
|
+
"coverageThreshold": {
|
|
96
|
+
"global": {
|
|
97
|
+
"branches": 100,
|
|
98
|
+
"functions": 100,
|
|
99
|
+
"lines": 100,
|
|
100
|
+
"statements": 100
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
"dependencies": {
|
|
105
|
+
"@rdfjs/types": "^2.0.1"
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// **MessageParser** parses RDF Message Logs (Turtle, TriG, N-Triples and N-Quads).
|
|
2
|
+
import { StringDecoder } from 'string_decoder';
|
|
3
|
+
import MessageParserCore from './MessageParserCore.js';
|
|
4
|
+
|
|
5
|
+
export default class MessageParser {
|
|
6
|
+
constructor(options) {
|
|
7
|
+
this._options = options || {};
|
|
8
|
+
// Fail early on unsupported options
|
|
9
|
+
this._createCore({});
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
_createCore(sink) {
|
|
13
|
+
return new MessageParserCore(this._options, sink);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// ### `parse` parses a string or a readable stream of RDF Messages.
|
|
17
|
+
//
|
|
18
|
+
// Without callbacks, a string is parsed synchronously into an array of
|
|
19
|
+
// messages (arrays of quads), and parse errors are thrown.
|
|
20
|
+
// With a callback `(error, message, prefixes)`, or an object with the
|
|
21
|
+
// callbacks `onMessage(error, message, prefixes)`, `onQuad(error, quad, messageIndex)`,
|
|
22
|
+
// `onPrefix(prefix, term)` and `onVersion(label)`, messages are reported as soon
|
|
23
|
+
// as they are complete. The final call has `null` as message.
|
|
24
|
+
parse(input, callbacks) {
|
|
25
|
+
if (typeof callbacks === 'function')
|
|
26
|
+
callbacks = { onMessage: callbacks };
|
|
27
|
+
const messages = callbacks ? null : [];
|
|
28
|
+
let error = null;
|
|
29
|
+
callbacks = callbacks || {};
|
|
30
|
+
const sink = {
|
|
31
|
+
message: (quads, index) => callbacks.onMessage ? callbacks.onMessage(null, quads, undefined, index) : messages && messages.push(quads),
|
|
32
|
+
end: prefixes => callbacks.onMessage && callbacks.onMessage(null, null, prefixes),
|
|
33
|
+
error: e => {
|
|
34
|
+
error = e;
|
|
35
|
+
callbacks.onMessage && callbacks.onMessage(e);
|
|
36
|
+
callbacks.onQuad && callbacks.onQuad(e);
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
if (callbacks.onQuad)
|
|
40
|
+
sink.quad = (quad, index) => callbacks.onQuad(null, quad, index);
|
|
41
|
+
if (callbacks.onPrefix)
|
|
42
|
+
sink.prefix = callbacks.onPrefix;
|
|
43
|
+
if (callbacks.onVersion)
|
|
44
|
+
sink.version = callbacks.onVersion;
|
|
45
|
+
const core = this._createCore(sink);
|
|
46
|
+
|
|
47
|
+
// Parse a string at once
|
|
48
|
+
if (typeof input === 'string') {
|
|
49
|
+
core.write(input);
|
|
50
|
+
core.end();
|
|
51
|
+
if (error && messages)
|
|
52
|
+
throw error;
|
|
53
|
+
return messages || undefined;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Parse a stream chunk by chunk
|
|
57
|
+
const decoder = new StringDecoder('utf8');
|
|
58
|
+
input.on('data', chunk => core.write(typeof chunk === 'string' ? chunk : decoder.write(chunk)));
|
|
59
|
+
input.on('end', () => {
|
|
60
|
+
core.write(decoder.end());
|
|
61
|
+
core.end();
|
|
62
|
+
});
|
|
63
|
+
input.on('error', e => sink.error(e));
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// ### `parseMessages` synchronously parses a string into an array of messages
|
|
69
|
+
export function parseMessages(input, options) {
|
|
70
|
+
return new MessageParser(options).parse(input);
|
|
71
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
// **MessageParserCore** is the push-based engine behind all message parsers.
|
|
2
|
+
// It feeds scanned text to the public N3.js parser and groups the resulting
|
|
3
|
+
// quads into messages.
|
|
4
|
+
import { EventEmitter } from 'events';
|
|
5
|
+
import { Parser, DataFactory } from 'n3';
|
|
6
|
+
import { TurtleScanner, LineScanner } from './MessageScanner.js';
|
|
7
|
+
import { resolveFormat, isMessagesVersion, baseVersion, isSupportedVersion } from './formats.js';
|
|
8
|
+
|
|
9
|
+
// Unrecognizable by construction: a document cannot contain it by accident
|
|
10
|
+
function createSentinel() {
|
|
11
|
+
return `rdf-messages-${Math.random().toString(36).slice(2)}${Math.random().toString(36).slice(2)}`;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export default class MessageParserCore {
|
|
15
|
+
// `sink` receives `message(quads, index)`, `end(prefixes)`, `error(error)`
|
|
16
|
+
// and optionally `quad(quad, messageIndex)`, `prefix(prefix, term)`, `version(label)`
|
|
17
|
+
constructor(options, sink) {
|
|
18
|
+
options = options || {};
|
|
19
|
+
const format = resolveFormat(options.format);
|
|
20
|
+
this._sink = sink;
|
|
21
|
+
this._factory = options.factory || DataFactory;
|
|
22
|
+
this._blankNodePrefix = typeof options.blankNodePrefix === 'string' ?
|
|
23
|
+
options.blankNodePrefix.replace(/^_:/, '') : undefined;
|
|
24
|
+
this._blankNodeCounter = 0;
|
|
25
|
+
this._supportedVersions = Parser.SUPPORTED_VERSIONS;
|
|
26
|
+
this._messages = options.messages === true || isMessagesVersion(options.version);
|
|
27
|
+
this._index = 0;
|
|
28
|
+
this._current = null;
|
|
29
|
+
this._scope = null;
|
|
30
|
+
this._seenQuad = false;
|
|
31
|
+
this._failed = false;
|
|
32
|
+
this._finished = false;
|
|
33
|
+
|
|
34
|
+
const n3Options = {
|
|
35
|
+
format: format.name,
|
|
36
|
+
factory: this._factory,
|
|
37
|
+
// Version labels are validated here, because N3.js does not know `-messages` labels
|
|
38
|
+
parseUnsupportedVersions: true,
|
|
39
|
+
};
|
|
40
|
+
if (options.baseIRI)
|
|
41
|
+
n3Options.baseIRI = options.baseIRI;
|
|
42
|
+
if (options.version) {
|
|
43
|
+
this._checkVersion(options.version, true);
|
|
44
|
+
n3Options.version = baseVersion(options.version);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const sentinel = createSentinel();
|
|
48
|
+
this._sentinel = sentinel;
|
|
49
|
+
this._scanner = format.lineMode ? new LineScanner(sentinel) : new TurtleScanner(sentinel);
|
|
50
|
+
this._input = new EventEmitter();
|
|
51
|
+
const callbacks = {
|
|
52
|
+
onQuad: (error, quad, prefixes) => this._onQuad(error, quad, prefixes),
|
|
53
|
+
onPrefix: (prefix, term) => this._failed || sink.prefix && sink.prefix(prefix, term),
|
|
54
|
+
onVersion: label => this._onVersion(label),
|
|
55
|
+
};
|
|
56
|
+
if (format.lineMode)
|
|
57
|
+
callbacks.onComment = comment => this._onComment(comment);
|
|
58
|
+
new Parser(n3Options).parse(this._input, callbacks);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// ### `write` accepts the next chunk of text
|
|
62
|
+
write(text) {
|
|
63
|
+
if (!this._failed && !this._finished && text.length > 0)
|
|
64
|
+
this._feed(this._scanner.push(text));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// ### `end` signals the end of the input
|
|
68
|
+
end() {
|
|
69
|
+
if (!this._failed && !this._finished) {
|
|
70
|
+
this._feed(this._scanner.end());
|
|
71
|
+
this._input.emit('end');
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
_feed(text) {
|
|
76
|
+
if (text.length > 0)
|
|
77
|
+
this._input.emit('data', text);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
_onQuad(error, quad, prefixes) {
|
|
81
|
+
if (this._failed || this._finished)
|
|
82
|
+
return;
|
|
83
|
+
if (error)
|
|
84
|
+
this._fail(error);
|
|
85
|
+
else if (quad)
|
|
86
|
+
this._addQuad(quad);
|
|
87
|
+
else {
|
|
88
|
+
this._finished = true;
|
|
89
|
+
if (this._current !== null)
|
|
90
|
+
this._emitMessage();
|
|
91
|
+
this._sink.end(prefixes);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
_addQuad(quad) {
|
|
96
|
+
this._seenQuad = true;
|
|
97
|
+
// Blank node labels are scoped to their message
|
|
98
|
+
if (this._messages)
|
|
99
|
+
quad = this._scopeQuad(quad);
|
|
100
|
+
if (this._current === null)
|
|
101
|
+
this._current = [];
|
|
102
|
+
this._current.push(quad);
|
|
103
|
+
if (this._sink.quad)
|
|
104
|
+
this._sink.quad(quad, this._index);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
_onVersion(label) {
|
|
108
|
+
if (this._failed)
|
|
109
|
+
return;
|
|
110
|
+
if (label === this._sentinel)
|
|
111
|
+
this._delimiter(this._scanner.delimiterLines.shift());
|
|
112
|
+
else
|
|
113
|
+
this._announce(label);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Line mode reports delimiters and versions as comments
|
|
117
|
+
_onComment(comment) {
|
|
118
|
+
if (this._failed || !comment.startsWith(this._sentinel))
|
|
119
|
+
return;
|
|
120
|
+
const rest = comment.substring(this._sentinel.length);
|
|
121
|
+
if (rest[0] === 'M')
|
|
122
|
+
this._delimiter(Number(rest.substring(1)));
|
|
123
|
+
else
|
|
124
|
+
this._announce(rest.substring(1));
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
_announce(label) {
|
|
128
|
+
const error = this._checkVersion(label);
|
|
129
|
+
if (error)
|
|
130
|
+
return this._fail(error);
|
|
131
|
+
if (isMessagesVersion(label) && !this._messages) {
|
|
132
|
+
if (this._seenQuad)
|
|
133
|
+
return this._fail(new Error(`Version "${label}" must be announced before the first statement.`));
|
|
134
|
+
this._messages = true;
|
|
135
|
+
}
|
|
136
|
+
if (this._sink.version)
|
|
137
|
+
this._sink.version(label);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Validates a version label, and returns an error for unsupported ones
|
|
141
|
+
_checkVersion(label, throwing) {
|
|
142
|
+
if (isSupportedVersion(baseVersion(label), this._supportedVersions))
|
|
143
|
+
return null;
|
|
144
|
+
const error = new Error(`Detected unsupported version: "${label}"`);
|
|
145
|
+
if (throwing)
|
|
146
|
+
throw error;
|
|
147
|
+
return error;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
_delimiter(line) {
|
|
151
|
+
if (!this._messages) {
|
|
152
|
+
return this._fail(new Error(`Unexpected "MESSAGE" on line ${line}: the document did not announce ` +
|
|
153
|
+
'a version with the "-messages" suffix.'));
|
|
154
|
+
}
|
|
155
|
+
this._emitMessage();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Finalizes the current message, which is empty if no quad was seen
|
|
159
|
+
_emitMessage() {
|
|
160
|
+
const quads = this._current || [];
|
|
161
|
+
this._current = null;
|
|
162
|
+
this._scope = null;
|
|
163
|
+
this._sink.message(quads, this._index++);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
_fail(error) {
|
|
167
|
+
this._failed = true;
|
|
168
|
+
this._current = null;
|
|
169
|
+
this._sink.error(error);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// ## Blank node scoping
|
|
173
|
+
|
|
174
|
+
_scopeQuad(quad) {
|
|
175
|
+
const subject = this._scopeTerm(quad.subject);
|
|
176
|
+
const predicate = this._scopeTerm(quad.predicate);
|
|
177
|
+
const object = this._scopeTerm(quad.object);
|
|
178
|
+
const graph = this._scopeTerm(quad.graph);
|
|
179
|
+
return subject === quad.subject && predicate === quad.predicate &&
|
|
180
|
+
object === quad.object && graph === quad.graph ?
|
|
181
|
+
quad : this._factory.quad(subject, predicate, object, graph);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
_scopeTerm(term) {
|
|
185
|
+
if (term.termType === 'BlankNode') {
|
|
186
|
+
const scope = this._scope || (this._scope = new Map());
|
|
187
|
+
let scoped = scope.get(term.value);
|
|
188
|
+
if (!scoped) {
|
|
189
|
+
scoped = this._blankNodePrefix === undefined ? this._factory.blankNode() :
|
|
190
|
+
this._factory.blankNode(`${this._blankNodePrefix}${this._blankNodeCounter++}`);
|
|
191
|
+
scope.set(term.value, scoped);
|
|
192
|
+
}
|
|
193
|
+
return scoped;
|
|
194
|
+
}
|
|
195
|
+
return term.termType === 'Quad' ? this._scopeQuad(term) : term;
|
|
196
|
+
}
|
|
197
|
+
}
|