eyeling 1.5.26 → 1.5.28
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 +58 -3
- package/package.json +1 -1
- package/test/api.test.js +29 -0
package/eyeling.js
CHANGED
|
@@ -235,6 +235,12 @@ function lex(inputText) {
|
|
|
235
235
|
i += 2;
|
|
236
236
|
continue;
|
|
237
237
|
}
|
|
238
|
+
// N3 predicate inversion: "<-" (swap subject/object for this predicate)
|
|
239
|
+
if (peek(1) === "-") {
|
|
240
|
+
tokens.push(new Token("OpPredInvert"));
|
|
241
|
+
i += 2;
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
238
244
|
// Otherwise IRIREF <...>
|
|
239
245
|
i++; // skip '<'
|
|
240
246
|
const iriChars = [];
|
|
@@ -280,8 +286,41 @@ function lex(inputText) {
|
|
|
280
286
|
continue;
|
|
281
287
|
}
|
|
282
288
|
|
|
283
|
-
// String literal
|
|
289
|
+
// String literal: short "..." or long """..."""
|
|
284
290
|
if (c === '"') {
|
|
291
|
+
// Long string literal """ ... """
|
|
292
|
+
if (peek(1) === '"' && peek(2) === '"') {
|
|
293
|
+
i += 3; // consume opening """
|
|
294
|
+
const sChars = [];
|
|
295
|
+
let closed = false;
|
|
296
|
+
while (i < n) {
|
|
297
|
+
// closing delimiter?
|
|
298
|
+
if (peek() === '"' && peek(1) === '"' && peek(2) === '"') {
|
|
299
|
+
i += 3; // consume closing """
|
|
300
|
+
closed = true;
|
|
301
|
+
break;
|
|
302
|
+
}
|
|
303
|
+
let cc = chars[i];
|
|
304
|
+
i++;
|
|
305
|
+
if (cc === "\\") {
|
|
306
|
+
// Preserve escapes verbatim (same behavior as short strings)
|
|
307
|
+
if (i < n) {
|
|
308
|
+
const esc = chars[i];
|
|
309
|
+
i++;
|
|
310
|
+
sChars.push("\\");
|
|
311
|
+
sChars.push(esc);
|
|
312
|
+
}
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
315
|
+
sChars.push(cc);
|
|
316
|
+
}
|
|
317
|
+
if (!closed) throw new Error('Unterminated long string literal """..."""');
|
|
318
|
+
const s = '"""' + sChars.join("") + '"""';
|
|
319
|
+
tokens.push(new Token("Literal", s));
|
|
320
|
+
continue;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Short string literal " ... "
|
|
285
324
|
i++; // consume opening "
|
|
286
325
|
const sChars = [];
|
|
287
326
|
while (i < n) {
|
|
@@ -790,9 +829,14 @@ class Parser {
|
|
|
790
829
|
while (true) {
|
|
791
830
|
// Verb (can also be 'a')
|
|
792
831
|
let pred;
|
|
832
|
+
let invert = false;
|
|
793
833
|
if (this.peek().typ === "Ident" && (this.peek().value || "") === "a") {
|
|
794
834
|
this.next();
|
|
795
835
|
pred = new Iri(RDF_NS + "type");
|
|
836
|
+
} else if (this.peek().typ === "OpPredInvert") {
|
|
837
|
+
this.next(); // consume "<-"
|
|
838
|
+
pred = this.parseTerm();
|
|
839
|
+
invert = true;
|
|
796
840
|
} else {
|
|
797
841
|
pred = this.parseTerm();
|
|
798
842
|
}
|
|
@@ -805,7 +849,8 @@ class Parser {
|
|
|
805
849
|
}
|
|
806
850
|
|
|
807
851
|
for (const o of objs) {
|
|
808
|
-
this.pendingTriples.push(new Triple(
|
|
852
|
+
this.pendingTriples.push(invert ? new Triple(o, pred, subj)
|
|
853
|
+
: new Triple(subj, pred, o));
|
|
809
854
|
}
|
|
810
855
|
|
|
811
856
|
if (this.peek().typ === "Semicolon") {
|
|
@@ -873,14 +918,21 @@ class Parser {
|
|
|
873
918
|
const out = [];
|
|
874
919
|
while (true) {
|
|
875
920
|
let verb;
|
|
921
|
+
let invert = false;
|
|
876
922
|
if (this.peek().typ === "Ident" && (this.peek().value || "") === "a") {
|
|
877
923
|
this.next();
|
|
878
924
|
verb = new Iri(RDF_NS + "type");
|
|
925
|
+
} else if (this.peek().typ === "OpPredInvert") {
|
|
926
|
+
this.next(); // consume "<-"
|
|
927
|
+
verb = this.parseTerm(); // predicate expression
|
|
928
|
+
invert = true;
|
|
879
929
|
} else {
|
|
880
930
|
verb = this.parseTerm();
|
|
881
931
|
}
|
|
882
932
|
const objects = this.parseObjectList();
|
|
883
|
-
for (const o of objects)
|
|
933
|
+
for (const o of objects) {
|
|
934
|
+
out.push(new Triple(invert ? o : subject, verb, invert ? subject : o));
|
|
935
|
+
}
|
|
884
936
|
|
|
885
937
|
if (this.peek().typ === "Semicolon") {
|
|
886
938
|
this.next();
|
|
@@ -1680,6 +1732,9 @@ function literalParts(lit) {
|
|
|
1680
1732
|
}
|
|
1681
1733
|
|
|
1682
1734
|
function stripQuotes(lex) {
|
|
1735
|
+
if (lex.length >= 6 && lex.startsWith('"""') && lex.endsWith('"""')) {
|
|
1736
|
+
return lex.slice(3, -3);
|
|
1737
|
+
}
|
|
1683
1738
|
if (lex.length >= 2 && lex[0] === '"' && lex[lex.length - 1] === '"') {
|
|
1684
1739
|
return lex.slice(1, -1);
|
|
1685
1740
|
}
|
package/package.json
CHANGED
package/test/api.test.js
CHANGED
|
@@ -621,6 +621,35 @@ ${U('s')} ${U('p')} ${U('o')}. # another trailing comment
|
|
|
621
621
|
mustOccurExactly(out, reD, 1, 'diamond subclass should not duplicate x type D');
|
|
622
622
|
},
|
|
623
623
|
},
|
|
624
|
+
|
|
625
|
+
{
|
|
626
|
+
name: '42 literals: language tags are accepted and preserved',
|
|
627
|
+
opt: { proofComments: false },
|
|
628
|
+
input: ` { ?s ${U('p')} ?o } => { ?s ${U('q')} ?o }. ${U('s')} ${U('p')} "colour"@en-GB.`,
|
|
629
|
+
expect: [new RegExp(`${EX}s>\\s+<${EX}q>\\s+"colour"@en-GB\\s*\\.`)],
|
|
630
|
+
},
|
|
631
|
+
|
|
632
|
+
{
|
|
633
|
+
name: '43 literals: long """...""" strings are accepted (with lang tag)',
|
|
634
|
+
opt: { proofComments: false },
|
|
635
|
+
input: ` { ?s ${U('p')} ?o } => { ?s ${U('q')} ?o }. ${U('s')} ${U('p')} """Hello
|
|
636
|
+
world"""@en.`,
|
|
637
|
+
expect: [new RegExp(`${EX}s>\\s+<${EX}q>\\s+(?:"""Hello[\\s\\S]*?world"""@en|"Hello\\\\nworld"@en)\\s*\\.`)],
|
|
638
|
+
},
|
|
639
|
+
|
|
640
|
+
{ name: '44 syntax: "<-" in predicate position swaps subject and object',
|
|
641
|
+
opt: { proofComments: false },
|
|
642
|
+
input: ` { ?s ${U('p')} ?o } => { ?s ${U('q')} ?o }.
|
|
643
|
+
${U('a')} <-${U('p')} ${U('b')}.`,
|
|
644
|
+
expect: [new RegExp(`${EX}b>\\s+<${EX}q>\\s+<${EX}a>\\s*\\.`)],
|
|
645
|
+
},
|
|
646
|
+
|
|
647
|
+
{ name: '45 syntax: "<-" works inside blank node property lists ([ ... ])',
|
|
648
|
+
opt: { proofComments: false },
|
|
649
|
+
input: ` ${U('s')} ${U('p')} [ <-${U('r')} ${U('o')} ].
|
|
650
|
+
{ ${U('o')} ${U('r')} ?x } => { ?x ${U('q')} ${U('k')} }.`,
|
|
651
|
+
expect: [new RegExp(`_:b1\\s+<${EX}q>\\s+<${EX}k>\\s*\\.`)],
|
|
652
|
+
},
|
|
624
653
|
];
|
|
625
654
|
|
|
626
655
|
let passed = 0;
|