UNPKG

botframework-webchat-component

Version:
87 lines (67 loc) 2.85 kB
import deepFreeze from 'deep-freeze-strict'; import { type BlankNode } from './BlankNode'; import getSafeOwnPropertyNames from './getSafeOwnPropertyNames'; import isBlankNode from './isBlankNode'; import isUnconnectedBlankNode from './isUnconnectedBlankNode'; import visitOnce from './visitOnce'; function dereferenceBlankNodesInline(objects: object[]): void { const blankNodeIdMap = new Map<string, BlankNode>(); const objectsToVisit1: any[] = [objects]; const shouldVisit1 = visitOnce<object>(); while (objectsToVisit1.length) { const object = objectsToVisit1.shift(); if (!object) { continue; } const indices = getSafeOwnPropertyNames(object); for (const index of indices) { // eslint-disable-next-line security/detect-object-injection const value = object[index]; if (isBlankNode(value) && !isUnconnectedBlankNode(value)) { blankNodeIdMap.set(value['@id'], value); } shouldVisit1(value) && objectsToVisit1.push(value); } } const objectsToVisit2: unknown[] = [objects]; const shouldVisit2 = visitOnce<object>(); while (objectsToVisit2.length) { const object = objectsToVisit2.shift(); if (!object) { continue; } const indices = getSafeOwnPropertyNames(object); for (const index of indices) { // eslint-disable-next-line security/detect-object-injection const value = object[index]; if (isBlankNode(value) && isUnconnectedBlankNode(value)) { const blankNode = blankNodeIdMap.get(value['@id']); if (blankNode) { // eslint-disable-next-line security/detect-object-injection object[index] = blankNode; } } else { shouldVisit2(value) && objectsToVisit2.push(value); } } } } /** * Dereferences all unconnected blank nodes to their corresponding blank node. This is done by replacing all unconnected blank nodes in a graph and purposefully introduce cyclic dependencies to help querying the graph. * * This function will always return a new instance of all objects in the graph. * * This function assumes the graph conforms to JSON-LD, notably: * * - For nodes that share the same blank node identifier, one of them should be connected and the other must be unconnected * - If none of them are connected node, these unconnected blank node will not be replaced * * @see https://json-ld.github.io/json-ld.org/spec/latest/json-ld/#data-model-overview * @param graph A list of nodes in the graph. * @returns A structured clone of graph with unconnected blank nodes replaced by their corresponding blank node. */ export default function dereferenceBlankNodes<T extends object>(graph: T[]): readonly T[] { const nextObjects = structuredClone(graph); dereferenceBlankNodesInline(nextObjects); return deepFreeze(nextObjects); }