All files / core/src/linker factor.ts

100% Statements 60/60
100% Branches 5/5
100% Functions 1/1
100% Lines 60/60

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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 611x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 63x 63x 63x 63x 63x 63x 63x 63x 63x 63x 40x 40x 40x 40x 40x 40x 40x 40x 63x 63x 63x 1x 1x  
import { Linker } from './linker';
 
/**
 * Prototype property decorator factory. Applying this decorator replaces the
 * decorated prototype property with a getter, which returns the linked instance
 * of a {@link Target}ed constructor, referenced by the `targetFactory`.
 * Depending on the supplied `transient` value, the target constructor is
 * invoked to construct (and link) an instance, if none is linked beforehand.
 *
 * @param targetFactory - A forward reference to the target constructor.
 * @param transient - Whether an instance is constructed if none is linked.
 * @typeParam K - The {@link Target}ed constructor type.
 * @returns A prototype property decorator.
 *
 * @example
 * **Factor** an eager and lazy service:
 * ```ts
 * import { Factor } from '@sgrud/core';
 * import { EagerService, LazyService } from './services';
 *
 * export class ServiceHandler {
 *
 *   ⁠@Factor(() => EagerService)
 *   private readonly service!: EagerService;
 *
 *   ⁠@Factor(() => LazyService, true)
 *   private readonly service?: LazyService;
 *
 * }
 * ```
 *
 * @see {@link Linker}
 * @see {@link Target}
 */
export function Factor<K extends new () => any>(
  targetFactory: () => K,
  transient: boolean = false
) {
 
  /**
   * @param prototype - The `prototype` to be decorated.
   * @param propertyKey - The `prototype` property to be decorated.
   */
  return function(prototype: object, propertyKey: PropertyKey): void {
    Object.defineProperty(prototype, propertyKey, {
      enumerable: true,
      get: (): InstanceType<K> | undefined => {
        const linker = new Linker<K>();
 
        if (transient && !linker.has(targetFactory())) {
          return undefined;
        }
 
        return linker.get(targetFactory());
      },
      set: Function.prototype as (...args: any[]) => any
    });
  };
 
}