import { Container } from "./Container"; import { DescriptorBuilder } from "./DescriptorBuilder"; import { containerSelfDescriptor } from "./DescriptorImpl"; import { Descriptor, IContainerBuilder, IDescriptorBuilder, DescriptorMap, ServiceLocator, ILifetime, IDestroyable, ContainerServices, ContainerServicesConstraint } from "./interfaces"; import { emptyLifetime, LifetimeManager } from "./LifetimeManager"; import { isDestroyable, prototype } from "./traits"; /** * Container builder used to prepare service descriptors and create a IoC container */ export class ContainerBuilder implements IContainerBuilder { private _pending = 1; private readonly _services: DescriptorMap>; private readonly _lifetimeManager = new LifetimeManager(); private readonly _lifetime: ILifetime; constructor(parentServices: DescriptorMap | null = null, lifetime?: ILifetime) { this._services = { ...parentServices }; // create a copy this._lifetime = lifetime ?? emptyLifetime(); } createServiceBuilder(name: K): IDescriptorBuilder, U> { return new DescriptorBuilder(this._lifetimeManager, this._register(name), this._fail); } build(): ServiceLocator { this._assertBuilding(); if (!this._complete()) throw new Error("The configuration didn't complete."); const {remove, store} = this._lifetime(null); const container = new Container(this._services, this._lifetimeManager, remove); store(container); return container; } private readonly _register = (name: K) => (descriptor: Descriptor) => { this._complete(); this._services[name] = descriptor; }; private readonly _fail = (ex: unknown) => { throw ex; }; private _assertBuilding() { if (!this._pending) throw new Error("The descriptor builder is finalized"); } private _complete() { return !(--this._pending); } }