import { AppError, castTo, type Class, getParentClass } from '@travetto/runtime'; import type { RegistrationMethods, RegistryAdapter, RegistrySimpleStore } from './types.ts'; /** * Base registry index implementation */ export class RegistryIndexStore = RegistryAdapter<{}>> implements RegistrySimpleStore { // Core data #adapters = new Map(); #idToCls = new Map(); #adapterCls: new (cls: Class) => A; #finalized = new Map(); constructor(adapterCls: new (cls: Class) => A) { this.#adapterCls = adapterCls; this.getClassById = this.getClassById.bind(this); } getClasses(): Class[] { return Array.from(this.#adapters.keys()); } getClassById(id: string): Class { return this.#idToCls.get(id)!; } finalize(cls: Class, parentConfig?: ReturnType): void { if (!parentConfig) { const parentClass = getParentClass(cls); parentConfig = castTo(parentClass && this.has(parentClass) ? this.get(parentClass).get() : undefined); } this.adapter(cls).finalize?.(parentConfig); this.#finalized.set(cls, true); } has(cls: Class): boolean { return this.#adapters.has(cls); } adapter(cls: Class): A { if (!this.#adapters.has(cls)!) { const adapter = new this.#adapterCls(cls); this.#adapters.set(cls, adapter); this.#idToCls.set(cls.Ⲑid, cls); } return castTo(this.#adapters.get(cls)); } getForRegister(cls: Class, allowFinalized = false): A { if (this.#finalized.get(cls) && !allowFinalized) { throw new AppError(`Class ${cls.Ⲑid} is already finalized`); } return this.adapter(cls); } get(cls: Class): Omit { if (!this.has(cls)) { throw new AppError(`Class ${cls.Ⲑid} is not registered for ${this.#adapterCls.Ⲑid}`); } return this.adapter(cls); } getOptional(cls: Class): Omit | undefined { if (!this.has(cls)) { return undefined; } return this.adapter(cls); } finalized(cls: Class): boolean { return this.#finalized.has(cls); } }