@@ -20,6 +20,8 @@ let optionIdent = Lident "option"
20
20
21
21
let optionalAttr = [ ({ txt = " optional" ; loc = Location. none }, PStr [] ) ]
22
22
23
+ let reactComponentAttr = [ ({ txt = " react.component" ; loc = Location. none }, PStr [] ) ]
24
+
23
25
let constantString ~loc str = Ast_helper.Exp. constant ~loc (Pconst_string (str, None ))
24
26
25
27
let recordWithOnlyKey ~loc = Exp. record ~loc
@@ -279,7 +281,7 @@ let jsxMapper () =
279
281
| _ -> false
280
282
in
281
283
(* 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
283
285
This would be redundant regarding PR progress https://github.com/rescript-lang/syntax/pull/299
284
286
*)
285
287
let props = if isEmptyRecord record then recordWithOnlyKey ~loc else record in
@@ -388,21 +390,21 @@ let jsxMapper () =
388
390
recursivelyTransformNamedArgsForMake mapper expression
389
391
((arg, default, pattern, alias, pattern.ppat_loc, type_) :: args) newtypes
390
392
| Pexp_fun (Nolabel , _ , { ppat_desc = Ppat_construct ({ txt = Lident "()" } , _ ) | Ppat_any } , _expression ) ->
391
- (args, newtypes, None )
393
+ (args, newtypes)
392
394
| Pexp_fun
393
395
( Nolabel ,
394
396
_,
395
- { ppat_desc = Ppat_var { txt } | Ppat_constraint ({ ppat_desc = Ppat_var { txt } }, _) },
397
+ { ppat_desc = Ppat_var _ | Ppat_constraint ({ ppat_desc = Ppat_var _ }, _) },
396
398
_expression ) ->
397
- (args, newtypes, Some txt )
399
+ (args, newtypes)
398
400
| Pexp_fun (Nolabel, _ , pattern , _expression ) ->
399
401
Location. raise_errorf ~loc: pattern.ppat_loc
400
402
" React: react.component refs only support plain arguments and type annotations."
401
403
| Pexp_newtype (label , expression ) ->
402
404
recursivelyTransformNamedArgsForMake mapper expression args (label :: newtypes)
403
405
| Pexp_constraint (expression , _typ ) ->
404
406
recursivelyTransformNamedArgsForMake mapper expression args newtypes
405
- | _ -> (args, newtypes, None )
407
+ | _ -> (args, newtypes)
406
408
[@@ raises Invalid_argument ]
407
409
in
408
410
@@ -546,14 +548,14 @@ let jsxMapper () =
546
548
in
547
549
spelunkForFunExpression expression
548
550
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
549
557
let modifiedBinding binding =
550
558
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
557
559
let expression = binding.pvb_expr in
558
560
let unerasableIgnoreExp exp =
559
561
{ exp with pexp_attributes = unerasableIgnore emptyLoc :: exp .pexp_attributes }
@@ -616,25 +618,10 @@ let jsxMapper () =
616
618
in
617
619
let bindingWrapper, _hasUnit, expression = modifiedBinding binding in
618
620
(* do stuff here! *)
619
- let namedArgList, _newtypes, _forwardRef =
621
+ let namedArgList, _newtypes =
620
622
recursivelyTransformNamedArgsForMake mapper (modifiedBindingOld binding) [] []
621
623
in
622
624
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
638
625
(* type props = { ... } *)
639
626
let propsRecordType =
640
627
makePropsRecordType " props" emptyLoc
@@ -662,29 +649,8 @@ let jsxMapper () =
662
649
[ Vb. mk ~loc: emptyLoc (Pat. var ~loc: emptyLoc { loc = emptyLoc; txt }) fullExpression ]
663
650
(Exp. ident ~loc: emptyLoc { loc = emptyLoc; txt = Lident txt })
664
651
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
688
654
(* let make = ({id, name, ...}: props<'id, 'name, ...>) => { ... } *)
689
655
let bindings, newBinding =
690
656
match recFlag with
@@ -699,7 +665,7 @@ let jsxMapper () =
699
665
(Exp. ident { loc = emptyLoc; txt = Lident fnName }));
700
666
], None )
701
667
| 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))
703
669
in
704
670
(Some propsRecordType, bindings, newBinding)
705
671
else (None , [ binding ], None )
@@ -821,7 +787,58 @@ let jsxMapper () =
821
787
match structure with structures -> default_mapper.structure mapper @@ reactComponentTransform mapper structures
822
788
[@@ raises Invalid_argument ]
823
789
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
+
825
842
let expr mapper expression =
826
843
match expression with
827
844
(* Does the function application have the @JSX attribute? *)
@@ -857,6 +874,14 @@ let jsxMapper () =
857
874
(* ReactDOMRe.createElement *)
858
875
(Exp. ident ~loc { loc; txt = Ldot (Lident " ReactDOMRe" , " createElement" ) })
859
876
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
860
885
(* Delegate to the default mapper, a deep identity traversal *)
861
886
| e -> default_mapper.expr mapper e
862
887
[@@ raises Invalid_argument ]
0 commit comments