import { DescriptorBuilder } from "./DescriptorBuilder"; import { ConfigurableKeys, ContainerServices, ConfigurableServices, RegistrationBuildersMap, RequiredKeys } from "./interfaces"; import { ServiceContainer } from "./interfaces"; import { argumentNotNull, each, isKey } from "./traits"; export class FluentConfiguration = ConfigurableKeys> { _builders: Partial> = {}; declare>>(): FluentConfiguration> { return this as FluentConfiguration>; } provided

>(): FluentConfiguration> { return this as FluentConfiguration>; } register(name: K, builder: RegistrationBuildersMap[K]): FluentConfiguration>; register(config: RegistrationBuildersMap): FluentConfiguration>; register(nameOrConfig: K | RegistrationBuildersMap, builder?: RegistrationBuildersMap[K]) { if (isKey(nameOrConfig)) { argumentNotNull(builder, "builder"); this._builders[nameOrConfig] = builder; } else { each(nameOrConfig, (v, k) => this.register(k, v)); } return this as FluentConfiguration>; } done(missing: RequiredKeys extends never ? void : RequiredKeys) { if (missing !== undefined) throw new Error("The configuration isn't complete"); return this; } apply>(target: ServiceContainer) { let pending = 1; const _t2 = target as ServiceContainer; const reject = (ex: unknown) => { throw ex; }; const complete = () => !--pending; each(this._builders, (v, k) => { pending++; const d = new DescriptorBuilder, NonNullable[typeof k]>>(_t2, result => { _t2.register(k, result); complete(); }, reject ); v(d); }); if (!complete()) throw new Error("The configuration didn't complete."); return _t2 as ServiceContainer; } }