Skip to content
This repository was archived by the owner on Jun 15, 2023. It is now read-only.

Commit 15b76e2

Browse files
committed
new jsx transform for lower case
1 parent 0bb7166 commit 15b76e2

File tree

1 file changed

+119
-57
lines changed

1 file changed

+119
-57
lines changed

cli/reactjs_jsx_ppx_v4.ml

Lines changed: 119 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -388,15 +388,19 @@ let transformUppercaseCall3 jsxRuntime modulePath mapper loc attrs
388388
let jsxExpr, key =
389389
match (!childrenArg, keyProp) with
390390
| None, (_, keyExpr) :: _ ->
391-
( Exp.ident ~loc {loc; txt = Ldot (Lident "React", "jsxKeyed")},
391+
( Exp.ident ~loc
392+
{loc; txt = Ldot (Ldot (Lident "Js", "React"), "jsxKeyed")},
392393
[(nolabel, keyExpr)] )
393394
| None, [] ->
394-
(Exp.ident ~loc {loc; txt = Ldot (Lident "React", "jsx")}, [])
395+
( Exp.ident ~loc {loc; txt = Ldot (Ldot (Lident "Js", "React"), "jsx")},
396+
[] )
395397
| Some _, (_, keyExpr) :: _ ->
396-
( Exp.ident ~loc {loc; txt = Ldot (Lident "React", "jsxsKeyed")},
398+
( Exp.ident ~loc
399+
{loc; txt = Ldot (Ldot (Lident "Js", "React"), "jsxsKeyed")},
397400
[(nolabel, keyExpr)] )
398401
| Some _, [] ->
399-
(Exp.ident ~loc {loc; txt = Ldot (Lident "React", "jsxs")}, [])
402+
( Exp.ident ~loc {loc; txt = Ldot (Ldot (Lident "Js", "React"), "jsxs")},
403+
[] )
400404
in
401405
Exp.apply ~loc ~attrs jsxExpr
402406
([(nolabel, Exp.ident ~loc {txt = ident; loc}); (nolabel, props)] @ key)
@@ -425,61 +429,119 @@ let transformUppercaseCall3 jsxRuntime modulePath mapper loc attrs
425429
])
426430
[@@raises Invalid_argument]
427431

