n3 2.12.0 → 2.12.1

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
@@ -685,10 +685,29 @@ class N3Lexer {
685
685
  };
686
686
  }
687
687
 
688
+ // ### `_tryTokenizeToEnd` tokenizes as far as possible, reporting failures through the callback
689
+ _tryTokenizeToEnd(callback, inputFinished) {
690
+ // Keep track of errors thrown by the callback, which must reach the caller unchanged
691
+ let callbackError;
692
+ try {
693
+ this._tokenizeToEnd((error, token) => {
694
+ try {
695
+ return callback(error, token);
696
+ } catch (thrown) {
697
+ throw callbackError = thrown;
698
+ }
699
+ }, inputFinished);
700
+ } catch (error) {
701
+ // Matching an extremely long token can exhaust the regular expression stack
702
+ if (error === callbackError || !(error instanceof RangeError)) throw error;
703
+ callback(this._syntaxError(null, `Token too long on line ${this._line}.`));
704
+ }
705
+ }
706
+
688
707
  // ### `_syntaxError` creates a syntax error for the given issue
689
- _syntaxError(issue) {
708
+ _syntaxError(issue, message = `Unexpected "${issue}" on line ${this._line}.`) {
690
709
  this._input = null;
691
- const err = new Error(`Unexpected "${issue}" on line ${this._line}.`);
710
+ const err = new Error(message);
692
711
  err.context = {
693
712
  token: undefined,
694
713
  line: this._line,
@@ -729,13 +748,13 @@ class N3Lexer {
729
748
  this._input = this._readStartingBom(input);
730
749
  // If a callback was passed, asynchronously call it
731
750
  if (typeof callback === 'function') queueMicrotask(() => {
732
- if (this._tokenization === tokenization) this._tokenizeToEnd(callback, true);
751
+ if (this._tokenization === tokenization) this._tryTokenizeToEnd(callback, true);
733
752
  });
734
753
  // If no callback was passed, tokenize synchronously and return
735
754
  else {
736
755
  const tokens = [];
737
756
  let error;
738
- this._tokenizeToEnd((e, t) => e ? error = e : tokens.push(t), true);
757
+ this._tryTokenizeToEnd((e, t) => e ? error = e : tokens.push(t), true);
739
758
  if (error) throw error;
740
759
  return tokens;
741
760
  }
@@ -762,7 +781,7 @@ class N3Lexer {
762
781
  // Tokenize as far as possible. When a previous attempt left a long unfinished token,
763
782
  // wait until the buffered input has doubled, so the token is not rescanned for every chunk.
764
783
  if (this._input.length >= retryLength) {
765
- this._tokenizeToEnd(callback, false);
784
+ this._tryTokenizeToEnd(callback, false);
766
785
  retryLength = this._input !== null && this._input.length > MIN_RESCAN_LENGTH ? 2 * this._input.length : 0;
767
786
  }
768
787
  }
@@ -773,7 +792,7 @@ class N3Lexer {
773
792
  // Decode any incomplete character left at the end
774
793
  const rest = decoder ? decoder.decode() : '';
775
794
  if (rest) this._input = typeof this._input === 'string' ? this._input + rest : rest;
776
- if (typeof this._input === 'string') this._tokenizeToEnd(callback, true);
795
+ if (typeof this._input === 'string') this._tryTokenizeToEnd(callback, true);
777
796
  }
778
797
  });
779
798
  input.on('error', error => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n3",
3
- "version": "2.12.0",
3
+ "version": "2.12.1",
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
@@ -714,10 +714,32 @@ export default class N3Lexer {
714
714
  return { value: '', matchLength: 0, finalLineLength: 0 };
715
715
  }
716
716
 
717
+ // ### `_tryTokenizeToEnd` tokenizes as far as possible, reporting failures through the callback
718
+ _tryTokenizeToEnd(callback, inputFinished) {
719
+ // Keep track of errors thrown by the callback, which must reach the caller unchanged
720
+ let callbackError;
721
+ try {
722
+ this._tokenizeToEnd((error, token) => {
723
+ try {
724
+ return callback(error, token);
725
+ }
726
+ catch (thrown) {
727
+ throw (callbackError = thrown);
728
+ }
729
+ }, inputFinished);
730
+ }
731
+ catch (error) {
732
+ // Matching an extremely long token can exhaust the regular expression stack
733
+ if (error === callbackError || !(error instanceof RangeError))
734
+ throw error;
735
+ callback(this._syntaxError(null, `Token too long on line ${this._line}.`));
736
+ }
737
+ }
738
+
717
739
  // ### `_syntaxError` creates a syntax error for the given issue
718
- _syntaxError(issue) {
740
+ _syntaxError(issue, message = `Unexpected "${issue}" on line ${this._line}.`) {
719
741
  this._input = null;
720
- const err = new Error(`Unexpected "${issue}" on line ${this._line}.`);
742
+ const err = new Error(message);
721
743
  err.context = {
722
744
  token: undefined,
723
745
  line: this._line,
@@ -760,13 +782,13 @@ export default class N3Lexer {
760
782
  if (typeof callback === 'function')
761
783
  queueMicrotask(() => {
762
784
  if (this._tokenization === tokenization)
763
- this._tokenizeToEnd(callback, true);
785
+ this._tryTokenizeToEnd(callback, true);
764
786
  });
765
787
  // If no callback was passed, tokenize synchronously and return
766
788
  else {
767
789
  const tokens = [];
768
790
  let error;
769
- this._tokenizeToEnd((e, t) => e ? (error = e) : tokens.push(t), true);
791
+ this._tryTokenizeToEnd((e, t) => e ? (error = e) : tokens.push(t), true);
770
792
  if (error) throw error;
771
793
  return tokens;
772
794
  }
@@ -793,7 +815,7 @@ export default class N3Lexer {
793
815
  // Tokenize as far as possible. When a previous attempt left a long unfinished token,
794
816
  // wait until the buffered input has doubled, so the token is not rescanned for every chunk.
795
817
  if (this._input.length >= retryLength) {
796
- this._tokenizeToEnd(callback, false);
818
+ this._tryTokenizeToEnd(callback, false);
797
819
  retryLength = this._input !== null && this._input.length > MIN_RESCAN_LENGTH ?
798
820
  2 * this._input.length : 0;
799
821
  }
@@ -807,7 +829,7 @@ export default class N3Lexer {
807
829
  if (rest)
808
830
  this._input = typeof this._input === 'string' ? this._input + rest : rest;
809
831
  if (typeof this._input === 'string')
810
- this._tokenizeToEnd(callback, true);
832
+ this._tryTokenizeToEnd(callback, true);
811
833
  }
812
834
  });
813
835
  input.on('error', error => {