All files / src/decorators Initializable.ts

100% Statements 21/21
93.75% Branches 15/16
100% Functions 5/5
100% Lines 21/21
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                1x 48x   48x   48x 48x       48x   48x 1x     47x 47x 47x 47x   47x     414211x 1x     414210x     163921x     47x     139328x   139328x       47x      
/* tslint:disable:no-invalid-this */
 
import { IInitializable } from '../interfaces/IInitializable';
 
/**
 * @param initializeMethodKey
 * @returns {(target:IInitializable, propertyKey:(string|symbol))=>PropertyDescriptor}
 */
export function initializable (
    initializeMethodKey: string = 'initialize'
): (target: IInitializable, propertyKey: string | symbol) => any {
    const decoratorName: string = Object.keys(this)[0];
 
    return (target: IInitializable, propertyKey: string | symbol): any => {
        const descriptor: PropertyDescriptor = {
            configurable: true,
            enumerable: true
        };
        const initializeMethod: any = (<any>target)[initializeMethodKey];
 
        if (!initializeMethod || typeof initializeMethod !== 'function') {
           throw new Error(`\`${initializeMethodKey}\` method with initialization logic not found. \`@${decoratorName}\` decorator requires \`${initializeMethodKey}\` method`);
        }
 
        const metadataPropertyKey: string = `_${propertyKey}`;
        const propertyDescriptor: PropertyDescriptor = Object.getOwnPropertyDescriptor(target, metadataPropertyKey) || descriptor;
        const methodDescriptor: PropertyDescriptor = Object.getOwnPropertyDescriptor(target, initializeMethodKey) || descriptor;
        const originalMethod: Function = methodDescriptor.value;
 
        Object.defineProperty(target, propertyKey, {
            ...propertyDescriptor,
            get: function (): any {
                if (this[metadataPropertyKey] === undefined) {
                    throw new Error(`Property \`${propertyKey}\` is not initialized! Initialize it first!`);
                }
 
                return this[metadataPropertyKey];
            },
            set: function (newVal: any): void {
                this[metadataPropertyKey] = newVal;
            }
        });
        Object.defineProperty(target, initializeMethodKey, {
            ...methodDescriptor,
            value: function (): void {
                originalMethod.apply(this, arguments);
 
                if (this[propertyKey]) {}
            }
        });
 
        return propertyDescriptor;
    };
}