n3 2.11.0 → 2.11.1
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/browser/n3.esm.min.js +5 -5
- package/browser/n3.min.js +5 -5
- package/lib/BaseIRI.js +6 -3
- package/lib/N3DataFactory.js +4 -1
- package/lib/N3Lexer.js +11 -4
- package/lib/N3Parser.js +40 -15
- package/lib/N3Store.js +10 -3
- package/package.json +34 -2
- package/src/BaseIRI.js +7 -3
- package/src/N3DataFactory.js +2 -1
- package/src/N3Lexer.js +13 -4
- package/src/N3Parser.js +42 -14
- package/src/N3Store.js +10 -4
package/lib/BaseIRI.js
CHANGED
|
@@ -9,7 +9,9 @@ var _Util = require("./Util");
|
|
|
9
9
|
// - file: IRIs (which could also use backslashes)
|
|
10
10
|
// - IRIs containing /. or /.. or //
|
|
11
11
|
const BASE_UNSUPPORTED = /^:?[^:?#]*(?:[?#]|$)|^file:|^[^:]*:\/*[^?#]+?\/(?:\.\.?(?:\/|$)|\/)/i;
|
|
12
|
-
|
|
12
|
+
// Supported suffixes have a first path segment other than . or ..,
|
|
13
|
+
// and further path segments of at least 3 characters
|
|
14
|
+
const SUFFIX_SUPPORTED = /^(?:(?!\.\.?(?:[/?#]|$))[^/?#]+(?:\/[^/?#]{3,})*\/?)?(?:[?#]|$)/;
|
|
13
15
|
const CURRENT = './';
|
|
14
16
|
const PARENT = '../';
|
|
15
17
|
const QUERY = '?';
|
|
@@ -80,8 +82,9 @@ class BaseIRI {
|
|
|
80
82
|
const suffix = iri.substring(length);
|
|
81
83
|
// Don't abbreviate unsupported path
|
|
82
84
|
if (parentPath !== QUERY && !SUFFIX_SUPPORTED.test(suffix)) return iri;
|
|
83
|
-
// Omit ./ with fragment or query string
|
|
84
|
-
|
|
85
|
+
// Omit ./ with fragment or query string,
|
|
86
|
+
// unless the first segment has a colon and would be read as a scheme
|
|
87
|
+
if (parentPath === CURRENT && /^[^?#]/.test(suffix) && (suffix.indexOf(':') < 0 || !/^[^/?#]*:/.test(suffix))) return suffix;
|
|
85
88
|
// Append suffix to relative parent path
|
|
86
89
|
return parentPath + suffix;
|
|
87
90
|
}
|
package/lib/N3DataFactory.js
CHANGED
|
@@ -484,7 +484,10 @@ function fromTerm(term) {
|
|
|
484
484
|
case 'DefaultGraph':
|
|
485
485
|
return DEFAULTGRAPH;
|
|
486
486
|
case 'Literal':
|
|
487
|
-
return literal(term.value, term.language
|
|
487
|
+
return literal(term.value, !term.language ? term.datatype : term.direction ? {
|
|
488
|
+
language: term.language,
|
|
489
|
+
direction: term.direction
|
|
490
|
+
} : term.language);
|
|
488
491
|
case 'Quad':
|
|
489
492
|
return fromQuad(term);
|
|
490
493
|
default:
|
package/lib/N3Lexer.js
CHANGED
|
@@ -53,6 +53,8 @@ const localNameEscapeReplacements = {
|
|
|
53
53
|
'%': '%'
|
|
54
54
|
};
|
|
55
55
|
const illegalIriChars = /[\x00-\x20<>\\"\{\}\|\^\`]/;
|
|
56
|
+
// Characters that cannot occur in a prefixed name, not even escaped
|
|
57
|
+
const nonPrefixedNameChar = /[\s<>"{}|^`]/;
|
|
56
58
|
|
|
57
59
|
// A valid code point is a Unicode scalar value: at most U+10FFFF and not a surrogate
|
|
58
60
|
function isValidCodePoint(charCode) {
|
|
@@ -80,10 +82,10 @@ class N3Lexer {
|
|
|
80
82
|
this._simpleApostropheString = /^'([^'\\\r\n]*)'(?=[^'])/;
|
|
81
83
|
this._langcode = /^@([a-z]+(?:-[a-z0-9]+)*)(?=[^a-z0-9])/i;
|
|
82
84
|
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<])/;
|
|
83
|
-
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
|
|
84
|
-
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
|
|
85
|
+
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-9: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-9: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-9: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#()\[\]\{\}"'<>]))/;
|
|
86
|
+
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-9: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#()\[\]\{\}"'<>])/;
|
|
85
87
|
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#()\[\]\{\}"'<>]))/;
|
|
86
|
-
this._number = /^[\-+]?(?:(\d+\.\d*|\.?\d+)[eE][\-+]
|
|
88
|
+
this._number = /^[\-+]?(?:(\d+\.\d*|\.?\d+)[eE][\-+]?\d+|(?=\.?\d)\d*(?:(\.)\d+)?)(?=\.?[,;:!\^\s#()\[\]\{\}"'<>])/;
|
|
87
89
|
this._boolean = /^(?:true|false)(?=[.,;!\^\s#()\[\]\{\}"'<>])/;
|
|
88
90
|
this._atKeyword = /^@[a-z]+(?=[\s#<:])/i;
|
|
89
91
|
this._keyword = /^(?:PREFIX|BASE|VERSION|GRAPH)(?=[\s#<])/i;
|
|
@@ -532,7 +534,12 @@ class N3Lexer {
|
|
|
532
534
|
|
|
533
535
|
// A prefix can start with a verb and continue with characters that are also
|
|
534
536
|
// valid verb boundaries. Prefer the longer prefixed name when it is complete.
|
|
535
|
-
if (this._prefixed.exec(input)
|
|
537
|
+
if (this._prefixed.exec(input)) return null;
|
|
538
|
+
// Appending to the input only matters when a prefixed name could run up to
|
|
539
|
+
// its end, which a character that cannot occur in prefixed names rules out.
|
|
540
|
+
// This avoids copying the rest of the document for every such verb.
|
|
541
|
+
if (nonPrefixedNameChar.test(input)) return verb;
|
|
542
|
+
if (this._prefixed.exec(`${input} `)) return null;
|
|
536
543
|
|
|
537
544
|
// If a stream chunk ends partway through such a prefix, wait for the colon
|
|
538
545
|
// instead of prematurely emitting the verb. Appending ": " lets the prefix
|
package/lib/N3Parser.js
CHANGED
|
@@ -24,7 +24,7 @@ class N3Parser {
|
|
|
24
24
|
options.factory && initDataFactory(this, options.factory);
|
|
25
25
|
|
|
26
26
|
// Set supported features depending on the format
|
|
27
|
-
const format = typeof options.format === 'string' ? options.format.match(
|
|
27
|
+
const format = typeof options.format === 'string' ? options.format.match(/(?:^|\W)(\w*)$/)[1].toLowerCase() : '',
|
|
28
28
|
isTurtle = /turtle/.test(format),
|
|
29
29
|
isTriG = /trig/.test(format),
|
|
30
30
|
isNTriples = /triple/.test(format),
|
|
@@ -87,7 +87,9 @@ class N3Parser {
|
|
|
87
87
|
if (fragmentPos >= 0) baseIRI = baseIRI.substr(0, fragmentPos);
|
|
88
88
|
// Set base IRI and its components
|
|
89
89
|
this._base = baseIRI;
|
|
90
|
-
|
|
90
|
+
const queryPos = baseIRI.indexOf('?');
|
|
91
|
+
const path = queryPos < 0 ? baseIRI : baseIRI.substr(0, queryPos);
|
|
92
|
+
this._basePath = baseIRI.indexOf('/') < 0 ? baseIRI : path.substr(0, path.lastIndexOf('/') + 1);
|
|
91
93
|
baseIRI = baseIRI.match(/^(?:([a-z][a-z0-9+.-]*:))?(?:\/\/[^\/]*)?/i);
|
|
92
94
|
this._baseRoot = baseIRI[0];
|
|
93
95
|
this._baseScheme = baseIRI[1];
|
|
@@ -117,14 +119,15 @@ class N3Parser {
|
|
|
117
119
|
inverse: this._inversePredicate,
|
|
118
120
|
expectOf: this._expectOf,
|
|
119
121
|
blankPrefix: this._prefixes._,
|
|
120
|
-
|
|
122
|
+
prefixChanges: this._prefixChanges,
|
|
123
|
+
quantifiedChanges: this._quantifiedChanges,
|
|
121
124
|
emptyFormula: this._emptyFormula
|
|
122
125
|
};
|
|
123
|
-
// Prefix and base declarations are scoped to their formula
|
|
126
|
+
// Prefix and base declarations are scoped to their formula,
|
|
127
|
+
// so record prefix changes to undo them when the formula ends
|
|
124
128
|
if (type === 'formula') {
|
|
125
|
-
context.prefixes = this._prefixes;
|
|
126
129
|
context.base = [this._base, this._basePath, this._baseRoot, this._baseScheme];
|
|
127
|
-
this.
|
|
130
|
+
this._prefixChanges = [];
|
|
128
131
|
}
|
|
129
132
|
this._contextStack.push(context);
|
|
130
133
|
// Every new scope resets the predicate direction
|
|
@@ -137,7 +140,7 @@ class N3Parser {
|
|
|
137
140
|
// Label the scope with the enclosing formula's blank node
|
|
138
141
|
// (using a dot as separator, as a blank node label cannot start with it)
|
|
139
142
|
this._prefixes._ = this._graph ? `${this._graph.value}.` : '.';
|
|
140
|
-
this.
|
|
143
|
+
this._quantifiedChanges = [];
|
|
141
144
|
}
|
|
142
145
|
// A formula starts empty and must not inherit its parent's subject
|
|
143
146
|
if (type === 'formula') {
|
|
@@ -163,11 +166,16 @@ class N3Parser {
|
|
|
163
166
|
if (this._n3Mode) {
|
|
164
167
|
this._inversePredicate = context.inverse;
|
|
165
168
|
this._expectOf = context.expectOf;
|
|
166
|
-
if (type === 'formula')
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
169
|
+
if (type === 'formula') [this._base, this._basePath, this._baseRoot, this._baseScheme] = context.base;
|
|
170
|
+
if (this._prefixChanges !== context.prefixChanges) {
|
|
171
|
+
undoChanges(this._prefixes, this._prefixChanges);
|
|
172
|
+
this._prefixChanges = context.prefixChanges;
|
|
173
|
+
}
|
|
174
|
+
this._prefixes._ = context.blankPrefix;
|
|
175
|
+
if (this._quantifiedChanges !== context.quantifiedChanges) {
|
|
176
|
+
undoChanges(this._quantified, this._quantifiedChanges);
|
|
177
|
+
this._quantifiedChanges = context.quantifiedChanges;
|
|
178
|
+
}
|
|
171
179
|
this._emptyFormula = context.emptyFormula;
|
|
172
180
|
}
|
|
173
181
|
}
|
|
@@ -976,6 +984,7 @@ class N3Parser {
|
|
|
976
984
|
_readPrefixIRI(token) {
|
|
977
985
|
if (token.type !== 'IRI') return this._error(`Expected IRI to follow prefix "${this._prefix}:"`, token);
|
|
978
986
|
const prefixNode = this._readEntity(token);
|
|
987
|
+
if (this._prefixChanges !== null) this._prefixChanges.push(this._prefix, this._prefixes[this._prefix]);
|
|
979
988
|
this._prefixes[this._prefix] = prefixNode.value;
|
|
980
989
|
this._prefixCallback(this._prefix, prefixNode);
|
|
981
990
|
return this._readDeclarationPunctuation;
|
|
@@ -1046,7 +1055,10 @@ class N3Parser {
|
|
|
1046
1055
|
return this._error(`Unexpected ${token.type}`, token);
|
|
1047
1056
|
}
|
|
1048
1057
|
// Without explicit quantifiers, map entities to a quantified entity
|
|
1049
|
-
if (!this._explicitQuantifiers)
|
|
1058
|
+
if (!this._explicitQuantifiers) {
|
|
1059
|
+
if (this._quantifiedChanges !== null) this._quantifiedChanges.push(entity.id, this._quantified[entity.id]);
|
|
1060
|
+
this._quantified[entity.id] = this._factory[this._quantifier](this._factory.blankNode().value);
|
|
1061
|
+
}
|
|
1050
1062
|
// With explicit quantifiers, output the reified quantifier
|
|
1051
1063
|
else {
|
|
1052
1064
|
// If this is the first item, start a new quantifier list
|
|
@@ -1407,7 +1419,10 @@ class N3Parser {
|
|
|
1407
1419
|
return this._base + iri;
|
|
1408
1420
|
// Resolve relative query string IRIs by replacing the query string
|
|
1409
1421
|
case '?':
|
|
1410
|
-
|
|
1422
|
+
{
|
|
1423
|
+
const queryPos = this._base.indexOf('?');
|
|
1424
|
+
return (queryPos < 0 ? this._base : this._base.substr(0, queryPos)) + iri;
|
|
1425
|
+
}
|
|
1411
1426
|
// Resolve root-relative IRIs at the root of the base IRI
|
|
1412
1427
|
case '/':
|
|
1413
1428
|
// Resolve scheme-relative IRIs to the scheme
|
|
@@ -1513,6 +1528,9 @@ class N3Parser {
|
|
|
1513
1528
|
this._inversePredicate = false;
|
|
1514
1529
|
this._expectOf = false;
|
|
1515
1530
|
this._quantified = Object.create(null);
|
|
1531
|
+
// Changes to prefixes and quantifiers in nested scopes, to undo when leaving them
|
|
1532
|
+
this._prefixChanges = null;
|
|
1533
|
+
this._quantifiedChanges = null;
|
|
1516
1534
|
this._emptyFormula = false;
|
|
1517
1535
|
let readToken = token => {
|
|
1518
1536
|
return this._readCallback = this._readCallback(token);
|
|
@@ -1569,8 +1587,15 @@ class N3Parser {
|
|
|
1569
1587
|
}
|
|
1570
1588
|
}
|
|
1571
1589
|
|
|
1572
|
-
//
|
|
1590
|
+
// ### `undoChanges` restores the entries of a map from a list of key and previous value pairs
|
|
1573
1591
|
exports.default = N3Parser;
|
|
1592
|
+
function undoChanges(map, changes) {
|
|
1593
|
+
for (let i = changes.length - 2; i >= 0; i -= 2) {
|
|
1594
|
+
if (changes[i + 1] === undefined) delete map[changes[i]];else map[changes[i]] = changes[i + 1];
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
|
|
1598
|
+
// The empty function
|
|
1574
1599
|
function noop() {}
|
|
1575
1600
|
|
|
1576
1601
|
// Initializes the parser with the given data factory
|
package/lib/N3Store.js
CHANGED
|
@@ -37,7 +37,10 @@ function merge(target, source, depth = 4) {
|
|
|
37
37
|
if (!(key in target)) {
|
|
38
38
|
size++;
|
|
39
39
|
target[key] = depth === 0 ? null : merge(Object.create(null), source[key], depth - 1);
|
|
40
|
-
}
|
|
40
|
+
}
|
|
41
|
+
// Merge into the existing object in place,
|
|
42
|
+
// as graph objects are frozen and cannot be reassigned
|
|
43
|
+
else if (depth !== 0) merge(target[key], source[key], depth - 1);
|
|
41
44
|
}
|
|
42
45
|
// Depth 2 is the level of the `subjects`, `predicates`, and `objects` indexes.
|
|
43
46
|
if (depth <= 2) target[SIZE] = size;
|
|
@@ -945,16 +948,20 @@ class N3Store {
|
|
|
945
948
|
}
|
|
946
949
|
|
|
947
950
|
// Store the list item and continue with parent
|
|
948
|
-
if (!first) malformed = onError(current, 'has no list head');else items.
|
|
951
|
+
if (!first) malformed = onError(current, 'has no list head');else items.push(first.object);
|
|
949
952
|
current = parent && parent.subject;
|
|
950
953
|
}
|
|
951
954
|
|
|
952
955
|
// Don't remove any quads if the list is malformed
|
|
953
956
|
if (malformed) remove = false;else {
|
|
957
|
+
// Items were collected from the tail to the head
|
|
958
|
+
items.reverse();
|
|
954
959
|
// Store the list under the value of its head
|
|
955
960
|
if (head) lists[head[headPos].value] = items;
|
|
956
961
|
// Leave lists with extra arcs fully intact; otherwise queue this list once.
|
|
957
|
-
if (remove && !extraArcs)
|
|
962
|
+
if (remove && !extraArcs) {
|
|
963
|
+
for (let i = 0; i < listQuads.length; i++) toRemove.push(listQuads[i]);
|
|
964
|
+
}
|
|
958
965
|
}
|
|
959
966
|
});
|
|
960
967
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "n3",
|
|
3
|
-
"version": "2.11.
|
|
3
|
+
"version": "2.11.1",
|
|
4
4
|
"description": "Lightning fast, asynchronous, streaming Turtle / N3 / RDF library.",
|
|
5
5
|
"author": "Ruben Verborgh <ruben.verborgh@gmail.com>",
|
|
6
6
|
"keywords": [
|
|
@@ -83,6 +83,17 @@
|
|
|
83
83
|
"spec-1-2-earl-nquads": "rdf-test-suite spec/parser.js https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-n-quads/syntax/manifest.ttl -i '{ \"format\": \"n-quads\" }' -c .rdf-test-suite-cache/ -o earl -p spec/earl-meta.json > spec/earl-nquads.ttl",
|
|
84
84
|
"spec-1-2-earl-turtle": "rdf-test-suite spec/parser.js https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-turtle/syntax/manifest.ttl -i '{ \"format\": \"turtle\" }' -c .rdf-test-suite-cache/ -o earl -p spec/earl-meta.json > spec/earl-turtle.ttl",
|
|
85
85
|
"spec-1-2-earl-trig": "rdf-test-suite spec/parser.js https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-trig/syntax/manifest.ttl -i '{ \"format\": \"trig\" }' -c .rdf-test-suite-cache/ -o earl -p spec/earl-meta.json > spec/earl-trig.ttl",
|
|
86
|
+
"spec-writer": "npm run spec-writer-1-1-turtle && npm run spec-writer-1-1-ntriples && npm run spec-writer-1-1-nquads && npm run spec-writer-1-1-trig && npm run spec-writer-1-2-turtle && npm run spec-writer-1-2-ntriples && npm run spec-writer-1-2-nquads && npm run spec-writer-1-2-trig && npm run spec-writer-1-2-turtle-eval && npm run spec-writer-1-2-trig-eval",
|
|
87
|
+
"spec-writer-1-1-turtle": "rdf-test-suite spec/writer.js https://w3c.github.io/rdf-tests/rdf/rdf11/rdf-turtle/manifest.ttl -i '{ \"format\": \"turtle\" }' -c .rdf-test-suite-cache/ --skip \"(bad-numeric-escape|bareword_decimal)\"",
|
|
88
|
+
"spec-writer-1-1-ntriples": "rdf-test-suite spec/writer.js https://w3c.github.io/rdf-tests/rdf/rdf11/rdf-n-triples/manifest.ttl -i '{ \"format\": \"n-triples\" }' -c .rdf-test-suite-cache/",
|
|
89
|
+
"spec-writer-1-1-nquads": "rdf-test-suite spec/writer.js https://w3c.github.io/rdf-tests/rdf/rdf11/rdf-n-quads/manifest.ttl -i '{ \"format\": \"n-quads\" }' -c .rdf-test-suite-cache/",
|
|
90
|
+
"spec-writer-1-1-trig": "rdf-test-suite spec/writer.js https://w3c.github.io/rdf-tests/rdf/rdf11/rdf-trig/manifest.ttl -i '{ \"format\": \"trig\" }' -c .rdf-test-suite-cache/ --skip \"(bad-numeric-escape|IRI-resolution-01)\"",
|
|
91
|
+
"spec-writer-1-2-turtle": "rdf-test-suite spec/writer.js https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-turtle/syntax/manifest.ttl -i '{ \"format\": \"turtle\" }' -c .rdf-test-suite-cache/",
|
|
92
|
+
"spec-writer-1-2-ntriples": "rdf-test-suite spec/writer.js https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-n-triples/syntax/manifest.ttl -i '{ \"format\": \"n-triples\" }' -c .rdf-test-suite-cache/",
|
|
93
|
+
"spec-writer-1-2-nquads": "rdf-test-suite spec/writer.js https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-n-quads/syntax/manifest.ttl -i '{ \"format\": \"n-quads\" }' -c .rdf-test-suite-cache/",
|
|
94
|
+
"spec-writer-1-2-trig": "rdf-test-suite spec/writer.js https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-trig/syntax/manifest.ttl -i '{ \"format\": \"trig\" }' -c .rdf-test-suite-cache/",
|
|
95
|
+
"spec-writer-1-2-turtle-eval": "rdf-test-suite spec/writer.js https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-turtle/eval/manifest.ttl -i '{ \"format\": \"turtle\" }' -c .rdf-test-suite-cache/",
|
|
96
|
+
"spec-writer-1-2-trig-eval": "rdf-test-suite spec/writer.js https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-trig/eval/manifest.ttl -i '{ \"format\": \"trig\" }' -c .rdf-test-suite-cache/",
|
|
86
97
|
"spec-n3": "npm run spec-n3-parser && npm run spec-n3-extended",
|
|
87
98
|
"spec-n3-fetch": "sh scripts/fetch-n3-tests.sh",
|
|
88
99
|
"spec-n3-parser": "npm run spec-n3-fetch && rdf-test-suite spec/parser.js https://w3c-cg.github.io/N3/tests/N3Tests/manifest-parser.ttl -i '{ \"format\": \"text/n3\" }' -m 'https://w3c-cg.github.io/N3/tests/~.n3-tests/tests/'",
|
|
@@ -126,7 +137,28 @@
|
|
|
126
137
|
},
|
|
127
138
|
"release": {
|
|
128
139
|
"branches": [
|
|
129
|
-
"main"
|
|
140
|
+
"main",
|
|
141
|
+
{
|
|
142
|
+
"name": "next-major",
|
|
143
|
+
"prerelease": "alpha",
|
|
144
|
+
"channel": "alpha"
|
|
145
|
+
}
|
|
146
|
+
],
|
|
147
|
+
"plugins": [
|
|
148
|
+
[
|
|
149
|
+
"@semantic-release/commit-analyzer",
|
|
150
|
+
{
|
|
151
|
+
"preset": "conventionalcommits"
|
|
152
|
+
}
|
|
153
|
+
],
|
|
154
|
+
[
|
|
155
|
+
"@semantic-release/release-notes-generator",
|
|
156
|
+
{
|
|
157
|
+
"preset": "conventionalcommits"
|
|
158
|
+
}
|
|
159
|
+
],
|
|
160
|
+
"@semantic-release/npm",
|
|
161
|
+
"@semantic-release/github"
|
|
130
162
|
]
|
|
131
163
|
},
|
|
132
164
|
"publishConfig": {
|
package/src/BaseIRI.js
CHANGED
|
@@ -4,7 +4,9 @@ import { escapeRegex } from './Util';
|
|
|
4
4
|
// - file: IRIs (which could also use backslashes)
|
|
5
5
|
// - IRIs containing /. or /.. or //
|
|
6
6
|
const BASE_UNSUPPORTED = /^:?[^:?#]*(?:[?#]|$)|^file:|^[^:]*:\/*[^?#]+?\/(?:\.\.?(?:\/|$)|\/)/i;
|
|
7
|
-
|
|
7
|
+
// Supported suffixes have a first path segment other than . or ..,
|
|
8
|
+
// and further path segments of at least 3 characters
|
|
9
|
+
const SUFFIX_SUPPORTED = /^(?:(?!\.\.?(?:[/?#]|$))[^/?#]+(?:\/[^/?#]{3,})*\/?)?(?:[?#]|$)/;
|
|
8
10
|
const CURRENT = './';
|
|
9
11
|
const PARENT = '../';
|
|
10
12
|
const QUERY = '?';
|
|
@@ -88,8 +90,10 @@ export default class BaseIRI {
|
|
|
88
90
|
// Don't abbreviate unsupported path
|
|
89
91
|
if (parentPath !== QUERY && !SUFFIX_SUPPORTED.test(suffix))
|
|
90
92
|
return iri;
|
|
91
|
-
// Omit ./ with fragment or query string
|
|
92
|
-
|
|
93
|
+
// Omit ./ with fragment or query string,
|
|
94
|
+
// unless the first segment has a colon and would be read as a scheme
|
|
95
|
+
if (parentPath === CURRENT && /^[^?#]/.test(suffix) &&
|
|
96
|
+
(suffix.indexOf(':') < 0 || !/^[^/?#]*:/.test(suffix)))
|
|
93
97
|
return suffix;
|
|
94
98
|
// Append suffix to relative parent path
|
|
95
99
|
return parentPath + suffix;
|
package/src/N3DataFactory.js
CHANGED
|
@@ -499,7 +499,8 @@ export function fromTerm(term) {
|
|
|
499
499
|
case 'BlankNode': return blankNode(term.value);
|
|
500
500
|
case 'Variable': return variable(term.value);
|
|
501
501
|
case 'DefaultGraph': return DEFAULTGRAPH;
|
|
502
|
-
case 'Literal': return literal(term.value, term.language
|
|
502
|
+
case 'Literal': return literal(term.value, !term.language ? term.datatype :
|
|
503
|
+
term.direction ? { language: term.language, direction: term.direction } : term.language);
|
|
503
504
|
case 'Quad': return fromQuad(term);
|
|
504
505
|
default: throw new Error(`Unexpected termType: ${term.termType}`);
|
|
505
506
|
}
|
package/src/N3Lexer.js
CHANGED
|
@@ -17,6 +17,8 @@ const localNameEscapeReplacements = {
|
|
|
17
17
|
'=': '=', '/': '/', '?': '?', '#': '#', '@': '@', '%': '%',
|
|
18
18
|
};
|
|
19
19
|
const illegalIriChars = /[\x00-\x20<>\\"\{\}\|\^\`]/;
|
|
20
|
+
// Characters that cannot occur in a prefixed name, not even escaped
|
|
21
|
+
const nonPrefixedNameChar = /[\s<>"{}|^`]/;
|
|
20
22
|
|
|
21
23
|
// A valid code point is a Unicode scalar value: at most U+10FFFF and not a surrogate
|
|
22
24
|
function isValidCodePoint(charCode) {
|
|
@@ -45,10 +47,10 @@ export default class N3Lexer {
|
|
|
45
47
|
this._simpleApostropheString = /^'([^'\\\r\n]*)'(?=[^'])/;
|
|
46
48
|
this._langcode = /^@([a-z]+(?:-[a-z0-9]+)*)(?=[^a-z0-9])/i;
|
|
47
49
|
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<])/;
|
|
48
|
-
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
|
|
49
|
-
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
|
|
50
|
+
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-9: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-9: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-9: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#()\[\]\{\}"'<>]))/;
|
|
51
|
+
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-9: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#()\[\]\{\}"'<>])/;
|
|
50
52
|
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#()\[\]\{\}"'<>]))/;
|
|
51
|
-
this._number = /^[\-+]?(?:(\d+\.\d*|\.?\d+)[eE][\-+]
|
|
53
|
+
this._number = /^[\-+]?(?:(\d+\.\d*|\.?\d+)[eE][\-+]?\d+|(?=\.?\d)\d*(?:(\.)\d+)?)(?=\.?[,;:!\^\s#()\[\]\{\}"'<>])/;
|
|
52
54
|
this._boolean = /^(?:true|false)(?=[.,;!\^\s#()\[\]\{\}"'<>])/;
|
|
53
55
|
this._atKeyword = /^@[a-z]+(?=[\s#<:])/i;
|
|
54
56
|
this._keyword = /^(?:PREFIX|BASE|VERSION|GRAPH)(?=[\s#<])/i;
|
|
@@ -542,7 +544,14 @@ export default class N3Lexer {
|
|
|
542
544
|
|
|
543
545
|
// A prefix can start with a verb and continue with characters that are also
|
|
544
546
|
// valid verb boundaries. Prefer the longer prefixed name when it is complete.
|
|
545
|
-
if (this._prefixed.exec(input)
|
|
547
|
+
if (this._prefixed.exec(input))
|
|
548
|
+
return null;
|
|
549
|
+
// Appending to the input only matters when a prefixed name could run up to
|
|
550
|
+
// its end, which a character that cannot occur in prefixed names rules out.
|
|
551
|
+
// This avoids copying the rest of the document for every such verb.
|
|
552
|
+
if (nonPrefixedNameChar.test(input))
|
|
553
|
+
return verb;
|
|
554
|
+
if (this._prefixed.exec(`${input} `))
|
|
546
555
|
return null;
|
|
547
556
|
|
|
548
557
|
// If a stream chunk ends partway through such a prefix, wait for the colon
|
package/src/N3Parser.js
CHANGED
|
@@ -18,7 +18,7 @@ export default class N3Parser {
|
|
|
18
18
|
|
|
19
19
|
// Set supported features depending on the format
|
|
20
20
|
const format = (typeof options.format === 'string') ?
|
|
21
|
-
options.format.match(
|
|
21
|
+
options.format.match(/(?:^|\W)(\w*)$/)[1].toLowerCase() : '',
|
|
22
22
|
isTurtle = /turtle/.test(format), isTriG = /trig/.test(format),
|
|
23
23
|
isNTriples = /triple/.test(format), isNQuads = /quad/.test(format),
|
|
24
24
|
isN3 = this._n3Mode = /n3/.test(format),
|
|
@@ -78,8 +78,10 @@ export default class N3Parser {
|
|
|
78
78
|
baseIRI = baseIRI.substr(0, fragmentPos);
|
|
79
79
|
// Set base IRI and its components
|
|
80
80
|
this._base = baseIRI;
|
|
81
|
+
const queryPos = baseIRI.indexOf('?');
|
|
82
|
+
const path = queryPos < 0 ? baseIRI : baseIRI.substr(0, queryPos);
|
|
81
83
|
this._basePath = baseIRI.indexOf('/') < 0 ? baseIRI :
|
|
82
|
-
|
|
84
|
+
path.substr(0, path.lastIndexOf('/') + 1);
|
|
83
85
|
baseIRI = baseIRI.match(/^(?:([a-z][a-z0-9+.-]*:))?(?:\/\/[^\/]*)?/i);
|
|
84
86
|
this._baseRoot = baseIRI[0];
|
|
85
87
|
this._baseScheme = baseIRI[1];
|
|
@@ -100,14 +102,15 @@ export default class N3Parser {
|
|
|
100
102
|
inverse: this._inversePredicate,
|
|
101
103
|
expectOf: this._expectOf,
|
|
102
104
|
blankPrefix: this._prefixes._,
|
|
103
|
-
|
|
105
|
+
prefixChanges: this._prefixChanges,
|
|
106
|
+
quantifiedChanges: this._quantifiedChanges,
|
|
104
107
|
emptyFormula: this._emptyFormula,
|
|
105
108
|
};
|
|
106
|
-
// Prefix and base declarations are scoped to their formula
|
|
109
|
+
// Prefix and base declarations are scoped to their formula,
|
|
110
|
+
// so record prefix changes to undo them when the formula ends
|
|
107
111
|
if (type === 'formula') {
|
|
108
|
-
context.prefixes = this._prefixes;
|
|
109
112
|
context.base = [this._base, this._basePath, this._baseRoot, this._baseScheme];
|
|
110
|
-
this.
|
|
113
|
+
this._prefixChanges = [];
|
|
111
114
|
}
|
|
112
115
|
this._contextStack.push(context);
|
|
113
116
|
// Every new scope resets the predicate direction
|
|
@@ -120,7 +123,7 @@ export default class N3Parser {
|
|
|
120
123
|
// Label the scope with the enclosing formula's blank node
|
|
121
124
|
// (using a dot as separator, as a blank node label cannot start with it)
|
|
122
125
|
this._prefixes._ = (this._graph ? `${this._graph.value}.` : '.');
|
|
123
|
-
this.
|
|
126
|
+
this._quantifiedChanges = [];
|
|
124
127
|
}
|
|
125
128
|
// A formula starts empty and must not inherit its parent's subject
|
|
126
129
|
if (type === 'formula') {
|
|
@@ -147,13 +150,17 @@ export default class N3Parser {
|
|
|
147
150
|
if (this._n3Mode) {
|
|
148
151
|
this._inversePredicate = context.inverse;
|
|
149
152
|
this._expectOf = context.expectOf;
|
|
150
|
-
if (type === 'formula')
|
|
151
|
-
this._prefixes = context.prefixes;
|
|
153
|
+
if (type === 'formula')
|
|
152
154
|
[this._base, this._basePath, this._baseRoot, this._baseScheme] = context.base;
|
|
155
|
+
if (this._prefixChanges !== context.prefixChanges) {
|
|
156
|
+
undoChanges(this._prefixes, this._prefixChanges);
|
|
157
|
+
this._prefixChanges = context.prefixChanges;
|
|
158
|
+
}
|
|
159
|
+
this._prefixes._ = context.blankPrefix;
|
|
160
|
+
if (this._quantifiedChanges !== context.quantifiedChanges) {
|
|
161
|
+
undoChanges(this._quantified, this._quantifiedChanges);
|
|
162
|
+
this._quantifiedChanges = context.quantifiedChanges;
|
|
153
163
|
}
|
|
154
|
-
else
|
|
155
|
-
this._prefixes._ = context.blankPrefix;
|
|
156
|
-
this._quantified = context.quantified;
|
|
157
164
|
this._emptyFormula = context.emptyFormula;
|
|
158
165
|
}
|
|
159
166
|
}
|
|
@@ -1055,6 +1062,8 @@ export default class N3Parser {
|
|
|
1055
1062
|
if (token.type !== 'IRI')
|
|
1056
1063
|
return this._error(`Expected IRI to follow prefix "${this._prefix}:"`, token);
|
|
1057
1064
|
const prefixNode = this._readEntity(token);
|
|
1065
|
+
if (this._prefixChanges !== null)
|
|
1066
|
+
this._prefixChanges.push(this._prefix, this._prefixes[this._prefix]);
|
|
1058
1067
|
this._prefixes[this._prefix] = prefixNode.value;
|
|
1059
1068
|
this._prefixCallback(this._prefix, prefixNode);
|
|
1060
1069
|
return this._readDeclarationPunctuation;
|
|
@@ -1133,8 +1142,11 @@ export default class N3Parser {
|
|
|
1133
1142
|
return this._error(`Unexpected ${token.type}`, token);
|
|
1134
1143
|
}
|
|
1135
1144
|
// Without explicit quantifiers, map entities to a quantified entity
|
|
1136
|
-
if (!this._explicitQuantifiers)
|
|
1145
|
+
if (!this._explicitQuantifiers) {
|
|
1146
|
+
if (this._quantifiedChanges !== null)
|
|
1147
|
+
this._quantifiedChanges.push(entity.id, this._quantified[entity.id]);
|
|
1137
1148
|
this._quantified[entity.id] = this._factory[this._quantifier](this._factory.blankNode().value);
|
|
1149
|
+
}
|
|
1138
1150
|
// With explicit quantifiers, output the reified quantifier
|
|
1139
1151
|
else {
|
|
1140
1152
|
// If this is the first item, start a new quantifier list
|
|
@@ -1521,7 +1533,10 @@ export default class N3Parser {
|
|
|
1521
1533
|
// Resolve relative fragment IRIs against the base IRI
|
|
1522
1534
|
case '#': return this._base + iri;
|
|
1523
1535
|
// Resolve relative query string IRIs by replacing the query string
|
|
1524
|
-
case '?':
|
|
1536
|
+
case '?': {
|
|
1537
|
+
const queryPos = this._base.indexOf('?');
|
|
1538
|
+
return (queryPos < 0 ? this._base : this._base.substr(0, queryPos)) + iri;
|
|
1539
|
+
}
|
|
1525
1540
|
// Resolve root-relative IRIs at the root of the base IRI
|
|
1526
1541
|
case '/':
|
|
1527
1542
|
// Resolve scheme-relative IRIs to the scheme
|
|
@@ -1632,6 +1647,9 @@ export default class N3Parser {
|
|
|
1632
1647
|
this._inversePredicate = false;
|
|
1633
1648
|
this._expectOf = false;
|
|
1634
1649
|
this._quantified = Object.create(null);
|
|
1650
|
+
// Changes to prefixes and quantifiers in nested scopes, to undo when leaving them
|
|
1651
|
+
this._prefixChanges = null;
|
|
1652
|
+
this._quantifiedChanges = null;
|
|
1635
1653
|
this._emptyFormula = false;
|
|
1636
1654
|
|
|
1637
1655
|
let readToken = token => {
|
|
@@ -1694,6 +1712,16 @@ export default class N3Parser {
|
|
|
1694
1712
|
}
|
|
1695
1713
|
}
|
|
1696
1714
|
|
|
1715
|
+
// ### `undoChanges` restores the entries of a map from a list of key and previous value pairs
|
|
1716
|
+
function undoChanges(map, changes) {
|
|
1717
|
+
for (let i = changes.length - 2; i >= 0; i -= 2) {
|
|
1718
|
+
if (changes[i + 1] === undefined)
|
|
1719
|
+
delete map[changes[i]];
|
|
1720
|
+
else
|
|
1721
|
+
map[changes[i]] = changes[i + 1];
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
|
|
1697
1725
|
// The empty function
|
|
1698
1726
|
function noop() {}
|
|
1699
1727
|
|
package/src/N3Store.js
CHANGED
|
@@ -30,8 +30,10 @@ function merge(target, source, depth = 4) {
|
|
|
30
30
|
size++;
|
|
31
31
|
target[key] = depth === 0 ? null : merge(Object.create(null), source[key], depth - 1);
|
|
32
32
|
}
|
|
33
|
+
// Merge into the existing object in place,
|
|
34
|
+
// as graph objects are frozen and cannot be reassigned
|
|
33
35
|
else if (depth !== 0)
|
|
34
|
-
|
|
36
|
+
merge(target[key], source[key], depth - 1);
|
|
35
37
|
}
|
|
36
38
|
// Depth 2 is the level of the `subjects`, `predicates`, and `objects` indexes.
|
|
37
39
|
if (depth <= 2)
|
|
@@ -1010,7 +1012,7 @@ export default class N3Store {
|
|
|
1010
1012
|
if (!first)
|
|
1011
1013
|
malformed = onError(current, 'has no list head');
|
|
1012
1014
|
else
|
|
1013
|
-
items.
|
|
1015
|
+
items.push(first.object);
|
|
1014
1016
|
current = parent && parent.subject;
|
|
1015
1017
|
}
|
|
1016
1018
|
|
|
@@ -1018,12 +1020,16 @@ export default class N3Store {
|
|
|
1018
1020
|
if (malformed)
|
|
1019
1021
|
remove = false;
|
|
1020
1022
|
else {
|
|
1023
|
+
// Items were collected from the tail to the head
|
|
1024
|
+
items.reverse();
|
|
1021
1025
|
// Store the list under the value of its head
|
|
1022
1026
|
if (head)
|
|
1023
1027
|
lists[head[headPos].value] = items;
|
|
1024
1028
|
// Leave lists with extra arcs fully intact; otherwise queue this list once.
|
|
1025
|
-
if (remove && !extraArcs)
|
|
1026
|
-
|
|
1029
|
+
if (remove && !extraArcs) {
|
|
1030
|
+
for (let i = 0; i < listQuads.length; i++)
|
|
1031
|
+
toRemove.push(listQuads[i]);
|
|
1032
|
+
}
|
|
1027
1033
|
}
|
|
1028
1034
|
});
|
|
1029
1035
|
|