Closed epreston closed 1 year ago
The issue with leaving these undetected is that it causes another rule, remove-unused-variables
, to incorrectly determine that a variable is unused. For example, "a" will incorrectly be matched as unused but it is used as the condition of the first "if statement".
let a = true;
let b = false;
if ((console.log('one'), console.log('two'), a)) {
console.log('three');
b = true;
if (b) {
console.log('four');
}
}
Just landed support of SequenceExpressions
to @putout/plugin-remove-unused-variables
v4.2.0
. Is it works for you?
About
let a = true;
if (console.log('one'), console.log('two'), a) {
console.log('three')
}
What if if
would be a part of while
for example
let a = true;
for (const b of c)
if (console.log('one'), console.log('two'), a) {
console.log('three')
}
In this case we should check that parent of IfStatement
is BodyBlock
, and if it's not we should create it. Also SequenceExpression
can be part of WhileStatement
and all kinds of For
-loops etc.
I don't think that this is very popular case, but sounds interesting. How did it get to your codebase?
Can confirm that plugin-remove-unused-variables
now correctly detects the usage of a variable when:
This is the edge case where some control statements, "if statements" in this case, will evaluate the last expression in a sequence as its condition. Little known but valid javascript.
To answer your question: Older Vue 2 templates promoted a style of javascript that required a factory pattern that leads to these hard to spot issues. It looks like an "if statement" with a complicated expression, but, its actually one or two simple statements, comma separated in a sequence, with trailing expression for the "if statement" to evaluate. Over a a large project this created 80+ false flags for unused variables.
You are right about "left" associating single line control statements where the BodyBlock
is optional. If there is no block, one will have to be made. "for, while, if" maybe others will use the following statement as its body without a BodyBlock
.
I'd be excited to see if we can hoist out these sequence expressions. Helpful if someone puts a comma in the wrong place creating a sequence expression when they mean to combine a condition into a larger expression for the control block. It would be neat to hit save and see the statement get ejected above on its own line.
OK, it can be something like this, but I think about more cases that can be counted (while
, for
, for-of
, for-in
, switch
... did I miss something?).
You can make a 🐊Putout plugin from this draft, and install it separately. There is a yoman generator for this purpose that simplifies things a lot :).
Well, about loops, it changes behavior of code, so can be skipped, what statements besides if
do you think should be supported?
I'd be excited to see if we can hoist out these sequence expressions. Helpful if someone puts a comma in the wrong place creating a sequence expression when they mean to combine a condition into a larger expression for the control block. It would be neat to hit save and see the statement get ejected above on its own line.
Landed in @putout/plugin-extract-sequence-expressions@3.5.0
🎉. Is it works for you?
It works well.
I'm going to write out some detailed bits so we have a good record of test overage, environment, versions.
module | version |
---|---|
putout | "28.3.0" |
@putout/plugin-extract-sequence-expressions | "3.5.0" |
@putout/plugin-logical-expressions | "1.2.0" |
language | files | code | comment | blank | total |
---|---|---|---|---|---|
JavaScript | 283 | 50,763 | 2,617 | 6,566 | 59,946 |
94 errors in 50 files
BodyBlock
BodyBlock
if required, then hoists the sequence statements above leaving the condition"For Statement" example for clarity:
for (let n = 0; n < t.length; n++)
if (((i = '(' + e + ': ' + t[n] + ')'), window.matchMedia(i).matches)) return t[n];
Is transformed into the more readable equivalent:
for (let n = 0; n < t.length; n++) {
i = '(' + e + ': ' + t[n] + ')';
if (window.matchMedia(i).matches) return t[n];
}
One class of sequence expressions missed by the
extract-sequence-expressions
rule (or some other rule for this purpose) is when the sequence statements are tucked into an "if expression'. For example:This is equivalent and more clearly written as:
Javascript returns the last expression in the sequence for evaluation in the "if expression".