428-
let transformLowercaseCall3 _jsxRuntime mapper loc attrs _callExpression
432+
let transformLowercaseCall3 jsxRuntime mapper loc attrs callExpression
429433
callArguments id =
430-
let children, nonChildrenProps = extractChildren ~loc callArguments in
431-
(* keep the v3 *)
432-
(* let record = recordFromProps callExpression nonChildrenProps in *)
433434
let componentNameExpr = constantString ~loc id in
434-
let childrenExpr = transformChildrenIfList ~loc ~mapper children in
435-
let createElementCall =
436-
match children with
437-
(* [@JSX] div(~children=[a]), coming from <div> a </div> *)
438-
| {
439-
pexp_desc =
440-
( Pexp_construct ({txt = Lident "::"}, Some {pexp_desc = Pexp_tuple _})
441-
| Pexp_construct ({txt = Lident "[]"}, None) );
442-
} ->
443-
"createDOMElementVariadic"
444-
(* [@JSX] div(~children= value), coming from <div> ...(value) </div> *)
445-
| _ ->
446-
raise
447-
(Invalid_argument
448-
"A spread as a DOM element's children don't make sense written \
449-
together. You can simply remove the spread.")
450-
in
451-
let args =
452-
match nonChildrenProps with
453-
| [_justTheUnitArgumentAtEnd] ->
454-
[
455-
(* "div" *)
456-
(nolabel, componentNameExpr);
457-
(* [|moreCreateElementCallsHere|] *)
458-
(nolabel, childrenExpr);
459-
]
460-
| nonEmptyProps ->
461-
let propsCall =
462-
Exp.apply ~loc
463-
(Exp.ident ~loc {loc; txt = Ldot (Lident "ReactDOMRe", "domProps")})
464-
(nonEmptyProps
465-
|> List.map (fun (label, expression) ->
466-
(label, mapper.expr mapper expression)))
467-
in
468-
[
469-
(* "div" *)
470-
(nolabel, componentNameExpr);
471-
(* ReactDOMRe.domProps(~className=blabla, ~foo=bar, ()) *)
472-
(labelled "props", propsCall);
473-
(* [|moreCreateElementCallsHere|] *)
474-
(nolabel, childrenExpr);
475-
]
476-
in
477-
Exp.apply
478-
~loc (* throw away the [@JSX] attribute and keep the others, if any *)
479-
~attrs
480-
(* ReactDOMRe.createElement *)
481-
(Exp.ident ~loc {loc; txt = Ldot (Lident "ReactDOMRe", createElementCall)})
482-
args
435+
match jsxRuntime with
436+
(* the new jsx transform *)
437+
| "automatic" ->
438+
let children, nonChildrenProps =
439+
extractChildren ~removeLastPositionUnit:true ~loc callArguments
440+
in
441+
let argsForMake = nonChildrenProps in
442+
let childrenExpr = transformChildrenIfListUpper ~loc ~mapper children in
443+
let recursivelyTransformedArgsForMake =
444+
argsForMake
445+
|> List.map (fun (label, expression) ->
446+
(label, mapper.expr mapper expression))
447+
in
448+
let childrenArg = ref None in
449+
let args =
450+
recursivelyTransformedArgsForMake
451+
@
452+
match childrenExpr with
453+
| Exact children -> [(labelled "children", children)]
454+
| ListLiteral {pexp_desc = Pexp_array list} when list = [] -> []
455+
| ListLiteral expression ->
456+
(* this is a hack to support react components that introspect into their children *)
457+
childrenArg := Some expression;
458+
[(labelled "children", expression)]
459+
in
460+
let isEmptyRecord {pexp_desc} =
461+
match pexp_desc with
462+
| Pexp_record (labelDecls, _) when List.length labelDecls = 0 -> true
463+
| _ -> false
464+
in
465+
let record = recordFromProps ~removeKey:true callExpression args in
466+
let props =
467+
if isEmptyRecord record then recordWithOnlyKey ~loc else record
468+
in
469+
let keyProp =
470+
args |> List.filter (fun (arg_label, _) -> "key" = getLabel arg_label)
471+
in
472+
let jsxExpr, key =
473+
match (!childrenArg, keyProp) with
474+
| None, (_, keyExpr) :: _ ->
475+
( Exp.ident ~loc
476+
{loc; txt = Ldot (Ldot (Lident "Js", "React"), "jsxKeyedDom")},
477+
[(nolabel, keyExpr)] )
478+
| None, [] ->
479+
( Exp.ident ~loc
480+
{loc; txt = Ldot (Ldot (Lident "Js", "React"), "jsxDom")},
481+
[] )
482+
| Some _, (_, keyExpr) :: _ ->
483+
( Exp.ident ~loc
484+
{loc; txt = Ldot (Ldot (Lident "Js", "React"), "jsxsKeyedDom")},
485+
[(nolabel, keyExpr)] )
486+
| Some _, [] ->
487+
( Exp.ident ~loc
488+
{loc; txt = Ldot (Ldot (Lident "Js", "React"), "jsxsDom")},
489+
[] )
490+
in
491+
Exp.apply ~loc ~attrs jsxExpr
492+
([(nolabel, componentNameExpr); (nolabel, props)] @ key)
493+
| _ ->
494+
let children, nonChildrenProps = extractChildren ~loc callArguments in
495+
let childrenExpr = transformChildrenIfList ~loc ~mapper children in
496+
let createElementCall =
497+
match children with
498+
(* [@JSX] div(~children=[a]), coming from <div> a </div> *)
499+
| {
500+
pexp_desc =
501+
( Pexp_construct ({txt = Lident "::"}, Some {pexp_desc = Pexp_tuple _})
502+
| Pexp_construct ({txt = Lident "[]"}, None) );
503+
} ->
504+
"createDOMElementVariadic"
505+
(* [@JSX] div(~children= value), coming from <div> ...(value) </div> *)
506+
| _ ->
507+
raise
508+
(Invalid_argument
509+
"A spread as a DOM element's children don't make sense written \
510+
together. You can simply remove the spread.")
511+
in
512+
let args =
513+
match nonChildrenProps with
514+
| [_justTheUnitArgumentAtEnd] ->
515+
[
516+
(* "div" *)
517+
(nolabel, componentNameExpr);
518+
(* [|moreCreateElementCallsHere|] *)
519+
(nolabel, childrenExpr);
520+
]
521+
| nonEmptyProps ->
522+
let propsCall =
523+
Exp.apply ~loc
524+
(Exp.ident ~loc {loc; txt = Ldot (Lident "ReactDOMRe", "domProps")})
525+
(nonEmptyProps
526+
|> List.map (fun (label, expression) ->
527+
(label, mapper.expr mapper expression)))
528+
in
529+
[
530+
(* "div" *)
531+
(nolabel, componentNameExpr);
532+
(* ReactDOMRe.domProps(~className=blabla, ~foo=bar, ()) *)
533+
(labelled "props", propsCall);
534+
(* [|moreCreateElementCallsHere|] *)
535+
(nolabel, childrenExpr);
536+
]
537+
in
538+
Exp.apply
539+
~loc (* throw away the [@JSX] attribute and keep the others, if any *)
540+
~attrs
541+
(* ReactDOMRe.createElement *)
542+
(Exp.ident ~loc
543+
{loc; txt = Ldot (Lident "ReactDOMRe", createElementCall)})
544+
args
483545
[@@raises Invalid_argument]
484546

485547
let rec recursivelyTransformNamedArgsForMake mapper expr args newtypes =

0 commit comments

Comments
 (0)