Skip to content
This repository was archived by the owner on Jun 15, 2023. It is now read-only.

Commit a7045c8

Browse files
committed
make react component name capitalized
1 parent fbd51e3 commit a7045c8

File tree

1 file changed

+30
-123
lines changed

1 file changed

+30
-123
lines changed

cli/reactjs_jsx_ppx_v3.ml

Lines changed: 30 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,9 @@ let optionalAttr = [ ({ txt = "optional"; loc = Location.none }, PStr []) ]
2323
let constantString ~loc str = Ast_helper.Exp.constant ~loc (Pconst_string (str, None))
2424

2525
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
2829

2930
let 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

4344
type '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 *)
4847
let 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 *)
148126
let 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 *)
284242
let 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

Comments
 (0)