55 *
66 * @description
77 * Creates an inject function that can be used for dependency injection.
8+ * (See {@link guide.di dependency injection})
9+ *
10+ * The inject function can be used for retrieving service instances or for calling any function
11+ * which has the $inject property so that the services can be automatically provided. Angular
12+ * creates an injection function automatically for the root scope and it is available as
13+ * {@link angular.scope.$service $service}.
814 *
915 * @param {Object= } [providerScope={}] provider's `this`
1016 * @param {Object.<string, function()>= } [providers=angular.service] Map of provider (factory)
1117 * function.
1218 * @param {Object.<string, function()>= } [cache={}] Place where instances are saved for reuse. Can
1319 * also be used to override services speciafied by `providers` (useful in tests).
14- * @returns {function() } Injector function.
20+ * @returns
21+ * {function() } Injector function: `function(value, scope, args...)`:
22+ *
23+ * * `value` - `{string|array|function}`
24+ * * `scope(optional=rootScope)` - optional function "`this`" when `value` is type `function`.
25+ * * `args(optional)` - optional set of arguments to pass to function after injection arguments.
26+ * (also known as curry arguments or currying).
27+ *
28+ * #Return value of `function(value, scope, args...)`
29+ * The injector function return value depended on the type of `value` argument:
30+ *
31+ * * `string`: return an instance for the injection key.
32+ * * `array` of keys: returns an array of instances for those keys. (see `string` above.)
33+ * * `function`: look at `$inject` property of function to determine instances to inject
34+ * and then call the function with instances and `scope`. Any additional arguments
35+ * (`args`) are appended to the function arguments.
36+ * * `none`: initialize eager providers.
1537 *
16- * @TODO These docs need a lot of work. Specifically the returned function should be described in
17- * great detail + we need to provide some examples.
1838 */
1939function createInjector ( providerScope , providers , cache ) {
2040 providers = providers || angularService ;
2141 cache = cache || { } ;
2242 providerScope = providerScope || { } ;
23- /**
24- * injection function
25- * @param value: string, array, object or function.
26- * @param scope: optional function "this"
27- * @param args: optional arguments to pass to function after injection
28- * parameters
29- * @returns depends on value:
30- * string: return an instance for the injection key.
31- * array of keys: returns an array of instances.
32- * function: look at $inject property of function to determine instances
33- * and then call the function with instances and `scope`. Any
34- * additional arguments (`args`) are appended to the function
35- * arguments.
36- * object: initialize eager providers and publish them the ones with publish here.
37- * none: same as object but use providerScope as place to publish.
38- */
3943 return function inject ( value , scope , args ) {
4044 var returnValue , provider ;
4145 if ( isString ( value ) ) {
@@ -51,7 +55,7 @@ function createInjector(providerScope, providers, cache) {
5155 returnValue . push ( inject ( name ) ) ;
5256 } ) ;
5357 } else if ( isFunction ( value ) ) {
54- returnValue = inject ( value . $inject || [ ] ) ;
58+ returnValue = inject ( injectionArgs ( value ) ) ;
5559 returnValue = value . apply ( scope , concat ( returnValue , arguments , 2 ) ) ;
5660 } else if ( isObject ( value ) ) {
5761 forEach ( providers , function ( provider , name ) {
@@ -80,3 +84,33 @@ function injectUpdateView(fn) {
8084function angularServiceInject ( name , fn , inject , eager ) {
8185 angularService ( name , fn , { $inject :inject , $eager :eager } ) ;
8286}
87+
88+
89+ /**
90+ * @returns the $inject property of function. If not found the
91+ * the $inject is computed by looking at the toString of function and
92+ * extracting all arguments which start with $ or end with _ as the
93+ * injection names.
94+ */
95+ var FN_ARGS = / ^ f u n c t i o n [ ^ \( ] * \( ( [ ^ \) ] * ) \) / ;
96+ var FN_ARG_SPLIT = / , / ;
97+ var FN_ARG = / ^ \s * ( ( ( \$ ? ) .+ ?) ( _ ? ) ) \s * $ / ;
98+ var STRIP_COMMENTS = / ( ( \/ \/ .* $ ) | ( \/ \* [ \s \S ] * ?\* \/ ) ) / mg;
99+ function injectionArgs ( fn ) {
100+ assertArgFn ( fn ) ;
101+ if ( ! fn . $inject ) {
102+ var args = fn . $inject = [ ] ;
103+ var fnText = fn . toString ( ) . replace ( STRIP_COMMENTS , '' ) ;
104+ var argDecl = fnText . match ( FN_ARGS ) ;
105+ forEach ( argDecl [ 1 ] . split ( FN_ARG_SPLIT ) , function ( arg ) {
106+ arg . replace ( FN_ARG , function ( all , name , injectName , $ , _ ) {
107+ assertArg ( args , name , 'after non-injectable arg' ) ;
108+ if ( $ || _ )
109+ args . push ( injectName ) ;
110+ else
111+ args = null ; // once we reach an argument which is not injectable then ignore
112+ } ) ;
113+ } ) ;
114+ }
115+ return fn . $inject ;
116+ } ;
0 commit comments