@factoidal/core 0.10.0 → 0.12.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 +496 -1
- package/README.md +70 -4
- package/api.d.ts +2 -3
- package/api.mjs +2 -2
- package/bin/ext.mjs +16 -20
- package/bin/factoidal.mjs +308 -69
- package/browser.d.ts +7 -2
- package/browser.js +5 -2
- package/fn.d.ts +1 -1
- package/fn.js +33 -100
- package/index.d.ts +105 -29
- package/index.mjs +5 -2
- package/l4-assets/l4factoidal.js +1 -1
- package/l4-assets/l4factoidal.mjs +1 -1
- package/l4-assets/l4factoidal.wasm +0 -0
- package/l4-assets/version.json +6 -6
- package/lib/api.mjs +214 -287
- package/lib/dataset.mjs +164 -75
- package/lib/delta-log-hosts.mjs +9 -8
- package/lib/errors.mjs +97 -0
- package/lib/lean-entry.mjs +36 -22
- package/lib/store.mjs +4 -5
- package/lib/version.mjs +1 -1
- package/lws/README.md +114 -7
- package/lws/persist.mjs +309 -0
- package/lws/server.mjs +364 -17
- package/package.json +2 -1
- package/rdfjs.mjs +151 -226
- package/solid/client/index.mjs +25 -9
- package/solid/server/index.mjs +99 -15
package/lib/api.mjs
CHANGED
|
@@ -22,66 +22,26 @@
|
|
|
22
22
|
// JSDoc note "entry_jsoo.ml's X" below names that lineage. The Lean op of
|
|
23
23
|
// the same name serves X now (formal/lean4/Wasm/Dispatch.lean lists them).
|
|
24
24
|
|
|
25
|
-
import { dataFactory, termFromSrj,
|
|
25
|
+
import { dataFactory, termFromSrj, termToJson, quadToJson, _setTextEngine } from '../rdfjs.mjs';
|
|
26
26
|
import { Dataset, INTERNAL, checkOptions, makeRegistry, WRITER_TAGS } from './dataset.mjs';
|
|
27
27
|
import { version as packageVersion } from './version.mjs';
|
|
28
28
|
import { openGeneration, readRegion, manifestKeys, hexOfBytes } from './store.mjs';
|
|
29
29
|
import { fullEngineMessage } from './lean-entry.mjs';
|
|
30
30
|
import { memoryDeltaLogStore } from './delta-log-hosts.mjs';
|
|
31
|
+
import { FactoidalError, errorFromEnvelope, envelopeResult } from './errors.mjs';
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
ntriples: 'nt',
|
|
36
|
-
nt: 'nt',
|
|
37
|
-
nquads: 'nq',
|
|
38
|
-
nq: 'nq',
|
|
39
|
-
trig: 'trig',
|
|
40
|
-
rdfxml: 'rdf',
|
|
41
|
-
'rdf-xml': 'rdf',
|
|
42
|
-
rdf: 'rdf',
|
|
43
|
-
jsonld: 'jsonld',
|
|
44
|
-
'json-ld': 'jsonld',
|
|
45
|
-
// RDF 1.2 opt-in: these select the engine's RDF 1.2 parsers (triple
|
|
46
|
-
// terms <<( s p o )>>, ~ reifiers, {| |} annotations, VERSION,
|
|
47
|
-
// directional literals "x"@lang--dir; Wasm/Ops/Parse.lean's
|
|
48
|
-
// `Mode.rdf12`); the plain names above stay RDF 1.1.
|
|
49
|
-
turtle12: 'ttl12',
|
|
50
|
-
ttl12: 'ttl12',
|
|
51
|
-
ntriples12: 'nt12',
|
|
52
|
-
nt12: 'nt12',
|
|
53
|
-
nquads12: 'nq12',
|
|
54
|
-
nq12: 'nq12',
|
|
55
|
-
trig12: 'trig12',
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
// Canonical format tag for the engine's parse ops (parseToDatasetJson,
|
|
59
|
-
// datasetOpen); the *12 tags select the RDF 1.2 mode.
|
|
60
|
-
const DATA_FORMAT_TAG = {
|
|
61
|
-
ttl: 'turtle', nt: 'ntriples', nq: 'nquads', trig: 'trig', rdf: 'rdfxml',
|
|
62
|
-
jsonld: 'jsonld',
|
|
63
|
-
ttl12: 'turtle12', nt12: 'ntriples12', nq12: 'nquads12', trig12: 'trig12',
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
const ENTAIL_VALUES = new Set(['none', 'RDFS', 'OWL-RL', 'x-rdfscore', 'x-rdfsplus']);
|
|
67
|
-
|
|
68
|
-
// queryRaw's options (op queryRaw, Wasm/Ops/QueryExtras.lean).
|
|
69
|
-
const RAW_OUTPUT_FORMATS = new Set(['json', 'csv', 'tsv', 'xml', 'table', 'ntriples']);
|
|
70
|
-
const RAW_DATA_FORMATS = {
|
|
71
|
-
turtle: 'turtle', ttl: 'turtle', ntriples: 'ntriples', nt: 'ntriples',
|
|
72
|
-
nquads: 'nquads', nq: 'nquads', trig: 'trig', rdfxml: 'rdfxml',
|
|
73
|
-
'rdf-xml': 'rdfxml', rdf: 'rdfxml',
|
|
74
|
-
};
|
|
33
|
+
// The format names, regimes and query outputs are the engine's tables (op
|
|
34
|
+
// engineTables, formal/lean4/Wasm/Ops/Handles.lean), read once per engine:
|
|
35
|
+
// no host copy (https://github.com/danbri/factoidal/issues/894 item 5).
|
|
75
36
|
|
|
76
|
-
|
|
37
|
+
// The parse tag a format name selects, from the engine's table.
|
|
38
|
+
// A name outside the table is refused by the engine (op apiCheck,
|
|
39
|
+
// code format.unknown).
|
|
40
|
+
function parseTagOf(e, tables, fmt, who) {
|
|
77
41
|
const key = String(fmt || 'turtle').toLowerCase();
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
Object.keys(DATA_FORMAT_EXT).join(', ')
|
|
82
|
-
);
|
|
83
|
-
}
|
|
84
|
-
return DATA_FORMAT_EXT[key];
|
|
42
|
+
const tag = tables.parseFormats[key];
|
|
43
|
+
if (tag === undefined) checkOptions(e, who || 'parse', { format: String(fmt) });
|
|
44
|
+
return tag;
|
|
85
45
|
}
|
|
86
46
|
|
|
87
47
|
// Where a function takes an options object, a bare string names the
|
|
@@ -102,28 +62,37 @@ function optionsOf(fn, options) {
|
|
|
102
62
|
// package, or a dispatch table that does not serve it). When the entry is
|
|
103
63
|
// the core engine and the op is one only the full engine serves, the error
|
|
104
64
|
// names the entry that has it (issue 713 stage 4).
|
|
65
|
+
// The engine's own answer to the op is the error (code op.unknown); an entry
|
|
66
|
+
// with no engine handle to ask gets the same code.
|
|
105
67
|
function missingOpError(what, e, op) {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
68
|
+
const eng = e && e.engine;
|
|
69
|
+
if (eng && typeof eng.call === 'function' && op) {
|
|
70
|
+
try {
|
|
71
|
+
eng.call(op, []);
|
|
72
|
+
} catch (err) {
|
|
73
|
+
if (err && err.envelope && err.envelope.code === 'op.unknown') {
|
|
74
|
+
const out = errorFromEnvelope(err.envelope);
|
|
75
|
+
if (e.profile === 'core' && Array.isArray(e.fullOnlyOps) && e.fullOnlyOps.includes(op)) {
|
|
76
|
+
out.message = `${what}: ${fullEngineMessage(`the op '${op}'`)}`;
|
|
77
|
+
}
|
|
78
|
+
return out;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
109
81
|
}
|
|
110
|
-
return new
|
|
82
|
+
return new FactoidalError(
|
|
111
83
|
`${what}: the loaded Lean wasm module has no dispatch op for this ` +
|
|
112
84
|
'operation. The module is older than this package; rebuild it with ' +
|
|
113
85
|
'formal/lean4/Wasm/build-wasm.sh, or point FACTOIDAL_L4_ASSETS at a ' +
|
|
114
|
-
'current build.');
|
|
86
|
+
'current build.', { code: 'op.unknown' });
|
|
115
87
|
}
|
|
116
88
|
|
|
117
|
-
//
|
|
118
|
-
//
|
|
119
|
-
//
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
.replace(/#[^\n]*/g, ' ');
|
|
125
|
-
const m = cleaned.match(/\b(select|ask|construct|describe)\b/i);
|
|
126
|
-
return m ? m[1].toLowerCase() : 'select';
|
|
89
|
+
// The query form, from the engine's SPARQL parser (op queryForm). A query
|
|
90
|
+
// the parser rejects answers 'select'; the query op then reports the parse
|
|
91
|
+
// error itself.
|
|
92
|
+
function queryFormOf(e, sparql) {
|
|
93
|
+
if (typeof e.queryForm !== 'function') return 'select';
|
|
94
|
+
const r = JSON.parse(e.queryForm(String(sparql)));
|
|
95
|
+
return r.ok ? r.kind : 'select';
|
|
127
96
|
}
|
|
128
97
|
|
|
129
98
|
// Bytes for an op that reads the byte region (queryHdt, storeOpen): a
|
|
@@ -157,85 +126,23 @@ function bindingsFromSrj(srj) {
|
|
|
157
126
|
}
|
|
158
127
|
|
|
159
128
|
// ---------------------------------------------------------------------
|
|
160
|
-
//
|
|
161
|
-
//
|
|
129
|
+
// The envelope unwrapper every engine call routes through. A refusal is a
|
|
130
|
+
// FactoidalError (lib/errors.mjs) whose code, spec section and position the
|
|
131
|
+
// engine decided (formal/lean4/Wasm/Ops/ErrorModel.lean).
|
|
162
132
|
// ---------------------------------------------------------------------
|
|
163
133
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
* when the failing engine call reported one (a parseToDatasetJson or
|
|
167
|
-
* datasetOpen error over Turtle, TriG, N-Triples or N-Quads), else
|
|
168
|
-
* `undefined`. RDF/XML and JSON-LD failures, and any non-parse engine
|
|
169
|
-
* error, stay plain Error -- entryResult() below decides which one to
|
|
170
|
-
* throw.
|
|
171
|
-
*
|
|
172
|
-
* Units: `line` and `column` are 1-based; `column` counts Unicode scalar
|
|
173
|
-
* values, as the engine reports it. `offset` is a UTF-16 code-unit index
|
|
174
|
-
* into the input JavaScript string, so `text.slice(err.offset)` starts
|
|
175
|
-
* at the error. The engine counts Unicode scalar values;
|
|
176
|
-
* utf16OffsetOf() below converts.
|
|
177
|
-
*/
|
|
178
|
-
class ParseError extends Error {
|
|
179
|
-
constructor(message, info) {
|
|
180
|
-
super(message);
|
|
181
|
-
this.name = 'ParseError';
|
|
182
|
-
const i = info || {};
|
|
183
|
-
this.line = i.line;
|
|
184
|
-
this.column = i.column;
|
|
185
|
-
this.offset = i.offset;
|
|
186
|
-
this.format = i.format;
|
|
187
|
-
if (typeof Error.captureStackTrace === 'function') {
|
|
188
|
-
Error.captureStackTrace(this, ParseError);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// Unwrap one dispatch-op JSON envelope ({"ok":true,...} |
|
|
194
|
-
// {"ok":false,"error":...}). A `line` or `offset` member on the error
|
|
195
|
-
// envelope means the failing call was a parse (Turtle/TriG/N-Triples/
|
|
196
|
-
// N-Quads carry a position; RDF/XML and JSON-LD carry a message only)
|
|
197
|
-
// -- throw ParseError so a caller can branch on position without
|
|
198
|
-
// string-matching the message. Every other failure stays a plain
|
|
199
|
-
// Error, as before. Pure (no per-driver state), so every buildApi()
|
|
200
|
-
// instance and DatasetHandle share this one function.
|
|
201
|
-
function entryResult(jsonText, what) {
|
|
202
|
-
const r = JSON.parse(jsonText);
|
|
203
|
-
if (!r.ok) {
|
|
204
|
-
if (r.line !== undefined || r.offset !== undefined) {
|
|
205
|
-
throw new ParseError(`${what}: ${r.error}`, {
|
|
206
|
-
line: r.line, column: r.column, offset: r.offset, format: r.format,
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
throw new Error(`${what}: ${r.error}`);
|
|
210
|
-
}
|
|
211
|
-
return r;
|
|
134
|
+
function entryResult(jsonText, _what, text) {
|
|
135
|
+
return envelopeResult(jsonText, text);
|
|
212
136
|
}
|
|
213
137
|
|
|
214
|
-
//
|
|
215
|
-
//
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
// engine's count into the UTF-16 index of the same position. A count past
|
|
219
|
-
// the end of the text gives text.length. Iterating a string with for..of
|
|
220
|
-
// yields one element per code point (a lone surrogate is one element, and
|
|
221
|
-
// the engine reads it as one replacement character), so both sides count
|
|
222
|
-
// the same units.
|
|
223
|
-
function utf16OffsetOf(text, scalarOffset) {
|
|
224
|
-
if (typeof text !== 'string' || !Number.isInteger(scalarOffset) || scalarOffset < 0) {
|
|
225
|
-
return scalarOffset;
|
|
226
|
-
}
|
|
227
|
-
let units = 0;
|
|
228
|
-
let scalars = 0;
|
|
229
|
-
for (const ch of text) {
|
|
230
|
-
if (scalars >= scalarOffset) break;
|
|
231
|
-
units += ch.length;
|
|
232
|
-
scalars += 1;
|
|
233
|
-
}
|
|
234
|
-
return units;
|
|
138
|
+
// entryResult() for an op that read `text`: the position's offset becomes a
|
|
139
|
+
// UTF-16 index into `text`.
|
|
140
|
+
function parseResult(jsonText, what, text) {
|
|
141
|
+
return entryResult(jsonText, what, text);
|
|
235
142
|
}
|
|
236
143
|
|
|
237
144
|
// The lenient parse's diagnostics (https://github.com/danbri/factoidal/issues/716)
|
|
238
|
-
// with each `offset` converted
|
|
145
|
+
// with each `offset` converted to a UTF-16 index as a FactoidalError's, so
|
|
239
146
|
// `text.slice(d.offset)` starts at the error. `line` and `column` are kept as
|
|
240
147
|
// the engine reports them. One pass over `text` for all diagnostics: the
|
|
241
148
|
// offsets are visited in increasing order, whatever order the list has.
|
|
@@ -263,23 +170,6 @@ function utf16Diagnostics(text, diagnostics) {
|
|
|
263
170
|
return diagnostics.map((d, i) => (units.has(i) ? { ...d, offset: units.get(i) } : d));
|
|
264
171
|
}
|
|
265
172
|
|
|
266
|
-
// entryResult() for an op that parsed `text`: a positioned ParseError gets
|
|
267
|
-
// its offset converted to a UTF-16 index into `text`.
|
|
268
|
-
function parseResult(jsonText, what, text) {
|
|
269
|
-
try {
|
|
270
|
-
return entryResult(jsonText, what);
|
|
271
|
-
} catch (err) {
|
|
272
|
-
if (err instanceof ParseError && typeof err.offset === 'number') {
|
|
273
|
-
err.offset = utf16OffsetOf(text, err.offset);
|
|
274
|
-
}
|
|
275
|
-
throw err;
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
// DatasetHandle: the name of the engine-resident dataset class before
|
|
280
|
-
// 0.10.0. Deprecated alias of Dataset, kept for 0.10.x only.
|
|
281
|
-
const DatasetHandle = Dataset;
|
|
282
|
-
|
|
283
173
|
// ---------------------------------------------------------------------
|
|
284
174
|
// The Lean persisted store (Shardborough generations: IBK3, IBK4, IBK5
|
|
285
175
|
// blocks with their index sidecars; skills/shardborough-storage). A
|
|
@@ -322,7 +212,8 @@ class Store {
|
|
|
322
212
|
get closed() { return this._closed; }
|
|
323
213
|
|
|
324
214
|
_assertOpen(who) {
|
|
325
|
-
|
|
215
|
+
// The engine answers handle.disposed for a closed store handle.
|
|
216
|
+
if (this._closed) entryResult(this._e.storeHandleClose(this.handle), `Store.${who}`);
|
|
326
217
|
}
|
|
327
218
|
|
|
328
219
|
/**
|
|
@@ -333,7 +224,7 @@ class Store {
|
|
|
333
224
|
async query(sparql) {
|
|
334
225
|
this._assertOpen('query');
|
|
335
226
|
if (typeof sparql !== 'string') throw new TypeError('Store.query: sparql must be a string');
|
|
336
|
-
const run = () => entryResult(this._e.storeHandleQuery(this.handle, sparql), 'Store.query');
|
|
227
|
+
const run = () => entryResult(this._e.storeHandleQuery(this.handle, sparql), 'Store.query', sparql);
|
|
337
228
|
const r = this._withExtensionRounds ? await this._withExtensionRounds(run) : run();
|
|
338
229
|
if (r.kind === 'ask') return r.boolean;
|
|
339
230
|
if (r.kind === 'construct' || r.kind === 'describe') {
|
|
@@ -384,16 +275,24 @@ function buildApi(driver) {
|
|
|
384
275
|
entryPromise = Promise.resolve()
|
|
385
276
|
.then(() => driver.loadEntry())
|
|
386
277
|
.then((e) => {
|
|
387
|
-
if (!e) throw new
|
|
278
|
+
if (!e) throw new FactoidalError('factoidal: the engine loader returned no entry object', { code: 'host.io' });
|
|
388
279
|
return e;
|
|
389
280
|
})
|
|
390
|
-
.catch((err) => {
|
|
281
|
+
.catch((err) => {
|
|
282
|
+
entryPromise = undefined;
|
|
283
|
+
throw err instanceof FactoidalError ? err
|
|
284
|
+
: new FactoidalError(`factoidal: the engine did not load: ${err && err.message}`,
|
|
285
|
+
{ code: 'host.io', cause: err });
|
|
286
|
+
});
|
|
391
287
|
}
|
|
392
288
|
return entryPromise;
|
|
393
289
|
}
|
|
394
290
|
|
|
395
|
-
//
|
|
396
|
-
//
|
|
291
|
+
// The options object of a public function, checked by the engine (op
|
|
292
|
+
// apiCheck): unknown keys, format names, regimes, outputs and versions.
|
|
293
|
+
async function checkedOptions(who, options) {
|
|
294
|
+
return checkOptions(await entry(), who, options);
|
|
295
|
+
}
|
|
397
296
|
|
|
398
297
|
|
|
399
298
|
// ---------------------------------------------------------------
|
|
@@ -525,7 +424,7 @@ function buildApi(driver) {
|
|
|
525
424
|
if (typeof e.registerServiceEndpoint !== 'function') {
|
|
526
425
|
throw missingOpError('registerServiceEndpoint');
|
|
527
426
|
}
|
|
528
|
-
const opts =
|
|
427
|
+
const opts = await checkedOptions('registerServiceEndpoint', optionsOf('registerServiceEndpoint', options));
|
|
529
428
|
const nq = await nquadsOf(data, opts, 'registerServiceEndpoint');
|
|
530
429
|
return entryResult(e.registerServiceEndpoint(iri, nq),
|
|
531
430
|
'registerServiceEndpoint');
|
|
@@ -549,9 +448,9 @@ function buildApi(driver) {
|
|
|
549
448
|
const result = runOnce();
|
|
550
449
|
if (extPending.length === 0) return result;
|
|
551
450
|
if (round >= EXT_MAX_ROUNDS) {
|
|
552
|
-
throw new
|
|
451
|
+
throw new FactoidalError(
|
|
553
452
|
'extension functions: async resolution did not converge ' +
|
|
554
|
-
`within ${EXT_MAX_ROUNDS} evaluation rounds
|
|
453
|
+
`within ${EXT_MAX_ROUNDS} evaluation rounds`, { code: 'capacity.exceeded' });
|
|
555
454
|
}
|
|
556
455
|
const pend = extPending;
|
|
557
456
|
extPending = [];
|
|
@@ -585,15 +484,16 @@ function buildApi(driver) {
|
|
|
585
484
|
return out;
|
|
586
485
|
}
|
|
587
486
|
|
|
588
|
-
// A ShEx focus/shape-label argument is
|
|
589
|
-
// or "_:label"
|
|
590
|
-
// or an RDF/JS term (NamedNode/BlankNode); accepting
|
|
591
|
-
// caller pass a term straight out of a query() binding.
|
|
487
|
+
// A ShEx focus/shape-label argument is a string in N-Triples term syntax
|
|
488
|
+
// ("<http://...>" or "_:label"), which the engine reads with its one
|
|
489
|
+
// term-string reader, or an RDF/JS term (NamedNode/BlankNode); accepting
|
|
490
|
+
// both lets a caller pass a term straight out of a query() binding.
|
|
592
491
|
function shexTermToString(t, who) {
|
|
593
|
-
if (typeof t === 'string') return t;
|
|
492
|
+
if (typeof t === 'string') return JSON.stringify(termToJson(t));
|
|
594
493
|
if (t && typeof t.termType === 'string') {
|
|
595
|
-
if (t.termType === 'BlankNode'
|
|
596
|
-
|
|
494
|
+
if (t.termType === 'BlankNode' || t.termType === 'NamedNode') {
|
|
495
|
+
return JSON.stringify(termToJson(t)); // the engine writes the node
|
|
496
|
+
}
|
|
597
497
|
throw new TypeError(`${who}: expected an IRI or blank node term`);
|
|
598
498
|
}
|
|
599
499
|
throw new TypeError(`${who}: expected a string or an RDF/JS term`);
|
|
@@ -613,9 +513,21 @@ function buildApi(driver) {
|
|
|
613
513
|
async function ctx() {
|
|
614
514
|
const e = await entry();
|
|
615
515
|
if (ctxCache && ctxCache.e === e) return ctxCache;
|
|
516
|
+
let tablesCache = null;
|
|
616
517
|
const c = {
|
|
617
518
|
e,
|
|
618
519
|
registry,
|
|
520
|
+
tables() {
|
|
521
|
+
if (!tablesCache) {
|
|
522
|
+
requireEntryFn(e, 'engineTables', 'format and regime tables');
|
|
523
|
+
const t = entryResult(e.engineTables(), 'engineTables');
|
|
524
|
+
tablesCache = { ...t.tables, errorCodes: t.errorCodes || [],
|
|
525
|
+
errorModelExemptOps: t.errorModelExemptOps || [] };
|
|
526
|
+
for (const k of Object.keys(WRITER_TAGS)) delete WRITER_TAGS[k];
|
|
527
|
+
Object.assign(WRITER_TAGS, tablesCache.writerFormats);
|
|
528
|
+
}
|
|
529
|
+
return tablesCache;
|
|
530
|
+
},
|
|
619
531
|
missing: (what, op) => missingOpError(what, e, op),
|
|
620
532
|
wrap(r, prefixes, extra) {
|
|
621
533
|
const { ok: _ok, handle, count, prefixes: own, ...info } = r;
|
|
@@ -638,16 +550,34 @@ function buildApi(driver) {
|
|
|
638
550
|
async closure(ds, regime) { return closureOnHandle(c, ds, regime); },
|
|
639
551
|
};
|
|
640
552
|
ctxCache = c;
|
|
553
|
+
installTextEngine(e);
|
|
641
554
|
return c;
|
|
642
555
|
}
|
|
643
556
|
|
|
557
|
+
// rdfjs.mjs's N-Quads text functions (nquadsToQuads, quadsToNQuads,
|
|
558
|
+
// termToNQuads, DatasetCore.fromNQuads/toNQuads) call these engine ops.
|
|
559
|
+
function installTextEngine(e) {
|
|
560
|
+
if (typeof e.parseQuadsJson !== 'function') return;
|
|
561
|
+
_setTextEngine({
|
|
562
|
+
parseQuads(text) {
|
|
563
|
+
return parseResult(e.parseQuadsJson(text, 'nquads12', ''), 'nquadsToQuads', text).quads;
|
|
564
|
+
},
|
|
565
|
+
writeQuads(quadsJson) {
|
|
566
|
+
return entryResult(e.quadsToNQuads(JSON.stringify(quadsJson)), 'quadsToNQuads').nquads;
|
|
567
|
+
},
|
|
568
|
+
termTokens(termsJson) {
|
|
569
|
+
return entryResult(e.termsToNTriples(JSON.stringify(termsJson)), 'termToNQuads').tokens;
|
|
570
|
+
},
|
|
571
|
+
});
|
|
572
|
+
}
|
|
573
|
+
|
|
644
574
|
// The parse tag of `format`, or the engine's inference when it is omitted.
|
|
645
575
|
function formatTagOf(c, text, format, who) {
|
|
646
576
|
if (format === undefined || format === null || format === '') {
|
|
647
577
|
requireEntryFn(c.e, 'detectFormat', `${who} (format inference)`);
|
|
648
578
|
return { tag: entryResult(c.e.detectFormat(text), who).format, inferred: true };
|
|
649
579
|
}
|
|
650
|
-
return { tag:
|
|
580
|
+
return { tag: parseTagOf(c.e, c.tables(), format, who), inferred: false };
|
|
651
581
|
}
|
|
652
582
|
|
|
653
583
|
// Open `text` as a Dataset. A parse error names the format and says
|
|
@@ -659,11 +589,10 @@ function buildApi(driver) {
|
|
|
659
589
|
try {
|
|
660
590
|
r = parseResult(c.e.datasetOpen(text, tag, baseIRI || ''), who, text);
|
|
661
591
|
} catch (err) {
|
|
662
|
-
if (
|
|
663
|
-
err.
|
|
664
|
-
err.
|
|
592
|
+
if (err instanceof FactoidalError) {
|
|
593
|
+
err.formatInferred = inferred;
|
|
594
|
+
err.format = err.format || tag;
|
|
665
595
|
}
|
|
666
|
-
err.format = err.format || tag;
|
|
667
596
|
throw err;
|
|
668
597
|
}
|
|
669
598
|
return c.wrap(r, undefined, { format: tag, formatInferred: inferred });
|
|
@@ -713,49 +642,29 @@ function buildApi(driver) {
|
|
|
713
642
|
|
|
714
643
|
async function queryDatasetHandle(c, ds, sparql, opts) {
|
|
715
644
|
if (typeof sparql !== 'string') throw new TypeError('query: sparql must be a string');
|
|
645
|
+
// The options were checked by the engine (op apiCheck, as 'query' or
|
|
646
|
+
// 'Dataset.query'): regime, version, output and their combination.
|
|
716
647
|
const entail = opts.entail || 'none';
|
|
717
|
-
if (/^x-ikl/i.test(entail)) {
|
|
718
|
-
throw new TypeError(
|
|
719
|
-
`query: entail '${entail}' is not implemented. The x-ikl-* ` +
|
|
720
|
-
"entailment regimes are the owner's design " +
|
|
721
|
-
"(danbri/factoidal#581); the Lean engine's dispatch for them " +
|
|
722
|
-
'was deleted on 2026-08-26 as collateral of the IKL-to-RDF ' +
|
|
723
|
-
'projection purge (danbri/factoidal#626). This is not a ' +
|
|
724
|
-
'policy exclusion.');
|
|
725
|
-
}
|
|
726
|
-
if (!ENTAIL_VALUES.has(entail)) {
|
|
727
|
-
throw new TypeError(`query: entail must be one of ${[...ENTAIL_VALUES].join(', ')}`);
|
|
728
|
-
}
|
|
729
|
-
if (opts.version !== undefined && !['1.1', '1.2'].includes(String(opts.version))) {
|
|
730
|
-
throw new TypeError("query: version must be '1.1' or '1.2'");
|
|
731
|
-
}
|
|
732
648
|
const sparql12 = opts.sparql12 === true || String(opts.version || '') === '1.2';
|
|
733
649
|
const e = c.e;
|
|
734
650
|
if (entail !== 'none' || opts.output !== undefined) {
|
|
735
651
|
// queryRaw over the stored dataset: an entailment regime, or a
|
|
736
652
|
// results format (SPARQL 1.1 Query Results JSON, XML, CSV, TSV).
|
|
737
|
-
if (sparql12) {
|
|
738
|
-
throw new TypeError(
|
|
739
|
-
"query: entail/output and SPARQL 1.2 cannot be combined; that path reads SPARQL 1.1");
|
|
740
|
-
}
|
|
741
653
|
const output = opts.output || 'json';
|
|
742
|
-
|
|
743
|
-
throw new TypeError(`query: output must be one of ${[...RAW_OUTPUT_FORMATS].join(', ')}`);
|
|
744
|
-
}
|
|
745
|
-
const form = sniffQueryForm(sparql);
|
|
654
|
+
const form = queryFormOf(e, sparql);
|
|
746
655
|
const graphForm = form === 'construct' || form === 'describe';
|
|
747
656
|
requireEntryFn(e, 'datasetQueryRaw', `query {entail/output}`);
|
|
748
657
|
if (opts.output === undefined) {
|
|
749
658
|
// An entailment regime with the default answer shape.
|
|
750
659
|
const r = entryResult(e.datasetQueryRaw(ds.handle, sparql, JSON.stringify({
|
|
751
|
-
entail, output: graphForm ? 'ntriples' : 'json' })), 'query');
|
|
660
|
+
entail, output: graphForm ? 'ntriples' : 'json' })), 'query', sparql);
|
|
752
661
|
if (graphForm) return c.fromNQuads(r.text, ds.prefixes);
|
|
753
662
|
const srj = JSON.parse(r.text);
|
|
754
663
|
if (typeof srj.boolean === 'boolean') return srj.boolean;
|
|
755
664
|
return bindingsFromSrj(srj);
|
|
756
665
|
}
|
|
757
666
|
const r = entryResult(e.datasetQueryRaw(ds.handle, sparql,
|
|
758
|
-
JSON.stringify({ entail, output })), 'query');
|
|
667
|
+
JSON.stringify({ entail, output })), 'query', sparql);
|
|
759
668
|
return output === 'json' && !graphForm ? JSON.parse(r.text) : r.text;
|
|
760
669
|
}
|
|
761
670
|
const fn = sparql12 ? e.datasetQuery12 : e.datasetQuery;
|
|
@@ -763,7 +672,7 @@ function buildApi(driver) {
|
|
|
763
672
|
throw missingOpError(`query (datasetQuery${sparql12 ? '12' : ''})`, e,
|
|
764
673
|
sparql12 ? 'datasetQuery12' : 'datasetQuery');
|
|
765
674
|
}
|
|
766
|
-
const r = await withExtensionRounds(() => entryResult(fn(ds.handle, sparql), 'query'));
|
|
675
|
+
const r = await withExtensionRounds(() => entryResult(fn(ds.handle, sparql), 'query', sparql));
|
|
767
676
|
if (r.kind === 'ask') return r.boolean;
|
|
768
677
|
if (r.kind === 'construct' || r.kind === 'describe') {
|
|
769
678
|
return c.fromNQuads(r.nquads, ds.prefixes);
|
|
@@ -791,18 +700,9 @@ function buildApi(driver) {
|
|
|
791
700
|
c.e.datasetShexValidate(ds.handle, schema, focusStr, shapeStr), 'shexValidate').verdict;
|
|
792
701
|
}
|
|
793
702
|
|
|
794
|
-
const CLOSURE_REGIMES = {
|
|
795
|
-
rdfs: 'rdfs', 'owl-rl': 'owl-rl', owlrl: 'owl-rl', owl_rl: 'owl-rl',
|
|
796
|
-
'rho-df': 'rho-df', rhodf: 'rho-df', 'core-rdfs': 'rho-df',
|
|
797
|
-
'rdfs-plus': 'rdfs-plus', rdfsplus: 'rdfs-plus',
|
|
798
|
-
};
|
|
799
|
-
|
|
800
703
|
async function closureOnHandle(c, ds, regime) {
|
|
801
|
-
const r0 =
|
|
802
|
-
if (!r0) {
|
|
803
|
-
throw new TypeError(
|
|
804
|
-
`closure: regime must be one of rdfs, owl-rl, rho-df, rdfs-plus (got '${regime}')`);
|
|
805
|
-
}
|
|
704
|
+
const r0 = c.tables().closureAliases[String(regime || '').toLowerCase()];
|
|
705
|
+
if (!r0) checkOptions(c.e, 'Dataset.closure', { regime: String(regime == null ? '' : regime) });
|
|
806
706
|
requireEntryFn(c.e, 'datasetClosure', 'closure');
|
|
807
707
|
const r = entryResult(c.e.datasetClosure(ds.handle, r0), 'closure');
|
|
808
708
|
return c.wrap(r, ds.prefixes);
|
|
@@ -813,7 +713,7 @@ function buildApi(driver) {
|
|
|
813
713
|
|
|
814
714
|
/**
|
|
815
715
|
* Parse one RDF document into a Dataset. Strict by default: a syntax
|
|
816
|
-
* error rejects with a
|
|
716
|
+
* error rejects with a FactoidalError (`code`, `position`, `spec`; for Turtle,
|
|
817
717
|
* TriG, N-Triples and N-Quads). `{lenient:true}` skips each bad statement
|
|
818
718
|
* of Turtle, TriG, N-Triples and N-Quads and lists one diagnostic per
|
|
819
719
|
* skipped statement in `dataset.diagnostics`
|
|
@@ -827,8 +727,7 @@ function buildApi(driver) {
|
|
|
827
727
|
*/
|
|
828
728
|
async function parse(text, options) {
|
|
829
729
|
if (typeof text !== 'string') throw new TypeError('parse: text must be a string');
|
|
830
|
-
const opts =
|
|
831
|
-
['format', 'baseIRI', 'lenient', 'maxErrors']);
|
|
730
|
+
const opts = await checkedOptions('parse', optionsOf('parse', options));
|
|
832
731
|
const c = await ctx();
|
|
833
732
|
if (opts.lenient) {
|
|
834
733
|
const { tag, inferred } = formatTagOf(c, text, opts.format, 'parse');
|
|
@@ -856,7 +755,7 @@ function buildApi(driver) {
|
|
|
856
755
|
* @returns {Promise<Dataset>}
|
|
857
756
|
*/
|
|
858
757
|
async function openDataset(data, options) {
|
|
859
|
-
const opts =
|
|
758
|
+
const opts = await checkedOptions('openDataset', optionsOf('openDataset', options));
|
|
860
759
|
const c = await ctx();
|
|
861
760
|
if (data instanceof Dataset) return data.clone();
|
|
862
761
|
return datasetOf(c, data, opts, 'openDataset').ds;
|
|
@@ -876,8 +775,7 @@ function buildApi(driver) {
|
|
|
876
775
|
*/
|
|
877
776
|
async function query(data, sparql, options) {
|
|
878
777
|
if (typeof sparql !== 'string') throw new TypeError('query: sparql must be a string');
|
|
879
|
-
const opts =
|
|
880
|
-
['format', 'baseIRI', 'entail', 'sparql12', 'version', 'output']);
|
|
778
|
+
const opts = await checkedOptions('query', optionsOf('query', options));
|
|
881
779
|
return withDataset(data, opts, 'query', (c, ds) => queryDatasetHandle(c, ds, sparql, opts));
|
|
882
780
|
}
|
|
883
781
|
|
|
@@ -892,15 +790,11 @@ function buildApi(driver) {
|
|
|
892
790
|
if (typeof sparql !== 'string') {
|
|
893
791
|
throw new TypeError('queryHdt: sparql must be a string');
|
|
894
792
|
}
|
|
895
|
-
const form = sniffQueryForm(sparql);
|
|
896
|
-
if (form === 'construct' || form === 'describe') {
|
|
897
|
-
throw new TypeError(
|
|
898
|
-
`queryHdt: ${form.toUpperCase()} is not supported over an HDT file (SELECT/ASK only)`);
|
|
899
|
-
}
|
|
900
793
|
const e = await entry();
|
|
901
794
|
requireEntryFn(e, 'queryHdt', 'queryHdt');
|
|
902
795
|
const r = entryResult(e.queryHdt(bytesToUint8Array(hdtBytes, 'queryHdt'), sparql), 'queryHdt');
|
|
903
796
|
if (r.kind === 'ask') return r.boolean;
|
|
797
|
+
if (r.kind === 'construct' || r.kind === 'describe') return (await ctx()).fromNQuads(r.nquads, {});
|
|
904
798
|
return bindingsFromSrj(r.srj);
|
|
905
799
|
}
|
|
906
800
|
|
|
@@ -914,7 +808,7 @@ function buildApi(driver) {
|
|
|
914
808
|
*/
|
|
915
809
|
async function update(data, updateText, options) {
|
|
916
810
|
if (typeof updateText !== 'string') throw new TypeError('update: updateText must be a string');
|
|
917
|
-
const opts =
|
|
811
|
+
const opts = await checkedOptions('update', optionsOf('update', options));
|
|
918
812
|
const c = await ctx();
|
|
919
813
|
const { ds, temp } = datasetOf(c, data, opts, 'update');
|
|
920
814
|
const out = temp ? ds : ds.clone();
|
|
@@ -938,14 +832,8 @@ function buildApi(driver) {
|
|
|
938
832
|
* @returns {Promise<string>}
|
|
939
833
|
*/
|
|
940
834
|
async function serialize(data, options) {
|
|
941
|
-
const opts =
|
|
942
|
-
['format', 'version', 'prefixes', 'literalShorthand', 'useNativeTypes',
|
|
943
|
-
'useRdfType', 'rdfDirection', 'inputFormat', 'baseIRI']);
|
|
835
|
+
const opts = await checkedOptions('serialize', optionsOf('serialize', options));
|
|
944
836
|
const { inputFormat, baseIRI, ...writeOpts } = opts;
|
|
945
|
-
if (writeOpts.format !== undefined && !WRITER_TAGS[String(writeOpts.format).toLowerCase()]) {
|
|
946
|
-
throw new TypeError(`serialize: unknown format '${writeOpts.format}'. Known formats: ` +
|
|
947
|
-
[...new Set(Object.values(WRITER_TAGS))].join(', '));
|
|
948
|
-
}
|
|
949
837
|
return withDataset(data, { format: inputFormat, baseIRI }, 'serialize',
|
|
950
838
|
(_c, ds) => ds.serialize(writeOpts));
|
|
951
839
|
}
|
|
@@ -957,7 +845,7 @@ function buildApi(driver) {
|
|
|
957
845
|
* @returns {Promise<string>}
|
|
958
846
|
*/
|
|
959
847
|
async function canonicalize(data, options) {
|
|
960
|
-
const opts =
|
|
848
|
+
const opts = await checkedOptions('canonicalize', optionsOf('canonicalize', options));
|
|
961
849
|
return withDataset(data, opts, 'canonicalize', (_c, ds) => ds.toString('rdfc'));
|
|
962
850
|
}
|
|
963
851
|
|
|
@@ -965,24 +853,24 @@ function buildApi(driver) {
|
|
|
965
853
|
* The named graphs of a Dataset, each as a Dataset (default graph
|
|
966
854
|
* excluded, first-seen order).
|
|
967
855
|
* @param {Dataset} dataset
|
|
968
|
-
* @returns {Array<[
|
|
856
|
+
* @returns {Array<[name: NamedNode|BlankNode, graph: Dataset]>}
|
|
969
857
|
*/
|
|
970
858
|
function graphs(dataset) {
|
|
971
859
|
if (!(dataset instanceof Dataset)) throw new TypeError('graphs: expected a Dataset');
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
return out;
|
|
860
|
+
dataset.size; // throws the disposed error
|
|
861
|
+
const c = dataset._ctx;
|
|
862
|
+
requireEntryFn(c.e, 'datasetGraphNames', 'graphs');
|
|
863
|
+
const names = entryResult(c.e.datasetGraphNames(dataset.handle), 'graphs').graphs;
|
|
864
|
+
return names.map((g) => {
|
|
865
|
+
const term = termFromSrj(g);
|
|
866
|
+
return [term, dataset.match(null, null, null, term)];
|
|
867
|
+
});
|
|
981
868
|
}
|
|
982
869
|
|
|
983
870
|
/**
|
|
984
871
|
* RDFC-1.0 canonical N-Quads of one graph: every quad's graph name is
|
|
985
|
-
* dropped first
|
|
872
|
+
* dropped first (op datasetGraphAsDefault with the union of the graphs).
|
|
873
|
+
* Text, not a digest.
|
|
986
874
|
* @param {Dataset} datasetOrGraph
|
|
987
875
|
* @returns {Promise<string>}
|
|
988
876
|
*/
|
|
@@ -990,9 +878,59 @@ function buildApi(driver) {
|
|
|
990
878
|
if (!(datasetOrGraph instanceof Dataset)) {
|
|
991
879
|
throw new TypeError('canonicalHash: expected a Dataset (e.g. one entry of graphs())');
|
|
992
880
|
}
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
881
|
+
datasetOrGraph.size; // throws the disposed error
|
|
882
|
+
const c = datasetOrGraph._ctx;
|
|
883
|
+
requireEntryFn(c.e, 'datasetGraphAsDefault', 'canonicalHash');
|
|
884
|
+
const merged = c.wrap(entryResult(c.e.datasetGraphAsDefault(datasetOrGraph.handle,
|
|
885
|
+
JSON.stringify({ type: 'union' })), 'canonicalHash'), {});
|
|
886
|
+
try {
|
|
887
|
+
return merged.toString('rdfc');
|
|
888
|
+
} finally {
|
|
889
|
+
merged.dispose();
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
/**
|
|
894
|
+
* Whether two datasets are isomorphic (RDF 1.1 Concepts 3.6 and 4; blank
|
|
895
|
+
* nodes inside RDF 1.2 triple terms included): the engine's
|
|
896
|
+
* Dataset.isomorphicOutcome (op datasetIsomorphic). Rejects when the
|
|
897
|
+
* blank-node search budget is exceeded.
|
|
898
|
+
* @param {Dataset|string|Array} a
|
|
899
|
+
* @param {Dataset|string|Array} b
|
|
900
|
+
* @param {{format?: string, baseIRI?: string}} [options] read text arguments
|
|
901
|
+
* @returns {Promise<boolean>}
|
|
902
|
+
*/
|
|
903
|
+
async function isomorphic(a, b, options) {
|
|
904
|
+
const opts = await checkedOptions('isomorphic', optionsOf('isomorphic', options));
|
|
905
|
+
return withDataset(a, opts, 'isomorphic', (c, da) =>
|
|
906
|
+
withDataset(b, opts, 'isomorphic', (_c, db) => {
|
|
907
|
+
requireEntryFn(c.e, 'datasetIsomorphic', 'isomorphic');
|
|
908
|
+
return entryResult(c.e.datasetIsomorphic(da.handle, db.handle), 'isomorphic').isomorphic;
|
|
909
|
+
}));
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
/**
|
|
913
|
+
* A Dataset holding RDF/JS quads (op datasetFromQuadsJson). Each term is
|
|
914
|
+
* sent as its components; the engine reads no text.
|
|
915
|
+
* @param {Iterable<object>} quads
|
|
916
|
+
* @returns {Promise<Dataset>}
|
|
917
|
+
*/
|
|
918
|
+
async function fromQuads(quads) {
|
|
919
|
+
const c = await ctx();
|
|
920
|
+
requireEntryFn(c.e, 'datasetFromQuadsJson', 'fromQuads');
|
|
921
|
+
const arr = [];
|
|
922
|
+
for (const q of quads) arr.push(quadToJson(q));
|
|
923
|
+
return c.wrap(entryResult(c.e.datasetFromQuadsJson(JSON.stringify(arr)), 'fromQuads'), {});
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
/** Load the engine; afterwards the N-Quads text functions of `@factoidal/core/rdfjs` work. */
|
|
927
|
+
async function ready() {
|
|
928
|
+
await ctx();
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
/** The engine's name tables (formats, regimes, query outputs, pack syntaxes). */
|
|
932
|
+
async function engineTables() {
|
|
933
|
+
return (await ctx()).tables();
|
|
996
934
|
}
|
|
997
935
|
|
|
998
936
|
// A wasm module older than this package can lack an op: `e[fnName]` is
|
|
@@ -1009,7 +947,7 @@ function buildApi(driver) {
|
|
|
1009
947
|
* @returns {Promise<{conforms: boolean, report: Dataset}>}
|
|
1010
948
|
*/
|
|
1011
949
|
async function shaclValidate(data, shapes, options) {
|
|
1012
|
-
const opts =
|
|
950
|
+
const opts = await checkedOptions('shaclValidate', optionsOf('shaclValidate', options));
|
|
1013
951
|
return withDataset(data, opts, 'shaclValidate(data)', (c, ds) => shaclOnHandle(c, ds, shapes, opts));
|
|
1014
952
|
}
|
|
1015
953
|
|
|
@@ -1025,7 +963,7 @@ function buildApi(driver) {
|
|
|
1025
963
|
* @returns {Promise<boolean>}
|
|
1026
964
|
*/
|
|
1027
965
|
async function shexValidate(data, schema, focus, shape, options) {
|
|
1028
|
-
const opts =
|
|
966
|
+
const opts = await checkedOptions('shexValidate', optionsOf('shexValidate', options));
|
|
1029
967
|
if (typeof schema !== 'string') throw new TypeError('shexValidate: schema must be a string');
|
|
1030
968
|
return withDataset(data, opts, 'shexValidate(data)', (c, ds) => shexOnHandle(c, ds, schema, focus, shape));
|
|
1031
969
|
}
|
|
@@ -1038,7 +976,7 @@ function buildApi(driver) {
|
|
|
1038
976
|
* @returns {Promise<Dataset>}
|
|
1039
977
|
*/
|
|
1040
978
|
async function closure(data, regime, options) {
|
|
1041
|
-
const opts =
|
|
979
|
+
const opts = await checkedOptions('closure', optionsOf('closure', options));
|
|
1042
980
|
return withDataset(data, opts, 'closure', (c, ds) => closureOnHandle(c, ds, regime));
|
|
1043
981
|
}
|
|
1044
982
|
|
|
@@ -1051,9 +989,8 @@ function buildApi(driver) {
|
|
|
1051
989
|
*/
|
|
1052
990
|
async function owlClosure(data, mode, options) {
|
|
1053
991
|
const m = String(mode || '').toLowerCase();
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
}
|
|
992
|
+
// The engine checks the mode against its regime table (op apiCheck).
|
|
993
|
+
await checkedOptions('owlClosure', { mode: String(mode == null ? '' : mode) });
|
|
1057
994
|
return closure(data, m, options);
|
|
1058
995
|
}
|
|
1059
996
|
|
|
@@ -1077,7 +1014,7 @@ function buildApi(driver) {
|
|
|
1077
1014
|
* @returns {Promise<{ok: boolean, fragment: boolean}>}
|
|
1078
1015
|
*/
|
|
1079
1016
|
async function coreRdfsCheck(data, options) {
|
|
1080
|
-
const opts =
|
|
1017
|
+
const opts = await checkedOptions('coreRdfsCheck', optionsOf('coreRdfsCheck', options));
|
|
1081
1018
|
const nq = await nquadsOf(data, opts, 'coreRdfsCheck(data)');
|
|
1082
1019
|
const e = await entry();
|
|
1083
1020
|
requireEntryFn(e, 'rhoDfFragmentCheck', 'core-RDFS fragment check');
|
|
@@ -1105,7 +1042,7 @@ function buildApi(driver) {
|
|
|
1105
1042
|
* @returns {Promise<{dataset: Dataset, addedCount: number, budgetHit?: boolean}>}
|
|
1106
1043
|
*/
|
|
1107
1044
|
async function tableauMaterialise(data, options) {
|
|
1108
|
-
const opts =
|
|
1045
|
+
const opts = await checkedOptions('tableauMaterialise', optionsOf('tableauMaterialise', options));
|
|
1109
1046
|
const nq = await nquadsOf(data, opts, 'tableauMaterialise(data)');
|
|
1110
1047
|
const c = await ctx();
|
|
1111
1048
|
requireEntryFn(c.e, 'tableauMaterialise', 'OWL tableau materialisation');
|
|
@@ -1125,7 +1062,7 @@ function buildApi(driver) {
|
|
|
1125
1062
|
* @returns {Promise<{inconsistent: boolean, rlAlone: boolean}>}
|
|
1126
1063
|
*/
|
|
1127
1064
|
async function tableauDlInconsistent(data, options) {
|
|
1128
|
-
const opts =
|
|
1065
|
+
const opts = await checkedOptions('tableauDlInconsistent', optionsOf('tableauDlInconsistent', options));
|
|
1129
1066
|
const nq = await nquadsOf(data, opts, 'tableauDlInconsistent(data)');
|
|
1130
1067
|
const e = await entry();
|
|
1131
1068
|
requireEntryFn(e, 'tableauDlInconsistent', 'OWL tableau DL inconsistency check');
|
|
@@ -1141,7 +1078,7 @@ function buildApi(driver) {
|
|
|
1141
1078
|
* @returns {Promise<{consistent: boolean|null, reason?: string}>}
|
|
1142
1079
|
*/
|
|
1143
1080
|
async function owlIsConsistent(data, options) {
|
|
1144
|
-
const opts =
|
|
1081
|
+
const opts = await checkedOptions('owlIsConsistent', optionsOf('owlIsConsistent', options));
|
|
1145
1082
|
const nq = await nquadsOf(data, opts, 'owlIsConsistent(data)');
|
|
1146
1083
|
const e = await entry();
|
|
1147
1084
|
requireEntryFn(e, 'owlIsConsistent', 'OWL DL consistency check');
|
|
@@ -1161,7 +1098,7 @@ function buildApi(driver) {
|
|
|
1161
1098
|
* @returns {Promise<{entailed: boolean|null, via: 'closure'|'refutation', reason?: string}>}
|
|
1162
1099
|
*/
|
|
1163
1100
|
async function owlEntails(premise, conclusion, options) {
|
|
1164
|
-
const opts =
|
|
1101
|
+
const opts = await checkedOptions('owlEntails', optionsOf('owlEntails', options));
|
|
1165
1102
|
const premiseNq = await nquadsOf(premise, opts, 'owlEntails(premise)');
|
|
1166
1103
|
const conclusionNq = await nquadsOf(conclusion, opts, 'owlEntails(conclusion)');
|
|
1167
1104
|
const e = await entry();
|
|
@@ -1185,8 +1122,8 @@ function buildApi(driver) {
|
|
|
1185
1122
|
async function rmlMap(mapping, sourceData, sourceKind, options) {
|
|
1186
1123
|
if (typeof sourceData !== 'string') throw new TypeError('rmlMap: sourceData must be a string');
|
|
1187
1124
|
const kind = String(sourceKind || '').toLowerCase();
|
|
1188
|
-
|
|
1189
|
-
const opts =
|
|
1125
|
+
await checkedOptions('rmlMap', { sourceKind: kind });
|
|
1126
|
+
const opts = await checkedOptions('rmlMap', optionsOf('rmlMap', options));
|
|
1190
1127
|
return withDataset(mapping, opts, 'rmlMap(mapping)', (c, ds) => {
|
|
1191
1128
|
requireEntryFn(c.e, 'datasetFromRml', 'RML mapping evaluation');
|
|
1192
1129
|
return c.wrap(entryResult(c.e.datasetFromRml(ds.handle, sourceData, kind), 'rmlMap'), {});
|
|
@@ -1206,7 +1143,7 @@ function buildApi(driver) {
|
|
|
1206
1143
|
if (typeof csvText !== 'string') throw new TypeError('csvwToRdf: csvText must be a string');
|
|
1207
1144
|
const meta = metadataJson == null ? '' : metadataJson;
|
|
1208
1145
|
if (typeof meta !== 'string') throw new TypeError('csvwToRdf: metadataJson must be a string');
|
|
1209
|
-
const opts =
|
|
1146
|
+
const opts = await checkedOptions('csvwToRdf', options);
|
|
1210
1147
|
const c = await ctx();
|
|
1211
1148
|
requireEntryFn(c.e, 'datasetFromCsvw', 'CSVW csv2rdf conversion');
|
|
1212
1149
|
const optionsJson = JSON.stringify({
|
|
@@ -1227,7 +1164,7 @@ function buildApi(driver) {
|
|
|
1227
1164
|
*/
|
|
1228
1165
|
async function jsonldToRdf(jsonldText, options) {
|
|
1229
1166
|
if (typeof jsonldText !== 'string') throw new TypeError('jsonldToRdf: jsonldText must be a string');
|
|
1230
|
-
const opts =
|
|
1167
|
+
const opts = await checkedOptions('jsonldToRdf', options);
|
|
1231
1168
|
const c = await ctx();
|
|
1232
1169
|
requireEntryFn(c.e, 'datasetFromJsonLd', 'jsonldToRdf');
|
|
1233
1170
|
const optionsJson = JSON.stringify({
|
|
@@ -1250,7 +1187,7 @@ function buildApi(driver) {
|
|
|
1250
1187
|
*/
|
|
1251
1188
|
async function rifEval(data, rifRulesXml, options) {
|
|
1252
1189
|
if (typeof rifRulesXml !== 'string') throw new TypeError('rifEval: rifRulesXml must be a string');
|
|
1253
|
-
const opts =
|
|
1190
|
+
const opts = await checkedOptions('rifEval', optionsOf('rifEval', options));
|
|
1254
1191
|
return withDataset(data, opts, 'rifEval(data)', (c, ds) => {
|
|
1255
1192
|
requireEntryFn(c.e, 'datasetRifEval', 'RIF Core evaluation');
|
|
1256
1193
|
return c.wrap(entryResult(c.e.datasetRifEval(rifRulesXml, ds.handle), 'rifEval'), ds.prefixes);
|
|
@@ -1266,8 +1203,7 @@ function buildApi(driver) {
|
|
|
1266
1203
|
* @returns {Promise<any>}
|
|
1267
1204
|
*/
|
|
1268
1205
|
async function jsonldFromRdf(data, options) {
|
|
1269
|
-
const opts =
|
|
1270
|
-
['useNativeTypes', 'useRdfType', 'rdfDirection', 'format', 'baseIRI']);
|
|
1206
|
+
const opts = await checkedOptions('jsonldFromRdf', optionsOf('jsonldFromRdf', options));
|
|
1271
1207
|
const { format, baseIRI, ...w } = opts;
|
|
1272
1208
|
return withDataset(data, { format, baseIRI }, 'jsonldFromRdf(data)',
|
|
1273
1209
|
(_c, ds) => JSON.parse(ds.toString({ format: 'jsonld', ...w })));
|
|
@@ -1980,28 +1916,16 @@ function buildApi(driver) {
|
|
|
1980
1916
|
if (typeof queryString !== 'string') {
|
|
1981
1917
|
throw new TypeError('queryRaw: queryString must be a string');
|
|
1982
1918
|
}
|
|
1983
|
-
const opts =
|
|
1919
|
+
const opts = await checkedOptions('queryRaw', options);
|
|
1984
1920
|
const dataFormat = String(opts.dataFormat || 'turtle').toLowerCase();
|
|
1985
1921
|
const entail = opts.entail || 'none';
|
|
1986
1922
|
const output = opts.output || 'json';
|
|
1987
|
-
|
|
1988
|
-
throw new TypeError(`queryRaw: unknown dataFormat '${opts.dataFormat}'`);
|
|
1989
|
-
}
|
|
1990
|
-
if (!ENTAIL_VALUES.has(entail)) {
|
|
1991
|
-
throw new TypeError(`queryRaw: entail must be one of ${[...ENTAIL_VALUES].join(', ')}`);
|
|
1992
|
-
}
|
|
1993
|
-
if (!RAW_OUTPUT_FORMATS.has(output)) {
|
|
1994
|
-
throw new TypeError(`queryRaw: output must be one of ${[...RAW_OUTPUT_FORMATS].join(', ')}`);
|
|
1995
|
-
}
|
|
1923
|
+
const tables = (await ctx()).tables();
|
|
1996
1924
|
const e = await entry();
|
|
1997
1925
|
requireEntryFn(e, 'queryRaw', 'queryRaw');
|
|
1998
|
-
const r =
|
|
1999
|
-
JSON.stringify({ dataFormat:
|
|
2000
|
-
|
|
2001
|
-
const err = new Error('SPARQL query failed: ' + r.error);
|
|
2002
|
-
err.stderr = String(r.error);
|
|
2003
|
-
throw err;
|
|
2004
|
-
}
|
|
1926
|
+
const r = entryResult(e.queryRaw(dataString, queryString,
|
|
1927
|
+
JSON.stringify({ dataFormat: tables.rawDataFormats[dataFormat], entail, output })),
|
|
1928
|
+
'queryRaw', queryString);
|
|
2005
1929
|
return output === 'json' ? JSON.parse(r.text) : r.text;
|
|
2006
1930
|
}
|
|
2007
1931
|
|
|
@@ -2280,10 +2204,13 @@ function buildApi(driver) {
|
|
|
2280
2204
|
deltaLogDestroy,
|
|
2281
2205
|
_deltaLogCorruptLastForTest,
|
|
2282
2206
|
queryRaw,
|
|
2207
|
+
isomorphic,
|
|
2208
|
+
fromQuads,
|
|
2209
|
+
ready,
|
|
2210
|
+
engineTables,
|
|
2283
2211
|
Dataset,
|
|
2284
|
-
DatasetHandle,
|
|
2285
2212
|
Store,
|
|
2286
|
-
|
|
2213
|
+
FactoidalError,
|
|
2287
2214
|
dataFactory,
|
|
2288
2215
|
// Metadata (issue #682): the same two fields on every driver's
|
|
2289
2216
|
// typed surface, so a caller can log/report which package version
|
|
@@ -2295,6 +2222,6 @@ function buildApi(driver) {
|
|
|
2295
2222
|
}
|
|
2296
2223
|
|
|
2297
2224
|
export {
|
|
2298
|
-
buildApi,
|
|
2299
|
-
|
|
2225
|
+
buildApi, bindingsFromSrj, entryResult, parseResult,
|
|
2226
|
+
missingOpError, FactoidalError, Store,
|
|
2300
2227
|
};
|