| @@ -1,6 +1,7 | |||||
| 1 | import { IDestroyable, MapOf } from "../interfaces"; |
|
1 | import { IDestroyable, MapOf } from "../interfaces"; | |
| 2 | import { argumentNotNull, isDestroyable } from "../safe"; |
|
2 | import { argumentNotNull, isDestroyable } from "../safe"; | |
| 3 | import { ILifetimeManager } from "./interfaces"; |
|
3 | import { ILifetimeManager, ILifetime } from "./interfaces"; | |
|
|
4 | import { ActivationContext } from "./ActivationContext"; | |||
| 4 |
|
5 | |||
| 5 | function safeCall(item: () => void) { |
|
6 | function safeCall(item: () => void) { | |
| 6 | try { |
|
7 | try { | |
| @@ -15,32 +16,53 export class LifetimeManager implements | |||||
| 15 | private _cache: MapOf<any> = {}; |
|
16 | private _cache: MapOf<any> = {}; | |
| 16 | private _destroyed = false; |
|
17 | private _destroyed = false; | |
| 17 |
|
18 | |||
| 18 | has(id: string) { |
|
19 | initialize(id: string, context: ActivationContext<any>): ILifetime { | |
| 19 | return id in this._cache; |
|
20 | const self = this; | |
| 20 | } |
|
21 | let pending = false; | |
|
|
22 | return { | |||
|
|
23 | has() { | |||
|
|
24 | return (id in self._cache); | |||
|
|
25 | }, | |||
|
|
26 | ||||
|
|
27 | get() { | |||
|
|
28 | const t = self._cache[id]; | |||
|
|
29 | if (t === undefined) | |||
|
|
30 | throw new Error(`The item with with the key ${id} isn't found`); | |||
|
|
31 | return t; | |||
|
|
32 | }, | |||
| 21 |
|
33 | |||
| 22 | get(id: string) { |
|
34 | enter() { | |
| 23 | const t = this._cache[id]; |
|
35 | if (pending) | |
| 24 | if (t === undefined) |
|
36 | throw Error(`Cyclic reference detected: the item with the key ${id} is already activating.`); | |
| 25 | throw new Error(`The item with with the key ${id} isn't found`); |
|
37 | pending = true; | |
| 26 | return t; |
|
38 | }, | |
|
|
39 | ||||
|
|
40 | store(item: any, cleanup?: (item: any) => void) { | |||
|
|
41 | argumentNotNull(id, "id"); | |||
|
|
42 | argumentNotNull(item, "item"); | |||
|
|
43 | ||||
|
|
44 | if (this.has()) | |||
|
|
45 | throw new Error(`The item with with the key ${id} already registered with this lifetime manager`); | |||
|
|
46 | pending = false; | |||
|
|
47 | ||||
|
|
48 | self._cache[id] = item; | |||
|
|
49 | ||||
|
|
50 | if (self._destroyed) | |||
|
|
51 | throw new Error("Lifetime manager is destroyed"); | |||
|
|
52 | if (cleanup) { | |||
|
|
53 | self._cleanup.push(() => cleanup(item)); | |||
|
|
54 | } else if (isDestroyable(item)) { | |||
|
|
55 | self._cleanup.push(() => item.destroy()); | |||
|
|
56 | } | |||
|
|
57 | } | |||
|
|
58 | }; | |||
| 27 | } |
|
59 | } | |
| 28 |
|
60 | |||
| 29 | register(id: string, item: any, cleanup?: (item: any) => void) { |
|
61 | ||
| 30 | argumentNotNull(id, "id"); |
|
62 | ||
| 31 | argumentNotNull(item, "item"); |
|
|||
| 32 | if (this.has(id)) |
|
|||
| 33 | throw new Error(`The item with with the key ${id} already registered with this lifetime manager`); |
|
|||
| 34 | this._cache[id] = item; |
|
|||
| 35 |
|
63 | |||
| 36 | if (this._destroyed) |
|
64 | ||
| 37 | throw new Error("Lifetime manager is destroyed"); |
|
65 | ||
| 38 | if (cleanup) { |
|
|||
| 39 | this._cleanup.push(() => cleanup(item)); |
|
|||
| 40 | } else if (isDestroyable(item)) { |
|
|||
| 41 | this._cleanup.push(() => item.destroy()); |
|
|||
| 42 | } |
|
|||
| 43 | } |
|
|||
| 44 |
|
66 | |||
| 45 | destroy() { |
|
67 | destroy() { | |
| 46 | if (!this._destroyed) { |
|
68 | if (!this._destroyed) { | |
| @@ -22,14 +22,15 function injectMethod<T, M extends keyof | |||||
| 22 | return m.call(target, _parse(args, context, "." + method)); |
|
22 | return m.call(target, _parse(args, context, "." + method)); | |
| 23 | } |
|
23 | } | |
| 24 |
|
24 | |||
| 25 | function makeClenupCallback<T>(method: Cleaner<T>) { |
|
25 | function makeCleanupCallback<T>(method: Cleaner<T>) { | |
| 26 | if (typeof (method) === "function") { |
|
26 | if (typeof (method) === "function") { | |
| 27 | return (target: T) => { |
|
27 | return (target: T) => { | |
| 28 | method(target); |
|
28 | method(target); | |
| 29 | }; |
|
29 | }; | |
| 30 | } else { |
|
30 | } else { | |
| 31 | return (target: T) => { |
|
31 | return (target: T) => { | |
| 32 |
|
|
32 | const m = target[method] as any; | |
|
|
33 | m.apply(target); | |||
| 33 | }; |
|
34 | }; | |
| 34 | } |
|
35 | } | |
| 35 | } |
|
36 | } | |
| @@ -102,7 +103,7 export class ServiceDescriptor<S extends | |||||
| 102 | throw new Error( |
|
103 | throw new Error( | |
| 103 | "The cleanup parameter must be either a function or a function name"); |
|
104 | "The cleanup parameter must be either a function or a function name"); | |
| 104 |
|
105 | |||
| 105 | this._cleanup = makeClenupCallback(opts.cleanup); |
|
106 | this._cleanup = makeCleanupCallback(opts.cleanup); | |
| 106 | } |
|
107 | } | |
| 107 | } |
|
108 | } | |
| 108 |
|
109 | |||
| @@ -112,6 +113,7 export class ServiceDescriptor<S extends | |||||
| 112 | if (lifetime.has()) { |
|
113 | if (lifetime.has()) { | |
| 113 | return lifetime.get(); |
|
114 | return lifetime.get(); | |
| 114 | } else { |
|
115 | } else { | |
|
|
116 | lifetime.enter(); | |||
| 115 | const instance = this._create(context); |
|
117 | const instance = this._create(context); | |
| 116 | lifetime.store(this._cacheId, this._cleanup); |
|
118 | lifetime.store(this._cacheId, this._cleanup); | |
| 117 | return instance; |
|
119 | return instance; | |
| @@ -46,6 +46,10 export interface ILifetimeManager extend | |||||
| 46 |
|
46 | |||
| 47 | export interface ILifetime { |
|
47 | export interface ILifetime { | |
| 48 | has(): boolean; |
|
48 | has(): boolean; | |
|
|
49 | ||||
| 49 | get(): any; |
|
50 | get(): any; | |
|
|
51 | ||||
|
|
52 | enter(): void; | |||
|
|
53 | ||||
| 50 | store(item: any, cleanup?: (item: any) => void): void; |
|
54 | store(item: any, cleanup?: (item: any) => void): void; | |
| 51 | } No newline at end of file |
|
55 | } | |
General Comments 0
You need to be logged in to leave comments.
Login now
