n3 2.9.0 → 2.9.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/lib/N3Lexer.js CHANGED
@@ -18,8 +18,6 @@ const SPACE = 0x20,
18
18
  CR = 0x0D,
19
19
  HASH = 0x23;
20
20
 
21
- // Regular expression and replacement strings to unescape N3 strings
22
- const escapeSequence = /\\u([a-fA-F0-9]{4})|\\U([a-fA-F0-9]{8})|\\([^])/g;
23
21
  // Fixed escape sequences allowed in string literals (ECHAR)
24
22
  const stringEscapeReplacements = {
25
23
  '\\': '\\',
@@ -549,34 +547,42 @@ class N3Lexer {
549
547
  // ### `_unescape` replaces N3 escape codes by their corresponding characters,
550
548
  // allowing only the fixed escape sequences from the given replacement table
551
549
  _unescape(item, replacements) {
552
- if (item.indexOf('\\') < 0) return item;
553
- let invalid = false;
554
- const replaced = item.replace(escapeSequence, (sequence, unicode4, unicode8, escapedChar) => {
555
- // 4-digit unicode character
556
- if (typeof unicode4 === 'string') {
557
- const charCode = Number.parseInt(unicode4, 16);
558
- if (!isValidCodePoint(charCode)) {
559
- invalid = true;
560
- return '';
550
+ let backslash = item.indexOf('\\');
551
+ if (backslash < 0) return item;
552
+ let result = '',
553
+ start = 0;
554
+ // A trailing lone backslash is not an escape sequence.
555
+ while (backslash >= 0 && backslash + 1 < item.length) {
556
+ const escapedChar = item[backslash + 1];
557
+ let end = backslash + 2,
558
+ replacement;
559
+ if (escapedChar === 'u' || escapedChar === 'U') {
560
+ end += escapedChar === 'u' ? 4 : 8;
561
+ if (end > item.length) return null;
562
+ let charCode = 0;
563
+ for (let i = backslash + 2; i < end; i++) {
564
+ let digit = item.charCodeAt(i);
565
+ if (digit >= 0x30 && digit <= 0x39)
566
+ // 0–9
567
+ digit -= 0x30;else if (digit >= 0x41 && digit <= 0x46)
568
+ // A–F
569
+ digit -= 0x41 - 10;else if (digit >= 0x61 && digit <= 0x66)
570
+ // a–f
571
+ digit -= 0x61 - 10;else return null;
572
+ // Eight digits can exceed a signed 32-bit integer; avoid bitwise shifts.
573
+ charCode = charCode * 16 + digit;
561
574
  }
562
- return String.fromCharCode(charCode);
575
+ if (!isValidCodePoint(charCode)) return null;
576
+ replacement = String.fromCodePoint(charCode);
577
+ } else {
578
+ if (!(escapedChar in replacements)) return null;
579
+ replacement = replacements[escapedChar];
563
580
  }
564
- // 8-digit unicode character
565
- if (typeof unicode8 === 'string') {
566
- let charCode = Number.parseInt(unicode8, 16);
567
- if (!isValidCodePoint(charCode)) {
568
- invalid = true;
569
- return '';
570
- }
571
- return charCode <= 0xFFFF ? String.fromCharCode(Number.parseInt(unicode8, 16)) : String.fromCharCode(0xD800 + ((charCode -= 0x10000) >> 10), 0xDC00 + (charCode & 0x3FF));
572
- }
573
- // fixed escape sequence
574
- if (escapedChar in replacements) return replacements[escapedChar];
575
- // invalid escape sequence
576
- invalid = true;
577
- return '';
578
- });
579
- return invalid ? null : replaced;
581
+ result += item.slice(start, backslash) + replacement;
582
+ start = end;
583
+ backslash = item.indexOf('\\', start);
584
+ }
585
+ return result + item.slice(start);
580
586
  }
581
587
 
582
588
  // ### `_parseLiteral` parses a literal into an unescaped value
package/lib/N3Store.js CHANGED
@@ -368,12 +368,15 @@ class N3Store {
368
368
  if (!(index2 = index1[key1])) return 0;
369
369
  return key2 ? key2 in index2 ? 1 : 0 : index2[SIZE];
370
370
  }
371
- for (const value1 in index1) count += index1[value1][SIZE];
371
+ const keys1 = Object.keys(index1);
372
+ for (let i1 = 0; i1 < keys1.length; i1++) count += index1[keys1[i1]][SIZE];
372
373
  return count;
373
374
  }
374
- for (const value0 in index0) {
375
- index1 = index0[value0];
376
- for (const value1 in index1) count += index1[value1][SIZE];
375
+ const keys0 = Object.keys(index0);
376
+ for (let i0 = 0; i0 < keys0.length; i0++) {
377
+ index1 = index0[keys0[i0]];
378
+ const keys1 = Object.keys(index1);
379
+ for (let i1 = 0; i1 < keys1.length; i1++) count += index1[keys1[i1]][SIZE];
377
380
  }
378
381
  return count;
379
382
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n3",
3
- "version": "2.9.0",
3
+ "version": "2.9.2",
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
@@ -5,8 +5,6 @@ import namespaces from './IRIs';
5
5
  const { xsd } = namespaces;
6
6
  const SPACE = 0x20, TAB = 0x09, LF = 0x0A, CR = 0x0D, HASH = 0x23;
7
7
 
8
- // Regular expression and replacement strings to unescape N3 strings
9
- const escapeSequence = /\\u([a-fA-F0-9]{4})|\\U([a-fA-F0-9]{8})|\\([^])/g;
10
8
  // Fixed escape sequences allowed in string literals (ECHAR)
11
9
  const stringEscapeReplacements = {
12
10
  '\\': '\\', "'": "'", '"': '"',
@@ -561,37 +559,48 @@ export default class N3Lexer {
561
559
  // ### `_unescape` replaces N3 escape codes by their corresponding characters,
562
560
  // allowing only the fixed escape sequences from the given replacement table
563
561
  _unescape(item, replacements) {
564
- if (item.indexOf('\\') < 0)
562
+ let backslash = item.indexOf('\\');
563
+ if (backslash < 0)
565
564
  return item;
566
- let invalid = false;
567
- const replaced = item.replace(escapeSequence, (sequence, unicode4, unicode8, escapedChar) => {
568
- // 4-digit unicode character
569
- if (typeof unicode4 === 'string') {
570
- const charCode = Number.parseInt(unicode4, 16);
571
- if (!isValidCodePoint(charCode)) {
572
- invalid = true;
573
- return '';
565
+
566
+ let result = '', start = 0;
567
+ // A trailing lone backslash is not an escape sequence.
568
+ while (backslash >= 0 && backslash + 1 < item.length) {
569
+ const escapedChar = item[backslash + 1];
570
+ let end = backslash + 2, replacement;
571
+ if (escapedChar === 'u' || escapedChar === 'U') {
572
+ end += escapedChar === 'u' ? 4 : 8;
573
+ if (end > item.length)
574
+ return null;
575
+
576
+ let charCode = 0;
577
+ for (let i = backslash + 2; i < end; i++) {
578
+ let digit = item.charCodeAt(i);
579
+ if (digit >= 0x30 && digit <= 0x39) // 0–9
580
+ digit -= 0x30;
581
+ else if (digit >= 0x41 && digit <= 0x46) // A–F
582
+ digit -= 0x41 - 10;
583
+ else if (digit >= 0x61 && digit <= 0x66) // a–f
584
+ digit -= 0x61 - 10;
585
+ else
586
+ return null;
587
+ // Eight digits can exceed a signed 32-bit integer; avoid bitwise shifts.
588
+ charCode = charCode * 16 + digit;
574
589
  }
575
- return String.fromCharCode(charCode);
590
+ if (!isValidCodePoint(charCode))
591
+ return null;
592
+ replacement = String.fromCodePoint(charCode);
576
593
  }
577
- // 8-digit unicode character
578
- if (typeof unicode8 === 'string') {
579
- let charCode = Number.parseInt(unicode8, 16);
580
- if (!isValidCodePoint(charCode)) {
581
- invalid = true;
582
- return '';
583
- }
584
- return charCode <= 0xFFFF ? String.fromCharCode(Number.parseInt(unicode8, 16)) :
585
- String.fromCharCode(0xD800 + ((charCode -= 0x10000) >> 10), 0xDC00 + (charCode & 0x3FF));
594
+ else {
595
+ if (!(escapedChar in replacements))
596
+ return null;
597
+ replacement = replacements[escapedChar];
586
598
  }
587
- // fixed escape sequence
588
- if (escapedChar in replacements)
589
- return replacements[escapedChar];
590
- // invalid escape sequence
591
- invalid = true;
592
- return '';
593
- });
594
- return invalid ? null : replaced;
599
+ result += item.slice(start, backslash) + replacement;
600
+ start = end;
601
+ backslash = item.indexOf('\\', start);
602
+ }
603
+ return result + item.slice(start);
595
604
  }
596
605
 
597
606
  // ### `_parseLiteral` parses a literal into an unescaped value
package/src/N3Store.js CHANGED
@@ -394,15 +394,18 @@ export default class N3Store {
394
394
  return key2 ? (key2 in index2 ? 1 : 0) : index2[SIZE];
395
395
  }
396
396
 
397
- for (const value1 in index1)
398
- count += index1[value1][SIZE];
397
+ const keys1 = Object.keys(index1);
398
+ for (let i1 = 0; i1 < keys1.length; i1++)
399
+ count += index1[keys1[i1]][SIZE];
399
400
  return count;
400
401
  }
401
402
 
402
- for (const value0 in index0) {
403
- index1 = index0[value0];
404
- for (const value1 in index1)
405
- count += index1[value1][SIZE];
403
+ const keys0 = Object.keys(index0);
404
+ for (let i0 = 0; i0 < keys0.length; i0++) {
405
+ index1 = index0[keys0[i0]];
406
+ const keys1 = Object.keys(index1);
407
+ for (let i1 = 0; i1 < keys1.length; i1++)
408
+ count += index1[keys1[i1]][SIZE];
406
409
  }
407
410
  return count;
408
411
  }