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 +90 -1
- package/lib/lexer.js +90 -1
- package/package.json +1 -1
- package/test/api.test.js +221 -0
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
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 },
|