n3 2.2.7 → 2.2.8
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 +1 -1
- package/browser/n3.min.js +1 -1
- package/lib/N3Lexer.js +3 -3
- package/lib/N3Parser.js +62 -9
- package/package.json +1 -1
- package/src/N3Lexer.js +3 -3
- package/src/N3Parser.js +66 -11
package/lib/N3Lexer.js
CHANGED
|
@@ -78,9 +78,9 @@ class N3Lexer {
|
|
|
78
78
|
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<])/;
|
|
79
79
|
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#()\[\]\{\}"'<>]))/;
|
|
80
80
|
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#()\[\]\{\}"'<>])/;
|
|
81
|
-
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]+|(?=\.?[
|
|
82
|
-
this._number = /^[\-+]?(?:(\d+\.\d*|\.?\d+)[eE][\-+]?|\d*(\.)?)\d+(?=\.?[
|
|
83
|
-
this._boolean = /^(?:true|false)(?=[
|
|
81
|
+
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#()\[\]\{\}"'<>]))/;
|
|
82
|
+
this._number = /^[\-+]?(?:(\d+\.\d*|\.?\d+)[eE][\-+]?|\d*(\.)?)\d+(?=\.?[,;:!\^\s#()\[\]\{\}"'<>])/;
|
|
83
|
+
this._boolean = /^(?:true|false)(?=[.,;!\^\s#()\[\]\{\}"'<>])/;
|
|
84
84
|
this._atKeyword = /^@[a-z]+(?=[\s#<:])/i;
|
|
85
85
|
this._keyword = /^(?:PREFIX|BASE|VERSION|GRAPH)(?=[\s#<])/i;
|
|
86
86
|
this._shortPredicates = /^a(?=[\s#()\[\]\{\}"'<>])/;
|
package/lib/N3Parser.js
CHANGED
|
@@ -249,8 +249,11 @@ class N3Parser {
|
|
|
249
249
|
if (token.prefix.length === 0) {
|
|
250
250
|
this._literalValue = token.value;
|
|
251
251
|
return this._completeSubjectLiteral;
|
|
252
|
-
} else
|
|
253
|
-
|
|
252
|
+
} else {
|
|
253
|
+
this._subject = this._factory.literal(token.value, this._factory.namedNode(token.prefix));
|
|
254
|
+
// This branch is N3-only, so the literal subject might start a path
|
|
255
|
+
return this._getPathReader(this._readPredicateOrNamedGraph);
|
|
256
|
+
}
|
|
254
257
|
case '<<(':
|
|
255
258
|
if (!this._n3Mode) return this._error('Disallowed triple term as subject', token);
|
|
256
259
|
this._saveContext('<<(', this._graph, null, null, null);
|
|
@@ -285,8 +288,9 @@ class N3Parser {
|
|
|
285
288
|
case ']':
|
|
286
289
|
case '}':
|
|
287
290
|
case '|}':
|
|
288
|
-
// Expected predicate didn't come, must have been trailing semicolon
|
|
289
|
-
|
|
291
|
+
// Expected predicate didn't come, must have been trailing semicolon.
|
|
292
|
+
// In N3 mode, a subject (such as a path) can be a statement by itself.
|
|
293
|
+
if (this._predicate === null && !this._n3Mode) return this._error(`Unexpected ${type}`, token);
|
|
290
294
|
this._subject = null;
|
|
291
295
|
return type === ']' ? this._readBlankNodeTail(token) : this._readPunctuation(token);
|
|
292
296
|
case ';':
|
|
@@ -325,7 +329,11 @@ class N3Parser {
|
|
|
325
329
|
return this._readDataTypeOrLang;
|
|
326
330
|
}
|
|
327
331
|
// Pre-datatyped string literal (prefix stores the datatype)
|
|
328
|
-
else
|
|
332
|
+
else {
|
|
333
|
+
this._object = this._factory.literal(token.value, this._factory.namedNode(token.prefix));
|
|
334
|
+
// In N3 mode, the literal object might start a path
|
|
335
|
+
if (this._n3Mode) return this._getPathReader(this._getContextEndReader());
|
|
336
|
+
}
|
|
329
337
|
break;
|
|
330
338
|
case '[':
|
|
331
339
|
// Start a new quad with a new blank node as subject
|
|
@@ -454,17 +462,31 @@ class N3Parser {
|
|
|
454
462
|
this._restoreContext('list', token);
|
|
455
463
|
// If this list is contained within a parent list, return the membership quad here.
|
|
456
464
|
// This will be `<parent list element> rdf:first <this list>.`.
|
|
457
|
-
if (stack.length !== 0 && stack[stack.length - 1].type === 'list')
|
|
465
|
+
if (stack.length !== 0 && stack[stack.length - 1].type === 'list') {
|
|
466
|
+
// In N3 mode, this list might be the start of a path
|
|
467
|
+
if (this._n3Mode) {
|
|
468
|
+
// Close this list's tail, as a path would alter the membership quad only
|
|
469
|
+
if (previousList !== null) this._emit(previousList, this.RDF_REST, this.RDF_NIL, this._graph);
|
|
470
|
+
// Create a new context to read the path;
|
|
471
|
+
// _readPath will restore the context and output the membership quad
|
|
472
|
+
this._saveContext('item', this._graph, this._subject, this._predicate, this._object);
|
|
473
|
+
this._subject = this._object, this._predicate = null;
|
|
474
|
+
return this._getPathReader(this._readListItem);
|
|
475
|
+
}
|
|
476
|
+
this._emit(this._subject, this._predicate, this._object, this._graph);
|
|
477
|
+
}
|
|
458
478
|
// Was this list the parent's subject?
|
|
459
479
|
if (this._predicate === null) {
|
|
460
480
|
// The next token is the predicate
|
|
461
|
-
next = this._readPredicate;
|
|
481
|
+
next = this._n3Mode ? this._getPathReader(this._readPredicate) : this._readPredicate;
|
|
462
482
|
// No list tail if this was an empty list
|
|
463
483
|
if (this._subject === this.RDF_NIL) return next;
|
|
464
484
|
}
|
|
465
485
|
// The list was in the parent context's object
|
|
466
486
|
else {
|
|
467
487
|
next = this._getContextEndReader();
|
|
488
|
+
// In N3 mode, the list object might be the start of a path
|
|
489
|
+
if (this._n3Mode) next = this._getPathReader(next);
|
|
468
490
|
// No list tail if this was an empty list
|
|
469
491
|
if (this._object === this.RDF_NIL) return next;
|
|
470
492
|
}
|
|
@@ -519,7 +541,7 @@ class N3Parser {
|
|
|
519
541
|
// If an item was read, add it to the list
|
|
520
542
|
if (item !== null) {
|
|
521
543
|
// In N3 mode, the item might be a path
|
|
522
|
-
if (this._n3Mode && (token.type === 'IRI' || token.type === 'prefixed')) {
|
|
544
|
+
if (this._n3Mode && (token.type === 'IRI' || token.type === 'prefixed' || token.type === 'var' || token.type === 'blank' || token.type === 'literal')) {
|
|
523
545
|
// Create a new context to add the item's path
|
|
524
546
|
this._saveContext('item', this._graph, list, this.RDF_FIRST, item);
|
|
525
547
|
this._subject = item, this._predicate = null;
|
|
@@ -585,7 +607,11 @@ class N3Parser {
|
|
|
585
607
|
this._literalLanguage = undefined;
|
|
586
608
|
token = null;
|
|
587
609
|
}
|
|
588
|
-
if (component === 'subject')
|
|
610
|
+
if (component === 'subject') {
|
|
611
|
+
// A subject literal implies N3 mode, so the literal might start a path
|
|
612
|
+
const reader = this._getPathEndReader(token, this._readPredicateOrNamedGraph);
|
|
613
|
+
return reader || this._readPredicateOrNamedGraph(token);
|
|
614
|
+
}
|
|
589
615
|
if (component === 'predicate') return token === null ? this._readObject : this._readObject(token);
|
|
590
616
|
return this._completeObjectLiteralPost(token, listItem);
|
|
591
617
|
}
|
|
@@ -607,6 +633,12 @@ class N3Parser {
|
|
|
607
633
|
// Postpone completion if the literal is only partially completed (such as lang+dir).
|
|
608
634
|
if (completed.readCb) return completed.readCb.bind(this, false);
|
|
609
635
|
|
|
636
|
+
// A subject literal implies N3 mode, so it might start a path.
|
|
637
|
+
if (component === 'subject') {
|
|
638
|
+
const reader = this._getPathEndReader(completed.token, next);
|
|
639
|
+
if (reader) return reader;
|
|
640
|
+
}
|
|
641
|
+
|
|
610
642
|
// If the token was consumed as a datatype, continue with the next component;
|
|
611
643
|
// otherwise, consume the token now
|
|
612
644
|
return completed.token === null ? next : next.call(this, completed.token);
|
|
@@ -633,6 +665,17 @@ class N3Parser {
|
|
|
633
665
|
return this._completeObjectLiteralPost(completed.token, listItem);
|
|
634
666
|
}
|
|
635
667
|
_completeObjectLiteralPost(token, listItem) {
|
|
668
|
+
// In N3 mode, the literal object might start a path
|
|
669
|
+
if (this._n3Mode && (token === null || token.type === '!' || token.type === '^')) {
|
|
670
|
+
// If this literal was part of a list, defer writing the item;
|
|
671
|
+
// _readPath will then restore the context and output it
|
|
672
|
+
if (listItem) {
|
|
673
|
+
this._saveContext('item', this._graph, this._subject, this.RDF_FIRST, this._object);
|
|
674
|
+
this._subject = this._object, this._predicate = null;
|
|
675
|
+
return this._getPathEndReader(token, this._readListItem);
|
|
676
|
+
}
|
|
677
|
+
return this._getPathEndReader(token, this._getContextEndReader());
|
|
678
|
+
}
|
|
636
679
|
// If this literal was part of a list, write the item
|
|
637
680
|
// (we could also check the context stack, but passing in a flag is faster)
|
|
638
681
|
if (listItem) this._emit(this._subject, this.RDF_FIRST, this._object, this._graph);
|
|
@@ -887,6 +930,16 @@ class N3Parser {
|
|
|
887
930
|
return this._readPath;
|
|
888
931
|
}
|
|
889
932
|
|
|
933
|
+
// ### `_getPathEndReader` continues reading after a term that might start a path,
|
|
934
|
+
// given the pending token that follows the term (or `null` if it was consumed)
|
|
935
|
+
_getPathEndReader(token, afterPath) {
|
|
936
|
+
// Other pending tokens are not handled here
|
|
937
|
+
if (token !== null && token.type !== '!' && token.type !== '^') return null;
|
|
938
|
+
const reader = this._getPathReader(afterPath);
|
|
939
|
+
// If no token is pending, wait for the next one; otherwise, consume it now
|
|
940
|
+
return token === null ? reader : reader.call(this, token);
|
|
941
|
+
}
|
|
942
|
+
|
|
890
943
|
// ### `_readPath` reads a potential path
|
|
891
944
|
_readPath(token) {
|
|
892
945
|
switch (token.type) {
|
package/package.json
CHANGED
package/src/N3Lexer.js
CHANGED
|
@@ -48,9 +48,9 @@ export default class N3Lexer {
|
|
|
48
48
|
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<])/;
|
|
49
49
|
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#()\[\]\{\}"'<>]))/;
|
|
50
50
|
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#()\[\]\{\}"'<>])/;
|
|
51
|
-
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]+|(?=\.?[
|
|
52
|
-
this._number = /^[\-+]?(?:(\d+\.\d*|\.?\d+)[eE][\-+]?|\d*(\.)?)\d+(?=\.?[
|
|
53
|
-
this._boolean = /^(?:true|false)(?=[
|
|
51
|
+
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#()\[\]\{\}"'<>]))/;
|
|
52
|
+
this._number = /^[\-+]?(?:(\d+\.\d*|\.?\d+)[eE][\-+]?|\d*(\.)?)\d+(?=\.?[,;:!\^\s#()\[\]\{\}"'<>])/;
|
|
53
|
+
this._boolean = /^(?:true|false)(?=[.,;!\^\s#()\[\]\{\}"'<>])/;
|
|
54
54
|
this._atKeyword = /^@[a-z]+(?=[\s#<:])/i;
|
|
55
55
|
this._keyword = /^(?:PREFIX|BASE|VERSION|GRAPH)(?=[\s#<])/i;
|
|
56
56
|
this._shortPredicates = /^a(?=[\s#()\[\]\{\}"'<>])/;
|
package/src/N3Parser.js
CHANGED
|
@@ -252,10 +252,11 @@ export default class N3Parser {
|
|
|
252
252
|
this._literalValue = token.value;
|
|
253
253
|
return this._completeSubjectLiteral;
|
|
254
254
|
}
|
|
255
|
-
else
|
|
255
|
+
else {
|
|
256
256
|
this._subject = this._factory.literal(token.value, this._factory.namedNode(token.prefix));
|
|
257
|
-
|
|
258
|
-
|
|
257
|
+
// This branch is N3-only, so the literal subject might start a path
|
|
258
|
+
return this._getPathReader(this._readPredicateOrNamedGraph);
|
|
259
|
+
}
|
|
259
260
|
case '<<(':
|
|
260
261
|
if (!this._n3Mode)
|
|
261
262
|
return this._error('Disallowed triple term as subject', token);
|
|
@@ -293,8 +294,9 @@ export default class N3Parser {
|
|
|
293
294
|
case ']':
|
|
294
295
|
case '}':
|
|
295
296
|
case '|}':
|
|
296
|
-
// Expected predicate didn't come, must have been trailing semicolon
|
|
297
|
-
|
|
297
|
+
// Expected predicate didn't come, must have been trailing semicolon.
|
|
298
|
+
// In N3 mode, a subject (such as a path) can be a statement by itself.
|
|
299
|
+
if (this._predicate === null && !this._n3Mode)
|
|
298
300
|
return this._error(`Unexpected ${type}`, token);
|
|
299
301
|
this._subject = null;
|
|
300
302
|
return type === ']' ? this._readBlankNodeTail(token) : this._readPunctuation(token);
|
|
@@ -343,8 +345,12 @@ export default class N3Parser {
|
|
|
343
345
|
return this._readDataTypeOrLang;
|
|
344
346
|
}
|
|
345
347
|
// Pre-datatyped string literal (prefix stores the datatype)
|
|
346
|
-
else
|
|
348
|
+
else {
|
|
347
349
|
this._object = this._factory.literal(token.value, this._factory.namedNode(token.prefix));
|
|
350
|
+
// In N3 mode, the literal object might start a path
|
|
351
|
+
if (this._n3Mode)
|
|
352
|
+
return this._getPathReader(this._getContextEndReader());
|
|
353
|
+
}
|
|
348
354
|
break;
|
|
349
355
|
case '[':
|
|
350
356
|
// Start a new quad with a new blank node as subject
|
|
@@ -481,12 +487,24 @@ export default class N3Parser {
|
|
|
481
487
|
this._restoreContext('list', token);
|
|
482
488
|
// If this list is contained within a parent list, return the membership quad here.
|
|
483
489
|
// This will be `<parent list element> rdf:first <this list>.`.
|
|
484
|
-
if (stack.length !== 0 && stack[stack.length - 1].type === 'list')
|
|
490
|
+
if (stack.length !== 0 && stack[stack.length - 1].type === 'list') {
|
|
491
|
+
// In N3 mode, this list might be the start of a path
|
|
492
|
+
if (this._n3Mode) {
|
|
493
|
+
// Close this list's tail, as a path would alter the membership quad only
|
|
494
|
+
if (previousList !== null)
|
|
495
|
+
this._emit(previousList, this.RDF_REST, this.RDF_NIL, this._graph);
|
|
496
|
+
// Create a new context to read the path;
|
|
497
|
+
// _readPath will restore the context and output the membership quad
|
|
498
|
+
this._saveContext('item', this._graph, this._subject, this._predicate, this._object);
|
|
499
|
+
this._subject = this._object, this._predicate = null;
|
|
500
|
+
return this._getPathReader(this._readListItem);
|
|
501
|
+
}
|
|
485
502
|
this._emit(this._subject, this._predicate, this._object, this._graph);
|
|
503
|
+
}
|
|
486
504
|
// Was this list the parent's subject?
|
|
487
505
|
if (this._predicate === null) {
|
|
488
506
|
// The next token is the predicate
|
|
489
|
-
next = this._readPredicate;
|
|
507
|
+
next = this._n3Mode ? this._getPathReader(this._readPredicate) : this._readPredicate;
|
|
490
508
|
// No list tail if this was an empty list
|
|
491
509
|
if (this._subject === this.RDF_NIL)
|
|
492
510
|
return next;
|
|
@@ -494,6 +512,9 @@ export default class N3Parser {
|
|
|
494
512
|
// The list was in the parent context's object
|
|
495
513
|
else {
|
|
496
514
|
next = this._getContextEndReader();
|
|
515
|
+
// In N3 mode, the list object might be the start of a path
|
|
516
|
+
if (this._n3Mode)
|
|
517
|
+
next = this._getPathReader(next);
|
|
497
518
|
// No list tail if this was an empty list
|
|
498
519
|
if (this._object === this.RDF_NIL)
|
|
499
520
|
return next;
|
|
@@ -558,7 +579,9 @@ export default class N3Parser {
|
|
|
558
579
|
// If an item was read, add it to the list
|
|
559
580
|
if (item !== null) {
|
|
560
581
|
// In N3 mode, the item might be a path
|
|
561
|
-
if (this._n3Mode && (token.type === 'IRI' || token.type === 'prefixed'
|
|
582
|
+
if (this._n3Mode && (token.type === 'IRI' || token.type === 'prefixed' ||
|
|
583
|
+
token.type === 'var' || token.type === 'blank' ||
|
|
584
|
+
token.type === 'literal')) {
|
|
562
585
|
// Create a new context to add the item's path
|
|
563
586
|
this._saveContext('item', this._graph, list, this.RDF_FIRST, item);
|
|
564
587
|
this._subject = item, this._predicate = null;
|
|
@@ -628,8 +651,11 @@ export default class N3Parser {
|
|
|
628
651
|
token = null;
|
|
629
652
|
}
|
|
630
653
|
|
|
631
|
-
if (component === 'subject')
|
|
632
|
-
|
|
654
|
+
if (component === 'subject') {
|
|
655
|
+
// A subject literal implies N3 mode, so the literal might start a path
|
|
656
|
+
const reader = this._getPathEndReader(token, this._readPredicateOrNamedGraph);
|
|
657
|
+
return reader || this._readPredicateOrNamedGraph(token);
|
|
658
|
+
}
|
|
633
659
|
if (component === 'predicate')
|
|
634
660
|
return token === null ? this._readObject : this._readObject(token);
|
|
635
661
|
return this._completeObjectLiteralPost(token, listItem);
|
|
@@ -656,6 +682,13 @@ export default class N3Parser {
|
|
|
656
682
|
if (completed.readCb)
|
|
657
683
|
return completed.readCb.bind(this, false);
|
|
658
684
|
|
|
685
|
+
// A subject literal implies N3 mode, so it might start a path.
|
|
686
|
+
if (component === 'subject') {
|
|
687
|
+
const reader = this._getPathEndReader(completed.token, next);
|
|
688
|
+
if (reader)
|
|
689
|
+
return reader;
|
|
690
|
+
}
|
|
691
|
+
|
|
659
692
|
// If the token was consumed as a datatype, continue with the next component;
|
|
660
693
|
// otherwise, consume the token now
|
|
661
694
|
return completed.token === null ? next : next.call(this, completed.token);
|
|
@@ -687,6 +720,17 @@ export default class N3Parser {
|
|
|
687
720
|
}
|
|
688
721
|
|
|
689
722
|
_completeObjectLiteralPost(token, listItem) {
|
|
723
|
+
// In N3 mode, the literal object might start a path
|
|
724
|
+
if (this._n3Mode && (token === null || token.type === '!' || token.type === '^')) {
|
|
725
|
+
// If this literal was part of a list, defer writing the item;
|
|
726
|
+
// _readPath will then restore the context and output it
|
|
727
|
+
if (listItem) {
|
|
728
|
+
this._saveContext('item', this._graph, this._subject, this.RDF_FIRST, this._object);
|
|
729
|
+
this._subject = this._object, this._predicate = null;
|
|
730
|
+
return this._getPathEndReader(token, this._readListItem);
|
|
731
|
+
}
|
|
732
|
+
return this._getPathEndReader(token, this._getContextEndReader());
|
|
733
|
+
}
|
|
690
734
|
// If this literal was part of a list, write the item
|
|
691
735
|
// (we could also check the context stack, but passing in a flag is faster)
|
|
692
736
|
if (listItem)
|
|
@@ -968,6 +1012,17 @@ export default class N3Parser {
|
|
|
968
1012
|
return this._readPath;
|
|
969
1013
|
}
|
|
970
1014
|
|
|
1015
|
+
// ### `_getPathEndReader` continues reading after a term that might start a path,
|
|
1016
|
+
// given the pending token that follows the term (or `null` if it was consumed)
|
|
1017
|
+
_getPathEndReader(token, afterPath) {
|
|
1018
|
+
// Other pending tokens are not handled here
|
|
1019
|
+
if (token !== null && token.type !== '!' && token.type !== '^')
|
|
1020
|
+
return null;
|
|
1021
|
+
const reader = this._getPathReader(afterPath);
|
|
1022
|
+
// If no token is pending, wait for the next one; otherwise, consume it now
|
|
1023
|
+
return token === null ? reader : reader.call(this, token);
|
|
1024
|
+
}
|
|
1025
|
+
|
|
971
1026
|
// ### `_readPath` reads a potential path
|
|
972
1027
|
_readPath(token) {
|
|
973
1028
|
switch (token.type) {
|