Skip to content

Commit 4ada50e

Browse files
authoredFeb 1, 2023
prefer-spread: Forbid use of Array#toSpliced() to copy array (#2034)
1 parent ca5c62a commit 4ada50e

File tree

6 files changed

+193
-3
lines changed

6 files changed

+193
-3
lines changed
 

‎docs/rules/prefer-spread.md

+13-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Prefer the spread operator over `Array.from(…)`, `Array#concat(…)`, `Array#slice()` and `String#split('')`
1+
# Prefer the spread operator over `Array.from(…)`, `Array#concat(…)`, `Array#{slice,toSpliced}()` and `String#split('')`
22

33
💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#preset-configs).
44

@@ -25,6 +25,10 @@ Enforces the use of [the spread operator (`...`)](https://developer.mozilla.org/
2525

2626
Variables named `arrayBuffer`, `blob`, `buffer`, `file`, and `this` are ignored.
2727

28+
- `Array#toSpliced()`
29+
30+
Shallow copy an `Array`.
31+
2832
- `String#split('')`
2933

3034
Split a string into an array of characters.
@@ -47,6 +51,14 @@ const array = array1.concat(array2);
4751
const copy = array.slice();
4852
```
4953

54+
```js
55+
const copy = array.slice(0);
56+
```
57+
58+
```js
59+
const copy = array.toSpliced();
60+
```
61+
5062
```js
5163
const characters = string.split('');
5264
```

‎readme.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ If you don't use the preset, ensure you use the same `env` and `parserOptions` c
145145
| [prefer-regexp-test](docs/rules/prefer-regexp-test.md) | Prefer `RegExp#test()` over `String#match()` and `RegExp#exec()`. || 🔧 | 💡 |
146146
| [prefer-set-has](docs/rules/prefer-set-has.md) | Prefer `Set#has()` over `Array#includes()` when checking for existence or non-existence. || 🔧 | 💡 |
147147
| [prefer-set-size](docs/rules/prefer-set-size.md) | Prefer using `Set#size` instead of `Array#length`. || 🔧 | |
148-
| [prefer-spread](docs/rules/prefer-spread.md) | Prefer the spread operator over `Array.from(…)`, `Array#concat(…)`, `Array#slice()` and `String#split('')`. || 🔧 | 💡 |
148+
| [prefer-spread](docs/rules/prefer-spread.md) | Prefer the spread operator over `Array.from(…)`, `Array#concat(…)`, `Array#{slice,toSpliced}()` and `String#split('')`. || 🔧 | 💡 |
149149
| [prefer-string-replace-all](docs/rules/prefer-string-replace-all.md) | Prefer `String#replaceAll()` over regex searches with the global flag. | | 🔧 | |
150150
| [prefer-string-slice](docs/rules/prefer-string-slice.md) | Prefer `String#slice()` over `String#substr()` and `String#substring()`. || 🔧 | |
151151
| [prefer-string-starts-ends-with](docs/rules/prefer-string-starts-ends-with.md) | Prefer `String#startsWith()` & `String#endsWith()` over `RegExp#test()`. || 🔧 | 💡 |

‎rules/prefer-spread.js

+18-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const isMethodNamed = require('./utils/is-method-named.js');
1616
const ERROR_ARRAY_FROM = 'array-from';
1717
const ERROR_ARRAY_CONCAT = 'array-concat';
1818
const ERROR_ARRAY_SLICE = 'array-slice';
19+
const ERROR_ARRAY_TO_SPLICED = 'array-to-spliced';
1920
const ERROR_STRING_SPLIT = 'string-split';
2021
const SUGGESTION_CONCAT_ARGUMENT_IS_SPREADABLE = 'argument-is-spreadable';
2122
const SUGGESTION_CONCAT_ARGUMENT_IS_NOT_SPREADABLE = 'argument-is-not-spreadable';
@@ -26,6 +27,7 @@ const messages = {
2627
[ERROR_ARRAY_FROM]: 'Prefer the spread operator over `Array.from(…)`.',
2728
[ERROR_ARRAY_CONCAT]: 'Prefer the spread operator over `Array#concat(…)`.',
2829
[ERROR_ARRAY_SLICE]: 'Prefer the spread operator over `Array#slice()`.',
30+
[ERROR_ARRAY_TO_SPLICED]: 'Prefer the spread operator over `Array#toSpliced()`.',
2931
[ERROR_STRING_SPLIT]: 'Prefer the spread operator over `String#split(\'\')`.',
3032
[SUGGESTION_CONCAT_ARGUMENT_IS_SPREADABLE]: 'First argument is an `array`.',
3133
[SUGGESTION_CONCAT_ARGUMENT_IS_NOT_SPREADABLE]: 'First argument is not an `array`.',
@@ -56,6 +58,14 @@ const arraySliceCallSelector = [
5658
'[callee.object.type!="ArrayExpression"]',
5759
].join('');
5860

61+
const arrayToSplicedCallSelector = [
62+
methodCallSelector({
63+
method: 'toSpliced',
64+
argumentsLength: 0,
65+
}),
66+
'[callee.object.type!="ArrayExpression"]',
67+
].join('');
68+
5969
const ignoredSliceCallee = [
6070
'arrayBuffer',
6171
'blob',
@@ -444,6 +454,13 @@ const create = context => {
444454
fix: methodCallToSpread(node, sourceCode),
445455
};
446456
},
457+
[arrayToSplicedCallSelector](node) {
458+
return {
459+
node: node.callee.property,
460+
messageId: ERROR_ARRAY_TO_SPLICED,
461+
fix: methodCallToSpread(node, sourceCode),
462+
};
463+
},
447464
[stringSplitCallSelector](node) {
448465
const [separator] = node.arguments;
449466
if (!isLiteral(separator, '')) {
@@ -495,7 +512,7 @@ module.exports = {
495512
meta: {
496513
type: 'suggestion',
497514
docs: {
498-
description: 'Prefer the spread operator over `Array.from(…)`, `Array#concat(…)`, `Array#slice()` and `String#split(\'\')`.',
515+
description: 'Prefer the spread operator over `Array.from(…)`, `Array#concat(…)`, `Array#{slice,toSpliced}()` and `String#split(\'\')`.',
499516
},
500517
fixable: 'code',
501518
hasSuggestions: true,

‎test/prefer-spread.mjs

+39
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,45 @@ test.snapshot({
347347
],
348348
});
349349

350+
// `Array#toSpliced`
351+
test.snapshot({
352+
valid: [
353+
'new Array.toSpliced()',
354+
'toSpliced()',
355+
'array[toSpliced]()',
356+
'array.toSpliced',
357+
'array.toSpliced(0)',
358+
'array.toSpliced(...[])',
359+
'array.toSpliced(...[0])',
360+
'array.toSpliced(0 + 0)',
361+
'array.toSpliced("")',
362+
'array.toSpliced(null)',
363+
'const ZERO = 0;array.toSpliced(0, ZERO)',
364+
'array.toSpliced(0, array.length)',
365+
'array.toSpliced(0, 0)',
366+
'array.notToSpliced()',
367+
// Why would someone write these
368+
'[...foo].toSpliced()',
369+
'[foo].toSpliced()',
370+
'array.toSpliced(100, 0)',
371+
'array.toSpliced(-1, 0)',
372+
],
373+
invalid: [
374+
'array.toSpliced()',
375+
'array.toSpliced().toSpliced()',
376+
'const copy = array.toSpliced()',
377+
'(( (( (( array )).toSpliced ))() ))',
378+
// Semicolon
379+
outdent`
380+
bar()
381+
foo.toSpliced()
382+
`,
383+
// `{String,TypedArray}#toSpliced` are wrongly detected
384+
'"".toSpliced()',
385+
'new Uint8Array([10, 20, 30, 40, 50]).toSpliced()',
386+
],
387+
});
388+
350389
// `String#slice('')`
351390
test.snapshot({
352391
valid: [

‎test/snapshots/prefer-spread.mjs.md

+122
Original file line numberDiff line numberDiff line change
@@ -2268,6 +2268,128 @@ Generated by [AVA](https://avajs.dev).
22682268
| ^^^^^ Prefer the spread operator over \`Array#slice()\`.␊
22692269
`
22702270

2271+
## Invalid #1
2272+
1 | array.toSpliced()
2273+
2274+
> Output
2275+
2276+
`␊
2277+
1 | [...array]␊
2278+
`
2279+
2280+
> Error 1/1
2281+
2282+
`␊
2283+
> 1 | array.toSpliced()␊
2284+
| ^^^^^^^^^ Prefer the spread operator over \`Array#toSpliced()\`.␊
2285+
`
2286+
2287+
## Invalid #2
2288+
1 | array.toSpliced().toSpliced()
2289+
2290+
> Output
2291+
2292+
`␊
2293+
1 | [...array].toSpliced()␊
2294+
`
2295+
2296+
> Error 1/2
2297+
2298+
`␊
2299+
> 1 | array.toSpliced().toSpliced()␊
2300+
| ^^^^^^^^^ Prefer the spread operator over \`Array#toSpliced()\`.␊
2301+
`
2302+
2303+
> Error 2/2
2304+
2305+
`␊
2306+
> 1 | array.toSpliced().toSpliced()␊
2307+
| ^^^^^^^^^ Prefer the spread operator over \`Array#toSpliced()\`.␊
2308+
`
2309+
2310+
## Invalid #3
2311+
1 | const copy = array.toSpliced()
2312+
2313+
> Output
2314+
2315+
`␊
2316+
1 | const copy = [...array]␊
2317+
`
2318+
2319+
> Error 1/1
2320+
2321+
`␊
2322+
> 1 | const copy = array.toSpliced()␊
2323+
| ^^^^^^^^^ Prefer the spread operator over \`Array#toSpliced()\`.␊
2324+
`
2325+
2326+
## Invalid #4
2327+
1 | (( (( (( array )).toSpliced ))() ))
2328+
2329+
> Output
2330+
2331+
`␊
2332+
1 | (( [...(( (( array )) ))] ))␊
2333+
`
2334+
2335+
> Error 1/1
2336+
2337+
`␊
2338+
> 1 | (( (( (( array )).toSpliced ))() ))␊
2339+
| ^^^^^^^^^ Prefer the spread operator over \`Array#toSpliced()\`.␊
2340+
`
2341+
2342+
## Invalid #5
2343+
1 | bar()
2344+
2 | foo.toSpliced()
2345+
2346+
> Output
2347+
2348+
`␊
2349+
1 | bar()␊
2350+
2 | ;[...foo]␊
2351+
`
2352+
2353+
> Error 1/1
2354+
2355+
`␊
2356+
1 | bar()␊
2357+
> 2 | foo.toSpliced()␊
2358+
| ^^^^^^^^^ Prefer the spread operator over \`Array#toSpliced()\`.␊
2359+
`
2360+
2361+
## Invalid #6
2362+
1 | "".toSpliced()
2363+
2364+
> Output
2365+
2366+
`␊
2367+
1 | [...""]␊
2368+
`
2369+
2370+
> Error 1/1
2371+
2372+
`␊
2373+
> 1 | "".toSpliced()␊
2374+
| ^^^^^^^^^ Prefer the spread operator over \`Array#toSpliced()\`.␊
2375+
`
2376+
2377+
## Invalid #7
2378+
1 | new Uint8Array([10, 20, 30, 40, 50]).toSpliced()
2379+
2380+
> Output
2381+
2382+
`␊
2383+
1 | [...new Uint8Array([10, 20, 30, 40, 50])]␊
2384+
`
2385+
2386+
> Error 1/1
2387+
2388+
`␊
2389+
> 1 | new Uint8Array([10, 20, 30, 40, 50]).toSpliced()␊
2390+
| ^^^^^^^^^ Prefer the spread operator over \`Array#toSpliced()\`.␊
2391+
`
2392+
22712393
## Invalid #1
22722394
1 | "string".split("")
22732395

‎test/snapshots/prefer-spread.mjs.snap

325 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)
Please sign in to comment.