AngularJS - How does the DI system know of the name of the arguments?
This is the trimmed down version of the way
var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;var FN_ARG_SPLIT = /,/;var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;function annotate(fn){ var $inject if (!($inject = fn.$inject)) { $inject = []; fnText = fn.toString().replace(STRIP_COMMENTS, ''); argDecl = fnText.match(FN_ARGS); angular.forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg){ arg.replace(FN_ARG, function(all, underscore, name){ $inject.push(name); }); }); fn.$inject = $inject; } return fn.$inject;}
Demo: Fiddle(See the console);
Steps:
1. Calling toString
in the function returns the function source
2. Remove all comments using regex
3. Extract the arguments from the source using regex
Straight from the source @GitHub:
The simplest form is to extract the dependencies from the arguments of the function. This is done by converting the function into a string using
toString()
method and extracting the argument names.
// Givenfunction MyController($scope, $route) { // ...}// Thenexpect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
And the annotate function
function annotate(fn) { var $inject, fnText, argDecl, last; if (typeof fn == 'function') { if (!($inject = fn.$inject)) { $inject = []; fnText = fn.toString().replace(STRIP_COMMENTS, ''); argDecl = fnText.match(FN_ARGS); forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg){ arg.replace(FN_ARG, function(all, underscore, name){ $inject.push(name); }); }); fn.$inject = $inject; } } else if (isArray(fn)) { last = fn.length - 1; assertArgFn(fn[last], 'fn') $inject = fn.slice(0, last); } else { assertArgFn(fn, 'fn', true); } return $inject;}
as seen on row 45 and later