@@ -14,6 +14,10 @@ let isOptional str = match str with Optional _ -> true | _ -> false
14
14
15
15
let isLabelled str = match str with Labelled _ -> true | _ -> false
16
16
17
+ let isForwardRef = function
18
+ | { pexp_desc = Pexp_ident { txt = (Ldot (Lident "React" , "forwardRef" )) } } -> true
19
+ | _ -> false
20
+
17
21
let getLabel str = match str with Optional str | Labelled str -> str | Nolabel -> " "
18
22
19
23
let optionIdent = Lident " option"
@@ -34,12 +38,7 @@ let safeTypeFromValue valueStr =
34
38
35
39
let keyType loc = Typ. constr ~loc { loc; txt = Lident " string" } []
36
40
37
- let refType loc = Typ. constr ~loc { loc; txt = Ldot (Lident " React" , " ref" ) }
38
- [
39
- (Typ. constr ~loc { loc; txt = Ldot (Ldot (Lident " Js" , " Nullable" ), " t" )}
40
- [(Typ. constr ~loc { loc; txt = Ldot (Lident " Dom" , " element" ) } [] )]
41
- )
42
- ]
41
+ let refType loc = (Typ. constr ~loc { loc; txt = Ldot (Ldot (Lident " ReactDOM" , " Ref" ), " currentDomRef" ) } [] )
43
42
44
43
type 'a children = ListLiteral of 'a | Exact of 'a
45
44
@@ -570,9 +569,10 @@ let jsxMapper () =
570
569
pattern,
571
570
({ pexp_desc = Pexp_fun _ } as internalExpression) );
572
571
} ->
573
- let wrap, hasUnit, exp = spelunkForFunExpression internalExpression in
572
+ let wrap, hasUnit, hasForwardRef, exp = spelunkForFunExpression internalExpression in
574
573
( wrap,
575
574
hasUnit,
575
+ hasForwardRef,
576
576
unerasableIgnoreExp { expression with pexp_desc = Pexp_fun (label, default, pattern, exp) } )
577
577
(* let make = (()) => ... *)
578
578
(* let make = (_) => ... *)
@@ -584,13 +584,13 @@ let jsxMapper () =
584
584
{ ppat_desc = Ppat_construct ({ txt = Lident " ()" }, _) | Ppat_any },
585
585
_internalExpression );
586
586
} ->
587
- ((fun a -> a), true , expression)
587
+ ((fun a -> a), true , false , expression)
588
588
(* let make = (~prop) => ... *)
589
589
| { pexp_desc = Pexp_fun ((Labelled _ | Optional _ ), _default , _pattern , _internalExpression ) } ->
590
- ((fun a -> a), false , unerasableIgnoreExp expression)
590
+ ((fun a -> a), false , false , unerasableIgnoreExp expression)
591
591
(* let make = (prop) => ... *)
592
592
| { pexp_desc = Pexp_fun (_nolabel , _default , pattern , _internalExpression ) } ->
593
- if hasApplication.contents then ((fun a -> a), false , unerasableIgnoreExp expression)
593
+ if ! hasApplication then ((fun a -> a), false , false , unerasableIgnoreExp expression)
594
594
else
595
595
Location. raise_errorf ~loc: pattern.ppat_loc
596
596
" React: props need to be labelled arguments.\n \
@@ -599,28 +599,35 @@ let jsxMapper () =
599
599
(* let make = {let foo = bar in (~prop) => ...} *)
600
600
| { pexp_desc = Pexp_let (recursive , vbs , internalExpression ) } ->
601
601
(* here's where we spelunk! *)
602
- let wrap, hasUnit, exp = spelunkForFunExpression internalExpression in
603
- (wrap, hasUnit, { expression with pexp_desc = Pexp_let (recursive, vbs, exp) })
602
+ let wrap, hasUnit, hasForwardRef, exp = spelunkForFunExpression internalExpression in
603
+ (wrap, hasUnit, hasForwardRef, { expression with pexp_desc = Pexp_let (recursive, vbs, exp) })
604
604
(* let make = React.forwardRef((~prop) => ...) *)
605
605
| { pexp_desc = Pexp_apply (wrapperExpression , [ (Nolabel, internalExpression ) ]) } ->
606
606
let () = hasApplication := true in
607
- let _, hasUnit, exp = spelunkForFunExpression internalExpression in
608
- ((fun exp -> Exp. apply wrapperExpression [ (nolabel, exp) ]), hasUnit, exp)
607
+ let _, hasUnit, _, exp = spelunkForFunExpression internalExpression in
608
+ let hasForwardRef = isForwardRef wrapperExpression in
609
+ ((fun exp -> Exp. apply wrapperExpression [ (nolabel, exp) ]), hasUnit, hasForwardRef, exp)
609
610
| { pexp_desc = Pexp_sequence (wrapperExpression , internalExpression ) } ->
610
- let wrap, hasUnit, exp = spelunkForFunExpression internalExpression in
611
- (wrap, hasUnit, { expression with pexp_desc = Pexp_sequence (wrapperExpression, exp) })
612
- | e -> ((fun a -> a), false , e)
611
+ let wrap, hasUnit, hasForwardRef, exp = spelunkForFunExpression internalExpression in
612
+ (wrap, hasUnit, hasForwardRef, { expression with pexp_desc = Pexp_sequence (wrapperExpression, exp) })
613
+ | e -> ((fun a -> a), false , false , e)
613
614
in
614
- let wrapExpression, hasUnit, expression = spelunkForFunExpression expression in
615
- (wrapExpressionWithBinding wrapExpression, hasUnit, expression)
615
+ let wrapExpression, hasUnit, hasForwardRef, expression = spelunkForFunExpression expression in
616
+ (wrapExpressionWithBinding wrapExpression, hasUnit, hasForwardRef, expression)
616
617
in
617
- let bindingWrapper, _hasUnit, expression = modifiedBinding binding in
618
+ let bindingWrapper, _hasUnit, hasForwardRef, expression = modifiedBinding binding in
618
619
(* do stuff here! *)
619
620
let namedArgList, _newtypes, _forwardRef =
620
621
recursivelyTransformNamedArgsForMake mapper (modifiedBindingOld binding) [] []
621
622
in
622
623
let namedTypeList = List. fold_left argToType [] namedArgList in
624
+ (* let _ = ref *)
623
625
let vbIgnoreUnusedRef = Vb. mk (Pat. any () ) (Exp. ident (Location. mknoloc (Lident " ref" ))) in
626
+ (* let ref = ref->Js.Nullable.fromOption *)
627
+ let vbRefFromOption = Vb. mk (Pat. var @@ Location. mknoloc " ref" )
628
+ (Exp. apply (Exp. ident (Location. mknoloc (Ldot (Ldot (Lident " Js" , " Nullable" ), " fromOption" ))))
629
+ [(Nolabel , Exp. ident (Location. mknoloc @@ Lident " ref" ))])
630
+ in
624
631
let namedArgWithDefaultValueList = List. filter_map argWithDefaultValue namedArgList in
625
632
let vbMatch ((label , default )) =
626
633
Vb. mk (Pat. var (Location. mknoloc label))
@@ -640,19 +647,31 @@ let jsxMapper () =
640
647
makePropsRecordType " props" emptyLoc
641
648
((true , " key" , [] , keyType emptyLoc) :: (true , " ref" , [] , refType pstr_loc) :: namedTypeList)
642
649
in
643
- let innerExpression = Exp. apply (Exp. ident (Location. mknoloc @@ Lident " make" ))
644
- [(Nolabel , Exp. ident (Location. mknoloc @@ Lident " props" ))]
650
+ let innerExpression = if hasForwardRef then
651
+ Exp. apply (Exp. ident @@ Location. mknoloc @@ Lident " make" )
652
+ [(Nolabel , Exp. record
653
+ [ (Location. mknoloc @@ Lident " ref" , Exp. apply ~attrs: optionalAttr
654
+ (Exp. ident (Location. mknoloc (Ldot (Ldot (Lident " Js" , " Nullable" ), " toOption" ))))
655
+ [ (Nolabel , Exp. ident (Location. mknoloc @@ Lident " ref" )) ])
656
+ ]
657
+ (Some (Exp. ident (Location. mknoloc @@ Lident " props" ))))]
658
+ else Exp. apply (Exp. ident (Location. mknoloc @@ Lident " make" ))
659
+ [(Nolabel , Exp. ident (Location. mknoloc @@ Lident " props" ))]
645
660
in
646
661
let fullExpression =
647
662
(* React component name should start with uppercase letter *)
648
663
(* let make = { let \"App" = props => make(props); \"App" } *)
664
+ (* let make = React.forwardRef({
665
+ let \"App" = (props, ref) => make({...props, ref: @optional (Js.Nullabel.toOption(ref))})
666
+ })*)
649
667
Exp. fun_ nolabel None
650
668
(match namedTypeList with
651
669
| [] -> (Pat. var @@ Location. mknoloc " props" )
652
670
| _ -> (Pat. constraint_
653
671
(Pat. var @@ Location. mknoloc " props" )
654
672
(Typ. constr (Location. mknoloc @@ Lident " props" )([Typ. any () ]))))
655
- innerExpression
673
+ (if hasForwardRef then Exp. fun_ nolabel None (Pat. var @@ Location. mknoloc " ref" ) innerExpression
674
+ else innerExpression)
656
675
in
657
676
let fullExpression =
658
677
match fullModuleName with
@@ -667,7 +686,10 @@ let jsxMapper () =
667
686
| Pexp_fun (_arg_label , _default , { ppat_desc = Ppat_construct ({ txt = Lident "()" } , _ ) | Ppat_any } , expr ) ->
668
687
(patterns, expr)
669
688
| 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
689
+ if isLabelled arg_label || isOptional arg_label then
690
+ returnedExpression (({loc = ppat_loc; txt = Lident (getLabel arg_label)}, Pat. var { txt = getLabel arg_label; loc = ppat_loc}) :: patterns) expr
691
+ else
692
+ returnedExpression patterns expr
671
693
| _ -> (patterns, expr)
672
694
in
673
695
let patternsWithLid, expression = returnedExpression [] expression in
@@ -677,6 +699,7 @@ let jsxMapper () =
677
699
let expression = if List. length vbMatchList = 0 then expression else (Exp. let_ Nonrecursive vbMatchList expression) in
678
700
(* add let _ = ref to ignore unused warning *)
679
701
let expression = Exp. let_ Nonrecursive [ vbIgnoreUnusedRef ] expression in
702
+ let expression = Exp. let_ Nonrecursive [ vbRefFromOption ] expression in
680
703
let expression = Exp. fun_ Nolabel None
681
704
begin
682
705
Pat. constraint_ pattern
0 commit comments