| @@ -71,7 +71,6 function(declare, safe, when, QueryResul | |||||
| 71 | }); |
|
71 | }); | |
| 72 | mapped.total = total; |
|
72 | mapped.total = total; | |
| 73 | var results = new QueryResults(mapped); |
|
73 | var results = new QueryResults(mapped); | |
| 74 | console.log(results); |
|
|||
| 75 | return results; |
|
74 | return results; | |
| 76 | }); |
|
75 | }); | |
| 77 | }, |
|
76 | }, | |
| @@ -2,8 +2,10 import { Cancellation } from "../Cancell | |||||
| 2 | import { IAsyncComponent, ICancellation, ICancellable, IDestroyable } from "../interfaces"; |
|
2 | import { IAsyncComponent, ICancellation, ICancellable, IDestroyable } from "../interfaces"; | |
| 3 | import { destroy } from "../safe"; |
|
3 | import { destroy } from "../safe"; | |
| 4 |
|
4 | |||
|
|
5 | const noop = () => void (0); | |||
|
|
6 | ||||
| 5 | export class AsyncComponent implements IAsyncComponent, ICancellable { |
|
7 | export class AsyncComponent implements IAsyncComponent, ICancellable { | |
| 6 |
_cancel: ((e: any) => void) |
|
8 | _cancel: ((e: any) => void) = noop; | |
| 7 |
|
9 | |||
| 8 | _completion: Promise<void> = Promise.resolve(); |
|
10 | _completion: Promise<void> = Promise.resolve(); | |
| 9 |
|
11 | |||
| @@ -26,7 +28,7 export class AsyncComponent implements I | |||||
| 26 | // after the operation is complete we need to cleanup the |
|
28 | // after the operation is complete we need to cleanup the | |
| 27 | // resources |
|
29 | // resources | |
| 28 | destroy(h); |
|
30 | destroy(h); | |
| 29 |
this._cancel = |
|
31 | this._cancel = noop; | |
| 30 | } |
|
32 | } | |
| 31 | }; |
|
33 | }; | |
| 32 |
|
34 | |||
| @@ -34,7 +36,6 export class AsyncComponent implements I | |||||
| 34 | } |
|
36 | } | |
| 35 |
|
37 | |||
| 36 | cancel(reason: any) { |
|
38 | cancel(reason: any) { | |
| 37 |
|
|
39 | this._cancel(reason); | |
| 38 | this._cancel(reason); |
|
|||
| 39 | } |
|
40 | } | |
| 40 | } |
|
41 | } | |
| @@ -1,6 +1,6 | |||||
| 1 | import { TraceSource } from "../log/TraceSource"; |
|
1 | import { TraceSource } from "../log/TraceSource"; | |
| 2 | import { argumentNotEmptyString } from "../safe"; |
|
2 | import { argumentNotEmptyString } from "../safe"; | |
| 3 | import { Descriptor, ContainerServiceMap, ContainerKeys, TypeOfService } from "./interfaces"; |
|
3 | import { Descriptor, ContainerServiceMap, ContainerKeys, TypeOfService, ILifetime } from "./interfaces"; | |
| 4 | import { Container } from "./Container"; |
|
4 | import { Container } from "./Container"; | |
| 5 | import { MapOf } from "../interfaces"; |
|
5 | import { MapOf } from "../interfaces"; | |
| 6 |
|
6 | |||
| @@ -13,6 +13,8 export interface ActivationContextInfo { | |||||
| 13 |
|
13 | |||
| 14 | } |
|
14 | } | |
| 15 |
|
15 | |||
|
|
16 | let nextId = 1; | |||
|
|
17 | ||||
| 16 | export class ActivationContext<S extends object> { |
|
18 | export class ActivationContext<S extends object> { | |
| 17 | _cache: MapOf<any>; |
|
19 | _cache: MapOf<any>; | |
| 18 |
|
20 | |||
| @@ -73,18 +75,23 export class ActivationContext<S extends | |||||
| 73 | this._services[name] = service as any; |
|
75 | this._services[name] = service as any; | |
| 74 | } |
|
76 | } | |
| 75 |
|
77 | |||
| 76 | has(id: string) { |
|
78 | createLifetime(): ILifetime { | |
| 77 | return id in this._cache; |
|
79 | const id = nextId++; | |
|
|
80 | const me = this; | |||
|
|
81 | return { | |||
|
|
82 | initialize() { | |||
|
|
83 | }, | |||
|
|
84 | has() { | |||
|
|
85 | return id in me._cache; | |||
|
|
86 | }, | |||
|
|
87 | get() { | |||
|
|
88 | return me._cache[id]; | |||
|
|
89 | }, | |||
|
|
90 | store(item: any) { | |||
|
|
91 | me._cache[id] = item; | |||
|
|
92 | } | |||
|
|
93 | }; | |||
| 78 | } |
|
94 | } | |
| 79 |
|
||||
| 80 | get<T>(id: string) { |
|
|||
| 81 | return this._cache[id]; |
|
|||
| 82 | } |
|
|||
| 83 |
|
||||
| 84 | store(id: string, value: any) { |
|
|||
| 85 | return (this._cache[id] = value); |
|
|||
| 86 | } |
|
|||
| 87 |
|
||||
| 88 | activate<T>(d: Descriptor<S, T>, name: string) { |
|
95 | activate<T>(d: Descriptor<S, T>, name: string) { | |
| 89 | if (trace.isLogEnabled()) |
|
96 | if (trace.isLogEnabled()) | |
| 90 | trace.log(`enter ${name} ${d}`); |
|
97 | trace.log(`enter ${name} ${d}`); | |
| @@ -3,7 +3,7 import { | |||||
| 3 | ActivationType, |
|
3 | ActivationType, | |
| 4 | ContainerKeys, |
|
4 | ContainerKeys, | |
| 5 | TypeOfService, |
|
5 | TypeOfService, | |
| 6 |
ILifetime |
|
6 | ILifetime | |
| 7 | } from "./interfaces"; |
|
7 | } from "./interfaces"; | |
| 8 |
|
8 | |||
| 9 | import { argumentNotEmptyString, isPrimitive, isPromise, delegate, argumentOfType, argumentNotNull, get, primitive } from "../safe"; |
|
9 | import { argumentNotEmptyString, isPrimitive, isPromise, delegate, argumentOfType, argumentNotNull, get, primitive } from "../safe"; | |
| @@ -281,9 +281,11 export class Configuration<S extends obj | |||||
| 281 | trace.debug("<{0}", name); |
|
281 | trace.debug("<{0}", name); | |
| 282 | } |
|
282 | } | |
| 283 |
|
283 | |||
| 284 |
|
|
284 | _visit(data: any, name: string): Promise<any> { | |
| 285 |
if (isPrimitive(data) |
|
285 | if (isPrimitive(data)) | |
| 286 | return data; |
|
286 | return Promise.resolve(new ValueDescriptor(data)); | |
|
|
287 | if (isDescriptor(data)) | |||
|
|
288 | return Promise.resolve(data); | |||
| 287 |
|
289 | |||
| 288 | if (isDependencyRegistration<S>(data)) { |
|
290 | if (isDependencyRegistration<S>(data)) { | |
| 289 | return this._visitDependencyRegistration(data, name); |
|
291 | return this._visitDependencyRegistration(data, name); | |
| @@ -398,9 +400,11 export class Configuration<S extends obj | |||||
| 398 | opts.type = data.$type; |
|
400 | opts.type = data.$type; | |
| 399 | } else { |
|
401 | } else { | |
| 400 | const [moduleName, typeName] = data.$type.split(":", 2); |
|
402 | const [moduleName, typeName] = data.$type.split(":", 2); | |
| 401 |
|
|
403 | opts.type = this._resolveType(moduleName, typeName).then(t => { | |
| 402 | if (!(t instanceof Function)) |
|
404 | if (!(t instanceof Function)) | |
| 403 | throw Error("$type (" + data.$type + ") is not a constructable"); |
|
405 | throw Error("$type (" + data.$type + ") is not a constructable"); | |
|
|
406 | return t; | |||
|
|
407 | }); | |||
| 404 | } |
|
408 | } | |
| 405 |
|
409 | |||
| 406 | const d = new TypeServiceDescriptor<S, any, any[]>( |
|
410 | const d = new TypeServiceDescriptor<S, any, any[]>( | |
| @@ -427,20 +431,20 export class Configuration<S extends obj | |||||
| 427 | return d; |
|
431 | return d; | |
| 428 | } |
|
432 | } | |
| 429 |
|
433 | |||
| 430 |
_getLifetimeManager(activation: ActivationType, typeId: string | undefined): ILifetime |
|
434 | _getLifetimeManager(activation: ActivationType, typeId: string | undefined): ILifetime { | |
| 431 | switch (activation) { |
|
435 | switch (activation) { | |
| 432 | case "container": |
|
436 | case "container": | |
| 433 | return this._container.getLifetimeManager(); |
|
437 | return LifetimeManager.containerLifetime(this._container); | |
| 434 | case "hierarchy": |
|
438 | case "hierarchy": | |
| 435 | return LifetimeManager.hierarchyLifetime; |
|
439 | return LifetimeManager.hierarchyLifetime(); | |
| 436 | case "context": |
|
440 | case "context": | |
| 437 | return LifetimeManager.contextLifetime; |
|
441 | return LifetimeManager.contextLifetime(); | |
| 438 | case "singleton": |
|
442 | case "singleton": | |
| 439 | if (typeId === undefined) |
|
443 | if (typeId === undefined) | |
| 440 | throw Error("The singleton activation requires a typeId"); |
|
444 | throw Error("The singleton activation requires a typeId"); | |
| 441 | return LifetimeManager.singletonLifetime(typeId); |
|
445 | return LifetimeManager.singletonLifetime(typeId); | |
| 442 | default: |
|
446 | default: | |
| 443 | return LifetimeManager.empty; |
|
447 | return LifetimeManager.empty(); | |
| 444 | } |
|
448 | } | |
| 445 | } |
|
449 | } | |
| 446 | } |
|
450 | } | |
| @@ -38,7 +38,7 export class LazyReferenceDescriptor<S e | |||||
| 38 |
|
38 | |||
| 39 | const saved = context.clone(); |
|
39 | const saved = context.clone(); | |
| 40 |
|
40 | |||
| 41 | return (cfg?: PartialServiceMap<S>) => { |
|
41 | return (cfg?: PartialServiceMap<S>): any => { | |
| 42 | // защищаем контекст на случай исключения в процессе |
|
42 | // защищаем контекст на случай исключения в процессе | |
| 43 | // активации |
|
43 | // активации | |
| 44 | const ct = cfg ? saved.clone() : saved; |
|
44 | const ct = cfg ? saved.clone() : saved; | |
| @@ -2,6 +2,7 import { IDestroyable, MapOf } from "../ | |||||
| 2 | import { argumentNotNull, isDestroyable } from "../safe"; |
|
2 | import { argumentNotNull, isDestroyable } from "../safe"; | |
| 3 | import { ILifetimeManager, ILifetime } from "./interfaces"; |
|
3 | import { ILifetimeManager, ILifetime } from "./interfaces"; | |
| 4 | import { ActivationContext } from "./ActivationContext"; |
|
4 | import { ActivationContext } from "./ActivationContext"; | |
|
|
5 | import { Container } from "./Container"; | |||
| 5 |
|
6 | |||
| 6 | function safeCall(item: () => void) { |
|
7 | function safeCall(item: () => void) { | |
| 7 | try { |
|
8 | try { | |
| @@ -16,7 +17,7 const emptyLifetime: ILifetime = { | |||||
| 16 | return false; |
|
17 | return false; | |
| 17 | }, |
|
18 | }, | |
| 18 |
|
19 | |||
| 19 | enter() { |
|
20 | initialize() { | |
| 20 |
|
21 | |||
| 21 | }, |
|
22 | }, | |
| 22 |
|
23 | |||
| @@ -30,6 +31,21 const emptyLifetime: ILifetime = { | |||||
| 30 |
|
31 | |||
| 31 | }; |
|
32 | }; | |
| 32 |
|
33 | |||
|
|
34 | const unknownLifetime: ILifetime = { | |||
|
|
35 | has() { | |||
|
|
36 | throw new Error("The lifetime is unknown"); | |||
|
|
37 | }, | |||
|
|
38 | initialize() { | |||
|
|
39 | throw new Error("Can't call initialize on the unknown lifetime object"); | |||
|
|
40 | }, | |||
|
|
41 | get() { | |||
|
|
42 | throw new Error("The lifetime object isn't initialized"); | |||
|
|
43 | }, | |||
|
|
44 | store() { | |||
|
|
45 | throw new Error("Can't store a value in the unknown lifetime object"); | |||
|
|
46 | } | |||
|
|
47 | } | |||
|
|
48 | ||||
| 33 | let nextId = 0; |
|
49 | let nextId = 0; | |
| 34 |
|
50 | |||
| 35 | export class LifetimeManager implements IDestroyable, ILifetimeManager { |
|
51 | export class LifetimeManager implements IDestroyable, ILifetimeManager { | |
| @@ -39,7 +55,7 export class LifetimeManager implements | |||||
| 39 |
|
55 | |||
| 40 | private _pending: MapOf<boolean> = {}; |
|
56 | private _pending: MapOf<boolean> = {}; | |
| 41 |
|
57 | |||
| 42 |
|
|
58 | create(): ILifetime { | |
| 43 | const self = this; |
|
59 | const self = this; | |
| 44 | const id = ++nextId; |
|
60 | const id = ++nextId; | |
| 45 | return { |
|
61 | return { | |
| @@ -54,7 +70,7 export class LifetimeManager implements | |||||
| 54 | return t; |
|
70 | return t; | |
| 55 | }, |
|
71 | }, | |
| 56 |
|
72 | |||
| 57 |
|
|
73 | initialize() { | |
| 58 | if (self._pending[id]) |
|
74 | if (self._pending[id]) | |
| 59 | throw Error(`Cyclic reference detected: the item with the key ${id} is already activating.`); |
|
75 | throw Error(`Cyclic reference detected: the item with the key ${id} is already activating.`); | |
| 60 | self._pending[id] = true; |
|
76 | self._pending[id] = true; | |
| @@ -89,43 +105,71 export class LifetimeManager implements | |||||
| 89 | } |
|
105 | } | |
| 90 | } |
|
106 | } | |
| 91 |
|
107 | |||
| 92 |
static |
|
108 | static empty(): ILifetime { | |
| 93 | initialize(): ILifetime { |
|
109 | return emptyLifetime; | |
| 94 | return emptyLifetime; |
|
110 | } | |
| 95 | } |
|
111 | ||
| 96 | }; |
|
112 | static hierarchyLifetime(): ILifetime { | |
|
|
113 | let _lifetime = unknownLifetime; | |||
|
|
114 | return { | |||
|
|
115 | initialize(context: ActivationContext<any>) { | |||
|
|
116 | if (_lifetime !== unknownLifetime) | |||
|
|
117 | throw new Error("Cyclic reference activation detected"); | |||
| 97 |
|
118 | |||
| 98 | static readonly hierarchyLifetime: ILifetimeManager = { |
|
119 | _lifetime = context.getContainer().getLifetimeManager().create(context); | |
| 99 | initialize(context: ActivationContext<any>): ILifetime { |
|
120 | }, | |
| 100 | return context.getContainer().getLifetimeManager().initialize(context); |
|
121 | get() { | |
| 101 | } |
|
122 | return _lifetime.get(); | |
| 102 | }; |
|
123 | }, | |
|
|
124 | has() { | |||
|
|
125 | return _lifetime.has(); | |||
|
|
126 | }, | |||
|
|
127 | store(item: any, cleanup?: (item: any) => void) { | |||
|
|
128 | return _lifetime.store(item, cleanup); | |||
|
|
129 | } | |||
|
|
130 | }; | |||
|
|
131 | } | |||
| 103 |
|
132 | |||
| 104 |
static |
|
133 | static contextLifetime(): ILifetime { | |
| 105 | initialize(context: ActivationContext<any>): ILifetime { |
|
134 | let _lifetime = unknownLifetime; | |
| 106 | const id = String(++nextId); |
|
135 | return { | |
| 107 | return { |
|
136 | initialize(context: ActivationContext<any>) { | |
| 108 | enter() { |
|
137 | if (_lifetime !== unknownLifetime) | |
| 109 | if (context.visit(id)) |
|
138 | throw new Error("Cyclic reference detected"); | |
| 110 | throw new Error("Cyclic reference detected"); |
|
139 | _lifetime = context.createLifetime(); | |
| 111 |
|
|
140 | }, | |
| 112 |
|
|
141 | get() { | |
| 113 |
|
|
142 | return _lifetime.get(); | |
| 114 |
|
|
143 | }, | |
| 115 |
|
|
144 | has() { | |
| 116 |
|
|
145 | return _lifetime.has(); | |
| 117 |
|
|
146 | }, | |
| 118 |
|
|
147 | store(item: any) { | |
| 119 |
|
|
148 | _lifetime.store(item); | |
| 120 |
|
|
149 | } | |
| 121 |
|
|
150 | }; | |
| 122 |
|
|
151 | } | |
| 123 | }; |
|
|||
| 124 |
|
152 | |||
| 125 |
static singletonLifetime(typeId: string): ILifetime |
|
153 | static singletonLifetime(typeId: string): ILifetime { | |
|
|
154 | return emptyLifetime; | |||
|
|
155 | } | |||
|
|
156 | ||||
|
|
157 | static containerLifetime(container: Container<any>) { | |||
|
|
158 | let _lifetime = unknownLifetime; | |||
| 126 | return { |
|
159 | return { | |
| 127 | initialize() { |
|
160 | initialize(context: ActivationContext<any>) { | |
| 128 |
|
|
161 | if (_lifetime !== unknownLifetime) | |
|
|
162 | throw new Error("Cyclic reference detected"); | |||
|
|
163 | _lifetime = container.getLifetimeManager().create(context); | |||
|
|
164 | }, | |||
|
|
165 | get() { | |||
|
|
166 | return _lifetime.get(); | |||
|
|
167 | }, | |||
|
|
168 | has() { | |||
|
|
169 | return _lifetime.has(); | |||
|
|
170 | }, | |||
|
|
171 | store(item: any) { | |||
|
|
172 | _lifetime.store(item); | |||
| 129 | } |
|
173 | } | |
| 130 | }; |
|
174 | }; | |
| 131 | } |
|
175 | } | |
| @@ -3,9 +3,26 import { ActivationContext } from "./Act | |||||
| 3 | import { Descriptor, PartialServiceMap, TypeOfService, ContainerKeys } from "./interfaces"; |
|
3 | import { Descriptor, PartialServiceMap, TypeOfService, ContainerKeys } from "./interfaces"; | |
| 4 |
|
4 | |||
| 5 | export interface ReferenceDescriptorParams<S extends object, K extends ContainerKeys<S>> { |
|
5 | export interface ReferenceDescriptorParams<S extends object, K extends ContainerKeys<S>> { | |
|
|
6 | /** | |||
|
|
7 | * The name of the descriptor | |||
|
|
8 | */ | |||
| 6 | name: K; |
|
9 | name: K; | |
|
|
10 | ||||
|
|
11 | /** | |||
|
|
12 | * The flag that indicates that the referenced service isn't required to exist. | |||
|
|
13 | * If the reference is optional and the referenced service doesn't exist, | |||
|
|
14 | * the undefined or a default value will be returned. | |||
|
|
15 | */ | |||
| 7 | optional?: boolean; |
|
16 | optional?: boolean; | |
|
|
17 | ||||
|
|
18 | /** | |||
|
|
19 | * a default value for the reference when the referenced service doesn't exist. | |||
|
|
20 | */ | |||
| 8 | default?: TypeOfService<S, K>; |
|
21 | default?: TypeOfService<S, K>; | |
|
|
22 | ||||
|
|
23 | /** | |||
|
|
24 | * The service overrides | |||
|
|
25 | */ | |||
| 9 | services?: PartialServiceMap<S>; |
|
26 | services?: PartialServiceMap<S>; | |
| 10 | } |
|
27 | } | |
| 11 |
|
28 | |||
| @@ -29,7 +46,10 export class ReferenceDescriptor<S exten | |||||
| 29 | this._services = (opts.services || {}) as PartialServiceMap<S>; |
|
46 | this._services = (opts.services || {}) as PartialServiceMap<S>; | |
| 30 | } |
|
47 | } | |
| 31 |
|
48 | |||
| 32 | activate(context: ActivationContext<S>) { |
|
49 | /** This method activates the referenced service if one exists | |
|
|
50 | * @param context activation context which is used during current activation | |||
|
|
51 | */ | |||
|
|
52 | activate(context: ActivationContext<S>): any { | |||
| 33 | // добавляем сервисы |
|
53 | // добавляем сервисы | |
| 34 | if (this._services) { |
|
54 | if (this._services) { | |
| 35 | each(this._services, (v, k) => context.register(k, v)); |
|
55 | each(this._services, (v, k) => context.register(k, v)); | |
| @@ -59,7 +59,7 export type InjectionSpec<T> = { | |||||
| 59 | }; |
|
59 | }; | |
| 60 |
|
60 | |||
| 61 | export interface ServiceDescriptorParams<S extends object, T, P extends any[]> { |
|
61 | export interface ServiceDescriptorParams<S extends object, T, P extends any[]> { | |
| 62 |
lifetime?: ILifetime |
|
62 | lifetime?: ILifetime; | |
| 63 |
|
63 | |||
| 64 | params?: P; |
|
64 | params?: P; | |
| 65 |
|
65 | |||
| @@ -79,14 +79,14 export class ServiceDescriptor<S extends | |||||
| 79 |
|
79 | |||
| 80 | _cleanup: ((item: T) => void) | undefined; |
|
80 | _cleanup: ((item: T) => void) | undefined; | |
| 81 |
|
81 | |||
| 82 |
_lifetime |
|
82 | _lifetime = LifetimeManager.empty(); | |
| 83 |
|
83 | |||
| 84 | _objectLifetime: ILifetime | undefined; |
|
84 | _objectLifetime: ILifetime | undefined; | |
| 85 |
|
85 | |||
| 86 | constructor(opts: ServiceDescriptorParams<S, T, P>) { |
|
86 | constructor(opts: ServiceDescriptorParams<S, T, P>) { | |
| 87 |
|
87 | |||
| 88 | if (opts.lifetime) |
|
88 | if (opts.lifetime) | |
| 89 |
this._lifetime |
|
89 | this._lifetime = opts.lifetime; | |
| 90 |
|
90 | |||
| 91 | if (!isNull(opts.params)) |
|
91 | if (!isNull(opts.params)) | |
| 92 | this._params = opts.params; |
|
92 | this._params = opts.params; | |
| @@ -105,15 +105,12 export class ServiceDescriptor<S extends | |||||
| 105 | } |
|
105 | } | |
| 106 |
|
106 | |||
| 107 | activate(context: ActivationContext<S>) { |
|
107 | activate(context: ActivationContext<S>) { | |
| 108 | if (!this._objectLifetime) |
|
108 | const lifetime = this._lifetime; | |
| 109 | this._objectLifetime = this._lifetimeManager.initialize(context); |
|
|||
| 110 |
|
||||
| 111 | const lifetime = this._objectLifetime; |
|
|||
| 112 |
|
109 | |||
| 113 | if (lifetime.has()) { |
|
110 | if (lifetime.has()) { | |
| 114 | return lifetime.get(); |
|
111 | return lifetime.get(); | |
| 115 | } else { |
|
112 | } else { | |
| 116 |
lifetime. |
|
113 | lifetime.initialize(context); | |
| 117 | const instance = this._create(context); |
|
114 | const instance = this._create(context); | |
| 118 | lifetime.store(instance, this._cleanup); |
|
115 | lifetime.store(instance, this._cleanup); | |
| 119 | return instance; |
|
116 | return instance; | |
| @@ -1,5 +1,4 | |||||
| 1 |
import { Resolver |
|
1 | import { Resolver, LazyDependencyOptions, DependencyOptions } from "./interfaces"; | |
| 2 | import { AnnotationBuilder } from "../Annotations"; |
|
|||
| 3 | import { Container } from "../Container"; |
|
2 | import { Container } from "../Container"; | |
| 4 | import { Descriptor, ILifetime, ContainerKeys } from "../interfaces"; |
|
3 | import { Descriptor, ILifetime, ContainerKeys } from "../interfaces"; | |
| 5 | import { ActivationContext } from "../ActivationContext"; |
|
4 | import { ActivationContext } from "../ActivationContext"; | |
| @@ -12,9 +11,6 export class DescriptorBuilder<T, S exte | |||||
| 12 | this._container = container; |
|
11 | this._container = container; | |
| 13 | this._cb = cb; |
|
12 | this._cb = cb; | |
| 14 | } |
|
13 | } | |
| 15 | service(service: AnnotationBuilder<T, S> | ServiceModule<T, S>) { |
|
|||
| 16 |
|
||||
| 17 | } |
|
|||
| 18 |
|
14 | |||
| 19 | factory(f: (resolve: Resolver<S>, activate: (lifetime: ILifetime, factory: () => any, cleanup?: (item: any) => void) => any) => T): void { |
|
15 | factory(f: (resolve: Resolver<S>, activate: (lifetime: ILifetime, factory: () => any, cleanup?: (item: any) => void) => any) => T): void { | |
| 20 | this._cb({ |
|
16 | this._cb({ | |
| @@ -34,7 +30,7 export class DescriptorBuilder<T, S exte | |||||
| 34 | if (lifetime.has()) { |
|
30 | if (lifetime.has()) { | |
| 35 | return lifetime.get(); |
|
31 | return lifetime.get(); | |
| 36 | } else { |
|
32 | } else { | |
| 37 |
lifetime. |
|
33 | lifetime.initialize(context); | |
| 38 | const instance = factory(); |
|
34 | const instance = factory(); | |
| 39 | lifetime.store(instance, cleanup); |
|
35 | lifetime.store(instance, cleanup); | |
| 40 | return instance; |
|
36 | return instance; | |
| @@ -26,13 +26,13 export type ServiceModule<T, S extends o | |||||
| 26 | [m in M]: AnnotationBuilder<T, S>; |
|
26 | [m in M]: AnnotationBuilder<T, S>; | |
| 27 | }; |
|
27 | }; | |
| 28 |
|
28 | |||
| 29 |
export type InferReferenceType<S extends object, K extends |
|
29 | export type InferReferenceType<S extends object, K extends ContainerKeys<S>, O> = O extends { default: infer X } ? (TypeOfService<S, K> | X) : | |
| 30 | O extends { optional: true } ? (TypeOfService<S, K> | undefined) : |
|
30 | O extends { optional: true } ? (TypeOfService<S, K> | undefined) : | |
| 31 | TypeOfService<S, K>; |
|
31 | TypeOfService<S, K>; | |
| 32 |
|
32 | |||
| 33 | export interface Resolver<S extends object> { |
|
33 | export interface Resolver<S extends object> { | |
| 34 |
<K extends |
|
34 | <K extends ContainerKeys<S>, O extends LazyDependencyOptions>(this: void, name: K, opts: O): () => InferReferenceType<S, K, O>; | |
| 35 |
<K extends |
|
35 | <K extends ContainerKeys<S>, O extends DependencyOptions>(this: void, name: K, opts?: O): InferReferenceType<S, K, O>; | |
| 36 | } |
|
36 | } | |
| 37 |
|
37 | |||
| 38 | export interface DescriptorBuilder<T, S extends object> { |
|
38 | export interface DescriptorBuilder<T, S extends object> { | |
| @@ -38,7 +38,7 export type ContainerRegistered<S extend | |||||
| 38 | export type ActivationType = "singleton" | "container" | "hierarchy" | "context" | "call"; |
|
38 | export type ActivationType = "singleton" | "container" | "hierarchy" | "context" | "call"; | |
| 39 |
|
39 | |||
| 40 | export interface ILifetimeManager { |
|
40 | export interface ILifetimeManager { | |
| 41 |
|
|
41 | create(context: ActivationContext<any>): ILifetime; | |
| 42 | } |
|
42 | } | |
| 43 |
|
43 | |||
| 44 | /** |
|
44 | /** | |
| @@ -51,7 +51,7 export interface ILifetime { | |||||
| 51 |
|
51 | |||
| 52 | get(): any; |
|
52 | get(): any; | |
| 53 |
|
53 | |||
| 54 | enter(): void; |
|
54 | initialize(context: ActivationContext<any>): void; | |
| 55 |
|
55 | |||
| 56 | store(item: any, cleanup?: (item: any) => void): void; |
|
56 | store(item: any, cleanup?: (item: any) => void): void; | |
| 57 | } |
|
57 | } | |
| @@ -1,6 +1,5 | |||||
| 1 | import { isPrimitive } from "../safe"; |
|
1 | import { isPrimitive } from "../safe"; | |
| 2 | import { Descriptor } from "./interfaces"; |
|
2 | import { Descriptor } from "./interfaces"; | |
| 3 | import { AnnotationBuilder } from "./Annotations"; |
|
|||
| 4 | import { Configuration } from "./fluent/Configuration"; |
|
3 | import { Configuration } from "./fluent/Configuration"; | |
| 5 |
|
4 | |||
| 6 | export function isDescriptor(x: any): x is Descriptor { |
|
5 | export function isDescriptor(x: any): x is Descriptor { | |
| @@ -8,16 +7,6 export function isDescriptor(x: any): x | |||||
| 8 | (x.activate instanceof Function); |
|
7 | (x.activate instanceof Function); | |
| 9 | } |
|
8 | } | |
| 10 |
|
9 | |||
| 11 |
export function |
|
10 | export function configure<S extends object>() { | |
| 12 | return { |
|
11 | return new Configuration<S>(); | |
| 13 | annotate<T>() { |
|
|||
| 14 | return new AnnotationBuilder<T, S>(); |
|
|||
| 15 | }, |
|
|||
| 16 | configure(): Configuration<S> { |
|
|||
| 17 | throw new Error(); |
|
|||
| 18 | }, |
|
|||
| 19 | dependency() { |
|
|||
| 20 | throw new Error(); |
|
|||
| 21 | } |
|
|||
| 22 | }; |
|
|||
| 23 | } |
|
12 | } | |
| @@ -129,8 +129,7 export function get(member: string, cont | |||||
| 129 | * @param {Function} cb функция, вызываемая для каждого элемента |
|
129 | * @param {Function} cb функция, вызываемая для каждого элемента | |
| 130 | * @param {Object} thisArg значение, которое будет передано в качестве |
|
130 | * @param {Object} thisArg значение, которое будет передано в качестве | |
| 131 | * <c>this</c> в <c>cb</c>. |
|
131 | * <c>this</c> в <c>cb</c>. | |
| 132 | * @returns Результат вызова функции <c>cb</c>, либо <c>undefined</c> |
|
132 | * @returns {void} | |
| 133 | * если достигнут конец массива. |
|
|||
| 134 | */ |
|
133 | */ | |
| 135 | export function each<T>(obj: T, cb: <X extends keyof T>(v: NonNullable<T[X]>, k: X) => void): void; |
|
134 | export function each<T>(obj: T, cb: <X extends keyof T>(v: NonNullable<T[X]>, k: X) => void): void; | |
| 136 | export function each<T>(array: T[], cb: (v: T, i: number) => void): void; |
|
135 | export function each<T>(array: T[], cb: (v: T, i: number) => void): void; | |
| @@ -138,18 +137,14 export function each(obj: any, cb: any, | |||||
| 138 | export function each(obj: any, cb: any, thisArg?: any) { |
|
137 | export function each(obj: any, cb: any, thisArg?: any) { | |
| 139 | argumentNotNull(cb, "cb"); |
|
138 | argumentNotNull(cb, "cb"); | |
| 140 | if (obj instanceof Array) { |
|
139 | if (obj instanceof Array) { | |
|
|
140 | let v: any; | |||
| 141 | for (let i = 0; i < obj.length; i++) { |
|
141 | for (let i = 0; i < obj.length; i++) { | |
| 142 |
|
|
142 | v = obj[i]; | |
| 143 |
if ( |
|
143 | if (v !== undefined) | |
| 144 | return x; |
|
144 | cb.call(thisArg, v, i); | |
| 145 | } |
|
145 | } | |
| 146 | } else { |
|
146 | } else { | |
| 147 | const _keys = Object.keys(obj); |
|
147 | Object.keys(obj).forEach(k => obj[k] !== undefined && cb.call(thisArg, obj[k], k)); | |
| 148 | for (const k of _keys) { |
|
|||
| 149 | const x = cb.call(thisArg, obj[k], k); |
|
|||
| 150 | if (x !== undefined) |
|
|||
| 151 | return x; |
|
|||
| 152 | } |
|
|||
| 153 | } |
|
148 | } | |
| 154 | } |
|
149 | } | |
| 155 |
|
150 | |||
| @@ -478,7 +473,7 export function firstWhere<T>( | |||||
| 478 | } |
|
473 | } | |
| 479 |
|
474 | |||
| 480 | export function isDestroyable(d: any): d is IDestroyable { |
|
475 | export function isDestroyable(d: any): d is IDestroyable { | |
| 481 | if (d && "destroy" in d && typeof(destroy) === "function") |
|
476 | if (d && "destroy" in d && typeof (destroy) === "function") | |
| 482 | return true; |
|
477 | return true; | |
| 483 | return false; |
|
478 | return false; | |
| 484 | } |
|
479 | } | |
| @@ -1,4 +1,4 | |||||
| 1 |
import { isPrimitive, isNull |
|
1 | import { isPrimitive, isNull, isKeyof, get } from "../safe"; | |
| 2 | import { MapOf } from "../interfaces"; |
|
2 | import { MapOf } from "../interfaces"; | |
| 3 |
|
3 | |||
| 4 | type SubstFn = (name: string, format?: string) => string; |
|
4 | type SubstFn = (name: string, format?: string) => string; | |
| @@ -1,7 +1,6 | |||||
| 1 | import { Foo } from "./Foo"; |
|
1 | import { Foo } from "./Foo"; | |
| 2 | import { annotate, dependency } from "./services"; |
|
|||
| 3 |
|
2 | |||
| 4 | export const service = annotate<Bar>(); |
|
3 | /* export const service = annotate<Bar>(); | |
| 5 |
|
4 | |||
| 6 | @service.wire({ |
|
5 | @service.wire({ | |
| 7 | foo: dependency("foo"), |
|
6 | foo: dependency("foo"), | |
| @@ -9,22 +8,27 export const service = annotate<Bar>(); | |||||
| 9 | lazy: dependency("foo", { lazy: true }) |
|
8 | lazy: dependency("foo", { lazy: true }) | |
| 10 | }, |
|
9 | }, | |
| 11 | host: dependency("host") |
|
10 | host: dependency("host") | |
| 12 |
|
|
11 | }, "") */ | |
| 13 | export class Bar { |
|
12 | export class Bar { | |
| 14 | barName = "Twister"; |
|
13 | barName = "Twister"; | |
| 15 |
|
14 | |||
| 16 | _v: Foo | undefined; |
|
15 | _v: Foo | undefined; | |
| 17 |
|
16 | |||
| 18 |
constructor( |
|
17 | constructor( | |
| 19 |
|
|
18 | _opts: { | |
| 20 | nested?: { |
|
19 | foo?: Foo; | |
| 21 | lazy: () => Foo |
|
20 | nested?: { | |
|
|
21 | lazy: () => Foo | |||
|
|
22 | }, | |||
|
|
23 | host: string | |||
| 22 | }, |
|
24 | }, | |
| 23 |
|
|
25 | s: string | |
| 24 | }, s: string) { |
|
26 | ) { | |
| 25 |
|
27 | |||
| 26 | if (_opts && _opts.foo) |
|
28 | if (_opts && _opts.foo) | |
| 27 | this._v = _opts.foo; |
|
29 | this._v = _opts.foo; | |
|
|
30 | if (s) | |||
|
|
31 | this.barName = s; | |||
| 28 | } |
|
32 | } | |
| 29 |
|
33 | |||
| 30 | setName(name: string) { |
|
34 | setName(name: string) { | |
| @@ -1,12 +1,11 | |||||
| 1 | import { Bar } from "./Bar"; |
|
1 | import { Bar } from "./Bar"; | |
| 2 | import { annotate, dependency } from "./services"; |
|
|||
| 3 |
|
2 | |||
| 4 | // export service descriptor |
|
3 | // export service descriptor | |
| 5 | // через service передается информация о типе зависимости |
|
4 | // через service передается информация о типе зависимости | |
| 6 | // даже если это шаблон. |
|
5 | // даже если это шаблон. | |
| 7 | export const service = annotate<Box<Bar>>(); |
|
6 | // export const service = annotate<Box<Bar>>(); | |
| 8 |
|
7 | |||
| 9 | @service.wire() |
|
8 | // @service.wire() | |
| 10 | export class Box<T> { |
|
9 | export class Box<T> { | |
| 11 | private _value: T | undefined; |
|
10 | private _value: T | undefined; | |
| 12 |
|
11 | |||
| @@ -14,7 +13,7 export class Box<T> { | |||||
| 14 | this._value = value; |
|
13 | this._value = value; | |
| 15 | } |
|
14 | } | |
| 16 |
|
15 | |||
| 17 | @service.inject(dependency("bar")) |
|
16 | // @service.inject(dependency("bar")) | |
| 18 | setValue(value: T) { |
|
17 | setValue(value: T) { | |
| 19 | this._value = value; |
|
18 | this._value = value; | |
| 20 | return value; |
|
19 | return value; | |
| @@ -1,10 +1,13 | |||||
| 1 |
import { c |
|
1 | import { Services } from "./services"; | |
|
|
2 | import { configure } from "../di/traits"; | |||
|
|
3 | import { LifetimeManager } from "../di/LifetimeManager"; | |||
| 2 |
|
4 | |||
| 3 | export const config = configure() |
|
5 | export const config = configure<Services>() | |
| 4 | .register("host", s => s.value("example.com")) |
|
6 | .register("host", s => s.value("example.com")) | |
| 5 | .register("bar2", bar2 => Promise.all([import("./Foo"), import("./Bar")]) |
|
7 | .register("bar2", bar2 => Promise.all([import("./Foo"), import("./Bar")]) | |
| 6 | .then(([{ Foo }, { Bar }]) => { |
|
8 | .then(([{ Foo }, { Bar }]) => { | |
| 7 |
const lifetime |
|
9 | const lifetime = LifetimeManager.hierarchyLifetime(); | |
|
|
10 | ||||
| 8 |
|
|
11 | bar2.factory((resolve, activate) => { | |
| 9 | const bar = new Bar({ |
|
12 | const bar = new Bar({ | |
| 10 | foo: activate(lifetime, () => new Foo()), |
|
13 | foo: activate(lifetime, () => new Foo()), | |
| @@ -1,7 +1,6 | |||||
| 1 | import { Foo } from "./Foo"; |
|
1 | import { Foo } from "./Foo"; | |
| 2 | import { Bar } from "./Bar"; |
|
2 | import { Bar } from "./Bar"; | |
| 3 | import { Box } from "./Box"; |
|
3 | import { Box } from "./Box"; | |
| 4 | import { declare } from "../di/traits"; |
|
|||
| 5 |
|
4 | |||
| 6 | /** |
|
5 | /** | |
| 7 | * Сервисы доступные внутри контейнера |
|
6 | * Сервисы доступные внутри контейнера | |
| @@ -18,8 +17,3 export interface Services { | |||||
| 18 | host: string; |
|
17 | host: string; | |
| 19 |
|
18 | |||
| 20 | } |
|
19 | } | |
| 21 |
|
||||
| 22 | /** |
|
|||
| 23 | * Экспортируем вспомогательные функции для описания сервисов и кинфогурации |
|
|||
| 24 | */ |
|
|||
| 25 | export const { dependency, annotate, configure } = declare<Services>(); |
|
|||
| 1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now
