Passed
Push — develop ( fd6ace...15cef8 )
by Lorenzo
01:12
created

Bean.ts ➔ Bean   B

Complexity

Conditions 6

Size

Total Lines 79
Code Lines 54

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 43
CRAP Score 6.0031

Importance

Changes 0
Metric Value
eloc 54
dl 0
loc 79
c 0
b 0
f 0
ccs 43
cts 45
cp 0.9556
rs 7.5721
cc 6
crap 6.0031

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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