eyeling 1.6.0 → 1.6.1

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
@@ -2438,6 +2438,11 @@ function listAppendSplit(parts, resElems, subst) {
2438
2438
  return out;
2439
2439
  }
2440
2440
 
2441
+ function numEqualTerm(t, n, eps = 1e-9) {
2442
+ const v = parseNum(t);
2443
+ return v !== null && Math.abs(v - n) < eps;
2444
+ }
2445
+
2441
2446
  // ============================================================================
2442
2447
  // Backward proof & builtins mutual recursion — declarations first
2443
2448
  // ============================================================================
@@ -2809,7 +2814,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
2809
2814
  s2[g.o.name] = new Literal(formatNum(cVal));
2810
2815
  return [s2];
2811
2816
  }
2812
- if (g.o instanceof Literal && g.o.value === formatNum(cVal)) {
2817
+ if (numEqualTerm(g.o, cVal)) {
2813
2818
  return [{ ...subst }];
2814
2819
  }
2815
2820
  }
@@ -2874,7 +2879,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
2874
2879
  s2[g.o.name] = new Literal(formatNum(cVal));
2875
2880
  return [s2];
2876
2881
  }
2877
- if (g.o instanceof Literal && g.o.value === formatNum(cVal)) {
2882
+ if (numEqualTerm(g.o, cVal)) {
2878
2883
  return [{ ...subst }];
2879
2884
  }
2880
2885
  }
@@ -2891,7 +2896,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
2891
2896
  s2[g.o.name] = new Literal(formatNum(cVal));
2892
2897
  return [s2];
2893
2898
  }
2894
- if (g.o instanceof Literal && g.o.value === formatNum(cVal)) {
2899
+ if (numEqualTerm(g.o, cVal)) {
2895
2900
  return [{ ...subst }];
2896
2901
  }
2897
2902
  }
@@ -2909,7 +2914,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
2909
2914
  s2[g.o.name] = new Literal(formatNum(cVal));
2910
2915
  return [s2];
2911
2916
  }
2912
- if (g.o instanceof Literal && g.o.value === formatNum(cVal)) {
2917
+ if (numEqualTerm(g.o, cVal)) {
2913
2918
  return [{ ...subst }];
2914
2919
  }
2915
2920
  }
@@ -2928,7 +2933,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
2928
2933
  s2[g.o.name] = new Literal(formatNum(cVal));
2929
2934
  return [s2];
2930
2935
  }
2931
- if (g.o instanceof Literal && g.o.value === formatNum(cVal)) {
2936
+ if (numEqualTerm(g.o, cVal)) {
2932
2937
  return [{ ...subst }];
2933
2938
  }
2934
2939
  }
@@ -2947,7 +2952,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
2947
2952
  s2[g.o.name] = new Literal(formatNum(cVal));
2948
2953
  return [s2];
2949
2954
  }
2950
- if (g.o instanceof Literal && g.o.value === formatNum(cVal)) {
2955
+ if (numEqualTerm(g.o, cVal)) {
2951
2956
  return [{ ...subst }];
2952
2957
  }
2953
2958
  }
@@ -2967,7 +2972,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
2967
2972
  s2[g.o.name] = new Literal(formatNum(cVal));
2968
2973
  return [s2];
2969
2974
  }
2970
- if (g.o instanceof Literal && g.o.value === formatNum(cVal)) {
2975
+ if (numEqualTerm(g.o, cVal)) {
2971
2976
  return [{ ...subst }];
2972
2977
  }
2973
2978
  }
@@ -2987,7 +2992,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
2987
2992
  s2[g.o.name] = new Literal(formatNum(cVal));
2988
2993
  return [s2];
2989
2994
  }
2990
- if (g.o instanceof Literal && g.o.value === formatNum(cVal)) {
2995
+ if (numEqualTerm(g.o, cVal)) {
2991
2996
  return [{ ...subst }];
2992
2997
  }
2993
2998
  }
@@ -3046,7 +3051,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
3046
3051
  s2[g.o.name] = new Literal(formatNum(cVal));
3047
3052
  return [s2];
3048
3053
  }
3049
- if (g.o instanceof Literal && g.o.value === formatNum(cVal)) {
3054
+ if (numEqualTerm(g.o, cVal)) {
3050
3055
  return [{ ...subst }];
3051
3056
  }
3052
3057
  }
@@ -3065,7 +3070,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
3065
3070
  s2[g.o.name] = new Literal(formatNum(cVal));
3066
3071
  return [s2];
3067
3072
  }
3068
- if (g.o instanceof Literal && g.o.value === formatNum(cVal)) {
3073
+ if (numEqualTerm(g.o, cVal)) {
3069
3074
  return [{ ...subst }];
3070
3075
  }
3071
3076
  }
