eyeling 1.28.9 → 1.29.0

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.
@@ -0,0 +1,138 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const fs = require('node:fs');
5
+ const os = require('node:os');
6
+ const path = require('node:path');
7
+
8
+ const { pass, failResult, info } = require('./report');
9
+ const { Iri, Triple } = require('../lib/prelude');
10
+ const { createFactStore } = require('../lib/store');
11
+ const { runAsync } = require('../index.js');
12
+
13
+ const EX = 'http://example.org/';
14
+ const a = new Iri(EX + 'a');
15
+ const p = new Iri(EX + 'p');
16
+ const q = new Iri(EX + 'q');
17
+ const b = new Iri(EX + 'b');
18
+ const c = new Iri(EX + 'c');
19
+ const x = new Iri(EX + 'x');
20
+ const y = new Iri(EX + 'y');
21
+ const r = new Iri(EX + 'r');
22
+ const z = new Iri(EX + 'z');
23
+
24
+ const triples = [
25
+ new Triple(a, p, b),
26
+ new Triple(a, p, c),
27
+ new Triple(a, q, b),
28
+ new Triple(x, p, b),
29
+ new Triple(y, r, z),
30
+ ];
31
+
32
+ async function collect(iterable) {
33
+ const out = [];
34
+ for await (const item of iterable) out.push(item);
35
+ return out;
36
+ }
37
+
38
+ async function withStore(factory, fn) {
39
+ const store = await factory();
40
+ try {
41
+ await store.batchAdd(triples, 'explicit');
42
+ await fn(store);
43
+ } finally {
44
+ if (store && typeof store.close === 'function') await store.close();
45
+ }
46
+ }
47
+
48
+ async function expectCount(store, label, args, expected) {
49
+ const out = await collect(store.match(...args));
50
+ if (out.length !== expected) {
51
+ throw new Error(`${label}: expected ${expected} match(es), got ${out.length}`);
52
+ }
53
+ }
54
+
55
+ const tests = [
56
+ {
57
+ name: 'memory store supports all eight triple match shapes',
58
+ fn: async () => withStore(() => createFactStore({ type: 'memory' }), async (store) => {
59
+ await expectCount(store, '(s,p,o)', [a, p, b], 1);
60
+ await expectCount(store, '(s,p,?)', [a, p, null], 2);
61
+ await expectCount(store, '(s,?,o)', [a, null, b], 2);
62
+ await expectCount(store, '(s,?,?)', [a, null, null], 3);
63
+ await expectCount(store, '(?,p,o)', [null, p, b], 2);
64
+ await expectCount(store, '(?,p,?)', [null, p, null], 3);
65
+ await expectCount(store, '(?,?,o)', [null, null, b], 3);
66
+ await expectCount(store, '(?,?,?)', [null, null, null], 5);
67
+ }),
68
+ },
69
+ {
70
+ name: 'persistent store supports all eight triple match shapes and duplicate prevention',
71
+ fn: async () => {
72
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'eyeling-store-test-'));
73
+ try {
74
+ await withStore(() => createFactStore({ name: 'patterns', path: dir, clear: true }), async (store) => {
75
+ await expectCount(store, '(s,p,o)', [a, p, b], 1);
76
+ await expectCount(store, '(s,p,?)', [a, p, null], 2);
77
+ await expectCount(store, '(s,?,o)', [a, null, b], 2);
78
+ await expectCount(store, '(s,?,?)', [a, null, null], 3);
79
+ await expectCount(store, '(?,p,o)', [null, p, b], 2);
80
+ await expectCount(store, '(?,p,?)', [null, p, null], 3);
81
+ await expectCount(store, '(?,?,o)', [null, null, b], 3);
82
+ await expectCount(store, '(?,?,?)', [null, null, null], 5);
83
+ const added = await store.add(new Triple(a, p, b), 'inferred');
84
+ if (added) throw new Error('duplicate insertion should return false');
85
+ if (typeof store.kindOf === 'function') {
86
+ const mask = await store.kindOf(new Triple(a, p, b));
87
+ if ((mask & 1) === 0 || (mask & 2) === 0) throw new Error('explicit/inferred bitmask should be preserved');
88
+ }
89
+ });
90
+ } finally {
91
+ fs.rmSync(dir, { recursive: true, force: true });
92
+ }
93
+ },
94
+ },
95
+ {
96
+ name: 'runAsync reuses a named persistent store across runs',
97
+ fn: async () => {
98
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'eyeling-runasync-store-'));
99
+ try {
100
+ const first = await runAsync('@prefix : <http://example.org/> .\n:a :p :b .', { store: { name: 'dataset', path: dir, clear: true } });
101
+ if (first.store) await first.store.close();
102
+
103
+ const second = await runAsync('@prefix : <http://example.org/> .\n{ ?s :p ?o } => { ?s :q ?o } .', { store: { name: 'dataset', path: dir } });
104
+ try {
105
+ const text = second.closureN3 || '';
106
+ if (!text.includes(':a :q :b .') && !text.includes(':a :q :b.')) throw new Error(`expected stored fact to feed rule, got:\n${text}`);
107
+ if (!second.store) throw new Error('runAsync should return the opened store');
108
+ const qMatches = await collect(second.store.match(a, q, b));
109
+ if (qMatches.length !== 1) throw new Error('expected inferred fact to be persisted');
110
+ } finally {
111
+ if (second.store) await second.store.close();
112
+ }
113
+ } finally {
114
+ fs.rmSync(dir, { recursive: true, force: true });
115
+ }
116
+ },
117
+ },
118
+ ];
119
+
120
+ (async function main() {
121
+ const startAll = Date.now();
122
+ let passed = 0;
123
+ for (let i = 0; i < tests.length; i += 1) {
124
+ const n = i + 1;
125
+ const t0 = Date.now();
126
+ try {
127
+ await tests[i].fn();
128
+ pass(n, tests[i].name, Date.now() - t0);
129
+ passed += 1;
130
+ } catch (e) {
131
+ failResult(n, tests[i].name, Date.now() - t0);
132
+ console.error(e && e.stack ? e.stack : e);
133
+ process.exitCode = 1;
134
+ break;
135
+ }
136
+ }
137
+ info(`Store tests: ${passed}/${tests.length} passed`, Date.now() - startAll);
138
+ })();
package/tools/bundle.js CHANGED
@@ -240,6 +240,10 @@ function getBrowserApi() {
240
240
 
241
241
  export const INFERENCE_FUSE_EXIT_CODE = 65;
242
242
 
243
+ export function runAsync(input, opts) {
244
+ return getBrowserApi().runAsync(input, opts);
245
+ }
246
+
243
247
  export function reasonStream(input, opts) {
244
248
  return getBrowserApi().reasonStream(input, opts);
245
249
  }
@@ -248,6 +252,10 @@ export function reasonRdfJs(input, opts) {
248
252
  return getBrowserApi().reasonRdfJs(input, opts);
249
253
  }
250
254
 
255
+ export function createFactStore(options) {
256
+ return getBrowserApi().createFactStore(options);
257
+ }
258
+
251
259
  export function registerBuiltin(iri, handler) {
252
260
  return getBrowserApi().registerBuiltin(iri, handler);
253
261
  }
@@ -295,9 +303,11 @@ const eyeling = {
295
303
  return getBrowserApi().version;
296
304
  },
297
305
  INFERENCE_FUSE_EXIT_CODE,
306
+ runAsync,
298
307
  reasonStream,
299
308
  reasonRdfJs,
300
309
  rdfjs,
310
+ createFactStore,
301
311
  registerBuiltin,
302
312
  unregisterBuiltin,
303
313
  registerBuiltinModule,