| @@ -0,0 +1,17 | |||
|
|
1 | import { Container } from "../Container"; | |
|
|
2 | import { ExtractDependency, ServiceRecordBuilder } from "./interfaces"; | |
|
|
3 | ||
|
|
4 | export class ConfigBuilder<S extends object, Y extends keyof S = keyof S> { | |
|
|
5 | register<K extends Y>(name: K, builder: (t: ServiceRecordBuilder<S[K], S>) => void | Promise<void>): ConfigBuilder<S, Exclude<Y, K>>; | |
|
|
6 | register<K extends Y, V>(name: S[K] extends ExtractDependency<V, S> ? K : never, value: V): ConfigBuilder<S, Exclude<Y, K>>; | |
|
|
7 | register<K extends Y>(name: K, value: S[K], raw: true): ConfigBuilder<S, Exclude<Y, K>>; | |
|
|
8 | register<K extends Y>(name: K, value: any, raw = false): ConfigBuilder<S, Exclude<Y, K>> { | |
|
|
9 | ||
|
|
10 | return this; | |
|
|
11 | } | |
|
|
12 | ||
|
|
13 | apply(container: Container<S>): PromiseLike<void> { | |
|
|
14 | ||
|
|
15 | return Promise.resolve(); | |
|
|
16 | } | |
|
|
17 | } | |
| @@ -0,0 +1,17 | |||
|
|
1 | import { RegistrationBuilder } from "./RegistrationBuilder"; | |
|
|
2 | ||
|
|
3 | export class ConstructorBuilder<C extends new (...args: any[]) => any, S extends object> | |
|
|
4 | extends RegistrationBuilder<InstanceType<C>, S> { | |
|
|
5 | ||
|
|
6 | $type: C; | |
|
|
7 | ||
|
|
8 | _params: any; | |
|
|
9 | ||
|
|
10 | constructor(target: C, params: any) { | |
|
|
11 | super(); | |
|
|
12 | this.$type = target; | |
|
|
13 | ||
|
|
14 | this._params = params; | |
|
|
15 | } | |
|
|
16 | ||
|
|
17 | } | |
| @@ -0,0 +1,14 | |||
|
|
1 | import { RegistrationBuilder } from "./RegistrationBuilder"; | |
|
|
2 | ||
|
|
3 | export class FactoryBuilder<F extends (...args: any[]) => any, S extends object> extends RegistrationBuilder<ReturnType<F>, S> { | |
|
|
4 | $factory: F; | |
|
|
5 | ||
|
|
6 | _params: any; | |
|
|
7 | ||
|
|
8 | constructor(target: F, params: any) { | |
|
|
9 | super(); | |
|
|
10 | ||
|
|
11 | this.$factory = target; | |
|
|
12 | this._params = params; | |
|
|
13 | } | |
|
|
14 | } | |
|
|
1 | NO CONTENT: new file 100644 |
| @@ -120,4 +120,11 export class ActivationContext<S extends | |||
|
|
120 | 120 | clone._service = service; |
|
|
121 | 121 | return clone; |
|
|
122 | 122 | } |
|
|
123 | ||
|
|
124 | /** Creates a clone for the current context, used to protect it from modifications */ | |
|
|
125 | clone(): this { | |
|
|
126 | const clone = Object.create(this); | |
|
|
127 | clone._services = Object.create(this._services); | |
|
|
128 | return clone; | |
|
|
129 | } | |
|
|
123 | 130 | } |
| @@ -1,5 +1,6 | |||
|
|
1 | 1 | import { TypeRegistration } from "./Configuration"; |
|
|
2 | 2 | import { ExtractDependency } from "./fluent/interfaces"; |
|
|
3 | import { RegistrationBuilder } from "./fluent/RegistrationBuilder"; | |
|
|
3 | 4 | |
|
|
4 | 5 | export class AnnotaionBuilder<T, S extends object> { |
|
|
5 | 6 | wire<P extends any[]>(...args: P) { |
| @@ -22,4 +23,8 export class AnnotaionBuilder<T, S exten | |||
|
|
22 | 23 | throw new Error(); |
|
|
23 | 24 | } |
|
|
24 | 25 | |
|
|
26 | getRegistrationBuilder(): RegistrationBuilder<T, S> { | |
|
|
27 | throw new Error(); | |
|
|
28 | } | |
|
|
29 | ||
|
|
25 | 30 | } |
| @@ -19,6 +19,7 import { makeResolver } from "./Resolver | |||
|
|
19 | 19 | import { ICancellation } from "../interfaces"; |
|
|
20 | 20 | import { isDescriptor } from "./traits"; |
|
|
21 | 21 | import { LazyReferenceDescriptor } from "./LazyReferenceDescriptor"; |
|
|
22 | import { LifetimeManager } from "./LifetimeManager"; | |
|
|
22 | 23 | |
|
|
23 | 24 | export interface RegistrationScope<S extends object> { |
|
|
24 | 25 | |
| @@ -74,8 +75,6 export interface LazyDependencyRegistrat | |||
|
|
74 | 75 | lazy: true; |
|
|
75 | 76 | } |
|
|
76 | 77 | |
|
|
77 | type OfType<K extends keyof S, S, T> = Extract<{ [k in K]: T}, S>; | |
|
|
78 | ||
|
|
79 | 78 | export type Registration<T, S extends object> = T extends primitive ? T : |
|
|
80 | 79 | ( |
|
|
81 | 80 | T | |
| @@ -325,7 +324,6 export class Configuration<S extends obj | |||
|
|
325 | 324 | |
|
|
326 | 325 | _makeServiceParams(data: ServiceRegistration<any, S>) { |
|
|
327 | 326 | const opts: any = { |
|
|
328 | owner: this._container | |
|
|
329 | 327 | }; |
|
|
330 | 328 | if (data.services) |
|
|
331 | 329 | opts.services = this._visitRegistrations(data.services, "services"); |
| @@ -347,7 +345,7 export class Configuration<S extends obj | |||
|
|
347 | 345 | this._visit(data.params, "params"); |
|
|
348 | 346 | |
|
|
349 | 347 | if (data.activation) { |
|
|
350 | opts.activation = data.activation; | |
|
|
348 | opts.activation = this._getLifetimeManager(data.activation); | |
|
|
351 | 349 | } |
|
|
352 | 350 | |
|
|
353 | 351 | if (data.cleanup) |
| @@ -412,4 +410,19 export class Configuration<S extends obj | |||
|
|
412 | 410 | this._leave(); |
|
|
413 | 411 | return d; |
|
|
414 | 412 | } |
|
|
413 | ||
|
|
414 | _getLifetimeManager(activation: ActivationType) { | |
|
|
415 | switch (activation) { | |
|
|
416 | case "container": | |
|
|
417 | return this._container.getLifetimeManager(); | |
|
|
418 | case "hierarchy": | |
|
|
419 | return LifetimeManager.hierarchyLifetime; | |
|
|
420 | case "context": | |
|
|
421 | return LifetimeManager.contextLifetime; | |
|
|
422 | case "singleton": | |
|
|
423 | return LifetimeManager.singletonLifetime; | |
|
|
424 | default: | |
|
|
425 | return LifetimeManager.empty; | |
|
|
426 | } | |
|
|
427 | } | |
|
|
415 | 428 | } |
| @@ -41,7 +41,7 export class LazyReferenceDescriptor<S e | |||
|
|
41 | 41 | return (cfg?: PartialServiceMap<S>) => { |
|
|
42 | 42 | // защищаем контекст на случай исключения в процессе |
|
|
43 | 43 | // активации |
|
|
44 | const ct = saved.clone(); | |
|
|
44 | const ct = cfg ? saved.clone() : saved; | |
|
|
45 | 45 | try { |
|
|
46 | 46 | if (cfg) { |
|
|
47 | 47 | each(cfg, (v, k) => ct.register(k, v)); |
| @@ -35,9 +35,10 export class LifetimeManager implements | |||
|
|
35 | 35 | private _cache: MapOf<any> = {}; |
|
|
36 | 36 | private _destroyed = false; |
|
|
37 | 37 | |
|
|
38 | private _pending: MapOf<boolean> = {}; | |
|
|
39 | ||
|
|
38 | 40 | initialize(id: string): ILifetime { |
|
|
39 | 41 | const self = this; |
|
|
40 | let pending = false; | |
|
|
41 | 42 | return { |
|
|
42 | 43 | has() { |
|
|
43 | 44 | return (id in self._cache); |
| @@ -51,9 +52,9 export class LifetimeManager implements | |||
|
|
51 | 52 | }, |
|
|
52 | 53 | |
|
|
53 | 54 | enter() { |
|
|
54 | if (pending) | |
|
|
55 | if (self._pending[id]) | |
|
|
55 | 56 | throw Error(`Cyclic reference detected: the item with the key ${id} is already activating.`); |
|
|
56 | pending = true; | |
|
|
57 | self._pending[id] = true; | |
|
|
57 | 58 | }, |
|
|
58 | 59 | |
|
|
59 | 60 | store(item: any, cleanup?: (item: any) => void) { |
| @@ -62,7 +63,7 export class LifetimeManager implements | |||
|
|
62 | 63 | |
|
|
63 | 64 | if (this.has()) |
|
|
64 | 65 | throw new Error(`The item with with the key ${id} already registered with this lifetime manager`); |
|
|
65 |
|
|
|
|
66 | delete self._pending[id]; | |
|
|
66 | 67 | |
|
|
67 | 68 | self._cache[id] = item; |
|
|
68 | 69 | |
| @@ -62,8 +62,6 export type InjectionSpec<T> = { | |||
|
|
62 | 62 | }; |
|
|
63 | 63 | |
|
|
64 | 64 | export interface ServiceDescriptorParams<S extends object, T, P extends any[]> { |
|
|
65 | owner: Container<S>; | |
|
|
66 | ||
|
|
67 | 65 | lifetime?: ILifetimeManager; |
|
|
68 | 66 | |
|
|
69 | 67 | params?: P; |
| @@ -88,12 +86,7 export class ServiceDescriptor<S extends | |||
|
|
88 | 86 | |
|
|
89 | 87 | _lifetime = LifetimeManager.empty; |
|
|
90 | 88 | |
|
|
91 | _owner: Container<S>; | |
|
|
92 | ||
|
|
93 | 89 | constructor(opts: ServiceDescriptorParams<S, T, P>) { |
|
|
94 | argumentNotNull(opts && opts.owner, "opts.owner"); | |
|
|
95 | ||
|
|
96 | this._owner = opts.owner; | |
|
|
97 | 90 | |
|
|
98 | 91 | if (opts.lifetime) |
|
|
99 | 92 | this._lifetime = opts.lifetime; |
| @@ -1,13 +1,12 | |||
|
|
1 | 1 | import { ServiceDescriptor, ServiceDescriptorParams } from "./ServiceDescriptor"; |
|
|
2 | import { Constructor, Factory } from "../interfaces"; | |
|
|
3 | 2 | import { argumentNotNull, isPrimitive } from "../safe"; |
|
|
4 | 3 | |
|
|
5 | 4 | export interface TypeServiceDescriptorParams<S extends object, T extends object, P extends any[]> extends ServiceDescriptorParams<S, T, P> { |
|
|
6 | type: Constructor<T>; | |
|
|
5 | type: new (...args: any[]) => T; | |
|
|
7 | 6 | } |
|
|
8 | 7 | |
|
|
9 | 8 | export class TypeServiceDescriptor<S extends object, T extends object, P extends any[]> extends ServiceDescriptor<S, T, P> { |
|
|
10 | _type: Constructor; | |
|
|
9 | _type: new (...args: any[]) => T; | |
|
|
11 | 10 | |
|
|
12 | 11 | constructor(opts: TypeServiceDescriptorParams<S, T, P>) { |
|
|
13 | 12 | super(opts); |
| @@ -18,9 +17,10 export class TypeServiceDescriptor<S ext | |||
|
|
18 | 17 | if (this._params) { |
|
|
19 | 18 | if (this._params.length) { |
|
|
20 | 19 | this._factory = (...args) => { |
|
|
21 | const t = Object.create(ctor.prototype); | |
|
|
20 | /*const t = Object.create(ctor.prototype); | |
|
|
22 | 21 | const inst = ctor.apply(t, args); |
|
|
23 | return isPrimitive(inst) ? t : inst; | |
|
|
22 | return isPrimitive(inst) ? t : inst;*/ | |
|
|
23 | return new ctor(...args); | |
|
|
24 | 24 | }; |
|
|
25 | 25 | } else { |
|
|
26 | 26 | this._factory = arg => { |
| @@ -1,7 +1,7 | |||
|
|
1 | import { ServiceRecordBuilder, ExtractDependency, RegistrationVisitor } from "./interfaces"; | |
|
|
1 | import { ServiceRecordBuilder, ExtractDependency, RegistrationVisitor, ServiceRegistration } from "./interfaces"; | |
|
|
2 | 2 | import { ActivationType } from "../interfaces"; |
|
|
3 | 3 | |
|
|
4 | export class RegistrationBuilder<T, S extends object> { | |
|
|
4 | export class RegistrationBuilder<T, S extends object> implements ServiceRegistration { | |
|
|
5 | 5 | private _activationType: ActivationType = "call"; |
|
|
6 | 6 | |
|
|
7 | 7 | private _overrides: { [m in keyof S]?: (...args: any) => void } | undefined; |
| @@ -31,7 +31,7 export class RegistrationBuilder<T, S ex | |||
|
|
31 | 31 | return this; |
|
|
32 | 32 | } |
|
|
33 | 33 | |
|
|
34 |
visit(visitor: RegistrationVisitor |
|
|
|
34 | visit(visitor: RegistrationVisitor) { | |
|
|
35 | 35 | |
|
|
36 | 36 | } |
|
|
37 | } No newline at end of file | |
|
|
37 | } | |
| @@ -37,7 +37,7 export interface ServiceRecordBuilder<T, | |||
|
|
37 | 37 | wired(module: ServiceModule<T, S>): RegistrationBuilder<T, S>; |
|
|
38 | 38 | } |
|
|
39 | 39 | |
|
|
40 |
export interface RegistrationVisitor |
|
|
|
40 | export interface RegistrationVisitor { | |
|
|
41 | 41 | visitDependency(): void; |
|
|
42 | 42 | |
|
|
43 | 43 | visitObject(): void; |
| @@ -48,23 +48,8 export interface RegistrationVisitor<S e | |||
|
|
48 | 48 | |
|
|
49 | 49 | } |
|
|
50 | 50 | |
|
|
51 |
export interface Registration |
|
|
|
52 | override<K extends keyof S>(name: K, builder: S[K], raw: true): this; | |
|
|
53 | override<K extends keyof S>(name: K, builder: (t: ServiceRecordBuilder<S[K], S>) => void): this; | |
|
|
54 | override<K extends keyof S, V>(name: S[K] extends ExtractDependency<V, S> ? K : never, value: V): this; | |
|
|
55 | ||
|
|
56 | activate(activation: ActivationType): this; | |
|
|
57 | inject<M extends keyof T, P extends any[]>(member: T[M] extends (...params: ExtractDependency<P, S>) => any ? M : never, ...params: P): this; | |
|
|
58 | ||
|
|
59 | visit(visitor: RegistrationVisitor<S>): void; | |
|
|
60 | } | |
|
|
61 | ||
|
|
62 | export interface ConstructorBuilder<C extends new (...args: any[]) => any, S extends object> extends RegistrationBuilder<InstanceType<C>, S> { | |
|
|
63 | $type: C; | |
|
|
64 | } | |
|
|
65 | ||
|
|
66 | export interface FactoryBuilder<F extends (...args: any[]) => any, S extends object> extends RegistrationBuilder<ReturnType<F>, S> { | |
|
|
67 | $factory: F; | |
|
|
51 | export interface ServiceRegistration { | |
|
|
52 | visit(visitor: RegistrationVisitor): void; | |
|
|
68 | 53 | } |
|
|
69 | 54 | |
|
|
70 | 55 | export interface ConfigBuilder<S extends object, Y extends keyof S = keyof S> { |
| @@ -75,7 +60,7 export interface ConfigBuilder<S extends | |||
|
|
75 | 60 | apply(container: Container<S>): Promise<void>; |
|
|
76 | 61 | } |
|
|
77 | 62 | |
|
|
78 | interface ServicesDeclaration<S extends object> { | |
|
|
63 | export interface ServicesDeclaration<S extends object> { | |
|
|
79 | 64 | build<T>(this: void): ServiceRecordBuilder<T, S>; |
|
|
80 | 65 | annotate<T>(this: void): AnnotaionBuilder<T, S>; |
|
|
81 | 66 | |
| @@ -84,5 +69,3 interface ServicesDeclaration<S extends | |||
|
|
84 | 69 | |
|
|
85 | 70 | configure(): ConfigBuilder<S>; |
|
|
86 | 71 | } |
|
|
87 | ||
|
|
88 | export declare function declare<S extends object>(): ServicesDeclaration<S>; | |
| @@ -50,4 +50,4 export interface ILifetime { | |||
|
|
50 | 50 | enter(): void; |
|
|
51 | 51 | |
|
|
52 | 52 | store(item: any, cleanup?: (item: any) => void): void; |
|
|
53 | } No newline at end of file | |
|
|
53 | } | |
| @@ -1,7 +1,50 | |||
|
|
1 | 1 | import { isPrimitive } from "../safe"; |
|
|
2 | 2 | import { Descriptor } from "./interfaces"; |
|
|
3 | import { ServicesDeclaration, ServiceRecordBuilder, ServiceModule, RegistrationBuilder, ExtractDependency } from "./fluent/interfaces"; | |
|
|
4 | import { AnnotaionBuilder } from "./Annotations"; | |
|
|
5 | import { FactoryBuilder } from "./fluent/FactoryBuilder"; | |
|
|
6 | import { ConstructorBuilder } from "./fluent/ConstructorBuiler"; | |
|
|
3 | 7 | |
|
|
4 | 8 | export function isDescriptor(x: any): x is Descriptor { |
|
|
5 | 9 | return (!isPrimitive(x)) && |
|
|
6 | 10 | (x.activate instanceof Function); |
|
|
7 | } No newline at end of file | |
|
|
11 | } | |
|
|
12 | ||
|
|
13 | export function declare<S extends object>(): ServicesDeclaration<S> { | |
|
|
14 | return { | |
|
|
15 | annotate<T>() { | |
|
|
16 | return new AnnotaionBuilder<T, S>(); | |
|
|
17 | }, | |
|
|
18 | build<T>(): ServiceRecordBuilder<T, S> { | |
|
|
19 | return { | |
|
|
20 | factory<P extends any[], F extends (...args: ExtractDependency<P, S>) => T>( | |
|
|
21 | target: F, | |
|
|
22 | ...params: P | |
|
|
23 | ): FactoryBuilder<F, S> { | |
|
|
24 | return new FactoryBuilder(target, params); | |
|
|
25 | }, | |
|
|
26 | ||
|
|
27 | type<P extends any[], C extends new (...args: ExtractDependency<P, S>) => T>( | |
|
|
28 | target: C, ...params: P | |
|
|
29 | ): ConstructorBuilder<C, S> { | |
|
|
30 | return new ConstructorBuilder(target, params); | |
|
|
31 | }, | |
|
|
32 | ||
|
|
33 | wired<M extends keyof any>(module: ServiceModule<T, S, M>, m?: M): RegistrationBuilder<T, S> { | |
|
|
34 | const service = m ? | |
|
|
35 | module[m] : | |
|
|
36 | (module as ServiceModule<T, S>).service; | |
|
|
37 | if (!service) | |
|
|
38 | throw new Error("The specified module doen's provides a service annotation"); | |
|
|
39 | return service.getRegistrationBuilder(); | |
|
|
40 | } | |
|
|
41 | }; | |
|
|
42 | }, | |
|
|
43 | configure() { | |
|
|
44 | throw new Error(); | |
|
|
45 | }, | |
|
|
46 | dependency() { | |
|
|
47 | throw new Error(); | |
|
|
48 | } | |
|
|
49 | }; | |
|
|
50 | } | |
General Comments 0
You need to be logged in to leave comments.
Login now
