simple-ioc
Version:
Simple Inversion of Control for node.js
109 lines • 4.36 kB
JavaScript
var IocError = require( '../genericHelpers/IocError.js' )(),
log = require( '../log/log.js' )( 'resolver' ),
errRerouter = require( '../genericHelpers/errRerouter.js' )(),
resolvedComponent = require( '../containerHelpers/resolvedComponent.js' )(),
wrapper = require( '../wrapping/wrapper.js' )(),
timer = require( '../genericHelpers/timer.js' )( 2000 ),
wrapper = require( '../wrapping/wrapper.js' )(),
injectableComponent = require( './injectableComponent.js' )();
module.exports = function( trueCallback ) {
var pub = {};
pub.resolveInjectableComponent = function( parentName, component, resolvedNonReservedDependencies, callback ) {
var pub = {},
setupFn,
asyncCallback = [ function( err, instance ) {
if( trueCallback )
setImmediate( callback, err, component.dependencies.hasPub ? pub : instance );
else
setImmediate( callback, undefined, component.dependencies.hasPub ? pub : instance || err );
}, function() {} ];
var instance = component.fn.apply( undefined, component.dependencies.parameters.map( function( dependency ) {
if( !dependency.isReserved )
return resolvedNonReservedDependencies[ dependency.name ];
else if( dependency.isCallback )
return asyncCallback.shift();
else if( dependency.isParentName )
return parentName;
else if( dependency.isPub )
return pub;
else if( dependency.isSetup ) {
return function( setup ) {
setupFn = setup;
};
}
} ) );
if( setupFn )
setupFn();
asyncCallback.shift()( undefined, instance );
};
var resolveDependencies = function( store, name, nonReserved, callback ) {
nonReserved = nonReserved.concat();
( function recursive( resolved ) {
if( !nonReserved.length )
callback( undefined, resolved );
else {
var dependencyName = nonReserved.pop();
pub.resolve( store, dependencyName, name, errRerouter( callback, function( instance ) {
resolved[ dependencyName ] = instance;
recursive( resolved );
} ) );
}
} )( {} );
};
pub.registerGlobalWrapper = function( name, wrapperResolveFn ) {
wrapper.registerWrapper( name, wrapperResolveFn );
};
pub.inject = function( store, fn, parentName, callback ) {
var component = injectableComponent.get( fn );
resolveDependencies( store, 'anonymousFunction', component.dependencies.nonReserved, function( err, resolvedNonReservedDependencies ) {
if( err && !callback )
log.fatal( 'Cannot resolve dependencies for anonymous function', err );
else
pub.resolveInjectableComponent( parentName, component, resolvedNonReservedDependencies, function( err, instance ) {
if( callback )
callback( err, instance );
} );
} );
};
pub.resolve = function( store, name, parentName, callback ) {
if( !store.isResolvable( name ) ) {
setImmediate( callback, new IocError( 'Component unresolvable', store.getResolvingProblems( name ) ) );
}
else if( store.isResolved( name ) ) {
store.addUsage( name, parentName );
wrapper.wrap( parentName, name, store.getResolved( name ).instance, function( err, wrappedInstance ) {
callback( undefined, wrappedInstance );
} );
}
else {
var component = store.getInjectable( name );
if( !component.isTransient && component.hasWaiting ) {
component.waiting = pub.resolve.bind( undefined, store, name, parentName, callback );
}
else {
if( !component.isTransient )
component.waiting = pub.resolve.bind( undefined, store, name, parentName, callback );
log.trace( 'Resolving', name );
resolveDependencies( store, name, component.dependencies.nonReserved, errRerouter( callback, function( resolvedNonReservedDependencies ) {
timer.startTimer( name );
pub.resolveInjectableComponent( parentName, component, resolvedNonReservedDependencies, errRerouter( callback, function( instance ) {
timer.stopTimer( name );
if( component.isTransient ) {
log.debug( 'Resolved transient', name );
store.addUsage( name, parentName );
wrapper.wrap( parentName, name, instance, function( err, wrappedInstance ) {
callback( undefined, wrappedInstance );
} );
}
else {
store.setResolved( name, resolvedComponent.get( instance ) );
while( component.hasWaiting )
setImmediate( component.waiting );
}
} ) );
} ) );
}
}
};
return pub;
};