##// END OF EJS Templates
initial commit
initial commit

File last commit:

r0:9cf129973079 default
r0:9cf129973079 default
Show More
DescriptorBuilder.ts
145 lines | 4.4 KiB | video/mp2t | TypeScriptLexer
/ src / main / ts / DescriptorBuilder.ts
import { Resolver, RegistrationBuilder } from "./interfaces";
import { Descriptor, ILifetime, ActivationType, PartialServiceMap, ServiceContainer } from "./interfaces";
import { DescriptorImpl } from "./DescriptorImpl";
import { LifetimeManager } from "./LifetimeManager";
export class DescriptorBuilder<S extends object, T> {
private readonly _container: ServiceContainer<S>;
private readonly _cb: (d: Descriptor<S, T>) => void;
private readonly _eb: (err: any) => void;
private _lifetime = LifetimeManager.empty();
private _overrides?: PartialServiceMap<S>;
private _cleanup?: (item: T) => void;
private _factory?: (resolve: Resolver<S>) => T;
private _pending = 1;
private _failed = false;
constructor(container: ServiceContainer<S>, cb: (d: Descriptor<S, T>) => void, eb: (err: any) => void) {
this._container = container;
this._cb = cb;
this._eb = eb;
}
build<T2>(): DescriptorBuilder<S, T2> {
this._defer();
return new DescriptorBuilder<S, T2>(this._container, () => this._complete(), err => this._fail(err));
}
override<K extends keyof S>(name: K, builder: RegistrationBuilder<S, S[K]>): this;
override<K extends keyof S>(services: { [name in K]: RegistrationBuilder<S, S[K]> }): this;
override<K extends keyof S>(nameOrServices: K | { [name in K]: RegistrationBuilder<S, S[K]> }, builder?: RegistrationBuilder<S, S[K]>): this {
const overrides: PartialServiceMap<S> = this._overrides ?
this._overrides :
(this._overrides = {});
const guard = (v: void | Promise<void>) => {
if (isPromise(v))
v.catch(err => this._fail(err));
};
if (isPrimitive(nameOrServices)) {
if (builder) {
this._defer();
const d = new DescriptorBuilder<S, S[K]>(
this._container,
result => {
overrides[nameOrServices] = result;
this._complete();
},
err => this._fail(err)
);
try {
guard(builder(d));
} catch (err) {
this._fail(err);
}
}
} else {
each(nameOrServices, (v, k) => this.override(k, v));
}
return this;
}
lifetime(lifetime: "singleton", typeId: string): this;
lifetime(lifetime: ILifetime | Exclude<ActivationType, "singleton">): this;
lifetime(lifetime: ILifetime | ActivationType, typeId?: string): this {
if (isString(lifetime)) {
this._lifetime = this._resolveLifetime(lifetime, typeId);
} else {
this._lifetime = lifetime;
}
return this;
}
cleanup(cb: (item: T) => void): this {
this._cleanup = cb;
return this;
}
factory(f: (resolve: Resolver<S>) => T): void {
this._factory = f;
this._complete();
}
value(v: T): void {
this._cb({
activate() {
return v;
}
});
}
_resolveLifetime(activation: ActivationType, typeId?: string | object) {
switch (activation) {
case "container":
return LifetimeManager.containerLifetime(this._container);
case "hierarchy":
return LifetimeManager.hierarchyLifetime();
case "context":
return LifetimeManager.contextLifetime();
case "singleton":
if (!typeId)
throw Error("The singleton activation requires a typeId");
const _oid = isString(typeId) ? typeId : oid(typeId);
return LifetimeManager.singletonLifetime(_oid);
default:
return LifetimeManager.empty();
}
}
_defer() {
this._pending++;
}
_complete() {
if (--this._pending === 0) {
if (!this._factory)
throw new Error("The factory must be specified");
this._cb(new DescriptorImpl<S, T>({
lifetime: this._lifetime,
factory: this._factory,
overrides: this._overrides,
cleanup: this._cleanup
}));
}
}
_fail(err: any) {
if (!this._failed) {
this._failed = true;
this._eb.call(undefined, err);
}
}
}