| @@ -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 |
|
NO CONTENT: new file 100644 |
| @@ -120,4 +120,11 export class ActivationContext<S extends | |||||
| 120 | clone._service = service; |
|
120 | clone._service = service; | |
| 121 | return clone; |
|
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 | import { TypeRegistration } from "./Configuration"; |
|
1 | import { TypeRegistration } from "./Configuration"; | |
| 2 | import { ExtractDependency } from "./fluent/interfaces"; |
|
2 | import { ExtractDependency } from "./fluent/interfaces"; | |
|
|
3 | import { RegistrationBuilder } from "./fluent/RegistrationBuilder"; | |||
| 3 |
|
4 | |||
| 4 | export class AnnotaionBuilder<T, S extends object> { |
|
5 | export class AnnotaionBuilder<T, S extends object> { | |
| 5 | wire<P extends any[]>(...args: P) { |
|
6 | wire<P extends any[]>(...args: P) { | |
| @@ -22,4 +23,8 export class AnnotaionBuilder<T, S exten | |||||
| 22 | throw new Error(); |
|
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 | import { ICancellation } from "../interfaces"; |
|
19 | import { ICancellation } from "../interfaces"; | |
| 20 | import { isDescriptor } from "./traits"; |
|
20 | import { isDescriptor } from "./traits"; | |
| 21 | import { LazyReferenceDescriptor } from "./LazyReferenceDescriptor"; |
|
21 | import { LazyReferenceDescriptor } from "./LazyReferenceDescriptor"; | |
|
|
22 | import { LifetimeManager } from "./LifetimeManager"; | |||
| 22 |
|
23 | |||
| 23 | export interface RegistrationScope<S extends object> { |
|
24 | export interface RegistrationScope<S extends object> { | |
| 24 |
|
25 | |||
| @@ -74,8 +75,6 export interface LazyDependencyRegistrat | |||||
| 74 | lazy: true; |
|
75 | lazy: true; | |
| 75 | } |
|
76 | } | |
| 76 |
|
77 | |||
| 77 | type OfType<K extends keyof S, S, T> = Extract<{ [k in K]: T}, S>; |
|
|||
| 78 |
|
||||
| 79 | export type Registration<T, S extends object> = T extends primitive ? T : |
|
78 | export type Registration<T, S extends object> = T extends primitive ? T : | |
| 80 | ( |
|
79 | ( | |
| 81 | T | |
|
80 | T | | |
| @@ -325,7 +324,6 export class Configuration<S extends obj | |||||
| 325 |
|
324 | |||
| 326 | _makeServiceParams(data: ServiceRegistration<any, S>) { |
|
325 | _makeServiceParams(data: ServiceRegistration<any, S>) { | |
| 327 | const opts: any = { |
|
326 | const opts: any = { | |
| 328 | owner: this._container |
|
|||
| 329 | }; |
|
327 | }; | |
| 330 | if (data.services) |
|
328 | if (data.services) | |
| 331 | opts.services = this._visitRegistrations(data.services, "services"); |
|
329 | opts.services = this._visitRegistrations(data.services, "services"); | |
| @@ -347,7 +345,7 export class Configuration<S extends obj | |||||
| 347 | this._visit(data.params, "params"); |
|
345 | this._visit(data.params, "params"); | |
| 348 |
|
346 | |||
| 349 | if (data.activation) { |
|
347 | if (data.activation) { | |
| 350 | opts.activation = data.activation; |
|
348 | opts.activation = this._getLifetimeManager(data.activation); | |
| 351 | } |
|
349 | } | |
| 352 |
|
350 | |||
| 353 | if (data.cleanup) |
|
351 | if (data.cleanup) | |
| @@ -412,4 +410,19 export class Configuration<S extends obj | |||||
| 412 | this._leave(); |
|
410 | this._leave(); | |
| 413 | return d; |
|
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 | return (cfg?: PartialServiceMap<S>) => { |
|
41 | return (cfg?: PartialServiceMap<S>) => { | |
| 42 | // защищаем контекст на случай исключения в процессе |
|
42 | // защищаем контекст на случай исключения в процессе | |
| 43 | // активации |
|
43 | // активации | |
| 44 | const ct = saved.clone(); |
|
44 | const ct = cfg ? saved.clone() : saved; | |
| 45 | try { |
|
45 | try { | |
| 46 | if (cfg) { |
|
46 | if (cfg) { | |
| 47 | each(cfg, (v, k) => ct.register(k, v)); |
|
47 | each(cfg, (v, k) => ct.register(k, v)); | |
| @@ -35,9 +35,10 export class LifetimeManager implements | |||||
| 35 | private _cache: MapOf<any> = {}; |
|
35 | private _cache: MapOf<any> = {}; | |
| 36 | private _destroyed = false; |
|
36 | private _destroyed = false; | |
| 37 |
|
37 | |||
|
|
38 | private _pending: MapOf<boolean> = {}; | |||
|
|
39 | ||||
| 38 | initialize(id: string): ILifetime { |
|
40 | initialize(id: string): ILifetime { | |
| 39 | const self = this; |
|
41 | const self = this; | |
| 40 | let pending = false; |
|
|||
| 41 | return { |
|
42 | return { | |
| 42 | has() { |
|
43 | has() { | |
| 43 | return (id in self._cache); |
|
44 | return (id in self._cache); | |
| @@ -51,9 +52,9 export class LifetimeManager implements | |||||
| 51 | }, |
|
52 | }, | |
| 52 |
|
53 | |||
| 53 | enter() { |
|
54 | enter() { | |
| 54 | if (pending) |
|
55 | if (self._pending[id]) | |
| 55 | throw Error(`Cyclic reference detected: the item with the key ${id} is already activating.`); |
|
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 | store(item: any, cleanup?: (item: any) => void) { |
|
60 | store(item: any, cleanup?: (item: any) => void) { | |
| @@ -62,7 +63,7 export class LifetimeManager implements | |||||
| 62 |
|
63 | |||
| 63 | if (this.has()) |
|
64 | if (this.has()) | |
| 64 | throw new Error(`The item with with the key ${id} already registered with this lifetime manager`); |
|
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 | self._cache[id] = item; |
|
68 | self._cache[id] = item; | |
| 68 |
|
69 | |||
| @@ -62,8 +62,6 export type InjectionSpec<T> = { | |||||
| 62 | }; |
|
62 | }; | |
| 63 |
|
63 | |||
| 64 | export interface ServiceDescriptorParams<S extends object, T, P extends any[]> { |
|
64 | export interface ServiceDescriptorParams<S extends object, T, P extends any[]> { | |
| 65 | owner: Container<S>; |
|
|||
| 66 |
|
||||
| 67 | lifetime?: ILifetimeManager; |
|
65 | lifetime?: ILifetimeManager; | |
| 68 |
|
66 | |||
| 69 | params?: P; |
|
67 | params?: P; | |
| @@ -88,12 +86,7 export class ServiceDescriptor<S extends | |||||
| 88 |
|
86 | |||
| 89 | _lifetime = LifetimeManager.empty; |
|
87 | _lifetime = LifetimeManager.empty; | |
| 90 |
|
88 | |||
| 91 | _owner: Container<S>; |
|
|||
| 92 |
|
||||
| 93 | constructor(opts: ServiceDescriptorParams<S, T, P>) { |
|
89 | constructor(opts: ServiceDescriptorParams<S, T, P>) { | |
| 94 | argumentNotNull(opts && opts.owner, "opts.owner"); |
|
|||
| 95 |
|
||||
| 96 | this._owner = opts.owner; |
|
|||
| 97 |
|
90 | |||
| 98 | if (opts.lifetime) |
|
91 | if (opts.lifetime) | |
| 99 | this._lifetime = opts.lifetime; |
|
92 | this._lifetime = opts.lifetime; | |
| @@ -1,13 +1,12 | |||||
| 1 | import { ServiceDescriptor, ServiceDescriptorParams } from "./ServiceDescriptor"; |
|
1 | import { ServiceDescriptor, ServiceDescriptorParams } from "./ServiceDescriptor"; | |
| 2 | import { Constructor, Factory } from "../interfaces"; |
|
|||
| 3 | import { argumentNotNull, isPrimitive } from "../safe"; |
|
2 | import { argumentNotNull, isPrimitive } from "../safe"; | |
| 4 |
|
3 | |||
| 5 | export interface TypeServiceDescriptorParams<S extends object, T extends object, P extends any[]> extends ServiceDescriptorParams<S, T, P> { |
|
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 | export class TypeServiceDescriptor<S extends object, T extends object, P extends any[]> extends ServiceDescriptor<S, T, P> { |
|
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 | constructor(opts: TypeServiceDescriptorParams<S, T, P>) { |
|
11 | constructor(opts: TypeServiceDescriptorParams<S, T, P>) { | |
| 13 | super(opts); |
|
12 | super(opts); | |
| @@ -18,9 +17,10 export class TypeServiceDescriptor<S ext | |||||
| 18 | if (this._params) { |
|
17 | if (this._params) { | |
| 19 | if (this._params.length) { |
|
18 | if (this._params.length) { | |
| 20 | this._factory = (...args) => { |
|
19 | this._factory = (...args) => { | |
| 21 | const t = Object.create(ctor.prototype); |
|
20 | /*const t = Object.create(ctor.prototype); | |
| 22 | const inst = ctor.apply(t, args); |
|
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 | } else { |
|
25 | } else { | |
| 26 | this._factory = arg => { |
|
26 | this._factory = arg => { | |
| @@ -1,7 +1,7 | |||||
| 1 | import { ServiceRecordBuilder, ExtractDependency, RegistrationVisitor } from "./interfaces"; |
|
1 | import { ServiceRecordBuilder, ExtractDependency, RegistrationVisitor, ServiceRegistration } from "./interfaces"; | |
| 2 | import { ActivationType } from "../interfaces"; |
|
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 | private _activationType: ActivationType = "call"; |
|
5 | private _activationType: ActivationType = "call"; | |
| 6 |
|
6 | |||
| 7 | private _overrides: { [m in keyof S]?: (...args: any) => void } | undefined; |
|
7 | private _overrides: { [m in keyof S]?: (...args: any) => void } | undefined; | |
| @@ -31,7 +31,7 export class RegistrationBuilder<T, S ex | |||||
| 31 | return this; |
|
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 | wired(module: ServiceModule<T, S>): RegistrationBuilder<T, S>; |
|
37 | wired(module: ServiceModule<T, S>): RegistrationBuilder<T, S>; | |
| 38 | } |
|
38 | } | |
| 39 |
|
39 | |||
| 40 |
export interface RegistrationVisitor |
|
40 | export interface RegistrationVisitor { | |
| 41 | visitDependency(): void; |
|
41 | visitDependency(): void; | |
| 42 |
|
42 | |||
| 43 | visitObject(): void; |
|
43 | visitObject(): void; | |
| @@ -48,23 +48,8 export interface RegistrationVisitor<S e | |||||
| 48 |
|
48 | |||
| 49 | } |
|
49 | } | |
| 50 |
|
50 | |||
| 51 |
export interface Registration |
|
51 | export interface ServiceRegistration { | |
| 52 | override<K extends keyof S>(name: K, builder: S[K], raw: true): this; |
|
52 | visit(visitor: RegistrationVisitor): void; | |
| 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; |
|
|||
| 68 | } |
|
53 | } | |
| 69 |
|
54 | |||
| 70 | export interface ConfigBuilder<S extends object, Y extends keyof S = keyof S> { |
|
55 | export interface ConfigBuilder<S extends object, Y extends keyof S = keyof S> { | |
| @@ -75,7 +60,7 export interface ConfigBuilder<S extends | |||||
| 75 | apply(container: Container<S>): Promise<void>; |
|
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 | build<T>(this: void): ServiceRecordBuilder<T, S>; |
|
64 | build<T>(this: void): ServiceRecordBuilder<T, S>; | |
| 80 | annotate<T>(this: void): AnnotaionBuilder<T, S>; |
|
65 | annotate<T>(this: void): AnnotaionBuilder<T, S>; | |
| 81 |
|
66 | |||
| @@ -84,5 +69,3 interface ServicesDeclaration<S extends | |||||
| 84 |
|
69 | |||
| 85 | configure(): ConfigBuilder<S>; |
|
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 | enter(): void; |
|
50 | enter(): void; | |
| 51 |
|
51 | |||
| 52 | store(item: any, cleanup?: (item: any) => void): void; |
|
52 | store(item: any, cleanup?: (item: any) => void): void; | |
| 53 | } No newline at end of file |
|
53 | } | |
| @@ -1,7 +1,50 | |||||
| 1 | import { isPrimitive } from "../safe"; |
|
1 | import { isPrimitive } from "../safe"; | |
| 2 | import { Descriptor } from "./interfaces"; |
|
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 | export function isDescriptor(x: any): x is Descriptor { |
|
8 | export function isDescriptor(x: any): x is Descriptor { | |
| 5 | return (!isPrimitive(x)) && |
|
9 | return (!isPrimitive(x)) && | |
| 6 | (x.activate instanceof Function); |
|
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
