import { DescriptorBuilder } from "./DescriptorBuilder"; import { ConfigurableKeys, ContainerServices, ConfigurableServices, RegistrationBuildersMap, ExtractRequired } from "./interfaces"; import { ServiceContainer } from "./interfaces"; import { argumentNotNull, each, isKey } from "./traits"; export class FluentConfiguration = ConfigurableKeys> { private _builders: Partial> = {}; /** Adds a declaration of the services to the current config. * * @template D The map of the services * @returns self */ declare>>(): FluentConfiguration> { return this as FluentConfiguration>; } /** Adds compile-time information about the already provided services * * @template P The map of the provided services * @returns self */ provided

>(): FluentConfiguration> { return this as FluentConfiguration>; } /** Register the service. * * @param name The name of the service * @param builder The service builder * @returns self */ register(name: K, builder: RegistrationBuildersMap[K]): FluentConfiguration>; /** Registers the collection of services * @param config The collection of services to register. * @returns self */ 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>; } /** * This method is used to enable a compile time check of the configuration. * If there are not configured services in the configuration the compiler * will trigger the error. * * @param missing Empty object literal should always be specified. * @returns self */ // eslint-disable-next-line @typescript-eslint/no-unused-vars done>(missing: M) { 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; } }