##// END OF EJS Templates
Fixed MatchingMemberKeys, ExtractMembers type parameter names and order
cin -
r156:1a8a956a013f v1.4.0 default
parent child
Show More
@@ -1,154 +1,154
1 1 import { ActivationContext } from "./ActivationContext";
2 2 import { Descriptor, ServiceMap, PartialServiceMap, ILifetime } from "./interfaces";
3 3 import { isPrimitive, keys, isNull } from "../safe";
4 4 import { TraceSource } from "../log/TraceSource";
5 5 import { isDescriptor } from "./traits";
6 6 import { LifetimeManager } from "./LifetimeManager";
7 7 import { MatchingMemberKeys } from "../interfaces";
8 8
9 9 const trace = TraceSource.get("@implab/core/di/ActivationContext");
10 10
11 11 function injectMethod<T, M extends keyof T, S extends object, A>(target: T, method: M, context: ActivationContext<S>, args: A) {
12 12
13 13 const m = target[method];
14 14 if (!m || typeof m !== "function")
15 15 throw new Error("Method '" + method + "' not found");
16 16
17 17 if (args instanceof Array)
18 18 return m.apply(target, _parse(args, context, "." + method));
19 19 else
20 20 return m.call(target, _parse(args, context, "." + method));
21 21 }
22 22
23 23 function makeCleanupCallback<T>(method: Cleaner<T>) {
24 24 if (typeof (method) === "function") {
25 25 return (target: T) => {
26 26 method(target);
27 27 };
28 28 } else {
29 29 return (target: T) => {
30 30 const m = target[method] as any;
31 31 m.apply(target);
32 32 };
33 33 }
34 34 }
35 35
36 36 function _parse(value: any, context: ActivationContext<any>, path: string): any {
37 37 if (isPrimitive(value))
38 38 return value as any;
39 39
40 40 trace.debug("parse {0}", path);
41 41
42 42 if (isDescriptor(value))
43 43 return context.activate(value, path);
44 44
45 45 if (value instanceof Array)
46 46 return value.map((x, i) => _parse(x, context, `${path}[${i}]`)) as any;
47 47
48 48 const t: any = {};
49 49
50 50 keys(value).forEach(p => t[p] = _parse(value[p], context, `${path}.${p}`));
51 51
52 52 return t;
53 53 }
54 54
55 export type Cleaner<T> = ((x: T) => void) | MatchingMemberKeys<() => void, T>;
55 export type Cleaner<T> = ((x: T) => void) | MatchingMemberKeys<T, () => void>;
56 56
57 57 export type InjectionSpec<T> = {
58 58 [m in keyof T]?: any;
59 59 };
60 60
61 61 export interface ServiceDescriptorParams<S extends object, T, P extends any[]> {
62 62 lifetime?: ILifetime;
63 63
64 64 params?: P;
65 65
66 66 inject?: InjectionSpec<T>[];
67 67
68 68 services?: PartialServiceMap<S>;
69 69
70 70 cleanup?: Cleaner<T>;
71 71 }
72 72
73 73 export class ServiceDescriptor<S extends object, T, P extends any[]> implements Descriptor<S, T> {
74 74 _services: ServiceMap<S>;
75 75
76 76 _params: P | undefined;
77 77
78 78 _inject: InjectionSpec<T>[];
79 79
80 80 _cleanup: ((item: T) => void) | undefined;
81 81
82 82 _lifetime = LifetimeManager.empty();
83 83
84 84 _objectLifetime: ILifetime | undefined;
85 85
86 86 constructor(opts: ServiceDescriptorParams<S, T, P>) {
87 87
88 88 if (opts.lifetime)
89 89 this._lifetime = opts.lifetime;
90 90
91 91 if (!isNull(opts.params))
92 92 this._params = opts.params;
93 93
94 94 this._inject = opts.inject || [];
95 95
96 96 this._services = (opts.services || {}) as ServiceMap<S>;
97 97
98 98 if (opts.cleanup) {
99 99 if (!(typeof (opts.cleanup) === "string" || opts.cleanup instanceof Function))
100 100 throw new Error(
101 101 "The cleanup parameter must be either a function or a function name");
102 102
103 103 this._cleanup = makeCleanupCallback(opts.cleanup);
104 104 }
105 105 }
106 106
107 107 activate(context: ActivationContext<S>) {
108 108 const lifetime = this._lifetime;
109 109
110 110 if (lifetime.has()) {
111 111 return lifetime.get();
112 112 } else {
113 113 lifetime.initialize(context);
114 114 const instance = this._create(context);
115 115 lifetime.store(instance, this._cleanup);
116 116 return instance;
117 117 }
118 118 }
119 119
120 120 _factory(...params: any[]): T {
121 121 throw Error("Not implemented");
122 122 }
123 123
124 124 _create(context: ActivationContext<S>) {
125 125 trace.debug(`constructing ${context._name}`);
126 126
127 127 if (this._services) {
128 128 keys(this._services).forEach(p => context.register(p, this._services[p]));
129 129 }
130 130
131 131 let instance: T;
132 132
133 133 if (this._params === undefined) {
134 134 instance = this._factory();
135 135 } else if (this._params instanceof Array) {
136 136 instance = this._factory.apply(this, _parse(this._params, context, "args"));
137 137 } else {
138 138 instance = this._factory(_parse(this._params, context, "args"));
139 139 }
140 140
141 141 if (this._inject) {
142 142 this._inject.forEach(spec => {
143 143 for (const m in spec)
144 144 injectMethod(instance, m, context, spec[m]);
145 145 });
146 146 }
147 147 return instance;
148 148 }
149 149
150 150 clone() {
151 151 return Object.create(this);
152 152 }
153 153
154 154 }
@@ -1,126 +1,126
1 1 export interface Constructor<T = {}> {
2 2 new(...args: any[]): T;
3 3 prototype: T;
4 4 }
5 5
6 6 export type PromiseOrValue<T> = T | PromiseLike<T>;
7 7
8 8 export type Factory<T = {}> = (...args: any[]) => T;
9 9
10 10 export type Predicate<T = any> = (x: T) => boolean;
11 11
12 export type MatchingMemberKeys<T, From> = { [K in keyof From]: From[K] extends T ? K : never}[keyof From];
12 export type MatchingMemberKeys<T, U> = { [K in keyof T]: T[K] extends U ? K : never}[keyof T];
13 13
14 export type NotMatchingMemberKeys<T, From> = { [K in keyof From]: From[K] extends T ? never : K}[keyof From];
14 export type NotMatchingMemberKeys<T, U> = { [K in keyof T]: T[K] extends U ? never : K}[keyof T];
15 15
16 export type ExtractMembers<T, From> = Pick<From, MatchingMemberKeys<T, From>>;
16 export type ExtractMembers<T, U> = Pick<T, MatchingMemberKeys<T, U>>;
17 17
18 export type ExcludeMembers<T, From> = Pick<From, NotMatchingMemberKeys<T, From>>;
18 export type ExcludeMembers<T, U> = Pick<T, NotMatchingMemberKeys<T, U>>;
19 19
20 20 export interface MapOf<T> {
21 21 [key: string]: T;
22 22 }
23 23
24 24 export interface IDestroyable {
25 25 destroy(): void;
26 26 }
27 27
28 28 export interface IRemovable {
29 29 remove(): void;
30 30 }
31 31
32 32 export interface ICancellation {
33 33 throwIfRequested(): void;
34 34 isRequested(): boolean;
35 35 isSupported(): boolean;
36 36 register(cb: (e: any) => void): IDestroyable;
37 37 }
38 38
39 39 /**
40 40 * Π˜Π½Ρ‚Π΅Ρ€Ρ„Π΅ΠΉΡ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°ΡŽΡ‰ΠΈΠΉ Π°ΡΠΈΠ½Ρ…Ρ€ΠΎΠ½Π½ΡƒΡŽ Π°ΠΊΡ‚ΠΈΠ²Π°Ρ†ΠΈΡŽ
41 41 */
42 42 export interface IActivatable {
43 43 /**
44 44 * @returns Boolean indicates the current state
45 45 */
46 46 isActive(): boolean;
47 47
48 48 /**
49 49 * Starts the component activation
50 50 * @param ct cancellation token for this operation
51 51 */
52 52 activate(ct?: ICancellation): Promise<void>;
53 53
54 54 /**
55 55 * Starts the component deactivation
56 56 * @param ct cancellation token for this operation
57 57 */
58 58 deactivate(ct?: ICancellation): Promise<void>;
59 59
60 60 /**
61 61 * Sets the activation controller for this component
62 62 * @param controller The activation controller
63 63 *
64 64 * Activation controller checks whether this component
65 65 * can be activated and manages the active state of the
66 66 * component
67 67 */
68 68 setActivationController(controller: IActivationController): void;
69 69
70 70 /** Indicates whether this component has an activation controller */
71 71 hasActivationController(): boolean;
72 72
73 73 /**
74 74 * Gets the current activation controller for this component
75 75 */
76 76 getActivationController(): IActivationController;
77 77 }
78 78
79 79 export interface IActivationController {
80 80 activating(component: IActivatable, ct?: ICancellation): Promise<void>;
81 81
82 82 activated(component: IActivatable, ct?: ICancellation): Promise<void>;
83 83
84 84 deactivating(component: IActivatable, ct?: ICancellation): Promise<void>;
85 85
86 86 deactivated(component: IActivatable, ct?: ICancellation): Promise<void>;
87 87
88 88 deactivate(ct?: ICancellation): Promise<void>;
89 89
90 90 activate(component: IActivatable, ct?: ICancellation): Promise<void>;
91 91
92 92 hasActive(): boolean;
93 93
94 94 getActive(): IActivatable;
95 95 }
96 96
97 97 export interface IAsyncComponent {
98 98 getCompletion(): Promise<void>;
99 99 }
100 100
101 101 export interface ICancellable {
102 102 cancel(reason?: any): void;
103 103 }
104 104
105 105 export interface IObservable<T> {
106 106 on(next: (x: T) => void, error?: (e: any) => void, complete?: () => void): IDestroyable;
107 107 next(ct?: ICancellation): Promise<T>;
108 108 }
109 109
110 110 export interface IObserver<T> {
111 111 next(event: T): void;
112 112
113 113 error(e: any): void;
114 114
115 115 complete(): void;
116 116 }
117 117
118 118 export interface TextWriter {
119 119 write(obj: any): void;
120 120 write(format: string, ...args: any[]): void;
121 121
122 122 writeLine(obj?: any): void;
123 123 writeLine(format: string, ...args: any[]): void;
124 124
125 125 writeValue(value: any, spec?: string): void;
126 126 }
General Comments 0
You need to be logged in to leave comments. Login now