mirror of
https://github.com/zhigang1992/angular.js.git
synced 2026-04-24 03:55:49 +08:00
feat(injector): "strict-DI" mode which disables "automatic" function annotation
This modifies the injector to prevent automatic annotation from occurring for a given injector.
This behaviour can be enabled when bootstrapping the application by using the attribute
"ng-strict-di" on the root element (the element containing "ng-app"), or alternatively by passing
an object with the property "strictDi" set to "true" in angular.bootstrap, when bootstrapping
manually.
JS example:
angular.module("name", ["dependencies", "otherdeps"])
.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.
}]);
angular.bootstrap(document, ["name"], {
strictDi: true
});
HTML:
<html ng-app="name" ng-strict-di>
<!-- ... -->
</html>
This will only affect functions with an arity greater than 0, and without an $inject property.
Closes #6719
Closes #6717
Closes #4504
Closes #6069
Closes #3611
This commit is contained in:
@@ -687,7 +687,7 @@ describe('angular', function() {
|
||||
var appElement = jqLite('<div ng-app="ABC"></div>')[0];
|
||||
element.querySelectorAll['[ng-app]'] = [appElement];
|
||||
angularInit(element, bootstrapSpy);
|
||||
expect(bootstrapSpy).toHaveBeenCalledOnceWith(appElement, ['ABC']);
|
||||
expect(bootstrapSpy).toHaveBeenCalledOnceWith(appElement, ['ABC'], jasmine.any(Object));
|
||||
});
|
||||
|
||||
|
||||
@@ -695,7 +695,7 @@ describe('angular', function() {
|
||||
var appElement = jqLite('<div id="ng-app" data-ng-app="ABC"></div>')[0];
|
||||
jqLite(document.body).append(appElement);
|
||||
angularInit(element, bootstrapSpy);
|
||||
expect(bootstrapSpy).toHaveBeenCalledOnceWith(appElement, ['ABC']);
|
||||
expect(bootstrapSpy).toHaveBeenCalledOnceWith(appElement, ['ABC'], jasmine.any(Object));
|
||||
});
|
||||
|
||||
|
||||
@@ -703,7 +703,7 @@ describe('angular', function() {
|
||||
var appElement = jqLite('<div data-ng-app="ABC"></div>')[0];
|
||||
element.querySelectorAll['.ng\\:app'] = [appElement];
|
||||
angularInit(element, bootstrapSpy);
|
||||
expect(bootstrapSpy).toHaveBeenCalledOnceWith(appElement, ['ABC']);
|
||||
expect(bootstrapSpy).toHaveBeenCalledOnceWith(appElement, ['ABC'], jasmine.any(Object));
|
||||
});
|
||||
|
||||
|
||||
@@ -711,14 +711,14 @@ describe('angular', function() {
|
||||
var appElement = jqLite('<div x-ng-app="ABC"></div>')[0];
|
||||
element.querySelectorAll['[ng\\:app]'] = [ appElement ];
|
||||
angularInit(element, bootstrapSpy);
|
||||
expect(bootstrapSpy).toHaveBeenCalledOnceWith(appElement, ['ABC']);
|
||||
expect(bootstrapSpy).toHaveBeenCalledOnceWith(appElement, ['ABC'], jasmine.any(Object));
|
||||
});
|
||||
|
||||
|
||||
it('should bootstrap using class name', function() {
|
||||
var appElement = jqLite('<div class="ng-app: ABC;"></div>')[0];
|
||||
angularInit(jqLite('<div></div>').append(appElement)[0], bootstrapSpy);
|
||||
expect(bootstrapSpy).toHaveBeenCalledOnceWith(appElement, ['ABC']);
|
||||
expect(bootstrapSpy).toHaveBeenCalledOnceWith(appElement, ['ABC'], jasmine.any(Object));
|
||||
});
|
||||
|
||||
|
||||
@@ -726,21 +726,21 @@ describe('angular', function() {
|
||||
var appElement = jqLite('<div x-ng-app></div>')[0];
|
||||
element.querySelectorAll['[x-ng-app]'] = [ appElement ];
|
||||
angularInit(element, bootstrapSpy);
|
||||
expect(bootstrapSpy).toHaveBeenCalledOnceWith(appElement, []);
|
||||
expect(bootstrapSpy).toHaveBeenCalledOnceWith(appElement, [], jasmine.any(Object));
|
||||
});
|
||||
|
||||
|
||||
it('should bootstrap anonymously using class only', function() {
|
||||
var appElement = jqLite('<div class="ng-app"></div>')[0];
|
||||
angularInit(jqLite('<div></div>').append(appElement)[0], bootstrapSpy);
|
||||
expect(bootstrapSpy).toHaveBeenCalledOnceWith(appElement, []);
|
||||
expect(bootstrapSpy).toHaveBeenCalledOnceWith(appElement, [], jasmine.any(Object));
|
||||
});
|
||||
|
||||
|
||||
it('should bootstrap if the annotation is on the root element', function() {
|
||||
var appElement = jqLite('<div class="ng-app"></div>')[0];
|
||||
angularInit(appElement, bootstrapSpy);
|
||||
expect(bootstrapSpy).toHaveBeenCalledOnceWith(appElement, []);
|
||||
expect(bootstrapSpy).toHaveBeenCalledOnceWith(appElement, [], jasmine.any(Object));
|
||||
});
|
||||
|
||||
|
||||
@@ -778,7 +778,24 @@ describe('angular', function() {
|
||||
);
|
||||
|
||||
dealoc(document);
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
it('should bootstrap in strict mode when ng-strict-di attribute is specified', function() {
|
||||
bootstrapSpy = spyOn(angular, 'bootstrap').andCallThrough();
|
||||
var appElement = jqLite('<div class="ng-app" ng-strict-di></div>');
|
||||
angularInit(jqLite('<div></div>').append(appElement[0])[0], bootstrapSpy);
|
||||
expect(bootstrapSpy).toHaveBeenCalledOnce();
|
||||
expect(bootstrapSpy.mostRecentCall.args[2].strictDi).toBe(true);
|
||||
|
||||
var injector = appElement.injector();
|
||||
function testFactory($rootScope) {};
|
||||
expect(function() {
|
||||
injector.instantiate(testFactory);
|
||||
}).toThrowMinErr('$injector', 'strictdi');
|
||||
|
||||
dealoc(appElement);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -864,3 +864,69 @@ describe('injector', function() {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('strict-di injector', function() {
|
||||
beforeEach(inject.strictDi(true));
|
||||
|
||||
describe('with ngMock', function() {
|
||||
it('should not throw when calling mock.module() with "magic" annotations', function() {
|
||||
expect(function() {
|
||||
module(function($provide, $httpProvider, $compileProvider) {
|
||||
// Don't throw!
|
||||
});
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
|
||||
it('should not throw when calling mock.inject() with "magic" annotations', function() {
|
||||
expect(function() {
|
||||
inject(function($rootScope, $compile, $http) {
|
||||
// Don't throw!
|
||||
});
|
||||
}).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should throw if magic annotation is used by service', function() {
|
||||
module(function($provide) {
|
||||
$provide.service({
|
||||
'$test': function() { return this; },
|
||||
'$test2': function($test) { return this; }
|
||||
});
|
||||
});
|
||||
inject(function($injector) {
|
||||
expect (function() {
|
||||
$injector.invoke(function($test2) {});
|
||||
}).toThrowMinErr('$injector', 'strictdi');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should throw if magic annotation is used by provider', function() {
|
||||
module(function($provide) {
|
||||
$provide.provider({
|
||||
'$test': function() { this.$get = function($rootScope) { return $rootScope; }; },
|
||||
});
|
||||
});
|
||||
inject(function($injector) {
|
||||
expect (function() {
|
||||
$injector.invoke(['$test', function($test) {}]);
|
||||
}).toThrowMinErr('$injector', 'strictdi');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should throw if magic annotation is used by factory', function() {
|
||||
module(function($provide) {
|
||||
$provide.factory({
|
||||
'$test': function($rootScope) { return function() {} },
|
||||
});
|
||||
});
|
||||
inject(function($injector) {
|
||||
expect(function() {
|
||||
$injector.invoke(['$test', function(test) {}]);
|
||||
}).toThrowMinErr('$injector', 'strictdi');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user