UNPKG

@travetto/registry

Version:

Patterns and utilities for handling registration of metadata and functionality for run-time use

77 lines (62 loc) 2.15 kB
import { AppError, castTo, type Class, getParentClass } from '@travetto/runtime'; import type { RegistrationMethods, RegistryAdapter, RegistrySimpleStore } from './types.ts'; /** * Base registry index implementation */ export class RegistryIndexStore<A extends RegistryAdapter<{}> = RegistryAdapter<{}>> implements RegistrySimpleStore { // Core data #adapters = new Map<Class, A>(); #idToCls = new Map<string, Class>(); #adapterCls: new (cls: Class) => A; #finalized = new Map<Class, boolean>(); 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<A['get']>): 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<A, RegistrationMethods> { 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<A, RegistrationMethods> | undefined { if (!this.has(cls)) { return undefined; } return this.adapter(cls); } finalized(cls: Class): boolean { return this.#finalized.has(cls); } }