@travetto/registry
Version:
Patterns and utilities for handling registration of metadata and functionality for run-time use
77 lines (62 loc) • 2.15 kB
text/typescript
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);
}
}