Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork2.8k
fix(eslint-plugin): [no-unused-vars] clear error report range#8640
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
fix(eslint-plugin): [no-unused-vars] clear error report range#8640
Uh oh!
There was an error while loading.Please reload this page.
Conversation
Thanks for the PR,@developer-bandi! typescript-eslint is a 100% community driven project, and we are incredibly grateful that you are contributing to that community. The core maintainers work on this in their personal time, so please understand that it may not be possible for them to review your work immediately. Thanks again! 🙏Please, if you or your company is finding typescript-eslint valuable, help us sustain the project by sponsoring it transparently onhttps://opencollective.com/typescript-eslint. |
netlifybot commentedMar 10, 2024 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
✅ Deploy Preview fortypescript-eslint ready!
To edit notification comments on pull requests, go to yourNetlify site configuration. |
nx-cloudbot commentedMar 10, 2024 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
codecovbot commentedMar 10, 2024 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@## main #8640 +/- ##==========================================- Coverage 87.40% 87.21% -0.19%========================================== Files 260 251 -9 Lines 12605 12308 -297 Branches 3937 3880 -57 ==========================================- Hits 11017 10735 -282+ Misses 1313 1303 -10+ Partials 275 270 -5
Flags with carried forward coverage won't be shown.Click here to find out more.
|
yeonjuan commentedMar 10, 2024 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Hi@developer-bandi , I think it would be nice to explicitly specify
{messageId:'unusedVar',line:3,column:1,endColumn:3,<<<<<<<add `endColumn`onsometestcasesdata:{varName:'foo',action:'assigned a value',additional:'',},}, |
developer-bandi commentedMar 10, 2024 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
@yeonjuan thank you, i add test case with
|
const node = writeReferences.length | ||
? writeReferences[writeReferences.length - 1].identifier | ||
: unusedVar.identifiers[0]; | ||
const { start } = node.loc; | ||
const nodeVariableLength = node.name.length; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
👍 What do you think about changing the variable names a bit?
constnode=writeReferences.length | |
?writeReferences[writeReferences.length-1].identifier | |
:unusedVar.identifiers[0]; | |
const{ start}=node.loc; | |
constnodeVariableLength=node.name.length; | |
constid=writeReferences.length | |
?writeReferences[writeReferences.length-1].identifier | |
:unusedVar.identifiers[0]; | |
const{ start}=node.loc; | |
constidLength=node.name.length; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
it make sense, so i change variable name. thank you!
node: writeReferences.length | ||
? writeReferences[writeReferences.length - 1].identifier | ||
: unusedVar.identifiers[0], | ||
node, |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
Uh oh!
There was an error while loading.Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
i delete node. thank you!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Ah, looking closer at this... I may have led you astray, at least partially. Sorry about that! The test failures in CI are due to having removed thenode
from the report, since some of the tests specifically check for the type of thenode
(the following function generates error assertions that demand anIdentifier
be reported on via thetype
field)
typescript-eslint/packages/eslint-plugin/tests/rules/no-unused-vars/no-unused-vars-eslint.test.ts
Lines 56 to 77 in584db29
/** | |
* Returns an expected error for assigned-but-not-used variables. | |
*@param varName The name of the variable | |
*@param [additional] The additional text for the message data | |
*@param [type] The node type (defaults to "Identifier") | |
*@returns An expected error object | |
*/ | |
functionassignedError( | |
varName:string, | |
additional='', | |
type=AST_NODE_TYPES.Identifier, | |
):TSESLint.TestCaseError<MessageIds>{ | |
return{ | |
messageId:'unusedVar', | |
data:{ | |
varName, | |
action:'assigned a value', | |
additional, | |
}, | |
type, | |
}; | |
} |
Now, it's still not clear to me that the value of thenode
is actually used in any way other than being tested, though, when theloc
is also provided. I ran into the same problem in#8874 and just removed thetype
from the test cases, but I'm not totally sure if that is sound.
My thought is
if it has no effect => we should remove thetype
from the test, since it's not testing anything at all, but it looks like it is
if it does have an effect => just putnode
back.
Maybe@JoshuaKGoldberg or@bradzacher will know for sure? Would either of you know whether there's any reason to provide a reportnode
ifloc
is being provided?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Yeah you only need to provide one or the other.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
@@ -419,10 +419,23 @@ export default createRule<Options, MessageIds>({ | |||
ref.from.variableScope === unusedVar.scope.variableScope, | |||
); | |||
const id = writeReferences.length |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Even though these branches collapse to do the same thing, I think it could be good to test both branches, in case one day they get separated (for example, to report different error messages)
What do you think about adding test cases with all 4 report loc fields for some cases like the following?
letfoo:number;
letfoo:number=1;foo=2;foo=3;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
(testing)
Could you also add a test case that uses thedeclare
modifier with the fullloc
data?
FYI - here and in other comments, there's probably no need to addnew test cases; modifying existing ones to have the fullloc
data would work too 🙂
This comment was marked as duplicate.
This comment was marked as duplicate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
In great shape - only thing remaining blocking merge is resolution of#8640 (comment) (by removing type from test cases). Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
8127873
intotypescript-eslint:mainUh oh!
There was an error while loading.Please reload this page.
cpojer commentedApr 30, 2024
I believe this change broke It now crashes here because I don't see a good reason why |
It does seem a very brittle that that plugin is depending on our private, internal implementation details like that. For example if we were to change the rule to report on a different node then the rule would similarly break. From the looks of it that's a horridly inefficient plugin too.
(1) is especially bad because it means you have multiple copies of the rule. i.e. if you use both This is a really unstable setup and I'm really not sure if we should be supporting usage of our private internals like that. I'm not sure I understand the point of the plugin - what is the usecase for separating out the imports from the regular variables? What's the benefit from working this way? |
cpojer commentedApr 30, 2024
Yup, I get your argument. In this case you could argue it keeps API shape compatibility with the corresponding rule in eslint, if you need a reason. The plugin comes with a fixer, which I run when hitting Note that the ESLint plugin has almost 2m downloads per week, and I'm sure many are using it while also using typescript-eslint, so you'll likely hear from more people soon. I'm just the one who lives on the bleeding edge :D cc@sweepline – would you be open to porting this rule into |
timtucker-dte commentedApr 30, 2024
@bradzacher we're using the plugin for auto-removing unused imports on save / build as well |
This comment has been minimized.
This comment has been minimized.
LeonsCd commentedApr 30, 2024 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
I ran into the same issue, and now it's just messed up the whole plugin. I don't think we should be doing these breaking updates. |
Let me be very clear: The other pluginmonkey patches eslint's API so it can hook into ourinternals. There is no breaking change here. If something builds on top of private implementation details and breaks when we change those details - that is not a breaking change. That fact is not up for debate. How to best remedy this is an open question that we shall discuss amongst the maintenance team and make a decision. |
HitkoDev commentedApr 30, 2024 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
To be clear: the plugin in question is used by almost 10% of Is there any good reason such functionality shouldn't be a part of |
JacobZyy commentedApr 30, 2024
mabe typescript-eslint can set a new rule named |
No, it's very unlikely that 1 in 10 of our users are using A more reliable metric would be something like Sourcegraph searches of open source repositories' At least in open source land, it seems more likely that the |
Two reasons. The first is that@typescript-eslint/no-unused-vars acts as an "extension rule" on top of the baseeslint/no-unused-vars rule. We don't add any major new functionality on top of base rules here. If you want that added, it'd be an issue for ESLint core. The reason why ESLint core isn't enthusiastically adding in the automatic removal of values is that it's actually a tricky thing to get right. Seemingly unused imports and variables can actually have side effects that change your code's behavior - which is very dangerous to have in an automatic rule fixer! Example of an import with a side effect: // a.jsletcount=0;console.log("Gotcha!");exportconstgetCount=()=>count; // b.js// Unused. Should we auto fix to...// import {} from "./a.js" ?// import "./a.js" ?// nothing at all?import{getCount}from"./a.js";console.log("Hi!"); Example of a variable with a side effect: letcount=0;exportfunctiongetNextCount(){return(count+=1);}// Unused. Should we auto-fix to...// getNextCount()// nothing at all?letunusedIsh=getNextCount(); Example of a variable without: functionhasNoSideEffect(){for(leti=0;i<9001**7;i+=1){}}// Unused. Should we auto-fix to...// hasNoSideEffect()// nothing at all?letalsoUnusedIsh=hasNoSideEffect() By using a plugin likeeslint-plugin-unused-imports, you explicitly are taking on the risk of changing code behavior due to side effects like that. Which, hey, might be a great sign about how you've structured your code 😄 nice job avoiding side effects! But lint rules can't make that assumption for the general case. One thing lint rulescan do is addsuggestions: which are likefixes but won't be applied automatically.Rule Change: Add support for suggestions for unused var tracks adding that on the ESLint side. That issue was accepted, assigned, and has an open pull request now! 🙌 For more info on the difference between afix and asuggestion, see: |
JoshuaKGoldberg commentedApr 30, 2024 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Given that:
...the "right" solution would be for Edit: that PR was merged the same minute as I posted this comment. Nice! |
Anyway, perour PR contributing guide, a previously-merged PR isn't the right place to discuss changes. We'd generally ask that bug reports and feature requests be reported as a standalone new issue so they're more discoverable. We get that this was a blocker for everyone using Locking this issue as this specific typescript-eslint PR doesn't need any more discussion. If more issues on the topic get filed I'll make sure they show up here. Cheers! |
The issue with an autofixer is that a lot of people run them on save. So imagine this:
There's many variations of this situation - the development loop is an inherently messy thing and there's no way for a static analysis tool to delineate between "unused and it should be deleted" and "unused but it should not be deleted". There's also the issue of side-effects that Josh mentioned. If you autofix delete an import or a variable - you can change runtime behaviour because side-effects are lost. There actually used to be a fixer for There's always scope to introduce an optional fixer for people to opt-in to the danger / annoyance. But as Josh mentioned the rule is intended to be a TS-compatible replacement for the base rule. Whilst itis a complete rewrite - the options, features and reports of the rule are the same. |
Uh oh!
There was an error while loading.Please reload this page.
PR Checklist
Overview
clear error range in
no-unused-vars
rule