-
-
Notifications
You must be signed in to change notification settings - Fork 417
Add no-useless-collection-argument rule
#2777
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
sindresorhus
merged 13 commits into
sindresorhus:main
from
fisker:no-useless-fallback-in-set-constructor
Oct 19, 2025
+798
−12
Merged
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
782ad67
Implement rule
fisker 2193ae5
Add docs
fisker 4c2c0f1
One more test
fisker b58b778
Check more cases
fisker f13b882
Rename
fisker 270aea5
Update docs
fisker 51fa983
Rename as `no-useless-collection-argument`
fisker 73cf23a
Update no-useless-collection-argument.md
sindresorhus b1f66db
Fix typos in comments for clarity
sindresorhus a37b5af
Update test/no-useless-collection-argument.js
fisker 5fef94a
Remove redundant test
fisker a81f78f
Update snapshot
fisker fed0ccd
Update snapshot
fisker File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| # Disallow useless values or fallbacks in `Set`, `Map`, `WeakSet`, or `WeakMap` | ||
|
|
||
| 💼 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). | ||
|
|
||
| <!-- end auto-generated rule header --> | ||
| <!-- Do not manually modify this header. Run: `npm run fix:eslint-docs` --> | ||
|
|
||
| It's unnecessary to pass an empty array or string when constructing a `Set`, `Map`, `WeakSet`, or `WeakMap`, since they accept nullish values. | ||
|
|
||
| It's also unnecessary to provide a fallback for possible nullish values. | ||
|
|
||
| ## Examples | ||
|
|
||
| ```js | ||
| // ❌ | ||
| const set = new Set([]); | ||
| // ❌ | ||
| const set = new Set(""); | ||
|
|
||
| // ✅ | ||
| const set = new Set(); | ||
| ``` | ||
|
|
||
| ```js | ||
| // ❌ | ||
| const set = new Set(foo ?? []); | ||
| // ❌ | ||
| const set = new Set(foo ?? ""); | ||
|
|
||
| // ✅ | ||
| const set = new Set(foo); | ||
| ``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| const isEmptyArrayExpression = node => | ||
| node.type === 'ArrayExpression' | ||
| && node.elements.length === 0; | ||
|
|
||
| export default isEmptyArrayExpression; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,101 @@ | ||
| import {isParenthesized, getParenthesizedRange} from './utils/index.js'; | ||
| import { | ||
| isNewExpression, | ||
| isEmptyArrayExpression, | ||
| isEmptyStringLiteral, | ||
| isNullLiteral, | ||
| isUndefined, | ||
| } from './ast/index.js'; | ||
| import {removeParentheses, removeArgument} from './fix/index.js'; | ||
|
|
||
| const MESSAGE_ID = 'no-useless-collection-argument'; | ||
| const messages = { | ||
| [MESSAGE_ID]: 'The {{description}} is useless.', | ||
| }; | ||
|
|
||
| const getDescription = node => { | ||
| if (isEmptyArrayExpression(node)) { | ||
| return 'empty array'; | ||
| } | ||
|
|
||
| if (isEmptyStringLiteral(node)) { | ||
| return 'empty string'; | ||
| } | ||
|
|
||
| if (isNullLiteral(node)) { | ||
| return '`null`'; | ||
| } | ||
|
|
||
| if (isUndefined(node)) { | ||
| return '`undefined`'; | ||
| } | ||
| }; | ||
|
|
||
| const removeFallback = (node, context) => | ||
| // Same code from rules/no-useless-fallback-in-spread.js | ||
| /** @param {import('eslint').Rule.RuleFixer} fixer */ | ||
| function * fix(fixer) { | ||
| const {sourceCode} = context; | ||
| const logicalExpression = node.parent; | ||
| const {left} = logicalExpression; | ||
| const isLeftObjectParenthesized = isParenthesized(left, sourceCode); | ||
| const [, start] = isLeftObjectParenthesized | ||
| ? getParenthesizedRange(left, sourceCode) | ||
| : sourceCode.getRange(left); | ||
| const [, end] = sourceCode.getRange(logicalExpression); | ||
|
|
||
| yield fixer.removeRange([start, end]); | ||
|
|
||
| if ( | ||
| isLeftObjectParenthesized | ||
| || left.type !== 'SequenceExpression' | ||
| ) { | ||
| yield * removeParentheses(logicalExpression, fixer, sourceCode); | ||
| } | ||
| }; | ||
|
|
||
| /** @param {import('eslint').Rule.RuleContext} context */ | ||
| const create = context => ({ | ||
| NewExpression(newExpression) { | ||
| if (!isNewExpression(newExpression, { | ||
| names: ['Set', 'Map', 'WeakSet', 'WeakMap'], | ||
| argumentsLength: 1, | ||
| })) { | ||
| return; | ||
| } | ||
|
|
||
| const [iterable] = newExpression.arguments; | ||
| const isCheckingFallback = iterable.type === 'LogicalExpression' && iterable.operator === '??'; | ||
| const node = isCheckingFallback ? iterable.right : iterable; | ||
| const description = getDescription(node); | ||
|
|
||
| if (!description) { | ||
| return; | ||
| } | ||
|
|
||
| return { | ||
| node, | ||
| messageId: MESSAGE_ID, | ||
| data: {description}, | ||
| fix: isCheckingFallback | ||
| ? removeFallback(node, context) | ||
| : fixer => removeArgument(fixer, node, context.sourceCode), | ||
| }; | ||
| }, | ||
| }); | ||
|
|
||
| /** @type {import('eslint').Rule.RuleModule} */ | ||
| const config = { | ||
| create, | ||
| meta: { | ||
| type: 'suggestion', | ||
| docs: { | ||
| description: 'Disallow useless values or fallbacks in `Set`, `Map`, `WeakSet`, or `WeakMap`.', | ||
| recommended: 'unopinionated', | ||
| }, | ||
| fixable: 'code', | ||
| messages, | ||
| }, | ||
| }; | ||
|
|
||
| export default config; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| import {getTester} from './utils/test.js'; | ||
|
|
||
| const {test} = getTester(import.meta); | ||
|
|
||
| // Useless value | ||
| test.snapshot({ | ||
| valid: [ | ||
| 'new Set()', | ||
| 'new Set', | ||
| 'new Set(foo)', | ||
| 'new Set(foo || [])', | ||
| 'new Set(foo && [])', | ||
| 'new Not_Set([])', | ||
| 'Set([])', | ||
| 'new Set([], extraArgument)', | ||
| 'new Set(...([]))', | ||
| 'new Set([""])', | ||
| 'new Set("not-empty")', | ||
| 'new Set(0)', | ||
| 'new ([])(Set)', | ||
| // Not checking | ||
| 'new globalThis.Set([])', | ||
| ], | ||
| invalid: [ | ||
| 'new Set([])', | ||
| 'new Set("")', | ||
| 'new Set(undefined)', | ||
| 'new Set(null)', | ||
| 'new WeakSet([])', | ||
| 'new Map([])', | ||
| 'new WeakMap([])', | ||
| 'new Set( (([])) )', | ||
| 'new Set([],)', | ||
| 'new Set( (([])), )', | ||
| ], | ||
| }); | ||
|
|
||
| // Fallbacks | ||
| test.snapshot({ | ||
| valid: [ | ||
| 'new Set(foo || [])', | ||
| 'new Set(foo && [])', | ||
| 'new Not_Set(foo ?? [])', | ||
| 'Set(foo ?? [])', | ||
| 'new Set(foo ?? [], extraArgument)', | ||
| 'new Set(...(foo ?? []))', | ||
| 'new Set(foo ?? [""])', | ||
| 'new Set(foo ?? "not-empty")', | ||
| 'new Set(foo ?? 0)', | ||
| 'new (foo ?? [])(Set)', | ||
| // Not checking | ||
| 'new globalThis.Set(foo ?? [])', | ||
| ], | ||
| invalid: [ | ||
| 'new Set(foo ?? [])', | ||
| 'new Set(foo ?? "")', | ||
| 'new Set(foo ?? undefined)', | ||
| 'new Set(foo ?? null)', | ||
| 'new WeakSet(foo ?? [])', | ||
| 'new Map(foo ?? [])', | ||
| 'new WeakMap(foo ?? [])', | ||
| 'new Set( ((foo ?? [])) )', | ||
| 'new Set( (( foo )) ?? [] )', | ||
| 'new Set( foo ?? (( [] )) )', | ||
| 'new Set( (await foo) ?? [] )', | ||
| 'new Set( (0, foo) ?? [] )', | ||
| 'new Set( (( (0, foo) ?? [] )) )', | ||
| // Who cares? | ||
| 'new Set(document.all ?? [])', | ||
| // Both sides are useless | ||
| 'new Set([] ?? "")', | ||
| 'new Set( (( (( "" )) ?? (( [] )) )) )', | ||
fisker marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| 'new Set(foo ?? bar ?? [])', | ||
| ], | ||
| }); | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.