mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-03-17 07:40:22 +00:00
156 lines
4.7 KiB
JavaScript
156 lines
4.7 KiB
JavaScript
'use strict';
|
|
|
|
/**
|
|
* @ngdoc function
|
|
* @name angular.injector
|
|
* @function
|
|
*
|
|
* @description
|
|
* Creates an injector function that can be used for retrieving services as well as for
|
|
* dependency injection (see {@link guide/dev_guide.di dependency injection}).
|
|
*
|
|
* Creating an injector doesn't automatically create all of the `$eager`
|
|
* {@link angular.service services}. You have to call `injector.eager()` to initialize them.
|
|
*
|
|
* @param {Object.<string, function()>=} [factories=angular.service] Map of the service factory
|
|
* functions.
|
|
* @returns {function()} Injector function:
|
|
*
|
|
* * `injector(serviceName)`:
|
|
* * `serviceName` - `{string=}` - Name of the service to retrieve.
|
|
*
|
|
* The injector function also has these properties:
|
|
*
|
|
* * An `invoke` property which can be used to invoke methods with dependency-injected arguments.
|
|
* `injector.invoke(self, fn, curryArgs)`
|
|
* * `self` - The "`this`" to be used when invoking the function.
|
|
* * `fn` - The function to be invoked. The function may have the `$inject` property that
|
|
* lists the set of arguments which should be auto-injected.
|
|
* (see {@link guide/dev_guide.di dependency injection}).
|
|
* * `curryArgs(array)` - Optional array of arguments to pass to the function
|
|
* invocation after the injection arguments (also known as curry arguments or currying).
|
|
* * An `eager` property which is used to initialize the eager services.
|
|
* `injector.eager()`
|
|
*/
|
|
function createInjector(factories) {
|
|
var instanceCache = {
|
|
$injector: injector
|
|
};
|
|
factories = factories || angularService;
|
|
|
|
injector.invoke = invoke;
|
|
|
|
forEach(factories, function(factory, name){
|
|
if (factory.$eager)
|
|
injector(name);
|
|
});
|
|
return instanceCache.$injector;
|
|
|
|
function injector(serviceId, path){
|
|
if (typeof serviceId == 'string') {
|
|
if (!(serviceId in instanceCache)) {
|
|
var factory = factories[serviceId];
|
|
path = path || [];
|
|
path.unshift(serviceId);
|
|
if (!factory) throw Error("Unknown provider for '" + path.join("' <- '") + "'.");
|
|
inferInjectionArgs(factory);
|
|
instanceCache[serviceId] = invoke(null, factory, [], path);
|
|
path.shift();
|
|
}
|
|
return instanceCache[serviceId];
|
|
} else {
|
|
return invoke(null, serviceId, path);
|
|
}
|
|
}
|
|
|
|
function invoke(self, fn, args, path){
|
|
args = args || [];
|
|
var injectNames;
|
|
var i;
|
|
if (typeof fn == 'function') {
|
|
injectNames = fn.$inject || [];
|
|
i = injectNames.length;
|
|
} else if (fn instanceof Array) {
|
|
injectNames = fn;
|
|
i = injectNames.length;
|
|
fn = injectNames[--i];
|
|
}
|
|
assertArgFn(fn, 'fn');
|
|
while(i--) {
|
|
args.unshift(injector(injectNames[i], path));
|
|
}
|
|
return fn.apply(self, args);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* THIS IS NOT PUBLIC DOC YET!
|
|
*
|
|
* @name angular.annotate
|
|
* @function
|
|
*
|
|
* @description
|
|
* Annotate the function with injection arguments. This is equivalent to setting the `$inject`
|
|
* property as described in {@link guide.di dependency injection}.
|
|
*
|
|
* <pre>
|
|
* var MyController = angular.annotate('$location', function($location){ ... });
|
|
* </pre>
|
|
*
|
|
* is the same as
|
|
*
|
|
* <pre>
|
|
* var MyController = function($location){ ... };
|
|
* MyController.$inject = ['$location'];
|
|
* </pre>
|
|
*
|
|
* @param {String|Array} serviceName... zero or more service names to inject into the
|
|
* `annotatedFunction`.
|
|
* @param {function} annotatedFunction function to annotate with `$inject`
|
|
* functions.
|
|
* @returns {function} `annotatedFunction`
|
|
*/
|
|
function annotate(services, fn) {
|
|
if (services instanceof Array) {
|
|
fn.$inject = services;
|
|
return fn;
|
|
} else {
|
|
var i = 0,
|
|
length = arguments.length - 1, // last one is the destination function
|
|
$inject = arguments[length].$inject = [];
|
|
for (; i < length; i++) {
|
|
$inject.push(arguments[i]);
|
|
}
|
|
return arguments[length]; // return the last one
|
|
}
|
|
}
|
|
|
|
function angularServiceInject(name, fn, inject, eager) {
|
|
angularService(name, fn, {$inject:inject, $eager:eager});
|
|
}
|
|
|
|
|
|
/**
|
|
* @returns the $inject property of function. If not found the
|
|
* the $inject is computed by looking at the toString of function and
|
|
* extracting all arguments which and assuming that they are the
|
|
* injection names.
|
|
*/
|
|
var FN_ARGS = /^function\s*[^\(]*\(([^\)]*)\)/m;
|
|
var FN_ARG_SPLIT = /,/;
|
|
var FN_ARG = /^\s*(.+?)\s*$/;
|
|
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
|
|
function inferInjectionArgs(fn) {
|
|
assertArgFn(fn);
|
|
if (!fn.$inject) {
|
|
var args = fn.$inject = [];
|
|
var fnText = fn.toString().replace(STRIP_COMMENTS, '');
|
|
var argDecl = fnText.match(FN_ARGS);
|
|
forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg){
|
|
arg.replace(FN_ARG, function(all, name){
|
|
args.push(name);
|
|
});
|
|
});
|
|
}
|
|
return fn.$inject;
|
|
}
|