@@ -23,8 +23,9 @@ let optionalAttr = [ ({ txt = "optional"; loc = Location.none }, PStr []) ]
2323let constantString ~loc str = Ast_helper.Exp. constant ~loc (Pconst_string (str, None ))
2424
2525let 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
2829
2930let safeTypeFromValue valueStr =
3031 let valueStr = getLabel valueStr in
@@ -42,8 +43,6 @@ let refType loc = Typ.constr ~loc { loc; txt = Ldot (Lident "React", "ref") }
4243
4344type 'a children = ListLiteral of 'a | Exact of 'a
4445
45- type componentConfig = { propsName : string }
46-
4746(* if children is a list, convert it to an array while mapping each element. If not, just map over it, as usual *)
4847let transformChildrenIfListUpper ~loc ~mapper theList =
4948 let rec transformChildren_ theList accum =
@@ -123,27 +122,6 @@ let makeNewBinding binding expression newName =
123122 | _ -> raise (Invalid_argument " react.component calls cannot be destructured." )
124123 [@@ raises Invalid_argument ]
125124
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-
147125(* Lookup the filename from the location information on the AST node and turn it into a valid module identifier *)
148126let filenameFromLoc (pstr_loc : Location.t ) =
149127 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 =
260238 ~kind: (Ptype_record labelDeclList);
261239 ]
262240
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-
283241(* TODO: some line number might still be wrong *)
284242let jsxMapper () =
285243 let jsxVersion = ref None in
@@ -656,40 +614,11 @@ let jsxMapper () =
656614 let wrapExpression, hasUnit, expression = spelunkForFunExpression expression in
657615 (wrapExpressionWithBinding wrapExpression, hasUnit, expression)
658616 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
669618 (* do stuff here! *)
670- let namedArgList, newtypes, forwardRef =
619+ let namedArgList, _newtypes, _forwardRef =
671620 recursivelyTransformNamedArgsForMake mapper (modifiedBindingOld binding) [] []
672621 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
693622 let namedTypeList = List. fold_left argToType [] namedArgList in
694623 let vbIgnoreUnusedRef = Vb. mk (Pat. any () ) (Exp. ident (Location. mknoloc (Lident " ref" ))) in
695624 let namedArgWithDefaultValueList = List. filter_map argWithDefaultValue namedArgList in
@@ -706,52 +635,24 @@ let jsxMapper () =
706635 ])
707636 in
708637 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
716638 (* type props = { ... } *)
717639 let propsRecordType =
718640 makePropsRecordType " props" emptyLoc
719641 ((true , " key" , [] , keyType emptyLoc) :: (true , " ref" , [] , refType pstr_loc) :: namedTypeList)
720642 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" ))]
744645 in
745646 let fullExpression =
647+ (* React component name should start with uppercase letter *)
648+ (* let make = { let \"App" = props => make(props); \"App" } *)
746649 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
755656 in
756657 let fullExpression =
757658 match fullModuleName with
@@ -785,33 +686,39 @@ let jsxMapper () =
785686 expression
786687 in
787688 (* let make = ({id, name, ...}: props<'id, 'name, ...>) => { ... } *)
788- let bindings =
689+ let bindings, newBinding =
789690 match recFlag with
790691 | Recursive ->
791- [
692+ ( [
792693 bindingWrapper
793694 (Exp. let_ ~loc: emptyLoc Recursive
794695 [
795696 makeNewBinding binding expression internalFnName;
796697 Vb. mk (Pat. var { loc = emptyLoc; txt = fnName }) fullExpression;
797698 ]
798699 (Exp. ident { loc = emptyLoc; txt = Lident fnName }));
799- ]
700+ ], None )
800701 | Nonrecursive ->
801- [ { binding with pvb_expr = expression; pvb_attributes = [] } ]
702+ ( [ { binding with pvb_expr = expression; pvb_attributes = [] } ], Some (bindingWrapper fullExpression))
802703 in
803- (Some propsRecordType, bindings)
804- else (None , [ binding ])
704+ (Some propsRecordType, bindings, newBinding )
705+ else (None , [ binding ], None )
805706 [@@ raises Invalid_argument ]
806707 in (* END of mapBinding fn *)
807708 let structuresAndBinding = List. map mapBinding valueBindings in
808- let otherStructures (type_ , binding ) (types , bindings ) =
709+ let otherStructures (type_ , binding , newBinding ) (types , bindings , newBindings ) =
809710 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)
811715 in
812- let types, bindings = List. fold_right otherStructures structuresAndBinding ([] , [] ) in
716+ let types, bindings, newBindings = List. fold_right otherStructures structuresAndBinding ([] , [] , [] ) in
813717 types
814718 @ [ { pstr_loc; pstr_desc = Pstr_value (recFlag, bindings) } ]
719+ @ ( match newBindings with
720+ | [] -> []
721+ | newBindings -> [ { pstr_loc = emptyLoc; pstr_desc = Pstr_value (recFlag, newBindings) } ] )
815722 @ returnStructures
816723 | structure -> structure :: returnStructures
817724 [@@ raises Invalid_argument ]
0 commit comments