UNPKG

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