n3 2.12.0 → 2.12.2
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 +7 -7
- package/browser/n3.min.js +7 -7
- package/lib/N3Lexer.js +52 -14
- package/lib/N3Parser.js +2 -1
- package/package.json +1 -1
- package/src/N3Lexer.js +44 -14
- package/src/N3Parser.js +2 -1
package/lib/N3Lexer.js
CHANGED
|
@@ -116,8 +116,8 @@ class N3Lexer {
|
|
|
116
116
|
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#()\[\]\{\}"'<>]))/y;
|
|
117
117
|
this._number = /[\-+]?(?:(\d+\.\d*|\.?\d+)[eE][\-+]?\d+|(?=\.?\d)\d*(?:(\.)\d+)?)(?=\.?[,;:!\^\s#()\[\]\{\}"'<>])/y;
|
|
118
118
|
this._boolean = /(?:true|false)(?=[.,;!\^\s#()\[\]\{\}"'<>])/y;
|
|
119
|
-
this._atKeyword = /@[a-z]+(?=[\s#<:])/iy;
|
|
120
|
-
this._keyword = /(?:PREFIX|BASE|VERSION|GRAPH)(?=[\s#<])/iy;
|
|
119
|
+
this._atKeyword = /@[a-z]+(?=[\s#<:"'])/iy;
|
|
120
|
+
this._keyword = /(?:PREFIX|BASE|VERSION|GRAPH)(?=[\s#<"'])/iy;
|
|
121
121
|
this._n3Verb = /(?:has|is|of)(?=[\s#()\[\]\{\}"'<>?_+\-0-9])/y;
|
|
122
122
|
this._n3Id = /id(?=[\s#<])/y;
|
|
123
123
|
this._shortPredicates = /a(?=[\s#()\[\]\{\}"'<>])/y;
|
|
@@ -236,7 +236,8 @@ class N3Lexer {
|
|
|
236
236
|
matchLength = 0,
|
|
237
237
|
lexicalLength = 0,
|
|
238
238
|
finalLineLength = 0,
|
|
239
|
-
inconclusive = false
|
|
239
|
+
inconclusive = false,
|
|
240
|
+
tripleQuoted = false;
|
|
240
241
|
switch (firstChar) {
|
|
241
242
|
case '^':
|
|
242
243
|
// A datatype marker separated from its type cannot be followed by another marker
|
|
@@ -310,7 +311,8 @@ class N3Lexer {
|
|
|
310
311
|
({
|
|
311
312
|
value,
|
|
312
313
|
matchLength,
|
|
313
|
-
finalLineLength
|
|
314
|
+
finalLineLength,
|
|
315
|
+
tripleQuoted
|
|
314
316
|
} = this._parseLiteral(input, pos));
|
|
315
317
|
if (value === null) return reportSyntaxError(this, input, pos);
|
|
316
318
|
}
|
|
@@ -328,7 +330,8 @@ class N3Lexer {
|
|
|
328
330
|
({
|
|
329
331
|
value,
|
|
330
332
|
matchLength,
|
|
331
|
-
finalLineLength
|
|
333
|
+
finalLineLength,
|
|
334
|
+
tripleQuoted
|
|
332
335
|
} = this._parseLiteral(input, pos));
|
|
333
336
|
if (value === null) return reportSyntaxError(this, input, pos);
|
|
334
337
|
}
|
|
@@ -521,7 +524,21 @@ class N3Lexer {
|
|
|
521
524
|
line,
|
|
522
525
|
start,
|
|
523
526
|
end: finalLineLength,
|
|
524
|
-
endLine: this._line
|
|
527
|
+
endLine: this._line,
|
|
528
|
+
tripleQuoted
|
|
529
|
+
};
|
|
530
|
+
callback(null, token);
|
|
531
|
+
}
|
|
532
|
+
// Triple-quoted strings are marked, since version declarations do not allow them
|
|
533
|
+
else if (tripleQuoted) {
|
|
534
|
+
token = {
|
|
535
|
+
type,
|
|
536
|
+
value,
|
|
537
|
+
prefix,
|
|
538
|
+
line,
|
|
539
|
+
start,
|
|
540
|
+
end: start + length,
|
|
541
|
+
tripleQuoted
|
|
525
542
|
};
|
|
526
543
|
callback(null, token);
|
|
527
544
|
} else token = emitToken(type, value, prefix, line, start, lexicalLength || length);
|
|
@@ -671,7 +688,8 @@ class N3Lexer {
|
|
|
671
688
|
return {
|
|
672
689
|
value: this._unescape(raw, stringEscapeReplacements),
|
|
673
690
|
matchLength,
|
|
674
|
-
finalLineLength
|
|
691
|
+
finalLineLength,
|
|
692
|
+
tripleQuoted: openingLength === 3
|
|
675
693
|
};
|
|
676
694
|
}
|
|
677
695
|
closingPos++;
|
|
@@ -681,14 +699,34 @@ class N3Lexer {
|
|
|
681
699
|
return {
|
|
682
700
|
value: '',
|
|
683
701
|
matchLength: 0,
|
|
684
|
-
finalLineLength: 0
|
|
702
|
+
finalLineLength: 0,
|
|
703
|
+
tripleQuoted: false
|
|
685
704
|
};
|
|
686
705
|
}
|
|
687
706
|
|
|
707
|
+
// ### `_tryTokenizeToEnd` tokenizes as far as possible, reporting failures through the callback
|
|
708
|
+
_tryTokenizeToEnd(callback, inputFinished) {
|
|
709
|
+
// Keep track of errors thrown by the callback, which must reach the caller unchanged
|
|
710
|
+
let callbackError;
|
|
711
|
+
try {
|
|
712
|
+
this._tokenizeToEnd((error, token) => {
|
|
713
|
+
try {
|
|
714
|
+
return callback(error, token);
|
|
715
|
+
} catch (thrown) {
|
|
716
|
+
throw callbackError = thrown;
|
|
717
|
+
}
|
|
718
|
+
}, inputFinished);
|
|
719
|
+
} catch (error) {
|
|
720
|
+
// Matching an extremely long token can exhaust the regular expression stack
|
|
721
|
+
if (error === callbackError || !(error instanceof RangeError)) throw error;
|
|
722
|
+
callback(this._syntaxError(null, `Token too long on line ${this._line}.`));
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
|
|
688
726
|
// ### `_syntaxError` creates a syntax error for the given issue
|
|
689
|
-
_syntaxError(issue) {
|
|
727
|
+
_syntaxError(issue, message = `Unexpected "${issue}" on line ${this._line}.`) {
|
|
690
728
|
this._input = null;
|
|
691
|
-
const err = new Error(
|
|
729
|
+
const err = new Error(message);
|
|
692
730
|
err.context = {
|
|
693
731
|
token: undefined,
|
|
694
732
|
line: this._line,
|
|
@@ -729,13 +767,13 @@ class N3Lexer {
|
|
|
729
767
|
this._input = this._readStartingBom(input);
|
|
730
768
|
// If a callback was passed, asynchronously call it
|
|
731
769
|
if (typeof callback === 'function') queueMicrotask(() => {
|
|
732
|
-
if (this._tokenization === tokenization) this.
|
|
770
|
+
if (this._tokenization === tokenization) this._tryTokenizeToEnd(callback, true);
|
|
733
771
|
});
|
|
734
772
|
// If no callback was passed, tokenize synchronously and return
|
|
735
773
|
else {
|
|
736
774
|
const tokens = [];
|
|
737
775
|
let error;
|
|
738
|
-
this.
|
|
776
|
+
this._tryTokenizeToEnd((e, t) => e ? error = e : tokens.push(t), true);
|
|
739
777
|
if (error) throw error;
|
|
740
778
|
return tokens;
|
|
741
779
|
}
|
|
@@ -762,7 +800,7 @@ class N3Lexer {
|
|
|
762
800
|
// Tokenize as far as possible. When a previous attempt left a long unfinished token,
|
|
763
801
|
// wait until the buffered input has doubled, so the token is not rescanned for every chunk.
|
|
764
802
|
if (this._input.length >= retryLength) {
|
|
765
|
-
this.
|
|
803
|
+
this._tryTokenizeToEnd(callback, false);
|
|
766
804
|
retryLength = this._input !== null && this._input.length > MIN_RESCAN_LENGTH ? 2 * this._input.length : 0;
|
|
767
805
|
}
|
|
768
806
|
}
|
|
@@ -773,7 +811,7 @@ class N3Lexer {
|
|
|
773
811
|
// Decode any incomplete character left at the end
|
|
774
812
|
const rest = decoder ? decoder.decode() : '';
|
|
775
813
|
if (rest) this._input = typeof this._input === 'string' ? this._input + rest : rest;
|
|
776
|
-
if (typeof this._input === 'string') this.
|
|
814
|
+
if (typeof this._input === 'string') this._tryTokenizeToEnd(callback, true);
|
|
777
815
|
}
|
|
778
816
|
});
|
|
779
817
|
input.on('error', error => {
|
package/lib/N3Parser.js
CHANGED
|
@@ -1025,7 +1025,8 @@ class N3Parser {
|
|
|
1025
1025
|
// ### `_readVersion` reads version string declaration
|
|
1026
1026
|
_readVersion(token) {
|
|
1027
1027
|
if (token.type !== 'literal') return this._error('Expected literal to follow version declaration', token);
|
|
1028
|
-
|
|
1028
|
+
// Only short strings are allowed, so no numbers or booleans (which have a datatype prefix)
|
|
1029
|
+
if (token.prefix !== '' || token.tripleQuoted) return this._error('Version declarations must use single quotes', token);
|
|
1029
1030
|
this._versionCallback(token.value);
|
|
1030
1031
|
if (!this._isValidVersion(token.value)) return this._error(`Detected unsupported version: "${token.value}"`, token);
|
|
1031
1032
|
return this._readDeclarationPunctuation;
|
package/package.json
CHANGED
package/src/N3Lexer.js
CHANGED
|
@@ -81,8 +81,8 @@ export default class N3Lexer {
|
|
|
81
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#()\[\]\{\}"'<>]))/y;
|
|
82
82
|
this._number = /[\-+]?(?:(\d+\.\d*|\.?\d+)[eE][\-+]?\d+|(?=\.?\d)\d*(?:(\.)\d+)?)(?=\.?[,;:!\^\s#()\[\]\{\}"'<>])/y;
|
|
83
83
|
this._boolean = /(?:true|false)(?=[.,;!\^\s#()\[\]\{\}"'<>])/y;
|
|
84
|
-
this._atKeyword = /@[a-z]+(?=[\s#<:])/iy;
|
|
85
|
-
this._keyword = /(?:PREFIX|BASE|VERSION|GRAPH)(?=[\s#<])/iy;
|
|
84
|
+
this._atKeyword = /@[a-z]+(?=[\s#<:"'])/iy;
|
|
85
|
+
this._keyword = /(?:PREFIX|BASE|VERSION|GRAPH)(?=[\s#<"'])/iy;
|
|
86
86
|
this._n3Verb = /(?:has|is|of)(?=[\s#()\[\]\{\}"'<>?_+\-0-9])/y;
|
|
87
87
|
this._n3Id = /id(?=[\s#<])/y;
|
|
88
88
|
this._shortPredicates = /a(?=[\s#()\[\]\{\}"'<>])/y;
|
|
@@ -208,7 +208,7 @@ export default class N3Lexer {
|
|
|
208
208
|
const line = this._line, firstChar = input[pos];
|
|
209
209
|
let type = '', value = '', prefix = '',
|
|
210
210
|
match = null, matchLength = 0, lexicalLength = 0,
|
|
211
|
-
finalLineLength = 0, inconclusive = false;
|
|
211
|
+
finalLineLength = 0, inconclusive = false, tripleQuoted = false;
|
|
212
212
|
switch (firstChar) {
|
|
213
213
|
case '^':
|
|
214
214
|
// A datatype marker separated from its type cannot be followed by another marker
|
|
@@ -293,7 +293,7 @@ export default class N3Lexer {
|
|
|
293
293
|
value = match[1];
|
|
294
294
|
// Try to find a literal wrapped in three pairs of quotes
|
|
295
295
|
else {
|
|
296
|
-
({ value, matchLength, finalLineLength } = this._parseLiteral(input, pos));
|
|
296
|
+
({ value, matchLength, finalLineLength, tripleQuoted } = this._parseLiteral(input, pos));
|
|
297
297
|
if (value === null)
|
|
298
298
|
return reportSyntaxError(this, input, pos);
|
|
299
299
|
}
|
|
@@ -310,7 +310,7 @@ export default class N3Lexer {
|
|
|
310
310
|
value = match[1];
|
|
311
311
|
// Try to find a literal wrapped in three pairs of quotes
|
|
312
312
|
else {
|
|
313
|
-
({ value, matchLength, finalLineLength } = this._parseLiteral(input, pos));
|
|
313
|
+
({ value, matchLength, finalLineLength, tripleQuoted } = this._parseLiteral(input, pos));
|
|
314
314
|
if (value === null)
|
|
315
315
|
return reportSyntaxError(this, input, pos);
|
|
316
316
|
}
|
|
@@ -550,10 +550,15 @@ export default class N3Lexer {
|
|
|
550
550
|
if (finalLineLength) {
|
|
551
551
|
token = {
|
|
552
552
|
type, value, prefix, line, start,
|
|
553
|
-
end: finalLineLength, endLine: this._line,
|
|
553
|
+
end: finalLineLength, endLine: this._line, tripleQuoted,
|
|
554
554
|
};
|
|
555
555
|
callback(null, token);
|
|
556
556
|
}
|
|
557
|
+
// Triple-quoted strings are marked, since version declarations do not allow them
|
|
558
|
+
else if (tripleQuoted) {
|
|
559
|
+
token = { type, value, prefix, line, start, end: start + length, tripleQuoted };
|
|
560
|
+
callback(null, token);
|
|
561
|
+
}
|
|
557
562
|
else
|
|
558
563
|
token = emitToken(type, value, prefix, line, start, lexicalLength || length);
|
|
559
564
|
this.previousToken = token;
|
|
@@ -705,19 +710,44 @@ export default class N3Lexer {
|
|
|
705
710
|
break;
|
|
706
711
|
this._line += lineCount;
|
|
707
712
|
const finalLineLength = lineCount === 0 ? 0 : lines[lines.length - 1].length + openingLength;
|
|
708
|
-
return {
|
|
713
|
+
return {
|
|
714
|
+
value: this._unescape(raw, stringEscapeReplacements), matchLength, finalLineLength,
|
|
715
|
+
tripleQuoted: openingLength === 3,
|
|
716
|
+
};
|
|
709
717
|
}
|
|
710
718
|
closingPos++;
|
|
711
719
|
}
|
|
712
720
|
this._literalClosingPos = input.length - pos - openingLength + 1;
|
|
713
721
|
}
|
|
714
|
-
return { value: '', matchLength: 0, finalLineLength: 0 };
|
|
722
|
+
return { value: '', matchLength: 0, finalLineLength: 0, tripleQuoted: false };
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
// ### `_tryTokenizeToEnd` tokenizes as far as possible, reporting failures through the callback
|
|
726
|
+
_tryTokenizeToEnd(callback, inputFinished) {
|
|
727
|
+
// Keep track of errors thrown by the callback, which must reach the caller unchanged
|
|
728
|
+
let callbackError;
|
|
729
|
+
try {
|
|
730
|
+
this._tokenizeToEnd((error, token) => {
|
|
731
|
+
try {
|
|
732
|
+
return callback(error, token);
|
|
733
|
+
}
|
|
734
|
+
catch (thrown) {
|
|
735
|
+
throw (callbackError = thrown);
|
|
736
|
+
}
|
|
737
|
+
}, inputFinished);
|
|
738
|
+
}
|
|
739
|
+
catch (error) {
|
|
740
|
+
// Matching an extremely long token can exhaust the regular expression stack
|
|
741
|
+
if (error === callbackError || !(error instanceof RangeError))
|
|
742
|
+
throw error;
|
|
743
|
+
callback(this._syntaxError(null, `Token too long on line ${this._line}.`));
|
|
744
|
+
}
|
|
715
745
|
}
|
|
716
746
|
|
|
717
747
|
// ### `_syntaxError` creates a syntax error for the given issue
|
|
718
|
-
_syntaxError(issue) {
|
|
748
|
+
_syntaxError(issue, message = `Unexpected "${issue}" on line ${this._line}.`) {
|
|
719
749
|
this._input = null;
|
|
720
|
-
const err = new Error(
|
|
750
|
+
const err = new Error(message);
|
|
721
751
|
err.context = {
|
|
722
752
|
token: undefined,
|
|
723
753
|
line: this._line,
|
|
@@ -760,13 +790,13 @@ export default class N3Lexer {
|
|
|
760
790
|
if (typeof callback === 'function')
|
|
761
791
|
queueMicrotask(() => {
|
|
762
792
|
if (this._tokenization === tokenization)
|
|
763
|
-
this.
|
|
793
|
+
this._tryTokenizeToEnd(callback, true);
|
|
764
794
|
});
|
|
765
795
|
// If no callback was passed, tokenize synchronously and return
|
|
766
796
|
else {
|
|
767
797
|
const tokens = [];
|
|
768
798
|
let error;
|
|
769
|
-
this.
|
|
799
|
+
this._tryTokenizeToEnd((e, t) => e ? (error = e) : tokens.push(t), true);
|
|
770
800
|
if (error) throw error;
|
|
771
801
|
return tokens;
|
|
772
802
|
}
|
|
@@ -793,7 +823,7 @@ export default class N3Lexer {
|
|
|
793
823
|
// Tokenize as far as possible. When a previous attempt left a long unfinished token,
|
|
794
824
|
// wait until the buffered input has doubled, so the token is not rescanned for every chunk.
|
|
795
825
|
if (this._input.length >= retryLength) {
|
|
796
|
-
this.
|
|
826
|
+
this._tryTokenizeToEnd(callback, false);
|
|
797
827
|
retryLength = this._input !== null && this._input.length > MIN_RESCAN_LENGTH ?
|
|
798
828
|
2 * this._input.length : 0;
|
|
799
829
|
}
|
|
@@ -807,7 +837,7 @@ export default class N3Lexer {
|
|
|
807
837
|
if (rest)
|
|
808
838
|
this._input = typeof this._input === 'string' ? this._input + rest : rest;
|
|
809
839
|
if (typeof this._input === 'string')
|
|
810
|
-
this.
|
|
840
|
+
this._tryTokenizeToEnd(callback, true);
|
|
811
841
|
}
|
|
812
842
|
});
|
|
813
843
|
input.on('error', error => {
|
package/src/N3Parser.js
CHANGED
|
@@ -1111,7 +1111,8 @@ export default class N3Parser {
|
|
|
1111
1111
|
_readVersion(token) {
|
|
1112
1112
|
if (token.type !== 'literal')
|
|
1113
1113
|
return this._error('Expected literal to follow version declaration', token);
|
|
1114
|
-
|
|
1114
|
+
// Only short strings are allowed, so no numbers or booleans (which have a datatype prefix)
|
|
1115
|
+
if (token.prefix !== '' || token.tripleQuoted)
|
|
1115
1116
|
return this._error('Version declarations must use single quotes', token);
|
|
1116
1117
|
this._versionCallback(token.value);
|
|
1117
1118
|
if (!this._isValidVersion(token.value))
|