diff --git a/docs/rules/explicit-length-check.md b/docs/rules/explicit-length-check.md index 5e197cc830..1ac2d77ede 100644 --- a/docs/rules/explicit-length-check.md +++ b/docs/rules/explicit-length-check.md @@ -79,6 +79,10 @@ const isNotEmpty = 0 < foo.length; const isNotEmpty = 1 <= foo.length; ``` +```js +const isNotEmpty = Boolean(foo.length); +``` + ```js // Negative style is forbidden too const isNotEmpty = !(foo.length === 0); diff --git a/rules/explicit-length-check.js b/rules/explicit-length-check.js index 621285221d..9dd6178ae6 100644 --- a/rules/explicit-length-check.js +++ b/rules/explicit-length-check.js @@ -11,12 +11,22 @@ const messages = { }; const isLogicNot = node => + node && node.type === 'UnaryExpression' && node.operator === '!'; const isLogicNotArgument = node => - node.parent && isLogicNot(node.parent) && node.parent.argument === node; +const isBooleanCall = node => + node && + node.type === 'CallExpression' && + node.callee && + node.callee.type === 'Identifier' && + node.callee.name === 'Boolean' && + node.arguments.length === 1; +const isBooleanCallArgument = node => + isBooleanCall(node.parent) && + node.parent.arguments[0] === node; const isCompareRight = (node, operator, value) => node.type === 'BinaryExpression' && node.operator === operator && @@ -62,9 +72,16 @@ const lengthSelector = [ function getBooleanAncestor(node) { let isNegative = false; - while (isLogicNotArgument(node)) { - isNegative = !isNegative; - node = node.parent; + // eslint-disable-next-line no-constant-condition + while (true) { + if (isLogicNotArgument(node)) { + isNegative = !isNegative; + node = node.parent; + } else if (isBooleanCallArgument(node)) { + node = node.parent; + } else { + break; + } } return {node, isNegative}; @@ -117,7 +134,12 @@ function getLengthCheckNode(node) { } function isBooleanNode(node) { - if (isLogicNot(node) || isLogicNotArgument(node)) { + if ( + isLogicNot(node) || + isLogicNotArgument(node) || + isBooleanCall(node) || + isBooleanCallArgument(node) + ) { return true; } diff --git a/test/explicit-length-check.js b/test/explicit-length-check.js index 2132be3b08..a82c0035fc 100644 --- a/test/explicit-length-check.js +++ b/test/explicit-length-check.js @@ -39,6 +39,9 @@ test({ // Not boolean 'const bar = foo.length', 'const bar = +foo.length', + 'const x = Boolean(foo.length, foo.length)', + 'const x = new Boolean(foo.length)', + 'const x = NotBoolean(foo.length)', // Checking 'non-zero' 'if (foo.length > 0) {}', @@ -119,5 +122,11 @@ test.visualize([ 'const isEmpty = foo.length < 1;', 'bar(foo.length >= 1)', 'bar(!foo.length || foo.length)', - 'const bar = void !foo.length;' + 'const bar = void !foo.length;', + 'const isNotEmpty = Boolean(foo.length)', + 'const isNotEmpty = Boolean(foo.length || bar)', + 'const isEmpty = Boolean(!foo.length)', + 'const isEmpty = Boolean(foo.length === 0)', + 'const isNotEmpty = !Boolean(foo.length === 0)', + 'const isEmpty = !Boolean(!Boolean(foo.length === 0))' ]); diff --git a/test/snapshots/explicit-length-check.js.md b/test/snapshots/explicit-length-check.js.md index 8df8ea337e..9d9b383f10 100644 --- a/test/snapshots/explicit-length-check.js.md +++ b/test/snapshots/explicit-length-check.js.md @@ -891,3 +891,99 @@ Generated by [AVA](https://avajs.dev). > 1 | const bar = void !foo.length;␊ | ^^^^^^^^^^^ Use `.length === 0` when checking length is zero.␊ ` + +## explicit-length-check - #15 + +> Snapshot 1 + + `␊ + Input:␊ + 1 | const isNotEmpty = Boolean(foo.length)␊ + ␊ + Output:␊ + 1 | const isNotEmpty = foo.length > 0␊ + ␊ + Error 1/1:␊ + > 1 | const isNotEmpty = Boolean(foo.length)␊ + | ^^^^^^^^^^^^^^^^^^^ Use `.length > 0` when checking length is not zero.␊ + ` + +## explicit-length-check - #16 + +> Snapshot 1 + + `␊ + Input:␊ + 1 | const isNotEmpty = Boolean(foo.length || bar)␊ + ␊ + Output:␊ + 1 | const isNotEmpty = Boolean(foo.length > 0 || bar)␊ + ␊ + Error 1/1:␊ + > 1 | const isNotEmpty = Boolean(foo.length || bar)␊ + | ^^^^^^^^^^ Use `.length > 0` when checking length is not zero.␊ + ` + +## explicit-length-check - #17 + +> Snapshot 1 + + `␊ + Input:␊ + 1 | const isEmpty = Boolean(!foo.length)␊ + ␊ + Output:␊ + 1 | const isEmpty = foo.length === 0␊ + ␊ + Error 1/1:␊ + > 1 | const isEmpty = Boolean(!foo.length)␊ + | ^^^^^^^^^^^^^^^^^^^^ Use `.length === 0` when checking length is zero.␊ + ` + +## explicit-length-check - #18 + +> Snapshot 1 + + `␊ + Input:␊ + 1 | const isEmpty = Boolean(foo.length === 0)␊ + ␊ + Output:␊ + 1 | const isEmpty = foo.length === 0␊ + ␊ + Error 1/1:␊ + > 1 | const isEmpty = Boolean(foo.length === 0)␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ Use `.length === 0` when checking length is zero.␊ + ` + +## explicit-length-check - #19 + +> Snapshot 1 + + `␊ + Input:␊ + 1 | const isNotEmpty = !Boolean(foo.length === 0)␊ + ␊ + Output:␊ + 1 | const isNotEmpty = foo.length > 0␊ + ␊ + Error 1/1:␊ + > 1 | const isNotEmpty = !Boolean(foo.length === 0)␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `.length > 0` when checking length is not zero.␊ + ` + +## explicit-length-check - #20 + +> Snapshot 1 + + `␊ + Input:␊ + 1 | const isEmpty = !Boolean(!Boolean(foo.length === 0))␊ + ␊ + Output:␊ + 1 | const isEmpty = foo.length === 0␊ + ␊ + Error 1/1:␊ + > 1 | const isEmpty = !Boolean(!Boolean(foo.length === 0))␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `.length === 0` when checking length is zero.␊ + ` diff --git a/test/snapshots/explicit-length-check.js.snap b/test/snapshots/explicit-length-check.js.snap index be74734502..da87f52b4a 100644 Binary files a/test/snapshots/explicit-length-check.js.snap and b/test/snapshots/explicit-length-check.js.snap differ