From 6402971e60be3a6b9249fb9db0899319cef3a0e5 Mon Sep 17 00:00:00 2001 From: Grigory Date: Mon, 20 Apr 2026 07:37:25 +0500 Subject: [PATCH 1/5] update tests --- tests/specs/jsx/JsxElement/JsxElement_Spaces.txt | 4 ++-- tests/specs/jsx/JsxText/JsxText_All.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/specs/jsx/JsxElement/JsxElement_Spaces.txt b/tests/specs/jsx/JsxElement/JsxElement_Spaces.txt index ac1ff8c1..b3ed6297 100644 --- a/tests/specs/jsx/JsxElement/JsxElement_Spaces.txt +++ b/tests/specs/jsx/JsxElement/JsxElement_Spaces.txt @@ -6,11 +6,11 @@ const t =
{t} {u} {v}
; [expect] const t =
{t} {u} {v}
; -== should remove spaces surrounding == +== should keep spaces surrounding == const t =
test
; [expect] -const t =
test
; +const t =
test
; == should handle a space when exceeding the line width with only the parent when the parent and children are on the same line == const t =
{test} {testsdffffffffffff}
; diff --git a/tests/specs/jsx/JsxText/JsxText_All.txt b/tests/specs/jsx/JsxText/JsxText_All.txt index f0a8f218..283159e2 100644 --- a/tests/specs/jsx/JsxText/JsxText_All.txt +++ b/tests/specs/jsx/JsxText/JsxText_All.txt @@ -4,7 +4,7 @@ const t = <> Testing this out ; [expect] -const t = <>Testing this out; +const t = <> Testing this out ; == should format when multi line == const t = <> From e0dd420eb7b2bd280cf336bec27b390537a49181 Mon Sep 17 00:00:00 2001 From: Grigory Date: Mon, 20 Apr 2026 09:10:38 +0500 Subject: [PATCH 2/5] solution --- src/generation/generate.rs | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/src/generation/generate.rs b/src/generation/generate.rs index 5c5ad077..9e999949 100644 --- a/src/generation/generate.rs +++ b/src/generation/generate.rs @@ -9214,23 +9214,57 @@ fn gen_jsx_children<'a>(opts: GenJsxChildrenOptions<'a>, context: &mut Context<' if children.is_empty() { items.push_signal(Signal::PossibleNewLine); } else { - let mut previous_child = None; + let children_len = children.len(); + let mut previous_child: Option> = None; + let mut before_last_child: Option> = None; for (index, (child, generated_child)) in children.into_iter().enumerate() { if index > 0 && should_use_space(*previous_child.as_ref().unwrap(), child, context) { items.extend(jsx_space_separator(*previous_child.as_ref().unwrap(), child, context)); + } else if index == 0 && jsx_child_has_leading_space(child, context) { + items.push_signal(Signal::SpaceOrNewLine); } else { items.push_signal(Signal::PossibleNewLine); } items.extend(generated_child.into()); + if children_len >= 2 && index == children_len - 2 { + before_last_child = Some(child); + } previous_child = Some(child); } - items.push_signal(Signal::PossibleNewLine); + if jsx_child_has_trailing_space(*previous_child.as_ref().unwrap(), before_last_child, context) { + items.push_signal(Signal::SpaceOrNewLine); + } else { + items.push_signal(Signal::PossibleNewLine); + } } items } + fn jsx_child_has_leading_space<'a>(child: Node<'a>, context: &mut Context<'a>) -> bool { + if let Node::JSXText(text) = child { + let raw = text.text_fast(context.program); + let leading_whitespace = &raw[..raw.len() - raw.trim_start().len()]; + !leading_whitespace.is_empty() && !leading_whitespace.contains('\n') + } else { + false + } + } + + fn jsx_child_has_trailing_space<'a>(child: Node<'a>, previous_child: Option>, context: &mut Context<'a>) -> bool { + if let Node::JSXText(text) = child { + if previous_child.map_or(false, |prev| is_ignore_jsx_expr_container(prev, context)) { + return false; + } + let raw = text.text_fast(context.program); + let trailing_whitespace = &raw[raw.trim_end().len()..]; + !trailing_whitespace.is_empty() && !trailing_whitespace.contains('\n') + } else { + false + } + } + fn should_use_space<'a>(previous_child: Node<'a>, current: Node<'a>, context: &mut Context<'a>) -> bool { if has_jsx_space_between(previous_child, current, context.program) { return true; From fdc2459c616e4450455973a11c3c562e84205db3 Mon Sep 17 00:00:00 2001 From: Grigory Date: Mon, 20 Apr 2026 09:39:23 +0500 Subject: [PATCH 3/5] adj --- src/generation/generate.rs | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/generation/generate.rs b/src/generation/generate.rs index 9e999949..e9e95984 100644 --- a/src/generation/generate.rs +++ b/src/generation/generate.rs @@ -9214,13 +9214,15 @@ fn gen_jsx_children<'a>(opts: GenJsxChildrenOptions<'a>, context: &mut Context<' if children.is_empty() { items.push_signal(Signal::PossibleNewLine); } else { + // `gen_jsx_text` trims boundary whitespace so multi-line JSX text doesn't keep source indentation. + // Restore meaningful same-line edge spaces here when the first or last rendered child is JSX text. let children_len = children.len(); let mut previous_child: Option> = None; let mut before_last_child: Option> = None; for (index, (child, generated_child)) in children.into_iter().enumerate() { if index > 0 && should_use_space(*previous_child.as_ref().unwrap(), child, context) { items.extend(jsx_space_separator(*previous_child.as_ref().unwrap(), child, context)); - } else if index == 0 && jsx_child_has_leading_space(child, context) { + } else if index == 0 && has_jsx_leading_space(child, context) { items.push_signal(Signal::SpaceOrNewLine); } else { items.push_signal(Signal::PossibleNewLine); @@ -9233,7 +9235,7 @@ fn gen_jsx_children<'a>(opts: GenJsxChildrenOptions<'a>, context: &mut Context<' } previous_child = Some(child); } - if jsx_child_has_trailing_space(*previous_child.as_ref().unwrap(), before_last_child, context) { + if has_jsx_trailing_space(*previous_child.as_ref().unwrap(), before_last_child, context) { items.push_signal(Signal::SpaceOrNewLine); } else { items.push_signal(Signal::PossibleNewLine); @@ -9242,24 +9244,23 @@ fn gen_jsx_children<'a>(opts: GenJsxChildrenOptions<'a>, context: &mut Context<' items } - fn jsx_child_has_leading_space<'a>(child: Node<'a>, context: &mut Context<'a>) -> bool { - if let Node::JSXText(text) = child { - let raw = text.text_fast(context.program); - let leading_whitespace = &raw[..raw.len() - raw.trim_start().len()]; - !leading_whitespace.is_empty() && !leading_whitespace.contains('\n') + fn has_jsx_leading_space<'a>(current_node: Node<'a>, context: &Context<'a>) -> bool { + if let Node::JSXText(text) = current_node { + let text = text.text_fast(context.program); + text.starts_with(' ') && utils::has_no_new_lines_in_leading_whitespace(text) } else { false } } - fn jsx_child_has_trailing_space<'a>(child: Node<'a>, previous_child: Option>, context: &mut Context<'a>) -> bool { - if let Node::JSXText(text) = child { - if previous_child.map_or(false, |prev| is_ignore_jsx_expr_container(prev, context)) { + fn has_jsx_trailing_space<'a>(current_node: Node<'a>, previous_node: Option>, context: &Context<'a>) -> bool { + if let Node::JSXText(text) = current_node { + if previous_node.map_or(false, |prev| is_ignore_jsx_expr_container(prev, context)) { return false; } - let raw = text.text_fast(context.program); - let trailing_whitespace = &raw[raw.trim_end().len()..]; - !trailing_whitespace.is_empty() && !trailing_whitespace.contains('\n') + + let text = text.text_fast(context.program); + text.ends_with(' ') && utils::has_no_new_lines_in_trailing_whitespace(text) } else { false } From b09e71aaae6fe586462121bed594ef4b05bfbbf9 Mon Sep 17 00:00:00 2001 From: Grigory Date: Mon, 20 Apr 2026 09:46:51 +0500 Subject: [PATCH 4/5] adj --- src/generation/generate.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/generation/generate.rs b/src/generation/generate.rs index e9e95984..131e9d40 100644 --- a/src/generation/generate.rs +++ b/src/generation/generate.rs @@ -9255,10 +9255,10 @@ fn gen_jsx_children<'a>(opts: GenJsxChildrenOptions<'a>, context: &mut Context<' fn has_jsx_trailing_space<'a>(current_node: Node<'a>, previous_node: Option>, context: &Context<'a>) -> bool { if let Node::JSXText(text) = current_node { - if previous_node.map_or(false, |prev| is_ignore_jsx_expr_container(prev, context)) { + if matches!(previous_node, Some(previous_node) if is_ignore_jsx_expr_container(previous_node, context)) { return false; } - + let text = text.text_fast(context.program); text.ends_with(' ') && utils::has_no_new_lines_in_trailing_whitespace(text) } else { From f8fbca097d0df87d0ccd88a35b3b799691962c06 Mon Sep 17 00:00:00 2001 From: Grigory Date: Tue, 19 May 2026 17:23:54 +0500 Subject: [PATCH 5/5] format --- src/generation/generate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/generation/generate.rs b/src/generation/generate.rs index 131e9d40..db8797cc 100644 --- a/src/generation/generate.rs +++ b/src/generation/generate.rs @@ -9258,7 +9258,7 @@ fn gen_jsx_children<'a>(opts: GenJsxChildrenOptions<'a>, context: &mut Context<' if matches!(previous_node, Some(previous_node) if is_ignore_jsx_expr_container(previous_node, context)) { return false; } - + let text = text.text_fast(context.program); text.ends_with(' ') && utils::has_no_new_lines_in_trailing_whitespace(text) } else {