'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}). * * Angular creates an injector automatically for the root scope and it is available as the * {@link angular.scope.$service $service} property. 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=} [factoryScope={}] The `this` for the service factory function. * @param {Object.=} [factories=angular.service] Map of the service factory * functions. * @param {Object.=} [instanceCache={}] Place where instances of services are * saved for reuse. Can also be used to override services specified by `serviceFactory` * (useful in tests). * @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(factoryScope, factories, instanceCache) { factories = factories || angularService; instanceCache = instanceCache || {}; factoryScope = factoryScope || {}; injector.invoke = invoke; injector.eager = function() { forEach(factories, function(factory, name){ if (factory.$eager) injector(name); if (factory.$creation) throw new Error("Failed to register service '" + name + "': $creation property is unsupported. Use $eager:true or see release notes."); }); }; return injector; function injector(value){ if (!(value in instanceCache)) { var factory = factories[value]; if (!factory) throw Error("Unknown provider for '"+value+"'."); inferInjectionArgs(factory); instanceCache[value] = invoke(factoryScope, factory); } return instanceCache[value]; } function invoke(self, fn, args){ args = args || []; var injectNames = fn.$inject || []; var i = injectNames.length; while(i--) { args.unshift(injector(injectNames[i])); } 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}. * *
 * var MyController = angular.annotate('$location', function($location){ ... });
 * 
* * is the same as * *
 * var MyController = function($location){ ... };
 * MyController.$inject = ['$location'];
 * 
* * @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; }