@factoidal/core 0.7.1 → 0.11.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.
- package/CHANGELOG.md +616 -1
- package/NOTICE +2 -21
- package/README.md +123 -993
- package/api.d.ts +53 -0
- package/api.js +5 -0
- package/api.mjs +56 -0
- package/bin/engine.mjs +38 -19
- package/bin/ext.mjs +16 -20
- package/bin/factoidal.mjs +667 -118
- package/bin/pack.mjs +37 -0
- package/bin/serve-worker.mjs +32 -0
- package/bin/serve.mjs +423 -0
- package/bin/store-worker-host.mjs +1 -1
- package/bin/store.mjs +1 -1
- package/browser.d.ts +114 -507
- package/browser.js +155 -2257
- package/docs/fuseki-replacement.md +108 -0
- package/fn.d.ts +25 -96
- package/fn.js +131 -240
- package/index.d.ts +620 -260
- package/index.js +4 -234
- package/index.mjs +180 -84
- package/l4-assets/l4factoidal.js +47 -7
- package/l4-assets/l4factoidal.mjs +1 -1
- package/l4-assets/l4factoidal.wasm +0 -0
- package/l4-assets/version.json +11 -7
- package/lib/api.mjs +2337 -0
- package/lib/browser-engine.mjs +69 -0
- package/lib/dataset.mjs +471 -0
- package/lib/delta-log-hosts.mjs +191 -0
- package/lib/lean-entry.mjs +213 -0
- package/lib/pure.mjs +98 -0
- package/lib/store.mjs +115 -0
- package/lib/version.mjs +5 -0
- package/lws/README.md +137 -0
- package/lws/persist.mjs +78 -0
- package/lws/server.mjs +416 -0
- package/package.json +59 -61
- package/rdfjs.js +5 -536
- package/rdfjs.mjs +517 -0
- package/sample-store.d.ts +8 -16
- package/sample-store.mjs +39 -29
- package/solid/client/README.md +100 -0
- package/solid/client/index.mjs +293 -0
- package/solid/server/README.md +96 -0
- package/solid/server/index.mjs +395 -0
- package/store-host/deno.mjs +8 -0
- package/store-host/index.mjs +12 -0
- package/store-host/node.mjs +8 -0
- package/xmpp/README.md +107 -0
- package/xmpp/index.mjs +229 -0
- package/browser-wasm.js +0 -872
- package/factoidal-npm-entry.js +0 -15477
- package/factoidal-npm-entry.wasm.assets/code-5a7fc68f2ab1323718b8.wasm +0 -0
- package/factoidal-npm-entry.wasm.js +0 -455
- package/factoidal.js +0 -13118
- package/factoidal.wasm.assets/code-bbe6099bfb5b10c4c3ab.wasm +0 -0
- package/factoidal.wasm.js +0 -457
- package/hacl-init.js +0 -92
- package/hacl-wasm/FStar.wasm +0 -0
- package/hacl-wasm/Hacl_Bignum.wasm +0 -0
- package/hacl-wasm/Hacl_Bignum25519_51.wasm +0 -0
- package/hacl-wasm/Hacl_Bignum_Base.wasm +0 -0
- package/hacl-wasm/Hacl_Curve25519_51.wasm +0 -0
- package/hacl-wasm/Hacl_Ed25519.wasm +0 -0
- package/hacl-wasm/Hacl_Ed25519_PrecompTable.wasm +0 -0
- package/hacl-wasm/Hacl_Hash_Base.wasm +0 -0
- package/hacl-wasm/Hacl_Hash_SHA2.wasm +0 -0
- package/hacl-wasm/Hacl_IntTypes_Intrinsics.wasm +0 -0
- package/hacl-wasm/LowStar_Endianness.wasm +0 -0
- package/hacl-wasm/WasmSupport.wasm +0 -0
- package/hacl-wasm/api.js +0 -775
- package/hacl-wasm/api.json +0 -3787
- package/hacl-wasm/layouts.json +0 -1
- package/hacl-wasm/loader.js +0 -568
- package/hacl-wasm/shell.js +0 -12
- package/l4-core.d.ts +0 -159
- package/l4-core.js +0 -188
- package/l4.d.ts +0 -50
- package/l4.js +0 -104
- package/lib/api.js +0 -2300
- package/lib/engine-js.js +0 -165
- package/lib/engine-wasm.js +0 -300
- package/sample-store/CURRENT +0 -1
- package/sample-store/gen-1/manifest.sbm2 +0 -0
- package/sample-store/gen-1/manifest.tsv +0 -14
- package/sample-store/gen-1/predicate-0.ibk3 +0 -0
- package/sample-store/gen-1/predicate-0.ibk3.merkle +0 -1
- package/sample-store/gen-1/predicate-0.ibk3.oli2 +0 -0
- package/sample-store/gen-1/predicate-0.ibk3.oli2.merkle +0 -1
- package/sample-store/gen-1/predicate-0.ibk3.sri2 +0 -0
- package/sample-store/gen-1/predicate-0.ibk3.sri2.merkle +0 -1
- package/sample-store/gen-1/predicate-0.ibk3.tli1 +0 -0
- package/sample-store/gen-1/predicate-0.ibk3.tli1.merkle +0 -0
- package/sample-store/gen-1/predicate-1.ibk3 +0 -0
- package/sample-store/gen-1/predicate-1.ibk3.merkle +0 -0
- package/sample-store/gen-1/predicate-1.ibk3.oli2 +0 -0
- package/sample-store/gen-1/predicate-1.ibk3.oli2.merkle +0 -0
- package/sample-store/gen-1/predicate-1.ibk3.sri2 +0 -0
- package/sample-store/gen-1/predicate-1.ibk3.sri2.merkle +0 -1
- package/sample-store/gen-1/predicate-1.ibk3.tli1 +0 -0
- package/sample-store/gen-1/predicate-1.ibk3.tli1.merkle +0 -1
- package/sample-store/gen-1/predicate-10.ibk3 +0 -0
- package/sample-store/gen-1/predicate-10.ibk3.merkle +0 -1
- package/sample-store/gen-1/predicate-10.ibk3.oli2 +0 -0
- package/sample-store/gen-1/predicate-10.ibk3.oli2.merkle +0 -0
- package/sample-store/gen-1/predicate-10.ibk3.sri2 +0 -0
- package/sample-store/gen-1/predicate-10.ibk3.sri2.merkle +0 -1
- package/sample-store/gen-1/predicate-10.ibk3.tli1 +0 -0
- package/sample-store/gen-1/predicate-10.ibk3.tli1.merkle +0 -1
- package/sample-store/gen-1/predicate-11.ibk3 +0 -0
- package/sample-store/gen-1/predicate-11.ibk3.merkle +0 -0
- package/sample-store/gen-1/predicate-11.ibk3.oli2 +0 -0
- package/sample-store/gen-1/predicate-11.ibk3.oli2.merkle +0 -1
- package/sample-store/gen-1/predicate-11.ibk3.sri2 +0 -0
- package/sample-store/gen-1/predicate-11.ibk3.sri2.merkle +0 -1
- package/sample-store/gen-1/predicate-11.ibk3.tli1 +0 -0
- package/sample-store/gen-1/predicate-11.ibk3.tli1.merkle +0 -1
- package/sample-store/gen-1/predicate-12.ibk3 +0 -0
- package/sample-store/gen-1/predicate-12.ibk3.merkle +0 -1
- package/sample-store/gen-1/predicate-12.ibk3.oli2 +0 -0
- package/sample-store/gen-1/predicate-12.ibk3.oli2.merkle +0 -1
- package/sample-store/gen-1/predicate-12.ibk3.sri2 +0 -0
- package/sample-store/gen-1/predicate-12.ibk3.sri2.merkle +0 -1
- package/sample-store/gen-1/predicate-12.ibk3.tli1 +0 -0
- package/sample-store/gen-1/predicate-12.ibk3.tli1.merkle +0 -1
- package/sample-store/gen-1/predicate-2.ibk3 +0 -0
- package/sample-store/gen-1/predicate-2.ibk3.merkle +0 -1
- package/sample-store/gen-1/predicate-2.ibk3.oli2 +0 -0
- package/sample-store/gen-1/predicate-2.ibk3.oli2.merkle +0 -1
- package/sample-store/gen-1/predicate-2.ibk3.sri2 +0 -0
- package/sample-store/gen-1/predicate-2.ibk3.sri2.merkle +0 -0
- package/sample-store/gen-1/predicate-2.ibk3.tli1 +0 -0
- package/sample-store/gen-1/predicate-2.ibk3.tli1.merkle +0 -0
- package/sample-store/gen-1/predicate-3.ibk3 +0 -0
- package/sample-store/gen-1/predicate-3.ibk3.merkle +0 -1
- package/sample-store/gen-1/predicate-3.ibk3.oli2 +0 -0
- package/sample-store/gen-1/predicate-3.ibk3.oli2.merkle +0 -1
- package/sample-store/gen-1/predicate-3.ibk3.sri2 +0 -0
- package/sample-store/gen-1/predicate-3.ibk3.sri2.merkle +0 -1
- package/sample-store/gen-1/predicate-3.ibk3.tli1 +0 -0
- package/sample-store/gen-1/predicate-3.ibk3.tli1.merkle +0 -1
- package/sample-store/gen-1/predicate-4.ibk3 +0 -0
- package/sample-store/gen-1/predicate-4.ibk3.merkle +0 -0
- package/sample-store/gen-1/predicate-4.ibk3.oli2 +0 -0
- package/sample-store/gen-1/predicate-4.ibk3.oli2.merkle +0 -1
- package/sample-store/gen-1/predicate-4.ibk3.sri2 +0 -0
- package/sample-store/gen-1/predicate-4.ibk3.sri2.merkle +0 -1
- package/sample-store/gen-1/predicate-4.ibk3.tli1 +0 -0
- package/sample-store/gen-1/predicate-4.ibk3.tli1.merkle +0 -2
- package/sample-store/gen-1/predicate-5.ibk3 +0 -0
- package/sample-store/gen-1/predicate-5.ibk3.merkle +0 -1
- package/sample-store/gen-1/predicate-5.ibk3.oli2 +0 -0
- package/sample-store/gen-1/predicate-5.ibk3.oli2.merkle +0 -1
- package/sample-store/gen-1/predicate-5.ibk3.sri2 +0 -0
- package/sample-store/gen-1/predicate-5.ibk3.sri2.merkle +0 -1
- package/sample-store/gen-1/predicate-5.ibk3.tli1 +0 -0
- package/sample-store/gen-1/predicate-5.ibk3.tli1.merkle +0 -1
- package/sample-store/gen-1/predicate-6.ibk3 +0 -0
- package/sample-store/gen-1/predicate-6.ibk3.merkle +0 -1
- package/sample-store/gen-1/predicate-6.ibk3.oli2 +0 -0
- package/sample-store/gen-1/predicate-6.ibk3.oli2.merkle +0 -1
- package/sample-store/gen-1/predicate-6.ibk3.sri2 +0 -0
- package/sample-store/gen-1/predicate-6.ibk3.sri2.merkle +0 -1
- package/sample-store/gen-1/predicate-6.ibk3.tli1 +0 -0
- package/sample-store/gen-1/predicate-6.ibk3.tli1.merkle +0 -0
- package/sample-store/gen-1/predicate-7.ibk3 +0 -0
- package/sample-store/gen-1/predicate-7.ibk3.merkle +0 -0
- package/sample-store/gen-1/predicate-7.ibk3.oli2 +0 -0
- package/sample-store/gen-1/predicate-7.ibk3.oli2.merkle +0 -2
- package/sample-store/gen-1/predicate-7.ibk3.sri2 +0 -0
- package/sample-store/gen-1/predicate-7.ibk3.sri2.merkle +0 -1
- package/sample-store/gen-1/predicate-7.ibk3.tli1 +0 -0
- package/sample-store/gen-1/predicate-7.ibk3.tli1.merkle +0 -1
- package/sample-store/gen-1/predicate-8.ibk3 +0 -0
- package/sample-store/gen-1/predicate-8.ibk3.merkle +0 -1
- package/sample-store/gen-1/predicate-8.ibk3.oli2 +0 -0
- package/sample-store/gen-1/predicate-8.ibk3.oli2.merkle +0 -1
- package/sample-store/gen-1/predicate-8.ibk3.sri2 +0 -0
- package/sample-store/gen-1/predicate-8.ibk3.sri2.merkle +0 -1
- package/sample-store/gen-1/predicate-8.ibk3.tli1 +0 -0
- package/sample-store/gen-1/predicate-8.ibk3.tli1.merkle +0 -1
- package/sample-store/gen-1/predicate-9.ibk3 +0 -0
- package/sample-store/gen-1/predicate-9.ibk3.merkle +0 -1
- package/sample-store/gen-1/predicate-9.ibk3.oli2 +0 -0
- package/sample-store/gen-1/predicate-9.ibk3.oli2.merkle +0 -1
- package/sample-store/gen-1/predicate-9.ibk3.sri2 +0 -0
- package/sample-store/gen-1/predicate-9.ibk3.sri2.merkle +0 -3
- package/sample-store/gen-1/predicate-9.ibk3.tli1 +0 -0
- package/sample-store/gen-1/predicate-9.ibk3.tli1.merkle +0 -2
- package/select.d.ts +0 -116
- package/select.js +0 -492
- package/version.json +0 -102
- package/wasm.d.ts +0 -130
- package/wasm.js +0 -158
package/fn.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// factoidal/fn — a strictly functional dataset API.
|
|
2
2
|
//
|
|
3
|
-
// Every
|
|
4
|
-
// has no mutation to expose); RDF/JS DatasetCore's add/delete is
|
|
3
|
+
// Every engine operation is a value-to-value function (the Lean
|
|
4
|
+
// library has no mutation to expose); RDF/JS DatasetCore's add/delete is
|
|
5
5
|
// wrapper-side skeuomorphism on top of that. This module makes the JS
|
|
6
6
|
// contract match the verified one: FnDataset is a frozen snapshot, all
|
|
7
7
|
// operations are free functions that return new values, and content
|
|
@@ -25,9 +25,10 @@ const crypto = require('node:crypto');
|
|
|
25
25
|
|
|
26
26
|
const engineApi = require('./index.js');
|
|
27
27
|
const {
|
|
28
|
-
|
|
28
|
+
DatasetCore,
|
|
29
29
|
dataFactory,
|
|
30
|
-
|
|
30
|
+
quadKey,
|
|
31
|
+
termKey,
|
|
31
32
|
quadsToNQuads,
|
|
32
33
|
} = require('./rdfjs.js');
|
|
33
34
|
|
|
@@ -92,10 +93,34 @@ function arrayBackend(quads) {
|
|
|
92
93
|
kind: 'array',
|
|
93
94
|
size: quads.length,
|
|
94
95
|
quads: () => quads,
|
|
96
|
+
engine: null,
|
|
95
97
|
precomputedHash: null,
|
|
96
98
|
};
|
|
97
99
|
}
|
|
98
100
|
|
|
101
|
+
// The engine backend (0.10.0, issue 882 of danbri/factoidal): the quads are
|
|
102
|
+
// an engine Dataset (lib/dataset.mjs) that this module never changes. Every
|
|
103
|
+
// engine operation takes that Dataset itself, so no N-Quads text crosses
|
|
104
|
+
// between steps. The JS quad array is read once, on demand.
|
|
105
|
+
function engineBackend(eds) {
|
|
106
|
+
let quads = null;
|
|
107
|
+
return {
|
|
108
|
+
kind: 'engine',
|
|
109
|
+
size: eds.size,
|
|
110
|
+
quads: () => (quads ||= Object.freeze(eds.toArray())),
|
|
111
|
+
engine: eds,
|
|
112
|
+
precomputedHash: null,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// An FnDataset over an engine Dataset this module made and never shares.
|
|
117
|
+
function wrapEngine(eds) {
|
|
118
|
+
return new FnDataset(engineBackend(eds));
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// ds (array-backed FnDataset) -> engine Dataset, opened once from its quads.
|
|
122
|
+
const ENGINE_CACHE = new WeakMap();
|
|
123
|
+
|
|
99
124
|
// Build a de-duplicated FnDataset from any iterable of RDF/JS quads.
|
|
100
125
|
// Every public constructor path (fromDataset, union, difference,
|
|
101
126
|
// filter, mapQuads, query's CONSTRUCT wrapping, builder().finish())
|
|
@@ -108,7 +133,7 @@ function makeFnDataset(quadsIterable) {
|
|
|
108
133
|
const out = [];
|
|
109
134
|
for (const q of quadsIterable) {
|
|
110
135
|
const frozen = dataFactory.fromQuad(q); // normalizes + (re)freezes
|
|
111
|
-
const key =
|
|
136
|
+
const key = quadKey(frozen); // RDF/JS Term.equals identity, no syntax
|
|
112
137
|
if (seen.has(key)) continue;
|
|
113
138
|
seen.add(key);
|
|
114
139
|
out.push(frozen);
|
|
@@ -147,14 +172,15 @@ class FnDataset {
|
|
|
147
172
|
toNQuads() {
|
|
148
173
|
let cached = NQUADS_CACHE.get(this);
|
|
149
174
|
if (cached === undefined) {
|
|
150
|
-
cached = quadsToNQuads(this.toArray());
|
|
175
|
+
cached = this._backend.engine ? this._backend.engine.toNQuads() : quadsToNQuads(this.toArray());
|
|
151
176
|
NQUADS_CACHE.set(this, cached);
|
|
152
177
|
}
|
|
153
178
|
return cached;
|
|
154
179
|
}
|
|
155
180
|
|
|
156
|
-
/** Read-only quad-pattern match (RDF/JS DatasetCore shape)
|
|
181
|
+
/** Read-only quad-pattern match (RDF/JS DatasetCore shape); the engine's indexes for an engine-backed dataset. */
|
|
157
182
|
match(subject, predicate, object, graph) {
|
|
183
|
+
if (this._backend.engine) return wrapEngine(this._backend.engine.match(subject, predicate, object, graph));
|
|
158
184
|
return makeFnDataset(this.toArray().filter((q) =>
|
|
159
185
|
(!subject || subject.equals(q.subject)) &&
|
|
160
186
|
(!predicate || predicate.equals(q.predicate)) &&
|
|
@@ -170,18 +196,31 @@ const EMPTY = new FnDataset(arrayBackend(Object.freeze([])));
|
|
|
170
196
|
// Interop with the mutable RDF/JS layer.
|
|
171
197
|
// ---------------------------------------------------------------------
|
|
172
198
|
|
|
173
|
-
/** Snapshot a (
|
|
199
|
+
/** Snapshot a Dataset (the engine's, or an RDF/JS DatasetCore) into an FnDataset. */
|
|
174
200
|
function fromDataset(dataset) {
|
|
175
|
-
if (
|
|
176
|
-
|
|
201
|
+
if (dataset instanceof engineApi.Dataset) return wrapEngine(dataset.clone());
|
|
202
|
+
if (!(dataset instanceof DatasetCore)) {
|
|
203
|
+
throw new TypeError('fromDataset: expected a Dataset or an RDF/JS DatasetCore');
|
|
177
204
|
}
|
|
178
205
|
return makeFnDataset(dataset);
|
|
179
206
|
}
|
|
180
207
|
|
|
181
|
-
|
|
208
|
+
// The engine Dataset of an FnDataset: its own, or (for one built from JS
|
|
209
|
+
// quads) one opened from its quads once and kept.
|
|
210
|
+
async function engineOf(ds) {
|
|
211
|
+
if (ds._backend.engine) return ds._backend.engine;
|
|
212
|
+
let eds = ENGINE_CACHE.get(ds);
|
|
213
|
+
if (!eds) {
|
|
214
|
+
eds = await engineApi.fromQuads(ds.toArray());
|
|
215
|
+
ENGINE_CACHE.set(ds, eds);
|
|
216
|
+
}
|
|
217
|
+
return eds;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/** Materialize an FnDataset into a fresh, independently-mutable RDF/JS DatasetCore. */
|
|
182
221
|
function toDataset(ds) {
|
|
183
222
|
assertFnDataset(ds, 'toDataset');
|
|
184
|
-
return new
|
|
223
|
+
return new DatasetCore(ds.toArray());
|
|
185
224
|
}
|
|
186
225
|
|
|
187
226
|
// ---------------------------------------------------------------------
|
|
@@ -247,7 +286,7 @@ async function fromChunks(chunks) {
|
|
|
247
286
|
|
|
248
287
|
/** Parse one RDF document into an FnDataset. Mirrors index.js's parse(). */
|
|
249
288
|
async function parse(text, options) {
|
|
250
|
-
return
|
|
289
|
+
return wrapEngine(await engineApi.parse(text, options));
|
|
251
290
|
}
|
|
252
291
|
|
|
253
292
|
/** Set union, first-seen order (a's quads, then b's not already present). */
|
|
@@ -259,8 +298,8 @@ function union(a, b) {
|
|
|
259
298
|
/** Quads in a that are not in b. */
|
|
260
299
|
function difference(a, b) {
|
|
261
300
|
assertFnDataset(a, 'difference'); assertFnDataset(b, 'difference');
|
|
262
|
-
const bKeys = new Set(b.toArray().map(
|
|
263
|
-
return makeFnDataset(a.toArray().filter((q) => !bKeys.has(
|
|
301
|
+
const bKeys = new Set(b.toArray().map(quadKey));
|
|
302
|
+
return makeFnDataset(a.toArray().filter((q) => !bKeys.has(quadKey(q))));
|
|
264
303
|
}
|
|
265
304
|
|
|
266
305
|
/** Keep quads matching quadPred(quad) => boolean. */
|
|
@@ -291,31 +330,22 @@ function mapQuads(ds, f) {
|
|
|
291
330
|
|
|
292
331
|
/**
|
|
293
332
|
* Run a SPARQL 1.1 query. SELECT -> Bindings[]; ASK -> boolean;
|
|
294
|
-
* CONSTRUCT -> FnDataset. Delegates entirely to index.js's
|
|
295
|
-
*
|
|
296
|
-
* absence throws the existing "pending npm-entry build" Error).
|
|
333
|
+
* CONSTRUCT and DESCRIBE -> FnDataset. Delegates entirely to index.js's
|
|
334
|
+
* query().
|
|
297
335
|
*/
|
|
298
336
|
async function query(ds, sparql, options) {
|
|
299
337
|
assertFnDataset(ds, 'query');
|
|
300
|
-
const result = await engineApi.query(
|
|
301
|
-
return result instanceof Dataset ?
|
|
338
|
+
const result = await engineApi.query((await engineOf(ds)), sparql, options);
|
|
339
|
+
return result instanceof engineApi.Dataset ? wrapEngine(result) : result;
|
|
302
340
|
}
|
|
303
341
|
|
|
304
342
|
/**
|
|
305
343
|
* Materialize an entailment closure as a new FnDataset.
|
|
306
344
|
*
|
|
307
|
-
* Reuses query()'s
|
|
308
|
-
*
|
|
309
|
-
*
|
|
310
|
-
*
|
|
311
|
-
* CONSTRUCT at all, so "CONSTRUCT ... WHERE ... { entail }" is not
|
|
312
|
-
* reachable through the existing API today. Instead this runs
|
|
313
|
-
* `SELECT ?s ?p ?o WHERE { ?s ?p ?o }` with the entailment option
|
|
314
|
-
* (exactly the combination test/api.test.js's "query: entail RDFS
|
|
315
|
-
* infers subclass instances" already exercises) and repackages each
|
|
316
|
-
* solution row as a quad — pure JS reshaping of already-materialized
|
|
317
|
-
* bindings, not new RDF/SPARQL semantics, so it works with the CLI
|
|
318
|
-
* bundle alone (no npm-entry bundle required).
|
|
345
|
+
* Reuses query()'s entailment support: it runs
|
|
346
|
+
* `SELECT ?s ?p ?o WHERE { ?s ?p ?o }` with the entailment option (the
|
|
347
|
+
* engine closes the default graph under the regime, then answers the
|
|
348
|
+
* query; op queryRaw) and repackages each solution row as a quad.
|
|
319
349
|
*
|
|
320
350
|
* Scope limitation (documented, not silent): like a bare
|
|
321
351
|
* `WHERE { ?s ?p ?o }` in SPARQL generally, this closes over the
|
|
@@ -324,71 +354,32 @@ async function query(ds, sparql, options) {
|
|
|
324
354
|
* per-graph closure semantics that the underlying query() does not
|
|
325
355
|
* define today.
|
|
326
356
|
*/
|
|
327
|
-
//
|
|
328
|
-
//
|
|
329
|
-
//
|
|
330
|
-
//
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
const
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
const key = String(regime == null ? 'none' : regime).toLowerCase();
|
|
339
|
-
return ENTAIL_REGIME_ALIASES[key] || regime;
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
// x-ikl-* is NOT IMPLEMENTED. It is not withheld by policy.
|
|
343
|
-
//
|
|
344
|
-
// CORRECTION 2026-08-26: an earlier version of this comment said the
|
|
345
|
-
// family was withheld by owner decision, citing the direction-B ruling
|
|
346
|
-
// of https://github.com/danbri/factoidal/issues/618. That ruling was
|
|
347
|
-
// about the IKL-to-RDF projection, not about this regime family, and
|
|
348
|
-
// attributing it here misstated a decision the owner did not make.
|
|
349
|
-
//
|
|
350
|
-
// The x-ikl-* family is the OWNER'S design
|
|
351
|
-
// (https://github.com/danbri/factoidal/issues/581). Its Lean dispatch
|
|
352
|
-
// was deleted on 2026-08-26 as collateral of the projection purge
|
|
353
|
-
// (https://github.com/danbri/factoidal/issues/626), not as its target.
|
|
354
|
-
// The SEMANTICS survived: Unified/ClBridge.lean's asserted_merge_sound
|
|
355
|
-
// is this regime's soundness statement -- lifting asserted named-graph
|
|
356
|
-
// content into the default graph -- and it carries no naming scheme.
|
|
357
|
-
// Restoring the family is a dispatch branch plus flipping this guard.
|
|
358
|
-
//
|
|
359
|
-
// The owner's own statement of what IKL does not supply, 2026-08-26:
|
|
360
|
-
// no profiles, no entailment procedures, no mapping from RDF datasets.
|
|
361
|
-
// Checked the same day against the IKL GUIDE and Hayes 2009: correct.
|
|
362
|
-
//
|
|
363
|
-
// engineApi.query() (lib/api.js) already rejects this, but
|
|
364
|
-
// normalizeEntailRegime() above passes any unrecognised string through
|
|
365
|
-
// UNCHANGED before it gets there — check explicitly here too, so this
|
|
366
|
-
// function's own contract states the rule rather than depending on a
|
|
367
|
-
// downstream check someone could relax without noticing this call
|
|
368
|
-
// site. Case-insensitive, any suffix; see test/select.test.js.
|
|
369
|
-
function rejectIklRegime(regime, who) {
|
|
370
|
-
if (regime != null && /^x-ikl/i.test(String(regime))) {
|
|
371
|
-
throw new TypeError(
|
|
372
|
-
`${who}: entail '${regime}' is not implemented. The x-ikl-* ` +
|
|
373
|
-
'entailment regimes are the owner\'s design ' +
|
|
374
|
-
'(danbri/factoidal#581); the Lean engine\'s dispatch for them was ' +
|
|
375
|
-
'deleted on 2026-08-26 as collateral of the IKL-to-RDF projection ' +
|
|
376
|
-
'purge (danbri/factoidal#626). This is not a policy exclusion.');
|
|
357
|
+
// The regime names, their case-insensitive aliases and the x-ikl-* refusal
|
|
358
|
+
// are the engine's tables (op engineTables): no host copy
|
|
359
|
+
// (https://github.com/danbri/factoidal/issues/894 item 5). A name with no
|
|
360
|
+
// alias passes through unchanged and engineApi.query reports it.
|
|
361
|
+
async function regimeOf(regime, who) {
|
|
362
|
+
const t = await engineApi.engineTables();
|
|
363
|
+
const r = regime == null ? 'none' : String(regime);
|
|
364
|
+
for (const [prefix, message] of Object.entries(t.refusedRegimePrefixes)) {
|
|
365
|
+
if (r.toLowerCase().startsWith(prefix)) {
|
|
366
|
+
throw new TypeError(message.replace('WHO', who).replace('REGIME', r));
|
|
367
|
+
}
|
|
377
368
|
}
|
|
369
|
+
return t.entailAliases[r.toLowerCase()] || regime;
|
|
378
370
|
}
|
|
379
371
|
|
|
380
372
|
async function entail(ds, regime) {
|
|
381
373
|
assertFnDataset(ds, 'entail');
|
|
382
|
-
|
|
383
|
-
const rows = await engineApi.query(
|
|
384
|
-
|
|
385
|
-
{ entail: normalizeEntailRegime(regime) });
|
|
374
|
+
const entailRegime = await regimeOf(regime, 'entail');
|
|
375
|
+
const rows = await engineApi.query((await engineOf(ds)), 'SELECT ?s ?p ?o WHERE { ?s ?p ?o }',
|
|
376
|
+
{ entail: entailRegime });
|
|
386
377
|
return makeFnDataset(
|
|
387
378
|
rows.map((row) => dataFactory.quad(row.get('s'), row.get('p'), row.get('o'))));
|
|
388
379
|
}
|
|
389
380
|
|
|
390
381
|
/**
|
|
391
|
-
* SHACL Core validation.
|
|
382
|
+
* SHACL Core validation. Neither
|
|
392
383
|
* argument is mutated or consumed -- both stay valid FnDatasets after
|
|
393
384
|
* the call, same as every other op in this module.
|
|
394
385
|
*
|
|
@@ -401,13 +392,13 @@ async function entail(ds, regime) {
|
|
|
401
392
|
async function validate(ds, shapes) {
|
|
402
393
|
assertFnDataset(ds, 'validate');
|
|
403
394
|
assertFnDataset(shapes, 'validate');
|
|
404
|
-
const r = await engineApi.shaclValidate(
|
|
405
|
-
return { conforms: r.conforms, report:
|
|
395
|
+
const r = await engineApi.shaclValidate((await engineOf(ds)), (await engineOf(shapes)));
|
|
396
|
+
return { conforms: r.conforms, report: wrapEngine(r.report) };
|
|
406
397
|
}
|
|
407
398
|
|
|
408
399
|
/**
|
|
409
400
|
* ShEx (Shape Expressions) validation of one focus node against one
|
|
410
|
-
* shape.
|
|
401
|
+
* shape.
|
|
411
402
|
*
|
|
412
403
|
* @param {FnDataset} ds the data graph
|
|
413
404
|
* @param {string} schema ShExJ (JSON Schema form), as text
|
|
@@ -420,14 +411,13 @@ async function validate(ds, shapes) {
|
|
|
420
411
|
*/
|
|
421
412
|
async function shex(ds, schema, focus, shape) {
|
|
422
413
|
assertFnDataset(ds, 'shex');
|
|
423
|
-
return engineApi.shexValidate(
|
|
414
|
+
return engineApi.shexValidate((await engineOf(ds)), schema, focus, shape);
|
|
424
415
|
}
|
|
425
416
|
|
|
426
417
|
/**
|
|
427
418
|
* Evaluate an RML mapping graph against one logical source's raw
|
|
428
|
-
* data, materializing the generated triples as a new FnDataset.
|
|
429
|
-
*
|
|
430
|
-
* every triples map in `mapping` reads the SAME `source` -- joins
|
|
419
|
+
* data, materializing the generated triples as a new FnDataset. Every
|
|
420
|
+
* triples map in `mapping` reads the SAME `source` -- joins
|
|
431
421
|
* across two different logical sources are not reachable through this
|
|
432
422
|
* one-source entry point (see engineApi.rmlMap's doc comment).
|
|
433
423
|
*
|
|
@@ -438,13 +428,13 @@ async function shex(ds, schema, focus, shape) {
|
|
|
438
428
|
*/
|
|
439
429
|
async function fromMapping(mapping, source, kind) {
|
|
440
430
|
assertFnDataset(mapping, 'fromMapping');
|
|
441
|
-
return
|
|
431
|
+
return wrapEngine(await engineApi.rmlMap((await engineOf(mapping)), source, kind));
|
|
442
432
|
}
|
|
443
433
|
|
|
444
434
|
/**
|
|
445
435
|
* CSVW csv2rdf conversion (w3.org/TR/csv2rdf): convert raw tabular
|
|
446
436
|
* data plus an optional CSVW metadata document into a new FnDataset.
|
|
447
|
-
*
|
|
437
|
+
* Unlike fromMapping there is no
|
|
448
438
|
* FnDataset input -- both arguments are raw text (CSVW's metadata
|
|
449
439
|
* format is JSON, not RDF). Scope cut (documented, not silent --
|
|
450
440
|
* mirrors fromMapping's one-source cut): every table in a multi-table
|
|
@@ -461,14 +451,13 @@ async function fromMapping(mapping, source, kind) {
|
|
|
461
451
|
* @returns {Promise<FnDataset>}
|
|
462
452
|
*/
|
|
463
453
|
async function fromCsvw(csv, metadata, options) {
|
|
464
|
-
return
|
|
454
|
+
return wrapEngine(await engineApi.csvwToRdf(csv, metadata, options));
|
|
465
455
|
}
|
|
466
456
|
|
|
467
457
|
/**
|
|
468
458
|
* RIF Core forward-chaining saturation, materialized as a new
|
|
469
459
|
* FnDataset (input triples + derived triples, default graph only --
|
|
470
|
-
* RIF Core has no named-graph notion).
|
|
471
|
-
* bundle.
|
|
460
|
+
* RIF Core has no named-graph notion).
|
|
472
461
|
*
|
|
473
462
|
* @param {FnDataset} ds the premise graph
|
|
474
463
|
* @param {string} rules a RIF Core XML rule document
|
|
@@ -476,7 +465,7 @@ async function fromCsvw(csv, metadata, options) {
|
|
|
476
465
|
*/
|
|
477
466
|
async function rif(ds, rules) {
|
|
478
467
|
assertFnDataset(ds, 'rif');
|
|
479
|
-
return
|
|
468
|
+
return wrapEngine(await engineApi.rifEval((await engineOf(ds)), rules));
|
|
480
469
|
}
|
|
481
470
|
|
|
482
471
|
/**
|
|
@@ -489,8 +478,7 @@ async function rif(ds, rules) {
|
|
|
489
478
|
* Gutierrez, "Simple and Efficient Minimal RDFS", J. Web Semantics
|
|
490
479
|
* 7(3), 2009). Mirrors engineApi.coreRdfsClosure's `{ok, ntriples}`
|
|
491
480
|
* result, with `ntriples` parsed into an FnDataset via
|
|
492
|
-
* Dataset
|
|
493
|
-
* npm-entry engine bundle. `rhoDfClosure` is kept below as a
|
|
481
|
+
* the engine Dataset of the closure. `rhoDfClosure` is kept below as a
|
|
494
482
|
* literature-name alias.
|
|
495
483
|
* @param {FnDataset} ds
|
|
496
484
|
* @param {{format?: string}} [options]
|
|
@@ -498,17 +486,15 @@ async function rif(ds, rules) {
|
|
|
498
486
|
*/
|
|
499
487
|
async function coreRdfsClosure(ds, options) {
|
|
500
488
|
assertFnDataset(ds, 'coreRdfsClosure');
|
|
501
|
-
const r = await engineApi.coreRdfsClosure(
|
|
502
|
-
return { ok:
|
|
489
|
+
const r = await engineApi.coreRdfsClosure((await engineOf(ds)), options);
|
|
490
|
+
return { ok: true, dataset: wrapEngine(r) };
|
|
503
491
|
}
|
|
504
492
|
/** Literature-name alias for coreRdfsClosure (ρdf; see above). */
|
|
505
493
|
const rhoDfClosure = coreRdfsClosure;
|
|
506
494
|
|
|
507
495
|
/**
|
|
508
|
-
* Decidable core-RDFS fragment check (`
|
|
509
|
-
*
|
|
510
|
-
* certified coreRdfsClosure guarantee apply to `ds`? Needs the
|
|
511
|
-
* npm-entry engine bundle. `rhoDfFragmentCheck` is kept below as a
|
|
496
|
+
* Decidable core-RDFS fragment check (L4Factoidal/RDFS, `isRhoDfFrag`):
|
|
497
|
+
* is `ds` in the core-RDFS fragment coreRdfsClosure is defined for? `rhoDfFragmentCheck` is kept below as a
|
|
512
498
|
* literature-name alias.
|
|
513
499
|
* @param {FnDataset} ds
|
|
514
500
|
* @param {{format?: string}} [options]
|
|
@@ -516,7 +502,7 @@ const rhoDfClosure = coreRdfsClosure;
|
|
|
516
502
|
*/
|
|
517
503
|
async function coreRdfsCheck(ds, options) {
|
|
518
504
|
assertFnDataset(ds, 'coreRdfsCheck');
|
|
519
|
-
return engineApi.coreRdfsCheck(
|
|
505
|
+
return engineApi.coreRdfsCheck((await engineOf(ds)), options);
|
|
520
506
|
}
|
|
521
507
|
/** Literature-name alias for coreRdfsCheck (ρdf; see above). */
|
|
522
508
|
const rhoDfFragmentCheck = coreRdfsCheck;
|
|
@@ -529,19 +515,17 @@ const rhoDfFragmentCheck = coreRdfsCheck;
|
|
|
529
515
|
* Allemang & Hendler 2008; "RDFS++", AllegroGraph). Every OWL row
|
|
530
516
|
* carries a proved licensing + truth lemma; no chain-level
|
|
531
517
|
* completeness claim (theorem registry) — weaker than
|
|
532
|
-
* coreRdfsClosure's decides-iff guarantee.
|
|
533
|
-
* bundle.
|
|
518
|
+
* coreRdfsClosure's decides-iff guarantee.
|
|
534
519
|
* @param {FnDataset} ds
|
|
535
520
|
* @param {{format?: string}} [options]
|
|
536
|
-
* @returns {Promise<{ok: boolean, dataset: FnDataset
|
|
521
|
+
* @returns {Promise<{ok: boolean, dataset: FnDataset}>}
|
|
537
522
|
*/
|
|
538
523
|
async function rdfsPlusClosure(ds, options) {
|
|
539
524
|
assertFnDataset(ds, 'rdfsPlusClosure');
|
|
540
|
-
const r = await engineApi.rdfsPlusClosure(
|
|
525
|
+
const r = await engineApi.rdfsPlusClosure((await engineOf(ds)), options);
|
|
541
526
|
return {
|
|
542
|
-
ok:
|
|
543
|
-
dataset:
|
|
544
|
-
rounds: r.rounds,
|
|
527
|
+
ok: true,
|
|
528
|
+
dataset: wrapEngine(r),
|
|
545
529
|
};
|
|
546
530
|
}
|
|
547
531
|
|
|
@@ -551,7 +535,7 @@ async function rdfsPlusClosure(ds, options) {
|
|
|
551
535
|
* individual the model-construction reasoner proves is a member of an
|
|
552
536
|
* OWL class expression (someValuesFrom / hasValue / unionOf /
|
|
553
537
|
* intersectionOf, and the named class an equivalentClass restriction
|
|
554
|
-
* defines).
|
|
538
|
+
* defines). Default graph only.
|
|
555
539
|
*
|
|
556
540
|
* @param {FnDataset} ds the ontology + ABox graph
|
|
557
541
|
* @returns {Promise<{dataset: FnDataset, addedCount: number}>} dataset
|
|
@@ -560,31 +544,29 @@ async function rdfsPlusClosure(ds, options) {
|
|
|
560
544
|
*/
|
|
561
545
|
async function tableauMaterialise(ds) {
|
|
562
546
|
assertFnDataset(ds, 'tableauMaterialise');
|
|
563
|
-
const r = await engineApi.tableauMaterialise(
|
|
564
|
-
return { dataset:
|
|
547
|
+
const r = await engineApi.tableauMaterialise((await engineOf(ds)));
|
|
548
|
+
return { dataset: wrapEngine(r.dataset), addedCount: r.addedCount };
|
|
565
549
|
}
|
|
566
550
|
|
|
567
551
|
/**
|
|
568
552
|
* OWL DL inconsistency verdict (bin/owl-runner's DL pipeline: OWL-RL
|
|
569
553
|
* closure -> tableau materialise -> OWL-RL closure -> is_inconsistent).
|
|
570
554
|
* `rlAlone` is the plain OWL-RL verdict on the same input, so a caller
|
|
571
|
-
* can see the cases the tableau adds.
|
|
572
|
-
* bundle. Default graph only.
|
|
555
|
+
* can see the cases the tableau adds. Default graph only.
|
|
573
556
|
*
|
|
574
557
|
* @param {FnDataset} ds the ontology + ABox graph
|
|
575
558
|
* @returns {Promise<{inconsistent: boolean, rlAlone: boolean}>}
|
|
576
559
|
*/
|
|
577
560
|
async function tableauDlInconsistent(ds) {
|
|
578
561
|
assertFnDataset(ds, 'tableauDlInconsistent');
|
|
579
|
-
return engineApi.tableauDlInconsistent(
|
|
562
|
+
return engineApi.tableauDlInconsistent((await engineOf(ds)));
|
|
580
563
|
}
|
|
581
564
|
|
|
582
565
|
/**
|
|
583
566
|
* OWL DL consistency verdict via the verified clash-detecting tableau
|
|
584
567
|
* (formal/fstar/Tableau.Refute.fst's `tableau_consistent` over the
|
|
585
568
|
* OWL-RL closure -- the pure verified chain bin/owl-runner runs under
|
|
586
|
-
* `--regime dl`, minus its native-only z3 oracle).
|
|
587
|
-
* bundle. Default graph only.
|
|
569
|
+
* `--regime dl`, minus its native-only z3 oracle). Default graph only.
|
|
588
570
|
*
|
|
589
571
|
* `consistent` is three-valued: `false` (a clash on every tableau
|
|
590
572
|
* branch), `true` (a model was constructed), or `null` -- the refuter
|
|
@@ -597,7 +579,7 @@ async function tableauDlInconsistent(ds) {
|
|
|
597
579
|
* @returns {Promise<{consistent: boolean|null, reason?: string}>}
|
|
598
580
|
*/
|
|
599
581
|
async function owlIsConsistent(ontology, options) {
|
|
600
|
-
const data = ontology instanceof FnDataset ?
|
|
582
|
+
const data = ontology instanceof FnDataset ? (await engineOf(ontology)) : ontology;
|
|
601
583
|
return engineApi.owlIsConsistent(data, options);
|
|
602
584
|
}
|
|
603
585
|
|
|
@@ -605,7 +587,7 @@ async function owlIsConsistent(ontology, options) {
|
|
|
605
587
|
* OWL entailment check: does `premise` entail `conclusion`? Verified
|
|
606
588
|
* two-path dispatch (`via: "closure"` for the OWL-RL closure path,
|
|
607
589
|
* `via: "refutation"` for negate-and-refute), mirroring bin/owl-runner.
|
|
608
|
-
*
|
|
590
|
+
* Default graph only. `entailed` is
|
|
609
591
|
* three-valued (`true` / `false` / `null` budget-out, `reason` names the
|
|
610
592
|
* cap).
|
|
611
593
|
*
|
|
@@ -615,20 +597,20 @@ async function owlIsConsistent(ontology, options) {
|
|
|
615
597
|
* @returns {Promise<{entailed: boolean|null, via: 'closure'|'refutation', reason?: string}>}
|
|
616
598
|
*/
|
|
617
599
|
async function owlEntails(premise, conclusion, options) {
|
|
618
|
-
const p = premise instanceof FnDataset ?
|
|
619
|
-
const c = conclusion instanceof FnDataset ?
|
|
600
|
+
const p = premise instanceof FnDataset ? (await engineOf(premise)) : premise;
|
|
601
|
+
const c = conclusion instanceof FnDataset ? (await engineOf(conclusion)) : conclusion;
|
|
620
602
|
return engineApi.owlEntails(p, c, options);
|
|
621
603
|
}
|
|
622
604
|
|
|
623
605
|
/**
|
|
624
|
-
* RDFC-1.0 canonicalization: canonical N-Quads text.
|
|
625
|
-
*
|
|
606
|
+
* RDFC-1.0 canonicalization: canonical N-Quads text (index.js's
|
|
607
|
+
* canonicalize()).
|
|
626
608
|
*/
|
|
627
609
|
async function canonicalize(ds) {
|
|
628
610
|
assertFnDataset(ds, 'canonicalize');
|
|
629
611
|
let cached = CANON_CACHE.get(ds);
|
|
630
612
|
if (cached === undefined) {
|
|
631
|
-
const p = engineApi.canonicalize(
|
|
613
|
+
const p = engineApi.canonicalize((await engineOf(ds))).then((text) => {
|
|
632
614
|
CANON_CACHE.set(ds, text); // replace the in-flight promise
|
|
633
615
|
return text;
|
|
634
616
|
});
|
|
@@ -677,111 +659,34 @@ function peekHash(ds) {
|
|
|
677
659
|
return typeof c === 'string' ? c : null;
|
|
678
660
|
}
|
|
679
661
|
|
|
680
|
-
function hasBlankNode(ds) {
|
|
681
|
-
for (const q of ds) {
|
|
682
|
-
if (q.subject.termType === 'BlankNode') return true;
|
|
683
|
-
if (q.object.termType === 'BlankNode') return true;
|
|
684
|
-
if (q.graph.termType === 'BlankNode') return true;
|
|
685
|
-
}
|
|
686
|
-
return false;
|
|
687
|
-
}
|
|
688
|
-
|
|
689
662
|
/**
|
|
690
|
-
*
|
|
691
|
-
*
|
|
692
|
-
*
|
|
693
|
-
*
|
|
694
|
-
* 2. Both sides already have a memoized hash -> compare those, O(1).
|
|
695
|
-
* 3. Exact quad-set match (same terms, same labels) -> equal, O(n).
|
|
696
|
-
* This is sound regardless of blank nodes: identical tokens can
|
|
697
|
-
* never be a false positive.
|
|
698
|
-
* 4. No blank nodes anywhere -> the step-3 negative is authoritative
|
|
699
|
-
* (ground quads have no relabeling to hide behind) -> not equal.
|
|
700
|
-
* 5. Otherwise (blank nodes present, step 3 was inconclusive) ->
|
|
701
|
-
* the only sound test left is RDFC-1.0 canonical-hash equality,
|
|
702
|
-
* which is exactly the O(n log n) canonicalize() cost this module
|
|
703
|
-
* tries to avoid paying twice.
|
|
663
|
+
* Dataset isomorphism (RDF 1.1 Concepts 3.6 and 4, blank nodes inside RDF
|
|
664
|
+
* 1.2 triple terms included), decided by the engine
|
|
665
|
+
* (Dataset.isomorphicOutcome, op datasetIsomorphic). The same FnDataset is
|
|
666
|
+
* equal to itself without a call.
|
|
704
667
|
*/
|
|
705
668
|
async function equals(a, b) {
|
|
706
669
|
assertFnDataset(a, 'equals'); assertFnDataset(b, 'equals');
|
|
707
670
|
if (a === b) return true;
|
|
708
|
-
|
|
709
|
-
const ha = peekHash(a);
|
|
710
|
-
const hb = peekHash(b);
|
|
711
|
-
if (ha !== null && hb !== null) return ha === hb;
|
|
712
|
-
const aKeys = new Set(a.toArray().map(quadToNQuads));
|
|
713
|
-
const bTokens = b.toArray().map(quadToNQuads);
|
|
714
|
-
const exact = bTokens.length === aKeys.size &&
|
|
715
|
-
bTokens.every((t) => aKeys.has(t));
|
|
716
|
-
if (exact) return true;
|
|
717
|
-
if (!hasBlankNode(a) && !hasBlankNode(b)) return false;
|
|
718
|
-
const [h1, h2] = await Promise.all([hash(a), hash(b)]);
|
|
719
|
-
return h1 === h2;
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
/**
|
|
723
|
-
* Open a COTTAS/Parquet artifact's raw bytes as a queryable, read-only
|
|
724
|
-
* store (docs/designissues/2026-07-06-inmemory-bytes-store.md, browser
|
|
725
|
-
* call site). Needs the npm-entry engine bundle. Unlike every other
|
|
726
|
-
* constructor in this module, the returned object is NOT an FnDataset:
|
|
727
|
-
* the whole point of the design is that rows decode lazily as a query
|
|
728
|
-
* touches them, never materializing the corpus into heap FnDataset
|
|
729
|
-
* quads (measured 64-161 B/quad vs. an FnDataset/heap Dataset's
|
|
730
|
-
* ~877 B/quad for the same data, in the design doc's native numbers).
|
|
731
|
-
*
|
|
732
|
-
* @param {string|Uint8Array|ArrayBuffer} bytes whole `.cottas` file contents
|
|
733
|
-
* @returns {Promise<{handle: string,
|
|
734
|
-
* query: (sparql: string) => Promise<Array<Map<string,object>>|boolean|FnDataset>,
|
|
735
|
-
* close: () => Promise<void>}>}
|
|
736
|
-
* query() divergences from fn.query() (documented, not silent): no
|
|
737
|
-
* entail option, no write/--delta-log overlay (read-only), and a
|
|
738
|
-
* query shape the backend executor can't push down rejects instead
|
|
739
|
-
* of silently falling back to a full materialize (see
|
|
740
|
-
* engineApi.queryCottas's doc comment). CONSTRUCT still returns an
|
|
741
|
-
* FnDataset (materialized once for that query only).
|
|
742
|
-
*/
|
|
743
|
-
async function openCottas(bytes) {
|
|
744
|
-
const handle = await engineApi.openCottas(bytes);
|
|
745
|
-
let closed = false;
|
|
746
|
-
return {
|
|
747
|
-
handle,
|
|
748
|
-
async query(sparql) {
|
|
749
|
-
if (closed) throw new Error('openCottas store: query() called after close()');
|
|
750
|
-
const result = await engineApi.queryCottas(handle, sparql);
|
|
751
|
-
return result instanceof Dataset ? fromDataset(result) : result;
|
|
752
|
-
},
|
|
753
|
-
async close() {
|
|
754
|
-
if (closed) return;
|
|
755
|
-
closed = true;
|
|
756
|
-
await engineApi.closeCottas(handle);
|
|
757
|
-
},
|
|
758
|
-
};
|
|
671
|
+
return engineApi.isomorphic(await engineOf(a), await engineOf(b));
|
|
759
672
|
}
|
|
760
673
|
|
|
761
674
|
/**
|
|
762
|
-
*
|
|
763
|
-
*
|
|
764
|
-
*
|
|
765
|
-
*
|
|
766
|
-
* reproduces the same queryable store.
|
|
767
|
-
*
|
|
768
|
-
* @param {FnDataset} ds
|
|
769
|
-
* @returns {Promise<Uint8Array>}
|
|
770
|
-
*/
|
|
771
|
-
async function toCottas(ds) {
|
|
772
|
-
assertFnDataset(ds, 'toCottas');
|
|
773
|
-
return engineApi.toCottas(toDataset(ds));
|
|
774
|
-
}
|
|
775
|
-
|
|
776
|
-
/**
|
|
777
|
-
* Enumerate named graphs (default graph excluded), first-seen order.
|
|
778
|
-
* Reuses index.js's graphs() enumeration; wraps each per-graph
|
|
779
|
-
* Dataset back into an FnDataset.
|
|
675
|
+
* Enumerate named graphs (default graph excluded), first-seen order. An
|
|
676
|
+
* engine-backed dataset asks the engine (op datasetGraphNames); an array of
|
|
677
|
+
* JS quads groups by RDF/JS Term.equals identity, so an IRI and a blank node
|
|
678
|
+
* with the same string are two graphs.
|
|
780
679
|
*/
|
|
781
680
|
function graphs(ds) {
|
|
782
681
|
assertFnDataset(ds, 'graphs');
|
|
783
|
-
|
|
784
|
-
.map(([
|
|
682
|
+
if (ds._backend.engine) {
|
|
683
|
+
return engineApi.graphs(ds._backend.engine).map(([name, g]) => [name, wrapEngine(g)]);
|
|
684
|
+
}
|
|
685
|
+
const seen = new Map();
|
|
686
|
+
for (const q of ds) {
|
|
687
|
+
if (q.graph.termType !== 'DefaultGraph' && !seen.has(termKey(q.graph))) seen.set(termKey(q.graph), q.graph);
|
|
688
|
+
}
|
|
689
|
+
return [...seen.values()].map((g) => [g, ds.match(null, null, null, g)]);
|
|
785
690
|
}
|
|
786
691
|
|
|
787
692
|
// ---------------------------------------------------------------------
|
|
@@ -860,7 +765,7 @@ function pipe(...fns) {
|
|
|
860
765
|
// -----------------------------------------------------------------
|
|
861
766
|
// Typed engine functions (#74). Re-exported unchanged from the JS
|
|
862
767
|
// engine api — each is already a pure, value-in / value-out function
|
|
863
|
-
// over one
|
|
768
|
+
// over one engine op (XSLT, MathML, XForms, JSON Schema,
|
|
864
769
|
// Schematron, TOAN CAS, matrix algebra), so they belong in the
|
|
865
770
|
// functional surface as-is. See index.d.ts / fn.d.ts for signatures.
|
|
866
771
|
// -----------------------------------------------------------------
|
|
@@ -875,12 +780,6 @@ const {
|
|
|
875
780
|
toanSimplify,
|
|
876
781
|
toanDiff,
|
|
877
782
|
toanSubst,
|
|
878
|
-
matrixDeterminant,
|
|
879
|
-
matrixScalarProduct,
|
|
880
|
-
matrixVectorProduct,
|
|
881
|
-
matrixOuterProduct,
|
|
882
|
-
sigmoidPoints,
|
|
883
|
-
sigmoidFormulaMathml,
|
|
884
783
|
vcSha256Hex,
|
|
885
784
|
vcEd25519SecretToPublic,
|
|
886
785
|
vcEd25519Sign,
|
|
@@ -921,8 +820,6 @@ module.exports = {
|
|
|
921
820
|
canonicalize,
|
|
922
821
|
hash,
|
|
923
822
|
equals,
|
|
924
|
-
openCottas,
|
|
925
|
-
toCottas,
|
|
926
823
|
graphs,
|
|
927
824
|
cell,
|
|
928
825
|
derive,
|
|
@@ -938,12 +835,6 @@ module.exports = {
|
|
|
938
835
|
toanSimplify,
|
|
939
836
|
toanDiff,
|
|
940
837
|
toanSubst,
|
|
941
|
-
matrixDeterminant,
|
|
942
|
-
matrixScalarProduct,
|
|
943
|
-
matrixVectorProduct,
|
|
944
|
-
matrixOuterProduct,
|
|
945
|
-
sigmoidPoints,
|
|
946
|
-
sigmoidFormulaMathml,
|
|
947
838
|
vcSha256Hex,
|
|
948
839
|
vcEd25519SecretToPublic,
|
|
949
840
|
vcEd25519Sign,
|