UNPKG

107 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', { value: true });
4
5function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
6
7var crossFetch = require('cross-fetch');
8var LinkHeader = _interopDefault(require('http-link-header'));
9var dataset = require('@rdfjs/dataset');
10var n3 = require('n3');
11
12/*! *****************************************************************************
13Copyright (c) Microsoft Corporation.
14
15Permission to use, copy, modify, and/or distribute this software for any
16purpose with or without fee is hereby granted.
17
18THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
19REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
20AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
21INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
22LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
23OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
24PERFORMANCE OF THIS SOFTWARE.
25***************************************************************************** */
26
27function __awaiter(thisArg, _arguments, P, generator) {
28 function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
29 return new (P || (P = Promise))(function (resolve, reject) {
30 function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
31 function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
32 function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
33 step((generator = generator.apply(thisArg, _arguments || [])).next());
34 });
35}
36
37/**
38 * Copyright 2020 Inrupt Inc.
39 *
40 * Permission is hereby granted, free of charge, to any person obtaining a copy
41 * of this software and associated documentation files (the "Software"), to deal in
42 * the Software without restriction, including without limitation the rights to use,
43 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
44 * Software, and to permit persons to whom the Software is furnished to do so,
45 * subject to the following conditions:
46 *
47 * The above copyright notice and this permission notice shall be included in
48 * all copies or substantial portions of the Software.
49 *
50 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
51 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
52 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
53 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
54 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
55 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
56 */
57/**
58 * @ignore Internal fallback for when no fetcher is provided; not to be used downstream.
59 */
60const fetch = (resource, init) => {
61 // Implementation note: it's up to the client application to resolve these module names to the
62 // respective npm packages. At least one commonly used tool (Webpack) is only able to do that if
63 // the module names are literal strings.
64 // Additionally, Webpack throws a warning in a way that halts compilation for at least Next.js
65 // when using native Javascript dynamic imports (`import()`), whereas `require()` just logs a
66 // warning. Since the use of package names instead of file names requires a bundles anyway, this
67 // should not have any practical consequences. For more background, see:
68 // https://github.com/webpack/webpack/issues/7713
69 let fetch;
70 try {
71 fetch = require("@inrupt/solid-auth-fetcher").fetch;
72 }
73 catch (e) {
74 try {
75 fetch = require("solid-auth-client").fetch;
76 }
77 catch (e) {
78 fetch = require("cross-fetch");
79 }
80 }
81 return fetch(resource, init);
82};
83
84/**
85 * Copyright 2020 Inrupt Inc.
86 *
87 * Permission is hereby granted, free of charge, to any person obtaining a copy
88 * of this software and associated documentation files (the "Software"), to deal in
89 * the Software without restriction, including without limitation the rights to use,
90 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
91 * Software, and to permit persons to whom the Software is furnished to do so,
92 * subject to the following conditions:
93 *
94 * The above copyright notice and this permission notice shall be included in
95 * all copies or substantial portions of the Software.
96 *
97 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
98 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
99 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
100 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
101 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
102 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
103 */
104const defaultFetchFileOptions = {
105 fetch: fetch,
106};
107const RESERVED_HEADERS = ["Slug", "If-None-Match", "Content-Type"];
108/**
109 * Some of the headers must be set by the library, rather than directly.
110 */
111function containsReserved(header) {
112 return RESERVED_HEADERS.some((reserved) => header.has(reserved));
113}
114/**
115 * Fetches a file at a given URL, and returns it as a blob of data.
116 *
117 * Please note that this function is still experimental: its API can change in non-major releases.
118 *
119 * @param url The URL of the fetched file
120 * @param options Fetching options: a custom fetcher and/or headers.
121 */
122function unstable_fetchFile(input, options = defaultFetchFileOptions) {
123 return __awaiter(this, void 0, void 0, function* () {
124 const config = Object.assign(Object.assign({}, defaultFetchFileOptions), options);
125 return config.fetch(input, config.init);
126 });
127}
128/**
129 * Deletes a file at a given URL
130 *
131 * Please note that this function is still experimental: its API can change in non-major releases.
132 *
133 * @param input The URL of the file to delete
134 */
135function unstable_deleteFile(input, options = defaultFetchFileOptions) {
136 return __awaiter(this, void 0, void 0, function* () {
137 const config = Object.assign(Object.assign({}, defaultFetchFileOptions), options);
138 return config.fetch(input, Object.assign(Object.assign({}, config.init), { method: "DELETE" }));
139 });
140}
141/**
142 * Saves a file in a folder at a given URL. The server will return the final
143 * filename (which may or may not be the given `slug`), it will return it in
144 * the response's Location header.
145 *
146 * @param folderUrl The URL of the folder where the new file is saved
147 * @param file The file to be written
148 * @param options Additional parameters for file creation (e.g. a slug)
149 */
150function unstable_saveFileInContainer(folderUrl, file, options = defaultFetchFileOptions) {
151 return __awaiter(this, void 0, void 0, function* () {
152 return writeFile(folderUrl, file, "POST", options);
153 });
154}
155/**
156 * Saves a file at a given URL, erasing any previous content.
157 *
158 * @param fileUrl The URL where the file is saved
159 * @param file The file to be written
160 * @param options Additional parameters for file creation (e.g. a slug)
161 */
162function unstable_overwriteFile(fileUrl, file, options = defaultFetchFileOptions) {
163 return __awaiter(this, void 0, void 0, function* () {
164 return writeFile(fileUrl, file, "PUT", options);
165 });
166}
167/**
168 * Internal function that performs the actual write HTTP query, either POST
169 * or PUT depending on the use case.
170 *
171 * @param fileUrl The URL where the file is saved
172 * @param file The file to be written
173 * @param method The HTTP method
174 * @param options Additional parameters for file creation (e.g. a slug)
175 */
176function writeFile(targetUrl, file, method, options) {
177 var _a, _b;
178 return __awaiter(this, void 0, void 0, function* () {
179 const config = Object.assign(Object.assign({}, defaultFetchFileOptions), options);
180 const headers = new crossFetch.Headers((_b = (_a = config.init) === null || _a === void 0 ? void 0 : _a.headers) !== null && _b !== void 0 ? _b : {});
181 if (containsReserved(headers)) {
182 throw new Error(`No reserved header (${RESERVED_HEADERS.join(", ")}) should be set in the optional RequestInit.`);
183 }
184 // If a slug is in the parameters, set the request headers accordingly
185 if (config.slug !== undefined) {
186 headers.append("Slug", config.slug);
187 }
188 headers.append("Content-Type", file.type);
189 return yield config.fetch(targetUrl, Object.assign(Object.assign({}, config.init), { headers,
190 method, body: file }));
191 });
192}
193
194/**
195 * Copyright 2020 Inrupt Inc.
196 *
197 * Permission is hereby granted, free of charge, to any person obtaining a copy
198 * of this software and associated documentation files (the "Software"), to deal in
199 * the Software without restriction, including without limitation the rights to use,
200 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
201 * Software, and to permit persons to whom the Software is furnished to do so,
202 * subject to the following conditions:
203 *
204 * The above copyright notice and this permission notice shall be included in
205 * all copies or substantial portions of the Software.
206 *
207 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
208 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
209 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
210 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
211 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
212 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
213 */
214/**
215 * @internal
216 */
217const DataFactory = { quad: dataset.quad, literal: dataset.literal, namedNode: dataset.namedNode, blankNode: dataset.blankNode };
218/**
219 * Clone a Dataset.
220 *
221 * Note that the Quads are not cloned, i.e. if you modify the Quads in the output Dataset, the Quads
222 * in the input Dataset will also be changed.
223 *
224 * @internal
225 * @param input Dataset to clone.
226 * @returns A new Dataset with the same Quads as `input`.
227 */
228function clone(input) {
229 const output = dataset.dataset();
230 for (const quad of input) {
231 output.add(quad);
232 }
233 return output;
234}
235/**
236 * @internal
237 * @param input Dataset to clone.
238 * @param callback Function that takes a Quad, and returns a boolean indicating whether that Quad should be included in the cloned Dataset.
239 * @returns A new Dataset with the same Quads as `input`, excluding the ones for which `callback` returned `false`.
240 */
241function filter(input, callback) {
242 const output = dataset.dataset();
243 for (const quad of input) {
244 if (callback(quad)) {
245 output.add(quad);
246 }
247 }
248 return output;
249}
250
251/**
252 * Copyright 2020 Inrupt Inc.
253 *
254 * Permission is hereby granted, free of charge, to any person obtaining a copy
255 * of this software and associated documentation files (the "Software"), to deal in
256 * the Software without restriction, including without limitation the rights to use,
257 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
258 * Software, and to permit persons to whom the Software is furnished to do so,
259 * subject to the following conditions:
260 *
261 * The above copyright notice and this permission notice shall be included in
262 * all copies or substantial portions of the Software.
263 *
264 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
265 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
266 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
267 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
268 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
269 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
270 */
271/**
272 * @param quads Triples that should be serialised to Turtle
273 * @internal Utility method for internal use; not part of the public API.
274 */
275function triplesToTurtle(quads) {
276 return __awaiter(this, void 0, void 0, function* () {
277 const format = "text/turtle";
278 const writer = new n3.Writer({ format: format });
279 // Remove any potentially lingering references to Named Graphs in Quads;
280 // they'll be determined by the URL the Turtle will be sent to:
281 const triples = quads.map((quad) => DataFactory.quad(quad.subject, quad.predicate, quad.object, undefined));
282 writer.addQuads(triples);
283 const writePromise = new Promise((resolve, reject) => {
284 writer.end((error, result) => {
285 /* istanbul ignore if [n3.js doesn't actually pass an error nor a result, apparently: https://github.com/rdfjs/N3.js/blob/62682e48c02d8965b4d728cb5f2cbec6b5d1b1b8/src/N3Writer.js#L290] */
286 if (error) {
287 return reject(error);
288 }
289 resolve(result);
290 });
291 });
292 const rawTurtle = yield writePromise;
293 return rawTurtle;
294 });
295}
296/**
297 * @param raw Turtle that should be parsed into Triples
298 * @internal Utility method for internal use; not part of the public API.
299 */
300function turtleToTriples(raw, resourceIri) {
301 return __awaiter(this, void 0, void 0, function* () {
302 const format = "text/turtle";
303 const parser = new n3.Parser({ format: format, baseIRI: resourceIri });
304 const parsingPromise = new Promise((resolve, reject) => {
305 const parsedTriples = [];
306 parser.parse(raw, (error, triple, _prefixes) => {
307 if (error) {
308 return reject(error);
309 }
310 if (triple) {
311 parsedTriples.push(triple);
312 }
313 else {
314 resolve(parsedTriples);
315 }
316 });
317 });
318 return parsingPromise;
319 });
320}
321
322/**
323 * Copyright 2020 Inrupt Inc.
324 *
325 * Permission is hereby granted, free of charge, to any person obtaining a copy
326 * of this software and associated documentation files (the "Software"), to deal in
327 * the Software without restriction, including without limitation the rights to use,
328 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
329 * Software, and to permit persons to whom the Software is furnished to do so,
330 * subject to the following conditions:
331 *
332 * The above copyright notice and this permission notice shall be included in
333 * all copies or substantial portions of the Software.
334 *
335 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
336 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
337 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
338 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
339 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
340 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
341 */
342/**
343 * IRIs of the XML Schema data types we support
344 * @internal
345 */
346const xmlSchemaTypes = {
347 boolean: "http://www.w3.org/2001/XMLSchema#boolean",
348 dateTime: "http://www.w3.org/2001/XMLSchema#dateTime",
349 decimal: "http://www.w3.org/2001/XMLSchema#decimal",
350 integer: "http://www.w3.org/2001/XMLSchema#integer",
351 string: "http://www.w3.org/2001/XMLSchema#string",
352 langString: "http://www.w3.org/1999/02/22-rdf-syntax-ns#langString",
353};
354/**
355 * @internal
356 * @param value Value to serialise.
357 * @returns String representation of `value`.
358 */
359function serializeBoolean(value) {
360 return value ? "1" : "0";
361}
362/**
363 * @internal
364 * @param value Value to deserialise.
365 * @returns Deserialized boolean, or null if the given value is not a valid serialised boolean.
366 */
367function deserializeBoolean(value) {
368 if (value === "1") {
369 return true;
370 }
371 else if (value === "0") {
372 return false;
373 }
374 else {
375 return null;
376 }
377}
378/**
379 * @internal
380 * @param value Value to serialise.
381 * @returns String representation of `value`.
382 */
383function serializeDatetime(value) {
384 // To align with rdflib, we ignore miliseconds:
385 // https://github.com/linkeddata/rdflib.js/blob/d84af88f367b8b5f617c753d8241c5a2035458e8/src/literal.js#L74
386 const roundedDate = new Date(Date.UTC(value.getUTCFullYear(), value.getUTCMonth(), value.getUTCDate(), value.getUTCHours(), value.getUTCMinutes(), value.getUTCSeconds(), 0));
387 // Truncate the `.000Z` at the end (i.e. the miliseconds), to plain `Z`:
388 const rdflibStyleString = roundedDate.toISOString().replace(/\.000Z$/, "Z");
389 return rdflibStyleString;
390}
391/**
392 * @internal
393 * @param value Value to deserialise.
394 * @returns Deserialized datetime, or null if the given value is not a valid serialised datetime.
395 */
396function deserializeDatetime(literalString) {
397 if (literalString === null ||
398 literalString.length <= 17 ||
399 literalString.indexOf("Z") === -1) {
400 return null;
401 }
402 // See https://github.com/linkeddata/rdflib.js/blob/d84af88f367b8b5f617c753d8241c5a2035458e8/src/literal.js#L87
403 const utcFullYear = parseInt(literalString.substring(0, 4), 10);
404 const utcMonth = parseInt(literalString.substring(5, 7), 10) - 1;
405 const utcDate = parseInt(literalString.substring(8, 10), 10);
406 const utcHours = parseInt(literalString.substring(11, 13), 10);
407 const utcMinutes = parseInt(literalString.substring(14, 16), 10);
408 const utcSeconds = parseInt(literalString.substring(17, literalString.indexOf("Z")), 10);
409 const date = new Date(0);
410 date.setUTCFullYear(utcFullYear);
411 date.setUTCMonth(utcMonth);
412 date.setUTCDate(utcDate);
413 date.setUTCHours(utcHours);
414 date.setUTCMinutes(utcMinutes);
415 date.setUTCSeconds(utcSeconds);
416 return date;
417}
418/**
419 * @internal
420 * @param value Value to serialise.
421 * @returns String representation of `value`.
422 */
423function serializeDecimal(value) {
424 return value.toString();
425}
426/**
427 * @internal
428 * @param value Value to deserialise.
429 * @returns Deserialized decimal, or null if the given value is not a valid serialised decimal.
430 */
431function deserializeDecimal(literalString) {
432 const deserialized = Number.parseFloat(literalString);
433 if (Number.isNaN(deserialized)) {
434 return null;
435 }
436 return deserialized;
437}
438/**
439 * @internal
440 * @param value Value to serialise.
441 * @returns String representation of `value`.
442 */
443function serializeInteger(value) {
444 return value.toString();
445}
446/**
447 * @internal
448 * @param value Value to deserialise.
449 * @returns Deserialized integer, or null if the given value is not a valid serialised integer.
450 */
451function deserializeInteger(literalString) {
452 const deserialized = Number.parseInt(literalString, 10);
453 if (Number.isNaN(deserialized)) {
454 return null;
455 }
456 return deserialized;
457}
458/**
459 * @internal
460 * @param locale Locale to transform into a consistent format.
461 */
462function normalizeLocale(locale) {
463 return locale.toLowerCase();
464}
465/**
466 * @internal Library users shouldn't need to be exposed to raw NamedNodes.
467 * @param value The value that might or might not be a Named Node.
468 * @returns Whether `value` is a Named Node.
469 */
470function isNamedNode(value) {
471 return (typeof value === "object" &&
472 typeof value.termType === "string" &&
473 value.termType === "NamedNode");
474}
475/**
476 * @internal Library users shouldn't need to be exposed to raw Literals.
477 * @param value The value that might or might not be a Literal.
478 * @returns Whether `value` is a Literal.
479 */
480function isLiteral(value) {
481 return (typeof value === "object" &&
482 typeof value.termType === "string" &&
483 value.termType === "Literal");
484}
485/**
486 * @internal Library users shouldn't need to be exposed to LocalNodes.
487 * @param value The value that might or might not be a Node with no known IRI yet.
488 * @returns Whether `value` is a Node with no known IRI yet.
489 */
490function isLocalNode(value) {
491 return (typeof value === "object" &&
492 typeof value.termType === "string" &&
493 value.termType === "BlankNode" &&
494 typeof value.name === "string");
495}
496/**
497 * Construct a new LocalNode.
498 *
499 * @internal Library users shouldn't need to be exposed to LocalNodes.
500 * @param name Name to identify this node by.
501 * @returns A LocalNode whose name will be resolved when it is persisted to a Pod.
502 */
503function getLocalNode(name) {
504 const localNode = Object.assign(DataFactory.blankNode(), {
505 name: name,
506 });
507 return localNode;
508}
509/**
510 * Ensure that a given value is a Named Node.
511 *
512 * If the given parameter is a Named Node already, it will be returned as-is. If it is a string, it
513 * will check whether it is a valid IRI. If not, it will throw an error; otherwise a Named Node
514 * representing the given IRI will be returned.
515 *
516 * @internal Library users shouldn't need to be exposed to raw NamedNodes.
517 * @param iri The IRI that should be converted into a Named Node, if it isn't one yet.
518 */
519function asNamedNode(iri) {
520 if (isNamedNode(iri)) {
521 return iri;
522 }
523 // If the runtime environment supports URL, instantiate one.
524 // If thte given IRI is not a valid URL, it will throw an error.
525 // See: https://developer.mozilla.org/en-US/docs/Web/API/URL
526 /* istanbul ignore else [URL is available in our testing environment, so we cannot test the alternative] */
527 if (typeof URL !== "undefined") {
528 new URL(iri);
529 }
530 return DataFactory.namedNode(iri);
531}
532/**
533 * Check whether two current- or potential NamedNodes are/will be equal.
534 *
535 * @internal Utility method; library users should not need to interact with LocalNodes directly.
536 */
537function isEqual(node1, node2, options = {}) {
538 if (isNamedNode(node1) && isNamedNode(node2)) {
539 return node1.equals(node2);
540 }
541 if (isLocalNode(node1) && isLocalNode(node2)) {
542 return node1.name === node2.name;
543 }
544 if (typeof options.resourceIri === "undefined") {
545 // If we don't know what IRI to resolve the LocalNode to,
546 // we cannot conclude that it is equal to the NamedNode's full IRI:
547 return false;
548 }
549 const namedNode1 = isNamedNode(node1)
550 ? node1
551 : resolveIriForLocalNode(node1, options.resourceIri);
552 const namedNode2 = isNamedNode(node2)
553 ? node2
554 : resolveIriForLocalNode(node2, options.resourceIri);
555 return namedNode1.equals(namedNode2);
556}
557/**
558 * @internal Utility method; library users should not need to interact with LocalNodes directly.
559 * @param quad The Quad to resolve LocalNodes in.
560 * @param resourceIri The IRI of the Resource to resolve the LocalNodes against.
561 */
562function resolveIriForLocalNodes(quad, resourceIri) {
563 const subject = isLocalNode(quad.subject)
564 ? resolveIriForLocalNode(quad.subject, resourceIri)
565 : quad.subject;
566 const object = isLocalNode(quad.object)
567 ? resolveIriForLocalNode(quad.object, resourceIri)
568 : quad.object;
569 return Object.assign(Object.assign({}, quad), { subject: subject, object: object });
570}
571/**
572 * @internal Utility method; library users should not need to interact with LocalNodes directly.
573 * @param localNode The LocalNode to resolve to a NamedNode.
574 * @param resourceIri The Resource in which the Node will be saved.
575 */
576function resolveIriForLocalNode(localNode, resourceIri) {
577 return DataFactory.namedNode(resolveLocalIri(localNode.name, resourceIri));
578}
579/**
580 * @internal API for internal use only.
581 * @param name The name identifying a Thing.
582 * @param resourceIri The Resource in which the Thing can be found.
583 */
584function resolveLocalIri(name, resourceIri) {
585 /* istanbul ignore if [The URL interface is available in the testing environment, so we cannot test this] */
586 if (typeof URL === "undefined") {
587 throw new Error("The URL interface is not available, so an IRI cannot be determined.");
588 }
589 const thingIri = new URL(resourceIri);
590 thingIri.hash = name;
591 return thingIri.href;
592}
593
594/**
595 * Copyright 2020 Inrupt Inc.
596 *
597 * Permission is hereby granted, free of charge, to any person obtaining a copy
598 * of this software and associated documentation files (the "Software"), to deal in
599 * the Software without restriction, including without limitation the rights to use,
600 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
601 * Software, and to permit persons to whom the Software is furnished to do so,
602 * subject to the following conditions:
603 *
604 * The above copyright notice and this permission notice shall be included in
605 * all copies or substantial portions of the Software.
606 *
607 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
608 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
609 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
610 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
611 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
612 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
613 */
614// TODO: These should be replaced by auto-generated constants,
615// if we can ensure that unused constants will be excluded from bundles.
616/** @internal */
617const acl = {
618 Authorization: "http://www.w3.org/ns/auth/acl#Authorization",
619 accessTo: "http://www.w3.org/ns/auth/acl#accessTo",
620 agent: "http://www.w3.org/ns/auth/acl#agent",
621 default: "http://www.w3.org/ns/auth/acl#default",
622 mode: "http://www.w3.org/ns/auth/acl#mode",
623};
624/** @internal */
625const rdf = {
626 type: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
627};
628
629/**
630 * Copyright 2020 Inrupt Inc.
631 *
632 * Permission is hereby granted, free of charge, to any person obtaining a copy
633 * of this software and associated documentation files (the "Software"), to deal in
634 * the Software without restriction, including without limitation the rights to use,
635 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
636 * Software, and to permit persons to whom the Software is furnished to do so,
637 * subject to the following conditions:
638 *
639 * The above copyright notice and this permission notice shall be included in
640 * all copies or substantial portions of the Software.
641 *
642 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
643 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
644 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
645 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
646 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
647 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
648 */
649/**
650 * Verify whether a given LitDataset includes metadata about where it was retrieved from.
651 *
652 * @param dataset A [[LitDataset]] that may have metadata attached about the Resource it was retrieved from.
653 * @returns True if `dataset` includes metadata about the Resource it was retrieved from, false if not.
654 */
655function hasDatasetInfo(dataset) {
656 const potentialDatasetInfo = dataset;
657 return typeof potentialDatasetInfo.datasetInfo === "object";
658}
659/** @internal */
660function hasChangelog(dataset) {
661 const potentialChangeLog = dataset;
662 return (typeof potentialChangeLog.changeLog === "object" &&
663 Array.isArray(potentialChangeLog.changeLog.additions) &&
664 Array.isArray(potentialChangeLog.changeLog.deletions));
665}
666/**
667 * Given a [[LitDataset]], verify whether it has ACL data attached to it.
668 *
669 * This should generally only be true for LitDatasets fetched by
670 * [[unstable_fetchLitDatasetWithAcl]].
671 *
672 * @param dataset A [[LitDataset]].
673 * @returns Whether the given `dataset` has ACL data attached to it.
674 * @internal
675 */
676function unstable_hasAccessibleAcl(dataset) {
677 return typeof dataset.datasetInfo.unstable_aclUrl === "string";
678}
679
680/**
681 * Copyright 2020 Inrupt Inc.
682 *
683 * Permission is hereby granted, free of charge, to any person obtaining a copy
684 * of this software and associated documentation files (the "Software"), to deal in
685 * the Software without restriction, including without limitation the rights to use,
686 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
687 * Software, and to permit persons to whom the Software is furnished to do so,
688 * subject to the following conditions:
689 *
690 * The above copyright notice and this permission notice shall be included in
691 * all copies or substantial portions of the Software.
692 *
693 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
694 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
695 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
696 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
697 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
698 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
699 */
700/**
701 * Extract Quads with a given Subject from a [[LitDataset]] into a [[Thing]].
702 *
703 * @param litDataset The [[LitDataset]] to extract the [[Thing]] from.
704 * @param thingUrl The URL of the desired [[Thing]].
705 * @param options Not yet implemented.
706 */
707function getThingOne(litDataset, thingUrl, options = {}) {
708 const subject = isLocalNode(thingUrl) ? thingUrl : asNamedNode(thingUrl);
709 const scope = options.scope
710 ? asNamedNode(options.scope)
711 : null;
712 const thingDataset = litDataset.match(subject, null, null, scope);
713 if (isLocalNode(subject)) {
714 const thing = Object.assign(thingDataset, {
715 name: subject.name,
716 });
717 return thing;
718 }
719 else {
720 const thing = Object.assign(thingDataset, {
721 url: subject.value,
722 });
723 return thing;
724 }
725}
726/**
727 * Get all [[Thing]]s about which a [[LitDataset]] contains Quads.
728 *
729 * @param litDataset The [[LitDataset]] to extract the [[Thing]]s from.
730 * @param options Not yet implemented.
731 */
732function getThingAll(litDataset, options = {}) {
733 const subjectNodes = new Array();
734 for (const quad of litDataset) {
735 // Because NamedNode objects with the same IRI are actually different
736 // object instances, we have to manually check whether `subjectNodes` does
737 // not yet include `quadSubject` before adding it.
738 const quadSubject = quad.subject;
739 if (isNamedNode(quadSubject) &&
740 !subjectNodes.some((subjectNode) => isEqual(subjectNode, quadSubject))) {
741 subjectNodes.push(quadSubject);
742 }
743 if (isLocalNode(quadSubject) &&
744 !subjectNodes.some((subjectNode) => isEqual(subjectNode, quadSubject))) {
745 subjectNodes.push(quadSubject);
746 }
747 }
748 const things = subjectNodes.map((subjectNode) => getThingOne(litDataset, subjectNode, options));
749 return things;
750}
751/**
752 * Insert a [[Thing]] into a [[LitDataset]], replacing previous instances of that Thing.
753 *
754 * @param litDataset The LitDataset to insert a Thing into.
755 * @param thing The Thing to insert into the given LitDataset.
756 * @returns A new LitDataset equal to the given LitDataset, but with the given Thing.
757 */
758function setThing(litDataset, thing) {
759 const newDataset = removeThing(litDataset, thing);
760 for (const quad of thing) {
761 newDataset.add(quad);
762 newDataset.changeLog.additions.push(quad);
763 }
764 return newDataset;
765}
766/**
767 * Remove a Thing from a LitDataset.
768 *
769 * @param litDataset The LitDataset to remove a Thing from.
770 * @param thing The Thing to remove from `litDataset`.
771 * @returns A new [[LitDataset]] equal to the input LitDataset, excluding the given Thing.
772 */
773function removeThing(litDataset, thing) {
774 const newLitDataset = withChangeLog(cloneLitStructs(litDataset));
775 const resourceIri = hasDatasetInfo(newLitDataset)
776 ? newLitDataset.datasetInfo.fetchedFrom
777 : undefined;
778 const thingSubject = toNode(thing);
779 for (const quad of litDataset) {
780 if (!isNamedNode(quad.subject) && !isLocalNode(quad.subject)) {
781 // This data is unexpected, and hence unlikely to be added by us. Thus, leave it intact:
782 newLitDataset.add(quad);
783 }
784 else if (!isEqual(thingSubject, quad.subject, { resourceIri: resourceIri })) {
785 newLitDataset.add(quad);
786 }
787 else {
788 newLitDataset.changeLog.deletions.push(quad);
789 }
790 }
791 return newLitDataset;
792}
793function withChangeLog(litDataset) {
794 const newLitDataset = hasChangelog(litDataset)
795 ? litDataset
796 : Object.assign(litDataset, {
797 changeLog: { additions: [], deletions: [] },
798 });
799 return newLitDataset;
800}
801function cloneLitStructs(litDataset) {
802 const freshDataset = dataset.dataset();
803 if (hasChangelog(litDataset)) {
804 freshDataset.changeLog = {
805 additions: [...litDataset.changeLog.additions],
806 deletions: [...litDataset.changeLog.deletions],
807 };
808 }
809 if (hasDatasetInfo(litDataset)) {
810 freshDataset.datasetInfo = Object.assign({}, litDataset.datasetInfo);
811 }
812 return freshDataset;
813}
814function createThing(options = {}) {
815 var _a;
816 if (typeof options.url !== "undefined") {
817 const url = options.url;
818 /* istanbul ignore else [URL is defined is the testing environment, so we cannot test this] */
819 if (typeof URL !== "undefined") {
820 // Throws an error if the IRI is invalid:
821 new URL(url);
822 }
823 const thing = Object.assign(dataset.dataset(), { url: url });
824 return thing;
825 }
826 const name = (_a = options.name) !== null && _a !== void 0 ? _a : generateName();
827 const thing = Object.assign(dataset.dataset(), { name: name });
828 return thing;
829}
830function asUrl(thing, baseUrl) {
831 if (isThingLocal(thing)) {
832 if (typeof baseUrl === "undefined") {
833 throw new Error("The URL of a Thing that has not been persisted cannot be determined without a base URL.");
834 }
835 return resolveLocalIri(thing.name, baseUrl);
836 }
837 return thing.url;
838}
839/** @hidden Alias of [[asUrl]] for those who prefer IRI terminology. */
840const asIri = asUrl;
841/**
842 * @param thing The [[Thing]] of which a URL might or might not be known.
843 * @return Whether `thing` has no known URL yet.
844 */
845function isThingLocal(thing) {
846 return (typeof thing.name === "string" &&
847 typeof thing.url === "undefined");
848}
849/**
850 * @internal
851 * @param thing The Thing whose Subject Node you're interested in.
852 * @returns A Node that can be used as the Subject for this Thing's Quads.
853 */
854function toNode(thing) {
855 if (isNamedNode(thing) || isLocalNode(thing)) {
856 return thing;
857 }
858 if (typeof thing === "string") {
859 return asNamedNode(thing);
860 }
861 if (isThingLocal(thing)) {
862 return getLocalNode(thing.name);
863 }
864 return asNamedNode(asUrl(thing));
865}
866function cloneThing(thing) {
867 const cloned = clone(thing);
868 if (isThingLocal(thing)) {
869 cloned.name = thing.name;
870 return cloned;
871 }
872 cloned.url = thing.url;
873 return cloned;
874}
875function filterThing(thing, callback) {
876 const filtered = filter(thing, callback);
877 if (isThingLocal(thing)) {
878 filtered.name = thing.name;
879 return filtered;
880 }
881 filtered.url = thing.url;
882 return filtered;
883}
884/**
885 * Generate a string that can be used as the unique identifier for a Thing
886 *
887 * This function works by starting with a date string (so that Things can be
888 * sorted chronologically), followed by a random number generated by taking a
889 * random number between 0 and 1, and cutting off the `0.`.
890 *
891 * @internal
892 * @returns An string that's likely to be unique
893 */
894const generateName = () => {
895 return (Date.now().toString() + Math.random().toString().substring("0.".length));
896};
897
898/**
899 * Copyright 2020 Inrupt Inc.
900 *
901 * Permission is hereby granted, free of charge, to any person obtaining a copy
902 * of this software and associated documentation files (the "Software"), to deal in
903 * the Software without restriction, including without limitation the rights to use,
904 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
905 * Software, and to permit persons to whom the Software is furnished to do so,
906 * subject to the following conditions:
907 *
908 * The above copyright notice and this permission notice shall be included in
909 * all copies or substantial portions of the Software.
910 *
911 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
912 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
913 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
914 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
915 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
916 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
917 */
918/**
919 * @param thing The [[Thing]] to read a URL value from.
920 * @param predicate The given Predicate for which you want the URL value.
921 * @returns A URL value for the given Predicate, if present, or null otherwise.
922 */
923function getUrlOne(thing, predicate) {
924 const namedNodeMatcher = getNamedNodeMatcher(predicate);
925 const matchingQuad = findOne(thing, namedNodeMatcher);
926 if (matchingQuad === null) {
927 return null;
928 }
929 return matchingQuad.object.value;
930}
931/** @hidden Alias of [[getUrlOne]] for those who prefer IRI terminology. */
932const getIriOne = getUrlOne;
933/**
934 * @param thing The [[Thing]] to read the URL values from.
935 * @param predicate The given Predicate for which you want the URL values.
936 * @returns The URL values for the given Predicate.
937 */
938function getUrlAll(thing, predicate) {
939 const iriMatcher = getNamedNodeMatcher(predicate);
940 const matchingQuads = findAll(thing, iriMatcher);
941 return matchingQuads.map((quad) => quad.object.value);
942}
943/** @hidden Alias of [[getUrlAll]] for those who prefer IRI terminology. */
944const getIriAll = getUrlAll;
945/**
946 * @param thing The [[Thing]] to read a boolean value from.
947 * @param predicate The given Predicate for which you want the boolean value.
948 * @returns A boolean value for the given Predicate, if present, or null otherwise.
949 */
950function getBooleanOne(thing, predicate) {
951 const literalString = getLiteralOneOfType(thing, predicate, xmlSchemaTypes.boolean);
952 if (literalString === null) {
953 return null;
954 }
955 return deserializeBoolean(literalString);
956}
957/**
958 * @param thing The [[Thing]] to read the boolean values from.
959 * @param predicate The given Predicate for which you want the boolean values.
960 * @returns The boolean values for the given Predicate.
961 */
962function getBooleanAll(thing, predicate) {
963 const literalStrings = getLiteralAllOfType(thing, predicate, xmlSchemaTypes.boolean);
964 return literalStrings
965 .map(deserializeBoolean)
966 .filter((possibleBoolean) => possibleBoolean !== null);
967}
968/**
969 * @param thing The [[Thing]] to read a datetime value from.
970 * @param predicate The given Predicate for which you want the datetime value.
971 * @returns A datetime value for the given Predicate, if present, or null otherwise.
972 */
973function getDatetimeOne(thing, predicate) {
974 const literalString = getLiteralOneOfType(thing, predicate, xmlSchemaTypes.dateTime);
975 if (literalString === null) {
976 return null;
977 }
978 return deserializeDatetime(literalString);
979}
980/**
981 * @param thing The [[Thing]] to read the datetime values from.
982 * @param predicate The given Predicate for which you want the datetime values.
983 * @returns The datetime values for the given Predicate.
984 */
985function getDatetimeAll(thing, predicate) {
986 const literalStrings = getLiteralAllOfType(thing, predicate, xmlSchemaTypes.dateTime);
987 return literalStrings
988 .map(deserializeDatetime)
989 .filter((potentialDatetime) => potentialDatetime !== null);
990}
991/**
992 * @param thing The [[Thing]] to read a decimal value from.
993 * @param predicate The given Predicate for which you want the decimal value.
994 * @returns A decimal value for the given Predicate, if present, or null otherwise.
995 */
996function getDecimalOne(thing, predicate) {
997 const literalString = getLiteralOneOfType(thing, predicate, xmlSchemaTypes.decimal);
998 if (literalString === null) {
999 return null;
1000 }
1001 return deserializeDecimal(literalString);
1002}
1003/**
1004 * @param thing The [[Thing]] to read the decimal values from.
1005 * @param predicate The given Predicate for which you want the decimal values.
1006 * @returns The decimal values for the given Predicate.
1007 */
1008function getDecimalAll(thing, predicate) {
1009 const literalStrings = getLiteralAllOfType(thing, predicate, xmlSchemaTypes.decimal);
1010 return literalStrings
1011 .map((literalString) => deserializeDecimal(literalString))
1012 .filter((potentialDecimal) => potentialDecimal !== null);
1013}
1014/**
1015 * @param thing The [[Thing]] to read an integer value from.
1016 * @param predicate The given Predicate for which you want the integer value.
1017 * @returns An integer value for the given Predicate, if present, or null otherwise.
1018 */
1019function getIntegerOne(thing, predicate) {
1020 const literalString = getLiteralOneOfType(thing, predicate, xmlSchemaTypes.integer);
1021 if (literalString === null) {
1022 return null;
1023 }
1024 return deserializeInteger(literalString);
1025}
1026/**
1027 * @param thing The [[Thing]] to read the integer values from.
1028 * @param predicate The given Predicate for which you want the integer values.
1029 * @returns The integer values for the given Predicate.
1030 */
1031function getIntegerAll(thing, predicate) {
1032 const literalStrings = getLiteralAllOfType(thing, predicate, xmlSchemaTypes.integer);
1033 return literalStrings
1034 .map((literalString) => deserializeInteger(literalString))
1035 .filter((potentialInteger) => potentialInteger !== null);
1036}
1037/**
1038 * @param thing The [[Thing]] to read a localised string value from.
1039 * @param predicate The given Predicate for which you want the localised string value.
1040 * @param locale The desired locale for the string value.
1041 * @returns A localised string value for the given Predicate, if present in `locale`, or null otherwise.
1042 */
1043function getStringInLocaleOne(thing, predicate, locale) {
1044 const localeStringMatcher = getLocaleStringMatcher(predicate, locale);
1045 const matchingQuad = findOne(thing, localeStringMatcher);
1046 if (matchingQuad === null) {
1047 return null;
1048 }
1049 return matchingQuad.object.value;
1050}
1051/**
1052 * @param thing The [[Thing]] to read the localised string values from.
1053 * @param predicate The given Predicate for which you want the localised string values.
1054 * @param locale The desired locale for the string values.
1055 * @returns The localised string values for the given Predicate.
1056 */
1057function getStringInLocaleAll(thing, predicate, locale) {
1058 const localeStringMatcher = getLocaleStringMatcher(predicate, locale);
1059 const matchingQuads = findAll(thing, localeStringMatcher);
1060 return matchingQuads.map((quad) => quad.object.value);
1061}
1062/**
1063 * @param thing The [[Thing]] to read a string value from.
1064 * @param predicate The given Predicate for which you want the string value.
1065 * @returns A string value for the given Predicate, if present, or null otherwise.
1066 */
1067function getStringUnlocalizedOne(thing, predicate) {
1068 const literalString = getLiteralOneOfType(thing, predicate, xmlSchemaTypes.string);
1069 return literalString;
1070}
1071/**
1072 * @param thing The [[Thing]] to read the string values from.
1073 * @param predicate The given Predicate for which you want the string values.
1074 * @returns The string values for the given Predicate.
1075 */
1076function getStringUnlocalizedAll(thing, predicate) {
1077 const literalStrings = getLiteralAllOfType(thing, predicate, xmlSchemaTypes.string);
1078 return literalStrings;
1079}
1080/**
1081 * @param thing The [[Thing]] to read a NamedNode value from.
1082 * @param predicate The given Predicate for which you want the NamedNode value.
1083 * @returns A NamedNode value for the given Predicate, if present, or null otherwise.
1084 * @ignore This should not be needed due to the other get*One() functions. If you do find yourself needing it, please file a feature request for your use case.
1085 */
1086function getNamedNodeOne(thing, predicate) {
1087 const namedNodeMatcher = getNamedNodeMatcher(predicate);
1088 const matchingQuad = findOne(thing, namedNodeMatcher);
1089 if (matchingQuad === null) {
1090 return null;
1091 }
1092 return matchingQuad.object;
1093}
1094/**
1095 * @param thing The [[Thing]] to read the NamedNode values from.
1096 * @param predicate The given Predicate for which you want the NamedNode values.
1097 * @returns The NamedNode values for the given Predicate.
1098 * @ignore This should not be needed due to the other get*One() functions. If you do find yourself needing it, please file a feature request for your use case.
1099 */
1100function getNamedNodeAll(thing, predicate) {
1101 const namedNodeMatcher = getNamedNodeMatcher(predicate);
1102 const matchingQuads = findAll(thing, namedNodeMatcher);
1103 return matchingQuads.map((quad) => quad.object);
1104}
1105/**
1106 * @param thing The [[Thing]] to read a Literal value from.
1107 * @param predicate The given Predicate for which you want the Literal value.
1108 * @returns A Literal value for the given Predicate, if present, or null otherwise.
1109 * @ignore This should not be needed due to the other get*One() functions. If you do find yourself needing it, please file a feature request for your use case.
1110 */
1111function getLiteralOne(thing, predicate) {
1112 const literalMatcher = getLiteralMatcher(predicate);
1113 const matchingQuad = findOne(thing, literalMatcher);
1114 if (matchingQuad === null) {
1115 return null;
1116 }
1117 return matchingQuad.object;
1118}
1119/**
1120 * @param thing The [[Thing]] to read the Literal values from.
1121 * @param predicate The given Predicate for which you want the Literal values.
1122 * @returns The Literal values for the given Predicate.
1123 * @ignore This should not be needed due to the other get*All() functions. If you do find yourself needing it, please file a feature request for your use case.
1124 */
1125function getLiteralAll(thing, predicate) {
1126 const literalMatcher = getLiteralMatcher(predicate);
1127 const matchingQuads = findAll(thing, literalMatcher);
1128 return matchingQuads.map((quad) => quad.object);
1129}
1130/**
1131 * @param thing The [[Thing]] to extract a Quad from.
1132 * @param matcher Callback function that returns a boolean indicating whether a given Quad should be included.
1133 * @returns First Quad in `thing` for which `matcher` returned true.
1134 */
1135function findOne(thing, matcher) {
1136 for (const quad of thing) {
1137 if (matcher(quad)) {
1138 return quad;
1139 }
1140 }
1141 return null;
1142}
1143/**
1144 * @param thing The [[Thing]] to extract Quads from.
1145 * @param matcher Callback function that returns a boolean indicating whether a given Quad should be included.
1146 * @returns All Quads in `thing` for which `matcher` returned true.
1147 */
1148function findAll(thing, matcher) {
1149 const matched = [];
1150 for (const quad of thing) {
1151 if (matcher(quad)) {
1152 matched.push(quad);
1153 }
1154 }
1155 return matched;
1156}
1157function getNamedNodeMatcher(predicate) {
1158 const predicateNode = asNamedNode(predicate);
1159 const matcher = function matcher(quad) {
1160 return predicateNode.equals(quad.predicate) && isNamedNode(quad.object);
1161 };
1162 return matcher;
1163}
1164function getLiteralMatcher(predicate) {
1165 const predicateNode = asNamedNode(predicate);
1166 const matcher = function matcher(quad) {
1167 return predicateNode.equals(quad.predicate) && isLiteral(quad.object);
1168 };
1169 return matcher;
1170}
1171function getLiteralOfTypeMatcher(predicate, datatype) {
1172 const predicateNode = asNamedNode(predicate);
1173 const matcher = function matcher(quad) {
1174 return (predicateNode.equals(quad.predicate) &&
1175 isLiteral(quad.object) &&
1176 quad.object.datatype.value === datatype);
1177 };
1178 return matcher;
1179}
1180function getLocaleStringMatcher(predicate, locale) {
1181 const predicateNode = asNamedNode(predicate);
1182 const matcher = function matcher(quad) {
1183 return (predicateNode.equals(quad.predicate) &&
1184 isLiteral(quad.object) &&
1185 quad.object.datatype.value === xmlSchemaTypes.langString &&
1186 quad.object.language.toLowerCase() === locale.toLowerCase());
1187 };
1188 return matcher;
1189}
1190/**
1191 * @param thing The [Thing]] to read a Literal of the given type from.
1192 * @param predicate The given Predicate for which you want the Literal value.
1193 * @param literalType Set type of the Literal data.
1194 * @returns The stringified value for the given Predicate and type, if present, or null otherwise.
1195 */
1196function getLiteralOneOfType(thing, predicate, literalType) {
1197 const literalOfTypeMatcher = getLiteralOfTypeMatcher(predicate, literalType);
1198 const matchingQuad = findOne(thing, literalOfTypeMatcher);
1199 if (matchingQuad === null) {
1200 return null;
1201 }
1202 return matchingQuad.object.value;
1203}
1204/**
1205 * @param thing The [Thing]] to read the Literals of the given type from.
1206 * @param predicate The given Predicate for which you want the Literal values.
1207 * @param literalType Set type of the Literal data.
1208 * @returns The stringified values for the given Predicate and type.
1209 */
1210function getLiteralAllOfType(thing, predicate, literalType) {
1211 const literalOfTypeMatcher = getLiteralOfTypeMatcher(predicate, literalType);
1212 const matchingQuads = findAll(thing, literalOfTypeMatcher);
1213 return matchingQuads.map((quad) => quad.object.value);
1214}
1215
1216/**
1217 * Copyright 2020 Inrupt Inc.
1218 *
1219 * Permission is hereby granted, free of charge, to any person obtaining a copy
1220 * of this software and associated documentation files (the "Software"), to deal in
1221 * the Software without restriction, including without limitation the rights to use,
1222 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
1223 * Software, and to permit persons to whom the Software is furnished to do so,
1224 * subject to the following conditions:
1225 *
1226 * The above copyright notice and this permission notice shall be included in
1227 * all copies or substantial portions of the Software.
1228 *
1229 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
1230 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
1231 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
1232 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
1233 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
1234 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1235 */
1236/** @internal */
1237function internal_fetchResourceAcl(dataset, options = defaultFetchOptions) {
1238 return __awaiter(this, void 0, void 0, function* () {
1239 if (!unstable_hasAccessibleAcl(dataset)) {
1240 return null;
1241 }
1242 try {
1243 const aclLitDataset = yield fetchLitDataset(dataset.datasetInfo.unstable_aclUrl, options);
1244 return Object.assign(aclLitDataset, {
1245 accessTo: dataset.datasetInfo.fetchedFrom,
1246 });
1247 }
1248 catch (e) {
1249 // Since a Solid server adds a `Link` header to an ACL even if that ACL does not exist,
1250 // failure to fetch the ACL is expected to happen - we just return `null` and let callers deal
1251 // with it.
1252 return null;
1253 }
1254 });
1255}
1256/** @internal */
1257function internal_fetchFallbackAcl(dataset, options = defaultFetchOptions) {
1258 return __awaiter(this, void 0, void 0, function* () {
1259 const resourceUrl = new URL(dataset.datasetInfo.fetchedFrom);
1260 const resourcePath = resourceUrl.pathname;
1261 // Note: we're currently assuming that the Origin is the root of the Pod. However, it is not yet
1262 // set in stone that that will always be the case. We might need to check the Container's
1263 // metadata at some point in time to check whether it is actually the root of the Pod.
1264 // See: https://github.com/solid/specification/issues/153#issuecomment-624630022
1265 if (resourcePath === "/") {
1266 // We're already at the root, so there's no Container we can retrieve:
1267 return null;
1268 }
1269 const containerPath = getContainerPath(resourcePath);
1270 const containerIri = new URL(containerPath, resourceUrl.origin).href;
1271 const containerInfo = yield internal_fetchLitDatasetInfo(containerIri, options);
1272 if (!unstable_hasAccessibleAcl(containerInfo)) {
1273 // If the current user does not have access to this Container's ACL,
1274 // we cannot determine whether its ACL is the one that applies. Thus, return null:
1275 return null;
1276 }
1277 const containerAcl = yield internal_fetchResourceAcl(containerInfo, options);
1278 if (containerAcl === null) {
1279 return internal_fetchFallbackAcl(containerInfo, options);
1280 }
1281 return containerAcl;
1282 });
1283}
1284function getContainerPath(resourcePath) {
1285 const resourcePathWithoutTrailingSlash = resourcePath.substring(resourcePath.length - 1) === "/"
1286 ? resourcePath.substring(0, resourcePath.length - 1)
1287 : resourcePath;
1288 const containerPath = resourcePath.substring(0, resourcePathWithoutTrailingSlash.lastIndexOf("/")) + "/";
1289 return containerPath;
1290}
1291/**
1292 * Verify whether an ACL was found for the given LitDataset.
1293 *
1294 * A LitDataset fetched with [[unstable_fetchLitDatasetWithAcl]] _might_ have an ACL attached, but
1295 * we cannot be sure: it might be that none exists for this specific Resource (in which case the
1296 * fallback ACL applies), or the currently authenticated user (if any) might not have Control access
1297 * to the fetched Resource.
1298 *
1299 * This function verifies that the LitDataset's ACL is accessible.
1300 *
1301 * @param dataset A [[LitDataset]] that might have an ACL attached.
1302 * @returns Whether `dataset` has an ACL attached.
1303 */
1304function unstable_hasResourceAcl(dataset) {
1305 return typeof dataset.acl.resourceAcl !== "undefined";
1306}
1307function unstable_getResourceAcl(dataset) {
1308 if (!unstable_hasResourceAcl(dataset)) {
1309 return null;
1310 }
1311 return dataset.acl.resourceAcl;
1312}
1313/**
1314 * Verify whether a fallback ACL was found for the given LitDataset.
1315 *
1316 * A LitDataset fetched with [[unstable_fetchLitDatasetWithAcl]] _might_ have a fallback ACL
1317 * attached, but we cannot be sure: the currently authenticated user (if any) might not have Control
1318 * access to one of the fetched Resource's Containers.
1319 *
1320 * This function verifies that the fallback ACL is accessible.
1321 *
1322 * @param dataset A [[LitDataset]] that might have a fallback ACL attached.
1323 * @returns Whether `dataset` has a fallback ACL attached.
1324 */
1325function unstable_hasFallbackAcl(dataset) {
1326 return dataset.acl.fallbackAcl !== null;
1327}
1328function unstable_getFallbackAcl(dataset) {
1329 if (!unstable_hasFallbackAcl(dataset)) {
1330 return null;
1331 }
1332 return dataset.acl.fallbackAcl;
1333}
1334/** @internal */
1335function internal_getAclRules(aclDataset) {
1336 const things = getThingAll(aclDataset);
1337 return things.filter(isAclRule);
1338}
1339function isAclRule(thing) {
1340 return getIriAll(thing, rdf.type).includes(acl.Authorization);
1341}
1342/** @internal */
1343function internal_getResourceAclRulesForResource(aclRules, resource) {
1344 return aclRules.filter((rule) => appliesToResource(rule, resource));
1345}
1346function appliesToResource(aclRule, resource) {
1347 return getIriAll(aclRule, acl.accessTo).includes(resource);
1348}
1349/** @internal */
1350function internal_getDefaultAclRulesForResource(aclRules, resource) {
1351 return aclRules.filter((rule) => isDefaultForResource(rule, resource));
1352}
1353function isDefaultForResource(aclRule, resource) {
1354 return getIriAll(aclRule, acl.default).includes(resource);
1355}
1356/** @internal */
1357function internal_getAccessModes(rule) {
1358 const ruleAccessModes = getIriAll(rule, acl.mode);
1359 const writeAccess = ruleAccessModes.includes(accessModeIriStrings.write);
1360 return writeAccess
1361 ? {
1362 read: ruleAccessModes.includes(accessModeIriStrings.read),
1363 append: true,
1364 write: true,
1365 control: ruleAccessModes.includes(accessModeIriStrings.control),
1366 }
1367 : {
1368 read: ruleAccessModes.includes(accessModeIriStrings.read),
1369 append: ruleAccessModes.includes(accessModeIriStrings.append),
1370 write: false,
1371 control: ruleAccessModes.includes(accessModeIriStrings.control),
1372 };
1373}
1374/** @internal */
1375function internal_combineAccessModes(modes) {
1376 return modes.reduce((accumulator, current) => {
1377 const writeAccess = accumulator.write || current.write;
1378 return writeAccess
1379 ? {
1380 read: accumulator.read || current.read,
1381 append: true,
1382 write: true,
1383 control: accumulator.control || current.control,
1384 }
1385 : {
1386 read: accumulator.read || current.read,
1387 append: accumulator.append || current.append,
1388 write: false,
1389 control: accumulator.control || current.control,
1390 };
1391 }, { read: false, append: false, write: false, control: false });
1392}
1393/**
1394 * IRIs of potential Access Modes
1395 * @internal
1396 */
1397const accessModeIriStrings = {
1398 read: "http://www.w3.org/ns/auth/acl#Read",
1399 append: "http://www.w3.org/ns/auth/acl#Append",
1400 write: "http://www.w3.org/ns/auth/acl#Write",
1401 control: "http://www.w3.org/ns/auth/acl#Control",
1402};
1403
1404/**
1405 * Copyright 2020 Inrupt Inc.
1406 *
1407 * Permission is hereby granted, free of charge, to any person obtaining a copy
1408 * of this software and associated documentation files (the "Software"), to deal in
1409 * the Software without restriction, including without limitation the rights to use,
1410 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
1411 * Software, and to permit persons to whom the Software is furnished to do so,
1412 * subject to the following conditions:
1413 *
1414 * The above copyright notice and this permission notice shall be included in
1415 * all copies or substantial portions of the Software.
1416 *
1417 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
1418 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
1419 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
1420 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
1421 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
1422 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1423 */
1424/**
1425 * Initialise a new [[LitDataset]] in memory.
1426 *
1427 * @returns An empty [[LitDataset]].
1428 */
1429function createLitDataset() {
1430 return dataset.dataset();
1431}
1432/**
1433 * @internal
1434 */
1435const defaultFetchOptions = {
1436 fetch: fetch,
1437};
1438/**
1439 * Fetch a LitDataset from the given URL. Currently requires the LitDataset to be available as [Turtle](https://www.w3.org/TR/turtle/).
1440 *
1441 * @param url URL to fetch a [[LitDataset]] from.
1442 * @param options Optional parameter `options.fetch`: An alternative `fetch` function to make the HTTP request, compatible with the browser-native [fetch API](https://developer.mozilla.org/docs/Web/API/WindowOrWorkerGlobalScope/fetch#parameters).
1443 * @returns Promise resolving to a [[LitDataset]] containing the data at the given Resource, or rejecting if fetching it failed.
1444 */
1445function fetchLitDataset(url, options = defaultFetchOptions) {
1446 return __awaiter(this, void 0, void 0, function* () {
1447 const config = Object.assign(Object.assign({}, defaultFetchOptions), options);
1448 const response = yield config.fetch(url);
1449 if (!response.ok) {
1450 throw new Error(`Fetching the Resource failed: ${response.status} ${response.statusText}.`);
1451 }
1452 const data = yield response.text();
1453 const triples = yield turtleToTriples(data, url);
1454 const resource = dataset.dataset();
1455 triples.forEach((triple) => resource.add(triple));
1456 const datasetInfo = parseDatasetInfo(response);
1457 const resourceWithDatasetInfo = Object.assign(resource, { datasetInfo: datasetInfo });
1458 return resourceWithDatasetInfo;
1459 });
1460}
1461/**
1462 * @internal
1463 */
1464function internal_fetchLitDatasetInfo(url, options = defaultFetchOptions) {
1465 return __awaiter(this, void 0, void 0, function* () {
1466 const config = Object.assign(Object.assign({}, defaultFetchOptions), options);
1467 const response = yield config.fetch(url, { method: "HEAD" });
1468 if (!response.ok) {
1469 throw new Error(`Fetching the Resource metadata failed: ${response.status} ${response.statusText}.`);
1470 }
1471 const datasetInfo = parseDatasetInfo(response);
1472 return { datasetInfo: datasetInfo };
1473 });
1474}
1475function parseDatasetInfo(response) {
1476 const datasetInfo = {
1477 fetchedFrom: response.url,
1478 };
1479 const linkHeader = response.headers.get("Link");
1480 if (linkHeader) {
1481 const parsedLinks = LinkHeader.parse(linkHeader);
1482 const aclLinks = parsedLinks.get("rel", "acl");
1483 if (aclLinks.length === 1) {
1484 datasetInfo.unstable_aclUrl = new URL(aclLinks[0].uri, datasetInfo.fetchedFrom).href;
1485 }
1486 }
1487 const wacAllowHeader = response.headers.get("WAC-Allow");
1488 if (wacAllowHeader) {
1489 datasetInfo.unstable_permissions = parseWacAllowHeader(wacAllowHeader);
1490 }
1491 return datasetInfo;
1492}
1493/**
1494 * Experimental: fetch a LitDataset and its associated Access Control List.
1495 *
1496 * This is an experimental function that fetches both a Resource, the linked ACL Resource (if
1497 * available), and the ACL that applies to it if the linked ACL Resource is not available. This can
1498 * result in many HTTP requests being executed, in lieu of the Solid spec mandating servers to
1499 * provide this info in a single request. Therefore, and because this function is still
1500 * experimental, prefer [[fetchLitDataset]] instead.
1501 *
1502 * If the Resource does not advertise the ACL Resource (because the authenticated user does not have
1503 * access to it), the `acl` property in the returned value will be null. `acl.resourceAcl` will be
1504 * undefined if the Resource's linked ACL Resource could not be fetched (because it does not exist),
1505 * and `acl.fallbackAcl` will be null if the applicable Container's ACL is not accessible to the
1506 * authenticated user.
1507 *
1508 * @param url URL of the LitDataset to fetch.
1509 * @param options Optional parameter `options.fetch`: An alternative `fetch` function to make the HTTP request, compatible with the browser-native [fetch API](https://developer.mozilla.org/docs/Web/API/WindowOrWorkerGlobalScope/fetch#parameters).
1510 * @returns A LitDataset and the ACLs that apply to it, if available to the authenticated user.
1511 */
1512function unstable_fetchLitDatasetWithAcl(url, options = defaultFetchOptions) {
1513 return __awaiter(this, void 0, void 0, function* () {
1514 const litDataset = yield fetchLitDataset(url, options);
1515 if (!unstable_hasAccessibleAcl(litDataset)) {
1516 return Object.assign(litDataset, { acl: null });
1517 }
1518 const [resourceAcl, fallbackAcl] = yield Promise.all([
1519 internal_fetchResourceAcl(litDataset, options),
1520 internal_fetchFallbackAcl(litDataset, options),
1521 ]);
1522 const acl = {
1523 fallbackAcl: fallbackAcl,
1524 resourceAcl: resourceAcl !== null ? resourceAcl : undefined,
1525 };
1526 return Object.assign(litDataset, { acl: acl });
1527 });
1528}
1529const defaultSaveOptions = {
1530 fetch: fetch,
1531};
1532/**
1533 * Given a LitDataset, store it in a Solid Pod (overwriting the existing data at the given URL).
1534 *
1535 * @param url URL to save `litDataset` to.
1536 * @param litDataset The [[LitDataset]] to save.
1537 * @param options Optional parameter `options.fetch`: An alternative `fetch` function to make the HTTP request, compatible with the browser-native [fetch API](https://developer.mozilla.org/docs/Web/API/WindowOrWorkerGlobalScope/fetch#parameters).
1538 * @returns A Promise resolving to a [[LitDataset]] containing the stored data, or rejecting if saving it failed.
1539 */
1540function saveLitDatasetAt(url, litDataset, options = defaultSaveOptions) {
1541 return __awaiter(this, void 0, void 0, function* () {
1542 const config = Object.assign(Object.assign({}, defaultSaveOptions), options);
1543 let requestInit;
1544 if (isUpdate(litDataset, url)) {
1545 const deleteStatement = litDataset.changeLog.deletions.length > 0
1546 ? `DELETE DATA {${(yield triplesToTurtle(litDataset.changeLog.deletions.map(getNamedNodesForLocalNodes))).trim()}};`
1547 : "";
1548 const insertStatement = litDataset.changeLog.additions.length > 0
1549 ? `INSERT DATA {${(yield triplesToTurtle(litDataset.changeLog.additions.map(getNamedNodesForLocalNodes))).trim()}};`
1550 : "";
1551 requestInit = {
1552 method: "PATCH",
1553 body: `${deleteStatement} ${insertStatement}`,
1554 headers: {
1555 "Content-Type": "application/sparql-update",
1556 },
1557 };
1558 }
1559 else {
1560 requestInit = {
1561 method: "PUT",
1562 body: yield triplesToTurtle(Array.from(litDataset).map(getNamedNodesForLocalNodes)),
1563 headers: {
1564 "Content-Type": "text/turtle",
1565 "If-None-Match": "*",
1566 Link: '<http://www.w3.org/ns/ldp#Resource>; rel="type"',
1567 },
1568 };
1569 }
1570 const response = yield config.fetch(url, requestInit);
1571 if (!response.ok) {
1572 throw new Error(`Storing the Resource failed: ${response.status} ${response.statusText}.`);
1573 }
1574 const datasetInfo = hasDatasetInfo(litDataset)
1575 ? Object.assign(Object.assign({}, litDataset.datasetInfo), { fetchedFrom: url }) : { fetchedFrom: url };
1576 const storedDataset = Object.assign(litDataset, {
1577 changeLog: { additions: [], deletions: [] },
1578 datasetInfo: datasetInfo,
1579 });
1580 const storedDatasetWithResolvedIris = resolveLocalIrisInLitDataset(storedDataset);
1581 return storedDatasetWithResolvedIris;
1582 });
1583}
1584function isUpdate(litDataset, url) {
1585 return (hasChangelog(litDataset) &&
1586 hasDatasetInfo(litDataset) &&
1587 typeof litDataset.datasetInfo.fetchedFrom === "string" &&
1588 litDataset.datasetInfo.fetchedFrom === url);
1589}
1590const defaultSaveInContainerOptions = {
1591 fetch: fetch,
1592};
1593/**
1594 * Given a LitDataset, store it in a Solid Pod in a new Resource inside a Container.
1595 *
1596 * @param containerUrl URL of the Container in which to create a new Resource.
1597 * @param litDataset The [[LitDataset]] to save to a new Resource in the given Container.
1598 * @param options Optional parameter `options.fetch`: An alternative `fetch` function to make the HTTP request, compatible with the browser-native [fetch API](https://developer.mozilla.org/docs/Web/API/WindowOrWorkerGlobalScope/fetch#parameters).
1599 * @returns A Promise resolving to a [[LitDataset]] containing the stored data linked to the new Resource, or rejecting if saving it failed.
1600 */
1601function saveLitDatasetInContainer(containerUrl, litDataset, options = defaultSaveInContainerOptions) {
1602 return __awaiter(this, void 0, void 0, function* () {
1603 const config = Object.assign(Object.assign({}, defaultSaveOptions), options);
1604 const rawTurtle = yield triplesToTurtle(Array.from(litDataset).map(getNamedNodesForLocalNodes));
1605 const headers = {
1606 "Content-Type": "text/turtle",
1607 Link: '<http://www.w3.org/ns/ldp#Resource>; rel="type"',
1608 };
1609 if (options.slugSuggestion) {
1610 headers.slug = options.slugSuggestion;
1611 }
1612 const response = yield config.fetch(containerUrl, {
1613 method: "POST",
1614 body: rawTurtle,
1615 headers: headers,
1616 });
1617 if (!response.ok) {
1618 throw new Error(`Storing the Resource in the Container failed: ${response.status} ${response.statusText}.`);
1619 }
1620 const locationHeader = response.headers.get("Location");
1621 if (locationHeader === null) {
1622 throw new Error("Could not determine the location for the newly saved LitDataset.");
1623 }
1624 const resourceIri = new URL(locationHeader, new URL(containerUrl).origin)
1625 .href;
1626 const datasetInfo = {
1627 fetchedFrom: resourceIri,
1628 };
1629 const resourceWithDatasetInfo = Object.assign(litDataset, { datasetInfo: datasetInfo });
1630 const resourceWithResolvedIris = resolveLocalIrisInLitDataset(resourceWithDatasetInfo);
1631 return resourceWithResolvedIris;
1632 });
1633}
1634function getNamedNodesForLocalNodes(quad) {
1635 const subject = isLocalNode(quad.subject)
1636 ? getNamedNodeFromLocalNode(quad.subject)
1637 : quad.subject;
1638 const object = isLocalNode(quad.object)
1639 ? getNamedNodeFromLocalNode(quad.object)
1640 : quad.object;
1641 return Object.assign(Object.assign({}, quad), { subject: subject, object: object });
1642}
1643function getNamedNodeFromLocalNode(localNode) {
1644 return DataFactory.namedNode("#" + localNode.name);
1645}
1646function resolveLocalIrisInLitDataset(litDataset) {
1647 const resourceIri = litDataset.datasetInfo.fetchedFrom;
1648 const unresolvedQuads = Array.from(litDataset);
1649 unresolvedQuads.forEach((unresolvedQuad) => {
1650 const resolvedQuad = resolveIriForLocalNodes(unresolvedQuad, resourceIri);
1651 litDataset.delete(unresolvedQuad);
1652 litDataset.add(resolvedQuad);
1653 });
1654 return litDataset;
1655}
1656/**
1657 * Parse a WAC-Allow header into user and public access booleans.
1658 *
1659 * @param wacAllowHeader A WAC-Allow header in the format `user="read append write control",public="read"`
1660 * @see https://github.com/solid/solid-spec/blob/cb1373a369398d561b909009bd0e5a8c3fec953b/api-rest.md#wac-allow-headers
1661 */
1662function parseWacAllowHeader(wacAllowHeader) {
1663 function parsePermissionStatement(permissionStatement) {
1664 const permissions = permissionStatement.split(" ");
1665 const writePermission = permissions.includes("write");
1666 return writePermission
1667 ? {
1668 read: permissions.includes("read"),
1669 append: true,
1670 write: true,
1671 control: permissions.includes("control"),
1672 }
1673 : {
1674 read: permissions.includes("read"),
1675 append: permissions.includes("append"),
1676 write: false,
1677 control: permissions.includes("control"),
1678 };
1679 }
1680 function getStatementFor(header, scope) {
1681 const relevantEntries = header
1682 .split(",")
1683 .map((rawEntry) => rawEntry.split("="))
1684 .filter((parts) => parts.length === 2 && parts[0].trim() === scope);
1685 // There should only be one statement with the given scope:
1686 if (relevantEntries.length !== 1) {
1687 return "";
1688 }
1689 const relevantStatement = relevantEntries[0][1].trim();
1690 // The given statement should be wrapped in double quotes to be valid:
1691 if (relevantStatement.charAt(0) !== '"' ||
1692 relevantStatement.charAt(relevantStatement.length - 1) !== '"') {
1693 return "";
1694 }
1695 // Return the statment without the wrapping quotes, e.g.: read append write control
1696 return relevantStatement.substring(1, relevantStatement.length - 1);
1697 }
1698 return {
1699 user: parsePermissionStatement(getStatementFor(wacAllowHeader, "user")),
1700 public: parsePermissionStatement(getStatementFor(wacAllowHeader, "public")),
1701 };
1702}
1703
1704/**
1705 * Copyright 2020 Inrupt Inc.
1706 *
1707 * Permission is hereby granted, free of charge, to any person obtaining a copy
1708 * of this software and associated documentation files (the "Software"), to deal in
1709 * the Software without restriction, including without limitation the rights to use,
1710 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
1711 * Software, and to permit persons to whom the Software is furnished to do so,
1712 * subject to the following conditions:
1713 *
1714 * The above copyright notice and this permission notice shall be included in
1715 * all copies or substantial portions of the Software.
1716 *
1717 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
1718 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
1719 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
1720 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
1721 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
1722 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1723 */
1724/**
1725 * Create a new Thing with a URL added for a Predicate.
1726 *
1727 * This preserves existing values for the given Predicate. To replace them, see [[setUrl]].
1728 *
1729 * The original `thing` is not modified; this function returns a cloned Thing with updated values.
1730 *
1731 * @param thing Thing to add a URL value to.
1732 * @param predicate Predicate for which to add the given URL value.
1733 * @param url URL to add to `thing` for the given `predicate`.
1734 * @returns A new Thing equal to the input Thing with the given value added for the given Predicate.
1735 */
1736const addUrl = (thing, predicate, url) => {
1737 const predicateNode = asNamedNode(predicate);
1738 const newThing = cloneThing(thing);
1739 newThing.add(DataFactory.quad(toNode(newThing), predicateNode, toNode(url)));
1740 return newThing;
1741};
1742/** @hidden Alias for [[addUrl]] for those who prefer IRI terminology. */
1743const addIri = addUrl;
1744/**
1745 * Create a new Thing with a boolean added for a Predicate.
1746 *
1747 * This preserves existing values for the given Predicate. To replace them, see [[setBoolean]].
1748 *
1749 * The original `thing` is not modified; this function returns a cloned Thing with updated values.
1750 *
1751 * @param thing Thing to add a boolean value to.
1752 * @param predicate Predicate for which to add the given boolean value.
1753 * @param value Boolean to add to `thing` for the given `predicate`.
1754 * @returns A new Thing equal to the input Thing with the given value added for the given Predicate.
1755 */
1756const addBoolean = (thing, predicate, value) => {
1757 return addLiteralOfType(thing, predicate, serializeBoolean(value), xmlSchemaTypes.boolean);
1758};
1759/**
1760 * Create a new Thing with a datetime added for a Predicate.
1761 *
1762 * This preserves existing values for the given Predicate. To replace them, see [[setDatetime]].
1763 *
1764 * The original `thing` is not modified; this function returns a cloned Thing with updated values.
1765 *
1766 * @param thing Thing to add a datetime value to.
1767 * @param predicate Predicate for which to add the given datetime value.
1768 * @param value Datetime to add to `thing` for the given `predicate`.
1769 * @returns A new Thing equal to the input Thing with the given value added for the given Predicate.
1770 */
1771const addDatetime = (thing, predicate, value) => {
1772 return addLiteralOfType(thing, predicate, serializeDatetime(value), xmlSchemaTypes.dateTime);
1773};
1774/**
1775 * Create a new Thing with a decimal added for a Predicate.
1776 *
1777 * This preserves existing values for the given Predicate. To replace them, see [[setDecimal]].
1778 *
1779 * The original `thing` is not modified; this function returns a cloned Thing with updated values.
1780 *
1781 * @param thing Thing to add a decimal value to.
1782 * @param predicate Predicate for which to add the given decimal value.
1783 * @param value Decimal to add to `thing` for the given `predicate`.
1784 * @returns A new Thing equal to the input Thing with the given value added for the given Predicate.
1785 */
1786const addDecimal = (thing, predicate, value) => {
1787 return addLiteralOfType(thing, predicate, serializeDecimal(value), xmlSchemaTypes.decimal);
1788};
1789/**
1790 * Create a new Thing with an integer added for a Predicate.
1791 *
1792 * This preserves existing values for the given Predicate. To replace them, see [[setInteger]].
1793 *
1794 * The original `thing` is not modified; this function returns a cloned Thing with updated values.
1795 *
1796 * @param thing Thing to add an integer value to.
1797 * @param predicate Predicate for which to add the given integer value.
1798 * @param value Integer to add to `thing` for the given `predicate`.
1799 * @returns A new Thing equal to the input Thing with the given value added for the given Predicate.
1800 */
1801const addInteger = (thing, predicate, value) => {
1802 return addLiteralOfType(thing, predicate, serializeInteger(value), xmlSchemaTypes.integer);
1803};
1804function addStringInLocale(thing, predicate, value, locale) {
1805 const literal = DataFactory.literal(value, normalizeLocale(locale));
1806 return addLiteral(thing, predicate, literal);
1807}
1808/**
1809 * Create a new Thing with an unlocalised string added for a Predicate.
1810 *
1811 * This preserves existing values for the given Predicate. To replace them, see [[setStringUnlocalized]].
1812 *
1813 * The original `thing` is not modified; this function returns a cloned Thing with updated values.
1814 *
1815 * @param thing Thing to add an unlocalised string value to.
1816 * @param predicate Predicate for which to add the given string value.
1817 * @param value String to add to `thing` for the given `predicate`.
1818 * @returns A new Thing equal to the input Thing with the given value added for the given Predicate.
1819 */
1820const addStringUnlocalized = (thing, predicate, value) => {
1821 return addLiteralOfType(thing, predicate, value, xmlSchemaTypes.string);
1822};
1823function addNamedNode(thing, predicate, value) {
1824 const predicateNode = asNamedNode(predicate);
1825 const newThing = cloneThing(thing);
1826 newThing.add(DataFactory.quad(toNode(newThing), predicateNode, value));
1827 return newThing;
1828}
1829function addLiteral(thing, predicate, value) {
1830 const predicateNode = asNamedNode(predicate);
1831 const newThing = cloneThing(thing);
1832 newThing.add(DataFactory.quad(toNode(newThing), predicateNode, value));
1833 return newThing;
1834}
1835function addLiteralOfType(thing, predicate, value, type) {
1836 const literal = DataFactory.literal(value, type);
1837 return addLiteral(thing, predicate, literal);
1838}
1839
1840/**
1841 * Copyright 2020 Inrupt Inc.
1842 *
1843 * Permission is hereby granted, free of charge, to any person obtaining a copy
1844 * of this software and associated documentation files (the "Software"), to deal in
1845 * the Software without restriction, including without limitation the rights to use,
1846 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
1847 * Software, and to permit persons to whom the Software is furnished to do so,
1848 * subject to the following conditions:
1849 *
1850 * The above copyright notice and this permission notice shall be included in
1851 * all copies or substantial portions of the Software.
1852 *
1853 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
1854 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
1855 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
1856 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
1857 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
1858 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1859 */
1860function removeAll(thing, predicate) {
1861 const predicateNode = asNamedNode(predicate);
1862 const updatedThing = filterThing(thing, (quad) => !quad.predicate.equals(predicateNode));
1863 return updatedThing;
1864}
1865/**
1866 * Create a new Thing with the given URL removed for the given Predicate.
1867 *
1868 * The original `thing` is not modified; this function returns a cloned Thing with updated values.
1869 *
1870 * @param thing Thing to remove a URL value from.
1871 * @param predicate Predicate for which to remove the given URL value.
1872 * @param value URL to remove from `thing` for the given `predicate`.
1873 * @returns A new Thing equal to the input Thing with the given value removed for the given Predicate.
1874 */
1875const removeUrl = (thing, predicate, value) => {
1876 const predicateNode = asNamedNode(predicate);
1877 const iriNode = isNamedNode(value)
1878 ? value
1879 : typeof value === "string"
1880 ? asNamedNode(value)
1881 : asNamedNode(asIri(value));
1882 const updatedThing = filterThing(thing, (quad) => {
1883 return (!quad.predicate.equals(predicateNode) ||
1884 !isNamedNode(quad.object) ||
1885 !quad.object.equals(iriNode));
1886 });
1887 return updatedThing;
1888};
1889/** @hidden Alias of [[removeUrl]] for those who prefer IRI terminology. */
1890const removeIri = removeUrl;
1891/**
1892 * Create a new Thing with the given boolean removed for the given Predicate.
1893 *
1894 * The original `thing` is not modified; this function returns a cloned Thing with updated values.
1895 *
1896 * @param thing Thing to remove a boolean value from.
1897 * @param predicate Predicate for which to remove the given boolean value.
1898 * @param value Boolean to remove from `thing` for the given `predicate`.
1899 * @returns A new Thing equal to the input Thing with the given value removed for the given Predicate.
1900 */
1901const removeBoolean = (thing, predicate, value) => {
1902 return removeLiteralOfType(thing, predicate, serializeBoolean(value), xmlSchemaTypes.boolean);
1903};
1904/**
1905 * Create a new Thing with the given datetime removed for the given Predicate.
1906 *
1907 * The original `thing` is not modified; this function returns a cloned Thing with updated values.
1908 *
1909 * @param thing Thing to remove a datetime value from.
1910 * @param predicate Predicate for which to remove the given datetime value.
1911 * @param value Datetime to remove from `thing` for the given `predicate`.
1912 * @returns A new Thing equal to the input Thing with the given value removed for the given Predicate.
1913 */
1914const removeDatetime = (thing, predicate, value) => {
1915 return removeLiteralOfType(thing, predicate, serializeDatetime(value), xmlSchemaTypes.dateTime);
1916};
1917/**
1918 * Create a new Thing with the given decimal removed for the given Predicate.
1919 *
1920 * The original `thing` is not modified; this function returns a cloned Thing with updated values.
1921 *
1922 * @param thing Thing to remove a decimal value from.
1923 * @param predicate Predicate for which to remove the given decimal value.
1924 * @param value Decimal to remove from `thing` for the given `predicate`.
1925 * @returns A new Thing equal to the input Thing with the given value removed for the given Predicate.
1926 */
1927const removeDecimal = (thing, predicate, value) => {
1928 return removeLiteralOfType(thing, predicate, serializeDecimal(value), xmlSchemaTypes.decimal);
1929};
1930/**
1931 * Create a new Thing with the given integer removed for the given Predicate.
1932 *
1933 * The original `thing` is not modified; this function returns a cloned Thing with updated values.
1934 *
1935 * @param thing Thing to remove an integer value from.
1936 * @param predicate Predicate for which to remove the given integer value.
1937 * @param value Integer to remove from `thing` for the given `predicate`.
1938 * @returns A new Thing equal to the input Thing with the given value removed for the given Predicate.
1939 */
1940const removeInteger = (thing, predicate, value) => {
1941 return removeLiteralOfType(thing, predicate, serializeInteger(value), xmlSchemaTypes.integer);
1942};
1943function removeStringInLocale(thing, predicate, value, locale) {
1944 // Note: Due to how the `DataFactory.literal` constructor behaves, this function
1945 // must call directly `removeLiteral` directly, with the locale as the data
1946 // type of the Literal (which is not a valid NamedNode).
1947 return removeLiteral(thing, predicate, DataFactory.literal(value, normalizeLocale(locale)));
1948}
1949/**
1950 * Create a new Thing with the given unlocalised string removed for the given Predicate.
1951 *
1952 * The original `thing` is not modified; this function returns a cloned Thing with updated values.
1953 *
1954 * @param thing Thing to remove an unlocalised string value from.
1955 * @param predicate Predicate for which to remove the given string value.
1956 * @param value String to remove from `thing` for the given `predicate`.
1957 * @returns A new Thing equal to the input Thing with the given value removed for the given Predicate.
1958 */
1959const removeStringUnlocalized = (thing, predicate, value) => {
1960 return removeLiteralOfType(thing, predicate, value, xmlSchemaTypes.string);
1961};
1962function removeNamedNode(thing, predicate, value) {
1963 const predicateNode = asNamedNode(predicate);
1964 const updatedThing = filterThing(thing, (quad) => {
1965 return (!quad.predicate.equals(predicateNode) ||
1966 !isNamedNode(quad.object) ||
1967 !quad.object.equals(value));
1968 });
1969 return updatedThing;
1970}
1971function removeLiteral(thing, predicate, value) {
1972 const predicateNode = asNamedNode(predicate);
1973 const updatedThing = filterThing(thing, (quad) => {
1974 return (!quad.predicate.equals(predicateNode) ||
1975 !isLiteral(quad.object) ||
1976 !quad.object.equals(value));
1977 });
1978 return updatedThing;
1979}
1980function removeLiteralOfType(thing, predicate, value, type) {
1981 const updatedThing = removeLiteral(thing, predicate, DataFactory.literal(value, DataFactory.namedNode(type)));
1982 return updatedThing;
1983}
1984
1985/**
1986 * Copyright 2020 Inrupt Inc.
1987 *
1988 * Permission is hereby granted, free of charge, to any person obtaining a copy
1989 * of this software and associated documentation files (the "Software"), to deal in
1990 * the Software without restriction, including without limitation the rights to use,
1991 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
1992 * Software, and to permit persons to whom the Software is furnished to do so,
1993 * subject to the following conditions:
1994 *
1995 * The above copyright notice and this permission notice shall be included in
1996 * all copies or substantial portions of the Software.
1997 *
1998 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
1999 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
2000 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
2001 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
2002 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
2003 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2004 */
2005/**
2006 * Create a new Thing with existing values replaced by the given URL for the given Predicate.
2007 *
2008 * To preserve existing values, see [[addUrl]].
2009 *
2010 * The original `thing` is not modified; this function returns a cloned Thing with updated values.
2011 *
2012 * @param thing Thing to set a URL value on.
2013 * @param predicate Predicate for which to set the given URL value.
2014 * @param url URL to set on `thing` for the given `predicate`.
2015 * @returns A new Thing equal to the input Thing with existing values replaced by the given value for the given Predicate.
2016 */
2017const setUrl = (thing, predicate, url) => {
2018 const newThing = removeAll(thing, predicate);
2019 const predicateNode = asNamedNode(predicate);
2020 newThing.add(DataFactory.quad(toNode(newThing), predicateNode, toNode(url)));
2021 return newThing;
2022};
2023/** @hidden Alias of [[setUrl]] for those who prefer IRI terminology. */
2024const setIri = setUrl;
2025/**
2026 * Create a new Thing with existing values replaced by the given boolean for the given Predicate.
2027 *
2028 * To preserve existing values, see [[addBoolean]].
2029 *
2030 * The original `thing` is not modified; this function returns a cloned Thing with updated values.
2031 *
2032 * @param thing Thing to set a boolean value on.
2033 * @param predicate Predicate for which to set the given boolean value.
2034 * @param value Boolean to set on `thing` for the given `predicate`.
2035 * @returns A new Thing equal to the input Thing with existing values replaced by the given value for the given Predicate.
2036 */
2037const setBoolean = (thing, predicate, value) => {
2038 return setLiteralOfType(thing, predicate, serializeBoolean(value), xmlSchemaTypes.boolean);
2039};
2040/**
2041 * Create a new Thing with existing values replaced by the given datetime for the given Predicate.
2042 *
2043 * To preserve existing values, see [[addDatetime]].
2044 *
2045 * The original `thing` is not modified; this function returns a cloned Thing with updated values.
2046 *
2047 * @param thing Thing to set an datetime value on.
2048 * @param predicate Predicate for which to set the given datetime value.
2049 * @param value Datetime to set on `thing` for the given `predicate`.
2050 * @returns A new Thing equal to the input Thing with existing values replaced by the given value for the given Predicate.
2051 */
2052const setDatetime = (thing, predicate, value) => {
2053 return setLiteralOfType(thing, predicate, serializeDatetime(value), xmlSchemaTypes.dateTime);
2054};
2055/**
2056 * Create a new Thing with existing values replaced by the given decimal for the given Predicate.
2057 *
2058 * To preserve existing values, see [[addDecimal]].
2059 *
2060 * The original `thing` is not modified; this function returns a cloned Thing with updated values.
2061 *
2062 * @param thing Thing to set a decimal value on.
2063 * @param predicate Predicate for which to set the given decimal value.
2064 * @param value Decimal to set on `thing` for the given `predicate`.
2065 * @returns A new Thing equal to the input Thing with existing values replaced by the given value for the given Predicate.
2066 */
2067const setDecimal = (thing, predicate, value) => {
2068 return setLiteralOfType(thing, predicate, serializeDecimal(value), xmlSchemaTypes.decimal);
2069};
2070/**
2071 * Create a new Thing with existing values replaced by the given integer for the given Predicate.
2072 *
2073 * To preserve existing values, see [[addInteger]].
2074 *
2075 * The original `thing` is not modified; this function returns a cloned Thing with updated values.
2076 *
2077 * @param thing Thing to set an integer value on.
2078 * @param predicate Predicate for which to set the given integer value.
2079 * @param value Integer to set on `thing` for the given `predicate`.
2080 * @returns A new Thing equal to the input Thing with existing values replaced by the given value for the given Predicate.
2081 */
2082const setInteger = (thing, predicate, value) => {
2083 return setLiteralOfType(thing, predicate, serializeInteger(value), xmlSchemaTypes.integer);
2084};
2085function setStringInLocale(thing, predicate, value, locale) {
2086 const literal = DataFactory.literal(value, normalizeLocale(locale));
2087 return setLiteral(thing, predicate, literal);
2088}
2089/**
2090 * Create a new Thing with existing values replaced by the given unlocalised string for the given Predicate.
2091 *
2092 * To preserve existing values, see [[addStringUnlocalized]].
2093 *
2094 * The original `thing` is not modified; this function returns a cloned Thing with updated values.
2095 *
2096 * @param thing Thing to set an unlocalised string value on.
2097 * @param predicate Predicate for which to set the given unlocalised string value.
2098 * @param value Unlocalised string to set on `thing` for the given `predicate`.
2099 * @returns A new Thing equal to the input Thing with existing values replaced by the given value for the given Predicate.
2100 */
2101const setStringUnlocalized = (thing, predicate, value) => {
2102 return setLiteralOfType(thing, predicate, value, xmlSchemaTypes.string);
2103};
2104function setNamedNode(thing, predicate, value) {
2105 const newThing = removeAll(thing, predicate);
2106 const predicateNode = asNamedNode(predicate);
2107 newThing.add(DataFactory.quad(toNode(newThing), predicateNode, value));
2108 return newThing;
2109}
2110function setLiteral(thing, predicate, value) {
2111 const newThing = removeAll(thing, predicate);
2112 const predicateNode = asNamedNode(predicate);
2113 newThing.add(DataFactory.quad(toNode(newThing), predicateNode, value));
2114 return newThing;
2115}
2116function setLiteralOfType(thing, predicate, value, type) {
2117 const literal = DataFactory.literal(value, type);
2118 return setLiteral(thing, predicate, literal);
2119}
2120
2121/**
2122 * Copyright 2020 Inrupt Inc.
2123 *
2124 * Permission is hereby granted, free of charge, to any person obtaining a copy
2125 * of this software and associated documentation files (the "Software"), to deal in
2126 * the Software without restriction, including without limitation the rights to use,
2127 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
2128 * Software, and to permit persons to whom the Software is furnished to do so,
2129 * subject to the following conditions:
2130 *
2131 * The above copyright notice and this permission notice shall be included in
2132 * all copies or substantial portions of the Software.
2133 *
2134 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
2135 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
2136 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
2137 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
2138 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
2139 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2140 */
2141/**
2142 * Find out what Access Modes have been granted to a given Agent specifically for a given LitDataset.
2143 *
2144 * Keep in mind that this function will not tell you what access the given Agent has through other ACL rules, e.g. public or group-specific permissions.
2145 *
2146 * Also, please note that this function is still experimental: its API can change in non-major releases.
2147 *
2148 * @param dataset The LitDataset to which the given Agent may have been granted access.
2149 * @param agent WebID of the Agent for which to retrieve what access it has to the Resource.
2150 * @returns Which Access Modes have been granted to the Agent specifically for the given LitDataset, or `null` if it could not be determined (e.g. because the current user does not have Control Access to a given Resource or its Container).
2151 */
2152function unstable_getAgentAccessModesOne(dataset, agent) {
2153 if (unstable_hasResourceAcl(dataset)) {
2154 const resourceAcl = unstable_getResourceAcl(dataset);
2155 return unstable_getAgentResourceAccessModesOne(resourceAcl, agent);
2156 }
2157 if (unstable_hasFallbackAcl(dataset)) {
2158 const fallbackAcl = unstable_getFallbackAcl(dataset);
2159 return unstable_getAgentDefaultAccessModesOne(fallbackAcl, agent);
2160 }
2161 return null;
2162}
2163/**
2164 * Find out what Access Modes have been granted to specific Agents for a given LitDataset.
2165 *
2166 * Keep in mind that this function will not tell you what access arbitrary Agents might have through other ACL rules, e.g. public or group-specific permissions.
2167 *
2168 * Also, please note that this function is still experimental: its API can change in non-major releases.
2169 *
2170 * @param dataset The LitDataset to which Agents may have been granted access.
2171 * @returns Which Access Modes have been granted to which Agents specifically for the given LitDataset, or `null` if it could not be determined (e.g. because the current user does not have Control Access to a given Resource or its Container).
2172 */
2173function unstable_getAgentAccessModesAll(dataset) {
2174 if (unstable_hasResourceAcl(dataset)) {
2175 const resourceAcl = unstable_getResourceAcl(dataset);
2176 return unstable_getAgentResourceAccessModesAll(resourceAcl);
2177 }
2178 if (unstable_hasFallbackAcl(dataset)) {
2179 const fallbackAcl = unstable_getFallbackAcl(dataset);
2180 return unstable_getAgentDefaultAccessModesAll(fallbackAcl);
2181 }
2182 return null;
2183}
2184/**
2185 * Given an ACL LitDataset, find out which access modes it provides to an Agent for its associated Resource.
2186 *
2187 * Keep in mind that this function will not tell you:
2188 * - what access the given Agent has through other ACL rules, e.g. public or group-specific permissions.
2189 * - what access the given Agent has to child Resources, in case the associated Resource is a Container.
2190 *
2191 * Also, please note that this function is still experimental: its API can change in non-major releases.
2192 *
2193 * @param aclDataset The LitDataset that contains Access-Control List rules.
2194 * @param agent WebID of the Agent for which to retrieve what access it has to the Resource.
2195 * @returns Which Access Modes have been granted to the Agent specifically for the Resource the given ACL LitDataset is associated with.
2196 */
2197function unstable_getAgentResourceAccessModesOne(aclDataset, agent) {
2198 const allRules = internal_getAclRules(aclDataset);
2199 const resourceRules = internal_getResourceAclRulesForResource(allRules, aclDataset.accessTo);
2200 const agentResourceRules = getAgentAclRulesForAgent(resourceRules, agent);
2201 const agentAccessModes = agentResourceRules.map(internal_getAccessModes);
2202 return internal_combineAccessModes(agentAccessModes);
2203}
2204/**
2205 * Given an ACL LitDataset, find out which access modes it provides to specific Agents for the associated Resource.
2206 *
2207 * Keep in mind that this function will not tell you:
2208 * - what access arbitrary Agents might have been given through other ACL rules, e.g. public or group-specific permissions.
2209 * - what access arbitrary Agents have to child Resources, in case the associated Resource is a Container.
2210 *
2211 * Also, please note that this function is still experimental: its API can change in non-major releases.
2212 *
2213 * @param aclDataset The LitDataset that contains Access-Control List rules.
2214 * @returns Which Access Modes have been granted to which Agents specifically for the Resource the given ACL LitDataset is associated with.
2215 */
2216function unstable_getAgentResourceAccessModesAll(aclDataset) {
2217 const allRules = internal_getAclRules(aclDataset);
2218 const resourceRules = internal_getResourceAclRulesForResource(allRules, aclDataset.accessTo);
2219 const agentResourceRules = getAgentAclRules(resourceRules);
2220 return getAccessModesByAgent(agentResourceRules);
2221}
2222/**
2223 * Given an ACL LitDataset, find out which access modes it provides to an Agent for the associated Container Resource's child Resources.
2224 *
2225 * Keep in mind that this function will not tell you:
2226 * - what access the given Agent has through other ACL rules, e.g. public or group-specific permissions.
2227 * - what access the given Agent has to Container Resource itself (see [[unstable_getAgentResourceAccessModesOne]] for that).
2228 *
2229 * Also, please note that this function is still experimental: its API can change in non-major releases.
2230 *
2231 * @param aclDataset The LitDataset that contains Access-Control List rules for a certain Container.
2232 * @param agent WebID of the Agent for which to retrieve what access it has to the Container's children.
2233 * @returns Which Access Modes have been granted to the Agent specifically for the children of the Container associated with the given ACL LitDataset.
2234 */
2235function unstable_getAgentDefaultAccessModesOne(aclDataset, agent) {
2236 const allRules = internal_getAclRules(aclDataset);
2237 const resourceRules = internal_getDefaultAclRulesForResource(allRules, aclDataset.accessTo);
2238 const agentResourceRules = getAgentAclRulesForAgent(resourceRules, agent);
2239 const agentAccessModes = agentResourceRules.map(internal_getAccessModes);
2240 return internal_combineAccessModes(agentAccessModes);
2241}
2242/**
2243 * Given an ACL LitDataset, find out which access modes it provides to specific Agents for the associated Container Resource's child Resources.
2244 *
2245 * Keep in mind that this function will not tell you:
2246 * - what access arbitrary Agents might have been given through other ACL rules, e.g. public or group-specific permissions.
2247 * - what access arbitrary Agents have to the Container Resource itself (see [[unstable_getAgentResourceAccessModesAll]] for that).
2248 *
2249 * Also, please note that this function is still experimental: its API can change in non-major releases.
2250 *
2251 * @param aclDataset The LitDataset that contains Access-Control List rules.
2252 * @returns Which Access Modes have been granted to which Agents specifically for the children of the Container associated with the given ACL LitDataset.
2253 */
2254function unstable_getAgentDefaultAccessModesAll(aclDataset) {
2255 const allRules = internal_getAclRules(aclDataset);
2256 const resourceRules = internal_getDefaultAclRulesForResource(allRules, aclDataset.accessTo);
2257 const agentResourceRules = getAgentAclRules(resourceRules);
2258 return getAccessModesByAgent(agentResourceRules);
2259}
2260function getAgentAclRulesForAgent(aclRules, agent) {
2261 return aclRules.filter((rule) => appliesToAgent(rule, agent));
2262}
2263function appliesToAgent(aclRule, agent) {
2264 return getIriAll(aclRule, acl.agent).includes(agent);
2265}
2266function getAgentAclRules(aclRules) {
2267 return aclRules.filter(isAgentAclRule);
2268}
2269function isAgentAclRule(aclRule) {
2270 return getIriOne(aclRule, acl.agent) !== null;
2271}
2272function getAccessModesByAgent(aclRules) {
2273 const agentAccess = {};
2274 aclRules.forEach((rule) => {
2275 const ruleAgents = getIriAll(rule, acl.agent);
2276 const accessModes = internal_getAccessModes(rule);
2277 // A rule might apply to multiple agents. If multiple rules apply to the same agent, the Access
2278 // Modes granted by those rules should be combined:
2279 ruleAgents.forEach((agent) => {
2280 agentAccess[agent] =
2281 typeof agentAccess[agent] === "undefined"
2282 ? accessModes
2283 : internal_combineAccessModes([agentAccess[agent], accessModes]);
2284 });
2285 });
2286 return agentAccess;
2287}
2288
2289exports.addBoolean = addBoolean;
2290exports.addDatetime = addDatetime;
2291exports.addDecimal = addDecimal;
2292exports.addInteger = addInteger;
2293exports.addIri = addIri;
2294exports.addLiteral = addLiteral;
2295exports.addNamedNode = addNamedNode;
2296exports.addStringInLocale = addStringInLocale;
2297exports.addStringUnlocalized = addStringUnlocalized;
2298exports.addUrl = addUrl;
2299exports.asIri = asIri;
2300exports.asUrl = asUrl;
2301exports.createLitDataset = createLitDataset;
2302exports.createThing = createThing;
2303exports.fetchLitDataset = fetchLitDataset;
2304exports.getBooleanAll = getBooleanAll;
2305exports.getBooleanOne = getBooleanOne;
2306exports.getDatetimeAll = getDatetimeAll;
2307exports.getDatetimeOne = getDatetimeOne;
2308exports.getDecimalAll = getDecimalAll;
2309exports.getDecimalOne = getDecimalOne;
2310exports.getIntegerAll = getIntegerAll;
2311exports.getIntegerOne = getIntegerOne;
2312exports.getIriAll = getIriAll;
2313exports.getIriOne = getIriOne;
2314exports.getLiteralAll = getLiteralAll;
2315exports.getLiteralOne = getLiteralOne;
2316exports.getNamedNodeAll = getNamedNodeAll;
2317exports.getNamedNodeOne = getNamedNodeOne;
2318exports.getStringInLocaleAll = getStringInLocaleAll;
2319exports.getStringInLocaleOne = getStringInLocaleOne;
2320exports.getStringUnlocalizedAll = getStringUnlocalizedAll;
2321exports.getStringUnlocalizedOne = getStringUnlocalizedOne;
2322exports.getThingAll = getThingAll;
2323exports.getThingOne = getThingOne;
2324exports.getUrlAll = getUrlAll;
2325exports.getUrlOne = getUrlOne;
2326exports.removeAll = removeAll;
2327exports.removeBoolean = removeBoolean;
2328exports.removeDatetime = removeDatetime;
2329exports.removeDecimal = removeDecimal;
2330exports.removeInteger = removeInteger;
2331exports.removeIri = removeIri;
2332exports.removeLiteral = removeLiteral;
2333exports.removeNamedNode = removeNamedNode;
2334exports.removeStringInLocale = removeStringInLocale;
2335exports.removeStringUnlocalized = removeStringUnlocalized;
2336exports.removeThing = removeThing;
2337exports.removeUrl = removeUrl;
2338exports.saveLitDatasetAt = saveLitDatasetAt;
2339exports.saveLitDatasetInContainer = saveLitDatasetInContainer;
2340exports.setBoolean = setBoolean;
2341exports.setDatetime = setDatetime;
2342exports.setDecimal = setDecimal;
2343exports.setInteger = setInteger;
2344exports.setIri = setIri;
2345exports.setLiteral = setLiteral;
2346exports.setNamedNode = setNamedNode;
2347exports.setStringInLocale = setStringInLocale;
2348exports.setStringUnlocalized = setStringUnlocalized;
2349exports.setThing = setThing;
2350exports.setUrl = setUrl;
2351exports.unstable_deleteFile = unstable_deleteFile;
2352exports.unstable_fetchFile = unstable_fetchFile;
2353exports.unstable_fetchLitDatasetWithAcl = unstable_fetchLitDatasetWithAcl;
2354exports.unstable_getAgentAccessModesAll = unstable_getAgentAccessModesAll;
2355exports.unstable_getAgentAccessModesOne = unstable_getAgentAccessModesOne;
2356exports.unstable_getAgentDefaultAccessModesAll = unstable_getAgentDefaultAccessModesAll;
2357exports.unstable_getAgentDefaultAccessModesOne = unstable_getAgentDefaultAccessModesOne;
2358exports.unstable_getAgentResourceAccessModesAll = unstable_getAgentResourceAccessModesAll;
2359exports.unstable_getAgentResourceAccessModesOne = unstable_getAgentResourceAccessModesOne;
2360exports.unstable_getFallbackAcl = unstable_getFallbackAcl;
2361exports.unstable_getResourceAcl = unstable_getResourceAcl;
2362exports.unstable_hasFallbackAcl = unstable_hasFallbackAcl;
2363exports.unstable_hasResourceAcl = unstable_hasResourceAcl;
2364exports.unstable_overwriteFile = unstable_overwriteFile;
2365exports.unstable_saveFileInContainer = unstable_saveFileInContainer;