From 4ada50e896dca899b029ada6a55ebf2141252251 Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Wed, 1 Feb 2023 23:31:06 +0800 Subject: [PATCH] `prefer-spread`: Forbid use of `Array#toSpliced()` to copy array (#2034) --- docs/rules/prefer-spread.md | 14 ++- readme.md | 2 +- rules/prefer-spread.js | 19 +++- test/prefer-spread.mjs | 39 ++++++++ test/snapshots/prefer-spread.mjs.md | 122 ++++++++++++++++++++++++++ test/snapshots/prefer-spread.mjs.snap | Bin 7259 -> 7584 bytes 6 files changed, 193 insertions(+), 3 deletions(-) diff --git a/docs/rules/prefer-spread.md b/docs/rules/prefer-spread.md index 9efefe4581..264c5ca8df 100644 --- a/docs/rules/prefer-spread.md +++ b/docs/rules/prefer-spread.md @@ -1,4 +1,4 @@ -# Prefer the spread operator over `Array.from(…)`, `Array#concat(…)`, `Array#slice()` and `String#split('')` +# Prefer the spread operator over `Array.from(…)`, `Array#concat(…)`, `Array#{slice,toSpliced}()` and `String#split('')` 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#preset-configs). @@ -25,6 +25,10 @@ Enforces the use of [the spread operator (`...`)](https://developer.mozilla.org/ Variables named `arrayBuffer`, `blob`, `buffer`, `file`, and `this` are ignored. +- `Array#toSpliced()` + + Shallow copy an `Array`. + - `String#split('')` Split a string into an array of characters. @@ -47,6 +51,14 @@ const array = array1.concat(array2); const copy = array.slice(); ``` +```js +const copy = array.slice(0); +``` + +```js +const copy = array.toSpliced(); +``` + ```js const characters = string.split(''); ``` diff --git a/readme.md b/readme.md index 6c9acfca2d..d15d6eebf7 100644 --- a/readme.md +++ b/readme.md @@ -145,7 +145,7 @@ If you don't use the preset, ensure you use the same `env` and `parserOptions` c | [prefer-regexp-test](docs/rules/prefer-regexp-test.md) | Prefer `RegExp#test()` over `String#match()` and `RegExp#exec()`. | ✅ | 🔧 | 💡 | | [prefer-set-has](docs/rules/prefer-set-has.md) | Prefer `Set#has()` over `Array#includes()` when checking for existence or non-existence. | ✅ | 🔧 | 💡 | | [prefer-set-size](docs/rules/prefer-set-size.md) | Prefer using `Set#size` instead of `Array#length`. | ✅ | 🔧 | | -| [prefer-spread](docs/rules/prefer-spread.md) | Prefer the spread operator over `Array.from(…)`, `Array#concat(…)`, `Array#slice()` and `String#split('')`. | ✅ | 🔧 | 💡 | +| [prefer-spread](docs/rules/prefer-spread.md) | Prefer the spread operator over `Array.from(…)`, `Array#concat(…)`, `Array#{slice,toSpliced}()` and `String#split('')`. | ✅ | 🔧 | 💡 | | [prefer-string-replace-all](docs/rules/prefer-string-replace-all.md) | Prefer `String#replaceAll()` over regex searches with the global flag. | | 🔧 | | | [prefer-string-slice](docs/rules/prefer-string-slice.md) | Prefer `String#slice()` over `String#substr()` and `String#substring()`. | ✅ | 🔧 | | | [prefer-string-starts-ends-with](docs/rules/prefer-string-starts-ends-with.md) | Prefer `String#startsWith()` & `String#endsWith()` over `RegExp#test()`. | ✅ | 🔧 | 💡 | diff --git a/rules/prefer-spread.js b/rules/prefer-spread.js index ba4d71f4f2..670079b244 100644 --- a/rules/prefer-spread.js +++ b/rules/prefer-spread.js @@ -16,6 +16,7 @@ const isMethodNamed = require('./utils/is-method-named.js'); const ERROR_ARRAY_FROM = 'array-from'; const ERROR_ARRAY_CONCAT = 'array-concat'; const ERROR_ARRAY_SLICE = 'array-slice'; +const ERROR_ARRAY_TO_SPLICED = 'array-to-spliced'; const ERROR_STRING_SPLIT = 'string-split'; const SUGGESTION_CONCAT_ARGUMENT_IS_SPREADABLE = 'argument-is-spreadable'; const SUGGESTION_CONCAT_ARGUMENT_IS_NOT_SPREADABLE = 'argument-is-not-spreadable'; @@ -26,6 +27,7 @@ const messages = { [ERROR_ARRAY_FROM]: 'Prefer the spread operator over `Array.from(…)`.', [ERROR_ARRAY_CONCAT]: 'Prefer the spread operator over `Array#concat(…)`.', [ERROR_ARRAY_SLICE]: 'Prefer the spread operator over `Array#slice()`.', + [ERROR_ARRAY_TO_SPLICED]: 'Prefer the spread operator over `Array#toSpliced()`.', [ERROR_STRING_SPLIT]: 'Prefer the spread operator over `String#split(\'\')`.', [SUGGESTION_CONCAT_ARGUMENT_IS_SPREADABLE]: 'First argument is an `array`.', [SUGGESTION_CONCAT_ARGUMENT_IS_NOT_SPREADABLE]: 'First argument is not an `array`.', @@ -56,6 +58,14 @@ const arraySliceCallSelector = [ '[callee.object.type!="ArrayExpression"]', ].join(''); +const arrayToSplicedCallSelector = [ + methodCallSelector({ + method: 'toSpliced', + argumentsLength: 0, + }), + '[callee.object.type!="ArrayExpression"]', +].join(''); + const ignoredSliceCallee = [ 'arrayBuffer', 'blob', @@ -444,6 +454,13 @@ const create = context => { fix: methodCallToSpread(node, sourceCode), }; }, + [arrayToSplicedCallSelector](node) { + return { + node: node.callee.property, + messageId: ERROR_ARRAY_TO_SPLICED, + fix: methodCallToSpread(node, sourceCode), + }; + }, [stringSplitCallSelector](node) { const [separator] = node.arguments; if (!isLiteral(separator, '')) { @@ -495,7 +512,7 @@ module.exports = { meta: { type: 'suggestion', docs: { - description: 'Prefer the spread operator over `Array.from(…)`, `Array#concat(…)`, `Array#slice()` and `String#split(\'\')`.', + description: 'Prefer the spread operator over `Array.from(…)`, `Array#concat(…)`, `Array#{slice,toSpliced}()` and `String#split(\'\')`.', }, fixable: 'code', hasSuggestions: true, diff --git a/test/prefer-spread.mjs b/test/prefer-spread.mjs index e98ef2500e..ec7a8822f3 100644 --- a/test/prefer-spread.mjs +++ b/test/prefer-spread.mjs @@ -347,6 +347,45 @@ test.snapshot({ ], }); +// `Array#toSpliced` +test.snapshot({ + valid: [ + 'new Array.toSpliced()', + 'toSpliced()', + 'array[toSpliced]()', + 'array.toSpliced', + 'array.toSpliced(0)', + 'array.toSpliced(...[])', + 'array.toSpliced(...[0])', + 'array.toSpliced(0 + 0)', + 'array.toSpliced("")', + 'array.toSpliced(null)', + 'const ZERO = 0;array.toSpliced(0, ZERO)', + 'array.toSpliced(0, array.length)', + 'array.toSpliced(0, 0)', + 'array.notToSpliced()', + // Why would someone write these + '[...foo].toSpliced()', + '[foo].toSpliced()', + 'array.toSpliced(100, 0)', + 'array.toSpliced(-1, 0)', + ], + invalid: [ + 'array.toSpliced()', + 'array.toSpliced().toSpliced()', + 'const copy = array.toSpliced()', + '(( (( (( array )).toSpliced ))() ))', + // Semicolon + outdent` + bar() + foo.toSpliced() + `, + // `{String,TypedArray}#toSpliced` are wrongly detected + '"".toSpliced()', + 'new Uint8Array([10, 20, 30, 40, 50]).toSpliced()', + ], +}); + // `String#slice('')` test.snapshot({ valid: [ diff --git a/test/snapshots/prefer-spread.mjs.md b/test/snapshots/prefer-spread.mjs.md index 984d0ab21b..f1aed9185f 100644 --- a/test/snapshots/prefer-spread.mjs.md +++ b/test/snapshots/prefer-spread.mjs.md @@ -2268,6 +2268,128 @@ Generated by [AVA](https://avajs.dev). | ^^^^^ Prefer the spread operator over \`Array#slice()\`.␊ ` +## Invalid #1 + 1 | array.toSpliced() + +> Output + + `␊ + 1 | [...array]␊ + ` + +> Error 1/1 + + `␊ + > 1 | array.toSpliced()␊ + | ^^^^^^^^^ Prefer the spread operator over \`Array#toSpliced()\`.␊ + ` + +## Invalid #2 + 1 | array.toSpliced().toSpliced() + +> Output + + `␊ + 1 | [...array].toSpliced()␊ + ` + +> Error 1/2 + + `␊ + > 1 | array.toSpliced().toSpliced()␊ + | ^^^^^^^^^ Prefer the spread operator over \`Array#toSpliced()\`.␊ + ` + +> Error 2/2 + + `␊ + > 1 | array.toSpliced().toSpliced()␊ + | ^^^^^^^^^ Prefer the spread operator over \`Array#toSpliced()\`.␊ + ` + +## Invalid #3 + 1 | const copy = array.toSpliced() + +> Output + + `␊ + 1 | const copy = [...array]␊ + ` + +> Error 1/1 + + `␊ + > 1 | const copy = array.toSpliced()␊ + | ^^^^^^^^^ Prefer the spread operator over \`Array#toSpliced()\`.␊ + ` + +## Invalid #4 + 1 | (( (( (( array )).toSpliced ))() )) + +> Output + + `␊ + 1 | (( [...(( (( array )) ))] ))␊ + ` + +> Error 1/1 + + `␊ + > 1 | (( (( (( array )).toSpliced ))() ))␊ + | ^^^^^^^^^ Prefer the spread operator over \`Array#toSpliced()\`.␊ + ` + +## Invalid #5 + 1 | bar() + 2 | foo.toSpliced() + +> Output + + `␊ + 1 | bar()␊ + 2 | ;[...foo]␊ + ` + +> Error 1/1 + + `␊ + 1 | bar()␊ + > 2 | foo.toSpliced()␊ + | ^^^^^^^^^ Prefer the spread operator over \`Array#toSpliced()\`.␊ + ` + +## Invalid #6 + 1 | "".toSpliced() + +> Output + + `␊ + 1 | [...""]␊ + ` + +> Error 1/1 + + `␊ + > 1 | "".toSpliced()␊ + | ^^^^^^^^^ Prefer the spread operator over \`Array#toSpliced()\`.␊ + ` + +## Invalid #7 + 1 | new Uint8Array([10, 20, 30, 40, 50]).toSpliced() + +> Output + + `␊ + 1 | [...new Uint8Array([10, 20, 30, 40, 50])]␊ + ` + +> Error 1/1 + + `␊ + > 1 | new Uint8Array([10, 20, 30, 40, 50]).toSpliced()␊ + | ^^^^^^^^^ Prefer the spread operator over \`Array#toSpliced()\`.␊ + ` + ## Invalid #1 1 | "string".split("") diff --git a/test/snapshots/prefer-spread.mjs.snap b/test/snapshots/prefer-spread.mjs.snap index 3d06834a1a6b01a286b3c4a4b59eb4712c61a0f8..a7c3747bf3f35b1d9b0b60c5a50bffe3e8e561ff 100644 GIT binary patch literal 7584 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 CTDkiG literal 7259 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