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

feat: add noUselessStringConcat rule #2720

Merged
merged 17 commits into from
May 6, 2024

Conversation

michellocana
Copy link
Contributor

@michellocana michellocana commented May 5, 2024

Implementation of the no-useless-concat ESLint rule in Biome.
Closes #2622

Summary

The rule handle many ways to express an useless concatenation and tries to fix the problem when the fix is safe to apply.

Invalid case Fix suggestion
const a = 'a' + 'b' const·a·=·"ab"
const a = 'a' + 'b' + 'c' const·a·=·"abc"
const a = 'a' + ('b' + 'c') const·a·=·"abc"
const a = ('a' + 'b') + 'c' const·a·=·"abc"
const a = 'a' + `b` const·a·=·"ab"
const a = `a` + 'b' const·a·=·"ab"
const a = `a` + `b` const·a·=·"ab"
const a = 'a' + 1 const·a·=·"a1"
const a = 1 + '1' const·a·=·"11"
const a = 1 + `1` const·a·=·"11"
const a = `1` + 1 const·a·=·"11"

Special case 1: foo + 'a' + 'b' + 'c'

The expression foo + 'a' might result in different string values depending of the value of foo, so we don't merge 'a' with 'bc' to preserve the expression result.

Invalid case Fix suggestion
const a = foo + 'a' + 'b' + 'c' const·a·=·foo·+·'a'·+·"bc"
const a = (foo + 'a') + ('b' + 'c') const·a·=·(foo·+·'a')·+·("bc")
const a = ((foo + 'a') + ('b' + 'c') + 1) const·a·=·((foo·+·'a')·+·("bc")·+·1)

Special case 2: const a = 1 + 1 + ""

We can't automatically infer the value of all expressions, so we don't suggest a fix unless we are sure of the expression result.

Test Plan

Added snapshots, for valid and invalid cases according to the no-useless-concat ESLint tests.

@github-actions github-actions bot added A-CLI Area: CLI A-Project Area: project A-Linter Area: linter L-JavaScript Language: JavaScript and super languages A-Diagnostic Area: diagnostocis labels May 5, 2024
Copy link

codspeed-hq bot commented May 5, 2024

CodSpeed Performance Report

Merging #2720 will not alter performance

Comparing michellocana:feat/no-useless-concat (37408c9) with main (b9f90b7)

Summary

✅ 85 untouched benchmarks

@ematipico
Copy link
Member

I haven't checked the code yet, but my first feedback is to change the name of the rule. At that beginning I thought it was about array concat: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat

What about noUselessConcatenation?

@Conaclos
Copy link
Member

Conaclos commented May 5, 2024

What about noUselessConcatenation?

Or noUselessStringConcat

Copy link
Contributor

@arendjr arendjr left a comment

Choose a reason for hiding this comment

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

Nice work!

Just left some questions and nits. As for the rule name itself, I think my vote would also be for noUselessStringConcatenation.


i Consider turning the expression into a single string to improve readability and runtime performance.

i Unsafe fix: Remove the useless concatenation
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is the fix unsafe?

Copy link
Contributor Author

@michellocana michellocana May 5, 2024

Choose a reason for hiding this comment

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

While implemented this rule, I realized string concatenations can get very weird sometimes in JS, so I decided to consider the fix "unsafe" because there's a small chance that a weird concatenation pattern can result in an incorrect fix that I didn't anticipate. However, I don't know the correct approach of fix categorization in these cases, so let me know if you want me to change to safe.

Copy link
Member

Choose a reason for hiding this comment

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

This is a safe assumption :) We could re-assess the fix category once many users have tested the rule.

3 3 │ const a = 'a' + ('b' + 'c')
4 4 │ const a = ('a' + 'b') + 'c'
5 │ - const·a·=·foo·+·'a'·+·'b'·+·'c'
5 │ + const·a·=·foo·+·'a'·+·"bc"
Copy link
Contributor

Choose a reason for hiding this comment

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

I’m not sure I fully understand the reason we can’t merge 'a' with the other strings. Regardless of the value of foo, wouldn’t the end result always end in "abc"?

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 was sure of that too, until I realized that {} + 'abc' is different from {} + 'a' + 'bc' in browser environments:
Browsers:

{} + 'abc' // NaN
{} + 'a' + 'bc' // "NaNbc"

Weirdly enough, the result is totally different in Node:

{} + 'a' + 'bc' // "[object Object]abc"
{} + 'abc' // "[object Object]abc"

@michellocana michellocana force-pushed the feat/no-useless-concat branch 2 times, most recently from a17fc13 to 62dc5c6 Compare May 5, 2024 20:05
@michellocana
Copy link
Contributor Author

What about noUselessConcatenation?

Or noUselessStringConcat

@ematipico @arendjr @Conaclos renamed to noUselessStringConcat

@arendjr
Copy link
Contributor

arendjr commented May 6, 2024

Could you add a changelog entry also?

@Conaclos Conaclos changed the title feat: add noUselessConcat rule feat: add noUselessStringConcat rule May 6, 2024
@github-actions github-actions bot added the A-Changelog Area: changelog label May 6, 2024
@michellocana
Copy link
Contributor Author

Could you add a changelog entry also?

Yup, done @arendjr!

@Conaclos Conaclos merged commit a8b3d8c into biomejs:main May 6, 2024
11 checks passed
@Conaclos
Copy link
Member

Conaclos commented May 6, 2024

@michellocana Thanks!

@Sec-ant
Copy link
Member

Sec-ant commented May 6, 2024

This rule lacks a fix_kind and thus fails the CI in the website repo: https://github.com/biomejs/website/actions/runs/8968865501/job/24629152214#step:8:275

@michellocana
Copy link
Contributor Author

This rule lacks a fix_kind and thus fails the CI in the website repo: https://github.com/biomejs/website/actions/runs/8968865501/job/24629152214#step:8:275

Oh, sorry about that, fixed it here #2748

@Sec-ant
Copy link
Member

Sec-ant commented May 6, 2024

Oh, sorry about that, fixed it here #2748

No need to apologize, thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Changelog Area: changelog A-CLI Area: CLI A-Diagnostic Area: diagnostocis A-Linter Area: linter A-Project Area: project L-JavaScript Language: JavaScript and super languages
Projects
None yet
Development

Successfully merging this pull request may close these issues.

📎 Implement noUselessStringConcat - no-useless-concat
5 participants