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

Commit 1c185ed

Browse files
committed
apply @react.component to fundef
1 parent d15b125 commit 1c185ed

File tree

1 file changed

+77
-52
lines changed

1 file changed

+77
-52
lines changed

cli/reactjs_jsx_ppx_v3.ml

Lines changed: 77 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ let optionIdent = Lident "option"
2020

2121
let optionalAttr = [ ({ txt = "optional"; loc = Location.none }, PStr []) ]
2222

23+
let reactComponentAttr = [ ({ txt = "react.component"; loc = Location.none }, PStr []) ]
24+
2325
let constantString ~loc str = Ast_helper.Exp.constant ~loc (Pconst_string (str, None))
2426

2527
let recordWithOnlyKey ~loc = Exp.record ~loc
@@ -279,7 +281,7 @@ let jsxMapper () =
279281
| _ -> false
280282
in
281283
(* check if record which goes to Foo.make({ ... } as record) empty or not
282-
if empty then change it to {key: None} only for upper case jsx
284+
if empty then change it to {key: @optional None} only for upper case jsx
283285
This would be redundant regarding PR progress https://github.com/rescript-lang/syntax/pull/299
284286
*)
285287
let props = if isEmptyRecord record then recordWithOnlyKey ~loc else record in
@@ -388,21 +390,21 @@ let jsxMapper () =
388390
recursivelyTransformNamedArgsForMake mapper expression
389391
((arg, default, pattern, alias, pattern.ppat_loc, type_) :: args) newtypes
390392
| Pexp_fun (Nolabel, _, { ppat_desc = Ppat_construct ({ txt = Lident "()" }, _) | Ppat_any }, _expression) ->
391-
(args, newtypes, None)
393+
(args, newtypes)
392394
| Pexp_fun
393395
( Nolabel,
394396
_,
395-
{ ppat_desc = Ppat_var { txt } | Ppat_constraint ({ ppat_desc = Ppat_var { txt } }, _) },
397+
{ ppat_desc = Ppat_var _ | Ppat_constraint ({ ppat_desc = Ppat_var _ }, _) },
396398
_expression ) ->
397-
(args, newtypes, Some txt)
399+
(args, newtypes)
398400
| Pexp_fun (Nolabel, _, pattern, _expression) ->
399401
Location.raise_errorf ~loc:pattern.ppat_loc
400402
"React: react.component refs only support plain arguments and type annotations."
401403
| Pexp_newtype (label, expression) ->
402404
recursivelyTransformNamedArgsForMake mapper expression args (label :: newtypes)
403405
| Pexp_constraint (expression, _typ) ->
404406
recursivelyTransformNamedArgsForMake mapper expression args newtypes
405-
| _ -> (args, newtypes, None)
407+
| _ -> (args, newtypes)
406408
[@@raises Invalid_argument]
407409
in
408410

