@@ -42,19 +42,32 @@ var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
42
42
var FN_ARG_SPLIT = / , / ;
43
43
var FN_ARG = / ^ \s * ( _ ? ) ( .+ ?) \1\s * $ / ;
44
44
var STRIP_COMMENTS = / ( ( \/ \/ .* $ ) | ( \/ \* [ \s \S ] * ?\* \/ ) ) / mg;
45
- function inferInjectionArgs ( fn ) {
46
- assertArgFn ( fn ) ;
47
- if ( ! fn . $inject ) {
48
- var args = fn . $inject = [ ] ;
49
- var fnText = fn . toString ( ) . replace ( STRIP_COMMENTS , '' ) ;
50
- var argDecl = fnText . match ( FN_ARGS ) ;
51
- forEach ( argDecl [ 1 ] . split ( FN_ARG_SPLIT ) , function ( arg ) {
52
- arg . replace ( FN_ARG , function ( all , underscore , name ) {
53
- args . push ( name ) ;
45
+ function annotate ( fn ) {
46
+ var $inject ,
47
+ fnText ,
48
+ argDecl ,
49
+ last ;
50
+
51
+ if ( typeof fn == 'function' ) {
52
+ if ( ! ( $inject = fn . $inject ) ) {
53
+ $inject = [ ] ;
54
+ fnText = fn . toString ( ) . replace ( STRIP_COMMENTS , '' ) ;
55
+ argDecl = fnText . match ( FN_ARGS ) ;
56
+ forEach ( argDecl [ 1 ] . split ( FN_ARG_SPLIT ) , function ( arg ) {
57
+ arg . replace ( FN_ARG , function ( all , underscore , name ) {
58
+ $inject . push ( name ) ;
59
+ } ) ;
54
60
} ) ;
55
- } ) ;
61
+ fn . $inject = $inject ;
62
+ }
63
+ } else if ( isArray ( fn ) ) {
64
+ last = fn . length - 1 ;
65
+ assertArgFn ( fn [ last ] , 'fn' )
66
+ $inject = fn . slice ( 0 , last ) ;
67
+ } else {
68
+ assertArgFn ( fn , 'fn' , true ) ;
56
69
}
57
- return fn . $inject ;
70
+ return $inject ;
58
71
}
59
72
60
73
///////////////////////////////////////
@@ -152,6 +165,87 @@ function inferInjectionArgs(fn) {
152
165
* @returns {Object } new instance of `Type`.
153
166
*/
154
167
168
+ /**
169
+ * @ngdoc method
170
+ * @name angular.module.AUTO.$injector#annotate
171
+ * @methodOf angular.module.AUTO.$injector
172
+ *
173
+ * @description
174
+ * Returns an array of service names which the function is requesting for injection. This API is used by the injector
175
+ * to determine which services need to be injected into the function when the function is invoked. There are three
176
+ * ways in which the function can be annotated with the needed dependencies.
177
+ *
178
+ * # Argument names
179
+ *
180
+ * The simplest form is to extract the dependencies from the arguments of the function. This is done by converting
181
+ * the function into a string using `toString()` method and extracting the argument names.
182
+ * <pre>
183
+ * // Given
184
+ * function MyController($scope, $route) {
185
+ * // ...
186
+ * }
187
+ *
188
+ * // Then
189
+ * expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
190
+ * </pre>
191
+ *
192
+ * This method does not work with code minfication / obfuscation. For this reason the following annotation strategies
193
+ * are supported.
194
+ *
195
+ * # The `$injector` property
196
+ *
197
+ * If a function has an `$inject` property and its value is an array of strings, then the strings represent names of
198
+ * services to be injected into the function.
199
+ * <pre>
200
+ * // Given
201
+ * var MyController = function(obfuscatedScope, obfuscatedRoute) {
202
+ * // ...
203
+ * }
204
+ * // Define function dependencies
205
+ * MyController.$inject = ['$scope', '$route'];
206
+ *
207
+ * // Then
208
+ * expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
209
+ * </pre>
210
+ *
211
+ * # The array notation
212
+ *
213
+ * It is often desirable to inline Injected functions and that's when setting the `$inject` property is very
214
+ * inconvenient. In these situations using the array notation to specify the dependencies in a way that survives
215
+ * minification is a better choice:
216
+ *
217
+ * <pre>
218
+ * // We wish to write this (not minification / obfuscation safe)
219
+ * injector.invoke(function($compile, $rootScope) {
220
+ * // ...
221
+ * });
222
+ *
223
+ * // We are forced to write break inlining
224
+ * var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) {
225
+ * // ...
226
+ * };
227
+ * tmpFn.$inject = ['$compile', '$rootScope'];
228
+ * injector.invoke(tempFn);
229
+ *
230
+ * // To better support inline function the inline annotation is supported
231
+ * injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
232
+ * // ...
233
+ * }]);
234
+ *
235
+ * // Therefore
236
+ * expect(injector.annotate(
237
+ * ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])
238
+ * ).toEqual(['$compile', '$rootScope']);
239
+ * </pre>
240
+ *
241
+ * @param {function|Array.<string|Function> } fn Function for which dependent service names need to be retrieved as described
242
+ * above.
243
+ *
244
+ * @returns {Array.<string> } The names of the services which the function requires.
245
+ */
246
+
247
+
248
+
155
249
156
250
/**
157
251
* @ngdoc object
@@ -454,30 +548,23 @@ function createInjector(modulesToLoad) {
454
548
455
549
function invoke ( fn , self , locals ) {
456
550
var args = [ ] ,
457
- $inject ,
458
- length ,
551
+ $inject = annotate ( fn ) ,
552
+ length , i ,
459
553
key ;
460
554
461
- if ( typeof fn == 'function' ) {
462
- $inject = inferInjectionArgs ( fn ) ;
463
- length = $inject . length ;
464
- } else {
465
- if ( isArray ( fn ) ) {
466
- $inject = fn ;
467
- length = $inject . length - 1 ;
468
- fn = $inject [ length ] ;
469
- }
470
- assertArgFn ( fn , 'fn' ) ;
471
- }
472
-
473
- for ( var i = 0 ; i < length ; i ++ ) {
555
+ for ( i = 0 , length = $inject . length ; i < length ; i ++ ) {
474
556
key = $inject [ i ] ;
475
557
args . push (
476
558
locals && locals . hasOwnProperty ( key )
477
559
? locals [ key ]
478
560
: getService ( key , path )
479
561
) ;
480
562
}
563
+ if ( ! fn . $inject ) {
564
+ // this means that we must be an array.
565
+ fn = fn [ length ] ;
566
+ }
567
+
481
568
482
569
// Performance optimization: http://jsperf.com/apply-vs-call-vs-invoke
483
570
switch ( self ? - 1 : args . length ) {
@@ -510,7 +597,8 @@ function createInjector(modulesToLoad) {
510
597
return {
511
598
invoke : invoke ,
512
599
instantiate : instantiate ,
513
- get : getService
600
+ get : getService ,
601
+ annotate : annotate
514
602
} ;
515
603
}
516
604
}
0 commit comments