##// END OF EJS Templates
sync
sync

File last commit:

r15:3985e8405319 tip default
r15:3985e8405319 tip default
Show More
ActivationContext.ts
111 lines | 4.1 KiB | video/mp2t | TypeScriptLexer
/ src / main / ts / ActivationContext.ts
import { ActivationError, ActivationItem } from "./ActivationError";
import { IActivationContext, DescriptorMap, ILifetimeManager, ILifetimeSlot, ServiceLocator, IContainerBuilder } from "../typings/interfaces";
import { argumentNotNull, each, prototype } from "./traits";
import { LifetimeManager } from "./LifetimeManager";
import { ContainerBuilder } from "./ContainerBuilder";
/** This object is created once per `Container.resolve` method call and used to
* cache dependencies and to track created instances. The activation context
* tracks services with `context` activation type.
*
* @template S The service map used in the activation context, services from
* this map are available to resolution.
* @template U A set of keys from the service map which can be overridden in
* this activation context.
*/
export class ActivationContext<S> implements IActivationContext<S> {
private readonly _container: ServiceLocator<S>;
private readonly _contextScope: ILifetimeManager;
private _services: DescriptorMap<S>;
private readonly _scope: ILifetimeManager[];
/** Creates a new activation context with the specified parameters.
* @param containerLifetimeManager the container which starts the activation process
* @param services the initial service registrations
* @param name the name of the service being activated, this parameter is
* used for the debug purpose.
* @param service the service to activate, this parameter is used for the
* debug purpose.
*/
constructor(container: ServiceLocator<S>, scope: ILifetimeManager[], services: DescriptorMap<S>, contextScope: ILifetimeManager = new LifetimeManager()) {
this._container = container;
this._contextScope = contextScope;
this._services = services;
this._scope = scope;
}
resolve<K extends keyof S>(name: K, stack: ActivationItem[]): NonNullable<S[K]>;
resolve<K extends keyof S, T>(name: K, stack: ActivationItem[], def: T): NonNullable<S[K]> | T;
resolve<K extends keyof S, T>(name: K, stack: ActivationItem[], def?: T): NonNullable<S[K]> | T | undefined {
const service = this._services[name];
if (service !== undefined) {
return service.activate(
this,
stack.concat({
name: name.toString(),
descriptor: service.toString()
})
);
} else {
if (arguments.length > 2)
return def;
else
throw new Error("Service not found");
}
}
/**
* registers services local to the the activation context
*
* @name{string} the name of the service
* @service{string} the service descriptor to register
*/
private _register<K extends keyof S>(name: K, service: DescriptorMap<S>[K]) {
argumentNotNull(name, "name");
const d = this._services[name];
if (d !== undefined && !d.configurable)
throw new Error(`Service ${String(name)} can't be overridden`);
this._services[name] = service;
}
scopeSlot<T>(level: number, slotId: string | number): ILifetimeSlot<T> {
if (level < 0 || level >= this._scope.length)
throw new Error("The scope level is out of range");
return this._scope[level].slot(slotId);
}
hierarchySlot<T>(slotId: string | number): ILifetimeSlot<T> {
return this._scope[this._scope.length - 1].slot(slotId);
}
selfContainer(): ServiceLocator<S> {
return this._container;
}
createChildContainer(): IContainerBuilder<S, keyof S> {
return new ContainerBuilder(this._services, this._scope);
}
contextSlot<T>(slotId: string | number): ILifetimeSlot<T> {
return this._contextScope.slot(slotId);
}
withOverrides<X>(overrides: DescriptorMap<S>, action: () => X) {
const services = this._services;
this._services = prototype(this._services);
try {
each(overrides, (v, k) => this._register(k, v));
return action();
} finally {
this._services = services;
}
}
}