123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131 |
- var Module = require('./module');
- var autoAnnotate = require('./annotation').parse;
- var Injector = function(modules, parent) {
- parent = parent || {
- get: function(name) {
- currentlyResolving.push(name);
- throw error('No provider for "' + name + '"!');
- }
- };
- var currentlyResolving = [];
- var providers = this._providers = Object.create(parent._providers || null);
- var instances = this._instances = Object.create(null);
- instances.injector = this;
- var error = function(msg) {
- var stack = currentlyResolving.join(' -> ');
- currentlyResolving.length = 0;
- return new Error(stack ? msg + ' (Resolving: ' + stack + ')' : msg);
- };
- var get = function(name) {
- if (!providers[name] && name.indexOf('.') !== -1) {
- var parts = name.split('.');
- var pivot = get(parts.shift());
- while(parts.length) {
- pivot = pivot[parts.shift()];
- }
- return pivot;
- }
- if (Object.hasOwnProperty.call(instances, name)) {
- return instances[name];
- }
- if (Object.hasOwnProperty.call(providers, name)) {
- if (currentlyResolving.indexOf(name) !== -1) {
- currentlyResolving.push(name);
- throw error('Can not resolve circular dependency!');
- }
- currentlyResolving.push(name);
- instances[name] = providers[name][0](providers[name][1]);
- currentlyResolving.pop();
- return instances[name];
- }
- return parent.get(name);
- };
- var instantiate = function(Type) {
- var instance = Object.create(Type.prototype);
- var returned = invoke(Type, instance);
- return typeof returned === 'object' ? returned : instance;
- };
- var invoke = function(fn, context) {
- if (typeof fn !== 'function') {
- throw error('Can not invoke "' + fn + '". Expected a function!');
- }
- var inject = fn.$inject && fn.$inject || autoAnnotate(fn);
- var dependencies = inject.map(function(dep) {
- return get(dep);
- });
- // TODO(vojta): optimize without apply
- return fn.apply(context, dependencies);
- };
- var createChild = function(modules, providersFromParent) {
- if (providersFromParent && providersFromParent.length) {
- var fromParentModule = Object.create(null);
- providersFromParent.forEach(function(name) {
- if (!providers[name]) {
- throw new Error('No provider for "' + name + '". Can not use provider from the parent!');
- }
- fromParentModule[name] = [providers[name][2], providers[name][1]];
- });
- modules.unshift(fromParentModule);
- }
- return new Injector(modules, this);
- };
- var factoryMap = {
- factory: invoke,
- type: instantiate,
- value: function(value) {
- return value;
- }
- };
- modules.forEach(function(module) {
- // TODO(vojta): handle wrong inputs (modules)
- if (module instanceof Module) {
- module.forEach(function(provider) {
- var name = provider[0];
- var type = provider[1];
- var value = provider[2];
- providers[name] = [factoryMap[type], value, type];
- });
- } else if (typeof module === 'object') {
- Object.keys(module).forEach(function(name) {
- var type = module[name][0];
- var value = module[name][1];
- providers[name] = [factoryMap[type], value, type];
- });
- }
- });
- // public API
- this.get = get;
- this.invoke = invoke;
- this.instantiate = instantiate;
- this.createChild = createChild;
- };
- module.exports = Injector;
|