eyeling 1.6.0 → 1.6.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/examples/alignment-demo.n3 +84 -0
- package/examples/minimal-skos-alignment.n3 +38 -0
- package/examples/output/alignment-demo.n3 +610 -0
- package/examples/output/minimal-skos-alignment.n3 +45 -0
- package/eyeling.js +51 -11
- package/index.js +1 -4
- package/package.json +1 -1
- package/test/api.test.js +32 -47
- package/test/examples.test.js +29 -24
- package/test/package.test.js +27 -15
- package/test/packlist.test.js +14 -17
- /package/examples/{collect-all-in.n3 → log-collect-all-in.n3} +0 -0
- /package/examples/{for-all-in.n3 → log-for-all-in.n3} +0 -0
- /package/examples/{not-includes.n3 → log-not-includes.n3} +0 -0
- /package/examples/{skolem.n3 → log-skolem.n3} +0 -0
- /package/examples/{uri.n3 → log-uri.n3} +0 -0
- /package/examples/output/{collect-all-in.n3 → log-collect-all-in.n3} +0 -0
- /package/examples/output/{for-all-in.n3 → log-for-all-in.n3} +0 -0
- /package/examples/output/{not-includes.n3 → log-not-includes.n3} +0 -0
- /package/examples/output/{skolem.n3 → log-skolem.n3} +0 -0
- /package/examples/output/{uri.n3 → log-uri.n3} +0 -0
package/eyeling.js
CHANGED
|
@@ -499,6 +499,25 @@ function lex(inputText) {
|
|
|
499
499
|
}
|
|
500
500
|
break;
|
|
501
501
|
}
|
|
502
|
+
|
|
503
|
+
// Optional exponent part: e.g., 1e0, 1.1e-3, 1.1E+0
|
|
504
|
+
if (i < n && (chars[i] === 'e' || chars[i] === 'E')) {
|
|
505
|
+
let j = i + 1;
|
|
506
|
+
if (j < n && (chars[j] === '+' || chars[j] === '-')) j++;
|
|
507
|
+
if (j < n && /[0-9]/.test(chars[j])) {
|
|
508
|
+
numChars.push(chars[i]); // e/E
|
|
509
|
+
i++;
|
|
510
|
+
if (i < n && (chars[i] === '+' || chars[i] === '-')) {
|
|
511
|
+
numChars.push(chars[i]);
|
|
512
|
+
i++;
|
|
513
|
+
}
|
|
514
|
+
while (i < n && /[0-9]/.test(chars[i])) {
|
|
515
|
+
numChars.push(chars[i]);
|
|
516
|
+
i++;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
502
521
|
tokens.push(new Token('Literal', numChars.join('')));
|
|
503
522
|
continue;
|
|
504
523
|
}
|
|
@@ -1863,6 +1882,22 @@ function unifyTerm(a, b, subst) {
|
|
|
1863
1882
|
if (a instanceof Literal && b instanceof Literal && a.value === b.value) return { ...subst };
|
|
1864
1883
|
if (a instanceof Blank && b instanceof Blank && a.label === b.label) return { ...subst };
|
|
1865
1884
|
|
|
1885
|
+
// Numeric-value match for literals (EYE-style): allow different lexical forms / typing
|
|
1886
|
+
// e.g. "1.1"^^xsd:double ≈ 1.1e0
|
|
1887
|
+
if (a instanceof Literal && b instanceof Literal) {
|
|
1888
|
+
const av = parseNumberLiteral(a); // BigInt | Number | null
|
|
1889
|
+
const bv = parseNumberLiteral(b);
|
|
1890
|
+
if (av !== null && bv !== null) {
|
|
1891
|
+
if (typeof av === 'bigint' && typeof bv === 'bigint') {
|
|
1892
|
+
if (av === bv) return { ...subst };
|
|
1893
|
+
} else {
|
|
1894
|
+
const an = typeof av === 'bigint' ? Number(av) : av;
|
|
1895
|
+
const bn = typeof bv === 'bigint' ? Number(bv) : bv;
|
|
1896
|
+
if (!Number.isNaN(an) && !Number.isNaN(bn) && an === bn) return { ...subst };
|
|
1897
|
+
}
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1900
|
+
|
|
1866
1901
|
// Open list vs concrete list
|
|
1867
1902
|
if (a instanceof OpenListTerm && b instanceof ListTerm) {
|
|
1868
1903
|
return unifyOpenWithList(a.prefix, a.tailVar, b.elems, subst);
|
|
@@ -2438,6 +2473,11 @@ function listAppendSplit(parts, resElems, subst) {
|
|
|
2438
2473
|
return out;
|
|
2439
2474
|
}
|
|
2440
2475
|
|
|
2476
|
+
function numEqualTerm(t, n, eps = 1e-9) {
|
|
2477
|
+
const v = parseNum(t);
|
|
2478
|
+
return v !== null && Math.abs(v - n) < eps;
|
|
2479
|
+
}
|
|
2480
|
+
|
|
2441
2481
|
// ============================================================================
|
|
2442
2482
|
// Backward proof & builtins mutual recursion — declarations first
|
|
2443
2483
|
// ============================================================================
|
|
@@ -2809,7 +2849,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
2809
2849
|
s2[g.o.name] = new Literal(formatNum(cVal));
|
|
2810
2850
|
return [s2];
|
|
2811
2851
|
}
|
|
2812
|
-
if (g.o
|
|
2852
|
+
if (numEqualTerm(g.o, cVal)) {
|
|
2813
2853
|
return [{ ...subst }];
|
|
2814
2854
|
}
|
|
2815
2855
|
}
|
|
@@ -2874,7 +2914,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
2874
2914
|
s2[g.o.name] = new Literal(formatNum(cVal));
|
|
2875
2915
|
return [s2];
|
|
2876
2916
|
}
|
|
2877
|
-
if (g.o
|
|
2917
|
+
if (numEqualTerm(g.o, cVal)) {
|
|
2878
2918
|
return [{ ...subst }];
|
|
2879
2919
|
}
|
|
2880
2920
|
}
|
|
@@ -2891,7 +2931,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
2891
2931
|
s2[g.o.name] = new Literal(formatNum(cVal));
|
|
2892
2932
|
return [s2];
|
|
2893
2933
|
}
|
|
2894
|
-
if (g.o
|
|
2934
|
+
if (numEqualTerm(g.o, cVal)) {
|
|
2895
2935
|
return [{ ...subst }];
|
|
2896
2936
|
}
|
|
2897
2937
|
}
|
|
@@ -2909,7 +2949,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
2909
2949
|
s2[g.o.name] = new Literal(formatNum(cVal));
|
|
2910
2950
|
return [s2];
|
|
2911
2951
|
}
|
|
2912
|
-
if (g.o
|
|
2952
|
+
if (numEqualTerm(g.o, cVal)) {
|
|
2913
2953
|
return [{ ...subst }];
|
|
2914
2954
|
}
|
|
2915
2955
|
}
|
|
@@ -2928,7 +2968,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
2928
2968
|
s2[g.o.name] = new Literal(formatNum(cVal));
|
|
2929
2969
|
return [s2];
|
|
2930
2970
|
}
|
|
2931
|
-
if (g.o
|
|
2971
|
+
if (numEqualTerm(g.o, cVal)) {
|
|
2932
2972
|
return [{ ...subst }];
|
|
2933
2973
|
}
|
|
2934
2974
|
}
|
|
@@ -2947,7 +2987,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
2947
2987
|
s2[g.o.name] = new Literal(formatNum(cVal));
|
|
2948
2988
|
return [s2];
|
|
2949
2989
|
}
|
|
2950
|
-
if (g.o
|
|
2990
|
+
if (numEqualTerm(g.o, cVal)) {
|
|
2951
2991
|
return [{ ...subst }];
|
|
2952
2992
|
}
|
|
2953
2993
|
}
|
|
@@ -2967,7 +3007,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
2967
3007
|
s2[g.o.name] = new Literal(formatNum(cVal));
|
|
2968
3008
|
return [s2];
|
|
2969
3009
|
}
|
|
2970
|
-
if (g.o
|
|
3010
|
+
if (numEqualTerm(g.o, cVal)) {
|
|
2971
3011
|
return [{ ...subst }];
|
|
2972
3012
|
}
|
|
2973
3013
|
}
|
|
@@ -2987,7 +3027,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
2987
3027
|
s2[g.o.name] = new Literal(formatNum(cVal));
|
|
2988
3028
|
return [s2];
|
|
2989
3029
|
}
|
|
2990
|
-
if (g.o
|
|
3030
|
+
if (numEqualTerm(g.o, cVal)) {
|
|
2991
3031
|
return [{ ...subst }];
|
|
2992
3032
|
}
|
|
2993
3033
|
}
|
|
@@ -3046,7 +3086,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3046
3086
|
s2[g.o.name] = new Literal(formatNum(cVal));
|
|
3047
3087
|
return [s2];
|
|
3048
3088
|
}
|
|
3049
|
-
if (g.o
|
|
3089
|
+
if (numEqualTerm(g.o, cVal)) {
|
|
3050
3090
|
return [{ ...subst }];
|
|
3051
3091
|
}
|
|
3052
3092
|
}
|
|
@@ -3065,7 +3105,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3065
3105
|
s2[g.o.name] = new Literal(formatNum(cVal));
|
|
3066
3106
|
return [s2];
|
|
3067
3107
|
}
|
|
3068
|
-
if (g.o
|
|
3108
|
+
if (numEqualTerm(g.o, cVal)) {
|
|
3069
3109
|
return [{ ...subst }];
|
|
3070
3110
|
}
|
|
3071
3111
|
}
|
|
@@ -3084,7 +3124,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3084
3124
|
s2[g.o.name] = new Literal(formatNum(cVal));
|
|
3085
3125
|
return [s2];
|
|
3086
3126
|
}
|
|
3087
|
-
if (g.o
|
|
3127
|
+
if (numEqualTerm(g.o, cVal)) {
|
|
3088
3128
|
return [{ ...subst }];
|
|
3089
3129
|
}
|
|
3090
3130
|
}
|
package/index.js
CHANGED
|
@@ -19,9 +19,7 @@ function reason(opt = {}, n3_input = '') {
|
|
|
19
19
|
// default: proof comments OFF for API output (machine-friendly)
|
|
20
20
|
// set { proofComments: true } to keep them
|
|
21
21
|
const proofComments =
|
|
22
|
-
|
|
23
|
-
(typeof opt.noProofComments === 'boolean') ? !opt.noProofComments :
|
|
24
|
-
false;
|
|
22
|
+
typeof opt.proofComments === 'boolean' ? opt.proofComments : typeof opt.noProofComments === 'boolean' ? !opt.noProofComments : false;
|
|
25
23
|
|
|
26
24
|
if (!proofComments) args.push('--no-proof-comments'); // CLI already supports this :contentReference[oaicite:1]{index=1}
|
|
27
25
|
|
|
@@ -58,4 +56,3 @@ function reason(opt = {}, n3_input = '') {
|
|
|
58
56
|
module.exports = { reason };
|
|
59
57
|
// small interop nicety for ESM default import
|
|
60
58
|
module.exports.default = module.exports;
|
|
61
|
-
|
package/package.json
CHANGED
package/test/api.test.js
CHANGED
|
@@ -4,9 +4,7 @@ const assert = require('node:assert/strict');
|
|
|
4
4
|
const { reason } = require('..');
|
|
5
5
|
|
|
6
6
|
const TTY = process.stdout.isTTY;
|
|
7
|
-
const C = TTY
|
|
8
|
-
? { g: '\x1b[32m', r: '\x1b[31m', y: '\x1b[33m', dim: '\x1b[2m', n: '\x1b[0m' }
|
|
9
|
-
: { g: '', r: '', y: '', dim: '', n: '' };
|
|
7
|
+
const C = TTY ? { g: '\x1b[32m', r: '\x1b[31m', y: '\x1b[33m', dim: '\x1b[2m', n: '\x1b[0m' } : { g: '', r: '', y: '', dim: '', n: '' };
|
|
10
8
|
|
|
11
9
|
function ok(msg) {
|
|
12
10
|
console.log(`${C.g}OK${C.n} ${msg}`);
|
|
@@ -352,10 +350,7 @@ ${U('a')} ${U('p')} ${U('b')}.
|
|
|
352
350
|
name: '17 heavier reachability: branching graph reach closure',
|
|
353
351
|
opt: { proofComments: false, maxBuffer: 200 * 1024 * 1024 },
|
|
354
352
|
input: reachabilityGraphN3(12),
|
|
355
|
-
expect: [
|
|
356
|
-
new RegExp(`${EX}g0>\\s+<${EX}reach>\\s+<${EX}g12>\\s*\\.`),
|
|
357
|
-
new RegExp(`${EX}g2>\\s+<${EX}reach>\\s+<${EX}g10>\\s*\\.`),
|
|
358
|
-
],
|
|
353
|
+
expect: [new RegExp(`${EX}g0>\\s+<${EX}reach>\\s+<${EX}g12>\\s*\\.`), new RegExp(`${EX}g2>\\s+<${EX}reach>\\s+<${EX}g10>\\s*\\.`)],
|
|
359
354
|
},
|
|
360
355
|
{
|
|
361
356
|
name: '18 heavier taxonomy: diamond subclass inference',
|
|
@@ -383,10 +378,7 @@ ${U('a')} ${U('p')} ${U('b')}.
|
|
|
383
378
|
name: '21 heavier equivalence: sameAs propagation (with symmetric sameAs)',
|
|
384
379
|
opt: { proofComments: false },
|
|
385
380
|
input: sameAsN3(),
|
|
386
|
-
expect: [
|
|
387
|
-
new RegExp(`${EX}b>\\s+<${EX}p>\\s+<${EX}o>\\s*\\.`),
|
|
388
|
-
new RegExp(`${EX}b>\\s+<${EX}sameAs>\\s+<${EX}a>\\s*\\.`),
|
|
389
|
-
],
|
|
381
|
+
expect: [new RegExp(`${EX}b>\\s+<${EX}p>\\s+<${EX}o>\\s*\\.`), new RegExp(`${EX}b>\\s+<${EX}sameAs>\\s+<${EX}a>\\s*\\.`)],
|
|
390
382
|
},
|
|
391
383
|
{
|
|
392
384
|
name: '22 heavier closure: transitive property via generic rule',
|
|
@@ -398,10 +390,7 @@ ${U('c')} ${U('sub')} ${U('d')}.
|
|
|
398
390
|
${U('d')} ${U('sub')} ${U('e')}.
|
|
399
391
|
${transitiveClosureN3('sub')}
|
|
400
392
|
`,
|
|
401
|
-
expect: [
|
|
402
|
-
new RegExp(`${EX}a>\\s+<${EX}sub>\\s+<${EX}e>\\s*\\.`),
|
|
403
|
-
new RegExp(`${EX}b>\\s+<${EX}sub>\\s+<${EX}d>\\s*\\.`),
|
|
404
|
-
],
|
|
393
|
+
expect: [new RegExp(`${EX}a>\\s+<${EX}sub>\\s+<${EX}e>\\s*\\.`), new RegExp(`${EX}b>\\s+<${EX}sub>\\s+<${EX}d>\\s*\\.`)],
|
|
405
394
|
},
|
|
406
395
|
{
|
|
407
396
|
name: '23 heavier social: symmetric + reachFriend closure',
|
|
@@ -416,10 +405,7 @@ ${transitiveClosureN3('sub')}
|
|
|
416
405
|
name: '24 heavier volume: 400 facts, simple rewrite rule p -> q',
|
|
417
406
|
opt: { proofComments: false, maxBuffer: 200 * 1024 * 1024 },
|
|
418
407
|
input: bigFactsN3(400),
|
|
419
|
-
expect: [
|
|
420
|
-
new RegExp(`${EX}x>\\s+<${EX}q>\\s+<${EX}o0>\\s*\\.`),
|
|
421
|
-
new RegExp(`${EX}x>\\s+<${EX}q>\\s+<${EX}o399>\\s*\\.`),
|
|
422
|
-
],
|
|
408
|
+
expect: [new RegExp(`${EX}x>\\s+<${EX}q>\\s+<${EX}o0>\\s*\\.`), new RegExp(`${EX}x>\\s+<${EX}q>\\s+<${EX}o399>\\s*\\.`)],
|
|
423
409
|
},
|
|
424
410
|
{
|
|
425
411
|
name: '25 heavier negative entailment: batch + forbidden => false (expect exit 2)',
|
|
@@ -505,10 +491,7 @@ ${U('c')} ${U('p')} ${U('d')}.
|
|
|
505
491
|
|
|
506
492
|
{ ?s ${U('p')} ?o. } => { ?s ${U('q')} ?o. }.
|
|
507
493
|
`,
|
|
508
|
-
expect: [
|
|
509
|
-
new RegExp(`${EX}a>\\s+<${EX}q>\\s+<${EX}b>\\s*\\.`),
|
|
510
|
-
new RegExp(`${EX}c>\\s+<${EX}q>\\s+<${EX}d>\\s*\\.`),
|
|
511
|
-
],
|
|
494
|
+
expect: [new RegExp(`${EX}a>\\s+<${EX}q>\\s+<${EX}b>\\s*\\.`), new RegExp(`${EX}c>\\s+<${EX}q>\\s+<${EX}d>\\s*\\.`)],
|
|
512
495
|
},
|
|
513
496
|
|
|
514
497
|
{
|
|
@@ -554,10 +537,7 @@ ${U('s')} ${U('p')} ${U('o')}.
|
|
|
554
537
|
|
|
555
538
|
{ ${U('s')} ${U('p')} ${U('o')}. } => { ${U('s')} ${U('q')} ${U('o')}. ${U('s')} ${U('r')} ${U('o')}. }.
|
|
556
539
|
`,
|
|
557
|
-
expect: [
|
|
558
|
-
new RegExp(`${EX}s>\\s+<${EX}q>\\s+<${EX}o>\\s*\\.`),
|
|
559
|
-
new RegExp(`${EX}s>\\s+<${EX}r>\\s+<${EX}o>\\s*\\.`),
|
|
560
|
-
],
|
|
540
|
+
expect: [new RegExp(`${EX}s>\\s+<${EX}q>\\s+<${EX}o>\\s*\\.`), new RegExp(`${EX}s>\\s+<${EX}r>\\s+<${EX}o>\\s*\\.`)],
|
|
561
541
|
},
|
|
562
542
|
|
|
563
543
|
{
|
|
@@ -637,56 +617,61 @@ world"""@en.`,
|
|
|
637
617
|
expect: [new RegExp(`${EX}s>\\s+<${EX}q>\\s+(?:"""Hello[\\s\\S]*?world"""@en|"Hello\\\\nworld"@en)\\s*\\.`)],
|
|
638
618
|
},
|
|
639
619
|
|
|
640
|
-
{
|
|
620
|
+
{
|
|
621
|
+
name: '44 syntax: "<-" in predicate position swaps subject and object',
|
|
641
622
|
opt: { proofComments: false },
|
|
642
623
|
input: ` { ?s ${U('p')} ?o } => { ?s ${U('q')} ?o }.
|
|
643
624
|
${U('a')} <-${U('p')} ${U('b')}.`,
|
|
644
625
|
expect: [new RegExp(`${EX}b>\\s+<${EX}q>\\s+<${EX}a>\\s*\\.`)],
|
|
645
626
|
},
|
|
646
627
|
|
|
647
|
-
{
|
|
628
|
+
{
|
|
629
|
+
name: '45 syntax: "<-" works inside blank node property lists ([ ... ])',
|
|
648
630
|
opt: { proofComments: false },
|
|
649
631
|
input: ` ${U('s')} ${U('p')} [ <-${U('r')} ${U('o')} ].
|
|
650
632
|
{ ${U('o')} ${U('r')} ?x } => { ?x ${U('q')} ${U('k')} }.`,
|
|
651
633
|
expect: [new RegExp(`_:b1\\s+<${EX}q>\\s+<${EX}k>\\s*\\.`)],
|
|
652
634
|
},
|
|
653
635
|
|
|
654
|
-
{
|
|
636
|
+
{
|
|
637
|
+
name: '46 syntax: N3 resource paths (! / ^) expand to blank-node triples (forward chain)',
|
|
655
638
|
opt: { proofComments: false },
|
|
656
639
|
input: ` ${U('joe')}!${U('hasAddress')}!${U('hasCity')} ${U('name')} "Metropolis".
|
|
657
640
|
{ ${U('joe')} ${U('hasAddress')} ?a } => { ?a ${U('q')} "addr" }.
|
|
658
641
|
{ ?a ${U('hasCity')} ?c } => { ?c ${U('q')} "city" }.
|
|
659
642
|
`,
|
|
660
|
-
expect: [
|
|
661
|
-
new RegExp(`_:b1\\s+<${EX}q>\\s+"addr"\\s*\\.`),
|
|
662
|
-
new RegExp(`_:b2\\s+<${EX}q>\\s+"city"\\s*\\.`),
|
|
663
|
-
],
|
|
643
|
+
expect: [new RegExp(`_:b1\\s+<${EX}q>\\s+"addr"\\s*\\.`), new RegExp(`_:b2\\s+<${EX}q>\\s+"city"\\s*\\.`)],
|
|
664
644
|
},
|
|
665
645
|
|
|
666
|
-
{
|
|
646
|
+
{
|
|
647
|
+
name: '47 syntax: N3 resource paths support reverse steps (^) in the chain',
|
|
667
648
|
opt: { proofComments: false },
|
|
668
649
|
input: ` ${U('joe')}!${U('hasMother')}^${U('hasMother')} ${U('knows')} ${U('someone')}.
|
|
669
650
|
{ ?sib ${U('hasMother')} ?mom. ${U('joe')} ${U('hasMother')} ?mom } => { ?sib ${U('q')} ${U('joe')} }.
|
|
670
651
|
`,
|
|
671
|
-
expect: [
|
|
672
|
-
new RegExp(`_:b2\\s+<${EX}q>\\s+<${EX}joe>\\s*\\.`),
|
|
673
|
-
],
|
|
652
|
+
expect: [new RegExp(`_:b2\\s+<${EX}q>\\s+<${EX}joe>\\s*\\.`)],
|
|
674
653
|
},
|
|
675
654
|
|
|
676
|
-
{
|
|
677
|
-
|
|
655
|
+
{
|
|
656
|
+
name: '48 rdf:first: works on list terms (alias of list:first)',
|
|
657
|
+
opt: { proofComments: false },
|
|
658
|
+
input: ` { ( ${U('a')} ${U('b')} ${U('c')} ) rdf:first ?x. } => { ${U('s')} ${U('first')} ?x. }.
|
|
678
659
|
`,
|
|
679
660
|
expect: [new RegExp(`${EX}s>\\s+<${EX}first>\\s+<${EX}a>\\s*\\.`)],
|
|
680
661
|
},
|
|
681
662
|
|
|
682
|
-
{
|
|
683
|
-
|
|
663
|
+
{
|
|
664
|
+
name: '49 rdf:rest: works on list terms (alias of list:rest)',
|
|
665
|
+
opt: { proofComments: false },
|
|
666
|
+
input: ` { ( ${U('a')} ${U('b')} ${U('c')} ) rdf:rest ?r. ?r rdf:first ?y. } => { ${U('s')} ${U('second')} ?y. }.
|
|
684
667
|
`,
|
|
685
668
|
expect: [new RegExp(`${EX}s>\\s+<${EX}second>\\s+<${EX}b>\\s*\\.`)],
|
|
686
669
|
},
|
|
687
670
|
|
|
688
|
-
{
|
|
689
|
-
|
|
671
|
+
{
|
|
672
|
+
name: '50 rdf collection materialization: rdf:first/rdf:rest triples become list terms',
|
|
673
|
+
opt: { proofComments: false },
|
|
674
|
+
input: ` ${U('s')} ${U('p')} _:l1.
|
|
690
675
|
_:l1 rdf:first ${U('a')}.
|
|
691
676
|
_:l1 rdf:rest _:l2.
|
|
692
677
|
_:l2 rdf:first ${U('b')}.
|
|
@@ -741,7 +726,7 @@ let failed = 0;
|
|
|
741
726
|
fail(
|
|
742
727
|
`Expected exit code ${tc.expectErrorCode}, got: ${e && e.code != null ? e.code : 'unknown'}\n${
|
|
743
728
|
e && e.stderr ? e.stderr : e && e.stack ? e.stack : String(e)
|
|
744
|
-
}
|
|
729
|
+
}`,
|
|
745
730
|
);
|
|
746
731
|
failed++;
|
|
747
732
|
continue;
|
|
@@ -761,7 +746,8 @@ let failed = 0;
|
|
|
761
746
|
|
|
762
747
|
console.log('');
|
|
763
748
|
const suiteMs = Date.now() - suiteStart;
|
|
764
|
-
console.log(`${C.y}==${C.n} Total elapsed: ${suiteMs} ms`);
|
|
749
|
+
console.log(`${C.y}==${C.n} Total elapsed: ${suiteMs} ms (${(suiteMs / 1000).toFixed(2)} s)`);
|
|
750
|
+
|
|
765
751
|
if (failed === 0) {
|
|
766
752
|
ok(`All API tests passed (${passed}/${cases.length})`);
|
|
767
753
|
process.exit(0);
|
|
@@ -770,4 +756,3 @@ let failed = 0;
|
|
|
770
756
|
process.exit(1);
|
|
771
757
|
}
|
|
772
758
|
})();
|
|
773
|
-
|
package/test/examples.test.js
CHANGED
|
@@ -7,13 +7,18 @@ const path = require('node:path');
|
|
|
7
7
|
const cp = require('node:child_process');
|
|
8
8
|
|
|
9
9
|
const TTY = process.stdout.isTTY;
|
|
10
|
-
const C = TTY
|
|
11
|
-
|
|
12
|
-
: { g: '', r: '', y: '', dim: '', n: '' };
|
|
10
|
+
const C = TTY ? { g: '\x1b[32m', r: '\x1b[31m', y: '\x1b[33m', dim: '\x1b[2m', n: '\x1b[0m' } : { g: '', r: '', y: '', dim: '', n: '' };
|
|
11
|
+
const msTag = (ms) => `${C.dim}(${ms} ms)${C.n}`;
|
|
13
12
|
|
|
14
|
-
function ok(msg)
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
function ok(msg) {
|
|
14
|
+
console.log(`${C.g}OK${C.n} ${msg}`);
|
|
15
|
+
}
|
|
16
|
+
function fail(msg) {
|
|
17
|
+
console.error(`${C.r}FAIL${C.n} ${msg}`);
|
|
18
|
+
}
|
|
19
|
+
function info(msg) {
|
|
20
|
+
console.log(`${C.y}==${C.n} ${msg}`);
|
|
21
|
+
}
|
|
17
22
|
|
|
18
23
|
function run(cmd, args, opts = {}) {
|
|
19
24
|
return cp.spawnSync(cmd, args, {
|
|
@@ -57,7 +62,9 @@ function mkTmpDir() {
|
|
|
57
62
|
}
|
|
58
63
|
|
|
59
64
|
function rmrf(p) {
|
|
60
|
-
try {
|
|
65
|
+
try {
|
|
66
|
+
fs.rmSync(p, { recursive: true, force: true });
|
|
67
|
+
} catch {}
|
|
61
68
|
}
|
|
62
69
|
|
|
63
70
|
function showDiff({ IN_GIT, examplesDir, expectedPath, generatedPath, relExpectedPosix }) {
|
|
@@ -103,13 +110,12 @@ function main() {
|
|
|
103
110
|
|
|
104
111
|
const IN_GIT = inGitWorktree(root);
|
|
105
112
|
|
|
106
|
-
const files = fs
|
|
107
|
-
.
|
|
113
|
+
const files = fs
|
|
114
|
+
.readdirSync(examplesDir)
|
|
115
|
+
.filter((f) => f.endsWith('.n3'))
|
|
108
116
|
.sort((a, b) => a.localeCompare(b));
|
|
109
117
|
|
|
110
|
-
info(
|
|
111
|
-
`Running ${files.length} examples tests (${IN_GIT ? 'git worktree mode' : 'npm-installed mode'})`
|
|
112
|
-
);
|
|
118
|
+
info(`Running ${files.length} examples tests (${IN_GIT ? 'git worktree mode' : 'npm-installed mode'})`);
|
|
113
119
|
console.log(`${C.dim}${getEyelingVersion(nodePath, eyelingJsPath, root)}; node ${process.version}${C.n}`);
|
|
114
120
|
|
|
115
121
|
if (files.length === 0) {
|
|
@@ -138,7 +144,7 @@ function main() {
|
|
|
138
144
|
n3Text = fs.readFileSync(filePath, 'utf8');
|
|
139
145
|
} catch (e) {
|
|
140
146
|
const ms = Date.now() - start;
|
|
141
|
-
fail(`${idx} ${file}
|
|
147
|
+
fail(`${idx} ${file} ${msTag(ms)}`);
|
|
142
148
|
fail(`Cannot read input: ${e.message}`);
|
|
143
149
|
failed++;
|
|
144
150
|
continue;
|
|
@@ -154,7 +160,7 @@ function main() {
|
|
|
154
160
|
// npm-installed / no .git: never modify output/ in node_modules
|
|
155
161
|
if (!fs.existsSync(expectedPath)) {
|
|
156
162
|
const ms = Date.now() - start;
|
|
157
|
-
fail(`${idx} ${file}
|
|
163
|
+
fail(`${idx} ${file} ${msTag(ms)}`);
|
|
158
164
|
fail(`Missing expected output/${file}`);
|
|
159
165
|
failed++;
|
|
160
166
|
continue;
|
|
@@ -170,12 +176,12 @@ function main() {
|
|
|
170
176
|
cwd: examplesDir,
|
|
171
177
|
stdio: ['ignore', outFd, 'pipe'], // stdout -> file, stderr captured
|
|
172
178
|
maxBuffer: 200 * 1024 * 1024,
|
|
173
|
-
encoding: 'utf8'
|
|
179
|
+
encoding: 'utf8',
|
|
174
180
|
});
|
|
175
181
|
|
|
176
182
|
fs.closeSync(outFd);
|
|
177
183
|
|
|
178
|
-
const rc =
|
|
184
|
+
const rc = r.status == null ? 1 : r.status;
|
|
179
185
|
|
|
180
186
|
const ms = Date.now() - start;
|
|
181
187
|
|
|
@@ -183,28 +189,28 @@ function main() {
|
|
|
183
189
|
let diffOk = false;
|
|
184
190
|
if (IN_GIT) {
|
|
185
191
|
const d = run('git', ['diff', '--quiet', '--', relExpectedPosix], { cwd: examplesDir });
|
|
186
|
-
diffOk =
|
|
192
|
+
diffOk = d.status === 0;
|
|
187
193
|
} else {
|
|
188
194
|
if (hasGit()) {
|
|
189
195
|
const d = run('git', ['diff', '--no-index', '--quiet', expectedPath, generatedPath], { cwd: examplesDir });
|
|
190
|
-
diffOk =
|
|
196
|
+
diffOk = d.status === 0;
|
|
191
197
|
} else {
|
|
192
198
|
const d = run('diff', ['-u', expectedPath, generatedPath], { cwd: examplesDir });
|
|
193
|
-
diffOk =
|
|
199
|
+
diffOk = d.status === 0;
|
|
194
200
|
}
|
|
195
201
|
}
|
|
196
202
|
|
|
197
|
-
const rcOk =
|
|
203
|
+
const rcOk = rc === expectedRc;
|
|
198
204
|
|
|
199
205
|
if (diffOk && rcOk) {
|
|
200
206
|
if (expectedRc === 0) {
|
|
201
|
-
ok(`${idx} ${file}
|
|
207
|
+
ok(`${idx} ${file} ${msTag(ms)}`);
|
|
202
208
|
} else {
|
|
203
|
-
ok(`${idx} ${file} (expected exit ${expectedRc}
|
|
209
|
+
ok(`${idx} ${file} (expected exit ${expectedRc}) ${msTag(ms)}`);
|
|
204
210
|
}
|
|
205
211
|
passed++;
|
|
206
212
|
} else {
|
|
207
|
-
fail(`${idx} ${file}
|
|
213
|
+
fail(`${idx} ${file} ${msTag(ms)}`);
|
|
208
214
|
if (!rcOk) {
|
|
209
215
|
fail(`Exit code ${rc}, expected ${expectedRc}`);
|
|
210
216
|
}
|
|
@@ -242,4 +248,3 @@ function main() {
|
|
|
242
248
|
}
|
|
243
249
|
|
|
244
250
|
main();
|
|
245
|
-
|
package/test/package.test.js
CHANGED
|
@@ -7,19 +7,29 @@ const path = require('node:path');
|
|
|
7
7
|
const cp = require('node:child_process');
|
|
8
8
|
|
|
9
9
|
const TTY = process.stdout.isTTY;
|
|
10
|
-
const C = TTY
|
|
11
|
-
? { g: '\x1b[32m', r: '\x1b[31m', y: '\x1b[33m', dim: '\x1b[2m', n: '\x1b[0m' }
|
|
12
|
-
: { g: '', r: '', y: '', dim: '', n: '' };
|
|
10
|
+
const C = TTY ? { g: '\x1b[32m', r: '\x1b[31m', y: '\x1b[33m', dim: '\x1b[2m', n: '\x1b[0m' } : { g: '', r: '', y: '', dim: '', n: '' };
|
|
13
11
|
|
|
14
|
-
function info(msg) {
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
function info(msg) {
|
|
13
|
+
console.log(`${C.y}==${C.n} ${msg}`);
|
|
14
|
+
}
|
|
15
|
+
function ok(msg) {
|
|
16
|
+
console.log(`${C.g}OK${C.n} ${msg}`);
|
|
17
|
+
}
|
|
18
|
+
function fail(msg) {
|
|
19
|
+
console.error(`${C.r}FAIL${C.n} ${msg}`);
|
|
20
|
+
}
|
|
17
21
|
|
|
18
|
-
function isWin() {
|
|
19
|
-
|
|
22
|
+
function isWin() {
|
|
23
|
+
return process.platform === 'win32';
|
|
24
|
+
}
|
|
25
|
+
function npmCmd() {
|
|
26
|
+
return isWin() ? 'npm.cmd' : 'npm';
|
|
27
|
+
}
|
|
20
28
|
|
|
21
29
|
function rmrf(p) {
|
|
22
|
-
try {
|
|
30
|
+
try {
|
|
31
|
+
fs.rmSync(p, { recursive: true, force: true });
|
|
32
|
+
} catch {}
|
|
23
33
|
}
|
|
24
34
|
|
|
25
35
|
function run(cmd, args, opts = {}) {
|
|
@@ -49,7 +59,10 @@ function runChecked(cmd, args, opts = {}) {
|
|
|
49
59
|
function packTarball(root) {
|
|
50
60
|
// `npm pack --silent` prints the filename (usually one line)
|
|
51
61
|
const res = runChecked(npmCmd(), ['pack', '--silent'], { cwd: root });
|
|
52
|
-
const out = String(res.stdout || '')
|
|
62
|
+
const out = String(res.stdout || '')
|
|
63
|
+
.trim()
|
|
64
|
+
.split(/\r?\n/)
|
|
65
|
+
.filter(Boolean);
|
|
53
66
|
if (out.length === 0) throw new Error('npm pack produced no output');
|
|
54
67
|
return out[out.length - 1].trim(); // tarball filename in root
|
|
55
68
|
}
|
|
@@ -97,9 +110,7 @@ function main() {
|
|
|
97
110
|
ok('API works');
|
|
98
111
|
|
|
99
112
|
info('CLI smoke test');
|
|
100
|
-
const bin = isWin()
|
|
101
|
-
? path.join(tmp, 'node_modules', '.bin', 'eyeling.cmd')
|
|
102
|
-
: path.join(tmp, 'node_modules', '.bin', 'eyeling');
|
|
113
|
+
const bin = isWin() ? path.join(tmp, 'node_modules', '.bin', 'eyeling.cmd') : path.join(tmp, 'node_modules', '.bin', 'eyeling');
|
|
103
114
|
runChecked(bin, ['-v'], { cwd: tmp, stdio: 'inherit' });
|
|
104
115
|
ok('CLI works');
|
|
105
116
|
|
|
@@ -121,7 +132,9 @@ function main() {
|
|
|
121
132
|
if (tgzInRoot) {
|
|
122
133
|
const maybe = path.join(root, tgzInRoot);
|
|
123
134
|
if (fs.existsSync(maybe)) {
|
|
124
|
-
try {
|
|
135
|
+
try {
|
|
136
|
+
fs.unlinkSync(maybe);
|
|
137
|
+
} catch {}
|
|
125
138
|
}
|
|
126
139
|
}
|
|
127
140
|
cleanup();
|
|
@@ -129,4 +142,3 @@ function main() {
|
|
|
129
142
|
}
|
|
130
143
|
|
|
131
144
|
main();
|
|
132
|
-
|
package/test/packlist.test.js
CHANGED
|
@@ -5,13 +5,17 @@ const cp = require('node:child_process');
|
|
|
5
5
|
const fs = require('node:fs');
|
|
6
6
|
|
|
7
7
|
const TTY = process.stdout.isTTY;
|
|
8
|
-
const C = TTY
|
|
9
|
-
? { g: '\x1b[32m', r: '\x1b[31m', y: '\x1b[33m', n: '\x1b[0m' }
|
|
10
|
-
: { g: '', r: '', y: '', n: '' };
|
|
8
|
+
const C = TTY ? { g: '\x1b[32m', r: '\x1b[31m', y: '\x1b[33m', n: '\x1b[0m' } : { g: '', r: '', y: '', n: '' };
|
|
11
9
|
|
|
12
|
-
function ok(msg) {
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
function ok(msg) {
|
|
11
|
+
console.log(`${C.g}OK${C.n} ${msg}`);
|
|
12
|
+
}
|
|
13
|
+
function info(msg) {
|
|
14
|
+
console.log(`${C.y}${msg}${C.n}`);
|
|
15
|
+
}
|
|
16
|
+
function fail(msg) {
|
|
17
|
+
console.error(`${C.r}FAIL${C.n} ${msg}`);
|
|
18
|
+
}
|
|
15
19
|
|
|
16
20
|
try {
|
|
17
21
|
info('Checking packlist + metadata…');
|
|
@@ -37,21 +41,15 @@ try {
|
|
|
37
41
|
}
|
|
38
42
|
|
|
39
43
|
const pack = JSON.parse(packJson)[0];
|
|
40
|
-
const paths = new Set(pack.files.map(f => f.path));
|
|
44
|
+
const paths = new Set(pack.files.map((f) => f.path));
|
|
41
45
|
|
|
42
|
-
const mustHave = [
|
|
43
|
-
'package.json',
|
|
44
|
-
'README.md',
|
|
45
|
-
'LICENSE.md',
|
|
46
|
-
'eyeling.js',
|
|
47
|
-
'index.js',
|
|
48
|
-
];
|
|
46
|
+
const mustHave = ['package.json', 'README.md', 'LICENSE.md', 'eyeling.js', 'index.js'];
|
|
49
47
|
|
|
50
48
|
for (const p of mustHave) assert.ok(paths.has(p), `missing from npm pack: ${p}`);
|
|
51
49
|
|
|
52
50
|
assert.ok(
|
|
53
|
-
[...paths].some(p => p.startsWith('examples/output/')),
|
|
54
|
-
'missing from npm pack: examples/output/*'
|
|
51
|
+
[...paths].some((p) => p.startsWith('examples/output/')),
|
|
52
|
+
'missing from npm pack: examples/output/*',
|
|
55
53
|
);
|
|
56
54
|
|
|
57
55
|
ok('packlist + metadata sanity checks passed');
|
|
@@ -59,4 +57,3 @@ try {
|
|
|
59
57
|
fail(e && e.stack ? e.stack : String(e));
|
|
60
58
|
process.exit(1);
|
|
61
59
|
}
|
|
62
|
-
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|