From 9b3632e1771d7f922107f95cf3774e7c47bd8e5d Mon Sep 17 00:00:00 2001 From: Jackson Morgan Date: Wed, 6 Mar 2024 22:59:44 -0500 Subject: [PATCH] Context util now supports typeNames --- .../jsonld-dataset-proxy/src/ContextUtil.ts | 143 +++++++++++++----- 1 file changed, 109 insertions(+), 34 deletions(-) diff --git a/packages/jsonld-dataset-proxy/src/ContextUtil.ts b/packages/jsonld-dataset-proxy/src/ContextUtil.ts index a26e5bc..5b2164c 100644 --- a/packages/jsonld-dataset-proxy/src/ContextUtil.ts +++ b/packages/jsonld-dataset-proxy/src/ContextUtil.ts @@ -1,5 +1,8 @@ import type { ContextDefinition, ExpandedTermDefinition } from "jsonld"; -import type { LdoJsonldContext } from "./LdoJsonldContext"; +import type { + LdoJsonldContext, + LdoJsonldContextExpandedTermDefinition, +} from "./LdoJsonldContext"; // Create JSONLD Shorthands const shorthandToIriMap: Record = { @@ -13,38 +16,70 @@ const shorthandToIriMap: Record = { export class ContextUtil { public readonly context: ContextDefinition | LdoJsonldContext; private iriToKeyMap: Record; + private typeNameToIriToKeyMap: Record>; 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 { + const iriToKeyMap = {}; Object.entries(context).forEach(([contextKey, contextValue]) => { if (typeof contextValue === "string") { - this.iriToKeyMap[this.keyIdToIri(contextValue)] = contextKey; + iriToKeyMap[this.keyIdToIri(contextValue)] = contextKey; } else if ( typeof contextValue === "object" && - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (contextValue as any)["@id"] + contextValue !== null && + !!contextValue["@id"] ) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - this.iriToKeyMap[this.keyIdToIri((contextValue as any)["@id"])] = - contextKey; + const iri = this.keyIdToIri(contextValue["@id"]); + iriToKeyMap[iri] = contextKey; } }); + return iriToKeyMap; } - public keyToIri(key: string): string { - if (!this.context[key]) { - return key; - } else if (typeof this.context[key] === "string") { - return this.keyIdToIri(this.context[key] as string); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - } else if (this.context[key] && (this.context[key] as any)["@id"]) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return this.keyIdToIri((this.context[key] as any)["@id"]); + /** + * Helper method that gets the relevant context to use if a typename is + * provided + */ + private getRelevantContext( + key: string, + typeName?: string, + ): ContextDefinition | LdoJsonldContext { + if ( + typeName && + typeof this.context[typeName] === "object" && + this.context[typeName]?.["@context"] && + this.context[typeName]?.["@context"][key] + ) { + return this.context[typeName]?.["@context"]; } - return key; + return this.context; } + /** + * Helper function that applies shorthands to keys + */ private keyIdToIri(keyId: string) { if (shorthandToIriMap[keyId]) { return shorthandToIriMap[keyId]; @@ -53,38 +88,78 @@ export class ContextUtil { } } - public iriToKey(iri: string): string { - if (this.iriToKeyMap[iri]) { - return this.iriToKeyMap[iri]; + /** + * Converts a given JsonLd key into an RDF IRI + */ + public keyToIri(key: string, typeName: string): 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, typeName: string): string { + const relevantMap = + this.typeNameToIriToKeyMap[typeName] || this.iriToKeyMap; + if (relevantMap[iri]) { + return relevantMap[iri]; } return iri; } - public getType(key: string): string { + /** + * Returns the IRI of a datatype of a specific object + */ + public getDataType(key: string, typeName: string): string { + const relevantContext = this.getRelevantContext(key, typeName); if ( - typeof this.context[key] === "object" && - (this.context[key] as ExpandedTermDefinition)["@type"] + typeof relevantContext[key] === "object" && + (relevantContext[key] as ExpandedTermDefinition)["@type"] ) { - return (this.context[key] as ExpandedTermDefinition)["@type"] as string; + return (relevantContext[key] as ExpandedTermDefinition)[ + "@type" + ] as string; } return "http://www.w3.org/2001/XMLSchema#string"; } - public isArray(key: string): boolean { + /** + * Returns true if the object is a collection + */ + public isArray(key: string, typeName: string): boolean { + const relevantContext = this.getRelevantContext(key, typeName); return !!( - this.context[key] && - typeof this.context[key] === "object" && - (this.context[key] as ExpandedTermDefinition)["@container"] && - (this.context[key] as ExpandedTermDefinition)["@container"] === "@set" + relevantContext[key] && + typeof relevantContext[key] === "object" && + (relevantContext[key] as ExpandedTermDefinition)["@container"] && + ((relevantContext[key] as ExpandedTermDefinition)["@container"] === + "@set" || + (relevantContext[key] as LdoJsonldContextExpandedTermDefinition)[ + "@isCollection" + ]) ); } - public isLangString(key: string): boolean { + /** + * Returns true if the object is a language string + */ + public isLangString(key: string, typeName: string): boolean { + const relevantContext = this.getRelevantContext(key, typeName); return !!( - this.context[key] && - typeof this.context[key] === "object" && - (this.context[key] as ExpandedTermDefinition)["@type"] && - (this.context[key] as ExpandedTermDefinition)["@type"] === + 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" ); }