n3 2.7.1 → 2.7.3
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 +4 -4
- package/browser/n3.min.js +7 -7
- package/lib/N3Lexer.js +25 -2
- package/lib/N3Parser.js +41 -7
- package/lib/N3Store.js +27 -20
- package/package.json +1 -1
- package/src/N3Lexer.js +29 -2
- package/src/N3Parser.js +46 -11
- package/src/N3Store.js +34 -20
package/lib/N3Lexer.js
CHANGED
|
@@ -322,11 +322,11 @@ class N3Lexer {
|
|
|
322
322
|
case 'h':
|
|
323
323
|
case 'o':
|
|
324
324
|
// Try to find an N3 verb keyword
|
|
325
|
-
if (this._n3Mode && (match = this.
|
|
325
|
+
if (this._n3Mode && (match = this._matchN3Verb(input, inputFinished))) type = match[0];else inconclusive = true;
|
|
326
326
|
break;
|
|
327
327
|
case 'i':
|
|
328
328
|
// Try to find an IRI property list identifier or N3 verb keyword
|
|
329
|
-
if (this._n3Mode && (match = this._n3Id.exec(input))) type = 'id';else if (this._n3Mode && (match = this.
|
|
329
|
+
if (this._n3Mode && (match = this._n3Id.exec(input))) type = 'id';else if (this._n3Mode && (match = this._matchN3Verb(input, inputFinished))) type = match[0];else inconclusive = true;
|
|
330
330
|
break;
|
|
331
331
|
case '=':
|
|
332
332
|
// Try to find an implication arrow or equals sign
|
|
@@ -438,6 +438,29 @@ class N3Lexer {
|
|
|
438
438
|
}
|
|
439
439
|
}
|
|
440
440
|
|
|
441
|
+
// ### `_matchN3Verb` matches an N3 verb unless the input is a longer prefixed name
|
|
442
|
+
_matchN3Verb(input, inputFinished) {
|
|
443
|
+
const verb = this._n3Verb.exec(input);
|
|
444
|
+
if (!verb) return null;
|
|
445
|
+
|
|
446
|
+
// Most verb boundaries cannot be part of a prefix, so keep the common path fast.
|
|
447
|
+
const next = input[verb[0].length];
|
|
448
|
+
if (next !== '-' && next !== '_' && (next < '0' || next > '9')) return verb;
|
|
449
|
+
|
|
450
|
+
// A prefix can start with a verb and continue with characters that are also
|
|
451
|
+
// valid verb boundaries. Prefer the longer prefixed name when it is complete.
|
|
452
|
+
if (this._prefixed.exec(input) || this._prefixed.exec(`${input} `)) return null;
|
|
453
|
+
|
|
454
|
+
// If a stream chunk ends partway through such a prefix, wait for the colon
|
|
455
|
+
// instead of prematurely emitting the verb. Appending ": " lets the prefix
|
|
456
|
+
// grammar determine whether all input seen so far can be a complete prefix.
|
|
457
|
+
if (!inputFinished) {
|
|
458
|
+
const prefix = this._prefix.exec(`${input}: `);
|
|
459
|
+
if (prefix) return null;
|
|
460
|
+
}
|
|
461
|
+
return verb;
|
|
462
|
+
}
|
|
463
|
+
|
|
441
464
|
// ### `_unescape` replaces N3 escape codes by their corresponding characters,
|
|
442
465
|
// allowing only the fixed escape sequences from the given replacement table
|
|
443
466
|
_unescape(item, replacements) {
|
package/lib/N3Parser.js
CHANGED
|
@@ -31,6 +31,13 @@ class N3Parser {
|
|
|
31
31
|
isNQuads = /quad/.test(format),
|
|
32
32
|
isN3 = this._n3Mode = /n3/.test(format),
|
|
33
33
|
isLineMode = isNTriples || isNQuads;
|
|
34
|
+
// Keep inverse handling off the non-N3 emission path
|
|
35
|
+
this._emitCurrent = this._emit;
|
|
36
|
+
if (isN3) {
|
|
37
|
+
this._createQuad = this._createQuadInDirection;
|
|
38
|
+
this._emit = this._emitInDirection;
|
|
39
|
+
this._emitCurrent = this._emitCurrentInDirection;
|
|
40
|
+
}
|
|
34
41
|
if (!(this._supportsNamedGraphs = !(isTurtle || isN3))) this._readPredicateOrNamedGraph = this._readPredicate;
|
|
35
42
|
// Support triples in other graphs
|
|
36
43
|
this._supportsQuads = !(isTurtle || isTriG || isNTriples || isN3);
|
|
@@ -514,7 +521,7 @@ class N3Parser {
|
|
|
514
521
|
if (token.type !== ']') return this._readBlankNodePunctuation(token);
|
|
515
522
|
|
|
516
523
|
// Store blank node quad
|
|
517
|
-
if (this._subject !== null) this.
|
|
524
|
+
if (this._subject !== null) this._emitCurrent(this._subject, this._predicate, this._object, this._graph);
|
|
518
525
|
|
|
519
526
|
// Restore the parent context containing this blank node
|
|
520
527
|
const empty = this._predicate === null;
|
|
@@ -841,7 +848,7 @@ class N3Parser {
|
|
|
841
848
|
if (token.type !== '}') return this._readPunctuation(token);
|
|
842
849
|
|
|
843
850
|
// Store the last quad of the formula
|
|
844
|
-
if (this._subject !== null) this.
|
|
851
|
+
if (this._subject !== null) this._emitCurrent(this._subject, this._predicate, this._object, this._graph);
|
|
845
852
|
const formula = this._graph,
|
|
846
853
|
empty = this._emptyFormula;
|
|
847
854
|
// Restore the parent context containing this formula
|
|
@@ -882,6 +889,7 @@ class N3Parser {
|
|
|
882
889
|
break;
|
|
883
890
|
// Semicolon means the subject is shared; predicate and object are different
|
|
884
891
|
case ';':
|
|
892
|
+
if (inversePredicate) this._inversePredicate = false;
|
|
885
893
|
next = this._readPredicate;
|
|
886
894
|
break;
|
|
887
895
|
// Comma means both the subject and predicate are shared; the object is different
|
|
@@ -902,6 +910,7 @@ class N3Parser {
|
|
|
902
910
|
// Same staleness rule as ~ above.
|
|
903
911
|
if (subject !== null) this._tripleTerm = null;
|
|
904
912
|
this._subject = this._readTripleTerm();
|
|
913
|
+
this._inversePredicate = false;
|
|
905
914
|
this._validAnnotation = false;
|
|
906
915
|
startingAnnotation = true;
|
|
907
916
|
next = this._readPredicate;
|
|
@@ -912,6 +921,7 @@ class N3Parser {
|
|
|
912
921
|
if (!this._validAnnotation) return this._error('Annotation block can not be empty', token);
|
|
913
922
|
this._subject = null;
|
|
914
923
|
this._annotation = false;
|
|
924
|
+
this._inversePredicate = false;
|
|
915
925
|
next = this._getContextEndReader();
|
|
916
926
|
break;
|
|
917
927
|
default:
|
|
@@ -926,7 +936,7 @@ class N3Parser {
|
|
|
926
936
|
if (subject !== null && (!startingAnnotation || startingAnnotation && !this._annotation)) {
|
|
927
937
|
const predicate = this._predicate,
|
|
928
938
|
object = this._object;
|
|
929
|
-
|
|
939
|
+
this._emit(subject, predicate, object, graph, inversePredicate);
|
|
930
940
|
}
|
|
931
941
|
if (startingAnnotation) {
|
|
932
942
|
this._annotation = true;
|
|
@@ -936,10 +946,12 @@ class N3Parser {
|
|
|
936
946
|
|
|
937
947
|
// ### `_readBlankNodePunctuation` reads punctuation in a blank node
|
|
938
948
|
_readBlankNodePunctuation(token) {
|
|
939
|
-
let next
|
|
949
|
+
let next,
|
|
950
|
+
resetInversePredicate = false;
|
|
940
951
|
switch (token.type) {
|
|
941
952
|
// Semicolon means the subject is shared; predicate and object are different
|
|
942
953
|
case ';':
|
|
954
|
+
resetInversePredicate = this._inversePredicate;
|
|
943
955
|
next = this._readPredicate;
|
|
944
956
|
break;
|
|
945
957
|
// Comma means both the subject and predicate are shared; the object is different
|
|
@@ -961,7 +973,8 @@ class N3Parser {
|
|
|
961
973
|
// nothing left to share with a following predicate-object pair
|
|
962
974
|
if (this._subject === null) return this._error('Expected ] to follow annotation', token);
|
|
963
975
|
// A quad has been completed now, so return it
|
|
964
|
-
this.
|
|
976
|
+
this._emitCurrent(this._subject, this._predicate, this._object, this._graph);
|
|
977
|
+
if (resetInversePredicate) this._inversePredicate = false;
|
|
965
978
|
return next;
|
|
966
979
|
}
|
|
967
980
|
|
|
@@ -1158,7 +1171,7 @@ class N3Parser {
|
|
|
1158
1171
|
_readTripleTermTail(token) {
|
|
1159
1172
|
if (token.type !== ')>>') return this._error(`Expected )>> but got ${token.type}`, token);
|
|
1160
1173
|
// Read the quad and restore the previous context
|
|
1161
|
-
const quad = this.
|
|
1174
|
+
const quad = this._createQuad(this._subject, this._predicate, this._object, this._graph, this._inversePredicate);
|
|
1162
1175
|
this._restoreContext('<<(', token);
|
|
1163
1176
|
|
|
1164
1177
|
// If we're in a list, continue processing that list
|
|
@@ -1257,6 +1270,7 @@ class N3Parser {
|
|
|
1257
1270
|
switch (token.type) {
|
|
1258
1271
|
// The subject stays shared with the next predicate-object pair
|
|
1259
1272
|
case ';':
|
|
1273
|
+
this._inversePredicate = false;
|
|
1260
1274
|
return this._readPredicate;
|
|
1261
1275
|
// The subject and predicate stay shared with the next object
|
|
1262
1276
|
case ',':
|
|
@@ -1274,7 +1288,7 @@ class N3Parser {
|
|
|
1274
1288
|
const parentGraph = parent ? parent.graph : undefined;
|
|
1275
1289
|
const reifier = this._reifier || this._factory.blankNode();
|
|
1276
1290
|
this._reifier = null;
|
|
1277
|
-
this._tripleTerm = this._tripleTerm || this.
|
|
1291
|
+
this._tripleTerm = this._tripleTerm || this._createQuad(this._subject, this._predicate, this._object, null, this._inversePredicate);
|
|
1278
1292
|
this._emit(reifier, this.RDF_REIFIES, this._tripleTerm, parentGraph || this._graph || this.DEFAULTGRAPH);
|
|
1279
1293
|
return reifier;
|
|
1280
1294
|
}
|
|
@@ -1297,6 +1311,26 @@ class N3Parser {
|
|
|
1297
1311
|
}
|
|
1298
1312
|
}
|
|
1299
1313
|
|
|
1314
|
+
// ### `_createQuad` creates a quad
|
|
1315
|
+
_createQuad(subject, predicate, object, graph) {
|
|
1316
|
+
return this._factory.quad(subject, predicate, object, graph || this.DEFAULTGRAPH);
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
// ### `_createQuadInDirection` creates a quad in the active predicate direction
|
|
1320
|
+
_createQuadInDirection(subject, predicate, object, graph, inversePredicate) {
|
|
1321
|
+
return inversePredicate ? this._factory.quad(object, predicate, subject, graph || this.DEFAULTGRAPH) : this._factory.quad(subject, predicate, object, graph || this.DEFAULTGRAPH);
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
// ### `_emitInDirection` sends a quad in the active predicate direction
|
|
1325
|
+
_emitInDirection(subject, predicate, object, graph, inversePredicate) {
|
|
1326
|
+
this._callback(null, this._createQuad(subject, predicate, object, graph, inversePredicate));
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
// ### `_emitCurrentInDirection` sends a quad in the current predicate direction
|
|
1330
|
+
_emitCurrentInDirection(subject, predicate, object, graph) {
|
|
1331
|
+
this._callback(null, this._createQuad(subject, predicate, object, graph, this._inversePredicate));
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1300
1334
|
// ### `_emit` sends a quad through the callback
|
|
1301
1335
|
_emit(subject, predicate, object, graph) {
|
|
1302
1336
|
this._callback(null, this._factory.quad(subject, predicate, object, graph || this.DEFAULTGRAPH));
|
package/lib/N3Store.js
CHANGED
|
@@ -249,13 +249,12 @@ class N3Store {
|
|
|
249
249
|
|
|
250
250
|
// ### `_findInIndex` finds a set of quads in a three-layered index.
|
|
251
251
|
// The index base is `index0` and the keys at each level are `key0`, `key1`, and `key2`.
|
|
252
|
-
//
|
|
252
|
+
// A key and any keys after it can be null or undefined, which is interpreted as a wildcard.
|
|
253
253
|
// `name0`, `name1`, and `name2` are the names of the keys at each level,
|
|
254
254
|
// used when reconstructing the resulting quad
|
|
255
255
|
// (for instance: _subject_, _predicate_, and _object_).
|
|
256
256
|
// Finally, `graphId` will be the graph of the created quads.
|
|
257
257
|
*_findInIndex(index0, key0, key1, key2, name0, name1, name2, graphId) {
|
|
258
|
-
let tmp, index1, index2;
|
|
259
258
|
const entityKeys = this._entities;
|
|
260
259
|
const graph = this._termFromId(entityKeys[graphId]);
|
|
261
260
|
const parts = {
|
|
@@ -264,24 +263,32 @@ class N3Store {
|
|
|
264
263
|
object: null
|
|
265
264
|
};
|
|
266
265
|
|
|
267
|
-
//
|
|
268
|
-
if (
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
266
|
+
// Exact matches avoid allocating key arrays or entering generic loops.
|
|
267
|
+
if (key2) {
|
|
268
|
+
const index1 = index0[key0];
|
|
269
|
+
const index2 = index1 && index1[key1];
|
|
270
|
+
if (!index2 || !(key2 in index2)) return;
|
|
271
|
+
parts[name0] = this._termFromId(entityKeys[key0]);
|
|
272
|
+
parts[name1] = this._termFromId(entityKeys[key1]);
|
|
273
|
+
parts[name2] = this._termFromId(entityKeys[key2]);
|
|
274
|
+
yield this._factory.quad(parts.subject, parts.predicate, parts.object, graph);
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
if (key0 && !(key0 in index0)) return;
|
|
278
|
+
// A null key list stops after visiting a bound key, avoiding a one-item array.
|
|
279
|
+
const keys0 = key0 ? null : Object.keys(index0);
|
|
280
|
+
for (let i0 = 0, value0 = key0 || keys0[0]; value0; value0 = keys0 && keys0[++i0]) {
|
|
281
|
+
const index1 = index0[value0];
|
|
282
|
+
parts[name0] = this._termFromId(entityKeys[value0]);
|
|
283
|
+
if (key1 && !(key1 in index1)) return;
|
|
284
|
+
const keys1 = key1 ? null : Object.keys(index1);
|
|
285
|
+
for (let i1 = 0, value1 = key1 || keys1[0]; value1; value1 = keys1 && keys1[++i1]) {
|
|
286
|
+
const index2 = index1[value1];
|
|
287
|
+
parts[name1] = this._termFromId(entityKeys[value1]);
|
|
288
|
+
const values = Object.keys(index2);
|
|
289
|
+
for (let l = 0; l < values.length; l++) {
|
|
290
|
+
parts[name2] = this._termFromId(entityKeys[values[l]]);
|
|
291
|
+
yield this._factory.quad(parts.subject, parts.predicate, parts.object, graph);
|
|
285
292
|
}
|
|
286
293
|
}
|
|
287
294
|
}
|
package/package.json
CHANGED
package/src/N3Lexer.js
CHANGED
|
@@ -326,7 +326,7 @@ export default class N3Lexer {
|
|
|
326
326
|
case 'h':
|
|
327
327
|
case 'o':
|
|
328
328
|
// Try to find an N3 verb keyword
|
|
329
|
-
if (this._n3Mode && (match = this.
|
|
329
|
+
if (this._n3Mode && (match = this._matchN3Verb(input, inputFinished)))
|
|
330
330
|
type = match[0];
|
|
331
331
|
else
|
|
332
332
|
inconclusive = true;
|
|
@@ -336,7 +336,7 @@ export default class N3Lexer {
|
|
|
336
336
|
// Try to find an IRI property list identifier or N3 verb keyword
|
|
337
337
|
if (this._n3Mode && (match = this._n3Id.exec(input)))
|
|
338
338
|
type = 'id';
|
|
339
|
-
else if (this._n3Mode && (match = this.
|
|
339
|
+
else if (this._n3Mode && (match = this._matchN3Verb(input, inputFinished)))
|
|
340
340
|
type = match[0];
|
|
341
341
|
else
|
|
342
342
|
inconclusive = true;
|
|
@@ -455,6 +455,33 @@ export default class N3Lexer {
|
|
|
455
455
|
function reportSyntaxError(self) { callback(self._syntaxError(/^\S*/.exec(input)[0])); }
|
|
456
456
|
}
|
|
457
457
|
|
|
458
|
+
// ### `_matchN3Verb` matches an N3 verb unless the input is a longer prefixed name
|
|
459
|
+
_matchN3Verb(input, inputFinished) {
|
|
460
|
+
const verb = this._n3Verb.exec(input);
|
|
461
|
+
if (!verb)
|
|
462
|
+
return null;
|
|
463
|
+
|
|
464
|
+
// Most verb boundaries cannot be part of a prefix, so keep the common path fast.
|
|
465
|
+
const next = input[verb[0].length];
|
|
466
|
+
if (next !== '-' && next !== '_' && (next < '0' || next > '9'))
|
|
467
|
+
return verb;
|
|
468
|
+
|
|
469
|
+
// A prefix can start with a verb and continue with characters that are also
|
|
470
|
+
// valid verb boundaries. Prefer the longer prefixed name when it is complete.
|
|
471
|
+
if (this._prefixed.exec(input) || this._prefixed.exec(`${input} `))
|
|
472
|
+
return null;
|
|
473
|
+
|
|
474
|
+
// If a stream chunk ends partway through such a prefix, wait for the colon
|
|
475
|
+
// instead of prematurely emitting the verb. Appending ": " lets the prefix
|
|
476
|
+
// grammar determine whether all input seen so far can be a complete prefix.
|
|
477
|
+
if (!inputFinished) {
|
|
478
|
+
const prefix = this._prefix.exec(`${input}: `);
|
|
479
|
+
if (prefix)
|
|
480
|
+
return null;
|
|
481
|
+
}
|
|
482
|
+
return verb;
|
|
483
|
+
}
|
|
484
|
+
|
|
458
485
|
// ### `_unescape` replaces N3 escape codes by their corresponding characters,
|
|
459
486
|
// allowing only the fixed escape sequences from the given replacement table
|
|
460
487
|
_unescape(item, replacements) {
|
package/src/N3Parser.js
CHANGED
|
@@ -23,6 +23,13 @@ export default class N3Parser {
|
|
|
23
23
|
isNTriples = /triple/.test(format), isNQuads = /quad/.test(format),
|
|
24
24
|
isN3 = this._n3Mode = /n3/.test(format),
|
|
25
25
|
isLineMode = isNTriples || isNQuads;
|
|
26
|
+
// Keep inverse handling off the non-N3 emission path
|
|
27
|
+
this._emitCurrent = this._emit;
|
|
28
|
+
if (isN3) {
|
|
29
|
+
this._createQuad = this._createQuadInDirection;
|
|
30
|
+
this._emit = this._emitInDirection;
|
|
31
|
+
this._emitCurrent = this._emitCurrentInDirection;
|
|
32
|
+
}
|
|
26
33
|
if (!(this._supportsNamedGraphs = !(isTurtle || isN3)))
|
|
27
34
|
this._readPredicateOrNamedGraph = this._readPredicate;
|
|
28
35
|
// Support triples in other graphs
|
|
@@ -550,7 +557,7 @@ export default class N3Parser {
|
|
|
550
557
|
|
|
551
558
|
// Store blank node quad
|
|
552
559
|
if (this._subject !== null)
|
|
553
|
-
this.
|
|
560
|
+
this._emitCurrent(this._subject, this._predicate, this._object, this._graph);
|
|
554
561
|
|
|
555
562
|
// Restore the parent context containing this blank node
|
|
556
563
|
const empty = this._predicate === null;
|
|
@@ -911,7 +918,7 @@ export default class N3Parser {
|
|
|
911
918
|
|
|
912
919
|
// Store the last quad of the formula
|
|
913
920
|
if (this._subject !== null)
|
|
914
|
-
this.
|
|
921
|
+
this._emitCurrent(this._subject, this._predicate, this._object, this._graph);
|
|
915
922
|
|
|
916
923
|
const formula = this._graph, empty = this._emptyFormula;
|
|
917
924
|
// Restore the parent context containing this formula
|
|
@@ -958,6 +965,7 @@ export default class N3Parser {
|
|
|
958
965
|
break;
|
|
959
966
|
// Semicolon means the subject is shared; predicate and object are different
|
|
960
967
|
case ';':
|
|
968
|
+
if (inversePredicate) this._inversePredicate = false;
|
|
961
969
|
next = this._readPredicate;
|
|
962
970
|
break;
|
|
963
971
|
// Comma means both the subject and predicate are shared; the object is different
|
|
@@ -980,6 +988,7 @@ export default class N3Parser {
|
|
|
980
988
|
if (subject !== null)
|
|
981
989
|
this._tripleTerm = null;
|
|
982
990
|
this._subject = this._readTripleTerm();
|
|
991
|
+
this._inversePredicate = false;
|
|
983
992
|
this._validAnnotation = false;
|
|
984
993
|
startingAnnotation = true;
|
|
985
994
|
next = this._readPredicate;
|
|
@@ -992,6 +1001,7 @@ export default class N3Parser {
|
|
|
992
1001
|
return this._error('Annotation block can not be empty', token);
|
|
993
1002
|
this._subject = null;
|
|
994
1003
|
this._annotation = false;
|
|
1004
|
+
this._inversePredicate = false;
|
|
995
1005
|
next = this._getContextEndReader();
|
|
996
1006
|
break;
|
|
997
1007
|
default:
|
|
@@ -1005,10 +1015,7 @@ export default class N3Parser {
|
|
|
1005
1015
|
// A quad has been completed now, so return it
|
|
1006
1016
|
if (subject !== null && (!startingAnnotation || (startingAnnotation && !this._annotation))) {
|
|
1007
1017
|
const predicate = this._predicate, object = this._object;
|
|
1008
|
-
|
|
1009
|
-
this._emit(subject, predicate, object, graph);
|
|
1010
|
-
else
|
|
1011
|
-
this._emit(object, predicate, subject, graph);
|
|
1018
|
+
this._emit(subject, predicate, object, graph, inversePredicate);
|
|
1012
1019
|
}
|
|
1013
1020
|
if (startingAnnotation) {
|
|
1014
1021
|
this._annotation = true;
|
|
@@ -1018,10 +1025,11 @@ export default class N3Parser {
|
|
|
1018
1025
|
|
|
1019
1026
|
// ### `_readBlankNodePunctuation` reads punctuation in a blank node
|
|
1020
1027
|
_readBlankNodePunctuation(token) {
|
|
1021
|
-
let next;
|
|
1028
|
+
let next, resetInversePredicate = false;
|
|
1022
1029
|
switch (token.type) {
|
|
1023
1030
|
// Semicolon means the subject is shared; predicate and object are different
|
|
1024
1031
|
case ';':
|
|
1032
|
+
resetInversePredicate = this._inversePredicate;
|
|
1025
1033
|
next = this._readPredicate;
|
|
1026
1034
|
break;
|
|
1027
1035
|
// Comma means both the subject and predicate are shared; the object is different
|
|
@@ -1044,7 +1052,9 @@ export default class N3Parser {
|
|
|
1044
1052
|
if (this._subject === null)
|
|
1045
1053
|
return this._error('Expected ] to follow annotation', token);
|
|
1046
1054
|
// A quad has been completed now, so return it
|
|
1047
|
-
this.
|
|
1055
|
+
this._emitCurrent(this._subject, this._predicate, this._object, this._graph);
|
|
1056
|
+
if (resetInversePredicate)
|
|
1057
|
+
this._inversePredicate = false;
|
|
1048
1058
|
return next;
|
|
1049
1059
|
}
|
|
1050
1060
|
|
|
@@ -1269,8 +1279,8 @@ export default class N3Parser {
|
|
|
1269
1279
|
if (token.type !== ')>>')
|
|
1270
1280
|
return this._error(`Expected )>> but got ${token.type}`, token);
|
|
1271
1281
|
// Read the quad and restore the previous context
|
|
1272
|
-
const quad = this.
|
|
1273
|
-
this._graph
|
|
1282
|
+
const quad = this._createQuad(this._subject, this._predicate, this._object,
|
|
1283
|
+
this._graph, this._inversePredicate);
|
|
1274
1284
|
this._restoreContext('<<(', token);
|
|
1275
1285
|
|
|
1276
1286
|
// If we're in a list, continue processing that list
|
|
@@ -1371,6 +1381,7 @@ export default class N3Parser {
|
|
|
1371
1381
|
switch (token.type) {
|
|
1372
1382
|
// The subject stays shared with the next predicate-object pair
|
|
1373
1383
|
case ';':
|
|
1384
|
+
this._inversePredicate = false;
|
|
1374
1385
|
return this._readPredicate;
|
|
1375
1386
|
// The subject and predicate stay shared with the next object
|
|
1376
1387
|
case ',':
|
|
@@ -1388,7 +1399,9 @@ export default class N3Parser {
|
|
|
1388
1399
|
const parentGraph = parent ? parent.graph : undefined;
|
|
1389
1400
|
const reifier = this._reifier || this._factory.blankNode();
|
|
1390
1401
|
this._reifier = null;
|
|
1391
|
-
this._tripleTerm = this._tripleTerm || this.
|
|
1402
|
+
this._tripleTerm = this._tripleTerm || this._createQuad(
|
|
1403
|
+
this._subject, this._predicate, this._object, null, this._inversePredicate,
|
|
1404
|
+
);
|
|
1392
1405
|
this._emit(reifier, this.RDF_REIFIES, this._tripleTerm, parentGraph || this._graph || this.DEFAULTGRAPH);
|
|
1393
1406
|
return reifier;
|
|
1394
1407
|
}
|
|
@@ -1413,6 +1426,28 @@ export default class N3Parser {
|
|
|
1413
1426
|
}
|
|
1414
1427
|
}
|
|
1415
1428
|
|
|
1429
|
+
// ### `_createQuad` creates a quad
|
|
1430
|
+
_createQuad(subject, predicate, object, graph) {
|
|
1431
|
+
return this._factory.quad(subject, predicate, object, graph || this.DEFAULTGRAPH);
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1434
|
+
// ### `_createQuadInDirection` creates a quad in the active predicate direction
|
|
1435
|
+
_createQuadInDirection(subject, predicate, object, graph, inversePredicate) {
|
|
1436
|
+
return inversePredicate ?
|
|
1437
|
+
this._factory.quad(object, predicate, subject, graph || this.DEFAULTGRAPH) :
|
|
1438
|
+
this._factory.quad(subject, predicate, object, graph || this.DEFAULTGRAPH);
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
// ### `_emitInDirection` sends a quad in the active predicate direction
|
|
1442
|
+
_emitInDirection(subject, predicate, object, graph, inversePredicate) {
|
|
1443
|
+
this._callback(null, this._createQuad(subject, predicate, object, graph, inversePredicate));
|
|
1444
|
+
}
|
|
1445
|
+
|
|
1446
|
+
// ### `_emitCurrentInDirection` sends a quad in the current predicate direction
|
|
1447
|
+
_emitCurrentInDirection(subject, predicate, object, graph) {
|
|
1448
|
+
this._callback(null, this._createQuad(subject, predicate, object, graph, this._inversePredicate));
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1416
1451
|
// ### `_emit` sends a quad through the callback
|
|
1417
1452
|
_emit(subject, predicate, object, graph) {
|
|
1418
1453
|
this._callback(null, this._factory.quad(subject, predicate, object, graph || this.DEFAULTGRAPH));
|
package/src/N3Store.js
CHANGED
|
@@ -268,35 +268,49 @@ export default class N3Store {
|
|
|
268
268
|
|
|
269
269
|
// ### `_findInIndex` finds a set of quads in a three-layered index.
|
|
270
270
|
// The index base is `index0` and the keys at each level are `key0`, `key1`, and `key2`.
|
|
271
|
-
//
|
|
271
|
+
// A key and any keys after it can be null or undefined, which is interpreted as a wildcard.
|
|
272
272
|
// `name0`, `name1`, and `name2` are the names of the keys at each level,
|
|
273
273
|
// used when reconstructing the resulting quad
|
|
274
274
|
// (for instance: _subject_, _predicate_, and _object_).
|
|
275
275
|
// Finally, `graphId` will be the graph of the created quads.
|
|
276
276
|
*_findInIndex(index0, key0, key1, key2, name0, name1, name2, graphId) {
|
|
277
|
-
let tmp, index1, index2;
|
|
278
277
|
const entityKeys = this._entities;
|
|
279
278
|
const graph = this._termFromId(entityKeys[graphId]);
|
|
280
279
|
const parts = { subject: null, predicate: null, object: null };
|
|
281
280
|
|
|
282
|
-
//
|
|
283
|
-
if (
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
281
|
+
// Exact matches avoid allocating key arrays or entering generic loops.
|
|
282
|
+
if (key2) {
|
|
283
|
+
const index1 = index0[key0];
|
|
284
|
+
const index2 = index1 && index1[key1];
|
|
285
|
+
if (!index2 || !(key2 in index2))
|
|
286
|
+
return;
|
|
287
|
+
parts[name0] = this._termFromId(entityKeys[key0]);
|
|
288
|
+
parts[name1] = this._termFromId(entityKeys[key1]);
|
|
289
|
+
parts[name2] = this._termFromId(entityKeys[key2]);
|
|
290
|
+
yield this._factory.quad(parts.subject, parts.predicate, parts.object, graph);
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
if (key0 && !(key0 in index0))
|
|
295
|
+
return;
|
|
296
|
+
// A null key list stops after visiting a bound key, avoiding a one-item array.
|
|
297
|
+
const keys0 = key0 ? null : Object.keys(index0);
|
|
298
|
+
for (let i0 = 0, value0 = key0 || keys0[0]; value0;
|
|
299
|
+
value0 = keys0 && keys0[++i0]) {
|
|
300
|
+
const index1 = index0[value0];
|
|
301
|
+
parts[name0] = this._termFromId(entityKeys[value0]);
|
|
302
|
+
|
|
303
|
+
if (key1 && !(key1 in index1))
|
|
304
|
+
return;
|
|
305
|
+
const keys1 = key1 ? null : Object.keys(index1);
|
|
306
|
+
for (let i1 = 0, value1 = key1 || keys1[0]; value1;
|
|
307
|
+
value1 = keys1 && keys1[++i1]) {
|
|
308
|
+
const index2 = index1[value1];
|
|
309
|
+
parts[name1] = this._termFromId(entityKeys[value1]);
|
|
310
|
+
const values = Object.keys(index2);
|
|
311
|
+
for (let l = 0; l < values.length; l++) {
|
|
312
|
+
parts[name2] = this._termFromId(entityKeys[values[l]]);
|
|
313
|
+
yield this._factory.quad(parts.subject, parts.predicate, parts.object, graph);
|
|
300
314
|
}
|
|
301
315
|
}
|
|
302
316
|
}
|