All files conditional-injector.ts

96.08% Statements 49/51
93.75% Branches 15/16
100% Functions 10/10
96% Lines 48/50

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 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109    1x                     6x 6x   6x 17x 30x 30x     30x 30x 30x     3x   27x 3x     11x 10x 10x   1x     6x 2x 2x 2x   2x 3x   2x       18x 18x 2x 16x 2x 2x   14x                 6x 20x 13x   7x   20x           20x 20x       1x 20x 6x     20x       20x 20x 20x 20x   20x 20x                
import * as Options from './options';
 
let injectableContainer: any = {};
 
type Injectable = {
    name: string;
    options: Options.Options;
    constructor: ObjectConstructor;
    singletonInstance?: any;
};
 
export class ParentClassContainer {
 
    private predicatesList: Injectable[] = [];
    private defaultList: Injectable[] = [];
 
    public create = (argument?: any): any => {
        for (const injectable of this.predicatesList) {
            const factoryPredicate = injectable.options.predicate;
            Iif (!factoryPredicate) {
                continue;
            }
            let factoryPredicateResult = false;
            try {
                factoryPredicateResult = factoryPredicate(argument);
            }
            catch (err) {
                throw new Error(`Error executing factory predicate of ${injectable.name}: ${err}`);
            }
            if (factoryPredicateResult) {
                return this.instantiateInjectable(injectable, argument);
            }
        }
        if (this.defaultList.length > 0) {
            let lastAddedDefault = this.defaultList[this.defaultList.length - 1];
            return this.instantiateInjectable(lastAddedDefault, argument);
        }
        return null;
    }
 
    public createAll = (argument?: any): any[] => {
        let returnList = [];
        for (const injectable of this.predicatesList) {
            returnList.push(this.instantiateInjectable(injectable, argument));
        }
        for (const injectable of this.defaultList) {
            returnList.push(this.instantiateInjectable(injectable, argument));
        }
        return returnList;
    }
 
    private instantiateInjectable(injectable: Injectable, argument: any): any {
        try {
            if (injectable.singletonInstance) {
                return injectable.singletonInstance;
            } else if (injectable.options.scope == Options.Scope.Application) {
                injectable.singletonInstance = new injectable.constructor(argument);
                return injectable.singletonInstance;
            } else {
                return new injectable.constructor(argument);
            }
        }
        catch (err) {
            throw new Error(`Error instantiating object of ${injectable.name}: ${err}`);
        }
 
    }
 
    public addInjectable = (injectable: Injectable): Injectable => {
        if (!injectable.options.predicate) {
            this.defaultList.push(injectable);
        } else {
            this.predicatesList.push(injectable);
        }
        return injectable;
    }
}
 
export class Container {
    public static subclassesOf(superClass: any): ParentClassContainer {
        const superClassName: string = superClass.prototype.constructor.name;
        return injectableContainer[superClassName] || { create: () => null};
    }
}
 
const getSuperClassContainer = (superClassName: string): any => {
    if (!injectableContainer[superClassName]) {
        injectableContainer[superClassName] = new ParentClassContainer();
    }
 
    return injectableContainer[superClassName];
};
 
export function Injectable(options?: Options.Options) {
    return function(constructor: any) {
        const superClassName = Object.getPrototypeOf(constructor.prototype).constructor.name;
        const className = constructor.prototype.constructor.name;
        const injectableContainer: ParentClassContainer = getSuperClassContainer(superClassName);
 
        let mergedOption = Options.completeAttributes(options);
        injectableContainer
            .addInjectable(
                {
                    name: className,
                    constructor: constructor,
                    options: mergedOption
                });
    };
}