|
1
|
9 |
|
import { |
|
2
|
|
|
registeredMethods, logger, registeredBeans, |
|
3
|
|
|
} from '@/core'; |
|
4
|
|
|
|
|
5
|
52 |
|
const getMethods = (singleton: any) => Reflect.ownKeys(Object.getPrototypeOf(singleton)) |
|
6
|
94 |
|
.filter((method) => method !== 'constructor') |
|
7
|
42 |
|
.map(methodName => [singleton[methodName], methodName] as const); |
|
8
|
|
|
|
|
9
|
|
|
/** |
|
10
|
|
|
* Instantiates a new instance of the singleton and registers it |
|
11
|
|
|
* @decorator |
|
12
|
|
|
* @param target |
|
13
|
|
|
* @param _context |
|
14
|
|
|
*/ |
|
15
|
9 |
|
export function Bean(target: any, _context: ClassDecoratorContext) { |
|
16
|
26 |
|
logger.debug(`Registering singleton: ${target.name}`); |
|
17
|
26 |
|
Reflect.defineProperty(target, '_className', { |
|
18
|
4 |
|
get: () => target.name, |
|
19
|
|
|
}); |
|
20
|
26 |
|
Reflect.defineProperty(target, '_instance', { |
|
21
|
65 |
|
get: () => registeredBeans.get(target.name), |
|
22
|
|
|
}); |
|
23
|
26 |
|
Reflect.defineProperty(target, '_beanUUID', { |
|
24
|
|
|
value: crypto.randomUUID(), |
|
25
|
|
|
}); |
|
26
|
|
|
|
|
27
|
26 |
|
const interceptors: Map<string, (target: unknown, prop: string) => unknown> = new Map(); |
|
28
|
26 |
|
const mappers: Map<string, (original: unknown) => any> = new Map(); |
|
29
|
|
|
|
|
30
|
26 |
|
const handlerConfig = { |
|
31
|
|
|
getInterceptor: (t: any, p: string) => { |
|
32
|
18 |
|
const interceptor = interceptors.get(p); |
|
33
|
18 |
|
if (interceptor) { |
|
34
|
4 |
|
return interceptor(t, p); |
|
35
|
|
|
} |
|
36
|
14 |
|
return t[p]; |
|
37
|
|
|
}, |
|
38
|
|
|
getMapper: (_t: any, p: string) => { |
|
39
|
16 |
|
const mapper = mappers.get(p); |
|
40
|
16 |
|
if (mapper) { |
|
41
|
2 |
|
return mapper; |
|
42
|
|
|
} |
|
43
|
14 |
|
return (...args: unknown[]) => { |
|
44
|
14 |
|
return args; |
|
45
|
|
|
}; |
|
46
|
|
|
} |
|
47
|
|
|
}; |
|
48
|
26 |
|
const instance: typeof target = Reflect.construct(target, []); |
|
49
|
26 |
|
const preComputedMethods = new Map<string | symbol, (...args: unknown[]) => any>(); |
|
50
|
26 |
|
const singleton: any = new Proxy(instance, { |
|
51
|
|
|
get(targetProxy, prop) { |
|
52
|
127 |
|
if (typeof targetProxy[prop] === 'function') { |
|
53
|
40 |
|
if (preComputedMethods.has(prop)) { |
|
54
|
19 |
|
return preComputedMethods.get(prop); |
|
55
|
|
|
} |
|
56
|
21 |
|
const methodName = String(prop); |
|
57
|
|
|
let handlerFunction; |
|
58
|
|
|
|
|
59
|
21 |
|
handlerFunction = (...args: unknown[]) => { |
|
60
|
18 |
|
const result = handlerConfig.getInterceptor(targetProxy, methodName).apply(targetProxy, args); |
|
61
|
17 |
|
if (result instanceof Promise) { |
|
62
|
4 |
|
return result.then(res => handlerConfig.getMapper(targetProxy, methodName)(res)); |
|
63
|
|
|
} |
|
64
|
13 |
|
return handlerConfig.getMapper(targetProxy, methodName)(result); |
|
65
|
|
|
}; |
|
66
|
|
|
|
|
67
|
21 |
|
preComputedMethods.set(prop, handlerFunction); |
|
68
|
21 |
|
return handlerFunction; |
|
69
|
|
|
} |
|
70
|
87 |
|
return targetProxy[prop]; |
|
71
|
|
|
} |
|
72
|
|
|
}); |
|
73
|
26 |
|
Reflect.defineProperty(singleton, '_className', { |
|
74
|
60 |
|
get: () => target.name, |
|
75
|
|
|
}); |
|
76
|
26 |
|
getMethods(instance) |
|
77
|
|
|
.forEach(([classMethod, methodName]) => { |
|
78
|
21 |
|
logger.debug(`registering method ${target.name}.${String(methodName)}`); |
|
79
|
21 |
|
registeredMethods.set(classMethod, singleton); |
|
80
|
|
|
}); |
|
81
|
26 |
|
getMethods(singleton) |
|
82
|
|
|
.forEach(([classMethod, methodName]) => { |
|
83
|
21 |
|
logger.debug(`registering method ${target.name}.${String(methodName)}`); |
|
84
|
21 |
|
registeredMethods.set(classMethod, singleton); |
|
85
|
|
|
}); |
|
86
|
26 |
|
Reflect.defineProperty(singleton, '_interceptors', { |
|
87
|
6 |
|
get: () => interceptors, |
|
88
|
|
|
}); |
|
89
|
26 |
|
Reflect.defineProperty(singleton, '_mappers', { |
|
90
|
4 |
|
get: () => mappers, |
|
91
|
|
|
}); |
|
92
|
26 |
|
registeredBeans.set(target.name, singleton); |
|
93
|
|
|
} |
|
94
|
|
|
|