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