From 494efd020cfde1148f663f563a9735a3bbbdf8d2 Mon Sep 17 00:00:00 2001 From: RJM Date: Wed, 12 Nov 2025 18:01:15 +1100 Subject: [PATCH] Fix nested brace counting in MDX expressions Remove parser check that prevented brace counting when external parser is configured. The original logic skipped counting opening braces in gnostic mode, causing expressions like `{{ x: 1 }}` to exit prematurely at the first closing brace. Tokenizer must count all braces to find expression boundaries before the external parser validates syntax. Fixes: - Nested object literals: `{{ x: 1 }}` - Nested function calls: `func({ x: g({ y: 2 }) })` - JSX attribute expressions with nested objects Tests added for nested object literal scenarios. --- src/construct/partial_mdx_expression.rs | 7 +++---- tests/mdx_expression_text.rs | 24 ++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/construct/partial_mdx_expression.rs b/src/construct/partial_mdx_expression.rs index 373595be..9a27c993 100644 --- a/src/construct/partial_mdx_expression.rs +++ b/src/construct/partial_mdx_expression.rs @@ -143,10 +143,9 @@ pub fn inside(tokenizer: &mut Tokenizer) -> State { tokenizer.exit(Name::MdxExpressionData); State::Retry(StateName::MdxExpressionBefore) } else { - // Don’t count if gnostic. - if tokenizer.current == Some(b'{') - && tokenizer.parse_state.options.mdx_expression_parse.is_none() - { + // Count braces even when external parser is present. + // Original check skipped nested braces, breaking `{{ x: 1 }}`. + if tokenizer.current == Some(b'{') { tokenizer.tokenize_state.size += 1; } else if tokenizer.current == Some(b'}') { tokenizer.tokenize_state.size -= 1; diff --git a/tests/mdx_expression_text.rs b/tests/mdx_expression_text.rs index f24e4fba..06750b55 100644 --- a/tests/mdx_expression_text.rs +++ b/tests/mdx_expression_text.rs @@ -372,5 +372,29 @@ fn mdx_expression_text_gnostic() -> Result<(), message::Message> { "should keep the correct number of spaces in a blockquote (text)" ); + assert_eq!( + to_html_with_options("a {{}} b", &swc)?, + "

a b

", + "should support nested empty object literal" + ); + + assert_eq!( + to_html_with_options("a {{ x: 1 }} b", &swc)?, + "

a b

", + "should support nested object literal with property" + ); + + assert_eq!( + to_html_with_options("a {func({ x: 1 })} b", &swc)?, + "

a b

", + "should support function call with nested object" + ); + + assert_eq!( + to_html_with_options("a {f({ x: g({ y: 2 }) })} b", &swc)?, + "

a b

", + "should support double nested function calls" + ); + Ok(()) }