DI test prototype

by Aleksey P

JavaScript

"use strict";

function IoC() {
  let services = {}; // services registration options
  let self = this;

  this.register = function(service, options) {
    if (typeof(service) !== "function")
      throw new Error("Service is not a function: " + service);

    if (typeof(options) === "undefined") {
      options = {};
    };
    setDefaultOptions(options);

    let name = service.name;
    if (services.hasOwnProperty(name))
      throw new Error("Service already has been registered: " + name);

    options.__service = service;
    services[name] = options;

    return function() {
      return self.resolve(name);
    };
  };

  this.resolve = function(name) {
    if (!services.hasOwnProperty(name))
      throw new Error("Service can not be resolved: " + name);
    let options = services[name];
    let service = options.__service;
    let usedServices = getParamNames(service).map(self.resolve);

    if (options.lifetime == "transient") {
      return function() {
        return new function() {
          return service.apply(this, usedServices);
        };
      };
    };
    if (options.lifetime == "singleton") {
      return function() {
        return options.__instance || (options.__instance = new function() {
          return service.apply(this, usedServices);
        });
      };
    };
    throw new Error("Service can not be resolved: " + name);
  };

  this.check = function() {
    Object.keys(services).forEach(checkUsedServicesExist);
    Object.keys(services).forEach(checkCycle);
  };
  
  function checkUsedServicesExist(name) {
  	getUsedServices(name).map(self.resolve);
  };

  let getUsedServices = name => getParamNames(services[name].__service);

  function checkCycle(name) {
    let chains = [[name]];
    let i = 0;
    while (i < chains.length) {
      let currentChain = chains[i];
      let currentName = currentChain[currentChain.length - 1];
      let currentUsed = getUsedServices(currentName);
      currentChain.forEach(x => {
        if...