eyeling 1.28.1 → 1.28.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/dist/browser/eyeling.browser.js +103 -0
- package/eyeling.js +103 -0
- package/lib/lexer.js +103 -0
- package/package.json +1 -1
- package/test/api.test.js +16 -0
|
@@ -11140,11 +11140,114 @@ function normalizeRdfCompatibility(inputText) {
|
|
|
11140
11140
|
return text.slice(at, j);
|
|
11141
11141
|
}
|
|
11142
11142
|
|
|
11143
|
+
function readBalancedTermAt(text, at) {
|
|
11144
|
+
const open = text[at];
|
|
11145
|
+
const matching = { '{': '}', '[': ']', '(': ')' };
|
|
11146
|
+
if (!matching[open]) return null;
|
|
11147
|
+
|
|
11148
|
+
const stack = [matching[open]];
|
|
11149
|
+
let j = at + 1;
|
|
11150
|
+
while (j < text.length) {
|
|
11151
|
+
const ch = text[j];
|
|
11152
|
+
if (ch === '"' || ch === "'") {
|
|
11153
|
+
const str = readStringAt(text, j);
|
|
11154
|
+
j = str.end;
|
|
11155
|
+
continue;
|
|
11156
|
+
}
|
|
11157
|
+
if (ch === '<' && !text.startsWith('<<', j)) {
|
|
11158
|
+
const iri = readIriAt(text, j);
|
|
11159
|
+
j = iri.end;
|
|
11160
|
+
continue;
|
|
11161
|
+
}
|
|
11162
|
+
if (ch === '#') {
|
|
11163
|
+
while (j < text.length && text[j] !== '\n' && text[j] !== '\r') j += 1;
|
|
11164
|
+
continue;
|
|
11165
|
+
}
|
|
11166
|
+
if (matching[ch]) {
|
|
11167
|
+
stack.push(matching[ch]);
|
|
11168
|
+
j += 1;
|
|
11169
|
+
continue;
|
|
11170
|
+
}
|
|
11171
|
+
if (ch === stack[stack.length - 1]) {
|
|
11172
|
+
stack.pop();
|
|
11173
|
+
j += 1;
|
|
11174
|
+
if (stack.length === 0) return { text: text.slice(at, j), end: j };
|
|
11175
|
+
continue;
|
|
11176
|
+
}
|
|
11177
|
+
j += 1;
|
|
11178
|
+
}
|
|
11179
|
+
|
|
11180
|
+
throw new N3SyntaxError(`Unterminated term inside RDF 1.2 triple term, expected ${stack[stack.length - 1]}`);
|
|
11181
|
+
}
|
|
11182
|
+
|
|
11183
|
+
function readRdfTripleTermComponent(text, at) {
|
|
11184
|
+
const j = skipWsAndComments(text, at);
|
|
11185
|
+
if (j >= text.length) return null;
|
|
11186
|
+
const ch = text[j];
|
|
11187
|
+
|
|
11188
|
+
if (ch === '<') return readIriAt(text, j);
|
|
11189
|
+
|
|
11190
|
+
if (ch === '"' || ch === "'") {
|
|
11191
|
+
const str = readStringAt(text, j);
|
|
11192
|
+
let end = str.end;
|
|
11193
|
+
let termText = str.text;
|
|
11194
|
+
if (text.startsWith('^^', end)) {
|
|
11195
|
+
const datatype = readRdfTripleTermComponent(text, end + 2);
|
|
11196
|
+
if (datatype) {
|
|
11197
|
+
termText += '^^' + datatype.text;
|
|
11198
|
+
end = datatype.end;
|
|
11199
|
+
}
|
|
11200
|
+
} else if (text[end] === '@') {
|
|
11201
|
+
let k = end + 1;
|
|
11202
|
+
if (/[A-Za-z]/.test(text[k] || '')) {
|
|
11203
|
+
while (k < text.length && /[A-Za-z0-9-]/.test(text[k])) k += 1;
|
|
11204
|
+
termText += text.slice(end, k);
|
|
11205
|
+
end = k;
|
|
11206
|
+
}
|
|
11207
|
+
}
|
|
11208
|
+
return { text: termText, end };
|
|
11209
|
+
}
|
|
11210
|
+
|
|
11211
|
+
if (ch === '{' || ch === '[' || ch === '(') return readBalancedTermAt(text, j);
|
|
11212
|
+
|
|
11213
|
+
let k = j;
|
|
11214
|
+
while (k < text.length && !/\s/.test(text[k]) && !'{}[](),;'.includes(text[k])) k += 1;
|
|
11215
|
+
if (k === j) return null;
|
|
11216
|
+
const value = text.slice(j, k);
|
|
11217
|
+
if (!value || value.startsWith('@')) return null;
|
|
11218
|
+
return { text: value, end: k };
|
|
11219
|
+
}
|
|
11220
|
+
|
|
11221
|
+
function validateSingleRdfTripleTerm(rawTriple) {
|
|
11222
|
+
const triple = rawTriple.trim();
|
|
11223
|
+
if (!triple) throw new N3SyntaxError('RDF 1.2 triple term must contain exactly one subject, predicate, and object');
|
|
11224
|
+
|
|
11225
|
+
let pos = 0;
|
|
11226
|
+
for (const label of ['subject', 'predicate', 'object']) {
|
|
11227
|
+
const term = readRdfTripleTermComponent(triple, pos);
|
|
11228
|
+
if (!term) throw new N3SyntaxError(`RDF 1.2 triple term is missing a ${label}`);
|
|
11229
|
+
pos = term.end;
|
|
11230
|
+
}
|
|
11231
|
+
|
|
11232
|
+
const rest = skipWsAndComments(triple, pos);
|
|
11233
|
+
if (rest >= triple.length) return;
|
|
11234
|
+
|
|
11235
|
+
const found = triple[rest];
|
|
11236
|
+
if (found === ',') {
|
|
11237
|
+
throw new N3SyntaxError("RDF 1.2 triple terms must contain exactly one object; object lists using ',' are not valid inside <<( ... )>>");
|
|
11238
|
+
}
|
|
11239
|
+
if (found === ';') {
|
|
11240
|
+
throw new N3SyntaxError("RDF 1.2 triple terms must contain exactly one predicate-object pair; ';' is not valid inside <<( ... )>>");
|
|
11241
|
+
}
|
|
11242
|
+
throw new N3SyntaxError(`RDF 1.2 triple term must contain exactly one subject, predicate, and object; unexpected ${JSON.stringify(triple.slice(rest, rest + 20))}`);
|
|
11243
|
+
}
|
|
11244
|
+
|
|
11143
11245
|
function graphTermFromTripleBody(rawBody, parenthesized) {
|
|
11144
11246
|
let body = rawBody.trim();
|
|
11145
11247
|
if (parenthesized && body.startsWith('(') && body.endsWith(')')) body = body.slice(1, -1).trim();
|
|
11146
11248
|
const split = splitTopLevelReifier(body);
|
|
11147
11249
|
const triple = split.triple;
|
|
11250
|
+
validateSingleRdfTripleTerm(triple);
|
|
11148
11251
|
const graph = '{ ' + triple + ' }';
|
|
11149
11252
|
if (split.reifier) {
|
|
11150
11253
|
const reifier = firstTerm(split.reifier);
|
package/eyeling.js
CHANGED
|
@@ -11140,11 +11140,114 @@ function normalizeRdfCompatibility(inputText) {
|
|
|
11140
11140
|
return text.slice(at, j);
|
|
11141
11141
|
}
|
|
11142
11142
|
|
|
11143
|
+
function readBalancedTermAt(text, at) {
|
|
11144
|
+
const open = text[at];
|
|
11145
|
+
const matching = { '{': '}', '[': ']', '(': ')' };
|
|
11146
|
+
if (!matching[open]) return null;
|
|
11147
|
+
|
|
11148
|
+
const stack = [matching[open]];
|
|
11149
|
+
let j = at + 1;
|
|
11150
|
+
while (j < text.length) {
|
|
11151
|
+
const ch = text[j];
|
|
11152
|
+
if (ch === '"' || ch === "'") {
|
|
11153
|
+
const str = readStringAt(text, j);
|
|
11154
|
+
j = str.end;
|
|
11155
|
+
continue;
|
|
11156
|
+
}
|
|
11157
|
+
if (ch === '<' && !text.startsWith('<<', j)) {
|
|
11158
|
+
const iri = readIriAt(text, j);
|
|
11159
|
+
j = iri.end;
|
|
11160
|
+
continue;
|
|
11161
|
+
}
|
|
11162
|
+
if (ch === '#') {
|
|
11163
|
+
while (j < text.length && text[j] !== '\n' && text[j] !== '\r') j += 1;
|
|
11164
|
+
continue;
|
|
11165
|
+
}
|
|
11166
|
+
if (matching[ch]) {
|
|
11167
|
+
stack.push(matching[ch]);
|
|
11168
|
+
j += 1;
|
|
11169
|
+
continue;
|
|
11170
|
+
}
|
|
11171
|
+
if (ch === stack[stack.length - 1]) {
|
|
11172
|
+
stack.pop();
|
|
11173
|
+
j += 1;
|
|
11174
|
+
if (stack.length === 0) return { text: text.slice(at, j), end: j };
|
|
11175
|
+
continue;
|
|
11176
|
+
}
|
|
11177
|
+
j += 1;
|
|
11178
|
+
}
|
|
11179
|
+
|
|
11180
|
+
throw new N3SyntaxError(`Unterminated term inside RDF 1.2 triple term, expected ${stack[stack.length - 1]}`);
|
|
11181
|
+
}
|
|
11182
|
+
|
|
11183
|
+
function readRdfTripleTermComponent(text, at) {
|
|
11184
|
+
const j = skipWsAndComments(text, at);
|
|
11185
|
+
if (j >= text.length) return null;
|
|
11186
|
+
const ch = text[j];
|
|
11187
|
+
|
|
11188
|
+
if (ch === '<') return readIriAt(text, j);
|
|
11189
|
+
|
|
11190
|
+
if (ch === '"' || ch === "'") {
|
|
11191
|
+
const str = readStringAt(text, j);
|
|
11192
|
+
let end = str.end;
|
|
11193
|
+
let termText = str.text;
|
|
11194
|
+
if (text.startsWith('^^', end)) {
|
|
11195
|
+
const datatype = readRdfTripleTermComponent(text, end + 2);
|
|
11196
|
+
if (datatype) {
|
|
11197
|
+
termText += '^^' + datatype.text;
|
|
11198
|
+
end = datatype.end;
|
|
11199
|
+
}
|
|
11200
|
+
} else if (text[end] === '@') {
|
|
11201
|
+
let k = end + 1;
|
|
11202
|
+
if (/[A-Za-z]/.test(text[k] || '')) {
|
|
11203
|
+
while (k < text.length && /[A-Za-z0-9-]/.test(text[k])) k += 1;
|
|
11204
|
+
termText += text.slice(end, k);
|
|
11205
|
+
end = k;
|
|
11206
|
+
}
|
|
11207
|
+
}
|
|
11208
|
+
return { text: termText, end };
|
|
11209
|
+
}
|
|
11210
|
+
|
|
11211
|
+
if (ch === '{' || ch === '[' || ch === '(') return readBalancedTermAt(text, j);
|
|
11212
|
+
|
|
11213
|
+
let k = j;
|
|
11214
|
+
while (k < text.length && !/\s/.test(text[k]) && !'{}[](),;'.includes(text[k])) k += 1;
|
|
11215
|
+
if (k === j) return null;
|
|
11216
|
+
const value = text.slice(j, k);
|
|
11217
|
+
if (!value || value.startsWith('@')) return null;
|
|
11218
|
+
return { text: value, end: k };
|
|
11219
|
+
}
|
|
11220
|
+
|
|
11221
|
+
function validateSingleRdfTripleTerm(rawTriple) {
|
|
11222
|
+
const triple = rawTriple.trim();
|
|
11223
|
+
if (!triple) throw new N3SyntaxError('RDF 1.2 triple term must contain exactly one subject, predicate, and object');
|
|
11224
|
+
|
|
11225
|
+
let pos = 0;
|
|
11226
|
+
for (const label of ['subject', 'predicate', 'object']) {
|
|
11227
|
+
const term = readRdfTripleTermComponent(triple, pos);
|
|
11228
|
+
if (!term) throw new N3SyntaxError(`RDF 1.2 triple term is missing a ${label}`);
|
|
11229
|
+
pos = term.end;
|
|
11230
|
+
}
|
|
11231
|
+
|
|
11232
|
+
const rest = skipWsAndComments(triple, pos);
|
|
11233
|
+
if (rest >= triple.length) return;
|
|
11234
|
+
|
|
11235
|
+
const found = triple[rest];
|
|
11236
|
+
if (found === ',') {
|
|
11237
|
+
throw new N3SyntaxError("RDF 1.2 triple terms must contain exactly one object; object lists using ',' are not valid inside <<( ... )>>");
|
|
11238
|
+
}
|
|
11239
|
+
if (found === ';') {
|
|
11240
|
+
throw new N3SyntaxError("RDF 1.2 triple terms must contain exactly one predicate-object pair; ';' is not valid inside <<( ... )>>");
|
|
11241
|
+
}
|
|
11242
|
+
throw new N3SyntaxError(`RDF 1.2 triple term must contain exactly one subject, predicate, and object; unexpected ${JSON.stringify(triple.slice(rest, rest + 20))}`);
|
|
11243
|
+
}
|
|
11244
|
+
|
|
11143
11245
|
function graphTermFromTripleBody(rawBody, parenthesized) {
|
|
11144
11246
|
let body = rawBody.trim();
|
|
11145
11247
|
if (parenthesized && body.startsWith('(') && body.endsWith(')')) body = body.slice(1, -1).trim();
|
|
11146
11248
|
const split = splitTopLevelReifier(body);
|
|
11147
11249
|
const triple = split.triple;
|
|
11250
|
+
validateSingleRdfTripleTerm(triple);
|
|
11148
11251
|
const graph = '{ ' + triple + ' }';
|
|
11149
11252
|
if (split.reifier) {
|
|
11150
11253
|
const reifier = firstTerm(split.reifier);
|
package/lib/lexer.js
CHANGED
|
@@ -515,11 +515,114 @@ function normalizeRdfCompatibility(inputText) {
|
|
|
515
515
|
return text.slice(at, j);
|
|
516
516
|
}
|
|
517
517
|
|
|
518
|
+
function readBalancedTermAt(text, at) {
|
|
519
|
+
const open = text[at];
|
|
520
|
+
const matching = { '{': '}', '[': ']', '(': ')' };
|
|
521
|
+
if (!matching[open]) return null;
|
|
522
|
+
|
|
523
|
+
const stack = [matching[open]];
|
|
524
|
+
let j = at + 1;
|
|
525
|
+
while (j < text.length) {
|
|
526
|
+
const ch = text[j];
|
|
527
|
+
if (ch === '"' || ch === "'") {
|
|
528
|
+
const str = readStringAt(text, j);
|
|
529
|
+
j = str.end;
|
|
530
|
+
continue;
|
|
531
|
+
}
|
|
532
|
+
if (ch === '<' && !text.startsWith('<<', j)) {
|
|
533
|
+
const iri = readIriAt(text, j);
|
|
534
|
+
j = iri.end;
|
|
535
|
+
continue;
|
|
536
|
+
}
|
|
537
|
+
if (ch === '#') {
|
|
538
|
+
while (j < text.length && text[j] !== '\n' && text[j] !== '\r') j += 1;
|
|
539
|
+
continue;
|
|
540
|
+
}
|
|
541
|
+
if (matching[ch]) {
|
|
542
|
+
stack.push(matching[ch]);
|
|
543
|
+
j += 1;
|
|
544
|
+
continue;
|
|
545
|
+
}
|
|
546
|
+
if (ch === stack[stack.length - 1]) {
|
|
547
|
+
stack.pop();
|
|
548
|
+
j += 1;
|
|
549
|
+
if (stack.length === 0) return { text: text.slice(at, j), end: j };
|
|
550
|
+
continue;
|
|
551
|
+
}
|
|
552
|
+
j += 1;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
throw new N3SyntaxError(`Unterminated term inside RDF 1.2 triple term, expected ${stack[stack.length - 1]}`);
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
function readRdfTripleTermComponent(text, at) {
|
|
559
|
+
const j = skipWsAndComments(text, at);
|
|
560
|
+
if (j >= text.length) return null;
|
|
561
|
+
const ch = text[j];
|
|
562
|
+
|
|
563
|
+
if (ch === '<') return readIriAt(text, j);
|
|
564
|
+
|
|
565
|
+
if (ch === '"' || ch === "'") {
|
|
566
|
+
const str = readStringAt(text, j);
|
|
567
|
+
let end = str.end;
|
|
568
|
+
let termText = str.text;
|
|
569
|
+
if (text.startsWith('^^', end)) {
|
|
570
|
+
const datatype = readRdfTripleTermComponent(text, end + 2);
|
|
571
|
+
if (datatype) {
|
|
572
|
+
termText += '^^' + datatype.text;
|
|
573
|
+
end = datatype.end;
|
|
574
|
+
}
|
|
575
|
+
} else if (text[end] === '@') {
|
|
576
|
+
let k = end + 1;
|
|
577
|
+
if (/[A-Za-z]/.test(text[k] || '')) {
|
|
578
|
+
while (k < text.length && /[A-Za-z0-9-]/.test(text[k])) k += 1;
|
|
579
|
+
termText += text.slice(end, k);
|
|
580
|
+
end = k;
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
return { text: termText, end };
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
if (ch === '{' || ch === '[' || ch === '(') return readBalancedTermAt(text, j);
|
|
587
|
+
|
|
588
|
+
let k = j;
|
|
589
|
+
while (k < text.length && !/\s/.test(text[k]) && !'{}[](),;'.includes(text[k])) k += 1;
|
|
590
|
+
if (k === j) return null;
|
|
591
|
+
const value = text.slice(j, k);
|
|
592
|
+
if (!value || value.startsWith('@')) return null;
|
|
593
|
+
return { text: value, end: k };
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
function validateSingleRdfTripleTerm(rawTriple) {
|
|
597
|
+
const triple = rawTriple.trim();
|
|
598
|
+
if (!triple) throw new N3SyntaxError('RDF 1.2 triple term must contain exactly one subject, predicate, and object');
|
|
599
|
+
|
|
600
|
+
let pos = 0;
|
|
601
|
+
for (const label of ['subject', 'predicate', 'object']) {
|
|
602
|
+
const term = readRdfTripleTermComponent(triple, pos);
|
|
603
|
+
if (!term) throw new N3SyntaxError(`RDF 1.2 triple term is missing a ${label}`);
|
|
604
|
+
pos = term.end;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
const rest = skipWsAndComments(triple, pos);
|
|
608
|
+
if (rest >= triple.length) return;
|
|
609
|
+
|
|
610
|
+
const found = triple[rest];
|
|
611
|
+
if (found === ',') {
|
|
612
|
+
throw new N3SyntaxError("RDF 1.2 triple terms must contain exactly one object; object lists using ',' are not valid inside <<( ... )>>");
|
|
613
|
+
}
|
|
614
|
+
if (found === ';') {
|
|
615
|
+
throw new N3SyntaxError("RDF 1.2 triple terms must contain exactly one predicate-object pair; ';' is not valid inside <<( ... )>>");
|
|
616
|
+
}
|
|
617
|
+
throw new N3SyntaxError(`RDF 1.2 triple term must contain exactly one subject, predicate, and object; unexpected ${JSON.stringify(triple.slice(rest, rest + 20))}`);
|
|
618
|
+
}
|
|
619
|
+
|
|
518
620
|
function graphTermFromTripleBody(rawBody, parenthesized) {
|
|
519
621
|
let body = rawBody.trim();
|
|
520
622
|
if (parenthesized && body.startsWith('(') && body.endsWith(')')) body = body.slice(1, -1).trim();
|
|
521
623
|
const split = splitTopLevelReifier(body);
|
|
522
624
|
const triple = split.triple;
|
|
625
|
+
validateSingleRdfTripleTerm(triple);
|
|
523
626
|
const graph = '{ ' + triple + ' }';
|
|
524
627
|
if (split.reifier) {
|
|
525
628
|
const reifier = firstTerm(split.reifier);
|
package/package.json
CHANGED
package/test/api.test.js
CHANGED
|
@@ -2916,6 +2916,22 @@ _:b a ex:Person ; ex:name "B" .
|
|
|
2916
2916
|
expect: [/:observation\s+:entails\s+<<\(\s+:sensor\s+:needs\s+:inspection\s*\)>>\s*\./m],
|
|
2917
2917
|
},
|
|
2918
2918
|
|
|
2919
|
+
{
|
|
2920
|
+
name: 'RDF mode rejects object lists inside RDF 1.2 triple terms',
|
|
2921
|
+
opt: { proofComments: false, rdf: true },
|
|
2922
|
+
input: `VERSION "1.2"
|
|
2923
|
+
@prefix : <http://example.org/ns#> .
|
|
2924
|
+
@prefix coll: <http://example.org/collection#> .
|
|
2925
|
+
|
|
2926
|
+
:climateDataset coll:contains
|
|
2927
|
+
<<( :asiaDataset coll:contains
|
|
2928
|
+
<<( :China :avgTemp :18C )>>,
|
|
2929
|
+
<<( :Thailand :avgTemp :20C )>>
|
|
2930
|
+
)>> .
|
|
2931
|
+
`,
|
|
2932
|
+
expectError: true,
|
|
2933
|
+
},
|
|
2934
|
+
|
|
2919
2935
|
{
|
|
2920
2936
|
name: 'RDF mode accepts PREFIX and reified triple terms with reifiers',
|
|
2921
2937
|
opt: { proofComments: false, rdf: true },
|