@@ -14,6 +14,10 @@ let isOptional str = match str with Optional _ -> true | _ -> false
1414
1515let isLabelled str = match str with Labelled _ -> true | _ -> false
1616
17+ let isForwardRef = function
18+ | { pexp_desc = Pexp_ident { txt = (Ldot (Lident "React" , "forwardRef" )) } } -> true
19+ | _ -> false
20+
1721let getLabel str = match str with Optional str | Labelled str -> str | Nolabel -> " "
1822
1923let optionIdent = Lident " option"
@@ -34,12 +38,7 @@ let safeTypeFromValue valueStr =
3438
3539let keyType loc = Typ. constr ~loc { loc; txt = Lident " string" } []
3640
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" ) } [] )
4342
4443type 'a children = ListLiteral of 'a | Exact of 'a
4544
@@ -570,9 +569,10 @@ let jsxMapper () =
570569 pattern,
571570 ({ pexp_desc = Pexp_fun _ } as internalExpression) );
572571 } ->
573- let wrap, hasUnit, exp = spelunkForFunExpression internalExpression in
572+ let wrap, hasUnit, hasForwardRef, exp = spelunkForFunExpression internalExpression in
574573 ( wrap,
575574 hasUnit,
575+ hasForwardRef,
576576 unerasableIgnoreExp { expression with pexp_desc = Pexp_fun (label, default, pattern, exp) } )
577577 (* let make = (()) => ... *)
578578 (* let make = (_) => ... *)
@@ -584,13 +584,13 @@ let jsxMapper () =
584584 { ppat_desc = Ppat_construct ({ txt = Lident " ()" }, _) | Ppat_any },
585585 _internalExpression );
586586 } ->
587- ((fun a -> a), true , expression)
587+ ((fun a -> a), true , false , expression)
588588 (* let make = (~prop) => ... *)
589589 | { pexp_desc = Pexp_fun ((Labelled _ | Optional _ ), _default , _pattern , _internalExpression ) } ->
590- ((fun a -> a), false , unerasableIgnoreExp expression)
590+ ((fun a -> a), false , false , unerasableIgnoreExp expression)
591591 (* let make = (prop) => ... *)
592592 | { 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)
594594 else
595595 Location. raise_errorf ~loc: pattern.ppat_loc
596596 " React: props need to be labelled arguments.\n \
@@ -599,28 +599,35 @@ let jsxMapper () =
599599 (* let make = {let foo = bar in (~prop) => ...} *)
600600 | { pexp_desc = Pexp_let (recursive , vbs , internalExpression ) } ->
601601 (* 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) })
604604 (* let make = React.forwardRef((~prop) => ...) *)
605605 | { pexp_desc = Pexp_apply (wrapperExpression , [ (Nolabel, internalExpression ) ]) } ->
606606 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)
609610 | { 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)
613614 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)
616617 in
617- let bindingWrapper, _hasUnit, expression = modifiedBinding binding in
618+ let bindingWrapper, _hasUnit, hasForwardRef, expression = modifiedBinding binding in
618619 (* do stuff here! *)
619620 let namedArgList, _newtypes, _forwardRef =
620621 recursivelyTransformNamedArgsForMake mapper (modifiedBindingOld binding) [] []
621622 in
622623 let namedTypeList = List. fold_left argToType [] namedArgList in
624+ (* let _ = ref *)
623625 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
624631 let namedArgWithDefaultValueList = List. filter_map argWithDefaultValue namedArgList in
625632 let vbMatch ((label , default )) =
626633 Vb. mk (Pat. var (Location. mknoloc label))
@@ -640,19 +647,31 @@ let jsxMapper () =
640647 makePropsRecordType " props" emptyLoc
641648 ((true , " key" , [] , keyType emptyLoc) :: (true , " ref" , [] , refType pstr_loc) :: namedTypeList)
642649 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" ))]
645660 in
646661 let fullExpression =
647662 (* React component name should start with uppercase letter *)
648663 (* 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+ })*)
649667 Exp. fun_ nolabel None
650668 (match namedTypeList with
651669 | [] -> (Pat. var @@ Location. mknoloc " props" )
652670 | _ -> (Pat. constraint_
653671 (Pat. var @@ Location. mknoloc " props" )
654672 (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)
656675 in
657676 let fullExpression =
658677 match fullModuleName with
@@ -667,7 +686,10 @@ let jsxMapper () =
667686 | Pexp_fun (_arg_label , _default , { ppat_desc = Ppat_construct ({ txt = Lident "()" } , _ ) | Ppat_any } , expr ) ->
668687 (patterns, expr)
669688 | 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
671693 | _ -> (patterns, expr)
672694 in
673695 let patternsWithLid, expression = returnedExpression [] expression in
@@ -677,6 +699,7 @@ let jsxMapper () =
677699 let expression = if List. length vbMatchList = 0 then expression else (Exp. let_ Nonrecursive vbMatchList expression) in
678700 (* add let _ = ref to ignore unused warning *)
679701 let expression = Exp. let_ Nonrecursive [ vbIgnoreUnusedRef ] expression in
702+ let expression = Exp. let_ Nonrecursive [ vbRefFromOption ] expression in
680703 let expression = Exp. fun_ Nolabel None
681704 begin
682705 Pat. constraint_ pattern
0 commit comments