From 7ed738a41d5f611b1907dc2a9afd2c454300577a Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Thu, 2 Feb 2023 12:52:48 +0800 Subject: [PATCH] `prefer-negative-index`: Check `.toSpliced()` and `.with()` (#2031) Co-authored-by: Sindre Sorhus --- docs/rules/prefer-negative-index.md | 22 ++++- readme.md | 2 +- rules/prefer-negative-index.js | 25 +++++- test/prefer-negative-index.mjs | 13 ++- test/snapshots/prefer-negative-index.mjs.md | 80 ++++++++++++++++++ test/snapshots/prefer-negative-index.mjs.snap | Bin 614 -> 885 bytes 6 files changed, 135 insertions(+), 7 deletions(-) diff --git a/docs/rules/prefer-negative-index.md b/docs/rules/prefer-negative-index.md index 78990618c1..59e042a6e0 100644 --- a/docs/rules/prefer-negative-index.md +++ b/docs/rules/prefer-negative-index.md @@ -1,4 +1,4 @@ -# Prefer negative index over `.length - index` for `{String,Array,TypedArray}#{slice,at}()` and `Array#splice()` +# Prefer negative index over `.length - index` when possible 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#preset-configs). @@ -7,7 +7,25 @@ -Prefer negative index over calculating from `.length` for [`String#slice()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/slice), [`Array#slice()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice), [`TypedArray#slice()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/slice), [`String#at()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/at), [`Array#at()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/at), [`TypedArray#at()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/at), and [`Array#splice()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice) +Prefer negative index over calculating from `.length` for: + +- [`String#slice()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/slice) +- [`Array#slice()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice) +- [`TypedArray#slice()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/slice) +- [`String#at()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/at) +- [`Array#at()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/at) +- [`TypedArray#at()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/at) +- [`Array#splice()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice) +- [`Array#toSpliced()`](https://github.com/tc39/proposal-change-array-by-copy#overview) +- [`Array#with()`](https://github.com/tc39/proposal-change-array-by-copy#overview) +- [`TypedArray#with()`](https://github.com/tc39/proposal-change-array-by-copy#overview) + + ## Fail diff --git a/readme.md b/readme.md index d15d6eebf7..36984423ea 100644 --- a/readme.md +++ b/readme.md @@ -134,7 +134,7 @@ If you don't use the preset, ensure you use the same `env` and `parserOptions` c | [prefer-modern-math-apis](docs/rules/prefer-modern-math-apis.md) | Prefer modern `Math` APIs over legacy patterns. | ✅ | 🔧 | | | [prefer-module](docs/rules/prefer-module.md) | Prefer JavaScript modules (ESM) over CommonJS. | ✅ | 🔧 | 💡 | | [prefer-native-coercion-functions](docs/rules/prefer-native-coercion-functions.md) | Prefer using `String`, `Number`, `BigInt`, `Boolean`, and `Symbol` directly. | ✅ | 🔧 | | -| [prefer-negative-index](docs/rules/prefer-negative-index.md) | Prefer negative index over `.length - index` for `{String,Array,TypedArray}#{slice,at}()` and `Array#splice()`. | ✅ | 🔧 | | +| [prefer-negative-index](docs/rules/prefer-negative-index.md) | Prefer negative index over `.length - index` when possible. | ✅ | 🔧 | | | [prefer-node-protocol](docs/rules/prefer-node-protocol.md) | Prefer using the `node:` protocol when importing Node.js builtin modules. | ✅ | 🔧 | | | [prefer-number-properties](docs/rules/prefer-number-properties.md) | Prefer `Number` static properties over global ones. | ✅ | 🔧 | 💡 | | [prefer-object-from-entries](docs/rules/prefer-object-from-entries.md) | Prefer using `Object.fromEntries(…)` to transform a list of key-value pairs into an object. | ✅ | 🔧 | | diff --git a/rules/prefer-negative-index.js b/rules/prefer-negative-index.js index 986b4e9f33..932676d0a5 100644 --- a/rules/prefer-negative-index.js +++ b/rules/prefer-negative-index.js @@ -36,6 +36,15 @@ const methods = new Map([ ]), }, ], + [ + 'toSpliced', + { + argumentsIndexes: [0], + supportObjects: new Set([ + 'Array', + ]), + }, + ], [ 'at', { @@ -47,6 +56,16 @@ const methods = new Map([ ]), }, ], + [ + 'with', + { + argumentsIndexes: [0], + supportObjects: new Set([ + 'Array', + ...typedArray, + ]), + }, + ], ]); const getMemberName = node => { @@ -92,12 +111,12 @@ function parse(node) { const parentCallee = callee.object.object; if ( - // [].{slice,splice} + // `[].{slice,splice,toSpliced,at,with}` ( parentCallee.type === 'ArrayExpression' && parentCallee.elements.length === 0 ) - // ''.slice + // `''.slice` || ( method === 'slice' && isLiteral(parentCallee, '') @@ -175,7 +194,7 @@ module.exports = { meta: { type: 'suggestion', docs: { - description: 'Prefer negative index over `.length - index` for `{String,Array,TypedArray}#{slice,at}()` and `Array#splice()`.', + description: 'Prefer negative index over `.length - index` when possible.', }, fixable: 'code', messages, diff --git a/test/prefer-negative-index.mjs b/test/prefer-negative-index.mjs index 2ea07d2dda..a11fc4cd9c 100644 --- a/test/prefer-negative-index.mjs +++ b/test/prefer-negative-index.mjs @@ -344,7 +344,13 @@ test({ }); test.snapshot({ - valid: [], + valid: [ + // There is no `String#{toSpliced,with}` + 'String.prototype.toSpliced.call(foo, foo.length - 1)', + 'String.prototype.with.call(foo, foo.length - 1)', + // There is no `TypedArray#toSpliced` + 'Uint8Array.prototype.toSpliced.call(foo, foo.length - 1)', + ], invalid: [ 'foo.slice(foo.length - 2, foo.length - 1)', 'foo.splice(foo.length - 1, 1)', @@ -361,5 +367,10 @@ test.snapshot({ Array.prototype.at.call(foo, foo.length - 2); Array.prototype.at.apply(foo, [foo.length - 3]); `, + 'foo.toSpliced(foo.length - 3, foo.length - 6)', + 'Array.prototype.toSpliced.call(foo, foo.length - 3, foo.length - 6)', + '[].toSpliced.call(foo, foo.length - 3, foo.length - 6)', + 'foo.with(foo.length - 3, foo.length - 6)', + 'Array.prototype.with.call(foo, foo.length - 3, foo.length - 6)', ], }); diff --git a/test/snapshots/prefer-negative-index.mjs.md b/test/snapshots/prefer-negative-index.mjs.md index e0ccc4e923..8e357dc042 100644 --- a/test/snapshots/prefer-negative-index.mjs.md +++ b/test/snapshots/prefer-negative-index.mjs.md @@ -139,3 +139,83 @@ Generated by [AVA](https://avajs.dev). > 3 | Array.prototype.at.apply(foo, [foo.length - 3]);␊ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer negative index over length minus index for \`at\`.␊ ` + +## Invalid #8 + 1 | foo.toSpliced(foo.length - 3, foo.length - 6) + +> Output + + `␊ + 1 | foo.toSpliced(- 3, foo.length - 6)␊ + ` + +> Error 1/1 + + `␊ + > 1 | foo.toSpliced(foo.length - 3, foo.length - 6)␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer negative index over length minus index for \`toSpliced\`.␊ + ` + +## Invalid #9 + 1 | Array.prototype.toSpliced.call(foo, foo.length - 3, foo.length - 6) + +> Output + + `␊ + 1 | Array.prototype.toSpliced.call(foo, - 3, foo.length - 6)␊ + ` + +> Error 1/1 + + `␊ + > 1 | Array.prototype.toSpliced.call(foo, foo.length - 3, foo.length - 6)␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer negative index over length minus index for \`toSpliced\`.␊ + ` + +## Invalid #10 + 1 | [].toSpliced.call(foo, foo.length - 3, foo.length - 6) + +> Output + + `␊ + 1 | [].toSpliced.call(foo, - 3, foo.length - 6)␊ + ` + +> Error 1/1 + + `␊ + > 1 | [].toSpliced.call(foo, foo.length - 3, foo.length - 6)␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer negative index over length minus index for \`toSpliced\`.␊ + ` + +## Invalid #11 + 1 | foo.with(foo.length - 3, foo.length - 6) + +> Output + + `␊ + 1 | foo.with(- 3, foo.length - 6)␊ + ` + +> Error 1/1 + + `␊ + > 1 | foo.with(foo.length - 3, foo.length - 6)␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer negative index over length minus index for \`with\`.␊ + ` + +## Invalid #12 + 1 | Array.prototype.with.call(foo, foo.length - 3, foo.length - 6) + +> Output + + `␊ + 1 | Array.prototype.with.call(foo, - 3, foo.length - 6)␊ + ` + +> Error 1/1 + + `␊ + > 1 | Array.prototype.with.call(foo, foo.length - 3, foo.length - 6)␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer negative index over length minus index for \`with\`.␊ + ` diff --git a/test/snapshots/prefer-negative-index.mjs.snap b/test/snapshots/prefer-negative-index.mjs.snap index 28def4358c81d9d6d048d37e4d69bec644cef1f1..aa0194e530787cb9ded2c91235e368c64acbc3ce 100644 GIT binary patch literal 885 zcmV-*1B(1XRzV^#gj3N8s*JvUWcj1RskC00000000A9 z$H>6I!@$2_?QE6~v2Q#JeD?;*@>(-7fPgj>UjkymVy-paMrvmxD_wcDmX_x*fkhP< zA($DcLGMRi&g)z$pBHxhe^b-`% zVrF14t=Vik@rvTEncKG9oT6RJ&IA^{4aG}X7#OTux6WADaO#3X;g=MRn@c`0fkp2? z@nlv82A|zcUXf*-MV!`Ln{Rzen8gGZy#vJ?*ccdmODo#a#0v|4e*e|yDnC_-2`qX8 ziYwU}7%FN?F5LgDw;&_oDJ%1*!=mIFV=3rphqomxLTJX@s8nyFH%SV+n%6@;!H*dsE-_riV`dJ3X1Ye@=GcUQuRvm zg9||FQ}mJ(b85u>n(*z=$4k&5|Rns98DRCv1fc*i=j7C_pP+|#6Rx|=DG{&wlv7jKQ5~4C1n89L! zYEeSxK5|+G+KXDLf=$L98svCBu>|OIBK(Eo5Td<^TAX0`_A3KwC}a56jx2|fT0~J0 zZj^_?4?+Umhmno~X8AD(rRj;;@-#vV4pK`H%E}M` LQ*4^2{|*2EJn4u> literal 614 zcmV-s0-60mRzVoDJ%1*!XdM(w zGBYsjQBrPAEqG|+aX^fF{@x9)OkhzLD1HsZmt_Ox@DqszOaBrlUN`) zfE9v6*dREXoq^%nVn6@j2|wSR{yKNQL*+dYCa`D=6zg*^Ffao{00bCW83Y++xfB!( z6>1dH^7EtBlM;*6WA%!2GLus^bQKIWxsa7I&0yfN!>$%2pac|9iq*?W%}X!IPyp*z z0D>BYIO2dpKv8O1YLP--YI_+jWI4TnklTUbi8CrDA-f%+km7itS|ms! zB`ZVRNva1qNg1LfCqwc)K{X#BXN&}3m?jXJF;LVFs*I6|l(-U0!2YlX3K;=~9E*w) zEAIXNKr>j0f>1XgH_U14HDK~5z^Wwfq>aV$_RO6c52POCtB zQS%tsWZa=aj^`6gfIcU}UnmYC+KVW