Skip to content

Commit 4a2c3f2

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

File tree

2 files changed

+49
-6
lines changed

2 files changed

+49
-6
lines changed

src/ng/parse.js

+8-4
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
},
@@ -1705,7 +1709,7 @@ ASTInterpreter.prototype = {
17051709
identifier: function(name, expensiveChecks, context, create, expression) {
17061710
return function(scope, locals, assign, inputs) {
17071711
var base = locals && (name in locals) ? locals : scope;
1708-
if (create && create !== 1 && base && !(base[name])) {
1712+
if (create && create !== 1 && base && base[name] == null) {
17091713
base[name] = {};
17101714
}
17111715
var value = base ? base[name] : undefined;
@@ -1749,7 +1753,7 @@ ASTInterpreter.prototype = {
17491753
var lhs = left(scope, locals, assign, inputs);
17501754
if (create && create !== 1) {
17511755
ensureSafeAssignContext(lhs);
1752-
if (lhs && !(lhs[right])) {
1756+
if (lhs && lhs[right] == null) {
17531757
lhs[right] = {};
17541758
}
17551759
}

test/ng/parseSpec.js

+41-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,45 @@ 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 scope properties with null or undefined value', inject(function($parse) {
3905+
var scope = {a:null};
3906+
$parse("a.b =1")(scope);
3907+
expect(scope.a).toEqual({b:1});
3908+
3909+
scope.a = undefined;
3910+
$parse("a.b =1")(scope);
3911+
expect(scope.a).toEqual({b:1});
3912+
}));
3913+
3914+
they('should not assign a property to scope properties with $prop value', [0, false, ''],
3915+
function(falsyValue) {
3916+
inject(function($parse) {
3917+
var scope = {a:falsyValue};
3918+
expect(function() {
3919+
$parse("a.b=1")(scope);
3920+
}).toThrow();
3921+
expect(scope.a).toBe(falsyValue);
3922+
3923+
scope = {a:falsyValue};
3924+
expect(function() {
3925+
$parse("a['b']=1")(scope);
3926+
}).toThrow();
3927+
expect(scope.a).toBe(falsyValue);
3928+
3929+
scope = {a:{b:falsyValue}};
3930+
expect(function() {
3931+
$parse("a.b.c=1")(scope);
3932+
}).toThrow();
3933+
expect(scope.a.b).toBe(falsyValue);
3934+
3935+
scope = {a:{b:falsyValue}};
3936+
expect(function() {
3937+
$parse("a.b['c']=1")(scope);
3938+
}).toThrow();
3939+
expect(scope.a.b).toBe(falsyValue);
3940+
});
3941+
});
39033942
});
39043943

39053944
describe('literal', function() {

0 commit comments

Comments
 (0)