Skip to content

Commit b374212

Browse files
committed
lowercase container element with children.
1 parent 1aaa686 commit b374212

File tree

1 file changed

+107
-6
lines changed

1 file changed

+107
-6
lines changed

compiler/syntax/src/jsx_v4.ml

Lines changed: 107 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1548,8 +1548,8 @@ module AutomaticExpr = struct
15481548
| JSXPropValue (_, _, {pexp_loc}) -> pexp_loc
15491549
| JSXPropSpreading (loc, _) -> loc
15501550

1551-
let mk_record_from_props (jsx_expr_loc : Location.t) (props : jsx_props) :
1552-
expression =
1551+
let mk_record_from_props mapper (jsx_expr_loc : Location.t)
1552+
(props : jsx_props) : expression =
15531553
(* Create an artificial range from the first till the last prop *)
15541554
let loc =
15551555
match props with
@@ -1580,7 +1580,8 @@ module AutomaticExpr = struct
15801580
in
15811581
let props, spread_props =
15821582
match props with
1583-
| JSXPropSpreading (_, expr) :: rest -> (rest, Some expr)
1583+
| JSXPropSpreading (_, expr) :: rest ->
1584+
(rest, Some (mapper.expr mapper expr))
15841585
| _ -> (props, None)
15851586
in
15861587

@@ -1592,7 +1593,9 @@ module AutomaticExpr = struct
15921593
Exp.ident {txt = Lident name.txt; loc = name.loc},
15931594
is_optional )
15941595
| JSXPropValue (name, is_optional, value) ->
1595-
({txt = Lident name.txt; loc = name.loc}, value, is_optional)
1596+
( {txt = Lident name.txt; loc = name.loc},
1597+
mapper.expr mapper value,
1598+
is_optional )
15961599
| JSXPropSpreading (loc, _) ->
15971600
(* There can only be one spread expression and it is expected to be the first prop *)
15981601
Jsx_common.raise_error ~loc
@@ -1694,7 +1697,7 @@ module AutomaticExpr = struct
16941697
{loc = Location.none; txt = Ldot (element_binding, "jsxKeyed")},
16951698
[key_prop; (nolabel, unit_expr ~loc:Location.none)] )
16961699
in
1697-
let props = mk_record_from_props loc props in
1700+
let props = mk_record_from_props mapper loc props in
16981701

16991702
Exp.apply ~loc ~attrs jsx_expr
17001703
([(nolabel, component_name_expr); (nolabel, props)] @ key_and_unit)
@@ -1718,13 +1721,111 @@ module AutomaticExpr = struct
17181721
},
17191722
[key_prop; (nolabel, unit_expr ~loc:Location.none)] )
17201723
in
1721-
let props = mk_record_from_props loc props in
1724+
let props = mk_record_from_props mapper loc props in
17221725
Exp.apply ~loc ~attrs jsx_expr
17231726
([(nolabel, make_id); (nolabel, props)] @ key_and_unit)
17241727
else
17251728
Jsx_common.raise_error ~loc
17261729
"JSX: element name is neither upper- or lowercase, got \"%s\""
17271730
(Longident.flatten tag_name.txt |> String.concat ".")
1731+
| {
1732+
pexp_desc =
1733+
Pexp_jsx_container_element
1734+
{
1735+
jsx_container_element_tag_name_start = tag_name;
1736+
jsx_container_element_props = props;
1737+
jsx_container_element_children = children;
1738+
};
1739+
pexp_loc = loc;
1740+
pexp_attributes = attrs;
1741+
} ->
1742+
let loc = {loc with loc_ghost = true} in
1743+
let name = Longident.flatten tag_name.txt |> String.concat "." in
1744+
(* For example: <div> <h1></h1> <br /> </div>
1745+
This has an impact if we want to use ReactDOM.jsx or ReactDOM.jsxs
1746+
*)
1747+
let has_multiple_literal_children =
1748+
match children with
1749+
| JSXChildrenItems (_ :: _ :: _) -> true
1750+
| _ -> false
1751+
in
1752+
if starts_with_lowercase name then
1753+
let component_name_expr = constant_string ~loc:tag_name.loc name in
1754+
let element_binding =
1755+
match config.module_ |> String.lowercase_ascii with
1756+
| "react" -> Lident "ReactDOM"
1757+
| _generic -> module_access_name config "Elements"
1758+
in
1759+
let props_record =
1760+
(* Append current props with JSXPropValue("children")
1761+
This will later be transformed correctly into a record. *)
1762+
let props_with_children =
1763+
match children with
1764+
| JSXChildrenItems [] -> props
1765+
| JSXChildrenItems [expr] | JSXChildrenSpreading expr ->
1766+
props
1767+
@ [
1768+
JSXPropValue
1769+
( {txt = "children"; loc = Location.none},
1770+
true,
1771+
Exp.apply
1772+
(Exp.ident
1773+
{
1774+
txt = Ldot (element_binding, "someElement");
1775+
loc = Location.none;
1776+
})
1777+
[(Nolabel, expr)] );
1778+
]
1779+
| JSXChildrenItems xs ->
1780+
(* this is a hack to support react components that introspect into their children *)
1781+
props
1782+
@ [
1783+
JSXPropValue
1784+
( {txt = "children"; loc = Location.none},
1785+
false,
1786+
Exp.apply
1787+
(Exp.ident
1788+
{
1789+
txt = module_access_name config "array";
1790+
loc = Location.none;
1791+
})
1792+
[
1793+
(Nolabel, Exp.array (List.map (mapper.expr mapper) xs));
1794+
] );
1795+
]
1796+
in
1797+
mk_record_from_props mapper loc props_with_children
1798+
in
1799+
let jsx_expr, key_and_unit =
1800+
match try_find_key_prop props with
1801+
| None ->
1802+
( Exp.ident
1803+
{
1804+
loc = Location.none;
1805+
txt =
1806+
Ldot
1807+
( element_binding,
1808+
if has_multiple_literal_children then "jsxs" else "jsx"
1809+
);
1810+
},
1811+
[] )
1812+
| Some key_prop ->
1813+
( Exp.ident
1814+
{
1815+
loc = Location.none;
1816+
txt =
1817+
Ldot
1818+
( element_binding,
1819+
if has_multiple_literal_children then "jsxsKeyed"
1820+
else "jsxKeyed" );
1821+
},
1822+
[key_prop; (nolabel, unit_expr ~loc:Location.none)] )
1823+
in
1824+
1825+
Exp.apply ~loc ~attrs jsx_expr
1826+
([(nolabel, component_name_expr); (nolabel, props_record)]
1827+
@ key_and_unit)
1828+
else failwith "TODO"
17281829
| e -> default_mapper.expr mapper e
17291830
end
17301831

0 commit comments

Comments
 (0)