Skip to content

Commit

Permalink
update rules to new rule format (requires eslint >= 2.10)
Browse files Browse the repository at this point in the history
  • Loading branch information
ganimomer committed Oct 9, 2016
1 parent 47be916 commit ef228f0
Show file tree
Hide file tree
Showing 38 changed files with 1,277 additions and 1,085 deletions.
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -23,7 +23,7 @@
"homepage": "https://github.com/wix/eslint-plugin-lodash",
"bugs": "https://github.com/wix/eslint-plugin-lodash/issues",
"peerDependencies": {
"eslint": ">=1.3.0"
"eslint": ">=2.10.0"
},
"dependencies": {
"lodash": "^4.0.0"
Expand Down
49 changes: 27 additions & 22 deletions src/rules/callback-binding.js
Expand Up @@ -3,36 +3,41 @@
*/
'use strict'

/**
* @fileoverview Rule to disallow the use of a chain for a single method
*/
// ------------------------------------------------------------------------------
// Rule Definition
// ------------------------------------------------------------------------------

module.exports = function (context) {
const {getLodashMethodVisitor, isCallToMethod} = require('../util/lodashUtil')
const {getMethodName} = require('../util/astUtil')
const settings = require('../util/settingsUtil').getSettings(context)
const transformerMethods = ['reduce', 'reduceRight', 'transform']
module.exports = {
create(context) {
const {getLodashMethodVisitor, isCallToMethod} = require('../util/lodashUtil')
const {getMethodName} = require('../util/astUtil')
const settings = require('../util/settingsUtil').getSettings(context)
const transformerMethods = ['reduce', 'reduceRight', 'transform']

function isBound(node) {
return node && node.type === 'CallExpression' && getMethodName(node) === 'bind' && node.arguments.length === 1
}
function isBound(node) {
return node && node.type === 'CallExpression' && getMethodName(node) === 'bind' && node.arguments.length === 1
}

const callExpressionReporters = {
3(node, iteratee) {
if (isBound(iteratee)) {
context.report(iteratee.callee.property, 'Unnecessary bind, pass `thisArg` to lodash method instead')
}
},
4(node, iteratee) {
const isTransformerMethod = transformerMethods.some(isCallToMethod.bind(null, node, settings.version))
const iterateeIndex = node.arguments.indexOf(iteratee)
if (iterateeIndex !== -1 && (isTransformerMethod && node.arguments[iterateeIndex + 2] || (!isTransformerMethod && node.arguments[iterateeIndex + 1]))) {
context.report(iteratee, 'Do not use Lodash 3 thisArg, use binding instead')
const callExpressionReporters = {
3(node, iteratee) {
if (isBound(iteratee)) {
context.report(iteratee.callee.property, 'Unnecessary bind, pass `thisArg` to lodash method instead')
}
},
4(node, iteratee) {
const isTransformerMethod = transformerMethods.some(isCallToMethod.bind(null, node, settings.version))
const iterateeIndex = node.arguments.indexOf(iteratee)
if (iterateeIndex !== -1 && (isTransformerMethod && node.arguments[iterateeIndex + 2] || (!isTransformerMethod && node.arguments[iterateeIndex + 1]))) {
context.report(iteratee, 'Do not use Lodash 3 thisArg, use binding instead')
}
}
}
}

return {
CallExpression: getLodashMethodVisitor(settings, callExpressionReporters[settings.version])
return {
CallExpression: getLodashMethodVisitor(settings, callExpressionReporters[settings.version])
}
}
}
75 changes: 40 additions & 35 deletions src/rules/chain-style.js
Expand Up @@ -3,48 +3,53 @@
*/
'use strict'

/**
* @fileoverview Rule to enforce a specific chain style
*/
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
module.exports = function (context) {
const {isChainable, isChainBreaker, isExplicitChainStart, isImplicitChainStart} = require('../util/lodashUtil')
const {isMethodCall} = require('../util/astUtil')
const settings = require('../util/settingsUtil').getSettings(context)
const callExpressionVisitors = {
'as-needed'(node) {
if (isExplicitChainStart(node, settings.pragma)) {
let curr = node.parent.parent
let needed = false
while (isMethodCall(curr) && !isChainBreaker(curr, settings.version)) {
if (!isChainable(curr, settings.version) && !isChainBreaker(curr.parent.parent, settings.version)) {
needed = true
module.exports = {
meta: {
schema: [{
enum: ['as-needed', 'implicit', 'explicit']
}]
},

create(context) {
const {isChainable, isChainBreaker, isExplicitChainStart, isImplicitChainStart} = require('../util/lodashUtil')
const {isMethodCall} = require('../util/astUtil')
const settings = require('../util/settingsUtil').getSettings(context)
const callExpressionVisitors = {
'as-needed'(node) {
if (isExplicitChainStart(node, settings.pragma)) {
let curr = node.parent.parent
let needed = false
while (isMethodCall(curr) && !isChainBreaker(curr, settings.version)) {
if (!isChainable(curr, settings.version) && !isChainBreaker(curr.parent.parent, settings.version)) {
needed = true
}
curr = curr.parent.parent
}
if (isMethodCall(curr) && !needed) {
context.report(node, 'Unnecessary explicit chaining')
}
curr = curr.parent.parent
}
if (isMethodCall(curr) && !needed) {
context.report(node, 'Unnecessary explicit chaining')
},
implicit(node) {
if (isExplicitChainStart(node, settings.pragma)) {
context.report(node, 'Do not use explicit chaining')
}
},
explicit(node) {
if (isImplicitChainStart(node, settings.pragma)) {
context.report(node, 'Do not use implicit chaining')
}
}
},
implicit(node) {
if (isExplicitChainStart(node, settings.pragma)) {
context.report(node, 'Do not use explicit chaining')
}
},
explicit(node) {
if (isImplicitChainStart(node, settings.pragma)) {
context.report(node, 'Do not use implicit chaining')
}
}
}

return {
CallExpression: callExpressionVisitors[context.options[0] || 'as-needed']
}
}

module.exports.schema = [
{
enum: ['as-needed', 'implicit', 'explicit']
return {
CallExpression: callExpressionVisitors[context.options[0] || 'as-needed']
}
}
]
}
73 changes: 39 additions & 34 deletions src/rules/collection-method-value.js
Expand Up @@ -3,49 +3,54 @@
*/
'use strict'

/**
* @fileoverview Rule to enforce usage of collection method values
*/
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
module.exports = function (context) {
const {
isChainBreaker,
isLodashCollectionMethod,
isCallToMethod,
isSideEffectIterationMethod,
isLodashCall,
isLodashChainStart
} = require('../util/lodashUtil')
const {getMethodName, isMethodCall} = require('../util/astUtil')
const settings = require('../util/settingsUtil').getSettings(context)
module.exports = {
create(context) {
const {
isChainBreaker,
isLodashCollectionMethod,
isCallToMethod,
isSideEffectIterationMethod,
isLodashCall,
isLodashChainStart
} = require('../util/lodashUtil')
const {getMethodName, isMethodCall} = require('../util/astUtil')
const settings = require('../util/settingsUtil').getSettings(context)

function parentUsesValue(node, isChain) {
const isBeforeChainBreaker = isChain && isChainBreaker(node.parent.parent, settings.version)
return (isBeforeChainBreaker ? node.parent.parent : node).parent.type !== 'ExpressionStatement'
}

function isPureLodashCollectionMethod(node) {
return isLodashCollectionMethod(node, settings.version) && !isCallToMethod(node, settings.version, 'remove')
}
function parentUsesValue(node, isChain) {
const isBeforeChainBreaker = isChain && isChainBreaker(node.parent.parent, settings.version)
return (isBeforeChainBreaker ? node.parent.parent : node).parent.type !== 'ExpressionStatement'
}

function reportIfMisused(node, isChain) {
if (isPureLodashCollectionMethod(node) && !parentUsesValue(node, isChain)) {
context.report(node, `Use value returned from _.${getMethodName(node)}`)
} else if (isSideEffectIterationMethod(node, settings.version) && parentUsesValue(node, isChain)) {
context.report(node, `Do not use value returned from _.${getMethodName(node)}`)
function isPureLodashCollectionMethod(node) {
return isLodashCollectionMethod(node, settings.version) && !isCallToMethod(node, settings.version, 'remove')
}
}

return {
CallExpression(node) {
if (isLodashCall(node, settings.pragma)) {
reportIfMisused(node, false)
function reportIfMisused(node, isChain) {
if (isPureLodashCollectionMethod(node) && !parentUsesValue(node, isChain)) {
context.report(node, `Use value returned from _.${getMethodName(node)}`)
} else if (isSideEffectIterationMethod(node, settings.version) && parentUsesValue(node, isChain)) {
context.report(node, `Do not use value returned from _.${getMethodName(node)}`)
}
if (isLodashChainStart(node, settings.pragma)) {
let curr = node
while (isMethodCall(curr.parent.parent) && !isChainBreaker(curr.parent.parent, settings.version)) {
curr = curr.parent.parent
}

return {
CallExpression(node) {
if (isLodashCall(node, settings.pragma)) {
reportIfMisused(node, false)
}
if (isLodashChainStart(node, settings.pragma)) {
let curr = node
while (isMethodCall(curr.parent.parent) && !isChainBreaker(curr.parent.parent, settings.version)) {
curr = curr.parent.parent
}
reportIfMisused(curr, true)
}
reportIfMisused(curr, true)
}
}
}
Expand Down
83 changes: 44 additions & 39 deletions src/rules/collection-return.js
Expand Up @@ -3,55 +3,60 @@
*/
'use strict'

/**
* @fileoverview Rule to check that iteratees for all collection functions except forEach return a value;
*/
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

module.exports = function (context) {
const [last, get] = ['last', 'get'].map(m => require(`lodash/${m}`))
const {getMethodName} = require('../util/astUtil')
const {isLodashCollectionMethod, isLodashCall, isLodashWrapper} = require('../util/lodashUtil')
const settings = require('../util/settingsUtil').getSettings(context)
const callStack = []
module.exports = {
create(context) {
const [last, get] = ['last', 'get'].map(m => require(`lodash/${m}`))
const {getMethodName} = require('../util/astUtil')
const {isLodashCollectionMethod, isLodashCall, isLodashWrapper} = require('../util/lodashUtil')
const settings = require('../util/settingsUtil').getSettings(context)
const callStack = []

function handleExitOfFunctionWithBlock(node) {
const functionNode = callStack.pop()
const lastItem = last(callStack)
if (!functionNode.found && get(lastItem, 'node.type') === 'CallExpression') {
context.report(node, `Do not use _.${getMethodName(lastItem.node)} without returning a value`)
}
if (lastItem && lastItem.node === node.parent) {
callStack.pop()
function handleExitOfFunctionWithBlock(node) {
const functionNode = callStack.pop()
const lastItem = last(callStack)
if (!functionNode.found && get(lastItem, 'node.type') === 'CallExpression') {
context.report(node, `Do not use _.${getMethodName(lastItem.node)} without returning a value`)
}
if (lastItem && lastItem.node === node.parent) {
callStack.pop()
}
}
}
function addToCallStackIfCollectionMethod(node) {
if (isLodashCollectionMethod(node, settings.version) &&
(isLodashCall(node, settings.pragma) || isLodashWrapper(node, settings.pragma, settings.version))) {
callStack.push({node})
function addToCallStackIfCollectionMethod(node) {
if (isLodashCollectionMethod(node, settings.version) &&
(isLodashCall(node, settings.pragma) || isLodashWrapper(node, settings.pragma, settings.version))) {
callStack.push({node})
}
}
}

return {
FunctionExpression(node) {
addToCallStackIfCollectionMethod(node.parent)
callStack.push({node, found: false})
},
'FunctionExpression:exit': handleExitOfFunctionWithBlock,
ArrowFunctionExpression(node) {
if (node.body.type === 'BlockStatement') {
return {
FunctionExpression(node) {
addToCallStackIfCollectionMethod(node.parent)
callStack.push({node, found: false})
}
},
'ArrowFunctionExpression:exit'(node) {
if (node.body.type === 'BlockStatement') {
handleExitOfFunctionWithBlock(node)
}
},
ReturnStatement() {
const lastItem = last(callStack)
if (lastItem) {
lastItem.found = true
},
'FunctionExpression:exit': handleExitOfFunctionWithBlock,
ArrowFunctionExpression(node) {
if (node.body.type === 'BlockStatement') {
addToCallStackIfCollectionMethod(node.parent)
callStack.push({node, found: false})
}
},
'ArrowFunctionExpression:exit'(node) {
if (node.body.type === 'BlockStatement') {
handleExitOfFunctionWithBlock(node)
}
},
ReturnStatement() {
const lastItem = last(callStack)
if (lastItem) {
lastItem.found = true
}
}
}
}
Expand Down

0 comments on commit ef228f0

Please sign in to comment.