n3 3.0.0-alpha.5 → 3.0.0-alpha.7
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/README.md +26 -0
- package/browser/n3.esm.min.js +12 -13
- package/browser/n3.min.js +12 -13
- package/lib/N3Lexer.js +54 -14
- package/lib/N3Parser.js +16 -5
- package/lib/N3Store.js +61 -3
- package/lib/N3Writer.js +20 -8
- package/package.json +1 -1
- package/src/N3Lexer.js +46 -14
- package/src/N3Parser.js +20 -5
- package/src/N3Store.js +52 -4
- package/src/N3Writer.js +23 -8
package/src/N3Store.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// **N3Store** objects store N3 quads by graph in memory.
|
|
2
|
-
import { Readable } from 'readable-stream';
|
|
2
|
+
import { Readable, finished } from 'readable-stream';
|
|
3
3
|
import { default as N3DataFactory, termToId, termFromId } from './N3DataFactory';
|
|
4
4
|
import namespaces from './IRIs';
|
|
5
5
|
import { isDefaultGraph } from './N3Util';
|
|
@@ -603,10 +603,55 @@ export default class N3Store {
|
|
|
603
603
|
return !this.readQuads(subjectOrQuad, predicate, object, graph).next().done;
|
|
604
604
|
}
|
|
605
605
|
|
|
606
|
-
// ### `import` adds a stream of quads to the store
|
|
606
|
+
// ### `import` adds a stream of quads to the store.
|
|
607
|
+
// It returns the stream, wrapped such that it can also be awaited
|
|
608
|
+
// as a promise of the store (per the RDF/JS `Dataset.import` signature).
|
|
607
609
|
import(stream) {
|
|
608
610
|
stream.on('data', quad => { this.addQuad(quad); });
|
|
609
|
-
|
|
611
|
+
|
|
612
|
+
// Only track completion once awaited, so unawaited imports keep the stream's behavior
|
|
613
|
+
const store = this;
|
|
614
|
+
let promise = null;
|
|
615
|
+
function completion() {
|
|
616
|
+
return promise || (promise = new Promise((resolve, reject) => {
|
|
617
|
+
let stopListening = null;
|
|
618
|
+
function settle(error) {
|
|
619
|
+
stopListening();
|
|
620
|
+
error ? reject(error) : resolve(store);
|
|
621
|
+
}
|
|
622
|
+
try {
|
|
623
|
+
stopListening = finished(stream, { readable: true, writable: false }, settle);
|
|
624
|
+
}
|
|
625
|
+
// RDF/JS streams that are not Node.js streams only signal their end and errors
|
|
626
|
+
// and must be awaited before they finish
|
|
627
|
+
catch {
|
|
628
|
+
stopListening = () => {
|
|
629
|
+
if (stream.removeListener) {
|
|
630
|
+
stream.removeListener('end', onFinish);
|
|
631
|
+
stream.removeListener('error', settle);
|
|
632
|
+
}
|
|
633
|
+
};
|
|
634
|
+
function onFinish() { settle(); }
|
|
635
|
+
stream.on('end', onFinish);
|
|
636
|
+
stream.on('error', settle);
|
|
637
|
+
}
|
|
638
|
+
}));
|
|
639
|
+
}
|
|
640
|
+
const thenable = {
|
|
641
|
+
then(onFulfilled, onRejected) { return completion().then(onFulfilled, onRejected); },
|
|
642
|
+
catch(onRejected) { return completion().catch(onRejected); },
|
|
643
|
+
finally(onFinally) { return completion().finally(onFinally); },
|
|
644
|
+
};
|
|
645
|
+
// Return a wrapper that behaves as the stream, but is also awaitable
|
|
646
|
+
return new Proxy(stream, {
|
|
647
|
+
get(target, property) {
|
|
648
|
+
if (property === 'then' || property === 'catch' || property === 'finally')
|
|
649
|
+
return thenable[property];
|
|
650
|
+
const value = target[property];
|
|
651
|
+
// Methods run on the stream itself, which may rely on private fields
|
|
652
|
+
return typeof value === 'function' ? value.bind(target) : value;
|
|
653
|
+
},
|
|
654
|
+
});
|
|
610
655
|
}
|
|
611
656
|
|
|
612
657
|
// ### `removeQuad` removes a quad from the store if it exists
|
|
@@ -649,9 +694,12 @@ export default class N3Store {
|
|
|
649
694
|
}
|
|
650
695
|
|
|
651
696
|
// ### `removeQuads` removes multiple quads from the store
|
|
697
|
+
// returns `true` if all quads were removed, `false` if some were not found
|
|
652
698
|
removeQuads(quads) {
|
|
699
|
+
let removed = true;
|
|
653
700
|
for (let i = 0; i < quads.length; i++)
|
|
654
|
-
this.removeQuad(quads[i]);
|
|
701
|
+
removed = this.removeQuad(quads[i]) && removed;
|
|
702
|
+
return removed;
|
|
655
703
|
}
|
|
656
704
|
|
|
657
705
|
// ### `remove` removes a stream of quads from the store
|
package/src/N3Writer.js
CHANGED
|
@@ -24,6 +24,9 @@ const escape = /["\\\t\n\r\b\f\u0000-\u0019\ud800-\udbff]/,
|
|
|
24
24
|
'\n': '\\n', '\r': '\\r', '\b': '\\b', '\f': '\\f',
|
|
25
25
|
};
|
|
26
26
|
|
|
27
|
+
// Characters that a version label cannot contain
|
|
28
|
+
const invalidVersionLabel = /["\\\u0000-\u001f\u007f]|[\ud800-\udbff](?![\udc00-\udfff])|(?:^|[^\ud800-\udbff])[\udc00-\udfff]/;
|
|
29
|
+
|
|
27
30
|
// ## Placeholder class to represent already pretty-printed terms
|
|
28
31
|
class SerializedTerm extends Term {
|
|
29
32
|
// Pretty-printed nodes are not equal to any other node
|
|
@@ -60,12 +63,19 @@ export default class N3Writer {
|
|
|
60
63
|
this._endStream = options.end === undefined ? true : !!options.end;
|
|
61
64
|
}
|
|
62
65
|
|
|
66
|
+
// A version label is written as-is, so it cannot contain characters that need escaping,
|
|
67
|
+
// nor unpaired surrogates (which cannot be encoded)
|
|
68
|
+
if (options.version && invalidVersionLabel.test(options.version))
|
|
69
|
+
throw new Error(`Invalid version label: ${JSON.stringify(options.version)}`);
|
|
70
|
+
|
|
63
71
|
// Initialize writer, depending on the format
|
|
64
72
|
this._subject = null;
|
|
65
73
|
if (!(/triple|quad/i).test(options.format)) {
|
|
66
74
|
this._lineMode = false;
|
|
67
75
|
this._escape = escape, this._escapeAll = escapeAll, this._characterReplacer = characterReplacer;
|
|
68
76
|
this._graph = DEFAULTGRAPH;
|
|
77
|
+
if (options.version)
|
|
78
|
+
this._write(`@version "${options.version}".\n`);
|
|
69
79
|
this._prefixIRIs = Object.create(null);
|
|
70
80
|
// Escaped prefix IRIs and names for the prefix matcher, computed once per prefix
|
|
71
81
|
this._prefixPatterns = Object.create(null);
|
|
@@ -82,6 +92,8 @@ export default class N3Writer {
|
|
|
82
92
|
// N-Triples and N-Quads are written in their canonical form
|
|
83
93
|
this._escape = canonicalEscape, this._escapeAll = canonicalEscapeAll;
|
|
84
94
|
this._characterReplacer = canonicalCharacterReplacer;
|
|
95
|
+
if (options.version)
|
|
96
|
+
this._write(`VERSION "${options.version}"\n`);
|
|
85
97
|
}
|
|
86
98
|
}
|
|
87
99
|
|
|
@@ -97,6 +109,15 @@ export default class N3Writer {
|
|
|
97
109
|
this._outputStream.write(string, 'utf8', callback);
|
|
98
110
|
}
|
|
99
111
|
|
|
112
|
+
// ### `_endStatement` finishes a pending statement and closes an open graph block
|
|
113
|
+
_endStatement() {
|
|
114
|
+
if (this._subject !== null) {
|
|
115
|
+
this._write(this._inDefaultGraph ? '.\n' : '\n}\n');
|
|
116
|
+
this._subject = null;
|
|
117
|
+
this._graph = DEFAULTGRAPH;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
100
121
|
// ### `_writeQuad` writes the quad to the output stream
|
|
101
122
|
_writeQuad(subject, predicate, object, graph, done) {
|
|
102
123
|
try {
|
|
@@ -324,10 +345,7 @@ export default class N3Writer {
|
|
|
324
345
|
iri = iri.value;
|
|
325
346
|
hasPrefixes = true;
|
|
326
347
|
// Finish a possible pending quad
|
|
327
|
-
|
|
328
|
-
this._write(this._inDefaultGraph ? '.\n' : '\n}\n');
|
|
329
|
-
this._subject = null, this._graph = '';
|
|
330
|
-
}
|
|
348
|
+
this._endStatement();
|
|
331
349
|
// Store and write the prefix
|
|
332
350
|
this._prefixIRIs[iri] = (prefix += ':');
|
|
333
351
|
this._prefixPatterns[iri] = escapeRegex(iri);
|
|
@@ -406,10 +424,7 @@ export default class N3Writer {
|
|
|
406
424
|
// ### `end` signals the end of the output stream
|
|
407
425
|
end(done) {
|
|
408
426
|
// Finish a possible pending quad
|
|
409
|
-
|
|
410
|
-
this._write(this._inDefaultGraph ? '.\n' : '\n}\n');
|
|
411
|
-
this._subject = null;
|
|
412
|
-
}
|
|
427
|
+
this._endStatement();
|
|
413
428
|
// Disallow further writing
|
|
414
429
|
this._write = this._blockedWrite;
|
|
415
430
|
|