n3 2.7.3 → 2.7.5

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
@@ -555,13 +555,18 @@ class N3Lexer {
555
555
  // ### `tokenize` starts the transformation of an N3 document into an array of tokens.
556
556
  // The input can be a string or a stream.
557
557
  tokenize(input, callback) {
558
+ // Deferred tokenization and stream events can outlive their invocation.
559
+ // Ignore them once a later call takes ownership of the lexer state.
560
+ const tokenization = this._tokenization = {};
558
561
  this._line = 1;
559
562
 
560
563
  // If the input is a string, continuously emit tokens through the callback until the end
561
564
  if (typeof input === 'string') {
562
565
  this._input = this._readStartingBom(input);
563
566
  // If a callback was passed, asynchronously call it
564
- if (typeof callback === 'function') queueMicrotask(() => this._tokenizeToEnd(callback, true));
567
+ if (typeof callback === 'function') queueMicrotask(() => {
568
+ if (this._tokenization === tokenization) this._tokenizeToEnd(callback, true);
569
+ });
565
570
  // If no callback was passed, tokenize synchronously and return
566
571
  else {
567
572
  const tokens = [];
@@ -577,7 +582,7 @@ class N3Lexer {
577
582
  if (typeof input.setEncoding === 'function') input.setEncoding('utf8');
578
583
  // Adds the data chunk to the buffer and parses as far as possible
579
584
  input.on('data', data => {
580
- if (this._input !== null && data.length !== 0) {
585
+ if (this._tokenization === tokenization && this._input !== null && data.length !== 0) {
581
586
  // Prepend any previous pending writes
582
587
  if (this._pendingBuffer) {
583
588
  data = _buffer.Buffer.concat([this._pendingBuffer, data]);
@@ -597,9 +602,11 @@ class N3Lexer {
597
602
  });
598
603
  // Parses until the end
599
604
  input.on('end', () => {
600
- if (typeof this._input === 'string') this._tokenizeToEnd(callback, true);
605
+ if (this._tokenization === tokenization && typeof this._input === 'string') this._tokenizeToEnd(callback, true);
606
+ });
607
+ input.on('error', error => {
608
+ if (this._tokenization === tokenization) callback(error);
601
609
  });
602
- input.on('error', callback);
603
610
  }
604
611
  }
605
612
  }
package/lib/N3Store.js CHANGED
@@ -278,12 +278,15 @@ class N3Store {
278
278
  // A null key list stops after visiting a bound key, avoiding a one-item array.
279
279
  const keys0 = key0 ? null : Object.keys(index0);
280
280
  for (let i0 = 0, value0 = key0 || keys0[0]; value0; value0 = keys0 && keys0[++i0]) {
281
+ // Mutations can remove keys captured before an earlier yield.
281
282
  const index1 = index0[value0];
283
+ if (!index1) continue; // eslint-disable-line no-continue
282
284
  parts[name0] = this._termFromId(entityKeys[value0]);
283
285
  if (key1 && !(key1 in index1)) return;
284
286
  const keys1 = key1 ? null : Object.keys(index1);
285
287
  for (let i1 = 0, value1 = key1 || keys1[0]; value1; value1 = keys1 && keys1[++i1]) {
286
288
  const index2 = index1[value1];
289
+ if (!index2) continue; // eslint-disable-line no-continue
287
290
  parts[name1] = this._termFromId(entityKeys[value1]);
288
291
  const values = Object.keys(index2);
289
292
  for (let l = 0; l < values.length; l++) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n3",
3
- "version": "2.7.3",
3
+ "version": "2.7.5",
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
@@ -575,6 +575,9 @@ export default class N3Lexer {
575
575
  // ### `tokenize` starts the transformation of an N3 document into an array of tokens.
576
576
  // The input can be a string or a stream.
577
577
  tokenize(input, callback) {
578
+ // Deferred tokenization and stream events can outlive their invocation.
579
+ // Ignore them once a later call takes ownership of the lexer state.
580
+ const tokenization = this._tokenization = {};
578
581
  this._line = 1;
579
582
 
580
583
  // If the input is a string, continuously emit tokens through the callback until the end
@@ -582,7 +585,10 @@ export default class N3Lexer {
582
585
  this._input = this._readStartingBom(input);
583
586
  // If a callback was passed, asynchronously call it
584
587
  if (typeof callback === 'function')
585
- queueMicrotask(() => this._tokenizeToEnd(callback, true));
588
+ queueMicrotask(() => {
589
+ if (this._tokenization === tokenization)
590
+ this._tokenizeToEnd(callback, true);
591
+ });
586
592
  // If no callback was passed, tokenize synchronously and return
587
593
  else {
588
594
  const tokens = [];
@@ -599,7 +605,7 @@ export default class N3Lexer {
599
605
  input.setEncoding('utf8');
600
606
  // Adds the data chunk to the buffer and parses as far as possible
601
607
  input.on('data', data => {
602
- if (this._input !== null && data.length !== 0) {
608
+ if (this._tokenization === tokenization && this._input !== null && data.length !== 0) {
603
609
  // Prepend any previous pending writes
604
610
  if (this._pendingBuffer) {
605
611
  data = Buffer.concat([this._pendingBuffer, data]);
@@ -622,10 +628,13 @@ export default class N3Lexer {
622
628
  });
623
629
  // Parses until the end
624
630
  input.on('end', () => {
625
- if (typeof this._input === 'string')
631
+ if (this._tokenization === tokenization && typeof this._input === 'string')
626
632
  this._tokenizeToEnd(callback, true);
627
633
  });
628
- input.on('error', callback);
634
+ input.on('error', error => {
635
+ if (this._tokenization === tokenization)
636
+ callback(error);
637
+ });
629
638
  }
630
639
  }
631
640
  }
package/src/N3Store.js CHANGED
@@ -297,7 +297,9 @@ export default class N3Store {
297
297
  const keys0 = key0 ? null : Object.keys(index0);
298
298
  for (let i0 = 0, value0 = key0 || keys0[0]; value0;
299
299
  value0 = keys0 && keys0[++i0]) {
300
+ // Mutations can remove keys captured before an earlier yield.
300
301
  const index1 = index0[value0];
302
+ if (!index1) continue; // eslint-disable-line no-continue
301
303
  parts[name0] = this._termFromId(entityKeys[value0]);
302
304
 
303
305
  if (key1 && !(key1 in index1))
@@ -306,6 +308,7 @@ export default class N3Store {
306
308
  for (let i1 = 0, value1 = key1 || keys1[0]; value1;
307
309
  value1 = keys1 && keys1[++i1]) {
308
310
  const index2 = index1[value1];
311
+ if (!index2) continue; // eslint-disable-line no-continue
309
312
  parts[name1] = this._termFromId(entityKeys[value1]);
310
313
  const values = Object.keys(index2);
311
314
  for (let l = 0; l < values.length; l++) {