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.
173 lines
5.3 KiB
173 lines
5.3 KiB
import type { ContextDefinition, ExpandedTermDefinition } from "jsonld";
|
|
import type {
|
|
LdoJsonldContext,
|
|
LdoJsonldContextExpandedTermDefinition,
|
|
} from "./LdoJsonldContext.js";
|
|
import type { NamedNode } from "@rdfjs/types";
|
|
|
|
// Create JSONLD Shorthands
|
|
const shorthandToIriMap: Record<string, string> = {
|
|
"@type": "http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
|
|
};
|
|
|
|
/**
|
|
* Context Util
|
|
* Handles the JSON-LD context and allows conversion between IRIs and terms
|
|
*/
|
|
export class ContextUtil {
|
|
public readonly context: ContextDefinition | LdoJsonldContext;
|
|
private iriToKeyMap: Record<string, string>;
|
|
private typeNameToIriToKeyMap: Record<string, Record<string, string>>;
|
|
|
|
constructor(context: ContextDefinition | LdoJsonldContext) {
|
|
this.context = context;
|
|
this.iriToKeyMap = {};
|
|
|
|
// Create the iriToKeyMap
|
|
this.iriToKeyMap = this.createIriToKeyMap(context);
|
|
this.typeNameToIriToKeyMap = {};
|
|
Object.entries(context).forEach(([contextKey, contextValue]) => {
|
|
if (
|
|
typeof contextValue === "object" &&
|
|
contextValue !== null &&
|
|
!!contextValue["@id"] &&
|
|
(contextValue as ExpandedTermDefinition)["@context"]
|
|
) {
|
|
this.typeNameToIriToKeyMap[contextKey] = this.createIriToKeyMap(
|
|
contextValue["@context"],
|
|
);
|
|
}
|
|
});
|
|
}
|
|
|
|
private createIriToKeyMap(
|
|
context: ContextDefinition,
|
|
): Record<string, string> {
|
|
const iriToKeyMap = {};
|
|
Object.entries(context).forEach(([contextKey, contextValue]) => {
|
|
if (typeof contextValue === "string") {
|
|
iriToKeyMap[this.keyIdToIri(contextValue)] = contextKey;
|
|
} else if (
|
|
typeof contextValue === "object" &&
|
|
contextValue !== null &&
|
|
!!contextValue["@id"]
|
|
) {
|
|
const iri = this.keyIdToIri(contextValue["@id"]);
|
|
iriToKeyMap[iri] = contextKey;
|
|
}
|
|
});
|
|
return iriToKeyMap;
|
|
}
|
|
|
|
/**
|
|
* Helper method that gets the relevant context to use if a typename is
|
|
* provided
|
|
*/
|
|
private getRelevantContext(
|
|
key: string,
|
|
typeNames: NamedNode[],
|
|
): ContextDefinition | LdoJsonldContext {
|
|
for (const typeNameNode of typeNames) {
|
|
const typeName = this.iriToKey((typeNameNode as NamedNode).value, []);
|
|
if (
|
|
typeof this.context[typeName] === "object" &&
|
|
this.context[typeName]?.["@context"] &&
|
|
this.context[typeName]?.["@context"][key]
|
|
) {
|
|
return this.context[typeName]?.["@context"];
|
|
}
|
|
}
|
|
return this.context;
|
|
}
|
|
|
|
/**
|
|
* Helper function that applies shorthands to keys
|
|
*/
|
|
private keyIdToIri(keyId: string) {
|
|
if (shorthandToIriMap[keyId]) {
|
|
return shorthandToIriMap[keyId];
|
|
} else {
|
|
return keyId;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Converts a given JsonLd key into an RDF IRI
|
|
*/
|
|
public keyToIri(key: string, typeName: NamedNode[]): string {
|
|
const relevantContext = this.getRelevantContext(key, typeName);
|
|
if (!relevantContext[key]) {
|
|
return key;
|
|
} else if (typeof relevantContext[key] === "string") {
|
|
return this.keyIdToIri(relevantContext[key] as string);
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
} else if (relevantContext[key] && (relevantContext[key] as any)["@id"]) {
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
return this.keyIdToIri((relevantContext[key] as any)["@id"]);
|
|
}
|
|
return key;
|
|
}
|
|
|
|
/**
|
|
* Converts a given RDF IRI into the JsonLd key
|
|
*/
|
|
public iriToKey(iri: string, typeNames: NamedNode[]): string {
|
|
let relevantMap = this.iriToKeyMap;
|
|
for (const typeNameNode of typeNames) {
|
|
const typeName = this.iriToKey((typeNameNode as NamedNode).value, []);
|
|
relevantMap = this.typeNameToIriToKeyMap[typeName]?.[iri]
|
|
? this.typeNameToIriToKeyMap[typeName]
|
|
: this.iriToKeyMap;
|
|
}
|
|
if (relevantMap[iri]) {
|
|
return relevantMap[iri];
|
|
}
|
|
return iri;
|
|
}
|
|
|
|
/**
|
|
* Returns the IRI of a datatype of a specific object
|
|
*/
|
|
public getDataType(key: string, typeName: NamedNode[]): string {
|
|
const relevantContext = this.getRelevantContext(key, typeName);
|
|
if (
|
|
typeof relevantContext[key] === "object" &&
|
|
(relevantContext[key] as ExpandedTermDefinition)["@type"]
|
|
) {
|
|
return (relevantContext[key] as ExpandedTermDefinition)[
|
|
"@type"
|
|
] as string;
|
|
}
|
|
return "http://www.w3.org/2001/XMLSchema#string";
|
|
}
|
|
|
|
/**
|
|
* Returns true if the object is a collection
|
|
*/
|
|
public isSet(key: string, typeName: NamedNode[]): boolean {
|
|
const relevantContext = this.getRelevantContext(key, typeName);
|
|
return !!(
|
|
relevantContext[key] &&
|
|
typeof relevantContext[key] === "object" &&
|
|
((relevantContext[key] as ExpandedTermDefinition)["@container"] ===
|
|
"@set" ||
|
|
(relevantContext[key] as LdoJsonldContextExpandedTermDefinition)[
|
|
"@isCollection"
|
|
])
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Returns true if the object is a language string
|
|
*/
|
|
public isLangString(key: string, typeName: NamedNode[]): boolean {
|
|
const relevantContext = this.getRelevantContext(key, typeName);
|
|
return !!(
|
|
relevantContext[key] &&
|
|
typeof relevantContext[key] === "object" &&
|
|
(relevantContext[key] as ExpandedTermDefinition)["@type"] &&
|
|
(relevantContext[key] as ExpandedTermDefinition)["@type"] ===
|
|
"http://www.w3.org/1999/02/22-rdf-syntax-ns#langString"
|
|
);
|
|
}
|
|
}
|
|
|