-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
feat(eslint-plugin): [no-array-delete] add rule #5852
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
Closed
mahdi-farnia
wants to merge
32
commits into
typescript-eslint:main
from
mahdi-farnia:no-array-delete
Closed
Changes from all commits
Commits
Show all changes
32 commits
Select commit
Hold shift + click to select a range
6ec086d
Complete Super Method Checking
mahdi-farnia 31be88c
Update packages/eslint-plugin/docs/rules/call-super-on-override.md
mahdi-farnia 5138d1d
Update packages/eslint-plugin/src/rules/call-super-on-override.ts
mahdi-farnia b8444c3
Update packages/eslint-plugin/src/rules/call-super-on-override.ts
mahdi-farnia a31ade2
Unnecessary ignoreMethods Option Removed
mahdi-farnia 2b65003
Support For Literal Method Names
mahdi-farnia ab81978
Merge branch 'typescript-eslint:main' into main
mahdi-farnia 1fe9429
Merge branch 'typescript-eslint:main' into main
mahdi-farnia 7f588b3
Merge remote-tracking branch 'refs/remotes/origin/main'
mahdi-farnia 35c527c
Merge branch 'typescript-eslint:main' into main
mahdi-farnia e95c87f
Resolve Failed CI Tests & TopLevel Option Removed
mahdi-farnia 4e9da68
Rule no-in-array
mahdi-farnia 75c1979
Rule no-array-delete Completed
mahdi-farnia 8d31382
Merge branch 'main' into no-array-delete
JoshuaKGoldberg f397a33
remove unneeded files from other branch
mahdi-farnia c32bb0a
remove unneeded files from other branch
mahdi-farnia 0b59dc6
Apply Suggested Changes
mahdi-farnia bf6b1b6
Merge branch 'main' into no-array-delete
mahdi-farnia b08dd24
Merge branch 'main' into no-array-delete
mahdi-farnia b7d976c
apply suggested changes
mahdi-farnia 264df53
Merge branch 'no-array-delete' of github.com:mahdi-farnia/typescript-…
mahdi-farnia ab27b88
more test & fix sequence expr suggestions
mahdi-farnia 41e88c2
Merge branch 'main' into no-array-delete
mahdi-farnia e4689f0
Fix Unit Test & Lint Test Errors
mahdi-farnia 7f3a68d
Fix spacing causing unit test error
mahdi-farnia 7fe1ee9
Merge branch 'main' into no-array-delete
mahdi-farnia de0a0b8
fix linting problem in test file
mahdi-farnia a3290ec
reduce amount of type request
mahdi-farnia b5d99e0
apply suggested changes
mahdi-farnia 8230f09
Update no-array-delete.md
bradzacher 2392654
make doc more clearer
mahdi-farnia 04ec031
fix(no-array-delete): buggy suggestion
mahdi-farnia 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,37 @@ | ||
--- | ||
description: 'Disallow delete operator for arrays.' | ||
--- | ||
|
||
> 🛑 This file is source code, not the primary documentation location! 🛑 | ||
> | ||
> See **https://typescript-eslint.io/rules/no-array-delete** for documentation. | ||
|
||
In JavaScript, using the `delete` operator on an array makes the given index empty and leaves the array length unchanged. | ||
See [MDN's _Deleting array elements_ documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete#deleting_array_elements) for more information. | ||
This can sometimes cause problems with performance and unexpected behaviors around array loops and index accesses. | ||
|
||
## Examples | ||
|
||
<!--tabs--> | ||
|
||
### ❌ Incorrect | ||
|
||
```ts | ||
declare const array: unknown[]; | ||
declare const index: number; | ||
|
||
delete array[index]; | ||
``` | ||
|
||
### ✅ Correct | ||
|
||
```ts | ||
declare const array: unknown[]; | ||
declare const index: number; | ||
|
||
array.splice(index, 1); | ||
``` | ||
|
||
## When Not To Use It | ||
|
||
If you don't care about having empty element in array, then you will not need this rule. |
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,91 @@ | ||
import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; | ||
import { AST_NODE_TYPES } from '@typescript-eslint/utils'; | ||
import { unionTypeParts } from 'tsutils'; | ||
import * as ts from 'typescript'; | ||
|
||
import * as util from '../util'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. util should probably be switched to named imports |
||
|
||
type MessageIds = 'arrayDelete' | 'suggestFunctionalDelete'; | ||
|
||
export default util.createRule<[], MessageIds>({ | ||
name: 'no-array-delete', | ||
meta: { | ||
hasSuggestions: true, | ||
docs: { | ||
description: 'Disallow delete operator for arrays', | ||
recommended: 'strict', | ||
requiresTypeChecking: true, | ||
}, | ||
messages: { | ||
arrayDelete: 'Using the delete operator on an array is dangerous.', | ||
suggestFunctionalDelete: | ||
'Using Array.slice instead of delete keyword prevents empty array element.', | ||
}, | ||
schema: [], | ||
type: 'problem', | ||
fixable: 'code', | ||
}, | ||
defaultOptions: [], | ||
create(context) { | ||
const parserServices = util.getParserServices(context); | ||
const checker = parserServices.program.getTypeChecker(); | ||
|
||
return { | ||
"UnaryExpression[operator='delete'] > MemberExpression[computed]"( | ||
node: TSESTree.MemberExpressionComputedName & { | ||
parent: TSESTree.UnaryExpression; | ||
}, | ||
): void { | ||
const originalNode = parserServices.esTreeNodeToTSNodeMap.get(node); | ||
|
||
const target = originalNode.getChildAt(0); | ||
const key = originalNode.getChildAt(2); | ||
|
||
const targetType = util.getConstrainedTypeAtLocation(checker, target); | ||
|
||
if (!isTypeArrayTypeOrArrayInUnionOfTypes(targetType, checker)) { | ||
return; | ||
} | ||
|
||
const keyType = util.getConstrainedTypeAtLocation(checker, key); | ||
|
||
if (!util.isTypeFlagSet(keyType, ts.TypeFlags.NumberLike)) { | ||
return; | ||
} | ||
|
||
context.report({ | ||
node, | ||
messageId: 'arrayDelete', | ||
suggest: [ | ||
mahdi-farnia marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
messageId: 'suggestFunctionalDelete', | ||
fix(fixer): TSESLint.RuleFix | null { | ||
const requiresParens = | ||
node.property.type === AST_NODE_TYPES.SequenceExpression; | ||
const keyText = key.getText(); | ||
|
||
if (util.isTypeFlagSet(keyType, ts.TypeFlags.String)) { | ||
return null; | ||
} | ||
|
||
return fixer.replaceText( | ||
node.parent, | ||
`${target.getText()}.splice(${ | ||
requiresParens ? `(${keyText})` : keyText | ||
}, 1)`, | ||
); | ||
}, | ||
}, | ||
], | ||
}); | ||
}, | ||
}; | ||
}, | ||
}); | ||
|
||
function isTypeArrayTypeOrArrayInUnionOfTypes( | ||
type: ts.Type, | ||
checker: ts.TypeChecker, | ||
): boolean { | ||
return unionTypeParts(type).some(checker.isArrayType); | ||
} |
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.