From d5cc8eaaa3dd9b97cbfc50afa401d71bdf516f32 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Sep 2025 12:19:20 +0000 Subject: [PATCH] Wrap non-component JSX children in curly braces --- CHANGELOG.md | 2 + compiler/syntax/src/res_parens.ml | 28 +---------- .../react_component_with_props.res.expected | 2 +- .../fixtures/react_component_with_props.res | 2 +- .../typescript-react-example/src/Hooks.res | 4 +- .../reason/expected/jsxProps.res.txt | 2 +- .../printer/comments/expected/jsx.res.txt | 2 +- .../data/printer/expr/expected/braced.res.txt | 2 +- .../printer/expr/expected/exoticIdent.res.txt | 4 +- .../data/printer/expr/expected/jsx.res.txt | 46 +++++++++---------- .../printer/other/expected/fatSlider.res.txt | 2 +- 11 files changed, 36 insertions(+), 60 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 40c450e7e2..974c7a4cb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,8 @@ #### :eyeglasses: Spec Compliance +- Wrap variables in curly braces inside JSX children. https://github.com/rescript-lang/rescript/pull/7863 + #### :rocket: New Feature - Add `Array.filterMapWithIndex` to Stdlib. https://github.com/rescript-lang/rescript/pull/7876 diff --git a/compiler/syntax/src/res_parens.ml b/compiler/syntax/src/res_parens.ml index 8c08829461..faa6f854e0 100644 --- a/compiler/syntax/src/res_parens.ml +++ b/compiler/syntax/src/res_parens.ml @@ -354,39 +354,13 @@ let jsx_prop_expr expr = let jsx_child_expr expr = match expr.Parsetree.pexp_desc with - | Parsetree.Pexp_let _ | Pexp_sequence _ | Pexp_letexception _ - | Pexp_letmodule _ | Pexp_open _ -> - Nothing + | Parsetree.Pexp_let _ | Pexp_sequence _ -> Nothing | _ -> ( let opt_braces, _ = ParsetreeViewer.process_braces_attr expr in match opt_braces with | Some ({Location.loc = braces_loc}, _) -> Braced braces_loc | _ -> ( match expr with - | { - Parsetree.pexp_desc = - Pexp_constant (Pconst_integer (x, _) | Pconst_float (x, _)); - pexp_attributes = []; - } - when starts_with_minus x -> - Parenthesized - | _ when ParsetreeViewer.expr_is_await expr -> Parenthesized - | { - Parsetree.pexp_desc = - ( Pexp_ident _ | Pexp_constant _ | Pexp_field _ | Pexp_construct _ - | Pexp_variant _ | Pexp_array _ | Pexp_pack _ | Pexp_record _ - | Pexp_extension _ | Pexp_letmodule _ | Pexp_letexception _ - | Pexp_open _ | Pexp_sequence _ | Pexp_let _ | Pexp_jsx_element _ ); - pexp_attributes = []; - } -> - Nothing - | { - Parsetree.pexp_desc = - Pexp_constraint - ({pexp_desc = Pexp_pack _}, {ptyp_desc = Ptyp_package _}); - pexp_attributes = []; - } -> - Nothing | {pexp_desc = Pexp_jsx_element _} -> Nothing | _ -> Parenthesized)) diff --git a/tests/build_tests/super_errors/expected/react_component_with_props.res.expected b/tests/build_tests/super_errors/expected/react_component_with_props.res.expected index ea08c175f2..1aa8fcf619 100644 --- a/tests/build_tests/super_errors/expected/react_component_with_props.res.expected +++ b/tests/build_tests/super_errors/expected/react_component_with_props.res.expected @@ -7,7 +7,7 @@ 3 │ let make = React.forwardRef(( 4 │  ~className=?, . │ ... - 12 │  children + 12 │  {children} 13 │   14 │ ) 15 │ } diff --git a/tests/build_tests/super_errors/fixtures/react_component_with_props.res b/tests/build_tests/super_errors/fixtures/react_component_with_props.res index 29ca3b301b..546c34e8c3 100644 --- a/tests/build_tests/super_errors/fixtures/react_component_with_props.res +++ b/tests/build_tests/super_errors/fixtures/react_component_with_props.res @@ -9,7 +9,7 @@ module V4C7 = { Belt.Option.map(React.Ref.domRef)} /> - children + {children} ) } diff --git a/tests/gentype_tests/typescript-react-example/src/Hooks.res b/tests/gentype_tests/typescript-react-example/src/Hooks.res index 0fb4c048b0..fedcaf7695 100644 --- a/tests/gentype_tests/typescript-react-example/src/Hooks.res +++ b/tests/gentype_tests/typescript-react-example/src/Hooks.res @@ -60,7 +60,7 @@ module Inner = { module NoProps = { @genType @react.component - let make = () =>
React.null
+ let make = () =>
{React.null}
} type cb = (~_to: vehicle) => unit @@ -133,7 +133,7 @@ module WithChildren = { let aComponentWithChildren = (~vehicle, ~children) =>
{React.string("Another Hook " ++ vehicle.name)} -
children
+
{children}
} diff --git a/tests/syntax_tests/data/conversion/reason/expected/jsxProps.res.txt b/tests/syntax_tests/data/conversion/reason/expected/jsxProps.res.txt index 3d98360833..c73baa3918 100644 --- a/tests/syntax_tests/data/conversion/reason/expected/jsxProps.res.txt +++ b/tests/syntax_tests/data/conversion/reason/expected/jsxProps.res.txt @@ -6,4 +6,4 @@ let handleClick = (href, event) => @react.component let make = (~href, ~className="", ~children) => - handleClick(href, event)}> children + handleClick(href, event)}> {children} diff --git a/tests/syntax_tests/data/printer/comments/expected/jsx.res.txt b/tests/syntax_tests/data/printer/comments/expected/jsx.res.txt index 664018ce3b..6dc09e7af4 100644 --- a/tests/syntax_tests/data/printer/comments/expected/jsx.res.txt +++ b/tests/syntax_tests/data/printer/comments/expected/jsx.res.txt @@ -3,7 +3,7 @@ module Cite = { let make = (~author: option, ~children) => { // For semantics, check out // https://css-tricks.com/quoting-in-html-quotations-citations-and-blockquotes/ -
foo
+
{foo}
} } diff --git a/tests/syntax_tests/data/printer/expr/expected/braced.res.txt b/tests/syntax_tests/data/printer/expr/expected/braced.res.txt index 80ea824389..f9ccb97ac2 100644 --- a/tests/syntax_tests/data/printer/expr/expected/braced.res.txt +++ b/tests/syntax_tests/data/printer/expr/expected/braced.res.txt @@ -282,7 +282,7 @@ apply({ a }) -let x = {
child
} +let x = {
{child}
} // not valid jsx let x = {@JSX child} diff --git a/tests/syntax_tests/data/printer/expr/expected/exoticIdent.res.txt b/tests/syntax_tests/data/printer/expr/expected/exoticIdent.res.txt index 9ba0e0c3d3..7f05729c4c 100644 --- a/tests/syntax_tests/data/printer/expr/expected/exoticIdent.res.txt +++ b/tests/syntax_tests/data/printer/expr/expected/exoticIdent.res.txt @@ -61,8 +61,8 @@ let x = 1 let x =
- \"module" - \"let" + {\"module"} + {\"let"}
type dict = { diff --git a/tests/syntax_tests/data/printer/expr/expected/jsx.res.txt b/tests/syntax_tests/data/printer/expr/expected/jsx.res.txt index b6364fa397..d97ab2c11d 100644 --- a/tests/syntax_tests/data/printer/expr/expected/jsx.res.txt +++ b/tests/syntax_tests/data/printer/expr/expected/jsx.res.txt @@ -209,8 +209,8 @@ let x = let x =
- ident - "constant" + {ident} + {"constant"} { let a = 1 let b = 2 @@ -240,13 +240,13 @@ let x = | Error => () }} {(a, b, c)} - Rgb(red, blue, green) - list{} - list{a, b} - list{a, b, ...x} - [a, b, c] - {x: 1, y: 2} - foo.bar + {Rgb(red, blue, green)} + {list{}} + {list{a, b}} + {list{a, b, ...x}} + {[a, b, c]} + {{x: 1, y: 2}} + {foo.bar} {user.name = "Steve"} {if true { () @@ -264,29 +264,29 @@ let x = do(i) }} {(20: int)} - { + {{ module L = Log L.log() - } - { + }} + {{ exception Exit throw(Exit) - } + }} {assert(true)} {module(Foo)} - module(Foo) + {module(Foo)} {module(Foo: Bar)} - module(Foo: Bar) - { + {module(Foo: Bar)} + {{ open React React.render() - } - %raw("eval()") - {"x": 1, "y": 2} + }} + {%raw("eval()")} + {{"x": 1, "y": 2}} {@attr ident}
-let x = test } nav={} /> +let x = {test} } nav={} />
{possibleGradeValues @@ -314,7 +314,7 @@ let x = test
} nav={} /> module App = { @react.component let make = () => { - <> 1 + <> {1} } } @@ -492,14 +492,14 @@ let fragmented_moo = let arrow_with_fragment = el => <> {t(nbsp ++ "(")} - el + {el} {t(")")} let arrow_with_container_tag = el =>
{t(nbsp ++ "(")} - el + {el} {t(")")}
diff --git a/tests/syntax_tests/data/printer/other/expected/fatSlider.res.txt b/tests/syntax_tests/data/printer/other/expected/fatSlider.res.txt index 6e065f0ac4..c493eb0a4a 100644 --- a/tests/syntax_tests/data/printer/other/expected/fatSlider.res.txt +++ b/tests/syntax_tests/data/printer/other/expected/fatSlider.res.txt @@ -34,7 +34,7 @@ let make = (~min=50, ~max=250, ~meterSuffix=?) => { values onChange={v => values_set(_ => v)} renderTrack={({props, children}) => { - let element =
children
+ let element =
{children}
ReasonReact.cloneElement(element, ~props=Obj.magic(props), [children]) }}