n3 2.2.12 → 2.2.14
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 +9 -0
- package/browser/n3.esm.min.js +6 -6
- package/browser/n3.min.js +1 -1
- package/lib/N3Parser.js +66 -21
- package/package.json +1 -1
- package/src/N3Parser.js +60 -22
package/lib/N3Parser.js
CHANGED
|
@@ -36,6 +36,9 @@ class N3Parser {
|
|
|
36
36
|
this._supportsQuads = !(isTurtle || isTriG || isNTriples || isN3);
|
|
37
37
|
// Whether the log:isImpliedBy predicate is supported
|
|
38
38
|
this._isImpliedBy = options.isImpliedBy;
|
|
39
|
+
// Whether an empty formula is read as the boolean literal true,
|
|
40
|
+
// as in the N3 spec tests (opt-in until the next major version)
|
|
41
|
+
this._emptyFormulaAsTrue = !!options.emptyFormulaAsTrue;
|
|
39
42
|
// Disable relative IRIs in N-Triples or N-Quads mode
|
|
40
43
|
if (isLineMode) this._resolveRelativeIRI = iri => {
|
|
41
44
|
return null;
|
|
@@ -83,26 +86,39 @@ class N3Parser {
|
|
|
83
86
|
// ### `_saveContext` stores the current parsing context
|
|
84
87
|
// when entering a new scope (list, blank node, formula)
|
|
85
88
|
_saveContext(type, graph, subject, predicate, object) {
|
|
86
|
-
|
|
89
|
+
// Only N3 contexts need the extra parser state.
|
|
90
|
+
if (!this._n3Mode) {
|
|
91
|
+
this._contextStack.push({
|
|
92
|
+
type,
|
|
93
|
+
subject,
|
|
94
|
+
predicate,
|
|
95
|
+
object,
|
|
96
|
+
graph
|
|
97
|
+
});
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
87
100
|
this._contextStack.push({
|
|
88
101
|
type,
|
|
89
102
|
subject,
|
|
90
103
|
predicate,
|
|
91
104
|
object,
|
|
92
105
|
graph,
|
|
93
|
-
inverse:
|
|
94
|
-
blankPrefix:
|
|
95
|
-
quantified:
|
|
106
|
+
inverse: this._inversePredicate,
|
|
107
|
+
blankPrefix: this._prefixes._,
|
|
108
|
+
quantified: this._quantified,
|
|
109
|
+
emptyFormula: this._emptyFormula
|
|
96
110
|
});
|
|
97
|
-
//
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
111
|
+
// Every new scope resets the predicate direction
|
|
112
|
+
this._inversePredicate = false;
|
|
113
|
+
// In N3, blank nodes are scoped to a formula
|
|
114
|
+
// (using a dot as separator, as a blank node label cannot start with it)
|
|
115
|
+
this._prefixes._ = this._graph ? `${this._graph.value}.` : '.';
|
|
116
|
+
// Quantifiers are scoped to a formula
|
|
117
|
+
this._quantified = Object.create(this._quantified);
|
|
118
|
+
// A formula starts empty and must not inherit its parent's subject
|
|
119
|
+
if (type === 'formula') {
|
|
120
|
+
this._subject = null;
|
|
121
|
+
this._emptyFormula = true;
|
|
106
122
|
}
|
|
107
123
|
}
|
|
108
124
|
|
|
@@ -124,6 +140,7 @@ class N3Parser {
|
|
|
124
140
|
this._inversePredicate = context.inverse;
|
|
125
141
|
this._prefixes._ = context.blankPrefix;
|
|
126
142
|
this._quantified = context.quantified;
|
|
143
|
+
this._emptyFormula = context.emptyFormula;
|
|
127
144
|
}
|
|
128
145
|
}
|
|
129
146
|
|
|
@@ -209,6 +226,8 @@ class N3Parser {
|
|
|
209
226
|
// ### `_readSubject` reads a quad's subject
|
|
210
227
|
_readSubject(token) {
|
|
211
228
|
this._predicate = null;
|
|
229
|
+
// Any statement token means the enclosing formula is not empty
|
|
230
|
+
if (token.type !== '}') this._emptyFormula = false;
|
|
212
231
|
switch (token.type) {
|
|
213
232
|
case '[':
|
|
214
233
|
// Start a new quad with a new blank node as subject
|
|
@@ -581,10 +600,10 @@ class N3Parser {
|
|
|
581
600
|
}
|
|
582
601
|
|
|
583
602
|
// ### `_completeLiteral` completes a literal with an optional datatype or language
|
|
603
|
+
// Defers possible direction tags without allocating bound callbacks.
|
|
584
604
|
_completeLiteral(token, component) {
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
let readCb;
|
|
605
|
+
let literal,
|
|
606
|
+
readCb = false;
|
|
588
607
|
switch (token.type) {
|
|
589
608
|
// Create a datatyped literal
|
|
590
609
|
case 'type':
|
|
@@ -603,8 +622,13 @@ class N3Parser {
|
|
|
603
622
|
literal = this._factory.literal(this._literalValue, token.value);
|
|
604
623
|
this._literalLanguage = token.value;
|
|
605
624
|
token = null;
|
|
606
|
-
|
|
625
|
+
// Save state for a possible direction tag
|
|
626
|
+
this._literalComponent = component;
|
|
627
|
+
readCb = true;
|
|
607
628
|
break;
|
|
629
|
+
// Create a simple string literal by default
|
|
630
|
+
default:
|
|
631
|
+
literal = this._factory.literal(this._literalValue);
|
|
608
632
|
}
|
|
609
633
|
return {
|
|
610
634
|
token,
|
|
@@ -612,7 +636,11 @@ class N3Parser {
|
|
|
612
636
|
readCb
|
|
613
637
|
};
|
|
614
638
|
}
|
|
615
|
-
|
|
639
|
+
|
|
640
|
+
// ### `_readDirCode` reads an optional directional language tag
|
|
641
|
+
_readDirCode(token) {
|
|
642
|
+
const component = this._literalComponent,
|
|
643
|
+
listItem = this._literalListItem;
|
|
616
644
|
// Attempt to read a dircode
|
|
617
645
|
if (token.type === 'dircode') {
|
|
618
646
|
const term = this._factory.literal(this._literalValue, {
|
|
@@ -647,7 +675,10 @@ class N3Parser {
|
|
|
647
675
|
}
|
|
648
676
|
|
|
649
677
|
// Postpone completion if the literal is only partially completed (such as lang+dir).
|
|
650
|
-
if (completed.readCb)
|
|
678
|
+
if (completed.readCb) {
|
|
679
|
+
this._literalListItem = false;
|
|
680
|
+
return this._readDirCode;
|
|
681
|
+
}
|
|
651
682
|
|
|
652
683
|
// A subject literal implies N3 mode, so it might start a path.
|
|
653
684
|
if (component === 'subject') {
|
|
@@ -677,7 +708,10 @@ class N3Parser {
|
|
|
677
708
|
this._object = completed.literal;
|
|
678
709
|
|
|
679
710
|
// Postpone completion if the literal is only partially completed (such as lang+dir).
|
|
680
|
-
if (completed.readCb)
|
|
711
|
+
if (completed.readCb) {
|
|
712
|
+
this._literalListItem = listItem;
|
|
713
|
+
return this._readDirCode;
|
|
714
|
+
}
|
|
681
715
|
return this._completeObjectLiteralPost(completed.token, listItem);
|
|
682
716
|
}
|
|
683
717
|
_completeObjectLiteralPost(token, listItem) {
|
|
@@ -710,9 +744,18 @@ class N3Parser {
|
|
|
710
744
|
|
|
711
745
|
// Store the last quad of the formula
|
|
712
746
|
if (this._subject !== null) this._emit(this._subject, this._predicate, this._object, this._graph);
|
|
713
|
-
|
|
747
|
+
const formula = this._graph,
|
|
748
|
+
empty = this._emptyFormula;
|
|
714
749
|
// Restore the parent context containing this formula
|
|
715
750
|
this._restoreContext('formula', token);
|
|
751
|
+
|
|
752
|
+
// When the emptyFormulaAsTrue option is set, an empty formula
|
|
753
|
+
// is read as the boolean literal true, following the N3 spec tests
|
|
754
|
+
// and the direction discussed in https://github.com/w3c-cg/N3/issues/185
|
|
755
|
+
if (empty && this._emptyFormulaAsTrue) {
|
|
756
|
+
if (this._subject === formula) this._subject = this.N3_TRUE;else this._object = this.N3_TRUE;
|
|
757
|
+
}
|
|
758
|
+
|
|
716
759
|
// If the formula was the subject, continue reading the predicate.
|
|
717
760
|
// If the formula was the object, read punctuation.
|
|
718
761
|
return this._object === null ? this._readPredicate : this._getContextEndReader();
|
|
@@ -1293,6 +1336,7 @@ class N3Parser {
|
|
|
1293
1336
|
this._versionCallback = onVersion || noop;
|
|
1294
1337
|
this._inversePredicate = false;
|
|
1295
1338
|
this._quantified = Object.create(null);
|
|
1339
|
+
this._emptyFormula = false;
|
|
1296
1340
|
|
|
1297
1341
|
// Parse synchronously if no quad callback is given
|
|
1298
1342
|
if (!onQuad) {
|
|
@@ -1345,6 +1389,7 @@ function initDataFactory(parser, factory) {
|
|
|
1345
1389
|
parser.RDF_REIFIES = factory.namedNode(_IRIs.default.rdf.reifies);
|
|
1346
1390
|
parser.N3_FORALL = factory.namedNode(_IRIs.default.r.forAll);
|
|
1347
1391
|
parser.N3_FORSOME = factory.namedNode(_IRIs.default.r.forSome);
|
|
1392
|
+
parser.N3_TRUE = factory.literal('true', factory.namedNode(_IRIs.default.xsd.boolean));
|
|
1348
1393
|
parser.ABBREVIATIONS = {
|
|
1349
1394
|
'a': factory.namedNode(_IRIs.default.rdf.type),
|
|
1350
1395
|
'=': factory.namedNode(_IRIs.default.owl.sameAs),
|
package/package.json
CHANGED
package/src/N3Parser.js
CHANGED
|
@@ -29,6 +29,9 @@ export default class N3Parser {
|
|
|
29
29
|
this._supportsQuads = !(isTurtle || isTriG || isNTriples || isN3);
|
|
30
30
|
// Whether the log:isImpliedBy predicate is supported
|
|
31
31
|
this._isImpliedBy = options.isImpliedBy;
|
|
32
|
+
// Whether an empty formula is read as the boolean literal true,
|
|
33
|
+
// as in the N3 spec tests (opt-in until the next major version)
|
|
34
|
+
this._emptyFormulaAsTrue = !!options.emptyFormulaAsTrue;
|
|
32
35
|
// Disable relative IRIs in N-Triples or N-Quads mode
|
|
33
36
|
if (isLineMode)
|
|
34
37
|
this._resolveRelativeIRI = iri => { return null; };
|
|
@@ -75,23 +78,30 @@ export default class N3Parser {
|
|
|
75
78
|
// ### `_saveContext` stores the current parsing context
|
|
76
79
|
// when entering a new scope (list, blank node, formula)
|
|
77
80
|
_saveContext(type, graph, subject, predicate, object) {
|
|
78
|
-
|
|
81
|
+
// Only N3 contexts need the extra parser state.
|
|
82
|
+
if (!this._n3Mode) {
|
|
83
|
+
this._contextStack.push({ type, subject, predicate, object, graph });
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
79
86
|
this._contextStack.push({
|
|
80
87
|
type,
|
|
81
88
|
subject, predicate, object, graph,
|
|
82
|
-
inverse:
|
|
83
|
-
blankPrefix:
|
|
84
|
-
quantified:
|
|
89
|
+
inverse: this._inversePredicate,
|
|
90
|
+
blankPrefix: this._prefixes._,
|
|
91
|
+
quantified: this._quantified,
|
|
92
|
+
emptyFormula: this._emptyFormula,
|
|
85
93
|
});
|
|
86
|
-
//
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
94
|
+
// Every new scope resets the predicate direction
|
|
95
|
+
this._inversePredicate = false;
|
|
96
|
+
// In N3, blank nodes are scoped to a formula
|
|
97
|
+
// (using a dot as separator, as a blank node label cannot start with it)
|
|
98
|
+
this._prefixes._ = (this._graph ? `${this._graph.value}.` : '.');
|
|
99
|
+
// Quantifiers are scoped to a formula
|
|
100
|
+
this._quantified = Object.create(this._quantified);
|
|
101
|
+
// A formula starts empty and must not inherit its parent's subject
|
|
102
|
+
if (type === 'formula') {
|
|
103
|
+
this._subject = null;
|
|
104
|
+
this._emptyFormula = true;
|
|
95
105
|
}
|
|
96
106
|
}
|
|
97
107
|
|
|
@@ -114,6 +124,7 @@ export default class N3Parser {
|
|
|
114
124
|
this._inversePredicate = context.inverse;
|
|
115
125
|
this._prefixes._ = context.blankPrefix;
|
|
116
126
|
this._quantified = context.quantified;
|
|
127
|
+
this._emptyFormula = context.emptyFormula;
|
|
117
128
|
}
|
|
118
129
|
}
|
|
119
130
|
|
|
@@ -205,6 +216,9 @@ export default class N3Parser {
|
|
|
205
216
|
// ### `_readSubject` reads a quad's subject
|
|
206
217
|
_readSubject(token) {
|
|
207
218
|
this._predicate = null;
|
|
219
|
+
// Any statement token means the enclosing formula is not empty
|
|
220
|
+
if (token.type !== '}')
|
|
221
|
+
this._emptyFormula = false;
|
|
208
222
|
switch (token.type) {
|
|
209
223
|
case '[':
|
|
210
224
|
// Start a new quad with a new blank node as subject
|
|
@@ -626,10 +640,9 @@ export default class N3Parser {
|
|
|
626
640
|
}
|
|
627
641
|
|
|
628
642
|
// ### `_completeLiteral` completes a literal with an optional datatype or language
|
|
643
|
+
// Defers possible direction tags without allocating bound callbacks.
|
|
629
644
|
_completeLiteral(token, component) {
|
|
630
|
-
|
|
631
|
-
let literal = this._factory.literal(this._literalValue);
|
|
632
|
-
let readCb;
|
|
645
|
+
let literal, readCb = false;
|
|
633
646
|
|
|
634
647
|
switch (token.type) {
|
|
635
648
|
// Create a datatyped literal
|
|
@@ -650,14 +663,21 @@ export default class N3Parser {
|
|
|
650
663
|
literal = this._factory.literal(this._literalValue, token.value);
|
|
651
664
|
this._literalLanguage = token.value;
|
|
652
665
|
token = null;
|
|
653
|
-
|
|
666
|
+
// Save state for a possible direction tag
|
|
667
|
+
this._literalComponent = component;
|
|
668
|
+
readCb = true;
|
|
654
669
|
break;
|
|
670
|
+
// Create a simple string literal by default
|
|
671
|
+
default:
|
|
672
|
+
literal = this._factory.literal(this._literalValue);
|
|
655
673
|
}
|
|
656
674
|
|
|
657
675
|
return { token, literal, readCb };
|
|
658
676
|
}
|
|
659
677
|
|
|
660
|
-
_readDirCode
|
|
678
|
+
// ### `_readDirCode` reads an optional directional language tag
|
|
679
|
+
_readDirCode(token) {
|
|
680
|
+
const component = this._literalComponent, listItem = this._literalListItem;
|
|
661
681
|
// Attempt to read a dircode
|
|
662
682
|
if (token.type === 'dircode') {
|
|
663
683
|
const term = this._factory.literal(this._literalValue, { language: this._literalLanguage, direction: token.value });
|
|
@@ -699,8 +719,10 @@ export default class N3Parser {
|
|
|
699
719
|
}
|
|
700
720
|
|
|
701
721
|
// Postpone completion if the literal is only partially completed (such as lang+dir).
|
|
702
|
-
if (completed.readCb)
|
|
703
|
-
|
|
722
|
+
if (completed.readCb) {
|
|
723
|
+
this._literalListItem = false;
|
|
724
|
+
return this._readDirCode;
|
|
725
|
+
}
|
|
704
726
|
|
|
705
727
|
// A subject literal implies N3 mode, so it might start a path.
|
|
706
728
|
if (component === 'subject') {
|
|
@@ -733,8 +755,10 @@ export default class N3Parser {
|
|
|
733
755
|
this._object = completed.literal;
|
|
734
756
|
|
|
735
757
|
// Postpone completion if the literal is only partially completed (such as lang+dir).
|
|
736
|
-
if (completed.readCb)
|
|
737
|
-
|
|
758
|
+
if (completed.readCb) {
|
|
759
|
+
this._literalListItem = listItem;
|
|
760
|
+
return this._readDirCode;
|
|
761
|
+
}
|
|
738
762
|
|
|
739
763
|
return this._completeObjectLiteralPost(completed.token, listItem);
|
|
740
764
|
}
|
|
@@ -774,8 +798,20 @@ export default class N3Parser {
|
|
|
774
798
|
if (this._subject !== null)
|
|
775
799
|
this._emit(this._subject, this._predicate, this._object, this._graph);
|
|
776
800
|
|
|
801
|
+
const formula = this._graph, empty = this._emptyFormula;
|
|
777
802
|
// Restore the parent context containing this formula
|
|
778
803
|
this._restoreContext('formula', token);
|
|
804
|
+
|
|
805
|
+
// When the emptyFormulaAsTrue option is set, an empty formula
|
|
806
|
+
// is read as the boolean literal true, following the N3 spec tests
|
|
807
|
+
// and the direction discussed in https://github.com/w3c-cg/N3/issues/185
|
|
808
|
+
if (empty && this._emptyFormulaAsTrue) {
|
|
809
|
+
if (this._subject === formula)
|
|
810
|
+
this._subject = this.N3_TRUE;
|
|
811
|
+
else
|
|
812
|
+
this._object = this.N3_TRUE;
|
|
813
|
+
}
|
|
814
|
+
|
|
779
815
|
// If the formula was the subject, continue reading the predicate.
|
|
780
816
|
// If the formula was the object, read punctuation.
|
|
781
817
|
return this._object === null ? this._readPredicate : this._getContextEndReader();
|
|
@@ -1392,6 +1428,7 @@ export default class N3Parser {
|
|
|
1392
1428
|
this._versionCallback = onVersion || noop;
|
|
1393
1429
|
this._inversePredicate = false;
|
|
1394
1430
|
this._quantified = Object.create(null);
|
|
1431
|
+
this._emptyFormula = false;
|
|
1395
1432
|
|
|
1396
1433
|
// Parse synchronously if no quad callback is given
|
|
1397
1434
|
if (!onQuad) {
|
|
@@ -1451,6 +1488,7 @@ function initDataFactory(parser, factory) {
|
|
|
1451
1488
|
parser.RDF_REIFIES = factory.namedNode(namespaces.rdf.reifies);
|
|
1452
1489
|
parser.N3_FORALL = factory.namedNode(namespaces.r.forAll);
|
|
1453
1490
|
parser.N3_FORSOME = factory.namedNode(namespaces.r.forSome);
|
|
1491
|
+
parser.N3_TRUE = factory.literal('true', factory.namedNode(namespaces.xsd.boolean));
|
|
1454
1492
|
parser.ABBREVIATIONS = {
|
|
1455
1493
|
'a': factory.namedNode(namespaces.rdf.type),
|
|
1456
1494
|
'=': factory.namedNode(namespaces.owl.sameAs),
|