import { ErrorCode, ErrorUtils } from "js-moi-utils"; import type { LogicManifest } from "../types/manifest"; import { ContextStateMatrix } from "./context-state-matrix"; /** * This class represents a descriptor for elements in the logic manifest. */ export class ElementDescriptor { protected stateMatrix: ContextStateMatrix; protected elements: Map = new Map(); protected callSites: Map = new Map(); protected classDefs: Map = new Map(); protected methodDefs: Map = new Map(); protected eventsDefs = new Map(); constructor(elements: LogicManifest.Element[]) { this.stateMatrix = new ContextStateMatrix(elements); // Populate the maps for elements, call sites, class and method definitions. for (const element of elements) { this.elements.set(element.ptr, element); switch (element.kind) { case "class": const classData = element.data as LogicManifest.Class; this.classDefs.set("class." + classData.name, element.ptr); break; case "method": const methodData = element.data as LogicManifest.Method; const methodDef: LogicManifest.MethodDef = { ptr: element.ptr, class: methodData.class, }; this.methodDefs.set(methodData.name, methodDef); break; case "callable": const routineData = element.data as LogicManifest.Routine; const callsite: LogicManifest.CallSite = { ptr: element.ptr, kind: routineData.kind, }; this.callSites.set(routineData.name, callsite); break; case "event": const eventData = element.data as LogicManifest.Event; this.eventsDefs.set(eventData.name, { ptr: element.ptr, topics: eventData.topics }); break; default: break; } } } /** * Retrieves the state matrix associated with the ElementDescriptor. * * @returns {ContextStateMatrix} The state matrix. */ public getStateMatrix(): ContextStateMatrix { return this.stateMatrix; } /** * Retrieves the map of elements associated with the ElementDescriptor. * * @returns {Map} The elements map. */ public getElements(): Map { return this.elements; } /** * Retrieves the map of call sites associated with the ElementDescriptor. * * @returns {Map} The call sites map. */ public getCallsites(): Map { return this.callSites; } /** * Retrieves the map of class definitions associated with the ElementDescriptor. * * @returns {Map} The class definitions map. */ public getClassDefs(): Map { return this.classDefs; } public getEvents(): Map { return this.eventsDefs; } /** * Retrieves the map of method definitions associated with the ElementDescriptor. * * @returns {Map} The method definitions map. */ public getMethodDefs(): Map { return this.methodDefs; } /** * Retrieves the methods of a class based on the given class name. * * @param {string} className - The name of the class. * @returns {Map} The methods of the class. * @throws {Error} if the class name is invalid. */ public getClassMethods(className: string): Map { const classPtr = this.classDefs.get(className); if (classPtr === undefined) { return ErrorUtils.throwError(`Invalid class name: ${className}`, ErrorCode.INVALID_ARGUMENT); } const classMethods: Map = new Map(); this.methodDefs.forEach((method, methodName) => { if (method.class === className) { const element = this.elements.get(method.ptr); if (element) { classMethods.set(methodName, element.data as LogicManifest.Method); } } }); return classMethods; } /** * Retrieves the element from the logic manifest based on the given * routine name. * * @param {string} routineName - The name of the routine. * @returns {LogicManifest.Element} The routine element. * @throws {Error} if the routine name is invalid. */ public getRoutineElement(routineName: string): LogicManifest.Element { const callsite = this.callSites.get(routineName); if (!callsite) { return ErrorUtils.throwError(`Invalid routine name: ${routineName}`, ErrorCode.INVALID_ARGUMENT); } return this.elements.get(callsite.ptr)!; } /** * Retrieves the element from the logic manifest based on the given * class name. * * @returns {LogicManifest.Element} The class element. * @throws {Error} if the class name is invalid. */ public getClassElement(className: string): LogicManifest.Element { const ptr = this.classDefs.get(className); if (ptr === undefined) { return ErrorUtils.throwError(`Invalid routine name: ${className}`, ErrorCode.INVALID_ARGUMENT); } return this.elements.get(ptr)!; } /** * Retrieves the element from the logic manifest based on the given * method name. * * @param {string} methodName - The name of the method. * @returns {LogicManifest.Element} The method element. * @throws {Error} if the method name is invalid. */ public getMethodElement(methodName: string): LogicManifest.Element { const methodDef = this.methodDefs.get(methodName); if (!methodDef) { return ErrorUtils.throwError(`Invalid routine name: ${methodName}`, ErrorCode.INVALID_ARGUMENT); } return this.elements.get(methodDef.ptr)!; } /** * Retrieves the element from the logic manifest based on the given * event name. * * @param {string} eventName - The name of the event. * @returns {LogicManifest.Element} The event element. * * @throws {Error} if the event name is invalid. */ public getEventElement(eventName: string) { const eventDef = this.eventsDefs.get(eventName); if (!eventDef) { return ErrorUtils.throwError(`Invalid event name: ${eventName}`, ErrorCode.INVALID_ARGUMENT); } return this.elements.get(eventDef.ptr) as LogicManifest.Element; } }