Skip to content

Commit 6f0ea45

Browse files
committed
feat(injector): optionally disable automatic function annotation
This modifies the injector to prevent automatic annotation from occurring for a given injector. This works by passing a `true` as the 3rd or 4th parameter to createInjector(), or alternatively to angular.module. ```js angular.module("name", ["dependencies", "otherdeps"], configFn, true) .provider("$willBreak", function() { this.$get = function($rootScope) { }; }) .run(["$willBreak", function($willBreak) { // This block will never run because the noMagic flag was set to true, and the $willBreak // '$get' function does not have an explicit annotation. }]); ``` This will only affect functions with an arity greater than 0, and without an $inject property. Related: angular#6717
1 parent 24a045c commit 6f0ea45

File tree

4 files changed

+66
-7
lines changed

4 files changed

+66
-7
lines changed

src/auto/injector.js

+9-5
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ var FN_ARG_SPLIT = /,/;
6666
var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
6767
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
6868
var $injectorMinErr = minErr('$injector');
69-
function annotate(fn) {
69+
function annotate(fn, noMagic) {
7070
var $inject,
7171
fnText,
7272
argDecl,
@@ -76,6 +76,9 @@ function annotate(fn) {
7676
if (!($inject = fn.$inject)) {
7777
$inject = [];
7878
if (fn.length) {
79+
if (noMagic) {
80+
throw $injectorMinErr('nomagic', '');
81+
}
7982
fnText = fn.toString().replace(STRIP_COMMENTS, '');
8083
argDecl = fnText.match(FN_ARGS);
8184
forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg){
@@ -587,7 +590,8 @@ function annotate(fn) {
587590
*/
588591

589592

590-
function createInjector(modulesToLoad) {
593+
function createInjector(modulesToLoad, noMagic) {
594+
noMagic = (noMagic === true);
591595
var INSTANTIATING = {},
592596
providerSuffix = 'Provider',
593597
path = [],
@@ -605,13 +609,13 @@ function createInjector(modulesToLoad) {
605609
providerInjector = (providerCache.$injector =
606610
createInternalInjector(providerCache, function() {
607611
throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
608-
})),
612+
}, noMagic)),
609613
instanceCache = {},
610614
instanceInjector = (instanceCache.$injector =
611615
createInternalInjector(instanceCache, function(servicename) {
612616
var provider = providerInjector.get(servicename + providerSuffix);
613617
return instanceInjector.invoke(provider.$get, provider);
614-
}));
618+
}, noMagic));
615619

616620

617621
forEach(loadModules(modulesToLoad), function(fn) { instanceInjector.invoke(fn || noop); });
@@ -745,7 +749,7 @@ function createInjector(modulesToLoad) {
745749

746750
function invoke(fn, self, locals){
747751
var args = [],
748-
$inject = annotate(fn),
752+
$inject = annotate(fn, noMagic),
749753
length, i,
750754
key;
751755

src/loader.js

+13-1
Original file line numberDiff line numberDiff line change
@@ -78,14 +78,26 @@ function setupModuleLoader(window) {
7878
* {@link angular.Module#config Module#config()}.
7979
* @returns {module} new module with the {@link angular.Module} api.
8080
*/
81-
return function module(name, requires, configFn) {
81+
return function module(name, requires, configFn, noMagic) {
8282
var assertNotHasOwnProperty = function(name, context) {
8383
if (name === 'hasOwnProperty') {
8484
throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
8585
}
8686
};
8787

8888
assertNotHasOwnProperty(name, 'module');
89+
90+
if (typeof configFn === "boolean") {
91+
noMagic = configFn;
92+
configFn = undefined;
93+
} else if (arguments.length < 4) {
94+
noMagic = false;
95+
}
96+
97+
if (noMagic !== true) {
98+
noMagic = false;
99+
}
100+
89101
if (requires && modules.hasOwnProperty(name)) {
90102
modules[name] = null;
91103
}

src/ngMock/angular-mocks.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -2156,7 +2156,12 @@ if(window.jasmine || window.mocha) {
21562156
modules.unshift('ng');
21572157
var injector = currentSpec.$injector;
21582158
if (!injector) {
2159-
injector = currentSpec.$injector = angular.injector(modules);
2159+
var noMagic = modules.indexOf(true);
2160+
if (noMagic >= 0) {
2161+
modules.splice(noMagic, 1);
2162+
noMagic = true;
2163+
}
2164+
injector = currentSpec.$injector = angular.injector(modules, noMagic);
21602165
}
21612166
for(var i = 0, ii = blockFns.length; i < ii; i++) {
21622167
try {

test/auto/injectorSpec.js

+38
Original file line numberDiff line numberDiff line change
@@ -864,3 +864,41 @@ describe('injector', function() {
864864
});
865865
});
866866
});
867+
868+
describe('$injector noMagic', function() {
869+
it('should throw if magic annotation is used by service', function() {
870+
module(['$provide', function($provide) {
871+
$provide.service({
872+
'$test': function() { return this; },
873+
'$test2': function($test) { return this; }
874+
});
875+
}], true);
876+
expect (function() {
877+
inject(['$test2', function(test2) {}]);
878+
}).toThrowMinErr('$injector', 'nomagic');
879+
});
880+
881+
882+
it('should throw if magic annotation is used by provider', function() {
883+
module(['$provide', function($provide) {
884+
$provide.provider({
885+
'$test': function() { this.$get = function($rootScope) { return $rootScope; }; },
886+
});
887+
}], true);
888+
expect (function() {
889+
inject(['$test', function(test) {}]);
890+
}).toThrowMinErr('$injector', 'nomagic');
891+
});
892+
893+
894+
it('should throw if magic annotation is used by factory', function() {
895+
module(['$provide', function($provide) {
896+
$provide.factory({
897+
'$test': function($rootScope) { return function() {} },
898+
});
899+
}], true);
900+
expect (function() {
901+
inject(['$test', function(test) {}]);
902+
}).toThrowMinErr('$injector', 'nomagic');
903+
});
904+
});

0 commit comments

Comments
 (0)