@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/rdfjs.mjs
CHANGED
|
@@ -6,22 +6,23 @@
|
|
|
6
6
|
// terms with spec-compliant `termType` / `value` / `language` /
|
|
7
7
|
// `datatype` and `.equals()`. Self-contained — no runtime deps.
|
|
8
8
|
//
|
|
9
|
-
// Also
|
|
10
|
-
// N-Quads
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
9
|
+
// Also: the field copy between RDF/JS terms and the engine's term objects
|
|
10
|
+
// (Lean L4Factoidal.RDF.TermJson), and N-Quads text in and out through
|
|
11
|
+
// engine ops. This file reads and writes no RDF syntax itself: no escaping,
|
|
12
|
+
// no tokenising (https://github.com/danbri/factoidal/issues/894). The text
|
|
13
|
+
// functions need the engine, which lib/api.mjs installs when it loads.
|
|
14
14
|
//
|
|
15
|
-
// ES module (0.9.0): the same file serves Node (index.mjs, and
|
|
16
|
-
//
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
//
|
|
21
|
-
|
|
22
|
-
const XSD_STRING = 'http://www.w3.org/2001/XMLSchema#string';
|
|
15
|
+
// ES module (0.9.0): the same file serves Node (index.mjs, and rdfjs.js for
|
|
16
|
+
// require()) and the browser (browser.js), with no build step.
|
|
17
|
+
|
|
18
|
+
import { FactoidalError } from './lib/errors.mjs';
|
|
19
|
+
|
|
20
|
+
// RDF/JS Data Model defaults of DataFactory.literal.
|
|
21
|
+
const XSD_STRING = 'http://www.w3.org/2001/XMLSchema#string'; // purity-lint: allow RDF/JS DataFactory default
|
|
23
22
|
const RDF_LANGSTRING =
|
|
24
|
-
'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString';
|
|
23
|
+
'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString'; // purity-lint: allow RDF/JS DataFactory default
|
|
24
|
+
const RDF_DIRLANGSTRING =
|
|
25
|
+
'http://www.w3.org/1999/02/22-rdf-syntax-ns#dirLangString'; // purity-lint: allow RDF/JS DataFactory default
|
|
25
26
|
|
|
26
27
|
// ---------------------------------------------------------------------
|
|
27
28
|
// Terms
|
|
@@ -52,18 +53,23 @@ class BlankNode {
|
|
|
52
53
|
}
|
|
53
54
|
|
|
54
55
|
class Literal {
|
|
55
|
-
constructor(value, language, datatype) {
|
|
56
|
+
constructor(value, language, datatype, direction) {
|
|
56
57
|
this.termType = 'Literal';
|
|
57
58
|
this.value = value;
|
|
58
59
|
this.language = language || '';
|
|
60
|
+
// RDF/JS Data Model DataFactory.literal: no datatype argument means
|
|
61
|
+
// xsd:string, a language means rdf:langString, a language and a
|
|
62
|
+
// direction mean rdf:dirLangString.
|
|
59
63
|
this.datatype = datatype ||
|
|
60
|
-
new NamedNode(language ? RDF_LANGSTRING : XSD_STRING);
|
|
64
|
+
new NamedNode(language ? (direction ? RDF_DIRLANGSTRING : RDF_LANGSTRING) : XSD_STRING); // purity-lint: allow RDF/JS DataFactory default
|
|
65
|
+
this.direction = direction || '';
|
|
61
66
|
Object.freeze(this);
|
|
62
67
|
}
|
|
63
68
|
equals(other) {
|
|
64
69
|
return !!other && other.termType === 'Literal' &&
|
|
65
70
|
other.value === this.value &&
|
|
66
71
|
other.language === this.language &&
|
|
72
|
+
(other.direction || '') === this.direction &&
|
|
67
73
|
!!other.datatype && other.datatype.value === this.datatype.value;
|
|
68
74
|
}
|
|
69
75
|
}
|
|
@@ -139,6 +145,11 @@ const dataFactory = {
|
|
|
139
145
|
if (typeof languageOrDatatype === 'string') {
|
|
140
146
|
return new Literal(v, languageOrDatatype, null);
|
|
141
147
|
}
|
|
148
|
+
// RDF/JS Data Model 1.1: {language, direction} for a directional
|
|
149
|
+
// language-tagged string.
|
|
150
|
+
if (typeof languageOrDatatype.language === 'string' && languageOrDatatype.termType === undefined) {
|
|
151
|
+
return new Literal(v, languageOrDatatype.language, null, languageOrDatatype.direction || '');
|
|
152
|
+
}
|
|
142
153
|
// A NamedNode datatype.
|
|
143
154
|
if (languageOrDatatype.termType === 'NamedNode') {
|
|
144
155
|
if (languageOrDatatype.value === RDF_LANGSTRING) {
|
|
@@ -174,10 +185,8 @@ const dataFactory = {
|
|
|
174
185
|
return new Literal(
|
|
175
186
|
original.value,
|
|
176
187
|
original.language || '',
|
|
177
|
-
original.
|
|
178
|
-
|
|
179
|
-
: new NamedNode(
|
|
180
|
-
(original.datatype && original.datatype.value) || XSD_STRING)
|
|
188
|
+
original.datatype ? new NamedNode(original.datatype.value) : null,
|
|
189
|
+
original.direction || ''
|
|
181
190
|
);
|
|
182
191
|
case 'Quad': return dataFactory.fromQuad(original);
|
|
183
192
|
default:
|
|
@@ -207,31 +216,38 @@ const dataFactory = {
|
|
|
207
216
|
* datatype}) into an RDF/JS term.
|
|
208
217
|
*/
|
|
209
218
|
function termFromSrj(t) {
|
|
219
|
+
return termFromSrjWith(t, dataFactory);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function termFromSrjWith(t, f) {
|
|
210
223
|
if (!t || typeof t.type !== 'string') {
|
|
211
224
|
throw new TypeError('termFromSrj: not a results-JSON term');
|
|
212
225
|
}
|
|
213
226
|
switch (t.type) {
|
|
214
227
|
case 'uri':
|
|
215
|
-
return
|
|
228
|
+
return f.namedNode(t.value);
|
|
216
229
|
case 'bnode':
|
|
217
|
-
return
|
|
230
|
+
return f.blankNode(t.value);
|
|
218
231
|
case 'literal':
|
|
219
232
|
case 'typed-literal': {
|
|
220
233
|
const lang = t['xml:lang'];
|
|
221
|
-
if (lang)
|
|
222
|
-
|
|
223
|
-
|
|
234
|
+
if (lang) {
|
|
235
|
+
if (t['its:dir'] && f === dataFactory) {
|
|
236
|
+
return new Literal(t.value, lang,
|
|
237
|
+
t.datatype ? new NamedNode(t.datatype) : null, t['its:dir']);
|
|
238
|
+
}
|
|
239
|
+
return f.literal(t.value, lang);
|
|
224
240
|
}
|
|
225
|
-
return
|
|
241
|
+
if (t.datatype) return f.literal(t.value, f.namedNode(t.datatype));
|
|
242
|
+
return f.literal(t.value);
|
|
226
243
|
}
|
|
227
244
|
case 'triple': {
|
|
228
|
-
// RDF 1.2 triple term
|
|
245
|
+
// RDF 1.2 triple term:
|
|
229
246
|
// {"type":"triple","value":{"subject":T,"predicate":T,"object":T}}
|
|
230
|
-
//
|
|
231
|
-
// the object may itself be a triple term.
|
|
247
|
+
// -> an RDF/JS Quad term. The object may itself be a triple term.
|
|
232
248
|
const v = t.value || {};
|
|
233
|
-
return
|
|
234
|
-
|
|
249
|
+
return f.quad(termFromSrjWith(v.subject, f), termFromSrjWith(v.predicate, f),
|
|
250
|
+
termFromSrjWith(v.object, f));
|
|
235
251
|
}
|
|
236
252
|
default:
|
|
237
253
|
throw new TypeError(`termFromSrj: unknown term type '${t.type}'`);
|
|
@@ -239,231 +255,132 @@ function termFromSrj(t) {
|
|
|
239
255
|
}
|
|
240
256
|
|
|
241
257
|
// ---------------------------------------------------------------------
|
|
242
|
-
//
|
|
258
|
+
// RDF/JS term <-> engine term object (Lean `L4Factoidal.RDF.TermJson`).
|
|
259
|
+
//
|
|
260
|
+
// These functions copy fields; they read and write no RDF syntax. Every
|
|
261
|
+
// N-Quads parse and write below is an engine op
|
|
262
|
+
// (https://github.com/danbri/factoidal/issues/894 items 1 and 2).
|
|
243
263
|
// ---------------------------------------------------------------------
|
|
244
264
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
case '\r': out += '\\r'; break;
|
|
253
|
-
case '\t': out += '\\t'; break;
|
|
254
|
-
default: out += ch;
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
return out;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
/** Serialize one RDF/JS term to its N-Quads token. */
|
|
261
|
-
function termToNQuads(term) {
|
|
265
|
+
/** The engine term object of an RDF/JS term (`TermJson.encodeTerm`'s shape). */
|
|
266
|
+
function termToJson(term) {
|
|
267
|
+
if (term === null || term === undefined) return null;
|
|
268
|
+
// A term given as text is one RDF 1.2 N-Triples term (`<IRI>`, `_:label`,
|
|
269
|
+
// a literal, `<<( s p o )>>`). The engine reads it
|
|
270
|
+
// (L4Factoidal.RDF.TermJson.readTermString); this file copies the text.
|
|
271
|
+
if (typeof term === 'string') return { type: 'nt', value: term };
|
|
262
272
|
switch (term.termType) {
|
|
263
|
-
case 'NamedNode':
|
|
264
|
-
|
|
265
|
-
case 'BlankNode':
|
|
266
|
-
return '_:' + term.value;
|
|
273
|
+
case 'NamedNode': return { type: 'uri', value: term.value };
|
|
274
|
+
case 'BlankNode': return { type: 'bnode', value: term.value };
|
|
267
275
|
case 'Literal': {
|
|
268
|
-
const
|
|
269
|
-
if (term.
|
|
270
|
-
if (term.
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
return body;
|
|
276
|
+
const o = { type: 'literal', value: term.value };
|
|
277
|
+
if (term.datatype) o.datatype = term.datatype.value;
|
|
278
|
+
if (term.language) o['xml:lang'] = term.language;
|
|
279
|
+
if (term.direction) o['its:dir'] = term.direction;
|
|
280
|
+
return o;
|
|
274
281
|
}
|
|
275
|
-
case 'DefaultGraph':
|
|
276
|
-
return '';
|
|
277
282
|
case 'Quad':
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
termToNQuads(term.predicate) + ' ' +
|
|
283
|
-
termToNQuads(term.object) + ' )>>';
|
|
283
|
+
return { type: 'triple', value: {
|
|
284
|
+
subject: termToJson(term.subject), predicate: termToJson(term.predicate),
|
|
285
|
+
object: termToJson(term.object) } };
|
|
286
|
+
case 'DefaultGraph': return { type: 'default' };
|
|
284
287
|
default:
|
|
285
|
-
throw new TypeError(
|
|
286
|
-
`termToNQuads: cannot serialize termType '${term.termType}'`);
|
|
288
|
+
throw new TypeError(`termToJson: cannot send termType '${term.termType}' to the engine`);
|
|
287
289
|
}
|
|
288
290
|
}
|
|
289
291
|
|
|
290
|
-
/**
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
292
|
+
/**
|
|
293
|
+
* The engine term object of a term an application supplies, for example an
|
|
294
|
+
* extension function's answer: an RDF/JS term (duck-typed on termType), an
|
|
295
|
+
* engine term object ({type, value, ...}), or a plain object
|
|
296
|
+
* {value, datatype} or {value, language, direction?}. The components are
|
|
297
|
+
* copied as given; the engine checks them (TermJson.decodeCheckedTerm) and
|
|
298
|
+
* keeps the lexical form and the datatype IRI unchanged.
|
|
299
|
+
*/
|
|
300
|
+
function appTermToJson(out) {
|
|
301
|
+
if (typeof out.termType === 'string') return termToJson(out);
|
|
302
|
+
if (typeof out.type === 'string') return out;
|
|
303
|
+
const o = { type: 'literal', value: out.value };
|
|
304
|
+
if (out.datatype !== undefined && out.datatype !== null) {
|
|
305
|
+
o.datatype = typeof out.datatype === 'string' ? out.datatype : out.datatype.value;
|
|
306
|
+
}
|
|
307
|
+
if (out.language !== undefined && out.language !== null && out.language !== '') o['xml:lang'] = out.language;
|
|
308
|
+
if (out.direction !== undefined && out.direction !== null && out.direction !== '') o['its:dir'] = out.direction;
|
|
309
|
+
return o;
|
|
298
310
|
}
|
|
299
311
|
|
|
300
|
-
/**
|
|
301
|
-
function
|
|
302
|
-
|
|
303
|
-
|
|
312
|
+
/** The engine quad array of an RDF/JS quad: [s, p, o] or [s, p, o, g]. */
|
|
313
|
+
function quadToJson(quad) {
|
|
314
|
+
const out = [termToJson(quad.subject), termToJson(quad.predicate), termToJson(quad.object)];
|
|
315
|
+
if (quad.graph && quad.graph.termType !== 'DefaultGraph') out.push(termToJson(quad.graph));
|
|
304
316
|
return out;
|
|
305
317
|
}
|
|
306
318
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
// reader for a machine-generated regular syntax, not a general RDF
|
|
314
|
-
// parser — user documents in any syntax go through the engine.
|
|
315
|
-
// ---------------------------------------------------------------------
|
|
319
|
+
/** The RDF/JS quad of an engine quad array. */
|
|
320
|
+
function quadFromJson(arr, factory) {
|
|
321
|
+
const f = factory || dataFactory;
|
|
322
|
+
return f.quad(termFromSrjWith(arr[0], f), termFromSrjWith(arr[1], f),
|
|
323
|
+
termFromSrjWith(arr[2], f), arr.length > 3 ? termFromSrjWith(arr[3], f) : f.defaultGraph());
|
|
324
|
+
}
|
|
316
325
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
};
|
|
326
|
+
// The engine the text functions below call. lib/api.mjs installs it when it
|
|
327
|
+
// loads the engine; until then they throw.
|
|
328
|
+
let textEngine = null;
|
|
321
329
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
continue;
|
|
334
|
-
}
|
|
335
|
-
if (e === 'U') {
|
|
336
|
-
out += String.fromCodePoint(parseInt(s.slice(i + 1, i + 9), 16));
|
|
337
|
-
i += 8;
|
|
338
|
-
continue;
|
|
339
|
-
}
|
|
340
|
-
throw new SyntaxError(
|
|
341
|
-
`N-Quads line ${lineNo}: bad escape '\\${e}'`);
|
|
342
|
-
}
|
|
343
|
-
return out;
|
|
330
|
+
/** @private lib/api.mjs: install the engine ops the text functions call. */
|
|
331
|
+
function _setTextEngine(engine) { textEngine = engine; }
|
|
332
|
+
|
|
333
|
+
function needEngine(who) {
|
|
334
|
+
if (!textEngine) {
|
|
335
|
+
throw new FactoidalError(
|
|
336
|
+
`${who}: N-Quads text is read and written by the engine, which is not ` +
|
|
337
|
+
'loaded yet. Await any @factoidal/core call first (for example ' +
|
|
338
|
+
'`await ready()`), or use parse() and Dataset.toString().', { code: 'op.unknown' });
|
|
339
|
+
}
|
|
340
|
+
return textEngine;
|
|
344
341
|
}
|
|
345
342
|
|
|
346
|
-
|
|
347
|
-
function
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
// (termType 'Quad'). Checked BEFORE the '<' IRI case since a triple
|
|
351
|
-
// term also opens with '<'. This reads the engine's own Mode_12
|
|
352
|
-
// N-Quads serializer output (RDF.NQuads.Serialize) into RDF/JS
|
|
353
|
-
// objects; it is not a conformance parser (that is the F* --rdf12
|
|
354
|
-
// path) — same interop role the rest of this reader plays.
|
|
355
|
-
if (c === '<' && s[i + 1] === '<' && s[i + 2] === '(') {
|
|
356
|
-
let j = skipWs(s, i + 3);
|
|
357
|
-
const [sub, a] = readTerm(s, j, lineNo, factory); j = skipWs(s, a);
|
|
358
|
-
const [pred, b] = readTerm(s, j, lineNo, factory); j = skipWs(s, b);
|
|
359
|
-
const [obj, d] = readTerm(s, j, lineNo, factory); j = skipWs(s, d);
|
|
360
|
-
if (s[j] === ')' && s[j + 1] === '>' && s[j + 2] === '>') {
|
|
361
|
-
return [factory.quad(sub, pred, obj), j + 3];
|
|
362
|
-
}
|
|
363
|
-
throw new SyntaxError(
|
|
364
|
-
`N-Quads line ${lineNo}: unterminated triple term (expected ')>>')`);
|
|
365
|
-
}
|
|
366
|
-
if (c === '<') {
|
|
367
|
-
const end = s.indexOf('>', i + 1);
|
|
368
|
-
if (end < 0) throw new SyntaxError(`N-Quads line ${lineNo}: unclosed IRI`);
|
|
369
|
-
return [factory.namedNode(s.slice(i + 1, end)), end + 1];
|
|
370
|
-
}
|
|
371
|
-
if (c === '_' && s[i + 1] === ':') {
|
|
372
|
-
let j = i + 2;
|
|
373
|
-
while (j < s.length && !/\s/.test(s[j])) j++;
|
|
374
|
-
return [factory.blankNode(s.slice(i + 2, j)), j];
|
|
375
|
-
}
|
|
376
|
-
if (c === '"') {
|
|
377
|
-
// Scan to the closing unescaped quote.
|
|
378
|
-
let j = i + 1;
|
|
379
|
-
for (;;) {
|
|
380
|
-
if (j >= s.length) {
|
|
381
|
-
throw new SyntaxError(`N-Quads line ${lineNo}: unclosed literal`);
|
|
382
|
-
}
|
|
383
|
-
if (s[j] === '\\') { j += 2; continue; }
|
|
384
|
-
if (s[j] === '"') break;
|
|
385
|
-
j++;
|
|
386
|
-
}
|
|
387
|
-
const lex = unescapeLiteral(s.slice(i + 1, j), lineNo);
|
|
388
|
-
j++; // past closing quote
|
|
389
|
-
if (s[j] === '@') {
|
|
390
|
-
let k = j + 1;
|
|
391
|
-
while (k < s.length && !/\s/.test(s[k])) k++;
|
|
392
|
-
return [factory.literal(lex, s.slice(j + 1, k)), k];
|
|
393
|
-
}
|
|
394
|
-
if (s[j] === '^' && s[j + 1] === '^' && s[j + 2] === '<') {
|
|
395
|
-
const end = s.indexOf('>', j + 3);
|
|
396
|
-
if (end < 0) {
|
|
397
|
-
throw new SyntaxError(`N-Quads line ${lineNo}: unclosed datatype IRI`);
|
|
398
|
-
}
|
|
399
|
-
return [
|
|
400
|
-
factory.literal(lex, factory.namedNode(s.slice(j + 3, end))),
|
|
401
|
-
end + 1,
|
|
402
|
-
];
|
|
403
|
-
}
|
|
404
|
-
return [factory.literal(lex), j];
|
|
405
|
-
}
|
|
406
|
-
throw new SyntaxError(
|
|
407
|
-
`N-Quads line ${lineNo}: unexpected character '${c}' at column ${i + 1}`);
|
|
343
|
+
/** One RDF/JS term as its canonical N-Quads token (the engine writes it). */
|
|
344
|
+
function termToNQuads(term) {
|
|
345
|
+
if (term && term.termType === 'DefaultGraph') return '';
|
|
346
|
+
return needEngine('termToNQuads').termTokens([termToJson(term)])[0];
|
|
408
347
|
}
|
|
409
348
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
return
|
|
349
|
+
/** One RDF/JS quad as its canonical N-Quads line (with trailing newline). */
|
|
350
|
+
function quadToNQuads(quad) {
|
|
351
|
+
return needEngine('quadToNQuads').writeQuads([quadToJson(quad)]);
|
|
413
352
|
}
|
|
414
353
|
|
|
415
|
-
/**
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
const f = factory || dataFactory;
|
|
421
|
-
let i = skipWs(line, 0);
|
|
422
|
-
if (i >= line.length || line[i] === '#') return null;
|
|
423
|
-
const terms = [];
|
|
424
|
-
while (terms.length < 4) {
|
|
425
|
-
const [term, next] = readTerm(line, i, lineNo, f);
|
|
426
|
-
terms.push(term);
|
|
427
|
-
i = skipWs(line, next);
|
|
428
|
-
if (line[i] === '.') break;
|
|
429
|
-
}
|
|
430
|
-
if (line[i] !== '.') {
|
|
431
|
-
throw new SyntaxError(`N-Quads line ${lineNo}: missing terminating '.'`);
|
|
432
|
-
}
|
|
433
|
-
if (terms.length < 3) {
|
|
434
|
-
throw new SyntaxError(`N-Quads line ${lineNo}: fewer than 3 terms`);
|
|
435
|
-
}
|
|
436
|
-
return f.quad(terms[0], terms[1], terms[2], terms[3] || f.defaultGraph());
|
|
354
|
+
/** An iterable of RDF/JS quads as an N-Quads document, one line per quad. */
|
|
355
|
+
function quadsToNQuads(quads) {
|
|
356
|
+
const arr = [];
|
|
357
|
+
for (const q of quads) arr.push(quadToJson(q));
|
|
358
|
+
return needEngine('quadsToNQuads').writeQuads(arr);
|
|
437
359
|
}
|
|
438
360
|
|
|
439
361
|
/**
|
|
440
|
-
*
|
|
441
|
-
*
|
|
442
|
-
*
|
|
443
|
-
*
|
|
444
|
-
*
|
|
445
|
-
*
|
|
446
|
-
*
|
|
362
|
+
* Parse an N-Quads document (RDF 1.2 grammar) into RDF/JS quads; the engine
|
|
363
|
+
* parses it and rejects any line the grammar rejects.
|
|
364
|
+
* The quads come in the engine's order: the default graph, then each named
|
|
365
|
+
* graph in the order of its first quad.
|
|
366
|
+
* options.blankNodePrefix: prepended to every blank-node label (keeps the
|
|
367
|
+
* labels of separate documents apart); options.factory: an RDF/JS
|
|
368
|
+
* DataFactory.
|
|
447
369
|
*/
|
|
448
370
|
function nquadsToQuads(text, options) {
|
|
449
371
|
const opts = options || {};
|
|
450
372
|
const factory = opts.factory || dataFactory;
|
|
451
373
|
const f = opts.blankNodePrefix
|
|
452
|
-
? {
|
|
453
|
-
...factory,
|
|
454
|
-
blankNode: (label) => factory.blankNode(
|
|
455
|
-
label === undefined || label === null
|
|
456
|
-
? undefined
|
|
457
|
-
: opts.blankNodePrefix + label),
|
|
458
|
-
}
|
|
374
|
+
? { ...factory, blankNode: (label) => factory.blankNode(opts.blankNodePrefix + label) }
|
|
459
375
|
: factory;
|
|
460
|
-
const quads =
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
376
|
+
const quads = needEngine('nquadsToQuads').parseQuads(String(text));
|
|
377
|
+
return quads.map((q) => quadFromJson(q, f));
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/** One N-Quads statement as an RDF/JS quad; null for a blank or comment line. */
|
|
381
|
+
function nquadsLineToQuad(line, _lineNo, factory) {
|
|
382
|
+
const qs = nquadsToQuads(line, { factory });
|
|
383
|
+
return qs.length ? qs[0] : null;
|
|
467
384
|
}
|
|
468
385
|
|
|
469
386
|
// ---------------------------------------------------------------------
|
|
@@ -481,7 +398,8 @@ function termKey(t) {
|
|
|
481
398
|
if (!t) return 'null';
|
|
482
399
|
switch (t.termType) {
|
|
483
400
|
case 'Literal':
|
|
484
|
-
return JSON.stringify(['Literal', t.value, t.language, t.datatype ? t.datatype.value : null
|
|
401
|
+
return JSON.stringify(['Literal', t.value, t.language, t.datatype ? t.datatype.value : null,
|
|
402
|
+
t.direction || '']);
|
|
485
403
|
case 'DefaultGraph':
|
|
486
404
|
return '["DefaultGraph"]';
|
|
487
405
|
case 'Quad':
|
|
@@ -562,7 +480,7 @@ class DatasetCore {
|
|
|
562
480
|
toArray() {
|
|
563
481
|
return this._quads.slice();
|
|
564
482
|
}
|
|
565
|
-
/** N-Quads text
|
|
483
|
+
/** N-Quads text, written by the engine. */
|
|
566
484
|
toNQuads() {
|
|
567
485
|
return quadsToNQuads(this._quads);
|
|
568
486
|
}
|
|
@@ -584,6 +502,13 @@ export {
|
|
|
584
502
|
Quad,
|
|
585
503
|
DatasetCore,
|
|
586
504
|
termFromSrj,
|
|
505
|
+
termToJson,
|
|
506
|
+
appTermToJson,
|
|
507
|
+
quadToJson,
|
|
508
|
+
quadFromJson,
|
|
509
|
+
quadKey,
|
|
510
|
+
termKey,
|
|
511
|
+
_setTextEngine,
|
|
587
512
|
nquadsLineToQuad,
|
|
588
513
|
termToNQuads,
|
|
589
514
|
quadToNQuads,
|
package/solid/client/index.mjs
CHANGED
|
@@ -158,17 +158,29 @@ export async function createSolidClient (options = {}) {
|
|
|
158
158
|
const maxSteps = typeof options.maxSteps === 'number' ? options.maxSteps : 16
|
|
159
159
|
const baseIri = typeof options.baseIri === 'string' ? options.baseIri : null
|
|
160
160
|
|
|
161
|
-
/** Where to send a request whose target the engine wrote
|
|
162
|
-
*
|
|
163
|
-
*
|
|
161
|
+
/** Where to send a request whose target the engine wrote. The engine
|
|
162
|
+
* resolves the target against baseIri (RFC 3986 section 5.2, op
|
|
163
|
+
* resolveIri) and says whether it was already absolute
|
|
164
|
+
* (https://github.com/danbri/factoidal/issues/894 item 5). */
|
|
164
165
|
function endpoint (target) {
|
|
165
|
-
|
|
166
|
+
let r
|
|
167
|
+
try {
|
|
168
|
+
r = engine.call('resolveIri', [baseIri === null ? '' : baseIri, String(target)])
|
|
169
|
+
} catch (error) {
|
|
170
|
+
if (isUnknownOp(error)) {
|
|
171
|
+
throw new SolidClientHostError(
|
|
172
|
+
'the loaded l4factoidal WebAssembly module does not carry the ' +
|
|
173
|
+
'resolveIri operation; rebuild it with formal/lean4/Wasm/build-wasm.sh')
|
|
174
|
+
}
|
|
175
|
+
throw error
|
|
176
|
+
}
|
|
177
|
+
if (r.referenceAbsolute) return String(target)
|
|
166
178
|
if (baseIri === null) {
|
|
167
179
|
throw new SolidClientHostError(
|
|
168
|
-
`the engine answered the
|
|
169
|
-
'baseIri to
|
|
180
|
+
`the engine answered the relative reference "${target}" and this client has no ` +
|
|
181
|
+
'baseIri to resolve it against; pass baseIri to createSolidClient')
|
|
170
182
|
}
|
|
171
|
-
return
|
|
183
|
+
return r.iri
|
|
172
184
|
}
|
|
173
185
|
|
|
174
186
|
function callRequest (kind, args) {
|
|
@@ -244,9 +256,13 @@ export async function createSolidClient (options = {}) {
|
|
|
244
256
|
if (interpretKind === null) return answer
|
|
245
257
|
// The record says what came back; `target` says what was asked. The
|
|
246
258
|
// storage walk needs both, and this is the engine's own target
|
|
247
|
-
// echoed back, not a URL this file composed.
|
|
259
|
+
// echoed back, not a URL this file composed. `requestUri` is the URL
|
|
260
|
+
// the request went to (the `endpoint` call above): the base IRI of
|
|
261
|
+
// the representation (RFC 3986 §5.1.3), which the engine resolves
|
|
262
|
+
// relative references against.
|
|
248
263
|
const interpretation = interpretationOf(
|
|
249
|
-
callResponse(interpretKind, { ...record, target: request.target
|
|
264
|
+
callResponse(interpretKind, { ...record, target: request.target,
|
|
265
|
+
requestUri: endpoint(request.target) }))
|
|
250
266
|
answer.interpretation = interpretation
|
|
251
267
|
if (interpretation.continue !== true) return answer
|
|
252
268
|
state = interpretation.state === undefined ? null : interpretation.state
|