# 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
    39x

    39x

    39x
    39x

    39x

    39x
    1x

    38x
    38x
    38x
    38x

    38x

    155174x
    1x

    155173x

    33363x

    38x

    27385x

    27385x

    38x

     /* 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;
        };
    }