FluentConfiguration.ts
93 lines
| 3.2 KiB
| video/mp2t
|
TypeScriptLexer
|
|
r0 | import { DescriptorBuilder } from "./DescriptorBuilder"; | ||
|
|
r2 | import { ConfigurableKeys, ContainerServices, ConfigurableServices, RegistrationBuildersMap, ExtractRequired } from "./interfaces"; | ||
|
|
r1 | import { ServiceContainer } from "./interfaces"; | ||
| import { argumentNotNull, each, isKey } from "./traits"; | ||||
|
|
r0 | |||
|
|
r1 | export class FluentConfiguration<S extends object, Y extends ConfigurableKeys<S> = ConfigurableKeys<S>> { | ||
|
|
r0 | |||
|
|
r2 | private _builders: Partial<RegistrationBuildersMap<S>> = {}; | ||
|
|
r0 | |||
|
|
r2 | /** Adds a declaration of the services to the current config. | ||
| * | ||||
| * @template D The map of the services | ||||
| * @returns self | ||||
| */ | ||||
|
|
r1 | declare<D extends Partial<Pick<S, keyof D & keyof S>>>(): FluentConfiguration<S & D, Y | ConfigurableKeys<D>> { | ||
| return this as FluentConfiguration<S & D, Y | ConfigurableKeys<D>>; | ||||
|
|
r0 | } | ||
|
|
r2 | /** Adds compile-time information about the already provided services | ||
| * | ||||
| * @template P The map of the provided services | ||||
| * @returns self | ||||
| */ | ||||
|
|
r1 | provided<P extends Pick<S, keyof P & keyof S>>(): FluentConfiguration<S & P, Exclude<Y, keyof P>> { | ||
| return this as FluentConfiguration<S & P, Exclude<Y, keyof P>>; | ||||
| } | ||||
|
|
r2 | /** Register the service. | ||
| * | ||||
| * @param name The name of the service | ||||
| * @param builder The service builder | ||||
| * @returns self | ||||
| */ | ||||
|
|
r1 | register<K extends Y>(name: K, builder: RegistrationBuildersMap<S>[K]): FluentConfiguration<S, Exclude<Y, K>>; | ||
|
|
r2 | /** Registers the collection of services | ||
| * @param config The collection of services to register. | ||||
| * @returns self | ||||
| */ | ||||
|
|
r1 | register<K extends Y>(config: RegistrationBuildersMap<S, K>): FluentConfiguration<S, Exclude<Y, K>>; | ||
| register<K extends Y>(nameOrConfig: K | RegistrationBuildersMap<S, K>, builder?: RegistrationBuildersMap<S>[K]) { | ||||
| if (isKey(nameOrConfig)) { | ||||
|
|
r0 | argumentNotNull(builder, "builder"); | ||
| this._builders[nameOrConfig] = builder; | ||||
| } else { | ||||
| each(nameOrConfig, (v, k) => this.register(k, v)); | ||||
| } | ||||
|
|
r1 | return this as FluentConfiguration<S, Exclude<Y, K>>; | ||
| } | ||||
|
|
r2 | /** | ||
| * 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<M extends ExtractRequired<S,Y>>(missing: M) { | ||||
|
|
r0 | return this; | ||
| } | ||||
|
|
r4 | apply<T extends ServiceContainer<S>>(target: T) { | ||
|
|
r0 | |||
| let pending = 1; | ||||
|
|
r1 | const reject = (ex: unknown) => { throw ex; }; | ||
| const complete = () => !--pending; | ||||
|
|
r0 | |||
|
|
r1 | each(this._builders, (v, k) => { | ||
| pending++; | ||||
|
|
r4 | const d = new DescriptorBuilder<ContainerServices<S>, NonNullable<ConfigurableServices<S>[typeof k]>>( | ||
| target, | ||||
|
|
r1 | result => { | ||
|
|
r4 | target.register(k, result); | ||
|
|
r1 | complete(); | ||
| }, | ||||
| reject | ||||
| ); | ||||
|
|
r0 | |||
|
|
r1 | |||
| v(d); | ||||
|
|
r0 | }); | ||
|
|
r1 | if (!complete()) | ||
| throw new Error("The configuration didn't complete."); | ||||
|
|
r4 | return target as T & ServiceContainer<S>; | ||
|
|
r0 | } | ||
| } | ||||
