You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
140 lines
4.3 KiB
140 lines
4.3 KiB
import { parseRdf } from "@ldo/ldo";
|
|
import { namedNode, quad as createQuad } from "@rdfjs/data-model";
|
|
import type { Dataset } from "@rdfjs/types";
|
|
import type { ContainerUri } from "./uriTypes";
|
|
import { isContainerUri } from "./uriTypes";
|
|
import { NoncompliantPodError } from "../requester/results/error/NoncompliantPodError";
|
|
import { UnexpectedResourceError } from "../requester/results/error/ErrorResult";
|
|
|
|
export const ldpContains = namedNode("http://www.w3.org/ns/ldp#contains");
|
|
export const rdfType = namedNode(
|
|
"http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
|
|
);
|
|
export const ldpResource = namedNode("http://www.w3.org/ns/ldp#Resource");
|
|
export const ldpContainer = namedNode("http://www.w3.org/ns/ldp#Container");
|
|
export const ldpBasicContainer = namedNode(
|
|
"http://www.w3.org/ns/ldp#BasicContainer",
|
|
);
|
|
|
|
/**
|
|
* @internal
|
|
* Gets the URI of a parent according the the Solid Spec
|
|
*
|
|
* @param uri - the child URI
|
|
* @returns A parent URI or undefined if not possible
|
|
*/
|
|
export function getParentUri(uri: string): ContainerUri | undefined {
|
|
const urlObject = new URL(uri);
|
|
const pathItems = urlObject.pathname.split("/");
|
|
if (
|
|
pathItems.length < 2 ||
|
|
(pathItems.length === 2 && pathItems[1].length === 0)
|
|
) {
|
|
return undefined;
|
|
}
|
|
if (pathItems[pathItems.length - 1] === "") {
|
|
pathItems.pop();
|
|
}
|
|
pathItems.pop();
|
|
urlObject.pathname = `${pathItems.join("/")}/`;
|
|
return urlObject.toString() as ContainerUri;
|
|
}
|
|
|
|
/**
|
|
* @internal
|
|
* Gets the slug (last part of the path) for a given URI
|
|
*
|
|
* @param uri - the full URI
|
|
* @returns the slug of the URI
|
|
*/
|
|
export function getSlug(uri: string): string {
|
|
const urlObject = new URL(uri);
|
|
const pathItems = urlObject.pathname.split("/");
|
|
return pathItems[pathItems.length - 1] || pathItems[pathItems.length - 2];
|
|
}
|
|
|
|
/**
|
|
* @internal
|
|
* Deletes mention of a resource from the provided dataset
|
|
*
|
|
* @param resourceUri - the resource to delete
|
|
* @param dataset - dataset to modify
|
|
*/
|
|
export function deleteResourceRdfFromContainer(
|
|
resourceUri: string,
|
|
dataset: Dataset,
|
|
) {
|
|
const parentUri = getParentUri(resourceUri);
|
|
if (parentUri) {
|
|
const parentNode = namedNode(parentUri);
|
|
const resourceNode = namedNode(resourceUri);
|
|
dataset.delete(
|
|
createQuad(parentNode, ldpContains, resourceNode, parentNode),
|
|
);
|
|
dataset.deleteMatches(resourceNode, undefined, undefined, parentNode);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @internal
|
|
* Adds a resource to a container in an RDF dataset
|
|
*
|
|
* @param resourceUri - the resource to add
|
|
* @param dataset - the dataset to modify
|
|
*/
|
|
export function addResourceRdfToContainer(
|
|
resourceUri: string,
|
|
dataset: Dataset,
|
|
) {
|
|
const parentUri = getParentUri(resourceUri);
|
|
if (parentUri) {
|
|
const parentNode = namedNode(parentUri);
|
|
const resourceNode = namedNode(resourceUri);
|
|
dataset.add(createQuad(parentNode, ldpContains, resourceNode, parentNode));
|
|
dataset.add(createQuad(resourceNode, rdfType, ldpResource, parentNode));
|
|
if (isContainerUri(resourceUri)) {
|
|
dataset.add(
|
|
createQuad(resourceNode, rdfType, ldpBasicContainer, parentNode),
|
|
);
|
|
dataset.add(createQuad(resourceNode, rdfType, ldpContainer, parentNode));
|
|
}
|
|
addResourceRdfToContainer(parentUri, dataset);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @internal
|
|
* Adds raw turtle to the provided dataset
|
|
* @param rawTurtle - String of raw turtle
|
|
* @param dataset - the dataset to modify
|
|
* @param baseUri - base URI to parsing turtle
|
|
* @returns Undefined if successful, noncompliantPodError if not
|
|
*/
|
|
export async function addRawTurtleToDataset(
|
|
rawTurtle: string,
|
|
dataset: Dataset,
|
|
baseUri: string,
|
|
): Promise<undefined | NoncompliantPodError> {
|
|
let loadedDataset: Dataset;
|
|
try {
|
|
loadedDataset = await parseRdf(rawTurtle, {
|
|
baseIRI: baseUri,
|
|
});
|
|
} catch (err) {
|
|
const error = UnexpectedResourceError.fromThrown(baseUri, err);
|
|
return new NoncompliantPodError(
|
|
baseUri,
|
|
`Request returned noncompliant turtle: ${error.message}`,
|
|
);
|
|
}
|
|
|
|
const graphNode = namedNode(baseUri);
|
|
// Destroy all triples that were once a part of this resouce
|
|
dataset.deleteMatches(undefined, undefined, undefined, graphNode);
|
|
// Add the triples from the fetched item
|
|
dataset.addAll(
|
|
loadedDataset.map((quad) =>
|
|
createQuad(quad.subject, quad.predicate, quad.object, graphNode),
|
|
),
|
|
);
|
|
}
|
|
|