Skip to content

Commit 38038e9

Browse files
committed
fix($parse): treat falsy values as defined in assignment expressions
Closes angular#14990
1 parent 1660ddd commit 38038e9

File tree

2 files changed

+36
-4
lines changed

2 files changed

+36
-4
lines changed

src/ng/parse.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -1042,7 +1042,7 @@ ASTCompiler.prototype = {
10421042
self.if_(self.stage === 'inputs' || 's', function() {
10431043
if (create && create !== 1) {
10441044
self.if_(
1045-
self.not(self.nonComputedMember('s', ast.name)),
1045+
self.isNull(self.nonComputedMember('s', ast.name)),
10461046
self.lazyAssign(self.nonComputedMember('s', ast.name), '{}'));
10471047
}
10481048
self.assign(intoId, self.nonComputedMember('s', ast.name));
@@ -1079,7 +1079,7 @@ ASTCompiler.prototype = {
10791079
} else {
10801080
ensureSafeMemberName(ast.property.name);
10811081
if (create && create !== 1) {
1082-
self.if_(self.not(self.nonComputedMember(left, ast.property.name)), self.lazyAssign(self.nonComputedMember(left, ast.property.name), '{}'));
1082+
self.if_(self.isNull(self.nonComputedMember(left, ast.property.name)), self.lazyAssign(self.nonComputedMember(left, ast.property.name), '{}'));
10831083
}
10841084
expression = self.nonComputedMember(left, ast.property.name);
10851085
if (self.state.expensiveChecks || isPossiblyDangerousMemberName(ast.property.name)) {
@@ -1274,6 +1274,10 @@ ASTCompiler.prototype = {
12741274
return '!(' + expression + ')';
12751275
},
12761276

1277+
isNull: function(expression) {
1278+
return expression + '==null';
1279+
},
1280+
12771281
notNull: function(expression) {
12781282
return expression + '!=null';
12791283
},

test/ng/parseSpec.js

+30-2
Original file line numberDiff line numberDiff line change
@@ -3059,7 +3059,7 @@ describe('parser', function() {
30593059
// foo.constructor is not a constructor.
30603060
expect(function() {
30613061
delete scope.foo;
3062-
scope.$eval('foo.constructor[0] = ""', {foo: {constructor: ''}});
3062+
scope.$eval('foo.constructor[0] = ""', {foo: {constructor: {}}});
30633063
}).not.toThrow();
30643064

30653065
expect(function() {
@@ -3176,7 +3176,7 @@ describe('parser', function() {
31763176
// foo.constructor.prototype is not a constructor prototype.
31773177
expect(function() {
31783178
delete scope.foo;
3179-
scope.$eval('foo.constructor.prototype[0] = ""', {foo: {constructor: {prototype: ''}}});
3179+
scope.$eval('foo.constructor.prototype[0] = ""', {foo: {constructor: {prototype: {}}}});
31803180
}).not.toThrow();
31813181
});
31823182
});
@@ -3900,6 +3900,34 @@ describe('parser', function() {
39003900
expect(isFunction(s.toString)).toBe(true);
39013901
expect(l.toString).toBe(1);
39023902
}));
3903+
3904+
it('should assign a property to locals properties with null or undefined value', inject(function($parse) {
3905+
var local = {a:null};
3906+
$parse("a.b =1")(local);
3907+
expect(local.a).toEqual({b:1});
3908+
3909+
local.a = undefined;
3910+
$parse("a.b =1")(local);
3911+
expect(local.a).toEqual({b:1});
3912+
}));
3913+
3914+
it('should not assign a property to locals properties with falsy value', inject(function($parse) {
3915+
var local = {a:0};
3916+
3917+
expect(function() {
3918+
$parse("a.b =1")(local);
3919+
}).toThrow();
3920+
3921+
local.a = false;
3922+
expect(function() {
3923+
$parse("a.b =1")(local);
3924+
}).toThrow();
3925+
3926+
local.a = '';
3927+
expect(function() {
3928+
$parse("a.b =1")(local);
3929+
}).toThrow();
3930+
}));
39033931
});
39043932

39053933
describe('literal', function() {

0 commit comments

Comments
 (0)