@@ -23,8 +23,9 @@ let optionalAttr = [ ({ txt = "optional"; loc = Location.none }, PStr []) ]
23
23
let constantString ~loc str = Ast_helper.Exp. constant ~loc (Pconst_string (str, None ))
24
24
25
25
let recordWithOnlyKey ~loc = Exp. record ~loc
26
- [({loc; txt = Lident " key" }, Exp. construct {loc; txt = Lident " None" } None )]
27
- None
26
+ (* {key: @optional None} *)
27
+ [({loc; txt = Lident " key" }, Exp. construct ~attrs: optionalAttr {loc; txt = Lident " None" } None )]
28
+ None
28
29
29
30
let safeTypeFromValue valueStr =
30
31
let valueStr = getLabel valueStr in
@@ -42,8 +43,6 @@ let refType loc = Typ.constr ~loc { loc; txt = Ldot (Lident "React", "ref") }
42
43
43
44
type 'a children = ListLiteral of 'a | Exact of 'a
44
45
45
- type componentConfig = { propsName : string }
46
-
47
46
(* if children is a list, convert it to an array while mapping each element. If not, just map over it, as usual *)
48
47
let transformChildrenIfListUpper ~loc ~mapper theList =
49
48
let rec transformChildren_ theList accum =
@@ -123,27 +122,6 @@ let makeNewBinding binding expression newName =
123
122
| _ -> raise (Invalid_argument " react.component calls cannot be destructured." )
124
123
[@@ raises Invalid_argument ]
125
124
126
- (* Lookup the value of `props` otherwise raise Invalid_argument error *)
127
- let getPropsNameValue _acc (loc , exp ) =
128
- match (loc, exp) with
129
- | { txt = Lident "props" } , { pexp_desc = Pexp_ident { txt = Lident str } } -> { propsName = str }
130
- | { txt } , _ ->
131
- raise (Invalid_argument (" react.component only accepts props as an option, given: " ^ Longident. last txt))
132
- [@@ raises Invalid_argument ]
133
-
134
- (* Lookup the `props` record or string as part of [@react.component] and store the name for use when rewriting *)
135
- let getPropsAttr payload =
136
- let defaultProps = { propsName = " Props" } in
137
- match payload with
138
- | Some (PStr ({ pstr_desc = Pstr_eval ({ pexp_desc = Pexp_record (recordFields , None) } , _ ) } :: _rest )) ->
139
- List. fold_left getPropsNameValue defaultProps recordFields
140
- | Some (PStr ({ pstr_desc = Pstr_eval ({ pexp_desc = Pexp_ident { txt = Lident "props" } } , _ ) } :: _rest )) ->
141
- { propsName = " props" }
142
- | Some (PStr ({ pstr_desc = Pstr_eval (_ , _ ) } :: _rest )) ->
143
- raise (Invalid_argument " react.component accepts a record config with props as an options." )
144
- | _ -> defaultProps
145
- [@@ raises Invalid_argument ]
146
-
147
125
(* Lookup the filename from the location information on the AST node and turn it into a valid module identifier *)
148
126
let filenameFromLoc (pstr_loc : Location.t ) =
149
127
let fileName = match pstr_loc.loc_start.pos_fname with "" -> ! Location. input_name | fileName -> fileName in
@@ -260,26 +238,6 @@ let makePropsRecordTypeSig propsName loc namedTypeList =
260
238
~kind: (Ptype_record labelDeclList);
261
239
]
262
240
263
- (* Build an AST node for the props name when converted to an object inside the function signature *)
264
- let makePropsName ~loc name = { ppat_desc = Ppat_var { txt = name; loc }; ppat_loc = loc; ppat_attributes = [] }
265
-
266
- let makeObjectField loc (_ , str , attrs , type_ ) = Otag ({ loc; txt = str }, attrs, type_)
267
-
268
- (* Build an AST node representing a "closed" object representing a component's props *)
269
- let makePropsType ~loc namedTypeList =
270
- Typ. mk ~loc (Ptyp_object (List. map (makeObjectField loc) namedTypeList, Closed ))
271
-
272
- let newtypeToVar newtype type_ =
273
- let var_desc = Ptyp_var (" type-" ^ newtype) in
274
- let typ (mapper : Ast_mapper.mapper ) typ =
275
- match typ.ptyp_desc with
276
- | Ptyp_constr ({txt = Lident name } , _ ) when name = newtype ->
277
- {typ with ptyp_desc = var_desc}
278
- | _ -> Ast_mapper. default_mapper.typ mapper typ
279
- in
280
- let mapper = {Ast_mapper. default_mapper with typ} in
281
- mapper.typ mapper type_
282
-
283
241
(* TODO: some line number might still be wrong *)
284
242
let jsxMapper () =
285
243
let jsxVersion = ref None in
@@ -656,40 +614,11 @@ let jsxMapper () =
656
614
let wrapExpression, hasUnit, expression = spelunkForFunExpression expression in
657
615
(wrapExpressionWithBinding wrapExpression, hasUnit, expression)
658
616
in
659
- let bindingWrapper, hasUnit, expression = modifiedBinding binding in
660
- let reactComponentAttribute =
661
- try Some (List. find hasAttr binding.pvb_attributes) with Not_found -> None
662
- in
663
- let _attr_loc, payload =
664
- match reactComponentAttribute with
665
- | Some (loc , payload ) -> (loc.loc, Some payload)
666
- | None -> (emptyLoc, None )
667
- in
668
- let props = getPropsAttr payload in
617
+ let bindingWrapper, _hasUnit, expression = modifiedBinding binding in
669
618
(* do stuff here! *)
670
- let namedArgList, newtypes, forwardRef =
619
+ let namedArgList, _newtypes, _forwardRef =
671
620
recursivelyTransformNamedArgsForMake mapper (modifiedBindingOld binding) [] []
672
621
in
673
- let namedArgListWithKeyAndRefForNew =
674
- match forwardRef with
675
- | Some txt -> namedArgList @ [ (nolabel, None , Pat. var { txt; loc = emptyLoc }, txt, emptyLoc, None ) ]
676
- | None -> namedArgList
677
- in
678
- let pluckArg (label , _ , _ , alias , loc , _ ) =
679
- let labelString =
680
- match label with label when isOptional label || isLabelled label -> getLabel label | _ -> " "
681
- in
682
- ( label,
683
- match labelString with
684
- | "" -> Exp. ident ~loc { txt = Lident alias; loc }
685
- | labelString ->
686
- Exp. apply ~loc
687
- (Exp. ident ~loc { txt = Lident " ##" ; loc })
688
- [
689
- (nolabel, Exp. ident ~loc { txt = Lident props.propsName; loc });
690
- (nolabel, Exp. ident ~loc { txt = Lident labelString; loc });
691
- ] )
692
- in
693
622
let namedTypeList = List. fold_left argToType [] namedArgList in
694
623
let vbIgnoreUnusedRef = Vb. mk (Pat. any () ) (Exp. ident (Location. mknoloc (Lident " ref" ))) in
695
624
let namedArgWithDefaultValueList = List. filter_map argWithDefaultValue namedArgList in
@@ -706,52 +635,24 @@ let jsxMapper () =
706
635
])
707
636
in
708
637
let vbMatchList = List. map vbMatch namedArgWithDefaultValueList in
709
- let externalTypes = (* translate newtypes to type variables *)
710
- List. fold_left
711
- (fun args newtype ->
712
- List. map (fun (a , b , c , typ ) -> (a, b, c, newtypeToVar newtype.txt typ)) args)
713
- namedTypeList
714
- newtypes
715
- in
716
638
(* type props = { ... } *)
717
639
let propsRecordType =
718
640
makePropsRecordType " props" emptyLoc
719
641
((true , " key" , [] , keyType emptyLoc) :: (true , " ref" , [] , refType pstr_loc) :: namedTypeList)
720
642
in
721
- let innerExpressionArgs =
722
- List. map pluckArg namedArgListWithKeyAndRefForNew
723
- @ if hasUnit then [ (Nolabel , Exp. construct { loc= emptyLoc; txt = Lident " ()" } None ) ] else []
724
- in
725
- let innerExpression =
726
- Exp. apply
727
- (Exp. ident
728
- { loc= emptyLoc; txt = Lident (match recFlag with Recursive -> internalFnName | Nonrecursive -> fnName) })
729
- innerExpressionArgs
730
- in
731
- let innerExpressionWithRef =
732
- match forwardRef with
733
- | Some txt ->
734
- {
735
- innerExpression with
736
- pexp_desc =
737
- Pexp_fun
738
- ( nolabel,
739
- None ,
740
- { ppat_desc = Ppat_var { txt; loc = emptyLoc }; ppat_loc = emptyLoc; ppat_attributes = [] },
741
- innerExpression );
742
- }
743
- | None -> innerExpression
643
+ let innerExpression = Exp. apply (Exp. ident (Location. mknoloc @@ Lident " make" ))
644
+ [(Nolabel , Exp. ident (Location. mknoloc @@ Lident " props" ))]
744
645
in
745
646
let fullExpression =
647
+ (* React component name should start with uppercase letter *)
648
+ (* let make = { let \"App" = props => make(props); \"App" } *)
746
649
Exp. fun_ nolabel None
747
- {
748
- ppat_desc =
749
- Ppat_constraint
750
- (makePropsName ~loc: emptyLoc props.propsName, makePropsType ~loc: emptyLoc externalTypes);
751
- ppat_loc = emptyLoc;
752
- ppat_attributes = [] ;
753
- }
754
- innerExpressionWithRef
650
+ (match namedTypeList with
651
+ | [] -> (Pat. var @@ Location. mknoloc " props" )
652
+ | _ -> (Pat. constraint_
653
+ (Pat. var @@ Location. mknoloc " props" )
654
+ (Typ. constr (Location. mknoloc @@ Lident " props" )([Typ. any () ]))))
655
+ innerExpression
755
656
in
756
657
let fullExpression =
757
658
match fullModuleName with
@@ -785,33 +686,39 @@ let jsxMapper () =
785
686
expression
786
687
in
787
688
(* let make = ({id, name, ...}: props<'id, 'name, ...>) => { ... } *)
788
- let bindings =
689
+ let bindings, newBinding =
789
690
match recFlag with
790
691
| Recursive ->
791
- [
692
+ ( [
792
693
bindingWrapper
793
694
(Exp. let_ ~loc: emptyLoc Recursive
794
695
[
795
696
makeNewBinding binding expression internalFnName;
796
697
Vb. mk (Pat. var { loc = emptyLoc; txt = fnName }) fullExpression;
797
698
]
798
699
(Exp. ident { loc = emptyLoc; txt = Lident fnName }));
799
- ]
700
+ ], None )
800
701
| Nonrecursive ->
801
- [ { binding with pvb_expr = expression; pvb_attributes = [] } ]
702
+ ( [ { binding with pvb_expr = expression; pvb_attributes = [] } ], Some (bindingWrapper fullExpression))
802
703
in
803
- (Some propsRecordType, bindings)
804
- else (None , [ binding ])
704
+ (Some propsRecordType, bindings, newBinding )
705
+ else (None , [ binding ], None )
805
706
[@@ raises Invalid_argument ]
806
707
in (* END of mapBinding fn *)
807
708
let structuresAndBinding = List. map mapBinding valueBindings in
808
- let otherStructures (type_ , binding ) (types , bindings ) =
709
+ let otherStructures (type_ , binding , newBinding ) (types , bindings , newBindings ) =
809
710
let types = match type_ with Some type_ -> type_ :: types | None -> types in
810
- (types, binding @ bindings)
711
+ let newBindings =
712
+ match newBinding with Some newBinding -> newBinding :: newBindings | None -> newBindings
713
+ in
714
+ (types, binding @ bindings, newBindings)
811
715
in
812
- let types, bindings = List. fold_right otherStructures structuresAndBinding ([] , [] ) in
716
+ let types, bindings, newBindings = List. fold_right otherStructures structuresAndBinding ([] , [] , [] ) in
813
717
types
814
718
@ [ { pstr_loc; pstr_desc = Pstr_value (recFlag, bindings) } ]
719
+ @ ( match newBindings with
720
+ | [] -> []
721
+ | newBindings -> [ { pstr_loc = emptyLoc; pstr_desc = Pstr_value (recFlag, newBindings) } ] )
815
722
@ returnStructures
816
723
| structure -> structure :: returnStructures
817
724
[@@ raises Invalid_argument ]
0 commit comments