n3 2.13.1 → 2.13.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/lib/N3Lexer.js CHANGED
@@ -136,7 +136,7 @@ class N3Lexer {
136
136
  if (!(key in lineModeRegExps) && this[key] instanceof RegExp) this[key] = invalidRegExp;
137
137
  }
138
138
  // The only keyword in N-Triples and N-Quads is VERSION, which is case-sensitive
139
- this._keyword = /VERSION(?=[\s#<])/y;
139
+ this._keyword = /VERSION(?=[\s#<"])/y;
140
140
  }
141
141
  // When not in line mode, enable N3 functionality by default
142
142
  else {
@@ -737,6 +737,27 @@ class N3Lexer {
737
737
  return err;
738
738
  }
739
739
 
740
+ // ### `_startTokenization` resets the lexer state for a new input
741
+ _startTokenization() {
742
+ this._line = 1;
743
+ this._linePosition = 0;
744
+ this._previousMarker = undefined;
745
+ this.previousToken = undefined;
746
+ this._literalClosingPos = 0;
747
+ this._input = undefined;
748
+ // Deferred tokenization and stream events can outlive their invocation.
749
+ // Ignore them once a later call takes ownership of the lexer state.
750
+ return this._tokenization = {};
751
+ }
752
+
753
+ // ### `_tokenizeString` synchronously emits the tokens of a complete string through the callback,
754
+ // so that the caller can consume each token without the lexer collecting them all first
755
+ _tokenizeString(input, callback) {
756
+ this._startTokenization();
757
+ this._input = this._readStartingBom(input);
758
+ this._tryTokenizeToEnd(callback, true);
759
+ }
760
+
740
761
  // ### Strips off any starting UTF BOM mark.
741
762
  _readStartingBom(input) {
742
763
  if (input.startsWith('\ufeff')) {
@@ -754,15 +775,7 @@ class N3Lexer {
754
775
  // Separator whitespace counts towards the next token's start, outside either range.
755
776
  // Multiline tokens also have endLine; their end column is relative to that line.
756
777
  tokenize(input, callback) {
757
- // Deferred tokenization and stream events can outlive their invocation.
758
- // Ignore them once a later call takes ownership of the lexer state.
759
- const tokenization = this._tokenization = {};
760
- this._line = 1;
761
- this._linePosition = 0;
762
- this._previousMarker = undefined;
763
- this.previousToken = undefined;
764
- this._literalClosingPos = 0;
765
- this._input = undefined;
778
+ const tokenization = this._startTokenization();
766
779
 
767
780
  // If the input is a string, continuously emit tokens through the callback until the end
768
781
  if (typeof input === 'string') {
package/lib/N3Parser.js CHANGED
@@ -1554,6 +1554,10 @@ class N3Parser {
1554
1554
  // The read callback is the next function to be executed when a token arrives.
1555
1555
  // We start reading in the top context.
1556
1556
  this._readCallback = this._readBeforeTopContext;
1557
+ // A parse that failed part-way can have left scopes and a statement open
1558
+ this._contextStack = [];
1559
+ this._graph = this._subject = this._predicate = this._object = null;
1560
+ this._tripleTerm = this._reifier = null;
1557
1561
  this._sparqlStyle = false;
1558
1562
  this._prefixes = Object.create(null);
1559
1563
  this._prefixes._ = this._blankNodePrefix ? this._blankNodePrefix.substr(2) : `b${blankNodePrefix++}_`;
@@ -1570,14 +1574,14 @@ class N3Parser {
1570
1574
  this._quantifiedChanges = null;
1571
1575
  this._emptyFormula = false;
1572
1576
  this._tripleTermDepth = 0;
1573
- let readToken = token => {
1577
+ const readGrammarToken = token => {
1574
1578
  return this._readCallback = this._readCallback(token);
1575
1579
  };
1580
+ let readToken = readGrammarToken;
1576
1581
 
1577
1582
  // Comments bypass the grammar, but participate in the token lifecycle.
1578
1583
  if (onComment || this._lexer.comments) {
1579
1584
  this._lexer.comments = true;
1580
- const readGrammarToken = readToken;
1581
1585
  readToken = token => {
1582
1586
  if (token.type !== 'comment') return readGrammarToken(token);
1583
1587
  if (onComment) onComment(token.value);
@@ -1611,7 +1615,22 @@ class N3Parser {
1611
1615
  this._callback = (e, t) => {
1612
1616
  e ? error = e : t && quads.push(t);
1613
1617
  };
1614
- this._lexer.tokenize(input).every(readToken);
1618
+ const lexer = this._lexer;
1619
+ // Without callbacks, nothing observes the parse before the whole document
1620
+ // has lexed, so tokens can be parsed as they are lexed instead of being
1621
+ // collected into an array first. A lexer that replaces the built-in
1622
+ // tokenize keeps going through its own implementation.
1623
+ if (!onPrefix && !onVersion && !onDirective && !onComment && !onToken && !onTokenEnd && lexer.tokenize === _N3Lexer.default.prototype.tokenize && typeof lexer._tokenizeString === 'function') {
1624
+ // A lexical error used to stop the parse before any token was read,
1625
+ // so undo base declarations that were read before it
1626
+ const base = [this._base, this._basePath, this._baseRoot, this._baseScheme];
1627
+ lexer._tokenizeString(input, (e, token) => {
1628
+ if (e) {
1629
+ [this._base, this._basePath, this._baseRoot, this._baseScheme] = base;
1630
+ this._callback(e), this._callback = noop;
1631
+ } else if (this._readCallback) readToken(token);
1632
+ });
1633
+ } else lexer.tokenize(input).every(readToken);
1615
1634
  if (error) throw error;
1616
1635
  return quads;
1617
1636
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n3",
3
- "version": "2.13.1",
3
+ "version": "2.13.3",
4
4
  "description": "Lightning fast, asynchronous, streaming Turtle / N3 / RDF library.",
5
5
  "author": "Ruben Verborgh <ruben.verborgh@gmail.com>",
6
6
  "keywords": [
package/src/N3Lexer.js CHANGED
@@ -102,7 +102,7 @@ export default class N3Lexer {
102
102
  this[key] = invalidRegExp;
103
103
  }
104
104
  // The only keyword in N-Triples and N-Quads is VERSION, which is case-sensitive
105
- this._keyword = /VERSION(?=[\s#<])/y;
105
+ this._keyword = /VERSION(?=[\s#<"])/y;
106
106
  }
107
107
  // When not in line mode, enable N3 functionality by default
108
108
  else {
@@ -758,6 +758,27 @@ export default class N3Lexer {
758
758
  return err;
759
759
  }
760
760
 
761
+ // ### `_startTokenization` resets the lexer state for a new input
762
+ _startTokenization() {
763
+ this._line = 1;
764
+ this._linePosition = 0;
765
+ this._previousMarker = undefined;
766
+ this.previousToken = undefined;
767
+ this._literalClosingPos = 0;
768
+ this._input = undefined;
769
+ // Deferred tokenization and stream events can outlive their invocation.
770
+ // Ignore them once a later call takes ownership of the lexer state.
771
+ return this._tokenization = {};
772
+ }
773
+
774
+ // ### `_tokenizeString` synchronously emits the tokens of a complete string through the callback,
775
+ // so that the caller can consume each token without the lexer collecting them all first
776
+ _tokenizeString(input, callback) {
777
+ this._startTokenization();
778
+ this._input = this._readStartingBom(input);
779
+ this._tryTokenizeToEnd(callback, true);
780
+ }
781
+
761
782
  // ### Strips off any starting UTF BOM mark.
762
783
  _readStartingBom(input) {
763
784
  if (input.startsWith('\ufeff')) {
@@ -775,15 +796,7 @@ export default class N3Lexer {
775
796
  // Separator whitespace counts towards the next token's start, outside either range.
776
797
  // Multiline tokens also have endLine; their end column is relative to that line.
777
798
  tokenize(input, callback) {
778
- // Deferred tokenization and stream events can outlive their invocation.
779
- // Ignore them once a later call takes ownership of the lexer state.
780
- const tokenization = this._tokenization = {};
781
- this._line = 1;
782
- this._linePosition = 0;
783
- this._previousMarker = undefined;
784
- this.previousToken = undefined;
785
- this._literalClosingPos = 0;
786
- this._input = undefined;
799
+ const tokenization = this._startTokenization();
787
800
 
788
801
  // If the input is a string, continuously emit tokens through the callback until the end
789
802
  if (typeof input === 'string') {
package/src/N3Parser.js CHANGED
@@ -1682,6 +1682,10 @@ export default class N3Parser {
1682
1682
  // The read callback is the next function to be executed when a token arrives.
1683
1683
  // We start reading in the top context.
1684
1684
  this._readCallback = this._readBeforeTopContext;
1685
+ // A parse that failed part-way can have left scopes and a statement open
1686
+ this._contextStack = [];
1687
+ this._graph = this._subject = this._predicate = this._object = null;
1688
+ this._tripleTerm = this._reifier = null;
1685
1689
  this._sparqlStyle = false;
1686
1690
  this._prefixes = Object.create(null);
1687
1691
  this._prefixes._ = this._blankNodePrefix ? this._blankNodePrefix.substr(2)
@@ -1701,14 +1705,14 @@ export default class N3Parser {
1701
1705
  this._emptyFormula = false;
1702
1706
  this._tripleTermDepth = 0;
1703
1707
 
1704
- let readToken = token => {
1708
+ const readGrammarToken = token => {
1705
1709
  return this._readCallback = this._readCallback(token);
1706
1710
  };
1711
+ let readToken = readGrammarToken;
1707
1712
 
1708
1713
  // Comments bypass the grammar, but participate in the token lifecycle.
1709
1714
  if (onComment || this._lexer.comments) {
1710
1715
  this._lexer.comments = true;
1711
- const readGrammarToken = readToken;
1712
1716
  readToken = token => {
1713
1717
  if (token.type !== 'comment')
1714
1718
  return readGrammarToken(token);
@@ -1743,7 +1747,26 @@ export default class N3Parser {
1743
1747
  const quads = [];
1744
1748
  let error;
1745
1749
  this._callback = (e, t) => { e ? (error = e) : t && quads.push(t); };
1746
- this._lexer.tokenize(input).every(readToken);
1750
+ const lexer = this._lexer;
1751
+ // Without callbacks, nothing observes the parse before the whole document
1752
+ // has lexed, so tokens can be parsed as they are lexed instead of being
1753
+ // collected into an array first. A lexer that replaces the built-in
1754
+ // tokenize keeps going through its own implementation.
1755
+ if (!onPrefix && !onVersion && !onDirective && !onComment && !onToken && !onTokenEnd &&
1756
+ lexer.tokenize === N3Lexer.prototype.tokenize && typeof lexer._tokenizeString === 'function') {
1757
+ // A lexical error used to stop the parse before any token was read,
1758
+ // so undo base declarations that were read before it
1759
+ const base = [this._base, this._basePath, this._baseRoot, this._baseScheme];
1760
+ lexer._tokenizeString(input, (e, token) => {
1761
+ if (e) {
1762
+ [this._base, this._basePath, this._baseRoot, this._baseScheme] = base;
1763
+ this._callback(e), this._callback = noop;
1764
+ }
1765
+ else if (this._readCallback) readToken(token);
1766
+ });
1767
+ }
1768
+ else
1769
+ lexer.tokenize(input).every(readToken);
1747
1770
  if (error) throw error;
1748
1771
  return quads;
1749
1772
  }