diff --git a/src/main/ts/di/LifetimeManager.ts b/src/main/ts/di/LifetimeManager.ts --- a/src/main/ts/di/LifetimeManager.ts +++ b/src/main/ts/di/LifetimeManager.ts @@ -1,6 +1,7 @@ import { IDestroyable, MapOf } from "../interfaces"; import { argumentNotNull, isDestroyable } from "../safe"; -import { ILifetimeManager } from "./interfaces"; +import { ILifetimeManager, ILifetime } from "./interfaces"; +import { ActivationContext } from "./ActivationContext"; function safeCall(item: () => void) { try { @@ -15,32 +16,53 @@ export class LifetimeManager implements private _cache: MapOf = {}; private _destroyed = false; - has(id: string) { - return id in this._cache; - } + initialize(id: string, context: ActivationContext): ILifetime { + const self = this; + let pending = false; + return { + has() { + return (id in self._cache); + }, + + get() { + const t = self._cache[id]; + if (t === undefined) + throw new Error(`The item with with the key ${id} isn't found`); + return t; + }, - get(id: string) { - const t = this._cache[id]; - if (t === undefined) - throw new Error(`The item with with the key ${id} isn't found`); - return t; + enter() { + if (pending) + throw Error(`Cyclic reference detected: the item with the key ${id} is already activating.`); + pending = true; + }, + + store(item: any, cleanup?: (item: any) => void) { + argumentNotNull(id, "id"); + argumentNotNull(item, "item"); + + if (this.has()) + throw new Error(`The item with with the key ${id} already registered with this lifetime manager`); + pending = false; + + self._cache[id] = item; + + if (self._destroyed) + throw new Error("Lifetime manager is destroyed"); + if (cleanup) { + self._cleanup.push(() => cleanup(item)); + } else if (isDestroyable(item)) { + self._cleanup.push(() => item.destroy()); + } + } + }; } - register(id: string, item: any, cleanup?: (item: any) => void) { - argumentNotNull(id, "id"); - argumentNotNull(item, "item"); - if (this.has(id)) - throw new Error(`The item with with the key ${id} already registered with this lifetime manager`); - this._cache[id] = item; + + - if (this._destroyed) - throw new Error("Lifetime manager is destroyed"); - if (cleanup) { - this._cleanup.push(() => cleanup(item)); - } else if (isDestroyable(item)) { - this._cleanup.push(() => item.destroy()); - } - } + + destroy() { if (!this._destroyed) { diff --git a/src/main/ts/di/ServiceDescriptor.ts b/src/main/ts/di/ServiceDescriptor.ts --- a/src/main/ts/di/ServiceDescriptor.ts +++ b/src/main/ts/di/ServiceDescriptor.ts @@ -22,14 +22,15 @@ function injectMethod(method: Cleaner) { +function makeCleanupCallback(method: Cleaner) { if (typeof (method) === "function") { return (target: T) => { method(target); }; } else { return (target: T) => { - (target[method] as any)(); + const m = target[method] as any; + m.apply(target); }; } } @@ -102,7 +103,7 @@ export class ServiceDescriptor void): void; } \ No newline at end of file