import { ActivationContext } from "./ActivationContext"; import { ActivationError } from "./ActivationError"; import { ContainerBuilder } from "./ContainerBuilder"; import { LifetimeManager } from "./LifetimeManager"; import { DescriptorMap, IContainerBuilder, IDestroyable, ILifetimeManager, ServiceLocator } from "./interfaces"; export class Container implements ServiceLocator, IDestroyable { private readonly _services: DescriptorMap; private readonly _lifetimeManagers: ILifetimeManager[]; private _disposed: boolean; private readonly _onDestroyed: () => void; constructor(services: DescriptorMap, lifetimeManagers: ILifetimeManager[], destroyed: () => void) { this._services = services; this._disposed = false; this._lifetimeManagers = lifetimeManagers.concat(new LifetimeManager()); this._onDestroyed = destroyed; } private _assertNotDestroyed() { if (this._disposed) throw new Error("The container is destroyed"); } createChildBuilder(): IContainerBuilder { this._assertNotDestroyed(); const lifetime = this._lifetimeManager.create(); return new ContainerBuilder(this._services, lifetime); } resolve(name: K): NonNullable; resolve(name: K, def: T): NonNullable | T; resolve(name: K, def?: T) { this._assertNotDestroyed(); const d = this._services[name]; if (d === undefined) { if (arguments.length > 1) return def; else throw new Error(`Service '${String(name)}' isn't found`); } else { const context = new ActivationContext(this._lifetimeManagers, this._services, String(name), d); try { return d.activate(context); } catch (error) { throw new ActivationError(name.toString(), context.getStack(), error); } } } destroy() { if (this._disposed) return; this._disposed = true; this._lifetimeManager.destroy(); (0,this._onDestroyed)(); } }