Select Git revision
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
linkedData.ts 3.12 KiB
import factory from "rdf-ext";
import { Readable } from "stream";
import rdfParser from "rdf-parse";
import type { Dataset, Quad } from "@rdfjs/types";
import formats from "@rdfjs-elements/formats-pretty";
import stringifyStream from "stream-to-string";
import { MetadataApi } from "@coscine/api-client";
import type DatasetExt from "rdf-ext/lib/Dataset";
export async function parseRDFDefinition(
definition: string,
contentType = "text/turtle",
baseIRI = "http://coscine.rwth-aachen.de"
): Promise<Dataset> {
const input = new Readable({
read: () => {
input.push(definition);
input.push(null);
},
});
const dataset = factory.dataset();
await new Promise((resolve) => {
rdfParser
.parse(input, { contentType: contentType, baseIRI: baseIRI })
.on("data", (quad: Quad) => dataset.add(quad))
.on("error", (error: unknown) => console.error(error))
.on("end", () => resolve(dataset));
});
return dataset as unknown as Dataset;
}
export async function serializeRDFDefinition(
dataset: Dataset,
contentType = "text/turtle"
): Promise<string> {
const canonical = dataset.toCanonical();
if (!canonical) {
return "";
}
const output = formats.serializers.import(contentType, dataset.toStream());
if (output === null) {
return "";
}
return await stringifyStream(output as NodeJS.ReadableStream);
}
/**
* Deals with import statements and create a full application profile
* @param baseUrl Base Url of the starting dataset
* @param dataset The starting dataset
* @returns Full Dataset with every imported dataset
*/
export async function resolveImports(
baseUrl: string,
dataset: Dataset
): Promise<Dataset> {
let fullApplicationProfile = dataset;
const toScanAPs = [dataset];
const owlImportsNode = factory.namedNode(
"http://www.w3.org/2002/07/owl#imports"
);
const visitedAPs = [baseUrl];
while (toScanAPs.length > 0) {
const dataset = toScanAPs.pop();
if (dataset) {
const importedAPs = Array.from(
dataset.match(null, owlImportsNode, null)
).map((quad) => quad.object);
for (const importedAP of importedAPs) {
if (
importedAP.termType === "NamedNode" &&
!visitedAPs.includes(importedAP.value)
) {
try {
const importedApiResponse = await MetadataApi.metadataGetProfile(
importedAP.value
);
const importedApplicationProfile = await parseRDFDefinition(
JSON.stringify(importedApiResponse.data),
"application/ld+json",
importedAP.value
);
fullApplicationProfile = (
fullApplicationProfile as unknown as DatasetExt
).merge(
importedApplicationProfile as unknown as DatasetExt
) as unknown as Dataset;
toScanAPs.push(importedApplicationProfile);
} catch {
console.error(
`The application profile ${importedAP.value} is not accessible.`
);
} finally {
visitedAPs.push(importedAP.value);
}
}
}
}
}
return fullApplicationProfile;
}