Home Identifier Source

lib/injector.js

/**
* @class Injector
*/
export class Injector{

  /**
  * This is an Injector
  * @constructor
  * @param {ResolvedBinding} resolvedBindings - The resolved binding of the injector
  * @param {Injector} parent - The parent injector
  */
  constructor(resolvedBindings, parent){
    this.resolvedBindings = resolvedBindings;
    this.parent = parent;
  }

  /**
  * This is an injector Factory
  * @param {Binding} bindings - List of the bindings to resolve
  * @Optionnal {Injector} injector - Optionnal parent injector
  * @returns {Injector} The new injector created
  */
  static resolveAndCreate(bindings, injector){
    return new Injector(Injector.resolve(bindings), injector);
  }

  /**
  * Start the binding resolution
  * @param {Binding} bindings - An array of bindings to resolve
  * @returns {ResolvedBinding} The array of resolvedBinding obtained
  */
  static resolve(bindings){
    let resolvedBindings = [];
    for(var b of bindings){
      resolvedBindings.push(b.resolve());
    }
    return resolvedBindings;
  }

  /**
  * Return the factory execution value if the key matches
  * @param {String} token - The key of the resolvedBinding factory to get
  * @returns {Object} The value corresponding to the factory execution
  */
  get(token){
    for(var rb of this.resolvedBindings){
      if(rb.key === token){
        return this.resolveDependencies(rb);
      }
    }
    return token;
  }

  /**
  * Resolve the dependencies of the resolvedBinding
  * @param {ResolvedBinding} resolvedBinding - The resolved binding concerned
  * @returns {Object} The factory execution loaded
  */
  resolveDependencies(resolvedBinding){
    let dependencyArray = this.parseDependencies(resolvedBinding.dependencies);
    let newInstance = this.resolveConstructor(resolvedBinding, dependencyArray.inConstructor);
    newInstance = this.resolveProperty(newInstance, dependencyArray.inProperty);
    newInstance = this.resolveSetters(newInstance, dependencyArray.inSetter);
    return newInstance;
  }

  /**
  * Split dependencies in an array of object
  * @param {Object} dependencies - An array of dependencies
  * @returns {Object} An array of dependencies splitted into 3 category
  * inConstructor, inProperty, inSetter
  */
  parseDependencies(dependencies){
    let dependencyArray = {inConstructor:[], inProperty:[], inSetter:[]}
    for(var d of dependencies){
      if(d.inSetter){
        dependencyArray.inSetter.push(d);
      }else{
        if(d.inProperty){
          dependencyArray.inProperty.push(d);
        }else{
          dependencyArray.inConstructor.push(d);
        }
      }
    }
    return dependencyArray;
  }

  /**
  * Resolve the constructor injector
  * @param {ResolvedBinding} resolvedBinding - The resolved binding to loaded
  * @param {Object} dependencies - The dependencies to inject
  * @returns {Object} Return the object instance with constructor dependencies
  */
  resolveConstructor(resolvedBinding, dependencies){
    let newInstance = null;
    switch(dependencies.length){
      case 0:
        newInstance = resolvedBinding.factory();
      break;

      case 1:
        newInstance = resolvedBinding.factory(this.get(dependencies[0]));
      break;

      case 2:
        newInstance = resolvedBinding.factory(this.get(dependencies[0]), this.get(dependencies[1]));
      break;

      case 3:
        newInstance = resolvedBinding.factory(this.get(dependencies[0]), this.get(dependencies[1]), this.get(dependencies[2]));
      break;

      case 4:
        newInstance = resolvedBinding.factory(this.get(dependencies[0]), this.get(dependencies[1]), this.get(dependencies[2]),
        this.get(dependencies[3]));
      break;

      case 5:
        newInstance = resolvedBinding.factory(this.get(dependencies[0]), this.get(dependencies[1]), this.get(dependencies[2]),
        this.get(dependencies[3]), this.get(dependencies[4]));
      break;

      case 6:
        newInstance = resolvedBinding.factory(this.get(dependencies[0]), this.get(dependencies[1]), this.get(dependencies[2]),
        this.get(dependencies[3]), this.get(dependencies[4]), this.get(dependencies[5]));
      break;

      case 7:
        newInstance = resolvedBinding.factory(this.get(dependencies[0]), this.get(dependencies[1]), this.get(dependencies[2]),
        this.get(dependencies[3]), this.get(dependencies[4]), this.get(dependencies[5]), this.get(dependencies[6]));
      break;

      case 8:
        newInstance = resolvedBinding.factory(this.get(dependencies[0]), this.get(dependencies[1]), this.get(dependencies[2]),
        this.get(dependencies[3]), this.get(dependencies[4]), this.get(dependencies[5]), this.get(dependencies[6]),
        this.get(dependencies[7]));
      break;

      case 9:
        newInstance = resolvedBinding.factory(this.get(dependencies[0]), this.get(dependencies[1]), this.get(dependencies[2]),
        this.get(dependencies[3]), this.get(dependencies[4]), this.get(dependencies[5]), this.get(dependencies[6]),
        this.get(dependencies[7]), this.get(dependencies[8]));
      break;

      case 10:
        newInstance = resolvedBinding.factory(this.get(dependencies[0]), this.get(dependencies[1]), this.get(dependencies[2]),
        this.get(dependencies[3]), this.get(dependencies[4]), this.get(dependencies[5]), this.get(dependencies[6]),
        this.get(dependencies[7]), this.get(dependencies[8]), this.get(dependencies[9]));
      break;
    }
    return newInstance;
  }

  /**
  * Resolve properties injection
  * @param {Object} newInstance - The object instance where to inject properties
  * @params {Object} dependencies - The property dependencies to inject
  * @returns {Object} The object with property injected
  */
  resolveProperty(newInstance, dependencies){
    for(var d of dependencies){
      newInstance[d.ref[0].toLowerCase() + d.ref.substring(1)] = this.get(d.ref);
    }
    return newInstance;
  }

  /**
  * Resolve setters injection
  * @param {Object} newInstance - The object where to make setter injection
  * @params {Object} dependencies - The setter dependencies to inject
  * @returns {Object} The object with setters injected
  */
  resolveSetters(newInstance, dependencies){
    for(var d of dependencies){
      newInstance['set'+d.ref] = this.get(d.ref);
    }
    return newInstance;
  }
}