@@ -1496,7 +1496,7 @@ let transform_signature_item ~config item =
14961496 " Only one JSX component call can exist on a component at one time" )
14971497 | _ -> [item]
14981498
1499- let transform_jsx_call ~config mapper call_expression call_arguments
1499+ let _transform_jsx_call ~config mapper call_expression call_arguments
15001500 jsx_expr_loc attrs =
15011501 match call_expression.pexp_desc with
15021502 | Pexp_ident caller -> (
@@ -1530,58 +1530,163 @@ let transform_jsx_call ~config mapper call_expression call_arguments
15301530 " JSX: `createElement` should be preceeded by a simple, direct module \
15311531 name."
15321532
1533- let mkChildrenProps (config : Jsx_common.jsx_config ) mapper
1534- (children : jsx_children ) =
1535- let record_of_children children =
1536- Exp. record [(Location. mknoloc (Lident " children" ), children, false )] None
1537- in
1538- let apply_jsx_array expr =
1539- Exp. apply
1540- (Exp. ident {txt = module_access_name config " array" ; loc = Location. none})
1541- [(Nolabel , expr)]
1542- in
1543- match children with
1544- | JSXChildrenItems [] -> empty_record ~loc: Location. none
1545- | JSXChildrenItems [child] | JSXChildrenSpreading child ->
1546- record_of_children (mapper.expr mapper child)
1547- | JSXChildrenItems xs -> (
1548- match config.mode with
1549- | "automatic" ->
1533+ let starts_with_lowercase s =
1534+ if String. length s = 0 then false
1535+ else
1536+ let c = s.[0 ] in
1537+ Char. lowercase_ascii c = c
1538+
1539+ let _starts_with_uppercase s =
1540+ if String. length s = 0 then false
1541+ else
1542+ let c = s.[0 ] in
1543+ Char. uppercase_ascii c = c
1544+
1545+ module AutomaticExpr = struct
1546+ let mk_children_props (config : Jsx_common.jsx_config ) mapper
1547+ (children : jsx_children ) =
1548+ let record_of_children children =
1549+ Exp. record [(Location. mknoloc (Lident " children" ), children, false )] None
1550+ in
1551+ let apply_jsx_array expr =
1552+ Exp. apply
1553+ (Exp. ident
1554+ {txt = module_access_name config " array" ; loc = Location. none})
1555+ [(Nolabel , expr)]
1556+ in
1557+ match children with
1558+ | JSXChildrenItems [] -> empty_record ~loc: Location. none
1559+ | JSXChildrenItems [child] | JSXChildrenSpreading child ->
1560+ record_of_children (mapper.expr mapper child)
1561+ | JSXChildrenItems xs ->
15501562 record_of_children
15511563 @@ apply_jsx_array (Exp. array (List. map (mapper.expr mapper) xs))
1552- | "classic" | _ -> empty_record ~loc: Location. none)
15531564
1554- let mkReactCreateElement (config : Jsx_common.jsx_config ) mapper loc attrs
1555- (elementTag : expression ) (children : jsx_children ) : expression =
1556- let more_than_one_children =
1557- match children with
1558- | JSXChildrenSpreading _ -> false
1559- | JSXChildrenItems xs -> List. length xs > 1
1560- in
1561- let children_props = mkChildrenProps config mapper children in
1562- let args =
1563- (nolabel, elementTag) :: (nolabel, children_props)
1564- ::
1565- (match (config.mode, children) with
1566- | "classic" , JSXChildrenItems xs when more_than_one_children ->
1567- [(nolabel, Exp. array (List. map (mapper.expr mapper) xs))]
1568- | _ -> [] )
1569- in
1570- Exp. apply ~loc ~attrs
1571- (* ReactDOM.createElement *)
1572- (match config.mode with
1573- | "automatic" ->
1574- if more_than_one_children then
1575- Exp. ident ~loc {loc; txt = module_access_name config " jsxs" }
1576- else Exp. ident ~loc {loc; txt = module_access_name config " jsx" }
1577- | "classic" | _ ->
1578- if more_than_one_children then
1579- Exp. ident ~loc
1580- {loc; txt = Ldot (Lident " React" , " createElementVariadic" )}
1581- else Exp. ident ~loc {loc; txt = Ldot (Lident " React" , " createElement" )})
1582- args
1565+ let mk_react_jsx (config : Jsx_common.jsx_config ) mapper loc attrs
1566+ (elementTag : expression ) (children : jsx_children ) : expression =
1567+ let more_than_one_children =
1568+ match children with
1569+ | JSXChildrenSpreading _ -> false
1570+ | JSXChildrenItems xs -> List. length xs > 1
1571+ in
1572+ let children_props = mk_children_props config mapper children in
1573+ let args = [(nolabel, elementTag); (nolabel, children_props)] in
1574+ Exp. apply ~loc ~attrs (* ReactDOM.jsx *)
1575+ (if more_than_one_children then
1576+ Exp. ident ~loc {loc; txt = module_access_name config " jsxs" }
1577+ else Exp. ident ~loc {loc; txt = module_access_name config " jsx" })
1578+ args
1579+
1580+ let try_find_key_prop (props : jsx_props ) : (arg_label * expression) option =
1581+ props
1582+ |> List. find_map (function
1583+ | JSXPropPunning (_ , ({txt = "key" } as name )) ->
1584+ Some (Labelled name, Exp. ident {txt = Lident " key" ; loc = name.loc})
1585+ | JSXPropValue (({txt = "key" } as name ), is_optional , expr ) ->
1586+ let arg_label =
1587+ if is_optional then Optional name else Labelled name
1588+ in
1589+ Some (arg_label, expr)
1590+ | _ -> None )
1591+
1592+ let expr ~(config : Jsx_common.jsx_config ) mapper expression =
1593+ match expression with
1594+ | {
1595+ pexp_desc = Pexp_jsx_fragment (_, children, _);
1596+ pexp_loc = loc;
1597+ pexp_attributes = attrs;
1598+ } ->
1599+ let loc = {loc with loc_ghost = true } in
1600+ let fragment =
1601+ Exp. ident ~loc {loc; txt = module_access_name config " jsxFragment" }
1602+ in
1603+ mk_react_jsx config mapper loc attrs fragment children
1604+ | {
1605+ pexp_desc =
1606+ Pexp_jsx_unary_element
1607+ {jsx_unary_element_tag_name = name; jsx_unary_element_props = props};
1608+ pexp_loc = loc;
1609+ pexp_attributes = attrs;
1610+ } -> (
1611+ match name.txt with
1612+ | Longident. Lident elementName when starts_with_lowercase elementName ->
1613+ (* For example 'input' *)
1614+ let component_name_expr = constant_string ~loc: name.loc elementName in
1615+ let element_binding =
1616+ match config.module_ |> String. lowercase_ascii with
1617+ | "react" -> Lident " ReactDOM"
1618+ | _generic -> module_access_name config " Elements"
1619+ in
1620+ let jsx_expr, key_and_unit =
1621+ match try_find_key_prop props with
1622+ | None ->
1623+ ( Exp. ident
1624+ {loc = Location. none; txt = Ldot (element_binding, " jsx" )},
1625+ [] )
1626+ | Some key_prop ->
1627+ ( Exp. ident
1628+ {loc = Location. none; txt = Ldot (element_binding, " jsxKeyed" )},
1629+ [key_prop; (nolabel, unit_expr ~loc: Location. none)] )
1630+ in
1631+ (* TODO *)
1632+ let props = empty_record ~loc in
1633+
1634+ Exp. apply ~loc ~attrs jsx_expr
1635+ ([(nolabel, component_name_expr); (nolabel, props)] @ key_and_unit)
1636+ | _ ->
1637+ Jsx_common. raise_error ~loc
1638+ " JSX: element name is neither upper- or lowercase, got \" %s\" "
1639+ (Longident. flatten name.txt |> String. concat " ." ))
1640+ | e -> default_mapper.expr mapper e
1641+ end
1642+
1643+ module ClassicExpr = struct
1644+ let mk_react_create_element mapper loc attrs (elementTag : expression )
1645+ (children : jsx_children ) : expression =
1646+ let more_than_one_children =
1647+ match children with
1648+ | JSXChildrenSpreading _ -> false
1649+ | JSXChildrenItems xs -> List. length xs > 1
1650+ in
1651+ (* children are a special prop are special in React.createElement *)
1652+ let children_props = empty_record ~loc: Location. none in
1653+ let args =
1654+ (nolabel, elementTag) :: (nolabel, children_props)
1655+ ::
1656+ (match children with
1657+ | JSXChildrenItems xs when more_than_one_children ->
1658+ [(nolabel, Exp. array (List. map (mapper.expr mapper) xs))]
1659+ | _ -> [] )
1660+ in
1661+ Exp. apply ~loc ~attrs
1662+ (* ReactDOM.createElement *)
1663+ (if more_than_one_children then
1664+ Exp. ident ~loc
1665+ {loc; txt = Ldot (Lident " React" , " createElementVariadic" )}
1666+ else Exp. ident ~loc {loc; txt = Ldot (Lident " React" , " createElement" )})
1667+ args
1668+
1669+ let expr (_config : Jsx_common.jsx_config ) mapper expression =
1670+ match expression with
1671+ | {
1672+ pexp_desc = Pexp_jsx_fragment (_, children, _);
1673+ pexp_loc = loc;
1674+ pexp_attributes = attrs;
1675+ } ->
1676+ let loc = {loc with loc_ghost = true } in
1677+ let fragment =
1678+ Exp. ident ~loc {loc; txt = Ldot (Lident " React" , " fragment" )}
1679+ in
1680+ mk_react_create_element mapper loc attrs fragment children
1681+ | e -> default_mapper.expr mapper e
1682+ end
15831683
15841684let expr ~(config : Jsx_common.jsx_config ) mapper expression =
1685+ match config.mode with
1686+ | "automatic" -> AutomaticExpr. expr ~config mapper expression
1687+ | "classic" -> ClassicExpr. expr config mapper expression
1688+ | _ -> default_mapper.expr mapper expression
1689+ (*
15851690 match expression with
15861691 | {
15871692 pexp_desc = Pexp_jsx_fragment (_, children, _);
@@ -1596,7 +1701,35 @@ let expr ~(config : Jsx_common.jsx_config) mapper expression =
15961701 | "classic" | _ ->
15971702 Exp.ident ~loc {loc; txt = Ldot (Lident "React", "fragment")}
15981703 in
1599- mkReactCreateElement config mapper loc attrs fragment children
1704+ mk_react_create_element config mapper loc attrs fragment children
1705+ | {
1706+ pexp_desc =
1707+ Pexp_jsx_unary_element
1708+ {jsx_unary_element_tag_name = name; jsx_unary_element_props = props};
1709+ pexp_loc = loc;
1710+ pexp_attributes = attrs;
1711+ } as e ->
1712+ let elementTag =
1713+ match name.txt with
1714+ | Longident.Lident elementName when starts_with_lowercase elementName -> (
1715+ (* For example 'input' *)
1716+ let component_name_expr = constant_string ~loc:name.loc elementName in
1717+ match config.mode with
1718+ | "automatic" ->
1719+ let element_binding =
1720+ match config.module_ |> String.lowercase_ascii with
1721+ | "react" -> Lident "ReactDOM"
1722+ | _generic -> module_access_name config "Elements"
1723+ in
1724+ Exp.ident ~loc {loc; txt = Lident elementName}
1725+ | "classic" | _ -> ()
1726+ )
1727+ | _ ->
1728+ Jsx_common.raise_error ~loc
1729+ "JSX: element name is neither upper- or lowercase, got \"%s\""
1730+ (Longident.flatten name.txt |> String.concat ".")
1731+ in
1732+ e
16001733 (* Does the function application have the @JSX attribute? *)
16011734 | {
16021735 pexp_desc = Pexp_apply {funct = call_expression; args = call_arguments};
@@ -1616,6 +1749,7 @@ let expr ~(config : Jsx_common.jsx_config) mapper expression =
16161749 non_jsx_attributes)
16171750 (* Delegate to the default mapper, a deep identity traversal *)
16181751 | e -> default_mapper.expr mapper e
1752+ *)
16191753
16201754let module_binding ~(config : Jsx_common.jsx_config ) mapper module_binding =
16211755 config.nested_modules < - module_binding.pmb_name.txt :: config.nested_modules;
0 commit comments