@@ -546,14 +548,14 @@ let jsxMapper () =
546548
in
547549
spelunkForFunExpression expression
548550
in
551+
let wrapExpressionWithBinding expressionFn expression =
552+
Vb.mk ~loc:bindingLoc
553+
~attrs:(List.filter otherAttrsPure binding.pvb_attributes)
554+
(Pat.var ~loc:bindingPatLoc { loc = bindingPatLoc; txt = fnName })
555+
(expressionFn expression)
556+
in
549557
let modifiedBinding binding =
550558
let hasApplication = ref false in
551-
let wrapExpressionWithBinding expressionFn expression =
552-
Vb.mk ~loc:bindingLoc
553-
~attrs:(List.filter otherAttrsPure binding.pvb_attributes)
554-
(Pat.var ~loc:bindingPatLoc { loc = bindingPatLoc; txt = fnName })
555-
(expressionFn expression)
556-
in
557559
let expression = binding.pvb_expr in
558560
let unerasableIgnoreExp exp =
559561
{ exp with pexp_attributes = unerasableIgnore emptyLoc :: exp.pexp_attributes }
@@ -616,25 +618,10 @@ let jsxMapper () =
616618
in
617619
let bindingWrapper, _hasUnit, expression = modifiedBinding binding in
618620
(* do stuff here! *)
619-
let namedArgList, _newtypes, _forwardRef =
621+
let namedArgList, _newtypes =
620622
recursivelyTransformNamedArgsForMake mapper (modifiedBindingOld binding) [] []
621623
in
622624
let namedTypeList = List.fold_left argToType [] namedArgList in
623-
let vbIgnoreUnusedRef = Vb.mk (Pat.any ()) (Exp.ident (Location.mknoloc (Lident "ref"))) in
624-
let namedArgWithDefaultValueList = List.filter_map argWithDefaultValue namedArgList in
625-
let vbMatch ((label, default)) =
626-
Vb.mk (Pat.var (Location.mknoloc label))
627-
(Exp.match_ (Exp.ident { txt = Lident label; loc=Location.none })
628-
[
629-
Exp.case
630-
(Pat.construct (Location.mknoloc @@ Lident "Some") (Some (Pat.var ( Location.mknoloc label))))
631-
(Exp.ident (Location.mknoloc @@ Lident label));
632-
Exp.case
633-
(Pat.construct (Location.mknoloc @@ Lident "None") None)
634-
default
635-
])
636-
in
637-
let vbMatchList = List.map vbMatch namedArgWithDefaultValueList in
638625
(* type props = { ... } *)
639626
let propsRecordType =
640627
makePropsRecordType "props" emptyLoc
@@ -662,29 +649,8 @@ let jsxMapper () =
662649
[ Vb.mk ~loc:emptyLoc (Pat.var ~loc:emptyLoc { loc = emptyLoc; txt }) fullExpression ]
663650
(Exp.ident ~loc:emptyLoc { loc = emptyLoc; txt = Lident txt })
664651
in
665-
let rec returnedExpression patterns ({ pexp_desc } as expr) =
666-
match pexp_desc with
667-
| Pexp_fun (_arg_label, _default, { ppat_desc = Ppat_construct ({ txt = Lident "()" }, _) | Ppat_any }, expr) ->
668-
(patterns, expr)
669-
| Pexp_fun (arg_label, _default, { ppat_loc }, expr) ->
670-
returnedExpression (({loc = ppat_loc; txt = Lident (getLabel arg_label)}, Pat.var { txt = getLabel arg_label; loc = ppat_loc}) :: patterns) expr
671-
| _ -> (patterns, expr)
672-
in
673-
let patternsWithLid, expression = returnedExpression [] expression in
674-
let pattern = (Pat.record ((List.rev patternsWithLid) @ [(Location.mknoloc (Lident "ref"), Pat.var (Location.mknoloc "ref"))]) Closed)
675-
in
676-
(* add patttern matching for optional prop value *)
677-
let expression = if List.length vbMatchList = 0 then expression else (Exp.let_ Nonrecursive vbMatchList expression) in
678-
(* add let _ = ref to ignore unused warning *)
679-
let expression = Exp.let_ Nonrecursive [ vbIgnoreUnusedRef ] expression in
680-
let expression = Exp.fun_ Nolabel None
681-
begin
682-
Pat.constraint_ pattern
683-
(Typ.constr ~loc:emptyLoc { txt = Lident "props"; loc=emptyLoc }
684-
(makePropsTypeParams namedTypeList))
685-
end
686-
expression
687-
in
652+
(* add @react.component attr *)
653+
let expression = { expression with pexp_attributes = reactComponentAttr } in
688654
(* let make = ({id, name, ...}: props<'id, 'name, ...>) => { ... } *)
689655
let bindings, newBinding =
690656
match recFlag with
@@ -699,7 +665,7 @@ let jsxMapper () =
699665
(Exp.ident { loc = emptyLoc; txt = Lident fnName }));
700666
], None)
701667
| Nonrecursive ->
702-
([ { binding with pvb_expr = expression; pvb_attributes = [] } ], Some (bindingWrapper fullExpression))
668+
([ bindingWrapper expression ], Some (Vb.mk (Pat.var { loc = emptyLoc; txt = fnName }) fullExpression))
703669
in
704670
(Some propsRecordType, bindings, newBinding)
705671
else (None, [ binding ], None)
@@ -821,7 +787,58 @@ let jsxMapper () =
821787
match structure with structures -> default_mapper.structure mapper @@ reactComponentTransform mapper structures
822788
[@@raises Invalid_argument]
823789
in
824-
790+
791+
let transformComponentExpression mapper expression attrs =
792+
match expression with
793+
| { pexp_desc = Pexp_fun _ } ->
794+
(* remove @react.component to prevent infinite loop *)
795+
let expression = { expression with pexp_attributes = attrs } in
796+
let emptyLoc = Location.none in
797+
let namedArgList, _newtypes = recursivelyTransformNamedArgsForMake mapper expression [] [] in
798+
let vbIgnoreUnusedRef = Vb.mk (Pat.any ()) (Exp.ident (Location.mknoloc (Lident "ref"))) in
799+
let namedArgWithDefaultValueList = List.filter_map argWithDefaultValue namedArgList in
800+
let namedTypeList = List.fold_left argToType [] namedArgList in
801+
let vbMatch ((label, default)) =
802+
Vb.mk (Pat.var (Location.mknoloc label))
803+
(Exp.match_ (Exp.ident { txt = Lident label; loc=Location.none })
804+
[
805+
Exp.case
806+
(Pat.construct (Location.mknoloc @@ Lident "Some") (Some (Pat.var ( Location.mknoloc label))))
807+
(Exp.ident (Location.mknoloc @@ Lident label));
808+
Exp.case
809+
(Pat.construct (Location.mknoloc @@ Lident "None") None)
810+
default
811+
])
812+
in
813+
let vbMatchList = List.map vbMatch namedArgWithDefaultValueList in
814+
let rec returnedExpression patterns ({ pexp_desc } as expr) =
815+
match pexp_desc with
816+
| Pexp_fun (_arg_label, _default, { ppat_desc = Ppat_construct ({ txt = Lident "()" }, _) | Ppat_any }, expr) ->
817+
(patterns, expr)
818+
| Pexp_fun (arg_label, _default, { ppat_loc }, expr) when isLabelled arg_label || isOptional arg_label ->
819+
returnedExpression (({loc = ppat_loc; txt = Lident (getLabel arg_label)}, Pat.var { txt = getLabel arg_label; loc = ppat_loc}) :: patterns) expr
820+
| _ -> (patterns, expr)
821+
in
822+
let patternsWithLid, expression = returnedExpression [] expression in
823+
let expression = mapper.expr mapper expression in
824+
let pattern = (Pat.record ((List.rev patternsWithLid) @ [(Location.mknoloc (Lident "ref"), Pat.var (Location.mknoloc "ref"))]) Closed)
825+
in
826+
(* add patttern matching for optional prop value *)
827+
let expression = if List.length vbMatchList = 0 then expression else (Exp.let_ Nonrecursive vbMatchList expression) in
828+
(* add let _ = ref to ignore unused warning *)
829+
let expression = Exp.let_ Nonrecursive [ vbIgnoreUnusedRef ] expression in
830+
let expression = Exp.fun_ Nolabel None
831+
begin
832+
Pat.constraint_ pattern
833+
(Typ.constr ~loc:emptyLoc { txt = Lident "props"; loc=emptyLoc }
834+
(makePropsTypeParams namedTypeList))
835+
end
836+
expression
837+
in
838+
expression
839+
| _ -> expression
840+
in
841+
825842
let expr mapper expression =
826843
match expression with
827844
(* Does the function application have the @JSX attribute? *)
@@ -857,6 +874,14 @@ let jsxMapper () =
857874
(* ReactDOMRe.createElement *)
858875
(Exp.ident ~loc { loc; txt = Ldot (Lident "ReactDOMRe", "createElement") })
859876
args )
877+
| { pexp_desc = Pexp_fun _; pexp_attributes } ->
878+
let reactComponentAttribute, nonReactComponentAttributes = List.partition hasAttr pexp_attributes in
879+
begin
880+
match (reactComponentAttribute, nonReactComponentAttributes) with
881+
| [], _ -> default_mapper.expr mapper expression
882+
| _, nonReactComponentAttributes ->
883+
transformComponentExpression mapper expression nonReactComponentAttributes
884+
end
860885
(* Delegate to the default mapper, a deep identity traversal *)
861886
| e -> default_mapper.expr mapper e
862887
[@@raises Invalid_argument]

0 commit comments

Comments
 (0)