From 305a77285eecdb8175bfdb05c5bae8d19cf1589e Mon Sep 17 00:00:00 2001 From: fisker Date: Fri, 5 Dec 2025 23:27:55 +0800 Subject: [PATCH 1/3] Add test --- test/no-useless-collection-argument.js | 2 ++ .../no-useless-collection-argument.js.md | 19 ++++++++++++++++++ .../no-useless-collection-argument.js.snap | Bin 1103 -> 1136 bytes 3 files changed, 21 insertions(+) diff --git a/test/no-useless-collection-argument.js b/test/no-useless-collection-argument.js index 848d51cdf6..f8bdf58178 100644 --- a/test/no-useless-collection-argument.js +++ b/test/no-useless-collection-argument.js @@ -71,5 +71,7 @@ test.snapshot({ 'new Set([] ?? "")', 'new Set( (( (( "" )) ?? (( [] )) )) )', 'new Set(foo ?? bar ?? [])', + // Comments + 'new Set([/**/])', ], }); diff --git a/test/snapshots/no-useless-collection-argument.js.md b/test/snapshots/no-useless-collection-argument.js.md index d452c799db..93e2c86a03 100644 --- a/test/snapshots/no-useless-collection-argument.js.md +++ b/test/snapshots/no-useless-collection-argument.js.md @@ -516,3 +516,22 @@ Generated by [AVA](https://avajs.dev). Output:␊ 1 | new Set(foo ?? bar)␊ ` + +## invalid(18): new Set([/**/]) + +> Input + + `␊ + 1 | new Set([/**/])␊ + ` + +> Error 1/1 + + `␊ + Message:␊ + > 1 | new Set([/**/])␊ + | ^^^^^^ The empty array is useless.␊ + ␊ + Output:␊ + 1 | new Set()␊ + ` diff --git a/test/snapshots/no-useless-collection-argument.js.snap b/test/snapshots/no-useless-collection-argument.js.snap index ddd014077190318ced6532c4c0a445caad973e72..2838eef5f75aff562ea685068b54d2c729a5b030 100644 GIT binary patch literal 1136 zcmV-$1dsbcRzVXnL!T?;RZ1>xOT<95`RNSZM!xE)*{H zTrLt)B|EI7NG)TDTJ(wCZ25tx2}Dc9IqG@F3Y{rF;?#r?vO~h(!UB1|N(o(W`rE{C zU1OV=9%*^hqMkQaEIw`d&6Yotm_;}T^ReqXE~!?kNt-psrly_Rrlz4bH-KnaWV5Z7 z*z|nYv{!QZ-0BaFPB2DWcAYj%o7NG(I+*&6#6YnUv%L$nO_6P;NYZ`q>p)nH{@-Fg z2E8GJdkh1+Wm$;*L15u(VvLRmbM63{A##4A=S`pZZU1Xdt2aZdlY!M2)L0X?@GzM5 zHD(k>hS}W#LL0NoR)B`p+BvM3-qKTn^*N(?+LJ4gD4txQI`7HVu9IPjromy%>P>;T^Dt9T!SN^c4ZMFwtqde z{{URhWyHA#rhkRIoy&Rdt&aRm@8_-CQ4SgBm%5Ctwfy3Wm5Q4^QRF|Yc0U%y8jeF| zX9?QtassguBd`y&o`?WbgztD|3Ju4}fT6}?KoeUg41(Zx0JMGz20p*#i*Zs8!&s6F zCL#-T6<}!q$05&khir*+`-K!N!hF|_m?vdKu%s8vN)Y%)0iHe_k1+SW18O$~3>N>? zQ=pWDCJKVG1EdVx^dsp@eu#Vq`aM}JOgl*Og~V(J3L6yF&Q+*XJXaG%x^%7vRWt06 zWR6tdA?Y|W?vN}<)OScKnjt~VjHiUA%`sq(@CgLyF+86@g-nE1u$mc0JHZJX31g_V5+pjA;hT45vqyA*_E6h+K`g~*a&hOAZ0LY zM*!Pb=_!VlJd@oPk0c?eM+Di3U3ZpS>(utg49gN`hbo{qm>3=@fsy+S$bAu#!^)in zHFlgVpYoI76+;F{{3a6&vj5E2E>8)4iQDGK|X>5WW_+U{HY|e+28!YwACqh%YJM9RL9R C91&~) literal 1103 zcmV-V1hD%-RzVJ)+#f^Ve8~63(S|VDwglimcQ%<{@!7uK?C|?;B4u9sq^bOSGv%1 zu}nyfZ1EvwX43^`v&T-W9fUzG5VTO9W4=$9*i8AM5KRanTO|6;&y#1%jIh;Kut})r z(M@9cr0p}C`Tl6R{G=VU+QCd}7ttQ9N1o?;q&8Md%dB%U4dd7{4Fi?A27(r4GCR=< znSS6|&Qc+r8~u^c2~KF+X|Sf{um+;n1Y5tBS}2LcWN(AmmP|I6B&|ODbs@Zt|L=7% z2E7r3yBq_jZQF?aK_KCBYK?9XrrZT#RHpnWUKD+#xAWJ6Qu`vQlcCh-jIKyqco^*Z z3bzUuhRNLmfet2@&j1DMwR4m&yQQZ>>2tJo+{qP&Xilyuy6EKU&pmmNyLuVrqFcV92n{%2Gp_T!XPnjdmuK*z##g!Vm406VHk6A z;YL)3ZVX5oz;UR3-9De<%x)0EsOd-CmwJeN2Jt&8TbMOSikZZG1BEw=dUF*nrz zVJ?)IVOZs8TNs~lpw1Baq%vTHeuAs$qx335vPr8*A5^l49M=f$WWxhA&F<#VddlD> zWGHfVBiT-{>vB|8CB{?(WkuJi6?9@1g;fWjhJ;fRb6}|c095;m(n9j7ic7z|xP@}` zW33LzjaM_Ushy#a0AuzIFnh0HmQJPsrb{bYLXN5$qnb#~uJr!UhMWYzMv!TMq`|Nq z0Bm2CQw&RaD%F;(q#$U<1bK_ya2MOF%n3%RZA-mF4bU4*EsvzY$o&T7zDUVo=}v- From a00524a4098e82c1baee9f3bc97cfc55af980263 Mon Sep 17 00:00:00 2001 From: fisker Date: Fri, 5 Dec 2025 23:30:02 +0800 Subject: [PATCH 2/3] Fix --- docs/rules/no-useless-collection-argument.md | 2 +- readme.md | 2 +- rules/no-useless-collection-argument.js | 52 ++++++++++++++---- .../no-useless-collection-argument.js.md | 2 +- .../no-useless-collection-argument.js.snap | Bin 1136 -> 1154 bytes 5 files changed, 44 insertions(+), 14 deletions(-) diff --git a/docs/rules/no-useless-collection-argument.md b/docs/rules/no-useless-collection-argument.md index acce08a208..c11a5d91a8 100644 --- a/docs/rules/no-useless-collection-argument.md +++ b/docs/rules/no-useless-collection-argument.md @@ -2,7 +2,7 @@ 💼 This rule is enabled in the following [configs](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config): ✅ `recommended`, ☑️ `unopinionated`. -🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). +🔧💡 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix) and manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions). diff --git a/readme.md b/readme.md index 0d5f824131..6e1c7561dc 100644 --- a/readme.md +++ b/readme.md @@ -120,7 +120,7 @@ export default [ | [no-unreadable-array-destructuring](docs/rules/no-unreadable-array-destructuring.md) | Disallow unreadable array destructuring. | ✅ ☑️ | 🔧 | | | [no-unreadable-iife](docs/rules/no-unreadable-iife.md) | Disallow unreadable IIFEs. | ✅ ☑️ | | | | [no-unused-properties](docs/rules/no-unused-properties.md) | Disallow unused object properties. | | | | -| [no-useless-collection-argument](docs/rules/no-useless-collection-argument.md) | Disallow useless values or fallbacks in `Set`, `Map`, `WeakSet`, or `WeakMap`. | ✅ ☑️ | 🔧 | | +| [no-useless-collection-argument](docs/rules/no-useless-collection-argument.md) | Disallow useless values or fallbacks in `Set`, `Map`, `WeakSet`, or `WeakMap`. | ✅ ☑️ | 🔧 | 💡 | | [no-useless-error-capture-stack-trace](docs/rules/no-useless-error-capture-stack-trace.md) | Disallow unnecessary `Error.captureStackTrace(…)`. | ✅ ☑️ | 🔧 | | | [no-useless-fallback-in-spread](docs/rules/no-useless-fallback-in-spread.md) | Disallow useless fallback when spreading in object literals. | ✅ ☑️ | 🔧 | | | [no-useless-length-check](docs/rules/no-useless-length-check.md) | Disallow useless array length check. | ✅ ☑️ | 🔧 | | diff --git a/rules/no-useless-collection-argument.js b/rules/no-useless-collection-argument.js index b6b5a4bd19..6be9a8b591 100644 --- a/rules/no-useless-collection-argument.js +++ b/rules/no-useless-collection-argument.js @@ -8,9 +8,16 @@ import { } from './ast/index.js'; import {removeParentheses, removeArgument} from './fix/index.js'; -const MESSAGE_ID = 'no-useless-collection-argument'; +/** +@import {TSESTree as ESTree} from '@typescript-eslint/types'; +@import * as ESLint from 'eslint'; +*/ + +const MESSAGE_ID_ERROR = 'no-useless-collection-argument/error'; +const MESSAGE_ID_SUGGESTION = 'no-useless-collection-argument/suggestion'; const messages = { - [MESSAGE_ID]: 'The {{description}} is useless.', + [MESSAGE_ID_ERROR]: 'The {{description}} is useless.', + [MESSAGE_ID_SUGGESTION]: 'Remove the {{description}}', }; const getDescription = node => { @@ -33,7 +40,7 @@ const getDescription = node => { const removeFallback = (node, context) => // Same code from rules/no-useless-fallback-in-spread.js - /** @param {import('eslint').Rule.RuleFixer} fixer */ + /** @param {ESLint.Rule.RuleFixer} fixer */ function * fix(fixer) { const {sourceCode} = context; const logicalExpression = node.parent; @@ -54,9 +61,9 @@ const removeFallback = (node, context) => } }; -/** @param {import('eslint').Rule.RuleContext} context */ +/** @param {ESLint.Rule.RuleContext} context */ const create = context => { - context.on('NewExpression', newExpression => { + context.on('NewExpression', (/** @type {ESTree.NewExpression} */ newExpression) => { if (!isNewExpression(newExpression, { names: ['Set', 'Map', 'WeakSet', 'WeakMap'], argumentsLength: 1, @@ -73,18 +80,40 @@ const create = context => { return; } - return { + let fix; + let shouldUseSuggestion = false; + if (isCheckingFallback) { + fix = removeFallback(node, context); + } else { + if (context.sourceCode.getCommentsInside(node).length > 0) { + shouldUseSuggestion = true; + } + + fix = fixer => removeArgument(fixer, node, context); + } + + const problem = { node, - messageId: MESSAGE_ID, + messageId: MESSAGE_ID_ERROR, data: {description}, - fix: isCheckingFallback - ? removeFallback(node, context) - : fixer => removeArgument(fixer, node, context), }; + + if (shouldUseSuggestion) { + problem.suggest = [ + { + messageId: MESSAGE_ID_SUGGESTION, + fix, + }, + ]; + } else { + problem.fix = fix; + } + + return problem; }); }; -/** @type {import('eslint').Rule.RuleModule} */ +/** @type {ESLint.Rule.RuleModule} */ const config = { create, meta: { @@ -94,6 +123,7 @@ const config = { recommended: 'unopinionated', }, fixable: 'code', + hasSuggestions: true, messages, }, }; diff --git a/test/snapshots/no-useless-collection-argument.js.md b/test/snapshots/no-useless-collection-argument.js.md index 93e2c86a03..5d73fe40a6 100644 --- a/test/snapshots/no-useless-collection-argument.js.md +++ b/test/snapshots/no-useless-collection-argument.js.md @@ -532,6 +532,6 @@ Generated by [AVA](https://avajs.dev). > 1 | new Set([/**/])␊ | ^^^^^^ The empty array is useless.␊ ␊ - Output:␊ + Suggestion 1/1: Remove the empty array:␊ 1 | new Set()␊ ` diff --git a/test/snapshots/no-useless-collection-argument.js.snap b/test/snapshots/no-useless-collection-argument.js.snap index 2838eef5f75aff562ea685068b54d2c729a5b030..2c41fa7e73c61de2d60ca181b09b22cc9dadbf31 100644 GIT binary patch literal 1154 zcmV-|1bzEKRzV_z&iAguf0(I5JHwE1>wYIZrxz53Hy{@_1>!FLe%en5a?^5nc z-_<-JWwOIc^3>33)S%DIcE|NZZ6K=U=c(gpOp--^v)NS( zY&x#3o6SrTb0=Kn2_ws;*K)`$_1yRr!3+rR1C ze*`Y)BH~;D)4vwGor_uSt)Bc`@8_+%K@ORWFLe=HYw^VuDkV32q{x3*?LjPxH7twF z%@MTM#RNhnMqnRk9UcLuNW9~vDKsoA1%^r-1De=UVc-O}1E6&iFvRm)wiqYmFp4EP zZz7^VR|1xXa2(=XcgU8wu%Ao7!p(PQ5%YwM2$uA`S#bj2IKVT2$UYBk=?R^cbE`pu(;ohrm)iK$4-PTbxhl z9+pCh>d6Wx)57>n0(VNBPox4y=qI>}K60-jq#Ab@$%6_9;o};^ldQLZs@j_zx}Oqw z#VTaEx{+#U*mWs(RUyDs2HQ&8)O5G26>O{u05uX@rFabt)gOTBP_VU-dZNuGzrC1& zQuJfF0?17k6R?SsVXOeg>>FVAUcf9`OaM%lmOlg^RWU#{6*;@2^FteQ8UPzZP6MP2 zhV2Mo`zk!eu#)Gp+rp6q1l52b8?o!wN~c9lcS17^ZgwaGdc%?7krEiW-+~9`t3Zem+5^&c{u_?y3s&+2He9qggG#_)Cfa){Q55f{4(}hd z10Mr(_puJ-6~kEl1-t2&xDUC7#rrBtL;6FeI{jzk-@G-==C)(1cY&|~hVMJT_aW(B zfGH+ICjExwjlpL%5U^r{{bFf+ymY#^b4HdWr1~WY@>ei1gN07BNgY?W%&xyGc|lv& U1|=@kBtN(Q16IiI1ppoZ0FrVt9smFU literal 1136 zcmV-$1dsbcRzVXnL!T?;RZ1>xOT<95`RNSZM!xE)*{H zTrLt)B|EI7NG)TDTJ(wCZ25tx2}Dc9IqG@F3Y{rF;?#r?vO~h(!UB1|N(o(W`rE{C zU1OV=9%*^hqMkQaEIw`d&6Yotm_;}T^ReqXE~!?kNt-psrly_Rrlz4bH-KnaWV5Z7 z*z|nYv{!QZ-0BaFPB2DWcAYj%o7NG(I+*&6#6YnUv%L$nO_6P;NYZ`q>p)nH{@-Fg z2E8GJdkh1+Wm$;*L15u(VvLRmbM63{A##4A=S`pZZU1Xdt2aZdlY!M2)L0X?@GzM5 zHD(k>hS}W#LL0NoR)B`p+BvM3-qKTn^*N(?+LJ4gD4txQI`7HVu9IPjromy%>P>;T^Dt9T!SN^c4ZMFwtqde z{{URhWyHA#rhkRIoy&Rdt&aRm@8_-CQ4SgBm%5Ctwfy3Wm5Q4^QRF|Yc0U%y8jeF| zX9?QtassguBd`y&o`?WbgztD|3Ju4}fT6}?KoeUg41(Zx0JMGz20p*#i*Zs8!&s6F zCL#-T6<}!q$05&khir*+`-K!N!hF|_m?vdKu%s8vN)Y%)0iHe_k1+SW18O$~3>N>? zQ=pWDCJKVG1EdVx^dsp@eu#Vq`aM}JOgl*Og~V(J3L6yF&Q+*XJXaG%x^%7vRWt06 zWR6tdA?Y|W?vN}<)OScKnjt~VjHiUA%`sq(@CgLyF+86@g-nE1u$mc0JHZJX31g_V5+pjA;hT45vqyA*_E6h+K`g~*a&hOAZ0LY zM*!Pb=_!VlJd@oPk0c?eM+Di3U3ZpS>(utg49gN`hbo{qm>3=@fsy+S$bAu#!^)in zHFlgVpYoI76+;F{{3a6&vj5E2E>8)4iQDGK|X>5WW_+U{HY|e+28!YwACqh%YJM9RL9R C91&~) From 5d1e93a33867d495d67bb729a576d05be24aa838 Mon Sep 17 00:00:00 2001 From: fisker Date: Mon, 8 Dec 2025 19:02:31 +0800 Subject: [PATCH 3/3] Fix test --- test/package.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/package.js b/test/package.js index a796a068cc..adeb0b7a1e 100644 --- a/test/package.js +++ b/test/package.js @@ -115,7 +115,12 @@ test('Every rule file has the appropriate contents', t => { const rulePath = path.join('rules', `${ruleName}.js`); const ruleContents = fs.readFileSync(rulePath, 'utf8'); - t.true(ruleContents.includes('/** @type {import(\'eslint\').Rule.RuleModule} */'), `${ruleName} includes jsdoc comment for rule type`); + t.true( + // TODO: Use `@import` instead of `import('eslint')` + ruleContents.includes('/** @type {import(\'eslint\').Rule.RuleModule} */') + || ruleContents.includes('/** @type {ESLint.Rule.RuleModule} */'), + `${ruleName} includes jsdoc comment for rule type`, + ); } });