import { Descriptor, ILifetime, ConfigurableKeys, DepsMap, Ref } from "./interfaces"; import { ActivationContext } from "./ActivationContext"; import { each, isKey, key } from "./traits"; export type RegistrationOverridesMap = { [k in ConfigurableKeys]?: Descriptor> }; export interface DescriptorImplArgs { lifetime: ILifetime; factory: (refs: Record) => T; cleanup?: (item: T) => void; overrides?: RegistrationOverridesMap; dependencies?: DepsMap; } export class DescriptorImpl implements Descriptor { private readonly _overrides?: RegistrationOverridesMap; private readonly _lifetime: ILifetime; private readonly _factory: (refs: Record) => T; private readonly _cleanup?: (item: T) => void; private readonly _deps?: DepsMap; constructor({ lifetime, factory, cleanup, overrides, dependencies }: DescriptorImplArgs) { this._lifetime = lifetime; this._factory = factory; if (cleanup) this._cleanup = cleanup; if (overrides) this._overrides = overrides; if (dependencies) this._deps = dependencies; } activate(context: ActivationContext): T { if (this._lifetime.has()) return this._lifetime.get(); this._lifetime.initialize(context); if (this._overrides) each(this._overrides, (v, k) => context.register(k, v)); const resolve = ({ name, lazy, ...opts }: Ref) => { if (lazy) { return () => "default" in opts ? context.resolve(name, opts.default) : context.resolve(name); } else { return "default" in opts ? context.resolve(name, opts.default) : context.resolve(name); } }; const makeRefs = (deps?: DepsMap) => deps ? Object.keys(deps) .map(k => { const ref = deps[k]; return isKey(ref) ? { [k]: resolve({ name: ref }) } : { [k]: resolve(ref) }; }) .reduce((a, p) => ({ ...a, ...p }), {} ) as Record: {} as Record; const instance = this._factory.call(undefined, makeRefs(this._deps)); this._lifetime.store(instance, this._cleanup); return instance; } toString() { return `[object DescriptorImpl, lifetime=${String(this._lifetime)}]`; } }