From 9fa2cd5dd8b9991620122d119c8cb72807b54128 Mon Sep 17 00:00:00 2001 From: fisker Date: Sun, 23 Nov 2025 22:28:12 +0800 Subject: [PATCH 1/3] `prefer-set-has`: Check `Iterator#toArray()` and `String#split()` --- rules/prefer-set-has.js | 25 ++++++++--- test/prefer-set-has.js | 2 + test/snapshots/prefer-set-has.js.md | 58 +++++++++++++++++++++++++- test/snapshots/prefer-set-has.js.snap | Bin 2718 -> 2772 bytes 4 files changed, 79 insertions(+), 6 deletions(-) diff --git a/rules/prefer-set-has.js b/rules/prefer-set-has.js index 59f6533925..ca4b36660c 100644 --- a/rules/prefer-set-has.js +++ b/rules/prefer-set-has.js @@ -9,8 +9,14 @@ const messages = { [MESSAGE_ID_SUGGESTION]: 'Switch `{{name}}` to `Set`.', }; -const arrayMethodsReturnsArray = [ - 'concat', +/* +Some of these methods can be `Iterator` +Since `Iterator` don't have an `includes()` method +We are safe to assume they are array. +Except `concat` and `slice` which can be an string, https://github.com/sindresorhus/eslint-plugin-unicorn/issues/2216 . +*/ +const methodsReturnsArray = [ + // `Array` 'copyWithin', 'fill', 'filter', @@ -18,13 +24,22 @@ const arrayMethodsReturnsArray = [ 'flatMap', 'map', 'reverse', - 'slice', 'sort', 'splice', 'toReversed', 'toSorted', 'toSpliced', 'with', + + // `Array` or `String` (unsafe) + 'slice', + 'concat', + + // `String` + 'split', + + // `Iterator` + 'toArray', ]; const isIncludesCall = node => @@ -95,9 +110,9 @@ const create = context => { optionalCall: false, optionalMember: false, }) - // Array methods that return an array + // Methods that return an array || isMethodCall(parent.init, { - methods: arrayMethodsReturnsArray, + methods: methodsReturnsArray, optionalCall: false, optionalMember: false, }) diff --git a/test/prefer-set-has.js b/test/prefer-set-has.js index b383e49805..14e2dcd29b 100644 --- a/test/prefer-set-has.js +++ b/test/prefer-set-has.js @@ -19,6 +19,8 @@ const methodsReturnsArray = [ 'toSorted', 'toSpliced', 'with', + 'toArray', + 'split', ]; test.snapshot({ diff --git a/test/snapshots/prefer-set-has.js.md b/test/snapshots/prefer-set-has.js.md index 89f67e320a..b96556f8dd 100644 --- a/test/snapshots/prefer-set-has.js.md +++ b/test/snapshots/prefer-set-has.js.md @@ -1346,7 +1346,63 @@ Generated by [AVA](https://avajs.dev). 4 | }␊ ` -## invalid(41): const foo = _([1,2,3]); const bar = foo.map(value => value); function unicorn() { return bar.includes(1); } +## invalid(41): const foo = bar.toArray(); function unicorn() { return foo.includes(1); } + +> Input + + `␊ + 1 | const foo = bar.toArray();␊ + 2 | function unicorn() {␊ + 3 | return foo.includes(1);␊ + 4 | }␊ + ` + +> Error 1/1 + + `␊ + Message:␊ + > 1 | const foo = bar.toArray();␊ + | ^^^ \`foo\` should be a \`Set\`, and use \`foo.has()\` to check existence or non-existence.␊ + 2 | function unicorn() {␊ + 3 | return foo.includes(1);␊ + 4 | }␊ + ␊ + Output:␊ + 1 | const foo = new Set(bar.toArray());␊ + 2 | function unicorn() {␊ + 3 | return foo.has(1);␊ + 4 | }␊ + ` + +## invalid(42): const foo = bar.split(); function unicorn() { return foo.includes(1); } + +> Input + + `␊ + 1 | const foo = bar.split();␊ + 2 | function unicorn() {␊ + 3 | return foo.includes(1);␊ + 4 | }␊ + ` + +> Error 1/1 + + `␊ + Message:␊ + > 1 | const foo = bar.split();␊ + | ^^^ \`foo\` should be a \`Set\`, and use \`foo.has()\` to check existence or non-existence.␊ + 2 | function unicorn() {␊ + 3 | return foo.includes(1);␊ + 4 | }␊ + ␊ + Output:␊ + 1 | const foo = new Set(bar.split());␊ + 2 | function unicorn() {␊ + 3 | return foo.has(1);␊ + 4 | }␊ + ` + +## invalid(43): const foo = _([1,2,3]); const bar = foo.map(value => value); function unicorn() { return bar.includes(1); } > Input diff --git a/test/snapshots/prefer-set-has.js.snap b/test/snapshots/prefer-set-has.js.snap index a64ffa14947e01e9fdc08e006bcbcf2b4ebf9247..59b6e11901c42ad3d59c072cd2ebd4df20406ea0 100644 GIT binary patch literal 2772 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 aKPsG^qTb;Eu8B!BH~$9|b@h0EdjJ50`d6+1 literal 2718 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 Date: Tue, 25 Nov 2025 03:04:48 +0700 Subject: [PATCH 2/3] Update prefer-set-has.js --- rules/prefer-set-has.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/rules/prefer-set-has.js b/rules/prefer-set-has.js index ca4b36660c..5825ba352b 100644 --- a/rules/prefer-set-has.js +++ b/rules/prefer-set-has.js @@ -10,10 +10,9 @@ const messages = { }; /* -Some of these methods can be `Iterator` -Since `Iterator` don't have an `includes()` method -We are safe to assume they are array. -Except `concat` and `slice` which can be an string, https://github.com/sindresorhus/eslint-plugin-unicorn/issues/2216 . +Some of these methods can be `Iterator`. + +Since `Iterator` don't have an `includes()` method, we are safe to assume they are array. Except `concat` and `slice` which can be a string: https://github.com/sindresorhus/eslint-plugin-unicorn/issues/2216 */ const methodsReturnsArray = [ // `Array` From 9c0fbc80ff91b05e10738ca0b8632cfbf8ababb3 Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Tue, 25 Nov 2025 04:40:38 +0800 Subject: [PATCH 3/3] Remove c8 from snapshot update command --- .github/workflows/update-snapshots.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-snapshots.yml b/.github/workflows/update-snapshots.yml index bfcb3c3e2e..69d4835859 100644 --- a/.github/workflows/update-snapshots.yml +++ b/.github/workflows/update-snapshots.yml @@ -19,7 +19,7 @@ jobs: - run: npm run lint - run: rm -rf test/snapshots # Force update snapshots, https://github.com/avajs/ava/discussions/2754 - - run: npx c8 ava --update-snapshots + - run: npx ava --update-snapshots env: AVA_FORCE_CI: not-ci - uses: autofix-ci/action@v1