Skip to content

Commit

Permalink
explicit-length-check: Check Boolean(foo.length) (#951)
Browse files Browse the repository at this point in the history
  • Loading branch information
fisker committed Dec 23, 2020
1 parent 582ca34 commit f4577f7
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 6 deletions.
4 changes: 4 additions & 0 deletions docs/rules/explicit-length-check.md
Expand Up @@ -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);
Expand Down
32 changes: 27 additions & 5 deletions rules/explicit-length-check.js
Expand Up @@ -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 &&
Expand Down Expand Up @@ -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};
Expand Down Expand Up @@ -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;
}

Expand Down
11 changes: 10 additions & 1 deletion test/explicit-length-check.js
Expand Up @@ -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) {}',
Expand Down Expand Up @@ -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))'
]);
96 changes: 96 additions & 0 deletions test/snapshots/explicit-length-check.js.md
Expand Up @@ -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.␊
`
Binary file modified test/snapshots/explicit-length-check.js.snap
Binary file not shown.

0 comments on commit f4577f7

Please sign in to comment.