Skip to content

Commit 230a968

Browse files
committed
Add no-array-sort rule
1 parent c7a270d commit 230a968

File tree

9 files changed

+417
-12
lines changed

9 files changed

+417
-12
lines changed

docs/rules/no-array-reverse.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,7 @@ Pass `allowExpressionStatement: false` to forbid `Array#reverse()` even if it's
3939
// eslint unicorn/no-array-reverse: ["error", {"allowExpressionStatement": true}]
4040
array.reverse();
4141
```
42+
43+
## Related rules
44+
45+
- [unicorn/no-array-sort](./no-array-sort.md)

docs/rules/no-array-sort.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# Prefer `Array#toSorted()` over `Array#sort()`
2+
3+
💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config).
4+
5+
💡 This rule is manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions).
6+
7+
<!-- end auto-generated rule header -->
8+
<!-- Do not manually modify this header. Run: `npm run fix:eslint-docs` -->
9+
10+
Prefer using [`Array#toSorted()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toSorted) over [`Array#sort()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort).
11+
12+
`Array#sort()` modifies the original array, while `Array#toSorted()` returns a new reversed array.
13+
14+
## Examples
15+
16+
```js
17+
//
18+
const sorted = [...array].sort();
19+
20+
//
21+
const sorted = [...array].toSorted();
22+
```
23+
24+
```js
25+
//
26+
const sorted = [...array].sort((a, b) => a - b);
27+
28+
//
29+
const sorted = [...array].toSorted((a, b) => a - b);
30+
```
31+
32+
## Options
33+
34+
Type: `object`
35+
36+
### allowExpressionStatement
37+
38+
Type: `boolean`\
39+
Default: `true`
40+
41+
This rule allows `array.sort()` to be used as an expression statement by default.\
42+
Pass `allowExpressionStatement: false` to forbid `Array#sort()` even if it's an expression statement.
43+
44+
#### Fail
45+
46+
```js
47+
// eslint unicorn/no-array-sort: ["error", {"allowExpressionStatement": true}]
48+
array.sort();
49+
```
50+
51+
## Related rules
52+
53+
- [unicorn/no-array-reverse](./no-array-reverse.md)

readme.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ export default [
8181
| [no-array-method-this-argument](docs/rules/no-array-method-this-argument.md) | Disallow using the `this` argument in array methods. || 🔧 | 💡 |
8282
| [no-array-reduce](docs/rules/no-array-reduce.md) | Disallow `Array#reduce()` and `Array#reduceRight()`. || | |
8383
| [no-array-reverse](docs/rules/no-array-reverse.md) | Prefer `Array#toReversed()` over `Array#reverse()`. || | 💡 |
84+
| [no-array-sort](docs/rules/no-array-sort.md) | Prefer `Array#toSorted()` over `Array#sort()`. || | 💡 |
8485
| [no-await-expression-member](docs/rules/no-await-expression-member.md) | Disallow member access from await expression. || 🔧 | |
8586
| [no-await-in-promise-methods](docs/rules/no-await-in-promise-methods.md) | Disallow using `await` in `Promise` method parameters. || | 💡 |
8687
| [no-console-spaces](docs/rules/no-console-spaces.md) | Do not use leading/trailing space between `console.log` parameters. || 🔧 | |

rules/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export {default as 'no-array-for-each'} from './no-array-for-each.js';
2525
export {default as 'no-array-method-this-argument'} from './no-array-method-this-argument.js';
2626
export {default as 'no-array-reduce'} from './no-array-reduce.js';
2727
export {default as 'no-array-reverse'} from './no-array-reverse.js';
28+
export {default as 'no-array-sort'} from './no-array-sort.js';
2829
export {default as 'no-await-expression-member'} from './no-await-expression-member.js';
2930
export {default as 'no-await-in-promise-methods'} from './no-await-in-promise-methods.js';
3031
export {default as 'no-console-spaces'} from './no-console-spaces.js';

rules/no-array-sort.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import noArrayMutateRule from './shared/no-array-mutate-rule.js';
2+
3+
export default noArrayMutateRule('sort');

rules/shared/no-array-mutate-rule.js

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,6 @@
11
import {isMethodCall} from '../ast/index.js';
22
import {getParenthesizedText} from '../utils/index.js';
33

4-
const schema = [
5-
{
6-
type: 'object',
7-
additionalProperties: false,
8-
properties: {
9-
allowExpressionStatement: {
10-
type: 'boolean',
11-
},
12-
},
13-
},
14-
];
15-
164
const MESSAGE_ID_ERROR = 'error';
175
const MESSAGE_ID_SUGGESTION_APPLY_REPLACEMENT = 'suggestion-apply-replacement';
186
const MESSAGE_ID_SUGGESTION_SPREADING_ARRAY = 'suggestion-spreading-array';
@@ -30,8 +18,31 @@ const methods = new Map([
3018
}),
3119
},
3220
],
21+
[
22+
'sort',
23+
{
24+
replacement: 'toSorted',
25+
predicate: callExpression => isMethodCall(callExpression, {
26+
method: 'sort',
27+
maximumArguments: 1,
28+
optionalCall: false,
29+
}),
30+
},
31+
],
3332
]);
3433

34+
const schema = [
35+
{
36+
type: 'object',
37+
additionalProperties: false,
38+
properties: {
39+
allowExpressionStatement: {
40+
type: 'boolean',
41+
},
42+
},
43+
},
44+
];
45+
3546
function noArrayMutateRule(methodName) {
3647
const {
3748
replacement,

test/no-array-sort.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import {getTester} from './utils/test.js';
2+
3+
const {test} = getTester(import.meta);
4+
5+
const FORBID_EXPRESSION_OPTIONS = [{allowExpressionStatement: false}];
6+
7+
test.snapshot({
8+
valid: [
9+
'sorted =[...array].toSorted()',
10+
'sorted =array.toSorted()',
11+
'sorted =[...array].sort',
12+
'sorted =[...array].sort?.()',
13+
'array.sort()',
14+
'array.sort?.()',
15+
'array?.sort()',
16+
'if (true) array.sort()',
17+
'sorted = array.sort(...[])',
18+
'sorted = array.sort(...[compareFn])',
19+
'sorted = array.sort(compareFn, extraArgument)',
20+
],
21+
invalid: [
22+
'sorted = [...array].sort()',
23+
'sorted = [...array]?.sort()',
24+
'sorted = array.sort()',
25+
'sorted = array?.sort()',
26+
'sorted = [...array].sort(compareFn)',
27+
'sorted = [...array]?.sort(compareFn)',
28+
'sorted = array.sort(compareFn)',
29+
'sorted = array?.sort(compareFn)',
30+
{
31+
code: 'array.sort()',
32+
options: FORBID_EXPRESSION_OPTIONS,
33+
},
34+
{
35+
code: 'array?.sort()',
36+
options: FORBID_EXPRESSION_OPTIONS,
37+
},
38+
// Don't care about `allowExpression`
39+
{
40+
code: '[...array].sort()',
41+
options: FORBID_EXPRESSION_OPTIONS,
42+
},
43+
'sorted = [...(0, array)].sort()',
44+
],
45+
});

0 commit comments

Comments
 (0)