eyeling 1.10.15 → 1.10.16

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyeling",
3
- "version": "1.10.15",
3
+ "version": "1.10.16",
4
4
  "description": "A minimal Notation3 (N3) reasoner in JavaScript.",
5
5
  "main": "./index.js",
6
6
  "keywords": [
package/test/api.test.js CHANGED
@@ -70,7 +70,7 @@ const C = TTY
70
70
  : { g: '', r: '', y: '', dim: '', n: '' };
71
71
 
72
72
  function ok(msg) {
73
- console.log(`${C.g}OK${C.n} ${msg}`);
73
+ console.log(`${C.g}OK ${C.n} ${msg}`);
74
74
  }
75
75
  function info(msg) {
76
76
  console.log(`${C.y}==${C.n} ${msg}`);
@@ -867,7 +867,7 @@ ex:a p:trig ex:b.
867
867
  },
868
868
  },
869
869
  {
870
- name: 'issue #6: RDF list nodes should not be rewritten; list:* builtins should traverse rdf:first/rest',
870
+ name: '55 issue #6: RDF list nodes should not be rewritten; list:* builtins should traverse rdf:first/rest',
871
871
  opt: {},
872
872
  input: `@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
873
873
  @prefix list: <http://www.w3.org/2000/10/swap/list#> .
@@ -899,7 +899,7 @@ ex:a p:trig ex:b.
899
899
  }
900
900
  ,
901
901
  {
902
- name: 'issue #6: duplicate rdf:first/rest statements should not break list:* builtins',
902
+ name: '56 issue #6: duplicate rdf:first/rest statements should not break list:* builtins',
903
903
  opt: {},
904
904
  input: `@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
905
905
  @prefix list: <http://www.w3.org/2000/10/swap/list#> .
@@ -21,7 +21,7 @@ const C = TTY
21
21
  ? { g: '\x1b[32m', r: '\x1b[31m', y: '\x1b[33m', dim: '\x1b[2m', n: '\x1b[0m' }
22
22
  : { g: '', r: '', y: '', dim: '', n: '' };
23
23
 
24
- function ok(msg) { console.log(`${C.g}OK${C.n} ${msg}`); }
24
+ function ok(msg) { console.log(`${C.g}OK ${C.n} ${msg}`); }
25
25
  function fail(msg) { console.error(`${C.r}FAIL${C.n} ${msg}`); }
26
26
  function info(msg) { console.log(`${C.y}==${C.n} ${msg}`); }
27
27
 
@@ -58,6 +58,50 @@ function runChecked(cmd, args, opts = {}) {
58
58
  return res;
59
59
  }
60
60
 
61
+ function normalizeNewlines(s) {
62
+ return String(s).replace(/\r\n/g, '\n');
63
+ }
64
+
65
+ // Expectation logic (shared with test/examples.test.js):
66
+ // 1) If file contains: # expect-exit: N -> use N
67
+ // 2) Else, if it contains "=> false" -> expect exit 2
68
+ // 3) Else -> expect exit 0
69
+ function expectedExitCode(n3Text) {
70
+ const m = n3Text.match(/^[ \t]*#[: ]*expect-exit:[ \t]*([0-9]+)\b/m);
71
+ if (m) return parseInt(m[1], 10);
72
+ if (/=>\s*false\b/.test(n3Text)) return 2;
73
+ return 0;
74
+ }
75
+
76
+ function hasGit() {
77
+ const r = run('git', ['--version']);
78
+ return r.status === 0;
79
+ }
80
+
81
+ function showDiff(expectedPath, generatedPath) {
82
+ try {
83
+ if (hasGit()) {
84
+ const d = run('git', ['diff', '--no-index', expectedPath, generatedPath]);
85
+ if (d.stdout) process.stdout.write(d.stdout);
86
+ if (d.stderr) process.stderr.write(d.stderr);
87
+ return;
88
+ }
89
+ } catch {}
90
+ try {
91
+ const d = run('diff', ['-u', expectedPath, generatedPath]);
92
+ if (d.stdout) process.stdout.write(d.stdout);
93
+ if (d.stderr) process.stderr.write(d.stderr);
94
+ return;
95
+ } catch {}
96
+ // Last resort: print a small excerpt
97
+ try {
98
+ const exp = fs.readFileSync(expectedPath, 'utf8').split(/\r?\n/).slice(0, 40).join('\n');
99
+ const gen = fs.readFileSync(generatedPath, 'utf8').split(/\r?\n/).slice(0, 40).join('\n');
100
+ console.error('\n--- expected (first 40 lines)\n' + exp);
101
+ console.error('\n--- generated (first 40 lines)\n' + gen);
102
+ } catch {}
103
+ }
104
+
61
105
  function packTarball(root) {
62
106
  // `npm pack --silent` prints the filename (usually one line)
63
107
  const res = runChecked(npmCmd(), ['pack', '--silent'], { cwd: root });
@@ -118,10 +162,74 @@ function main() {
118
162
  runChecked(bin, ['-v'], { cwd: tmp, stdio: 'inherit' });
119
163
  ok('CLI works');
120
164
 
121
- info('Examples test (installed package)');
122
- const examplesRunner = path.join(tmp, 'node_modules', 'eyeling', 'test', 'examples.test.js');
123
- runChecked(process.execPath, [examplesRunner], { cwd: tmp, stdio: 'inherit' });
124
- ok('Installed examples test passed');
165
+
166
+ info('Examples smoke test (installed package)');
167
+ const pkgRoot = path.join(tmp, 'node_modules', 'eyeling');
168
+ const examplesDir = path.join(pkgRoot, 'examples');
169
+ const outputDir = path.join(examplesDir, 'output');
170
+ const eyelingJsPath = path.join(pkgRoot, 'eyeling.js');
171
+
172
+ if (!fs.existsSync(examplesDir)) throw new Error(`Missing examples directory in installed package: ${examplesDir}`);
173
+ if (!fs.existsSync(outputDir)) throw new Error(`Missing examples/output directory in installed package: ${outputDir}`);
174
+ if (!fs.existsSync(eyelingJsPath)) throw new Error(`Missing eyeling.js in installed package: ${eyelingJsPath}`);
175
+
176
+ // Keep this fast: package.test.js is a smoke test. The full matrix is covered by test/examples.test.js in-repo.
177
+ const SMOKE_EXAMPLES = [
178
+ 'age.n3',
179
+ 'basic-monadic.n3',
180
+ 'collection.n3',
181
+ 'family.n3',
182
+ 'backward.n3',
183
+ ];
184
+
185
+ const tmpExamplesOut = fs.mkdtempSync(path.join(os.tmpdir(), 'eyeling-pkg-examples-'));
186
+ let smokeIdx = 1;
187
+ const smokePad2 = (n) => String(n).padStart(2, '0');
188
+ const smokeOk = (n, msg) => console.log(`${C.g}OK${C.n} ${smokePad2(n)} ${msg}`);
189
+ try {
190
+ for (const file of SMOKE_EXAMPLES) {
191
+ const inputPath = path.join(examplesDir, file);
192
+ const expectedPath = path.join(outputDir, file);
193
+
194
+ if (!fs.existsSync(inputPath)) throw new Error(`Missing example in installed package: ${inputPath}`);
195
+ if (!fs.existsSync(expectedPath)) throw new Error(`Missing golden output in installed package: ${expectedPath}`);
196
+
197
+ const n3Text = fs.readFileSync(inputPath, 'utf8');
198
+ const expectedRc = expectedExitCode(n3Text);
199
+
200
+ const r = cp.spawnSync(process.execPath, [eyelingJsPath, '-d', file], {
201
+ cwd: examplesDir,
202
+ stdio: ['ignore', 'pipe', 'pipe'],
203
+ maxBuffer: 200 * 1024 * 1024,
204
+ encoding: 'utf8',
205
+ });
206
+
207
+ const rc = r.status == null ? 1 : r.status;
208
+ if (rc !== expectedRc) {
209
+ const stderr = (r.stderr || '').trim();
210
+ throw new Error(`Example ${file}: exit ${rc}, expected ${expectedRc}${stderr ? `
211
+ ${stderr}` : ''}`);
212
+ }
213
+
214
+ // Normalize newlines so this is stable across platforms.
215
+ const got = normalizeNewlines(r.stdout || '');
216
+ const exp = normalizeNewlines(fs.readFileSync(expectedPath, 'utf8'));
217
+
218
+ if (got !== exp) {
219
+ const genPath = path.join(tmpExamplesOut, file);
220
+ fs.writeFileSync(genPath, got, 'utf8');
221
+ console.error(`
222
+ Output differs for ${file}:`);
223
+ showDiff(expectedPath, genPath);
224
+ throw new Error(`Example ${file}: output differs from golden`);
225
+ }
226
+
227
+ smokeOk(smokeIdx++, `Example smoke: ${file}`);
228
+ }
229
+ } finally {
230
+ rmrf(tmpExamplesOut);
231
+ }
232
+ smokeOk(smokeIdx++, 'Installed examples smoke test passed');
125
233
 
126
234
  const suiteMs = Date.now() - suiteStart;
127
235
  console.log('');
@@ -8,7 +8,7 @@ const TTY = process.stdout.isTTY;
8
8
  const C = TTY ? { g: '\x1b[32m', r: '\x1b[31m', y: '\x1b[33m', n: '\x1b[0m' } : { g: '', r: '', y: '', n: '' };
9
9
 
10
10
  function ok(msg) {
11
- console.log(`${C.g}OK${C.n} ${msg}`);
11
+ console.log(`${C.g}OK ${C.n} ${msg}`);
12
12
  }
13
13
  function info(msg) {
14
14
  console.log(`${C.y}${msg}${C.n}`);
@@ -23,7 +23,7 @@ const C = TTY
23
23
  ? { g: '\x1b[32m', r: '\x1b[31m', y: '\x1b[33m', dim: '\x1b[2m', n: '\x1b[0m' }
24
24
  : { g: '', r: '', y: '', dim: '', n: '' };
25
25
  function ok(msg) {
26
- console.log(`${C.g}OK${C.n} ${msg}`);
26
+ console.log(`${C.g}OK ${C.n} ${msg}`);
27
27
  }
28
28
  function info(msg) {
29
29
  console.log(`${C.y}==${C.n} ${msg}`);