Skip to content

Commit 3dc2f77

Browse files
fiskersindresorhus
andauthored
prefer-array-some: Check cases comparing .find() with undefined (#1422)
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
1 parent d0ed9c0 commit 3dc2f77

File tree

5 files changed

+175
-2
lines changed

5 files changed

+175
-2
lines changed

docs/rules/prefer-array-some.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ We only check `.filter().length > 0` and `.filter().length !== 0`. These two non
88

99
- Using [`Array#find()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find) to ensure at least one element in the array passes a given check.
1010

11+
- Comparing the result of [`Array#find()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find) with `undefined`.
12+
1113
This rule is fixable for `.filter(…).length` check and has a suggestion for `.find(…)`.
1214

1315
## Fail
@@ -34,6 +36,14 @@ if (array.find(element => isUnicorn(element))) {
3436
const foo = array.find(element => isUnicorn(element)) ? bar : baz;
3537
```
3638

39+
```js
40+
const hasUnicorn = array.find(element => isUnicorn(element) !== undefined;
41+
```
42+
43+
```js
44+
const hasUnicorn = array.find(element => isUnicorn(element) != null;
45+
```
46+
3747
```vue
3848
<template>
3949
<div v-if="array.find(element => isUnicorn(element))">Vue</div>

rules/prefer-array-some.js

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const {methodCallSelector, matches, memberExpressionSelector} = require('./selec
33
const {checkVueTemplate} = require('./utils/rule.js');
44
const {isBooleanNode} = require('./utils/boolean.js');
55
const {getParenthesizedRange} = require('./utils/parentheses.js');
6+
const isLiteralValue = require('./utils/is-literal-value.js');
67
const {removeMemberExpressionProperty} = require('./fix/index.js');
78

89
const ERROR_ID_ARRAY_SOME = 'some';
@@ -20,6 +21,31 @@ const arrayFindCallSelector = methodCallSelector({
2021
max: 2,
2122
});
2223

24+
const isCheckingUndefined = node =>
25+
node.parent.type === 'BinaryExpression' &&
26+
// Not checking yoda expression `null != foo.find()` and `undefined !== foo.find()
27+
node.parent.left === node &&
28+
(
29+
(
30+
(
31+
node.parent.operator === '!=' ||
32+
node.parent.operator === '==' ||
33+
node.parent.operator === '===' ||
34+
node.parent.operator === '!=='
35+
) &&
36+
node.parent.right.type === 'Identifier' &&
37+
node.parent.right.name === 'undefined'
38+
) ||
39+
(
40+
(
41+
node.parent.operator === '!=' ||
42+
node.parent.operator === '=='
43+
) &&
44+
// eslint-disable-next-line unicorn/no-null
45+
isLiteralValue(node.parent.right, null)
46+
)
47+
);
48+
2349
const arrayFilterCallSelector = [
2450
'BinaryExpression',
2551
'[right.type="Literal"]',
@@ -35,7 +61,8 @@ const arrayFilterCallSelector = [
3561
const create = context => {
3662
return {
3763
[arrayFindCallSelector](findCall) {
38-
if (!isBooleanNode(findCall)) {
64+
const isCompare = isCheckingUndefined(findCall);
65+
if (!isCompare && !isBooleanNode(findCall)) {
3966
return;
4067
}
4168

@@ -46,7 +73,22 @@ const create = context => {
4673
suggest: [
4774
{
4875
messageId: SUGGESTION_ID_ARRAY_SOME,
49-
fix: fixer => fixer.replaceText(findProperty, 'some'),
76+
* fix(fixer) {
77+
yield fixer.replaceText(findProperty, 'some');
78+
79+
if (!isCompare) {
80+
return;
81+
}
82+
83+
const parenthesizedRange = getParenthesizedRange(findCall, context.getSourceCode());
84+
yield fixer.replaceTextRange([parenthesizedRange[1], findCall.parent.range[1]], '');
85+
86+
if (findCall.parent.operator === '!=' || findCall.parent.operator === '!==') {
87+
return;
88+
}
89+
90+
yield fixer.insertTextBeforeRange(parenthesizedRange, '!');
91+
},
5092
},
5193
],
5294
};

test/prefer-array-some.mjs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,3 +206,26 @@ test.vue({
206206
},
207207
],
208208
});
209+
210+
// Compare with `undefined`
211+
test.snapshot({
212+
valid: [
213+
'foo.find(fn) == 0',
214+
'foo.find(fn) != ""',
215+
'foo.find(fn) === null',
216+
'foo.find(fn) !== "null"',
217+
'foo.find(fn) >= undefined',
218+
'foo.find(fn) instanceof undefined',
219+
// We are not checking this right now
220+
'typeof foo.find(fn) === "undefined"',
221+
],
222+
invalid: [
223+
'foo.find(fn) == null',
224+
'foo.find(fn) == undefined',
225+
'foo.find(fn) === undefined',
226+
'foo.find(fn) != null',
227+
'foo.find(fn) != undefined',
228+
'foo.find(fn) !== undefined',
229+
'a = (( ((foo.find(fn))) == ((null)) )) ? "no" : "yes";',
230+
],
231+
});

test/snapshots/prefer-array-some.mjs.md

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,3 +153,101 @@ Generated by [AVA](https://avajs.dev).
153153
14 | ))␊
154154
15 | );␊
155155
`
156+
157+
## Invalid #1
158+
1 | foo.find(fn) == null
159+
160+
> Error 1/1
161+
162+
`␊
163+
> 1 | foo.find(fn) == null␊
164+
| ^^^^ Prefer \`.some(…)\` over \`.find(…)\`.␊
165+
166+
--------------------------------------------------------------------------------␊
167+
Suggestion 1/1: Replace \`.find(…)\` with \`.some(…)\`.␊
168+
1 | !foo.some(fn)␊
169+
`
170+
171+
## Invalid #2
172+
1 | foo.find(fn) == undefined
173+
174+
> Error 1/1
175+
176+
`␊
177+
> 1 | foo.find(fn) == undefined␊
178+
| ^^^^ Prefer \`.some(…)\` over \`.find(…)\`.␊
179+
180+
--------------------------------------------------------------------------------␊
181+
Suggestion 1/1: Replace \`.find(…)\` with \`.some(…)\`.␊
182+
1 | !foo.some(fn)␊
183+
`
184+
185+
## Invalid #3
186+
1 | foo.find(fn) === undefined
187+
188+
> Error 1/1
189+
190+
`␊
191+
> 1 | foo.find(fn) === undefined␊
192+
| ^^^^ Prefer \`.some(…)\` over \`.find(…)\`.␊
193+
194+
--------------------------------------------------------------------------------␊
195+
Suggestion 1/1: Replace \`.find(…)\` with \`.some(…)\`.␊
196+
1 | !foo.some(fn)␊
197+
`
198+
199+
## Invalid #4
200+
1 | foo.find(fn) != null
201+
202+
> Error 1/1
203+
204+
`␊
205+
> 1 | foo.find(fn) != null␊
206+
| ^^^^ Prefer \`.some(…)\` over \`.find(…)\`.␊
207+
208+
--------------------------------------------------------------------------------␊
209+
Suggestion 1/1: Replace \`.find(…)\` with \`.some(…)\`.␊
210+
1 | foo.some(fn)␊
211+
`
212+
213+
## Invalid #5
214+
1 | foo.find(fn) != undefined
215+
216+
> Error 1/1
217+
218+
`␊
219+
> 1 | foo.find(fn) != undefined␊
220+
| ^^^^ Prefer \`.some(…)\` over \`.find(…)\`.␊
221+
222+
--------------------------------------------------------------------------------␊
223+
Suggestion 1/1: Replace \`.find(…)\` with \`.some(…)\`.␊
224+
1 | foo.some(fn)␊
225+
`
226+
227+
## Invalid #6
228+
1 | foo.find(fn) !== undefined
229+
230+
> Error 1/1
231+
232+
`␊
233+
> 1 | foo.find(fn) !== undefined␊
234+
| ^^^^ Prefer \`.some(…)\` over \`.find(…)\`.␊
235+
236+
--------------------------------------------------------------------------------␊
237+
Suggestion 1/1: Replace \`.find(…)\` with \`.some(…)\`.␊
238+
1 | foo.some(fn)␊
239+
`
240+
241+
## Invalid #7
242+
1 | a = (( ((foo.find(fn))) == ((null)) )) ? "no" : "yes";
243+
244+
> Error 1/1
245+
246+
`␊
247+
> 1 | a = (( ((foo.find(fn))) == ((null)) )) ? "no" : "yes";␊
248+
| ^^^^ Prefer \`.some(…)\` over \`.find(…)\`.␊
249+
250+
--------------------------------------------------------------------------------␊
251+
Suggestion 1/1: Replace \`.find(…)\` with \`.some(…)\`.␊
252+
1 | a = (( !((foo.some(fn))) )) ? "no" : "yes";␊
253+
`
308 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)