Skip to content
This repository was archived by the owner on Apr 4, 2025. It is now read-only.

Commit 73a3195

Browse files
erwinmombaySomeKittens
authored andcommitted
fix(events): fix parser to handle ternary expressions
1 parent 0b98cfa commit 73a3195

File tree

3 files changed

+59
-32
lines changed

3 files changed

+59
-32
lines changed

dist/hint.js

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1210,7 +1210,7 @@ var getFunctionNames = function(str) {
12101210
// To fully fix these issues we would need a full blown expression parser.
12111211
var results = removeStringExp(str.replace(/\s+/g, ''))
12121212
.replace(/\(.*?\)/g, '')
1213-
.split(/[\+\-\/\|\<\>\^=&!%~;]/g).map(function(x) {
1213+
.split(/[\+\-\/\|\<\>\^=&!%~?:;]/g).map(function(x) {
12141214
if (isNaN(+x)) {
12151215
if (x.match(/\w+\(.*\)$/)){
12161216
return x.substr(0, x.indexOf('('));
@@ -1246,22 +1246,31 @@ function ngEventDirectivesDecorator(ngEventAttrName) {
12461246

12471247
return function ngEventHandler(scope, element, attrs) {
12481248
var boundFuncs = getFunctionNames(attrs[ngEventAttrName]);
1249-
boundFuncs.forEach(function(boundFn) {
1250-
var property, propChain, lastProp = '';
1251-
while((property = boundFn.match(/^.+?([^\.\[])*/)) !== null) {
1252-
property = property[0];
1253-
propChain = lastProp + property;
1254-
if ($parse(propChain)(scope) === undefined) {
1255-
angular.hint.emit(MODULE_NAME + ':undef', propChain + ' is undefined');
1256-
}
1257-
boundFn = boundFn.replace(property, '');
1258-
lastProp += property;
1259-
if(boundFn.charAt(0) === '.') {
1260-
lastProp += '.';
1261-
boundFn = boundFn.substr(1);
1249+
1250+
// guard against any parsing errors since the parsing code
1251+
// to split the expression is pretty simple and naive.
1252+
try {
1253+
boundFuncs.forEach(function(boundFn) {
1254+
var property, propChain, lastProp = '';
1255+
while((property = boundFn.match(/^.+?([^\.\[])*/)) !== null) {
1256+
property = property[0];
1257+
propChain = lastProp + property;
1258+
if ($parse(propChain)(scope) === undefined) {
1259+
angular.hint.emit(MODULE_NAME + ':undef', propChain + ' is undefined');
1260+
}
1261+
boundFn = boundFn.replace(property, '');
1262+
lastProp += property;
1263+
if(boundFn.charAt(0) === '.') {
1264+
lastProp += '.';
1265+
boundFn = boundFn.substr(1);
1266+
}
12621267
}
1263-
}
1264-
});
1268+
});
1269+
} catch (e) {
1270+
angular.hint.emit(MODULE_NAME + ':undef', '' +
1271+
'parsing error: please inform the angular-hint ' +
1272+
'or batarang teams. expression: ' + boundFuncs.join(''));
1273+
}
12651274

12661275
return linkFn.apply(this, arguments);
12671276
};

src/modules/events.js

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ var getFunctionNames = function(str) {
3636
// To fully fix these issues we would need a full blown expression parser.
3737
var results = removeStringExp(str.replace(/\s+/g, ''))
3838
.replace(/\(.*?\)/g, '')
39-
.split(/[\+\-\/\|\<\>\^=&!%~;]/g).map(function(x) {
39+
.split(/[\+\-\/\|\<\>\^=&!%~?:;]/g).map(function(x) {
4040
if (isNaN(+x)) {
4141
if (x.match(/\w+\(.*\)$/)){
4242
return x.substr(0, x.indexOf('('));
@@ -72,22 +72,31 @@ function ngEventDirectivesDecorator(ngEventAttrName) {
7272

7373
return function ngEventHandler(scope, element, attrs) {
7474
var boundFuncs = getFunctionNames(attrs[ngEventAttrName]);
75-
boundFuncs.forEach(function(boundFn) {
76-
var property, propChain, lastProp = '';
77-
while((property = boundFn.match(/^.+?([^\.\[])*/)) !== null) {
78-
property = property[0];
79-
propChain = lastProp + property;
80-
if ($parse(propChain)(scope) === undefined) {
81-
angular.hint.emit(MODULE_NAME + ':undef', propChain + ' is undefined');
82-
}
83-
boundFn = boundFn.replace(property, '');
84-
lastProp += property;
85-
if(boundFn.charAt(0) === '.') {
86-
lastProp += '.';
87-
boundFn = boundFn.substr(1);
75+
76+
// guard against any parsing errors since the parsing code
77+
// to split the expression is pretty simple and naive.
78+
try {
79+
boundFuncs.forEach(function(boundFn) {
80+
var property, propChain, lastProp = '';
81+
while((property = boundFn.match(/^.+?([^\.\[])*/)) !== null) {
82+
property = property[0];
83+
propChain = lastProp + property;
84+
if ($parse(propChain)(scope) === undefined) {
85+
angular.hint.emit(MODULE_NAME + ':undef', propChain + ' is undefined');
86+
}
87+
boundFn = boundFn.replace(property, '');
88+
lastProp += property;
89+
if(boundFn.charAt(0) === '.') {
90+
lastProp += '.';
91+
boundFn = boundFn.substr(1);
92+
}
8893
}
89-
}
90-
});
94+
});
95+
} catch (e) {
96+
angular.hint.emit(MODULE_NAME + ':undef', '' +
97+
'parsing error: please inform the angular-hint ' +
98+
'or batarang teams. expression: ' + boundFuncs.join(''));
99+
}
91100

92101
return linkFn.apply(this, arguments);
93102
};

test/events.spec.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,15 @@ describe('hintEvents', function() {
3636
expect(angular.hint.emit).not.toHaveBeenCalledWith();
3737
});
3838

39+
it('should be able to handle ternary expression', function() {
40+
var elt = angular.element('<button ng-click="a.b ? a.b() : a">Fake Increment</button>');
41+
$rootScope.a = {};
42+
$compile(elt)($rootScope);
43+
44+
$rootScope.$digest();
45+
expect(angular.hint.emit).toHaveBeenCalledWith('Events:undef', 'a.b is undefined');
46+
});
47+
3948
it('should be able to handle multiple statements separated by a semi colon', function() {
4049
var elt = angular.element('<button ng-click="a.b.c(); a.b;">Fake Increment</button>');
4150
var spy = jasmine.createSpy();

0 commit comments

Comments
 (0)