Skip to content
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

fix(lint/useOptionalChain): incorrect fix for optional chaining #2127

Merged
merged 5 commits into from
Mar 19, 2024

Conversation

arendjr
Copy link
Contributor

@arendjr arendjr commented Mar 18, 2024

Summary

This was a pretty rough rule to get into. I even considered whether it wasn't easier to rewrite the logic, but thankfully that wasn't necessary. I do still wonder whether it wouldn’t be easier to just match directly against previous arms of a logical expression, instead of putting everything into queues. The ideal fix for the expression foo && foo.bar?.baz && foo.bar?.qux is foo?.bar?.baz && foo.bar.qux. However, I didn’t get further than the same fix offered by ESLint: foo?.bar?.baz && foo.bar?.qux
But with the way the queues and the sorting enum work it isn’t really feasible to match against previous arms that are not strictly decreasing in length. Anyway, that’s a lot of rambling for saying I have a fix, but I didn’t manage to get the ideal solution yet :)

Sorry the diff is a bit larger, since I updated the documentation and some variable names in my process of trying to understand the rule. I'll leave a comment for the part that's really relevant.

Fixes #1925 (cc @Sec-ant)

Test Plan

Added test cases.

@github-actions github-actions bot added A-Linter Area: linter L-JavaScript Language: JavaScript and super languages labels Mar 18, 2024
Copy link

netlify bot commented Mar 18, 2024

Deploy Preview for biomejs ready!

Name Link
🔨 Latest commit 20eddee
🔍 Latest deploy log https://app.netlify.com/sites/biomejs/deploys/65f94dbc8d50bc0008f9b80d
😎 Deploy Preview https://deploy-preview-2127--biomejs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 94 (🔴 down 6 from production)
Accessibility: 97 (no change from production)
Best Practices: 100 (no change from production)
SEO: 93 (no change from production)
PWA: -
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify site configuration.

// If the previous branch had other expressions that already
// included the optional chaining operators, we need to
// include them as well.
if let Some(mut prev_branch) = prev_branch {
Copy link
Contributor Author

@arendjr arendjr Mar 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This block provides the real fix, together with a similar looking one a little bit below.

I'm not entirely happy with the repetition between these blocks, but I'm also afraid it's going to introduce even more boilerplate and hard-to-follow indirection if I try to share that (a closure won't help here because of borrowing rules).

@arendjr arendjr changed the title Fix incorrect fix for optional chaining fix(lint/useOptionalChain): incorrect fix for optional chaining Mar 18, 2024
@github-actions github-actions bot added A-Website Area: website A-Changelog Area: changelog labels Mar 18, 2024
Copy link

codspeed-hq bot commented Mar 18, 2024

CodSpeed Performance Report

Merging #2127 will not alter performance

Comparing arendjr:fix-incorrect-optional-chaining-fix (20eddee) with main (98d53ae)

Summary

✅ 93 untouched benchmarks

Comment on lines 263 to 290
/// `LogicalAndChainOrdering` is the result of a comparison between two logical and chain.
/// `LogicalAndChainOrdering` is the result of a comparison between two logical
/// AND chains.
enum LogicalAndChainOrdering {
/// An ordering where a chain is a sub-chain of another.
///
/// ```js
/// (foo && foo.bar) /* is sub-chain of */ (foo && foo.bar && foo.bar.baz)
/// ```
///
/// Chains can be considered subchains even when they have unequal
/// optional chaining internally. For instance:
///
/// ```js
/// (foo?.bar) /* is also a sub-chain of */ (foo?.bar && foo.bar.baz)
/// ```
SubChain,
/// An ordering where a chain is equal to another.
/// ```js
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I may be wrong, but the comments here are confusing. I think the LogicalAndChainOrdering is the result of comparing two dot-notation chains appearing on each side of a && operator, e.g. a.b && a.b.c or a?.b && a.b.c, where a.b or a?.b is considered a subchain of a.b.c. That's also how LogicalAndChain::cmp_chain is implemented.

The names are really confusing though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, your understanding is correct. What do feel is the confusing part? The fact it’s called a subchain at all, or the comment I added? I know it took me quite a while to understand as well, so I would be happy if we can improve the wording or naming.

Copy link
Member

@Sec-ant Sec-ant Mar 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do feel is the confusing part?

I think we should change the particular examples here to:

 /// An ordering where a chain is a sub-chain of another.
 ///
 /// ```js
-/// (foo && foo.bar) /* is sub-chain of */ (foo && foo.bar && foo.bar.baz)
+/// (foo.bar) /* is a sub-chain of */ (foo.bar.baz)
 /// ```
 ///
 /// Chains can be considered subchains even when they have unequal
 /// optional chaining internally. For instance:
 ///
 /// ```js
-/// (foo?.bar) /* is also a sub-chain of */ (foo?.bar && foo.bar.baz)
+/// (foo?.bar) /* is also a sub-chain of */ (foo.bar.baz)
 /// ```

And maybe we should use other terms (instead of "sub-chain") for a && a.b vs a && a.b && a.b.c to discriminate && chains and . chains? 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yes, good suggestions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about what’s a better word for subchain yet though… Maybe best to leave it for now.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah naming is hard. I think just updating the examples would be enough for now.

Comment on lines +103 to +106
i Unsafe fix: Change to an optional chain.

7 │ foo?.bar·&&·foo.bar?.baz·&&·foo.bar?.qux;
│ -----------
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been wondering this since my previous attempt to fix this rule: Why sometimes the suggested fix doesn't provide a diff (like what it does in the following diagnostics)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yes, that tripped me in the beginning too. The trick is, when it only removes characters it is indicated by minuses below. Once you know it is a bit clearer, but it is not intuitive at first, I agree.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh wow, thanks for the explanation, this is so much clearer now! I originally misunderstood those minus signs as underlines to indicate which part of the expression should be fixed.🤦

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know, I had the exact same experience 😅

@arendjr arendjr merged commit c10688c into biomejs:main Mar 19, 2024
16 of 17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Changelog Area: changelog A-Linter Area: linter A-Website Area: website L-JavaScript Language: JavaScript and super languages
Projects
None yet
Development

Successfully merging this pull request may close these issues.

💅 incorrect fix for lint/complexity/useOptionalChain rule.
2 participants