-
Notifications
You must be signed in to change notification settings - Fork 14
/
decorators.ts
134 lines (126 loc) · 5.17 KB
/
decorators.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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import { IClassAdviceSignature } from "./interface/IClassAdviceSignature"
import { bootstrap } from "./core/bootstrapFn"
import { IAdviceSignature } from "./interface/IAdviceSignature"
import { IFakeMethodReplacement } from "./interface/IFakeMethodReplacement"
import { IAdviceParamInjector } from "./interface/IAdviceParamInjector"
import { IStackEntry } from "./interface/IStackEntry"
/**
* @function adviceMetadata - this decorator function sets a property '$$meta'
* with the requested metadata param index
*
* @param {Object} target method class
* @param {string} propertyKey ..
* @param {number} parameterIndex ..
*/
export function adviceMetadata (target: Object, propertyKey: string | symbol, parameterIndex: number) {
target[propertyKey].$$meta = parameterIndex
}
/**
* @function adviceParam - fill an array with the requested param order
* if array '$$params' property does not exist in the method advice it
* will be created
* @param {number} index requested index param
*/
export function adviceParam (index: number) {
return function (target: Object, propertyKey: string | symbol, parameterIndex: number) {
if (!target[propertyKey].$$params) { target[propertyKey].$$params = [] }
target[propertyKey].$$params[parameterIndex] = index
}
}
/**
* @function afterInstance - this decorator function places the 'adviceFn' to be executed
* within (after) the decorated class (constructor) call stack
*
* @param {Function} adviceFn advice reference
* @param {Array} args advice arguments
* @return {IClassAdviceSignature} wrapped constructor reference
*/
export function afterInstance (adviceFn: (...args) => void, ...args: any[]): IClassAdviceSignature {
return function (target: any) {
if (!target || !target.$$before) {
let rawConstructor = target
target = bootstrap(undefined, "constructor", rawConstructor)
}
const advice = adviceFn as IAdviceParamInjector
const stackEntry: IStackEntry = { advice, args }
target.$$after.unshift(stackEntry)
return target
}
}
/**
* @function afterMethod - this decorator function places the 'adviceFn' to be executed
* within (after) the decorated method call stack
*
* @param {Function} adviceFn advice reference
* @param {Array} args advice arguments
* @return {IAdviceSignature} wrapped method reference
*/
export function afterMethod (adviceFn: (...args) => void, ...args: any[]): IAdviceSignature {
return function (target: Object, propertyKey: string, descriptor: PropertyDescriptor) {
if (!descriptor.value.$$before) {
let rawMethod = descriptor.value
descriptor.value = bootstrap(target, propertyKey, rawMethod)
}
const advice = adviceFn as IAdviceParamInjector
const stackEntry: IStackEntry = { advice, args }
descriptor.value.$$after.unshift(stackEntry)
return descriptor
}
}
/**
* @function beforeInstance - this decorator function places the 'adviceFn' to be executed
* within (before) the decorated class (constructor) call stack
*
* @param {Function} adviceFn advice reference
* @param {Array} args advice arguments
* @return {IClassAdviceSignature} wrapped constructor reference
*/
export function beforeInstance (adviceFn: (...args) => void, ...args: any[]): IClassAdviceSignature {
return function (target: any) {
if (!target || !target.$$before) {
let rawConstructor = target
target = bootstrap(undefined, "constructor", rawConstructor)
}
const advice = adviceFn as IAdviceParamInjector
const stackEntry: IStackEntry = { advice, args }
target.$$before.unshift(stackEntry)
return target
}
}
/**
* @function beforeMethod - this decorator function places the 'adviceFn' to be executed
* within (before) the decorated method call stack
*
* @param {Function} adviceFn advice reference
* @param {Array} args advice arguments
* @return {IAdviceSignature} wrapped method reference
*/
export function beforeMethod (adviceFn: (...args) => void, ...args: any[]): IAdviceSignature {
return function (target: Object, propertyKey: string, descriptor: PropertyDescriptor) {
if (!descriptor.value.$$before) {
let rawMethod = descriptor.value
descriptor.value = bootstrap(target, propertyKey, rawMethod)
}
const advice = adviceFn as IAdviceParamInjector
const stackEntry: IStackEntry = { advice, args }
descriptor.value.$$before.unshift(stackEntry)
return descriptor
}
}
/**
* Triggers an aspect when an exception occurs
*/
export function onException (adviceFn: (...args) => void, ...args: any[]): IAdviceSignature {
return function (target: Object, propertyKey: string, descriptor: PropertyDescriptor) {
// If descriptor hasn't been initializated
if (!descriptor.value.$$error) {
let rawMethod = descriptor.value
descriptor.value = bootstrap(target, propertyKey, rawMethod)
}
const advice = adviceFn as IAdviceParamInjector
const stackEntry: IStackEntry = { advice, args }
// Place it at the end of the $$before stack
descriptor.value.$$error = stackEntry
return descriptor
}
}