eyeling 1.27.7 → 1.27.8
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/README.md +1 -0
- package/package.json +9 -9
- package/test/rdf12.test.js +337 -0
package/README.md
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# eyeling
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/eyeling)
|
|
3
4
|
[](https://doi.org/10.5281/zenodo.19068086)
|
|
4
5
|
|
|
5
6
|
A compact [Notation3 (N3)](https://notation3.org/) reasoner in **JavaScript**.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eyeling",
|
|
3
|
-
"version": "1.27.
|
|
3
|
+
"version": "1.27.8",
|
|
4
4
|
"description": "A minimal Notation3 (N3) reasoner in JavaScript.",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"keywords": [
|
|
@@ -43,20 +43,20 @@
|
|
|
43
43
|
"test:builtins": "node test/builtins.test.js",
|
|
44
44
|
"test:examples": "node test/examples.test.js",
|
|
45
45
|
"test:examples:proof": "node test/examples.test.js --proof-only",
|
|
46
|
+
"test:stream-messages": "node test/stream_messages.test.js",
|
|
46
47
|
"test:manifest": "node test/manifest.test.js",
|
|
48
|
+
"test:rdf12": "node test/rdf12.test.js",
|
|
49
|
+
"test:rdf12:ntriples": "node test/rdf12.test.js ntriples",
|
|
50
|
+
"test:rdf12:nquads": "node test/rdf12.test.js nquads",
|
|
51
|
+
"test:rdf12:turtle": "node test/rdf12.test.js turtle",
|
|
52
|
+
"test:rdf12:trig": "node test/rdf12.test.js trig",
|
|
47
53
|
"test:playground": "node test/playground.test.js",
|
|
48
54
|
"test:package": "node test/package.test.js",
|
|
49
55
|
"pretest": "npm run build && npm run test:packlist",
|
|
50
|
-
"test": "npm run test:api && npm run test:builtins && npm run test:examples && npm run test:examples:proof && npm run test:manifest && npm run rdf12 && npm run test:playground",
|
|
56
|
+
"test": "npm run test:api && npm run test:builtins && npm run test:examples && npm run test:examples:proof && npm run test:manifest && npm run test:rdf12 && npm run test:playground",
|
|
51
57
|
"posttest": "npm run test:package",
|
|
52
58
|
"preversion": "npm test",
|
|
53
|
-
"postversion": "git push origin HEAD --follow-tags"
|
|
54
|
-
"test:stream-messages": "node test/stream_messages.test.js",
|
|
55
|
-
"rdf12": "npm run rdf-12-turtle && npm run rdf-12-ntriples && npm run rdf-12-nquads && npm run rdf-12-trig",
|
|
56
|
-
"rdf-12-ntriples": "rdf-test-suite spec/rdf12-parser.js https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-n-triples/syntax/manifest.ttl -i '{ \"format\": \"n-triples\" }' -c .rdf-test-suite-cache/",
|
|
57
|
-
"rdf-12-nquads": "rdf-test-suite spec/rdf12-parser.js https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-n-quads/syntax/manifest.ttl -i '{ \"format\": \"n-quads\" }' -c .rdf-test-suite-cache/",
|
|
58
|
-
"rdf-12-turtle": "rdf-test-suite spec/rdf12-parser.js https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-turtle/syntax/manifest.ttl -i '{ \"format\": \"turtle\" }' -c .rdf-test-suite-cache/",
|
|
59
|
-
"rdf-12-trig": "rdf-test-suite spec/rdf12-parser.js https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-trig/syntax/manifest.ttl -i '{ \"format\": \"trig\" }' -c .rdf-test-suite-cache/"
|
|
59
|
+
"postversion": "git push origin HEAD --follow-tags"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
62
|
"rdf-test-suite": "^2.1.4"
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const cp = require('node:child_process');
|
|
5
|
+
|
|
6
|
+
const USE_COLOR = !process.env.NO_COLOR && (
|
|
7
|
+
process.stdout.isTTY ||
|
|
8
|
+
(process.env.FORCE_COLOR && process.env.FORCE_COLOR !== '0')
|
|
9
|
+
);
|
|
10
|
+
const C = USE_COLOR
|
|
11
|
+
? { g: '\x1b[32m', r: '\x1b[31m', y: '\x1b[33m', gray: '\x1b[90m', dim: '\x1b[2m', n: '\x1b[0m' }
|
|
12
|
+
: { g: '', r: '', y: '', gray: '', dim: '', n: '' };
|
|
13
|
+
|
|
14
|
+
function formatDuration(ms) {
|
|
15
|
+
if (!Number.isFinite(ms) || ms < 0) return '0 ms';
|
|
16
|
+
if (ms < 1000) return `${Math.round(ms)} ms`;
|
|
17
|
+
if (ms < 10000) return `${(ms / 1000).toFixed(2)} s`;
|
|
18
|
+
if (ms < 60000) return `${(ms / 1000).toFixed(1)} s`;
|
|
19
|
+
|
|
20
|
+
const minutes = Math.floor(ms / 60000);
|
|
21
|
+
const seconds = ((ms % 60000) / 1000).toFixed(1).padStart(4, '0');
|
|
22
|
+
return `${minutes}m ${seconds}s`;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function durationSuffix(ms) {
|
|
26
|
+
return ms == null ? '' : ` ${C.gray}${formatDuration(ms)}${C.n}`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function ok(msg, ms) {
|
|
30
|
+
console.log(`${C.g}OK${C.n} ${msg}${durationSuffix(ms)}`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function fail(msg, ms) {
|
|
34
|
+
console.error(`${C.r}FAIL${C.n} ${msg}${durationSuffix(ms)}`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function info(msg, ms) {
|
|
38
|
+
console.log(`${C.y}==${C.n} ${msg}${durationSuffix(ms)}`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function detail(msg) {
|
|
42
|
+
console.log(`${C.dim}${msg}${C.n}`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function nowMs() {
|
|
46
|
+
return Number(process.hrtime.bigint()) / 1e6;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const RDF_TEST_SUITE = process.platform === 'win32' ? 'rdf-test-suite.cmd' : 'rdf-test-suite';
|
|
50
|
+
const CACHE_DIR = '.rdf-test-suite-cache/';
|
|
51
|
+
|
|
52
|
+
const SUITES = {
|
|
53
|
+
turtle: {
|
|
54
|
+
label: 'RDF 1.2 Turtle',
|
|
55
|
+
format: 'turtle',
|
|
56
|
+
manifest: 'https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-turtle/syntax/manifest.ttl',
|
|
57
|
+
},
|
|
58
|
+
ntriples: {
|
|
59
|
+
label: 'RDF 1.2 N-Triples',
|
|
60
|
+
format: 'n-triples',
|
|
61
|
+
manifest: 'https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-n-triples/syntax/manifest.ttl',
|
|
62
|
+
},
|
|
63
|
+
nquads: {
|
|
64
|
+
label: 'RDF 1.2 N-Quads',
|
|
65
|
+
format: 'n-quads',
|
|
66
|
+
manifest: 'https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-n-quads/syntax/manifest.ttl',
|
|
67
|
+
},
|
|
68
|
+
trig: {
|
|
69
|
+
label: 'RDF 1.2 TriG',
|
|
70
|
+
format: 'trig',
|
|
71
|
+
manifest: 'https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-trig/syntax/manifest.ttl',
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const ALIASES = new Map([
|
|
76
|
+
['all', Object.keys(SUITES)],
|
|
77
|
+
['rdf12', Object.keys(SUITES)],
|
|
78
|
+
['rdf-12-turtle', ['turtle']],
|
|
79
|
+
['rdf-12-ntriples', ['ntriples']],
|
|
80
|
+
['rdf-12-n-triples', ['ntriples']],
|
|
81
|
+
['rdf-12-nquads', ['nquads']],
|
|
82
|
+
['rdf-12-n-quads', ['nquads']],
|
|
83
|
+
['rdf-12-trig', ['trig']],
|
|
84
|
+
['turtle', ['turtle']],
|
|
85
|
+
['ntriples', ['ntriples']],
|
|
86
|
+
['n-triples', ['ntriples']],
|
|
87
|
+
['nquads', ['nquads']],
|
|
88
|
+
['n-quads', ['nquads']],
|
|
89
|
+
['trig', ['trig']],
|
|
90
|
+
]);
|
|
91
|
+
|
|
92
|
+
function stripAnsi(text) {
|
|
93
|
+
return String(text).replace(/\x1b\[[0-9;]*m/g, '');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function normalizeLine(line) {
|
|
97
|
+
return stripAnsi(line).replace(/\r/g, '').trim();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function classifyLine(line) {
|
|
101
|
+
const text = normalizeLine(line);
|
|
102
|
+
if (!text) return null;
|
|
103
|
+
|
|
104
|
+
const pass = text.match(/^(?:✔|✓|√)\s*(.*)$/u);
|
|
105
|
+
if (pass) return { kind: 'ok', message: pass[1].trim() || 'passed' };
|
|
106
|
+
|
|
107
|
+
const failure = text.match(/^(?:✘|✖|✗|×)\s*(.*)$/u);
|
|
108
|
+
if (failure) return { kind: 'fail', message: failure[1].trim() || 'failed' };
|
|
109
|
+
|
|
110
|
+
const tapFail = text.match(/^not ok\b\s*(.*)$/i);
|
|
111
|
+
if (tapFail) return { kind: 'fail', message: tapFail[1].trim() || text };
|
|
112
|
+
|
|
113
|
+
const tapOk = text.match(/^ok\b\s*(.*)$/i);
|
|
114
|
+
if (tapOk) return { kind: 'ok', message: tapOk[1].trim() || text };
|
|
115
|
+
|
|
116
|
+
return { kind: 'info', message: text };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function rdfTestSuiteArgs(suite) {
|
|
120
|
+
return [
|
|
121
|
+
'spec/rdf12-parser.js',
|
|
122
|
+
suite.manifest,
|
|
123
|
+
'-i',
|
|
124
|
+
JSON.stringify({ format: suite.format }),
|
|
125
|
+
'-c',
|
|
126
|
+
CACHE_DIR,
|
|
127
|
+
];
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function resolveSuiteKeys(args) {
|
|
131
|
+
if (args.length === 0) return Object.keys(SUITES);
|
|
132
|
+
|
|
133
|
+
const keys = [];
|
|
134
|
+
for (const arg of args) {
|
|
135
|
+
const expanded = ALIASES.get(arg);
|
|
136
|
+
if (!expanded) {
|
|
137
|
+
throw new Error(`Unknown RDF 1.2 suite: ${arg}. Use one of: ${Array.from(ALIASES.keys()).sort().join(', ')}`);
|
|
138
|
+
}
|
|
139
|
+
for (const key of expanded) {
|
|
140
|
+
if (!keys.includes(key)) keys.push(key);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return keys;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function sequenceLabel(n) {
|
|
147
|
+
return String(n).padStart(3, '0');
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function createLineReader(onLine) {
|
|
151
|
+
let buffer = '';
|
|
152
|
+
|
|
153
|
+
return {
|
|
154
|
+
push(chunk) {
|
|
155
|
+
buffer += String(chunk);
|
|
156
|
+
const lines = buffer.split(/\r?\n/);
|
|
157
|
+
buffer = lines.pop() || '';
|
|
158
|
+
for (const line of lines) onLine(line);
|
|
159
|
+
},
|
|
160
|
+
flush() {
|
|
161
|
+
if (buffer) {
|
|
162
|
+
onLine(buffer);
|
|
163
|
+
buffer = '';
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function printEvent(suiteResult, event, totals) {
|
|
170
|
+
if (event.kind === 'info') {
|
|
171
|
+
detail(` ${event.message}`);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
totals.sequence++;
|
|
176
|
+
const now = nowMs();
|
|
177
|
+
const caseElapsedMs = now - suiteResult.lastCaseAt;
|
|
178
|
+
suiteResult.lastCaseAt = now;
|
|
179
|
+
|
|
180
|
+
const message = `${sequenceLabel(totals.sequence)} ${suiteResult.suite.label}: ${event.message}`;
|
|
181
|
+
if (event.kind === 'ok') {
|
|
182
|
+
ok(message, caseElapsedMs);
|
|
183
|
+
totals.passed++;
|
|
184
|
+
} else {
|
|
185
|
+
fail(message, caseElapsedMs);
|
|
186
|
+
totals.failed++;
|
|
187
|
+
suiteResult.failedCount++;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function runSuite(key, totals) {
|
|
192
|
+
return new Promise((resolve) => {
|
|
193
|
+
const suite = SUITES[key];
|
|
194
|
+
const startedAt = nowMs();
|
|
195
|
+
const suiteResult = {
|
|
196
|
+
key,
|
|
197
|
+
suite,
|
|
198
|
+
status: null,
|
|
199
|
+
error: null,
|
|
200
|
+
startedAt,
|
|
201
|
+
lastCaseAt: startedAt,
|
|
202
|
+
caseCount: 0,
|
|
203
|
+
failedCount: 0,
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
info(`${suite.label} syntax suite`);
|
|
207
|
+
|
|
208
|
+
let sawCase = false;
|
|
209
|
+
let settled = false;
|
|
210
|
+
|
|
211
|
+
function handleLine(line) {
|
|
212
|
+
const event = classifyLine(line);
|
|
213
|
+
if (!event) return;
|
|
214
|
+
if (event.kind === 'ok' || event.kind === 'fail') {
|
|
215
|
+
sawCase = true;
|
|
216
|
+
suiteResult.caseCount++;
|
|
217
|
+
}
|
|
218
|
+
printEvent(suiteResult, event, totals);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const stdout = createLineReader(handleLine);
|
|
222
|
+
const stderr = createLineReader(handleLine);
|
|
223
|
+
|
|
224
|
+
let child;
|
|
225
|
+
try {
|
|
226
|
+
child = cp.spawn(RDF_TEST_SUITE, rdfTestSuiteArgs(suite), {
|
|
227
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
228
|
+
env: {
|
|
229
|
+
...process.env,
|
|
230
|
+
FORCE_COLOR: '0',
|
|
231
|
+
NO_COLOR: '1',
|
|
232
|
+
},
|
|
233
|
+
});
|
|
234
|
+
} catch (e) {
|
|
235
|
+
const elapsedMs = nowMs() - startedAt;
|
|
236
|
+
suiteResult.error = e;
|
|
237
|
+
if (!sawCase) {
|
|
238
|
+
totals.sequence++;
|
|
239
|
+
fail(`${sequenceLabel(totals.sequence)} ${suite.label}: rdf-test-suite could not start: ${e.message || String(e)}`, elapsedMs);
|
|
240
|
+
totals.failed++;
|
|
241
|
+
suiteResult.caseCount++;
|
|
242
|
+
}
|
|
243
|
+
console.log(`${C.gray}Suite elapsed ${formatDuration(elapsedMs)}${C.n}`);
|
|
244
|
+
console.log('');
|
|
245
|
+
resolve({ ...suiteResult, status: 1, elapsedMs });
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
child.stdout.on('data', (chunk) => stdout.push(chunk));
|
|
250
|
+
child.stderr.on('data', (chunk) => stderr.push(chunk));
|
|
251
|
+
|
|
252
|
+
child.on('error', (e) => {
|
|
253
|
+
suiteResult.error = e;
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
child.on('close', (code, signal) => {
|
|
257
|
+
if (settled) return;
|
|
258
|
+
settled = true;
|
|
259
|
+
|
|
260
|
+
stdout.flush();
|
|
261
|
+
stderr.flush();
|
|
262
|
+
|
|
263
|
+
suiteResult.status = code == null ? 1 : code;
|
|
264
|
+
const elapsedMs = nowMs() - startedAt;
|
|
265
|
+
suiteResult.elapsedMs = elapsedMs;
|
|
266
|
+
|
|
267
|
+
if (!sawCase) {
|
|
268
|
+
totals.sequence++;
|
|
269
|
+
const startError = suiteResult.error && suiteResult.error.message ? suiteResult.error.message : null;
|
|
270
|
+
const exitText = signal ? `signal ${signal}` : `status ${suiteResult.status}`;
|
|
271
|
+
const message = startError
|
|
272
|
+
? `${suite.label}: rdf-test-suite could not start: ${startError}`
|
|
273
|
+
: `${suite.label}: rdf-test-suite exited with ${suiteResult.status === 0 ? 'success' : exitText}`;
|
|
274
|
+
|
|
275
|
+
if (suiteResult.status === 0) {
|
|
276
|
+
ok(`${sequenceLabel(totals.sequence)} ${message}`, elapsedMs);
|
|
277
|
+
totals.passed++;
|
|
278
|
+
} else {
|
|
279
|
+
fail(`${sequenceLabel(totals.sequence)} ${message}`, elapsedMs);
|
|
280
|
+
totals.failed++;
|
|
281
|
+
}
|
|
282
|
+
suiteResult.caseCount++;
|
|
283
|
+
} else if (suiteResult.status !== 0 && suiteResult.failedCount === 0) {
|
|
284
|
+
totals.sequence++;
|
|
285
|
+
fail(`${sequenceLabel(totals.sequence)} ${suite.label}: rdf-test-suite exited with status ${suiteResult.status}`, elapsedMs);
|
|
286
|
+
totals.failed++;
|
|
287
|
+
suiteResult.caseCount++;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
console.log(`${C.gray}Suite elapsed ${formatDuration(elapsedMs)}${C.n}`);
|
|
291
|
+
console.log('');
|
|
292
|
+
resolve(suiteResult);
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
async function main() {
|
|
298
|
+
let keys;
|
|
299
|
+
try {
|
|
300
|
+
keys = resolveSuiteKeys(process.argv.slice(2));
|
|
301
|
+
} catch (e) {
|
|
302
|
+
fail(e && e.message ? e.message : String(e));
|
|
303
|
+
process.exit(1);
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
const grandStartedAt = nowMs();
|
|
308
|
+
const totals = {
|
|
309
|
+
sequence: 0,
|
|
310
|
+
passed: 0,
|
|
311
|
+
failed: 0,
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
info(`Running ${keys.length} RDF 1.2 syntax suite${keys.length === 1 ? '' : 's'}`);
|
|
315
|
+
const results = [];
|
|
316
|
+
for (const key of keys) {
|
|
317
|
+
// Run suites sequentially so the live output stays readable and sequence numbers remain stable.
|
|
318
|
+
results.push(await runSuite(key, totals));
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
const grandElapsedMs = nowMs() - grandStartedAt;
|
|
322
|
+
info(`Grand total: ${totals.passed} OK, ${totals.failed} FAIL, ${totals.sequence} RDF 1.2 tests`, grandElapsedMs);
|
|
323
|
+
|
|
324
|
+
if (totals.failed === 0 && results.every((suiteResult) => suiteResult.status === 0)) {
|
|
325
|
+
ok(`All RDF 1.2 syntax tests passed (${totals.passed}/${totals.sequence})`);
|
|
326
|
+
process.exit(0);
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
fail(`Some RDF 1.2 syntax tests failed (${totals.passed}/${totals.sequence})`);
|
|
331
|
+
process.exit(1);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
main().catch((e) => {
|
|
335
|
+
fail(e && e.stack ? e.stack : String(e));
|
|
336
|
+
process.exit(1);
|
|
337
|
+
});
|