Skip to content

Commit

Permalink
prefer-array-index-of: Prefer .lastIndexOf() over `.findLastIndex…
Browse files Browse the repository at this point in the history
…()` (#1896)
  • Loading branch information
fisker authored Sep 19, 2022
1 parent e5faebc commit 70e5bdd
Show file tree
Hide file tree
Showing 7 changed files with 327 additions and 12 deletions.
53 changes: 51 additions & 2 deletions docs/rules/prefer-array-index-of.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Prefer `Array#indexOf()` over `Array#findIndex()` when looking for the index of an item
# Prefer `Array#{indexOf,lastIndexOf}()` over `Array#{findIndex,findLastIndex}()` when looking for the index of an item

<!-- Do not manually modify RULE_NOTICE part. Run: `npm run generate-rule-notices` -->
<!-- RULE_NOTICE -->
Expand All @@ -7,7 +7,7 @@
🔧💡 *This rule is [auto-fixable](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) and provides [suggestions](https://eslint.org/docs/developer-guide/working-with-rules#providing-suggestions).*
<!-- /RULE_NOTICE -->

[`Array#findIndex()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex) is intended for more complex needs. If you are just looking for the index where the given item is present, then the code can be simplified to use [`Array#indexOf()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf). This applies to any search with a literal, a variable, or any expression that doesn't have any explicit side effects. However, if the expression you are looking for relies on an item related to the function (its arguments, the function self, etc.), the case is still valid.
[`Array#findIndex()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex) and [`Array#findLastIndex()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findLastIndex) are intended for more complex needs. If you are just looking for the index where the given item is present, then the code can be simplified to use [`Array#indexOf()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf) or [`Array#lastIndexOf()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/lastIndexOf) . This applies to any search with a literal, a variable, or any expression that doesn't have any explicit side effects. However, if the expression you are looking for relies on an item related to the function (its arguments, the function self, etc.), the case is still valid.

This rule is fixable, unless the search expression has side effects.

Expand All @@ -27,6 +27,20 @@ const index = foo.findIndex(x => {
});
```

```js
const index = foo.findLastIndex(x => x === 'foo');
```

```js
const index = foo.findLastIndex(x => 'foo' === x);
```

```js
const index = foo.findLastIndex(x => {
return x === 'foo';
});
```

## Pass

```js
Expand Down Expand Up @@ -63,3 +77,38 @@ const index = foo.findIndex(x => {
return x === bar;
});
```

```js
const index = foo.lastIndexOf('foo');
```

```js
const index = foo.findLastIndex(x => x == undefined);
```

```js
const index = foo.findLastIndex(x => x !== 'foo');
```

```js
const index = foo.findLastIndex((x, index) => x === index);
```

```js
const index = foo.findLastIndex(x => (x === 'foo') && isValid());
```

```js
const index = foo.findLastIndex(x => y === 'foo');
```

```js
const index = foo.findLastIndex(x => y.x === 'foo');
```

```js
const index = foo.findLastIndex(x => {
const bar = getBar();
return x === bar;
});
```
2 changes: 1 addition & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ Each rule has emojis denoting:
| [prefer-array-find](docs/rules/prefer-array-find.md) | Prefer `.find(…)` over the first element from `.filter(…)`. || 🔧 | 💡 |
| [prefer-array-flat](docs/rules/prefer-array-flat.md) | Prefer `Array#flat()` over legacy techniques to flatten arrays. || 🔧 | |
| [prefer-array-flat-map](docs/rules/prefer-array-flat-map.md) | Prefer `.flatMap(…)` over `.map(…).flat()`. || 🔧 | |
| [prefer-array-index-of](docs/rules/prefer-array-index-of.md) | Prefer `Array#indexOf()` over `Array#findIndex()` when looking for the index of an item. || 🔧 | 💡 |
| [prefer-array-index-of](docs/rules/prefer-array-index-of.md) | Prefer `Array#{indexOf,lastIndexOf}()` over `Array#{findIndex,findLastIndex}()` when looking for the index of an item. || 🔧 | 💡 |
| [prefer-array-some](docs/rules/prefer-array-some.md) | Prefer `.some(…)` over `.filter(…).length` check and `.{find,findLast}(…)`. || 🔧 | 💡 |
| [prefer-at](docs/rules/prefer-at.md) | Prefer `.at()` method for index access and `String#charAt()`. | | 🔧 | 💡 |
| [prefer-code-point](docs/rules/prefer-code-point.md) | Prefer `String#codePointAt(…)` over `String#charCodeAt(…)` and `String.fromCodePoint(…)` over `String.fromCharCode(…)`. || | 💡 |
Expand Down
19 changes: 15 additions & 4 deletions rules/prefer-array-index-of.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,32 @@
'use strict';
const simpleArraySearchRule = require('./shared/simple-array-search-rule.js');

const {messages, createListeners} = simpleArraySearchRule({
const indexOfOverFindIndexRule = simpleArraySearchRule({
method: 'findIndex',
replacement: 'indexOf',
});

const lastIndexOfOverFindLastIndexRule = simpleArraySearchRule({
method: 'findLastIndex',
replacement: 'lastIndexOf',
});

/** @type {import('eslint').Rule.RuleModule} */
module.exports = {
create: context => createListeners(context),
create: context => ({
...indexOfOverFindIndexRule.createListeners(context),
...lastIndexOfOverFindLastIndexRule.createListeners(context),
}),
meta: {
type: 'suggestion',
docs: {
description: 'Prefer `Array#indexOf()` over `Array#findIndex()` when looking for the index of an item.',
description: 'Prefer `Array#{indexOf,lastIndexOf}()` over `Array#{findIndex,findLastIndex}()` when looking for the index of an item.',
},
fixable: 'code',
hasSuggestions: true,
messages,
messages: {
...indexOfOverFindIndexRule.messages,
...lastIndexOfOverFindLastIndexRule.messages,
},
},
};
16 changes: 12 additions & 4 deletions test/prefer-array-index-of.mjs
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
import {getTester} from './utils/test.mjs';
import tests from './shared/simple-array-search-rule-tests.mjs';
import createSimpleArraySearchRuleTestFixtures from './shared/simple-array-search-rule-tests.mjs';

const {test} = getTester(import.meta);

const {snapshot, typescript} = tests({
const indexOfOverFindIndexFixtures = createSimpleArraySearchRuleTestFixtures({
method: 'findIndex',
replacement: 'indexOf',
});

test.snapshot(snapshot);
test.typescript(typescript);
test.snapshot(indexOfOverFindIndexFixtures.snapshot);
test.typescript(indexOfOverFindIndexFixtures.typescript);

const lastIndexOfOverFindLastIndexFixtures = createSimpleArraySearchRuleTestFixtures({
method: 'findLastIndex',
replacement: 'lastIndexOf',
});

test.snapshot(lastIndexOfOverFindLastIndexFixtures.snapshot);
test.typescript(lastIndexOfOverFindLastIndexFixtures.typescript);
2 changes: 1 addition & 1 deletion test/shared/simple-array-search-rule-tests.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ function snapshotTests({method, replacement}) {
// Computed
`foo[${method}](x => x === 1)`,
// Not `findIndex`
'foo.notListedMethod(x => x === 1)',
`foo.not_${method}(x => x === 1)`,

// Test `callback` part
// Not function
Expand Down
Loading

0 comments on commit 70e5bdd

Please sign in to comment.