eyeling 1.14.13 → 1.14.14

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/eyeling.js CHANGED
@@ -7847,6 +7847,95 @@ function decodeN3StringEscapes(s, offset = null) {
7847
7847
  return out;
7848
7848
  }
7849
7849
 
7850
+ function formatCodePoint(cp) {
7851
+ return cp
7852
+ .toString(16)
7853
+ .toUpperCase()
7854
+ .padStart(cp <= 0xffff ? 4 : 6, '0');
7855
+ }
7856
+
7857
+ function isForbiddenIriRefChar(c) {
7858
+ return (
7859
+ c === '<' || c === '>' || c === '"' || c === '{' || c === '}' || c === '|' || c === '^' || c === '`' || c === '\\'
7860
+ );
7861
+ }
7862
+
7863
+ function assertValidIriRefCodePoint(cp, offset = null) {
7864
+ if (cp <= 0x20) {
7865
+ throw new N3SyntaxError(`Invalid IRIREF: character U+${formatCodePoint(cp)} is not allowed inside <...>`, offset);
7866
+ }
7867
+
7868
+ if (cp >= 0xd800 && cp <= 0xdfff) {
7869
+ throw new N3SyntaxError(
7870
+ `Invalid IRIREF: surrogate code point U+${formatCodePoint(cp)} is not allowed inside <...>`,
7871
+ offset,
7872
+ );
7873
+ }
7874
+
7875
+ if (isForbiddenNoncharacterCodePoint(cp)) {
7876
+ throw new N3SyntaxError(
7877
+ `Invalid IRIREF: noncharacter U+${formatCodePoint(cp)} is not allowed inside <...>`,
7878
+ offset,
7879
+ );
7880
+ }
7881
+
7882
+ const c = String.fromCodePoint(cp);
7883
+ if (isForbiddenIriRefChar(c)) {
7884
+ throw new N3SyntaxError(`Invalid IRIREF: character ${JSON.stringify(c)} is not allowed inside <...>`, offset);
7885
+ }
7886
+ }
7887
+
7888
+ function decodeIriRefEscapes(s, offset = null) {
7889
+ let out = '';
7890
+ for (let i = 0; i < s.length; i++) {
7891
+ const c = s[i];
7892
+ if (c !== '\\') {
7893
+ const cp = c.codePointAt(0);
7894
+ assertValidIriRefCodePoint(cp, offset);
7895
+ out += c;
7896
+ continue;
7897
+ }
7898
+
7899
+ if (i + 1 >= s.length) {
7900
+ throw new N3SyntaxError('Invalid IRIREF: bare backslash is not allowed inside <...>', offset);
7901
+ }
7902
+
7903
+ const e = s[++i];
7904
+ if (e === 'u') {
7905
+ const hex = s.slice(i + 1, i + 5);
7906
+ if (!/^[0-9A-Fa-f]{4}$/.test(hex)) {
7907
+ throw new N3SyntaxError('Invalid IRIREF: malformed \\u escape inside <...>', offset);
7908
+ }
7909
+ const cp = parseInt(hex, 16);
7910
+ assertValidIriRefCodePoint(cp, offset);
7911
+ out += String.fromCodePoint(cp);
7912
+ i += 4;
7913
+ continue;
7914
+ }
7915
+
7916
+ if (e === 'U') {
7917
+ const hex = s.slice(i + 1, i + 9);
7918
+ if (!/^[0-9A-Fa-f]{8}$/.test(hex)) {
7919
+ throw new N3SyntaxError('Invalid IRIREF: malformed \\U escape inside <...>', offset);
7920
+ }
7921
+ const cp = parseInt(hex, 16);
7922
+ if (cp < 0 || cp > 0x10ffff) {
7923
+ throw new N3SyntaxError(`Invalid IRIREF: code point U+${hex.toUpperCase()} is out of range`, offset);
7924
+ }
7925
+ assertValidIriRefCodePoint(cp, offset);
7926
+ out += String.fromCodePoint(cp);
7927
+ i += 8;
7928
+ continue;
7929
+ }
7930
+
7931
+ throw new N3SyntaxError(
7932
+ `Invalid IRIREF: character ${JSON.stringify('\\' + e)} is not allowed inside <...>`,
7933
+ offset,
7934
+ );
7935
+ }
7936
+ return out;
7937
+ }
7938
+
7850
7939
  function assertValidStringLiteralValue(s, offset = null) {
7851
7940
  for (let i = 0; i < s.length; i++) {
7852
7941
  const cu = s.charCodeAt(i);
@@ -8032,7 +8121,7 @@ function lex(inputText) {
8032
8121
  throw new N3SyntaxError('Unterminated IRI <...>', start);
8033
8122
  }
8034
8123
  i++; // skip '>'
8035
- const iri = iriChars.join('');
8124
+ const iri = decodeIriRefEscapes(iriChars.join(''), start);
8036
8125
  tokens.push(new Token('IriRef', iri, start));
8037
8126
  continue;
8038
8127
  }
package/lib/lexer.js CHANGED
@@ -201,6 +201,95 @@ function decodeN3StringEscapes(s, offset = null) {
201
201
  return out;
202
202
  }
203
203
 
204
+ function formatCodePoint(cp) {
205
+ return cp
206
+ .toString(16)
207
+ .toUpperCase()
208
+ .padStart(cp <= 0xffff ? 4 : 6, '0');
209
+ }
210
+
211
+ function isForbiddenIriRefChar(c) {
212
+ return (
213
+ c === '<' || c === '>' || c === '"' || c === '{' || c === '}' || c === '|' || c === '^' || c === '`' || c === '\\'
214
+ );
215
+ }
216
+
217
+ function assertValidIriRefCodePoint(cp, offset = null) {
218
+ if (cp <= 0x20) {
219
+ throw new N3SyntaxError(`Invalid IRIREF: character U+${formatCodePoint(cp)} is not allowed inside <...>`, offset);
220
+ }
221
+
222
+ if (cp >= 0xd800 && cp <= 0xdfff) {
223
+ throw new N3SyntaxError(
224
+ `Invalid IRIREF: surrogate code point U+${formatCodePoint(cp)} is not allowed inside <...>`,
225
+ offset,
226
+ );
227
+ }
228
+
229
+ if (isForbiddenNoncharacterCodePoint(cp)) {
230
+ throw new N3SyntaxError(
231
+ `Invalid IRIREF: noncharacter U+${formatCodePoint(cp)} is not allowed inside <...>`,
232
+ offset,
233
+ );
234
+ }
235
+
236
+ const c = String.fromCodePoint(cp);
237
+ if (isForbiddenIriRefChar(c)) {
238
+ throw new N3SyntaxError(`Invalid IRIREF: character ${JSON.stringify(c)} is not allowed inside <...>`, offset);
239
+ }
240
+ }
241
+
242
+ function decodeIriRefEscapes(s, offset = null) {
243
+ let out = '';
244
+ for (let i = 0; i < s.length; i++) {
245
+ const c = s[i];
246
+ if (c !== '\\') {
247
+ const cp = c.codePointAt(0);
248
+ assertValidIriRefCodePoint(cp, offset);
249
+ out += c;
250
+ continue;
251
+ }
252
+
253
+ if (i + 1 >= s.length) {
254
+ throw new N3SyntaxError('Invalid IRIREF: bare backslash is not allowed inside <...>', offset);
255
+ }
256
+
257
+ const e = s[++i];
258
+ if (e === 'u') {
259
+ const hex = s.slice(i + 1, i + 5);
260
+ if (!/^[0-9A-Fa-f]{4}$/.test(hex)) {
261
+ throw new N3SyntaxError('Invalid IRIREF: malformed \\u escape inside <...>', offset);
262
+ }
263
+ const cp = parseInt(hex, 16);
264
+ assertValidIriRefCodePoint(cp, offset);
265
+ out += String.fromCodePoint(cp);
266
+ i += 4;
267
+ continue;
268
+ }
269
+
270
+ if (e === 'U') {
271
+ const hex = s.slice(i + 1, i + 9);
272
+ if (!/^[0-9A-Fa-f]{8}$/.test(hex)) {
273
+ throw new N3SyntaxError('Invalid IRIREF: malformed \\U escape inside <...>', offset);
274
+ }
275
+ const cp = parseInt(hex, 16);
276
+ if (cp < 0 || cp > 0x10ffff) {
277
+ throw new N3SyntaxError(`Invalid IRIREF: code point U+${hex.toUpperCase()} is out of range`, offset);
278
+ }
279
+ assertValidIriRefCodePoint(cp, offset);
280
+ out += String.fromCodePoint(cp);
281
+ i += 8;
282
+ continue;
283
+ }
284
+
285
+ throw new N3SyntaxError(
286
+ `Invalid IRIREF: character ${JSON.stringify('\\' + e)} is not allowed inside <...>`,
287
+ offset,
288
+ );
289
+ }
290
+ return out;
291
+ }
292
+
204
293
  function assertValidStringLiteralValue(s, offset = null) {
205
294
  for (let i = 0; i < s.length; i++) {
206
295
  const cu = s.charCodeAt(i);
@@ -386,7 +475,7 @@ function lex(inputText) {
386
475
  throw new N3SyntaxError('Unterminated IRI <...>', start);
387
476
  }
388
477
  i++; // skip '>'
389
- const iri = iriChars.join('');
478
+ const iri = decodeIriRefEscapes(iriChars.join(''), start);
390
479
  tokens.push(new Token('IriRef', iri, start));
391
480
  continue;
392
481
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyeling",
3
- "version": "1.14.13",
3
+ "version": "1.14.14",
4
4
  "description": "A minimal Notation3 (N3) reasoner in JavaScript.",
5
5
  "main": "./index.js",
6
6
  "keywords": [
package/test/api.test.js CHANGED
@@ -567,6 +567,227 @@ bad.:example a bad.:Person.
567
567
  `,
568
568
  expectError: true,
569
569
  },
570
+ {
571
+ name: '12h invalid syntax: space is not allowed inside IRIREF',
572
+ opt: { proofComments: false },
573
+ input: `
574
+ @prefix : <http://example.org/> .
575
+ @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
576
+
577
+ <http://bad example.org/> a :BadExample.
578
+
579
+ {
580
+ :subject :predicate ?X.
581
+ }
582
+ =>
583
+ {
584
+ :result :has :crash-syntax-7.
585
+ }.
586
+
587
+ {} => {
588
+ :test :contains :crash-syntax-7.
589
+ }.
590
+
591
+ {
592
+ :result :has :crash-syntax-7.
593
+ }
594
+ =>
595
+ {
596
+ :test :is false.
597
+ }.
598
+ `,
599
+ expectError: true,
600
+ },
601
+ {
602
+ name: '12i invalid syntax: UCHAR escape is not allowed inside IRIREF',
603
+ opt: { proofComments: false },
604
+ input: String.raw`
605
+ @prefix : <http://example.org/> .
606
+ @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
607
+
608
+ <http://bad\u0020example.org/> a :BadExample.
609
+
610
+ {
611
+ :subject :predicate ?X.
612
+ }
613
+ =>
614
+ {
615
+ :result :has :crash-syntax-8.
616
+ }.
617
+
618
+ {} => {
619
+ :test :contains :crash-syntax-8.
620
+ }.
621
+
622
+ {
623
+ :result :has :crash-syntax-8.
624
+ }
625
+ =>
626
+ {
627
+ :test :is false.
628
+ }.
629
+ `,
630
+ expectError: true,
631
+ },
632
+ {
633
+ name: '12j invalid syntax: control characters are not allowed inside IRIREF',
634
+ opt: { proofComments: false },
635
+ input: `
636
+ @prefix : <http://example.org/> .
637
+ @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
638
+
639
+ <http://badexample.org> :foo <http://example.org/> .
640
+
641
+ {
642
+ :subject :predicate ?X.
643
+ }
644
+ =>
645
+ {
646
+ :result :has :crash-syntax-9.
647
+ }.
648
+
649
+ {} => {
650
+ :test :contains :crash-syntax-9.
651
+ }.
652
+
653
+ {
654
+ :result :has :crash-syntax-9.
655
+ }
656
+ =>
657
+ {
658
+ :test :is false.
659
+ }.
660
+ `,
661
+ expectError: true,
662
+ },
663
+ {
664
+ name: '12k invalid syntax: control-character UCHAR is not allowed inside IRIREF',
665
+ opt: { proofComments: false },
666
+ input: String.raw`
667
+ @prefix : <http://example.org/> .
668
+ @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
669
+
670
+ <http://bad\u0007example.org> :foo <http://example.org/> .
671
+
672
+ {
673
+ :subject :predicate ?X.
674
+ }
675
+ =>
676
+ {
677
+ :result :has :crash-syntax-10.
678
+ }.
679
+
680
+ {} => {
681
+ :test :contains :crash-syntax-10.
682
+ }.
683
+
684
+ {
685
+ :result :has :crash-syntax-10.
686
+ }
687
+ =>
688
+ {
689
+ :test :is false.
690
+ }.
691
+ `,
692
+ expectError: true,
693
+ },
694
+ {
695
+ name: '12l regression: IRIREF \\u escape decodes before log:uri comparison (mismatch stays falsey)',
696
+ opt: { proofComments: false },
697
+ input: String.raw`
698
+ @prefix : <http://example.org/> .
699
+ @prefix log: <http://www.w3.org/2000/10/swap/log#> .
700
+ @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
701
+ @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
702
+ @base <http://example.org/>.
703
+
704
+ {
705
+ <http://example.org/\u0041> log:uri "http://example.org/\\u0041".
706
+ }
707
+ =>
708
+ {
709
+ :result :has :fail-literal-1.
710
+ }.
711
+
712
+ { } => {
713
+ :test :contains :fail-literal-1.
714
+ }.
715
+ `,
716
+ expect: [/:(?:test)\s+:(?:contains)\s+:(?:fail-literal-1)\s*\./],
717
+ notExpect: [/:(?:result)\s+:(?:has)\s+:(?:fail-literal-1)\s*\./, /:(?:test)\s+:(?:is)\s+true\s*\./],
718
+ },
719
+ {
720
+ name: '12m regression: IRIREF \\u escape matches plain-A literal via log:uri',
721
+ opt: { proofComments: false },
722
+ input: String.raw`
723
+ @prefix : <http://example.org/> .
724
+ @prefix log: <http://www.w3.org/2000/10/swap/log#> .
725
+ @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
726
+ @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
727
+ @base <http://example.org/>.
728
+
729
+ {
730
+ <http://example.org/\u0041> log:uri "http://example.org/A".
731
+ }
732
+ =>
733
+ {
734
+ :result :has :success-literal-5.
735
+ }.
736
+
737
+ { } => {
738
+ :test :contains :success-literal-5.
739
+ }.
740
+
741
+ {
742
+ :result :has :success-literal-5.
743
+ }
744
+ =>
745
+ {
746
+ :test :is true.
747
+ }.
748
+ `,
749
+ expect: [
750
+ /:(?:result)\s+:(?:has)\s+:(?:success-literal-5)\s*\./,
751
+ /:(?:test)\s+:(?:contains)\s+:(?:success-literal-5)\s*\./,
752
+ /:(?:test)\s+:(?:is)\s+true\s*\./,
753
+ ],
754
+ },
755
+ {
756
+ name: '12n regression: IRIREF \\u escape matches decoded literal escape via log:uri',
757
+ opt: { proofComments: false },
758
+ input: String.raw`
759
+ @prefix : <http://example.org/> .
760
+ @prefix log: <http://www.w3.org/2000/10/swap/log#> .
761
+ @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
762
+ @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
763
+ @base <http://example.org/>.
764
+
765
+ {
766
+ <http://example.org/\u0041> log:uri "http://example.org/\u0041".
767
+ }
768
+ =>
769
+ {
770
+ :result :has :success-literal-6.
771
+ }.
772
+
773
+ { } => {
774
+ :test :contains :success-literal-6.
775
+ }.
776
+
777
+ {
778
+ :result :has :success-literal-6.
779
+ }
780
+ =>
781
+ {
782
+ :test :is true.
783
+ }.
784
+ `,
785
+ expect: [
786
+ /:(?:result)\s+:(?:has)\s+:(?:success-literal-6)\s*\./,
787
+ /:(?:test)\s+:(?:contains)\s+:(?:success-literal-6)\s*\./,
788
+ /:(?:test)\s+:(?:is)\s+true\s*\./,
789
+ ],
790
+ },
570
791
  {
571
792
  name: '13 heavier recursion: ancestor closure over 15 links',
572
793
  opt: { proofComments: false, maxBuffer: 200 * 1024 * 1024 },