|
|
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<S extends object, Y extends ConfigurableKeys<S> = ConfigurableKeys<S>> {
|
|
|
|
|
|
_builders: Partial<RegistrationBuildersMap<S>> = {};
|
|
|
|
|
|
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>>;
|
|
|
}
|
|
|
|
|
|
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>>;
|
|
|
}
|
|
|
|
|
|
register<K extends Y>(name: K, builder: RegistrationBuildersMap<S>[K]): FluentConfiguration<S, Exclude<Y, K>>;
|
|
|
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)) {
|
|
|
argumentNotNull(builder, "builder");
|
|
|
this._builders[nameOrConfig] = builder;
|
|
|
} else {
|
|
|
each(nameOrConfig, (v, k) => this.register(k, v));
|
|
|
}
|
|
|
|
|
|
return this as FluentConfiguration<S, Exclude<Y, K>>;
|
|
|
}
|
|
|
|
|
|
done(missing: RequiredKeys<S, Y> extends never ? void : RequiredKeys<S, Y>) {
|
|
|
if (missing !== undefined)
|
|
|
throw new Error("The configuration isn't complete");
|
|
|
return this;
|
|
|
}
|
|
|
|
|
|
|
|
|
apply<A extends Partial<S>>(target: ServiceContainer<A>) {
|
|
|
|
|
|
let pending = 1;
|
|
|
|
|
|
const _t2 = target as ServiceContainer<S>;
|
|
|
|
|
|
const reject = (ex: unknown) => { throw ex; };
|
|
|
|
|
|
const complete = () => !--pending;
|
|
|
|
|
|
each(this._builders, (v, k) => {
|
|
|
pending++;
|
|
|
const d = new DescriptorBuilder<ContainerServices<S>, NonNullable<ConfigurableServices<S>[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<A & S>;
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|