src/definition.js
var Definition = function Definition(id, conf, container) { var self = this;

the id of the definition

self.id = id;

The callable that creates the service

self.fn = false;

The arguments that will be send to the callable when called, order matters

self.args = [];

The tags that the service will receive

self.tags = [];

Contains the last created instance of the service, this is reused when the service is a shared service

self.service = false;

Indicate wether the service behaves like a singleton; returning the same instance on repeated requests

self.shared = false;

Method retrieve()

Create an instance from this definition

Returns a mixed

self.retrieve = function retrieve() { if(self.shared === true && self.service !== false) { return self.service; } var service = self.fn(); if(service === undefined) { throw new Error('"'+id+'" service returned "'+undefined+'" on instantiation.'); } self.service = service; return service; };

Method addArgument

Add an argument (at the end) to the definition

Parameters:

  • arg must be a mixed.
self.addArgument = function addArgument(arg) { self.args.push(arg); return self; };

Method addTag()

Tag the service

Parameters:

  • tag must be a string.
self.addTag = function addTag(tag) { if(self.tags.indexOf(tag) === -1) self.tags.push(tag); return self; };

Resolve arguments that are container ids

Returns an Array
(the resolved arguments)

self.resolveArguments = function resolveArguments(arr) { arr = typeof arr !== 'undefined' ? arr : self.args; arr.forEach(function(arg, i){ if(container.isId(arg)) { arr[i] = container.get(arg.replace(container.idPrefix, '')); } else if(Array.isArray(arg)) { arr[i] = self.resolveArguments(arg); } else if(arg.constructor == Object) { Object.keys(arg).forEach(function(k){ if(container.isId(arg[k])) arg[k] = container.get(arg[k].replace(container.idPrefix, '')); }); } }); return arr; };

Private method

Create an callable that can creates instances for this definitions

Parameters:

  • fnParam must be a string.
    (the container parameter that contains the constructor or factory function)

  • type must be a string.
    (either 'c' for constructor or 'f' for factory)

Returns a Function

self._createCallable = function(fnParam, type) { var res = false; var getCheckCallable = function(p) { var fn = false; if(typeof p === 'function') { fn = p; } else { try { fn = container.getParameter(p.replace(container.idPrefix, '')); } catch(e) { throw new Error('Whene trying to instanciate service "'+self.id+'", the parameter specifying the '+((type == 'f') ? ('factory') : ('constructor'))+': "'+fnParam+'" did not exist.'); } } if(typeof fn !== 'function') { throw new Error('Whene trying to instanciate service "'+self.id+'", the parameter specifying the '+((type == 'f') ? ('factory') : ('constructor'))+': "'+fnParam+'" did not return a function, instead received: "'+fn+'"'); } return fn; }; function neu(constructor, args) { var instance = Object.create(constructor.prototype); var result = constructor.apply(instance, args); return typeof result === 'object' ? result : instance; } //constructor type use new if(type === 'c') { res = function() { var _c = new getCheckCallable(fnParam); var _args = self.resolveArguments(); return neu(_c, _args); }; return res; } //factory type just call it return function() { return getCheckCallable(fnParam).apply(container, self.resolveArguments()); //create using factory fn }; };

Apply an defintion configuration

Parameters:

  • conf must be an Object.

Returns a Definition

self.configure = function(conf) { //shared if(conf.shared !== undefined) { if(String(conf.shared).toLowerCase() === 'true') { self.shared = true; } else if(String(conf.shared).toLowerCase() === 'false') { self.shared = false; } else { throw new Error('Configuration of "'+self.id+'" shared should be an boolean, received: "'+conf+'"'); } } //constructing var fnParam = conf.constructorFn; var type = 'c'; if(fnParam === undefined) { fnParam = conf.factoryFn; type = 'f'; } else if(conf.factoryFn !== undefined) { throw new Error('Configuration of "'+self.id+'" should specify a constructor OR an factory function, not both - received: "'+conf+'"'); } if(fnParam === undefined) throw new Error('Configuration of "'+self.id+'" must either specify an constructor or an factory function - received: "'+conf+'"'); if(container.isId(fnParam) === false && typeof fnParam !== 'function') { throw new Error('Constructor or an factory function of "'+self.id+'" should be specified using a parameter id - received: "'+fnParam+'"'); } self.fn = self._createCallable(fnParam, type); //arguments var args = conf.arguments; if(args !== undefined) { if(!Array.isArray(args)) throw new Error('Instantiation arguments of "'+self.id+'" should be specified as an array - received: "'+args+'"'); args.forEach(function(arg){ self.addArgument(arg); }); } //tags var tags = conf.tags; if(tags !== undefined) { if(!Array.isArray(tags)) throw new Error('Service tags of "'+self.id+'" should be specified as an array - received: "'+tags+'"'); tags.forEach(function(tag){ self.addTag(tag); }); } return self; }; //configure the definition with the provided argument self.configure(conf); }; module.exports = Definition;