@@ -3084,7 +3089,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
3084
3089
  s2[g.o.name] = new Literal(formatNum(cVal));
3085
3090
  return [s2];
3086
3091
  }
3087
- if (g.o instanceof Literal && g.o.value === formatNum(cVal)) {
3092
+ if (numEqualTerm(g.o, cVal)) {
3088
3093
  return [{ ...subst }];
3089
3094
  }
3090
3095
  }
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
- (typeof opt.proofComments === 'boolean') ? opt.proofComments :
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyeling",
3
- "version": "1.6.0",
3
+ "version": "1.6.1",
4
4
  "description": "A minimal Notation3 (N3) reasoner in JavaScript.",
5
5
  "main": "./index.js",
6
6
  "keywords": [
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
- { name: '44 syntax: "<-" in predicate position swaps subject and object',
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
- { name: '45 syntax: "<-" works inside blank node property lists ([ ... ])',
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
- { name: '46 syntax: N3 resource paths (! / ^) expand to blank-node triples (forward chain)',
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
- { name: '47 syntax: N3 resource paths support reverse steps (^) in the chain',
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
- { name: '48 rdf:first: works on list terms (alias of list:first)',
677
- opt: { proofComments: false }, input: ` { ( ${U('a')} ${U('b')} ${U('c')} ) rdf:first ?x. } => { ${U('s')} ${U('first')} ?x. }.
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
- { name: '49 rdf:rest: works on list terms (alias of list:rest)',
683
- opt: { proofComments: false }, input: ` { ( ${U('a')} ${U('b')} ${U('c')} ) rdf:rest ?r. ?r rdf:first ?y. } => { ${U('s')} ${U('second')} ?y. }.
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
- { name: '50 rdf collection materialization: rdf:first/rdf:rest triples become list terms',
689
- opt: { proofComments: false }, input: ` ${U('s')} ${U('p')} _:l1.
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
-
@@ -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
- ? { 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: '' };
11
+ const msTag = (ms) => `${C.dim}(${ms} ms)${C.n}`;
13
12
 
14
- function ok(msg) { console.log(`${C.g}OK${C.n} ${msg}`); }
15
- function fail(msg) { console.error(`${C.r}FAIL${C.n} ${msg}`); }
16
- function info(msg) { console.log(`${C.y}==${C.n} ${msg}`); }
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 { fs.rmSync(p, { recursive: true, force: true }); } catch {}
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.readdirSync(examplesDir)
107
- .filter(f => f.endsWith('.n3'))
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} (${ms} ms)`);
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} (${ms} ms)`);
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 = (r.status == null) ? 1 : r.status;
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 = (d.status === 0);
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 = (d.status === 0);
196
+ diffOk = d.status === 0;
191
197
  } else {
192
198
  const d = run('diff', ['-u', expectedPath, generatedPath], { cwd: examplesDir });
193
- diffOk = (d.status === 0);
199
+ diffOk = d.status === 0;
194
200
  }
195
201
  }
196
202
 
197
- const rcOk = (rc === expectedRc);
203
+ const rcOk = rc === expectedRc;
198
204
 
199
205
  if (diffOk && rcOk) {
200
206
  if (expectedRc === 0) {
201
- ok(`${idx} ${file} (${ms} ms)`);
207
+ ok(`${idx} ${file} ${msTag(ms)}`);
202
208
  } else {
203
- ok(`${idx} ${file} (expected exit ${expectedRc}, ${ms} ms)`);
209
+ ok(`${idx} ${file} (expected exit ${expectedRc}) ${msTag(ms)}`);
204
210
  }
205
211
  passed++;
206
212
  } else {
207
- fail(`${idx} ${file} (${ms} ms)`);
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
-
@@ -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) { console.log(`${C.y}==${C.n} ${msg}`); }
15
- function ok(msg) { console.log(`${C.g}OK${C.n} ${msg}`); }
16
- function fail(msg) { console.error(`${C.r}FAIL${C.n} ${msg}`); }
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() { return process.platform === 'win32'; }
19
- function npmCmd() { return isWin() ? 'npm.cmd' : 'npm'; }
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 { fs.rmSync(p, { recursive: true, force: true }); } catch {}
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 || '').trim().split(/\r?\n/).filter(Boolean);
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 { fs.unlinkSync(maybe); } catch {}
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
-
@@ -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) { console.log(`${C.g}OK${C.n} ${msg}`); }
13
- function info(msg) { console.log(`${C.y}${msg}${C.n}`); }
14
- function fail(msg) { console.error(`${C.r}FAIL${C.n} ${msg}`); }
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