diff --git a/rules/definedundefined.js b/rules/definedundefined.js index e747a9ed..8005cf27 100644 --- a/rules/definedundefined.js +++ b/rules/definedundefined.js @@ -9,7 +9,17 @@ */ 'use strict'; +var utils = require('./utils/utils'); + + module.exports = function(context) { + function isCompareOperator(operator) { + return operator === '===' || operator === '!==' || operator === '==' || operator === '!='; + } + function reportError(node) { + context.report(node, 'You should not use directly the "undefined" keyword. Prefer ' + + 'angular.isUndefined or angular.isDefined', {}); + } /** * Rule that check if we use angular.is(Un)defined() instead of the undefined keyword */ @@ -27,15 +37,15 @@ module.exports = function(context) { } }, BinaryExpression: function(node) { - if (node.operator === '===' || node.operator === '!==') { - if (node.left.type === 'Identifier' && node.left.name === 'undefined') { - context.report(node, 'You should not use directly the "undefined" keyword. Prefer ' + - 'angular.isUndefined or angular.isDefined', {}); - } - - if (node.right.type === 'Identifier' && node.right.name === 'undefined') { - context.report(node, 'You should not use directly the "undefined" keyword. Prefer ' + - 'angular.isUndefined or angular.isDefined', {}); + if (isCompareOperator(node.operator)) { + if (utils.isTypeOfStatement(node.left) && node.right.value === 'undefined') { + reportError(node); + } else if (utils.isTypeOfStatement(node.right) && node.left.value === 'undefined') { + reportError(node); + } else if (node.left.type === 'Identifier' && node.left.name === 'undefined') { + reportError(node); + } else if (node.right.type === 'Identifier' && node.right.name === 'undefined') { + reportError(node); } } } diff --git a/test/definedundefined.js b/test/definedundefined.js index 4a6710fd..f3e1cc4a 100644 --- a/test/definedundefined.js +++ b/test/definedundefined.js @@ -16,13 +16,26 @@ var eslintTester = new RuleTester(); eslintTester.run('definedundefined', rule, { valid: [ 'angular.isUndefined(toto)', - 'angular.isDefined(toto)' + 'angular.isDefined(toto)', + // possible false positives + 'variable === otherValue', + 'variable === null', + 'variable > undefined', + 'angular.isString(null)' ].concat(commonFalsePositives), invalid: [ {code: 'variable === undefined', errors: [{message: 'You should not use directly the "undefined" keyword. Prefer angular.isUndefined or angular.isDefined'}]}, {code: 'undefined === variable', errors: [{message: 'You should not use directly the "undefined" keyword. Prefer angular.isUndefined or angular.isDefined'}]}, {code: 'undefined !== variable', errors: [{message: 'You should not use directly the "undefined" keyword. Prefer angular.isUndefined or angular.isDefined'}]}, {code: 'variable !== undefined', errors: [{message: 'You should not use directly the "undefined" keyword. Prefer angular.isUndefined or angular.isDefined'}]}, + {code: 'variable == undefined', errors: [{message: 'You should not use directly the "undefined" keyword. Prefer angular.isUndefined or angular.isDefined'}]}, + {code: 'undefined == variable', errors: [{message: 'You should not use directly the "undefined" keyword. Prefer angular.isUndefined or angular.isDefined'}]}, + {code: 'undefined != variable', errors: [{message: 'You should not use directly the "undefined" keyword. Prefer angular.isUndefined or angular.isDefined'}]}, + {code: 'variable != undefined', errors: [{message: 'You should not use directly the "undefined" keyword. Prefer angular.isUndefined or angular.isDefined'}]}, + {code: 'typeof variable === "undefined"', errors: [{message: 'You should not use directly the "undefined" keyword. Prefer angular.isUndefined or angular.isDefined'}]}, + {code: 'typeof variable !== "undefined"', errors: [{message: 'You should not use directly the "undefined" keyword. Prefer angular.isUndefined or angular.isDefined'}]}, + {code: '"undefined" == typeof variable', errors: [{message: 'You should not use directly the "undefined" keyword. Prefer angular.isUndefined or angular.isDefined'}]}, + {code: '"undefined" != typeof variable', errors: [{message: 'You should not use directly the "undefined" keyword. Prefer angular.isUndefined or angular.isDefined'}]}, {code: '!angular.isUndefined(variable)', errors: [{message: 'Instead of !angular.isUndefined, you can use the out-of-box angular.isDefined method'}]}, {code: '!angular.isDefined(variable)', errors: [{message: 'Instead of !angular.isDefined, you can use the out-of-box angular.isUndefined method'}]} ]