|
|
import { ActivationContext } from "./ActivationContext";
|
|
|
import { ActivationError } from "./ActivationError";
|
|
|
import { ContainerBuilder } from "./ContainerBuilder";
|
|
|
import { DescriptorMap, IContainerBuilder, IDestroyable, ILifetimeManager, ServiceLocator } from "./interfaces";
|
|
|
|
|
|
export class Container<S> implements ServiceLocator<S>, IDestroyable {
|
|
|
private readonly _services: DescriptorMap<S>;
|
|
|
|
|
|
private readonly _lifetimeManager: ILifetimeManager;
|
|
|
|
|
|
private _disposed: boolean;
|
|
|
|
|
|
private readonly _onDestroyed: () => void;
|
|
|
|
|
|
constructor(services: DescriptorMap<S>, lifetimeManager: ILifetimeManager, destroyed: () => void) {
|
|
|
this._services = {
|
|
|
...services,
|
|
|
container: {
|
|
|
configurable: false,
|
|
|
activate: () => this
|
|
|
},
|
|
|
childContainer: {
|
|
|
configurable: false,
|
|
|
activate: () => this.createChildBuilder(),
|
|
|
}
|
|
|
};
|
|
|
|
|
|
this._disposed = false;
|
|
|
this._lifetimeManager = lifetimeManager;
|
|
|
this._onDestroyed = destroyed;
|
|
|
|
|
|
}
|
|
|
|
|
|
private _assertNotDestroyed() {
|
|
|
if (this._disposed)
|
|
|
throw new Error("The container is destroyed");
|
|
|
}
|
|
|
|
|
|
createChildBuilder(): IContainerBuilder<S, keyof S> {
|
|
|
this._assertNotDestroyed();
|
|
|
|
|
|
const lifetime = this._lifetimeManager.create<IDestroyable>();
|
|
|
|
|
|
return new ContainerBuilder(this._services, lifetime);
|
|
|
}
|
|
|
|
|
|
resolve<K extends keyof S>(name: K): NonNullable<S[K]>;
|
|
|
resolve<K extends keyof S, T>(name: K, def: T): NonNullable<S[K]> | T;
|
|
|
resolve<K extends keyof S, T>(name: K, def?: T) {
|
|
|
this._assertNotDestroyed();
|
|
|
|
|
|
const d = this._services[name];
|
|
|
if (d === undefined) {
|
|
|
if (arguments.length > 1)
|
|
|
return def;
|
|
|
else
|
|
|
throw new Error(`Service '${String(name)}' isn't found`);
|
|
|
} else {
|
|
|
const context = new ActivationContext(this._lifetimeManager, this._services, String(name), d);
|
|
|
try {
|
|
|
return d.activate(context);
|
|
|
} catch (error) {
|
|
|
throw new ActivationError(name.toString(), context.getStack(), error);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
destroy() {
|
|
|
if (this._disposed)
|
|
|
return;
|
|
|
this._disposed = true;
|
|
|
this._lifetimeManager.destroy();
|
|
|
(0,this._onDestroyed)();
|
|
|
}
|
|
|
}
|
|
|
|