4
4
* @function
5
5
*
6
6
* @description
7
- * Creates an inject function that can be used for dependency injection.
8
- * (See {@link guide.di dependency injection})
7
+ * Creates an injector function that can be used for retrieving services as well as for
8
+ * dependency injection (see {@link guide.di dependency injection}).
9
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}.
10
+ * Angular creates an injector automatically for the root scope and it is available as the
11
+ * {@link angular.scope.$service $service} property. Creation of the injector automatically creates
12
+ * all of the `$eager` {@link angular.service services}.
14
13
*
15
- * @param {Object= } [providerScope ={}] provider's `this`
16
- * @param {Object.<string, function()>= } [providers =angular.service] Map of provider ( factory)
17
- * function .
18
- * @param {Object.<string, function()>= } [cache ={}] Place where instances are saved for reuse. Can
19
- * also be used to override services speciafied by `providers` (useful in tests).
20
- * @returns
21
- * {function() } Injector function: `function(value, scope, args...)` :
14
+ * @param {Object= } [factoryScope ={}] `this` for the service factory function.
15
+ * @param {Object.<string, function()>= } [factories =angular.service] Map of service factory
16
+ * functions .
17
+ * @param {Object.<string, function()>= } [instanceCache ={}] Place where instances of services are
18
+ * saved for reuse. Can also be used to override services specified by `serviceFactory`
19
+ * (useful in tests).
20
+ * @returns {function() } Injector function:
22
21
*
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).
22
+ * * `injector(serviceName)`:
23
+ * * `serviceName` - `{string=}` - name of the service to retrieve.
27
24
*
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.
25
+ * The injector function also has these properties:
37
26
*
27
+ * * an `invoke` property which can be used to invoke methods with dependency-injected arguments.
28
+ * `injector.invoke(self, fn, curryArgs)`
29
+ * * `self` - "`this`" to be used when invoking the function.
30
+ * * `fn` - the function to be invoked. The function may have the `$inject` property which
31
+ * lists the set of arguments which should be auto injected
32
+ * (see {@link guide.di dependency injection}).
33
+ * * `curryArgs(array)` - optional array of arguments to pass to function invocation after the
34
+ * injection arguments (also known as curry arguments or currying).
35
+ * * an `eager` property which is used to initialize the eager services.
36
+ * `injector.eager()`
38
37
*/
39
- function createInjector ( providerScope , providers , cache ) {
40
- providers = providers || angularService ;
41
- cache = cache || { } ;
42
- providerScope = providerScope || { } ;
43
- return function inject ( value , scope , args ) {
44
- var returnValue , provider ;
45
- if ( isString ( value ) ) {
46
- if ( ! ( value in cache ) ) {
47
- provider = providers [ value ] ;
48
- if ( ! provider ) throw "Unknown provider for '" + value + "'." ;
49
- cache [ value ] = inject ( provider , providerScope ) ;
50
- }
51
- returnValue = cache [ value ] ;
52
- } else if ( isArray ( value ) ) {
53
- returnValue = [ ] ;
54
- forEach ( value , function ( name ) {
55
- returnValue . push ( inject ( name ) ) ;
56
- } ) ;
57
- } else if ( isFunction ( value ) ) {
58
- returnValue = inject ( injectionArgs ( value ) ) ;
59
- returnValue = value . apply ( scope , concat ( returnValue , arguments , 2 ) ) ;
60
- } else if ( isObject ( value ) ) {
61
- forEach ( providers , function ( provider , name ) {
62
- if ( provider . $eager )
63
- inject ( name ) ;
38
+ function createInjector ( factoryScope , factories , instanceCache ) {
39
+ factories = factories || angularService ;
40
+ instanceCache = instanceCache || { } ;
41
+ factoryScope = factoryScope || { } ;
42
+ injector . invoke = invoke ;
64
43
65
- if ( provider . $creation )
66
- throw new Error ( "Failed to register service '" + name +
67
- "': $creation property is unsupported. Use $eager:true or see release notes." ) ;
68
- } ) ;
69
- } else {
70
- returnValue = inject ( providerScope ) ;
44
+ injector . eager = function ( ) {
45
+ forEach ( factories , function ( factory , name ) {
46
+ if ( factory . $eager )
47
+ injector ( name ) ;
48
+
49
+ if ( factory . $creation )
50
+ throw new Error ( "Failed to register service '" + name +
51
+ "': $creation property is unsupported. Use $eager:true or see release notes." ) ;
52
+ } ) ;
53
+ } ;
54
+ return injector ;
55
+
56
+ function injector ( value ) {
57
+ if ( ! ( value in instanceCache ) ) {
58
+ var factory = factories [ value ] ;
59
+ if ( ! factory ) throw Error ( "Unknown provider for '" + value + "'." ) ;
60
+ instanceCache [ value ] = invoke ( factoryScope , factory ) ;
71
61
}
72
- return returnValue ;
62
+ return instanceCache [ value ] ;
73
63
} ;
74
- }
75
64
76
- function injectService ( services , fn ) {
77
- return extend ( fn , { $inject :services } ) ;
65
+ function invoke ( self , fn , args ) {
66
+ args = args || [ ] ;
67
+ var injectNames = injectionArgs ( fn ) ;
68
+ var i = injectNames . length ;
69
+ while ( i -- ) {
70
+ args . unshift ( injector ( injectNames [ i ] ) ) ;
71
+ }
72
+ return fn . apply ( self , args ) ;
73
+ }
78
74
}
79
75
80
- function injectUpdateView ( fn ) {
81
- return injectService ( [ '$updateView' ] , fn ) ;
76
+ /**
77
+ * @ngdoc function
78
+ * @name angular.annotate
79
+ * @function
80
+ *
81
+ * @description
82
+ * Annotate the function with injection arguments. This is equivalent to setting the `$inject`
83
+ * property as described in {@link guide.di dependency injection}.
84
+ *
85
+ * <pre>
86
+ * var MyController = angular.annotate('$location', function($location){ ... });
87
+ * </pre>
88
+ *
89
+ * is the same as
90
+ *
91
+ * <pre>
92
+ * var MyController = function($location){ ... };
93
+ * MyController.$inject = ['$location'];
94
+ * </pre>
95
+ *
96
+ * @param {String|Array } serviceName... zero or more service names to inject into the
97
+ * `annotatedFunction`.
98
+ * @param {function } annotatedFunction function to annotate with `$inject`
99
+ * functions.
100
+ * @returns {function } `annotatedFunction`
101
+ */
102
+ function annotate ( services , fn ) {
103
+ if ( services instanceof Array ) {
104
+ fn . $inject = services ;
105
+ return fn ;
106
+ } else {
107
+ var i = 0 ,
108
+ length = arguments . length - 1 , // last one is the destination function
109
+ $inject = arguments [ length ] . $inject = [ ] ;
110
+ for ( ; i < length ; i ++ ) {
111
+ $inject . push ( arguments [ i ] ) ;
112
+ }
113
+ return arguments [ length ] ; // return the last one
114
+ }
82
115
}
83
116
84
117
function angularServiceInject ( name , fn , inject , eager ) {
@@ -89,12 +122,12 @@ function angularServiceInject(name, fn, inject, eager) {
89
122
/**
90
123
* @returns the $inject property of function. If not found the
91
124
* the $inject is computed by looking at the toString of function and
92
- * extracting all arguments which start with $ or end with _ as the
125
+ * extracting all arguments which and assuming that they are the
93
126
* injection names.
94
127
*/
95
128
var FN_ARGS = / ^ f u n c t i o n \s * [ ^ \( ] * \( ( [ ^ \) ] * ) \) / ;
96
129
var FN_ARG_SPLIT = / , / ;
97
- var FN_ARG = / ^ \s * ( ( ( \$ ? ) .+ ?) ( _ ? ) ) \s * $ / ;
130
+ var FN_ARG = / ^ \s * ( .+ ?) \s * $ / ;
98
131
var STRIP_COMMENTS = / ( ( \/ \/ .* $ ) | ( \/ \* [ \s \S ] * ?\* \/ ) ) / mg;
99
132
function injectionArgs ( fn ) {
100
133
assertArgFn ( fn ) ;
@@ -103,12 +136,8 @@ function injectionArgs(fn) {
103
136
var fnText = fn . toString ( ) . replace ( STRIP_COMMENTS , '' ) ;
104
137
var argDecl = fnText . match ( FN_ARGS ) ;
105
138
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
139
+ arg . replace ( FN_ARG , function ( all , name ) {
140
+ args . push ( name ) ;
112
141
} ) ;
113
142
} ) ;
114
143
}
0 commit comments