eslint-plugin-lodash
Version:
Lodash specific linting rules for ESLint
93 lines (75 loc) • 4.15 kB
JavaScript
/**
* @fileoverview Rule to prefer _.noop over an empty function
*/
;
/**
* @fileoverview Rule to prefer _.noop over an empty function
*/
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
module.exports = {
create: function create(context) {
var _require = require('../util/astUtil');
var isNegationExpression = _require.isNegationExpression;
var isEquivalentMemberExp = _require.isEquivalentMemberExp;
var _require2 = require('../util/lodashUtil');
var isCallToLodashMethod = _require2.isCallToLodashMethod;
var getLodashImportVisitors = _require2.getLodashImportVisitors;
var _require3 = require('../util/ruleUtil');
var combineVisitorObjects = _require3.combineVisitorObjects;
var _ = require('lodash');
var nilChecks = {
null: {
isValue: _.matches({ type: 'Literal', value: null }),
expressionChecks: [getLodashTypeCheckedBy('isNull'), getValueComparedTo('null')]
},
undefined: {
isValue: _.matches({ type: 'Identifier', name: 'undefined' }),
expressionChecks: [getLodashTypeCheckedBy('isUndefined'), getValueComparedTo('undefined'), getValueWithTypeofUndefinedComparison]
}
};
function getLodashTypeCheckedBy(typecheck) {
return function (node) {
return isCallToLodashMethod(node, typecheck, context) && node.arguments[0];
};
}
function getValueComparedTo(nil) {
return function (node, operator) {
return node.type === 'BinaryExpression' && node.operator === operator && (nilChecks[nil].isValue(node.right) && node.left || nilChecks[nil].isValue(node.left) && node.right);
};
}
var getTypeofArgument = _.cond([[_.matches({ type: 'UnaryExpression', operator: 'typeof' }), _.property('argument')]]);
var isUndefinedString = _.matches({ type: 'Literal', value: 'undefined' });
function getValueWithTypeofUndefinedComparison(node, operator) {
return node.type === 'BinaryExpression' && node.operator === operator && (isUndefinedString(node.right) && getTypeofArgument(node.left) || isUndefinedString(node.left) && getTypeofArgument(node.right));
}
function checkExpression(nil, operator, node) {
return _(nilChecks[nil].expressionChecks).map(function (check) {
return check(node, operator);
}).find();
}
function checkNegatedExpression(nil, node) {
return isNegationExpression(node) && checkExpression(nil, '===', node.argument) || checkExpression(nil, '!==', node);
}
function isEquivalentExistingExpression(node, leftNil, rightNil) {
var leftExp = checkExpression(leftNil, '===', node.left);
return leftExp && isEquivalentMemberExp(leftExp, checkExpression(rightNil, '===', node.right));
}
function isEquivalentExistingNegation(node, leftNil, rightNil) {
var leftExp = checkNegatedExpression(leftNil, node.left);
return leftExp && isEquivalentMemberExp(leftExp, checkNegatedExpression(rightNil, node.right));
}
return combineVisitorObjects({
LogicalExpression: function LogicalExpression(node) {
if (node.operator === '||') {
if (isEquivalentExistingExpression(node, 'undefined', 'null') || isEquivalentExistingExpression(node, 'null', 'undefined')) {
context.report(node, 'Prefer isNil over checking for undefined or null.');
}
} else if (isEquivalentExistingNegation(node, 'undefined', 'null') || isEquivalentExistingNegation(node, 'null', 'undefined')) {
context.report(node, 'Prefer isNil over checking for undefined or null.');
}
}
}, getLodashImportVisitors(context));
}
};