mirror of
https://github.com/oxc-project/oxc.git
synced 2026-11-04 10:29:58 +00:00
fix(formatter): keep source parens around html-in-js placeholders past comments (#28381)
It's a rare case, but just to be safe.
This commit is contained in:
1 parent
e738daede1
commit
fb3aefa8d6
4 files changed
+27
-14
No files matched your search
+3
@@ -0,0 +1,3 @@
|
||||
html`<script>f((${a}) /* c */)</script>`;
|
||||
html`<script>f((${a}))</script>`;
|
||||
html`<script>f(/* c */ (${a}))</script>`;
|
||||
@@ -74,7 +74,7 @@
|
||||
|
||||
## html-in-js
|
||||
|
||||
### Option 1: 172/200 (86.00%)
|
||||
### Option 1: 173/201 (86.07%)
|
||||
|
||||
```json
|
||||
{"printWidth":80}
|
||||
@@ -137,7 +137,7 @@
|
||||
- [externals/webawesome/textarea/textarea.ts](diffs/html-in-js/externals__webawesome__textarea__textarea.ts.md)
|
||||
- crates/oxc_formatter/DIVERGENCES.md#union-annotation-flat-retry
|
||||
|
||||
### Option 2: 186/200 (93.00%)
|
||||
### Option 2: 187/201 (93.03%)
|
||||
|
||||
```json
|
||||
{"printWidth":100,"htmlWhitespaceSensitivity":"ignore"}
|
||||
|
||||
+2
-2
@@ -74,7 +74,7 @@ const d = html`<style>
|
||||
const a = html`
|
||||
<style>
|
||||
a {
|
||||
- prettier_html_placeholder_0_2989_in_js: ${c};
|
||||
- prettier_html_placeholder_0_2992_in_js: ${c};
|
||||
+ ${b}: ${c};
|
||||
}
|
||||
</style>
|
||||
@@ -110,7 +110,7 @@ const d = html`
|
||||
const a = html`
|
||||
<style>
|
||||
a {
|
||||
prettier_html_placeholder_0_2989_in_js: ${c};
|
||||
prettier_html_placeholder_0_2992_in_js: ${c};
|
||||
}
|
||||
</style>
|
||||
`;
|
||||
|
||||
@@ -144,23 +144,33 @@ impl NeedsParentheses<'_> for AstNode<'_, '_, IdentifierReference<'_>> {
|
||||
|
||||
/// Whether the source wraps `node` in parentheses of its own (the AST keeps none),
|
||||
/// besides those of the syntax around it (a sole call argument, an `if` test, ...).
|
||||
/// Comments between them are skipped (`f((a) /* c */)`).
|
||||
#[expect(clippy::cast_possible_truncation)] // Offsets fit in `u32`, source length does
|
||||
fn is_parenthesized_in_source(
|
||||
node: &AstNode<'_, '_, IdentifierReference<'_>>,
|
||||
f: &JsFormatter<'_, '_>,
|
||||
) -> bool {
|
||||
let bytes = f.source_text().as_str().as_bytes();
|
||||
let (mut start, mut end) = (node.span.start as usize, node.span.end as usize);
|
||||
let mut pairs = 0;
|
||||
loop {
|
||||
let before = bytes[..start].iter().rposition(|b| !b.is_ascii_whitespace());
|
||||
let after = bytes[end..].iter().position(|b| !b.is_ascii_whitespace()).map(|i| end + i);
|
||||
match (before, after) {
|
||||
(Some(before), Some(after)) if bytes[before] == b'(' && bytes[after] == b')' => {
|
||||
pairs += 1;
|
||||
(start, end) = (before, after + 1);
|
||||
let comments = f.context().comments();
|
||||
// The last byte before `pos` that is neither whitespace nor in a comment
|
||||
let before = |mut pos: u32| -> Option<u32> {
|
||||
loop {
|
||||
let i = bytes[..pos as usize].iter().rposition(|b| !b.is_ascii_whitespace())? as u32;
|
||||
match comments.all_comments_before(pos).last() {
|
||||
Some(comment) if comment.span.end > i => pos = comment.span.start,
|
||||
_ => return Some(i),
|
||||
}
|
||||
_ => break,
|
||||
}
|
||||
};
|
||||
let (mut start, mut end) = (node.span.start, node.span.end);
|
||||
let mut pairs = 0;
|
||||
while let Some(open) = before(start)
|
||||
&& bytes[open as usize] == b'('
|
||||
&& comments.is_followed_by_closing_paren(end)
|
||||
{
|
||||
pairs += 1;
|
||||
start = open;
|
||||
end = comments.position_after_character(end, b')');
|
||||
}
|
||||
let span = node.span;
|
||||
let syntax_parens = match node.parent() {
|
||||
|
||||
Reference in new issue
Block a user