Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

prefer-set-has: Ignore arrays only checking existence once #706

Merged
merged 6 commits into from May 3, 2020
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
23 changes: 10 additions & 13 deletions docs/rules/prefer-set-has.md
Expand Up @@ -8,28 +8,25 @@ This rule is fixable.

```js
const array = [1, 2, 3];

function hasValue(value) {
return array.includes(value);
}
const hasValue = value => array.includes(value);
```

## Pass

```js
const set = new Set([1, 2, 3]);

function hasValue(value) {
return set.has(value);
}
const hasValue = value => set.has(value);
```

```js
// This array is not only checking existence.
const array = [1, 2];

function hasValue(value) {
return array.includes(value);
}

const hasValue = value => array.includes(value);
array.push(3);
```

```js
// This array is only checked once.
const array = [1, 2, 3];
const hasOne = array.includes(1);
```
38 changes: 37 additions & 1 deletion rules/prefer-set-has.js
Expand Up @@ -107,6 +107,35 @@ const isIncludesCall = node => {
);
};

const multipleCallNodeTypes = new Set([
'ForOfStatement',
'ForStatement',
'WhileStatement',
'DoWhileStatement',
'FunctionDeclaration',
'FunctionExpression',
'ArrowFunctionExpression',
'ObjectMethod',
'ClassMethod'
]);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These types are all I got in mind could call .includes() multiple times. Maybe more from other parser, need feedback.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forgot ForInStatement, added in aaa3638.


const isMultipleCall = (identifier, node) => {
const root = node.parent.parent.parent;
let {parent} = identifier.parent; // `.include()` callExpression
while (
parent &&
parent !== root
) {
if (multipleCallNodeTypes.has(parent.type)) {
return true;
}

parent = parent.parent;
}

return false;
};

const create = context => {
return {
[selector]: node => {
Expand All @@ -115,7 +144,14 @@ const create = context => {

if (
identifiers.length === 0 ||
identifiers.some(node => !isIncludesCall(node))
identifiers.some(identifier => !isIncludesCall(identifier))
) {
return;
}

if (
identifiers.length === 1 &&
identifiers.every(identifier => !isMultipleCall(identifier, node))
Comment on lines +154 to +155
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I use .every() on purpose, we might add option to ignore 2 :)

) {
return;
}
Expand Down