import type { FaceContext, OntologyFaceDefinition } from "#types/ontology.types"; import { collectionCycle, duplicateCollection, unregisteredCollection } from "#configuration/strings/ontology.strings"; const REGISTRY = new Map(); export const defineOntologyFace = function defineOntologyFace

( definition: OntologyFaceDefinition

, ): OntologyFaceDefinition

{ if (REGISTRY.has(definition.name)) { throw new Error(duplicateCollection(definition.name)); } const frozen = Object.freeze({ ...definition, dependsOn: Object.freeze([...(definition.dependsOn ?? [])]) }); REGISTRY.set(definition.name, frozen); return frozen; }; interface FoldState { byName: Map; built: Map; building: Set; context: FaceContext; } const buildFace = function buildFace(name: string, state: FoldState): unknown { if (state.built.has(name)) { return state.built.get(name); } if (state.building.has(name)) { throw new Error(collectionCycle(name)); } const definition = state.byName.get(name); if (!definition) { throw new Error(unregisteredCollection(name)); } state.building.add(name); const dependencies: Record = {}; for (const dependency of definition.dependsOn ?? []) { dependencies[dependency] = buildFace(dependency, state); } const port = definition.build(state.context, dependencies); state.building.delete(name); state.built.set(name, port); return port; }; export const foldFaces = function foldFaces( definitions: readonly OntologyFaceDefinition[], context: FaceContext, ): Map { const state: FoldState = { building: new Set(), built: new Map(), byName: new Map(definitions.map((definition) => [definition.name, definition])), context, }; for (const definition of definitions) { buildFace(definition.name, state); } return state.built; };