ReScript Formatter Bug: Tagged Templates & Arrow Functions
Hey guys, there's a bit of an odd issue going on with the ReScript formatter that I wanted to bring to your attention. It seems like when you're using tagged template literals followed by an arrow expression, the formatter is deconstructing them into arrays. This isn't the intended behavior, and it can lead to some unexpected code transformations. Let's dive into the details and see what's happening.
The Issue: Tagged Template Literals Gone Wild
So, what's exactly happening? The ReScript formatter, in certain situations, is breaking down tagged template literals into arrays when they are immediately followed by an arrow expression. To be clear, tagged template literals are a powerful feature in ReScript (and JavaScript) that allow you to use a function to process template literals. This is super handy for things like building SQL queries or handling internationalization.
Imagine you have a tagged template literal like this:
sql`SELECT * FROM users WHERE id = ${userId}`
Normally, this would be processed by the sql function, allowing you to safely construct a query. However, when this is followed by an arrow expression, the formatter is turning it into something like this:
[`SELECT * FROM users WHERE id = `, ``], [userId]
This is definitely not what we want! It breaks the intended functionality of the tagged template literal and can lead to errors in your code. This transformation makes the code hard to read and defeats the purpose of using tagged templates in the first place. We expect the formatter to leave our tagged templates alone, especially when they are part of a chain of operations involving arrow functions.
The Specific Scenario: Arrow Expressions Trigger the Bug
The key trigger for this issue seems to be the presence of an arrow expression immediately following the tagged template literal. If the tagged literal is the last expression in a chain, the formatter behaves as expected. But when you introduce an arrow function, things go south quickly. This behavior has been observed in ReScript versions 11.1.4 and 12.0.0-rc.3, so it's not a recent regression.
To illustrate, let's look at a concrete example. Consider this piece of ReScript code:
sql
->SQL.query`INSERT INTO my_table (a, b, c) VALUES ${a}, ${b}, ${c}`
->Promise.thenResolve(Console.log)
Here, we're using a tagged template literal to construct an SQL query and then piping the result to a Promise. The expected behavior is that the SQL.query function processes the tagged template as is. However, the formatter steps in and transforms it into:
sql
->(
SQL.query(
[`INSERT INTO my_table (a, b, c) VALUES `, `, `, `, `, ``],
[a, b, c],
)
)
->Promise.thenResolve(Console.log)
See how the tagged template is now an array and a list of interpolated values? This is not what we want, guys! The arrow expression in the Promise.thenResolve part seems to be the culprit here. Removing the arrow expression or restructuring the code can prevent this, but it's clearly a formatter bug that needs addressing.
Expected vs. Actual: A Clear Discrepancy
What should happen? The expected behavior is that the formatter leaves the tagged template literal untouched. It should recognize that it's a special construct and not try to deconstruct it into an array. Tagged template literals are a deliberate language feature, and the formatter should respect their syntax and semantics. We rely on the formatter to make our code look consistent and readable, but in this case, it's actively changing the meaning of the code.
However, the actual behavior is that the formatter incorrectly transforms the tagged template literal into an array and a list of values. This breaks the intended logic and makes the code harder to understand. It also introduces a potential runtime error because the SQL.query function is now receiving a different input than it expects. This discrepancy between expected and actual behavior is a clear indication of a bug.
Playground Example: See It in Action
If you want to see this in action, head over to the ReScript playground. There's a live example that demonstrates the issue:
Just paste the code into the playground, and you'll see the formatter deconstructing the tagged template literal when it's followed by the arrow expression. This is a quick and easy way to reproduce the issue and confirm that you're experiencing the same problem.
Why This Matters: The Impact on Code Quality and Maintainability
This formatter bug isn't just a minor annoyance; it has a real impact on code quality and maintainability. When the formatter changes the structure of your code in unexpected ways, it can lead to several problems:
- Reduced Readability: Deconstructed tagged templates are harder to read and understand than the original literals. This makes the code more difficult to maintain and debug.
- Potential Errors: The transformation can introduce runtime errors if the tagged template function is not designed to handle arrays and value lists.
- Code Churn: Developers may spend time trying to work around the bug, leading to unnecessary code churn and complexity.
- Lost Confidence in the Formatter: If the formatter is making significant changes to the code's meaning, developers may lose trust in it and be less likely to use it.
Therefore, fixing this bug is crucial for ensuring the reliability and usability of the ReScript formatter. We want the formatter to be a tool that helps us write better code, not one that introduces unexpected changes and potential errors.
Possible Workarounds: Temporary Solutions
While we wait for a fix, there are a couple of workarounds you can use to avoid this issue:
- Avoid Arrow Expressions Immediately After Tagged Templates: Restructure your code to avoid using arrow expressions directly after tagged template literals. This might involve extracting the arrow function into a separate binding or using a different syntax.
- Disable Formatting for Specific Sections: You can use formatter directives to disable formatting for the affected sections of your code. This will prevent the formatter from deconstructing the tagged template, but it also means that the code in that section won't be automatically formatted.
These workarounds are not ideal, as they require you to change your coding style or disable formatting. However, they can be useful in the short term until a proper fix is available.
Conclusion: Let's Get This Fixed!
In summary, the ReScript formatter has a bug where it deconstructs tagged template literals into arrays when they are followed by an arrow expression. This is not the intended behavior, and it can lead to reduced code readability, potential errors, and lost confidence in the formatter. We've seen the issue in action, discussed its impact, and explored some temporary workarounds.
The next step is to ensure that this bug is reported and addressed by the ReScript team. If you're experiencing this issue, please consider adding your voice to the discussion on the ReScript forums or issue tracker. The more attention this gets, the faster it's likely to be resolved.
Thanks for reading, and let's hope for a quick fix to this annoying bug! Keep coding, guys, and stay tuned for updates.