-
Notifications
You must be signed in to change notification settings - Fork 37
/
method_call.ts
81 lines (75 loc) · 2.62 KB
/
method_call.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import { Precondition, JoinPoint } from '../core/join_point';
import { Advice } from '../core/advice';
import { Pointcut } from '../core/pointcut';
import { AspectRegistry, Targets, Aspect } from '../core/aspect';
import { MethodSelector } from './selectors';
import { MethodPrecondition } from './preconditions';
const BLACK_LIST = ['constructor'];
export class MethodCallJoinPoint extends JoinPoint {
public getTarget(fn: Function): any {
return fn.prototype;
}
public match(target: Function): any[] {
let keys = Object.getOwnPropertyNames(target.prototype);
keys = keys.filter(key => {
return BLACK_LIST.indexOf(key) < 0;
});
const res = keys
.map(key => {
const descriptor = Object.getOwnPropertyDescriptor(target.prototype, key);
if (
this.precondition.assert({
classDefinition: target,
methodName: key
}) &&
typeof descriptor.value === 'function'
) {
return key;
}
return false;
})
.filter(val => !!val);
return res;
}
protected woveTarget(proto: { [key: string]: any }, key: string, advice: Advice, woveMetadata: any) {
const className = proto.constructor.name;
const bak = proto[key];
const self = this;
proto[key] = function() {
const metadata = self.getMetadata(className, key, bak, arguments, this, woveMetadata);
return advice.wove(bak, metadata);
};
proto[key].__woven__ = true;
}
}
export function makeMethodCallAdviceDecorator(constr: any) {
return function(...selectors: MethodSelector[]): MethodDecorator {
return function<T>(target: Object, prop: symbol | string, descriptor: TypedPropertyDescriptor<T>) {
const joinpoints = selectors.map(selector => {
return new MethodCallJoinPoint(new MethodPrecondition(selector));
});
const pointcut = new Pointcut();
pointcut.advice = <Advice>new constr(target, descriptor.value);
pointcut.joinPoints = joinpoints;
const aspectName = target.constructor.name;
const aspect = AspectRegistry.get(aspectName) || new Aspect();
aspect.pointcuts.push(pointcut);
AspectRegistry.set(aspectName, aspect);
// For lazy loading
Targets.forEach(({ target, config }) => aspect.wove(target, config));
return target;
};
};
}
/**
* Kept for backward compability only.
* Use {@link MethodCallJoinPoint} instead.
*
* @deprecated renamed to MethodCallJoinPoint
* @see MethodCallJoinPoint
*/
export abstract class MethodCallJointPoint extends MethodCallJoinPoint {
constructor(precondition: Precondition) {
super(precondition);
}
}