eyeling 1.5.26 → 1.5.27

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
@@ -280,8 +280,41 @@ function lex(inputText) {
280
280
  continue;
281
281
  }
282
282
 
283
- // String literal
283
+ // String literal: short "..." or long """..."""
284
284
  if (c === '"') {
285
+ // Long string literal """ ... """
286
+ if (peek(1) === '"' && peek(2) === '"') {
287
+ i += 3; // consume opening """
288
+ const sChars = [];
289
+ let closed = false;
290
+ while (i < n) {
291
+ // closing delimiter?
292
+ if (peek() === '"' && peek(1) === '"' && peek(2) === '"') {
293
+ i += 3; // consume closing """
294
+ closed = true;
295
+ break;
296
+ }
297
+ let cc = chars[i];
298
+ i++;
299
+ if (cc === "\\") {
300
+ // Preserve escapes verbatim (same behavior as short strings)
301
+ if (i < n) {
302
+ const esc = chars[i];
303
+ i++;
304
+ sChars.push("\\");
305
+ sChars.push(esc);
306
+ }
307
+ continue;
308
+ }
309
+ sChars.push(cc);
310
+ }
311
+ if (!closed) throw new Error('Unterminated long string literal """..."""');
312
+ const s = '"""' + sChars.join("") + '"""';
313
+ tokens.push(new Token("Literal", s));
314
+ continue;
315
+ }
316
+
317
+ // Short string literal " ... "
285
318
  i++; // consume opening "
286
319
  const sChars = [];
287
320
  while (i < n) {
@@ -1680,6 +1713,9 @@ function literalParts(lit) {
1680
1713
  }
1681
1714
 
1682
1715
  function stripQuotes(lex) {
1716
+ if (lex.length >= 6 && lex.startsWith('"""') && lex.endsWith('"""')) {
1717
+ return lex.slice(3, -3);
1718
+ }
1683
1719
  if (lex.length >= 2 && lex[0] === '"' && lex[lex.length - 1] === '"') {
1684
1720
  return lex.slice(1, -1);
1685
1721
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyeling",
3
- "version": "1.5.26",
3
+ "version": "1.5.27",
4
4
  "description": "A minimal Notation3 (N3) reasoner in JavaScript.",
5
5
  "main": "./index.js",
6
6
  "keywords": [
package/test/api.test.js CHANGED
@@ -621,6 +621,21 @@ ${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
+ },
624
639
  ];
625
640
 
626
641
  let passed = 0;