diff --git a/CHANGELOG.md b/CHANGELOG.md
index be4f2516c5..81557b99d3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,7 +14,8 @@
#### :rocket: New Feature
-- experimental support of tagged template literals, eg ```sql`select * from ${table}```. https://github.com/rescript-lang/rescript-compiler/pull/6250
+- Experimental support of tagged template literals, eg ```sql`select * from ${table}```. https://github.com/rescript-lang/rescript-compiler/pull/6250
+- Experimental support for generic/custom JSX transforms. https://github.com/rescript-lang/rescript-compiler/pull/6565
#### :bug: Bug Fix
diff --git a/jscomp/bsb/bsb_jsx.ml b/jscomp/bsb/bsb_jsx.ml
index b4a66de189..b9fbd08661 100644
--- a/jscomp/bsb/bsb_jsx.ml
+++ b/jscomp/bsb/bsb_jsx.ml
@@ -1,5 +1,5 @@
type version = Jsx_v3 | Jsx_v4
-type module_ = React
+type module_ = React | Generic of {moduleName: string}
type mode = Classic | Automatic
type dependencies = string list
@@ -15,7 +15,7 @@ let encode_no_nl jsx =
| None -> ""
| Some Jsx_v3 -> "3"
| Some Jsx_v4 -> "4")
- ^ (match jsx.module_ with None -> "" | Some React -> "React")
+ ^ (match jsx.module_ with None -> "" | Some React -> "React" | Some Generic {moduleName} -> moduleName)
^
match jsx.mode with
| None -> ""
@@ -55,10 +55,10 @@ let from_map map =
`Obj
(fun m ->
match m.?(Bsb_build_schemas.jsx_module) with
- | Some (Str { loc; str }) -> (
+ | Some (Str { str }) -> (
match str with
| "react" -> module_ := Some React
- | _ -> Bsb_exception.errorf ~loc "Unsupported jsx module %s" str)
+ | moduleName -> module_ := Some (Generic {moduleName}))
| Some x ->
Bsb_exception.config_error x
"Unexpected input (jsx module name) for jsx module"
diff --git a/jscomp/bsb/bsb_ninja_rule.ml b/jscomp/bsb/bsb_ninja_rule.ml
index 829a8f5bfe..1103a3ac4c 100644
--- a/jscomp/bsb/bsb_ninja_rule.ml
+++ b/jscomp/bsb/bsb_ninja_rule.ml
@@ -169,7 +169,8 @@ let make_custom_rules ~(gentype_config : Bsb_config_types.gentype_config)
| None, None -> ());
(match jsx.module_ with
| None -> ()
- | Some React -> Ext_buffer.add_string buf " -bs-jsx-module react");
+ | Some React -> Ext_buffer.add_string buf " -bs-jsx-module react"
+ | Some Generic {moduleName} -> Ext_buffer.add_string buf (" -bs-jsx-module " ^ moduleName));
(match jsx.mode with
| None -> ()
| Some Classic -> Ext_buffer.add_string buf " -bs-jsx-mode classic"
diff --git a/jscomp/bsc/rescript_compiler_main.ml b/jscomp/bsc/rescript_compiler_main.ml
index 6a4d63173c..0307e1f708 100644
--- a/jscomp/bsc/rescript_compiler_main.ml
+++ b/jscomp/bsc/rescript_compiler_main.ml
@@ -251,7 +251,6 @@ let buckle_script_flags : (string * Bsc_args.spec * string) array =
"*internal* Set jsx version";
"-bs-jsx-module", string_call (fun i ->
- (if i <> "react" then Bsc_args.bad_arg (" Not supported jsx-module : " ^ i));
Js_config.jsx_module := Js_config.jsx_module_of_string i),
"*internal* Set jsx module";
diff --git a/jscomp/common/js_config.ml b/jscomp/common/js_config.ml
index ef3ad90b60..7602c681e2 100644
--- a/jscomp/common/js_config.ml
+++ b/jscomp/common/js_config.ml
@@ -25,7 +25,7 @@
(** Browser is not set via command line only for internal use *)
type jsx_version = Jsx_v3 | Jsx_v4
-type jsx_module = React
+type jsx_module = React | Generic of {moduleName: string}
type jsx_mode = Classic | Automatic
let no_version_header = ref false
@@ -64,6 +64,7 @@ let int_of_jsx_version = function
let string_of_jsx_module = function
| React -> "react"
+| Generic {moduleName} -> moduleName
let string_of_jsx_mode = function
| Classic -> "classic"
@@ -76,7 +77,7 @@ let jsx_version_of_int = function
let jsx_module_of_string = function
| "react" -> React
-| _ -> React
+| moduleName -> Generic {moduleName}
let jsx_mode_of_string = function
| "classic" -> Classic
diff --git a/jscomp/common/js_config.mli b/jscomp/common/js_config.mli
index f5df0349d3..fd9df5785a 100644
--- a/jscomp/common/js_config.mli
+++ b/jscomp/common/js_config.mli
@@ -23,7 +23,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
type jsx_version = Jsx_v3 | Jsx_v4
-type jsx_module = React
+type jsx_module = React | Generic of {moduleName: string}
type jsx_mode = Classic | Automatic
(* val get_packages_info :
diff --git a/jscomp/frontend/ppx_entry.ml b/jscomp/frontend/ppx_entry.ml
index 7f73ef8414..67d50bb61c 100644
--- a/jscomp/frontend/ppx_entry.ml
+++ b/jscomp/frontend/ppx_entry.ml
@@ -35,7 +35,7 @@ let rewrite_signature (ast : Parsetree.signature) : Parsetree.signature =
let jsxVersion = int_of_jsx_version jsxVersion in
let jsxModule = string_of_jsx_module !jsx_module in
let jsxMode = string_of_jsx_mode !jsx_mode in
- Reactjs_jsx_ppx.rewrite_signature ~jsxVersion ~jsxModule ~jsxMode ast
+ Jsx_ppx.rewrite_signature ~jsxVersion ~jsxModule ~jsxMode ast
in
if !Js_config.no_builtin_ppx then ast
else
@@ -55,7 +55,7 @@ let rewrite_implementation (ast : Parsetree.structure) : Parsetree.structure =
let jsxVersion = int_of_jsx_version jsxVersion in
let jsxModule = string_of_jsx_module !jsx_module in
let jsxMode = string_of_jsx_mode !jsx_mode in
- Reactjs_jsx_ppx.rewrite_implementation ~jsxVersion ~jsxModule ~jsxMode ast
+ Jsx_ppx.rewrite_implementation ~jsxVersion ~jsxModule ~jsxMode ast
in
if !Js_config.no_builtin_ppx then ast
else
diff --git a/jscomp/syntax/cli/res_cli.ml b/jscomp/syntax/cli/res_cli.ml
index bcc4024259..23d9006f35 100644
--- a/jscomp/syntax/cli/res_cli.ml
+++ b/jscomp/syntax/cli/res_cli.ml
@@ -284,7 +284,7 @@ module CliArgProcessor = struct
else exit 1)
else
let parsetree =
- Reactjs_jsx_ppx.rewrite_signature ~jsxVersion ~jsxModule ~jsxMode
+ Jsx_ppx.rewrite_signature ~jsxVersion ~jsxModule ~jsxMode
parseResult.parsetree
in
printEngine.printInterface ~width ~filename
@@ -300,7 +300,7 @@ module CliArgProcessor = struct
else exit 1)
else
let parsetree =
- Reactjs_jsx_ppx.rewrite_implementation ~jsxVersion ~jsxModule ~jsxMode
+ Jsx_ppx.rewrite_implementation ~jsxVersion ~jsxModule ~jsxMode
parseResult.parsetree
in
printEngine.printImplementation ~width ~filename
diff --git a/jscomp/syntax/src/react_jsx_common.ml b/jscomp/syntax/src/jsx_common.ml
similarity index 88%
rename from jscomp/syntax/src/react_jsx_common.ml
rename to jscomp/syntax/src/jsx_common.ml
index 51c4711032..4281f0580a 100644
--- a/jscomp/syntax/src/react_jsx_common.ml
+++ b/jscomp/syntax/src/jsx_common.ml
@@ -6,11 +6,14 @@ type jsxConfig = {
mutable module_: string;
mutable mode: string;
mutable nestedModules: string list;
- mutable hasReactComponent: bool;
+ mutable hasComponent: bool;
}
(* Helper method to look up the [@react.component] attribute *)
-let hasAttr (loc, _) = loc.txt = "react.component"
+let hasAttr (loc, _) =
+ match loc.txt with
+ | "react.component" | "jsx.component" -> true
+ | _ -> false
(* Iterate over the attributes and try to find the [@react.component] attribute *)
let hasAttrOnBinding {pvb_attributes} =
@@ -20,7 +23,7 @@ let coreTypeOfAttrs attributes =
List.find_map
(fun ({txt}, payload) ->
match (txt, payload) with
- | "react.component", PTyp coreType -> Some coreType
+ | ("react.component" | "jsx.component"), PTyp coreType -> Some coreType
| _ -> None)
attributes
@@ -37,7 +40,7 @@ let typVarsOfCoreType {ptyp_desc} =
let raiseError ~loc msg = Location.raise_errorf ~loc msg
-let raiseErrorMultipleReactComponent ~loc =
+let raiseErrorMultipleComponent ~loc =
raiseError ~loc
"Only one component definition is allowed for each module. Move to a \
submodule or other file if necessary."
diff --git a/jscomp/syntax/src/reactjs_jsx_ppx.ml b/jscomp/syntax/src/jsx_ppx.ml
similarity index 88%
rename from jscomp/syntax/src/reactjs_jsx_ppx.ml
rename to jscomp/syntax/src/jsx_ppx.ml
index f6449a6cc1..e362a9c0a5 100644
--- a/jscomp/syntax/src/reactjs_jsx_ppx.ml
+++ b/jscomp/syntax/src/jsx_ppx.ml
@@ -50,8 +50,8 @@ let updateConfig config payload =
let fields = getPayloadFields payload in
(match getInt ~key:"version" fields with
| None -> ()
- | Some i -> config.React_jsx_common.version <- i);
- (match getString ~key:"module" fields with
+ | Some i -> config.Jsx_common.version <- i);
+ (match getString ~key:"module_" fields with
| None -> ()
| Some s -> config.module_ <- s);
match getString ~key:"mode" fields with
@@ -68,7 +68,7 @@ let getMapper ~config =
Reactjs_jsx_v3.jsxMapper ~config
in
let expr4, module_binding4, transformSignatureItem4, transformStructureItem4 =
- Reactjs_jsx_v4.jsxMapper ~config
+ Jsx_v4.jsxMapper ~config
in
let expr mapper e =
@@ -89,18 +89,18 @@ let getMapper ~config =
version = config.version;
module_ = config.module_;
mode = config.mode;
- hasReactComponent = config.hasReactComponent;
+ hasComponent = config.hasComponent;
}
in
let restoreConfig oldConfig =
- config.version <- oldConfig.React_jsx_common.version;
+ config.version <- oldConfig.Jsx_common.version;
config.module_ <- oldConfig.module_;
config.mode <- oldConfig.mode;
- config.hasReactComponent <- oldConfig.hasReactComponent
+ config.hasComponent <- oldConfig.hasComponent
in
let signature mapper items =
let oldConfig = saveConfig () in
- config.hasReactComponent <- false;
+ config.hasComponent <- false;
let result =
List.map
(fun item ->
@@ -119,7 +119,7 @@ let getMapper ~config =
in
let structure mapper items =
let oldConfig = saveConfig () in
- config.hasReactComponent <- false;
+ config.hasComponent <- false;
let result =
List.map
(fun item ->
@@ -143,11 +143,11 @@ let rewrite_implementation ~jsxVersion ~jsxModule ~jsxMode
(code : Parsetree.structure) : Parsetree.structure =
let config =
{
- React_jsx_common.version = jsxVersion;
+ Jsx_common.version = jsxVersion;
module_ = jsxModule;
mode = jsxMode;
nestedModules = [];
- hasReactComponent = false;
+ hasComponent = false;
}
in
let mapper = getMapper ~config in
@@ -157,11 +157,11 @@ let rewrite_signature ~jsxVersion ~jsxModule ~jsxMode
(code : Parsetree.signature) : Parsetree.signature =
let config =
{
- React_jsx_common.version = jsxVersion;
+ Jsx_common.version = jsxVersion;
module_ = jsxModule;
mode = jsxMode;
nestedModules = [];
- hasReactComponent = false;
+ hasComponent = false;
}
in
let mapper = getMapper ~config in
diff --git a/jscomp/syntax/src/reactjs_jsx_ppx.mli b/jscomp/syntax/src/jsx_ppx.mli
similarity index 100%
rename from jscomp/syntax/src/reactjs_jsx_ppx.mli
rename to jscomp/syntax/src/jsx_ppx.mli
diff --git a/jscomp/syntax/src/reactjs_jsx_v4.ml b/jscomp/syntax/src/jsx_v4.ml
similarity index 90%
rename from jscomp/syntax/src/reactjs_jsx_v4.ml
rename to jscomp/syntax/src/jsx_v4.ml
index e62054d80f..5246bbd31c 100644
--- a/jscomp/syntax/src/reactjs_jsx_v4.ml
+++ b/jscomp/syntax/src/jsx_v4.ml
@@ -4,6 +4,8 @@ open Asttypes
open Parsetree
open Longident
+let moduleAccessName config = String.capitalize_ascii config.Jsx_common.module_
+
let nolabel = Nolabel
let labelled str = Labelled str
@@ -27,7 +29,7 @@ let getLabel str =
| Optional str | Labelled str -> str
| Nolabel -> ""
-let optionalAttrs = [React_jsx_common.optionalAttr]
+let optionalAttrs = [Jsx_common.optionalAttr]
let constantString ~loc str =
Ast_helper.Exp.constant ~loc (Pconst_string (str, None))
@@ -93,7 +95,7 @@ let extractChildren ?(removeLastPositionUnit = false) ~loc propsAndChildren =
| [(Nolabel, {pexp_desc = Pexp_construct ({txt = Lident "()"}, None)})] ->
acc
| (Nolabel, {pexp_loc}) :: _rest ->
- React_jsx_common.raiseError ~loc:pexp_loc
+ Jsx_common.raiseError ~loc:pexp_loc
"JSX: found non-labelled argument before the last position"
| arg :: rest -> allButLast_ rest (arg :: acc)
in
@@ -110,13 +112,16 @@ let extractChildren ?(removeLastPositionUnit = false) ~loc propsAndChildren =
| [(_, childrenExpr)], props ->
(childrenExpr, if removeLastPositionUnit then allButLast props else props)
| _ ->
- React_jsx_common.raiseError ~loc
+ Jsx_common.raiseError ~loc
"JSX: somehow there's more than one `children` label"
let merlinFocus = ({loc = Location.none; txt = "merlin.focus"}, PStr [])
(* Helper method to filter out any attribute that isn't [@react.component] *)
-let otherAttrsPure (loc, _) = loc.txt <> "react.component"
+let otherAttrsPure (loc, _) =
+ match loc.txt with
+ | "react.component" | "jsx.component" -> false
+ | _ -> true
(* Finds the name of the variable the binding is assigned to, otherwise raises Invalid_argument *)
let rec getFnName binding =
@@ -124,8 +129,8 @@ let rec getFnName binding =
| {ppat_desc = Ppat_var {txt}} -> txt
| {ppat_desc = Ppat_constraint (pat, _)} -> getFnName pat
| {ppat_loc} ->
- React_jsx_common.raiseError ~loc:ppat_loc
- "react.component calls cannot be destructured."
+ Jsx_common.raiseError ~loc:ppat_loc
+ "JSX component calls cannot be destructured."
let makeNewBinding binding expression newName =
match binding with
@@ -138,8 +143,8 @@ let makeNewBinding binding expression newName =
pvb_attributes = [merlinFocus];
}
| {pvb_loc} ->
- React_jsx_common.raiseError ~loc:pvb_loc
- "react.component calls cannot be destructured."
+ Jsx_common.raiseError ~loc:pvb_loc
+ "JSX component calls cannot be destructured."
(* Lookup the filename from the location information on the AST node and turn it into a valid module identifier *)
let filenameFromLoc (pstr_loc : Location.t) =
@@ -184,7 +189,7 @@ let recordFromProps ~loc ~removeKey callArguments =
| [(Nolabel, {pexp_desc = Pexp_construct ({txt = Lident "()"}, None)})] ->
acc
| (Nolabel, {pexp_loc}) :: _rest ->
- React_jsx_common.raiseError ~loc:pexp_loc
+ Jsx_common.raiseError ~loc:pexp_loc
"JSX: found non-labelled argument before the last position"
| ((Labelled txt, {pexp_loc}) as prop) :: rest
| ((Optional txt, {pexp_loc}) as prop) :: rest ->
@@ -192,7 +197,7 @@ let recordFromProps ~loc ~removeKey callArguments =
match acc with
| [] -> removeLastPositionUnitAux rest (prop :: acc)
| _ ->
- React_jsx_common.raiseError ~loc:pexp_loc
+ Jsx_common.raiseError ~loc:pexp_loc
"JSX: use {...p} {x: v} not {x: v} {...p} \n\
\ multiple spreads {...p} {...p} not allowed."
else removeLastPositionUnitAux rest (prop :: acc)
@@ -297,8 +302,7 @@ let makeLabelDecls namedTypeList =
| hd :: tl ->
if mem_label hd tl then
let _, label, _, loc, _ = hd in
- React_jsx_common.raiseError ~loc "JSX: found the duplicated prop `%s`"
- label
+ Jsx_common.raiseError ~loc "JSX: found the duplicated prop `%s`" label
else checkDuplicatedLabel tl
in
let () = namedTypeList |> List.rev |> checkDuplicatedLabel in
@@ -374,13 +378,16 @@ let transformUppercaseCall3 ~config modulePath mapper jsxExprLoc callExprLoc
| ListLiteral expression -> (
(* this is a hack to support react components that introspect into their children *)
childrenArg := Some expression;
- match config.React_jsx_common.mode with
+ match config.Jsx_common.mode with
| "automatic" ->
[
( labelled "children",
Exp.apply
(Exp.ident
- {txt = Ldot (Lident "React", "array"); loc = Location.none})
+ {
+ txt = Ldot (Lident (moduleAccessName config), "array");
+ loc = Location.none;
+ })
[(Nolabel, expression)] );
]
| _ ->
@@ -424,16 +431,31 @@ let transformUppercaseCall3 ~config modulePath mapper jsxExprLoc callExprLoc
match (!childrenArg, keyProp) with
| None, key :: _ ->
( Exp.ident
- {loc = Location.none; txt = Ldot (Lident "React", "jsxKeyed")},
+ {
+ loc = Location.none;
+ txt = Ldot (Lident (moduleAccessName config), "jsxKeyed");
+ },
[key; (nolabel, unitExpr ~loc:Location.none)] )
| None, [] ->
- (Exp.ident {loc = Location.none; txt = Ldot (Lident "React", "jsx")}, [])
+ ( Exp.ident
+ {
+ loc = Location.none;
+ txt = Ldot (Lident (moduleAccessName config), "jsx");
+ },
+ [] )
| Some _, key :: _ ->
( Exp.ident
- {loc = Location.none; txt = Ldot (Lident "React", "jsxsKeyed")},
+ {
+ loc = Location.none;
+ txt = Ldot (Lident (moduleAccessName config), "jsxsKeyed");
+ },
[key; (nolabel, unitExpr ~loc:Location.none)] )
| Some _, [] ->
- ( Exp.ident {loc = Location.none; txt = Ldot (Lident "React", "jsxs")},
+ ( Exp.ident
+ {
+ loc = Location.none;
+ txt = Ldot (Lident (moduleAccessName config), "jsxs");
+ },
[] )
in
Exp.apply ~loc:jsxExprLoc ~attrs jsxExpr
@@ -474,9 +496,15 @@ let transformUppercaseCall3 ~config modulePath mapper jsxExprLoc callExprLoc
let transformLowercaseCall3 ~config mapper jsxExprLoc callExprLoc attrs
callArguments id =
let componentNameExpr = constantString ~loc:callExprLoc id in
- match config.React_jsx_common.mode with
+ match config.Jsx_common.mode with
(* the new jsx transform *)
| "automatic" ->
+ let elementBinding =
+ match moduleAccessName config with
+ | "React" -> Lident "ReactDOM"
+ | generic -> Ldot (Lident generic, "DOM")
+ in
+
let children, nonChildrenProps =
extractChildren ~removeLastPositionUnit:true ~loc:jsxExprLoc callArguments
in
@@ -498,7 +526,7 @@ let transformLowercaseCall3 ~config mapper jsxExprLoc callExprLoc attrs
Exp.apply ~attrs:optionalAttrs
(Exp.ident
{
- txt = Ldot (Lident "ReactDOM", "someElement");
+ txt = Ldot (elementBinding, "someElement");
loc = Location.none;
})
[(Nolabel, children)] );
@@ -511,7 +539,10 @@ let transformLowercaseCall3 ~config mapper jsxExprLoc callExprLoc attrs
( labelled "children",
Exp.apply
(Exp.ident
- {txt = Ldot (Lident "React", "array"); loc = Location.none})
+ {
+ txt = Ldot (Lident (moduleAccessName config), "array");
+ loc = Location.none;
+ })
[(Nolabel, expression)] );
]
in
@@ -531,17 +562,16 @@ let transformLowercaseCall3 ~config mapper jsxExprLoc callExprLoc attrs
match (!childrenArg, keyProp) with
| None, key :: _ ->
( Exp.ident
- {loc = Location.none; txt = Ldot (Lident "ReactDOM", "jsxKeyed")},
+ {loc = Location.none; txt = Ldot (elementBinding, "jsxKeyed")},
[key; (nolabel, unitExpr ~loc:Location.none)] )
| None, [] ->
- ( Exp.ident {loc = Location.none; txt = Ldot (Lident "ReactDOM", "jsx")},
- [] )
+ (Exp.ident {loc = Location.none; txt = Ldot (elementBinding, "jsx")}, [])
| Some _, key :: _ ->
( Exp.ident
- {loc = Location.none; txt = Ldot (Lident "ReactDOM", "jsxsKeyed")},
+ {loc = Location.none; txt = Ldot (elementBinding, "jsxsKeyed")},
[key; (nolabel, unitExpr ~loc:Location.none)] )
| Some _, [] ->
- ( Exp.ident {loc = Location.none; txt = Ldot (Lident "ReactDOM", "jsxs")},
+ ( Exp.ident {loc = Location.none; txt = Ldot (elementBinding, "jsxs")},
[] )
in
Exp.apply ~loc:jsxExprLoc ~attrs jsxExpr
@@ -562,7 +592,7 @@ let transformLowercaseCall3 ~config mapper jsxExprLoc callExprLoc attrs
"createDOMElementVariadic"
(* [@JSX] div(~children= value), coming from
...(value)
*)
| {pexp_loc} ->
- React_jsx_common.raiseError ~loc:pexp_loc
+ Jsx_common.raiseError ~loc:pexp_loc
"A spread as a DOM element's children don't make sense written \
together. You can simply remove the spread."
in
@@ -601,11 +631,11 @@ let rec recursivelyTransformNamedArgsForMake expr args newtypes coreType =
match expr.pexp_desc with
(* TODO: make this show up with a loc. *)
| Pexp_fun (Labelled "key", _, _, _) | Pexp_fun (Optional "key", _, _, _) ->
- React_jsx_common.raiseError ~loc:expr.pexp_loc
+ Jsx_common.raiseError ~loc:expr.pexp_loc
"Key cannot be accessed inside of a component. Don't worry - you can \
always key a component from its parent!"
| Pexp_fun (Labelled "ref", _, _, _) | Pexp_fun (Optional "ref", _, _, _) ->
- React_jsx_common.raiseError ~loc:expr.pexp_loc
+ Jsx_common.raiseError ~loc:expr.pexp_loc
"Ref cannot be passed as a normal prop. Please use `forwardRef` API \
instead."
| Pexp_fun (arg, default, pattern, expression)
@@ -721,18 +751,18 @@ let argToConcreteType types (name, attrs, loc, type_) =
let check_string_int_attribute_iter =
let attribute _ ({txt; loc}, _) =
if txt = "string" || txt = "int" then
- React_jsx_common.raiseError ~loc
+ Jsx_common.raiseError ~loc
"@string and @int attributes not supported. See \
https://github.com/rescript-lang/rescript-compiler/issues/5724"
in
{Ast_iterator.default_iterator with attribute}
-let checkMultipleReactComponents ~config ~loc =
- (* If there is another @react.component, throw error *)
- if config.React_jsx_common.hasReactComponent then
- React_jsx_common.raiseErrorMultipleReactComponent ~loc
- else config.hasReactComponent <- true
+let checkMultipleComponents ~config ~loc =
+ (* If there is another component, throw error *)
+ if config.Jsx_common.hasComponent then
+ Jsx_common.raiseErrorMultipleComponent ~loc
+ else config.hasComponent <- true
let modifiedBindingOld binding =
let expression = binding.pvb_expr in
@@ -757,9 +787,9 @@ let modifiedBindingOld binding =
| {pexp_desc = Pexp_constraint (innerFunctionExpression, _typ)} ->
spelunkForFunExpression innerFunctionExpression
| {pexp_loc} ->
- React_jsx_common.raiseError ~loc:pexp_loc
- "react.component calls can only be on function definitions or \
- component wrappers (forwardRef, memo)."
+ Jsx_common.raiseError ~loc:pexp_loc
+ "JSX component calls can only be on function definitions or component \
+ wrappers (forwardRef, memo)."
in
spelunkForFunExpression expression
@@ -882,15 +912,13 @@ let vbMatchExpr namedArgList expr =
aux (List.rev namedArgList)
let mapBinding ~config ~emptyLoc ~pstr_loc ~fileName ~recFlag binding =
- if React_jsx_common.hasAttrOnBinding binding then (
- checkMultipleReactComponents ~config ~loc:pstr_loc;
- let binding = React_jsx_common.removeArity binding in
- let coreTypeOfAttr =
- React_jsx_common.coreTypeOfAttrs binding.pvb_attributes
- in
+ if Jsx_common.hasAttrOnBinding binding then (
+ checkMultipleComponents ~config ~loc:pstr_loc;
+ let binding = Jsx_common.removeArity binding in
+ let coreTypeOfAttr = Jsx_common.coreTypeOfAttrs binding.pvb_attributes in
let typVarsOfCoreType =
coreTypeOfAttr
- |> Option.map React_jsx_common.typVarsOfCoreType
+ |> Option.map Jsx_common.typVarsOfCoreType
|> Option.value ~default:[]
in
let bindingLoc = binding.pvb_loc in
@@ -947,7 +975,7 @@ let mapBinding ~config ~emptyLoc ~pstr_loc ~fileName ~recFlag binding =
(Typ.constr (Location.mknoloc @@ Lident "props") [Typ.any ()])
in
let innerExpression =
- React_jsx_common.async_component ~async:isAsync innerExpression
+ Jsx_common.async_component ~async:isAsync innerExpression
in
let fullExpression =
(* React component name should start with uppercase letter *)
@@ -1129,17 +1157,17 @@ let transformStructureItem ~config item =
pstr_desc =
Pstr_primitive ({pval_attributes; pval_type} as value_description);
} as pstr -> (
- match List.filter React_jsx_common.hasAttr pval_attributes with
+ match List.filter Jsx_common.hasAttr pval_attributes with
| [] -> [item]
| [_] ->
- checkMultipleReactComponents ~config ~loc:pstr_loc;
+ checkMultipleComponents ~config ~loc:pstr_loc;
check_string_int_attribute_iter.structure_item
check_string_int_attribute_iter item;
- let pval_type = React_jsx_common.extractUncurried pval_type in
- let coreTypeOfAttr = React_jsx_common.coreTypeOfAttrs pval_attributes in
+ let pval_type = Jsx_common.extractUncurried pval_type in
+ let coreTypeOfAttr = Jsx_common.coreTypeOfAttrs pval_attributes in
let typVarsOfCoreType =
coreTypeOfAttr
- |> Option.map React_jsx_common.typVarsOfCoreType
+ |> Option.map Jsx_common.typVarsOfCoreType
|> Option.value ~default:[]
in
let rec getPropTypes types
@@ -1175,7 +1203,10 @@ let transformStructureItem ~config item =
(* can't be an arrow because it will defensively uncurry *)
let newExternalType =
Ptyp_constr
- ( {loc = pstr_loc; txt = Ldot (Lident "React", "componentLike")},
+ ( {
+ loc = pstr_loc;
+ txt = Ldot (Lident (moduleAccessName config), "componentLike");
+ },
[retPropsType; innerType] )
in
let newStructure =
@@ -1192,8 +1223,8 @@ let transformStructureItem ~config item =
in
[propsRecordType; newStructure]
| _ ->
- React_jsx_common.raiseError ~loc:pstr_loc
- "Only one react.component call can exist on a component at one time")
+ Jsx_common.raiseError ~loc:pstr_loc
+ "Only one JSX component call can exist on a component at one time")
(* let component = ... *)
| {pstr_loc; pstr_desc = Pstr_value (recFlag, valueBindings)} -> (
let fileName = filenameFromLoc pstr_loc in
@@ -1232,18 +1263,18 @@ let transformSignatureItem ~config item =
psig_loc;
psig_desc = Psig_value ({pval_attributes; pval_type} as psig_desc);
} as psig -> (
- match List.filter React_jsx_common.hasAttr pval_attributes with
+ match List.filter Jsx_common.hasAttr pval_attributes with
| [] -> [item]
| [_] ->
- checkMultipleReactComponents ~config ~loc:psig_loc;
- let pval_type = React_jsx_common.extractUncurried pval_type in
+ checkMultipleComponents ~config ~loc:psig_loc;
+ let pval_type = Jsx_common.extractUncurried pval_type in
check_string_int_attribute_iter.signature_item
check_string_int_attribute_iter item;
let hasForwardRef = ref false in
- let coreTypeOfAttr = React_jsx_common.coreTypeOfAttrs pval_attributes in
+ let coreTypeOfAttr = Jsx_common.coreTypeOfAttrs pval_attributes in
let typVarsOfCoreType =
coreTypeOfAttr
- |> Option.map React_jsx_common.typVarsOfCoreType
+ |> Option.map Jsx_common.typVarsOfCoreType
|> Option.value ~default:[]
in
let rec getPropTypes types ({ptyp_loc; ptyp_desc} as fullType) =
@@ -1290,7 +1321,10 @@ let transformSignatureItem ~config item =
(* can't be an arrow because it will defensively uncurry *)
let newExternalType =
Ptyp_constr
- ( {loc = psig_loc; txt = Ldot (Lident "React", "componentLike")},
+ ( {
+ loc = psig_loc;
+ txt = Ldot (Lident (moduleAccessName config), "componentLike");
+ },
[retPropsType; innerType] )
in
let newStructure =
@@ -1307,8 +1341,8 @@ let transformSignatureItem ~config item =
in
[propsRecordType; newStructure]
| _ ->
- React_jsx_common.raiseError ~loc:psig_loc
- "Only one react.component call can exist on a component at one time")
+ Jsx_common.raiseError ~loc:psig_loc
+ "Only one JSX component call can exist on a component at one time")
| _ -> [item]
let transformJsxCall ~config mapper callExpression callArguments jsxExprLoc
@@ -1317,7 +1351,7 @@ let transformJsxCall ~config mapper callExpression callArguments jsxExprLoc
| Pexp_ident caller -> (
match caller with
| {txt = Lident "createElement"; loc} ->
- React_jsx_common.raiseError ~loc
+ Jsx_common.raiseError ~loc
"JSX: `createElement` should be preceeded by a module name."
(* Foo.createElement(~prop1=foo, ~prop2=bar, ~children=[], ()) *)
| {loc; txt = Ldot (modulePath, ("createElement" | "make"))} ->
@@ -1330,18 +1364,18 @@ let transformJsxCall ~config mapper callExpression callArguments jsxExprLoc
transformLowercaseCall3 ~config mapper jsxExprLoc loc attrs callArguments
id
| {txt = Ldot (_, anythingNotCreateElementOrMake); loc} ->
- React_jsx_common.raiseError ~loc
+ Jsx_common.raiseError ~loc
"JSX: the JSX attribute should be attached to a \
`YourModuleName.createElement` or `YourModuleName.make` call. We saw \
`%s` instead"
anythingNotCreateElementOrMake
| {txt = Lapply _; loc} ->
(* don't think there's ever a case where this is reached *)
- React_jsx_common.raiseError ~loc
+ Jsx_common.raiseError ~loc
"JSX: encountered a weird case while processing the code. Please \
report this!")
| _ ->
- React_jsx_common.raiseError ~loc:callExpression.pexp_loc
+ Jsx_common.raiseError ~loc:callExpression.pexp_loc
"JSX: `createElement` should be preceeded by a simple, direct module \
name."
@@ -1385,7 +1419,8 @@ let expr ~config mapper expression =
let fragment =
match config.mode with
| "automatic" ->
- Exp.ident ~loc {loc; txt = Ldot (Lident "React", "jsxFragment")}
+ Exp.ident ~loc
+ {loc; txt = Ldot (Lident (moduleAccessName config), "jsxFragment")}
| "classic" | _ ->
Exp.ident ~loc {loc; txt = Ldot (Lident "React", "fragment")}
in
@@ -1393,10 +1428,13 @@ let expr ~config mapper expression =
let recordOfChildren children =
Exp.record [(Location.mknoloc (Lident "children"), children)] None
in
- let applyReactArray expr =
+ let applyJsxArray expr =
Exp.apply
(Exp.ident
- {txt = Ldot (Lident "React", "array"); loc = Location.none})
+ {
+ txt = Ldot (Lident (moduleAccessName config), "array");
+ loc = Location.none;
+ })
[(Nolabel, expr)]
in
let countOfChildren = function
@@ -1411,11 +1449,11 @@ let expr ~config mapper expression =
| [child] -> recordOfChildren child
| _ -> (
match config.mode with
- | "automatic" -> recordOfChildren @@ applyReactArray childrenExpr
+ | "automatic" -> recordOfChildren @@ applyJsxArray childrenExpr
| "classic" | _ -> emptyRecord ~loc:Location.none))
| _ -> (
match config.mode with
- | "automatic" -> recordOfChildren @@ applyReactArray childrenExpr
+ | "automatic" -> recordOfChildren @@ applyJsxArray childrenExpr
| "classic" | _ -> emptyRecord ~loc:Location.none)
in
let args =
@@ -1434,8 +1472,11 @@ let expr ~config mapper expression =
(match config.mode with
| "automatic" ->
if countOfChildren childrenExpr > 1 then
- Exp.ident ~loc {loc; txt = Ldot (Lident "React", "jsxs")}
- else Exp.ident ~loc {loc; txt = Ldot (Lident "React", "jsx")}
+ Exp.ident ~loc
+ {loc; txt = Ldot (Lident (moduleAccessName config), "jsxs")}
+ else
+ Exp.ident ~loc
+ {loc; txt = Ldot (Lident (moduleAccessName config), "jsx")}
| "classic" | _ ->
if countOfChildren childrenExpr > 1 then
Exp.ident ~loc
@@ -1446,8 +1487,7 @@ let expr ~config mapper expression =
(* Delegate to the default mapper, a deep identity traversal *)
| e -> default_mapper.expr mapper e
-let module_binding ~(config : React_jsx_common.jsxConfig) mapper module_binding
- =
+let module_binding ~(config : Jsx_common.jsxConfig) mapper module_binding =
config.nestedModules <- module_binding.pmb_name.txt :: config.nestedModules;
let mapped = default_mapper.module_binding mapper module_binding in
let () =
diff --git a/jscomp/syntax/src/reactjs_jsx_v3.ml b/jscomp/syntax/src/reactjs_jsx_v3.ml
index 0ecbb4cf43..83316c9d5c 100644
--- a/jscomp/syntax/src/reactjs_jsx_v3.ml
+++ b/jscomp/syntax/src/reactjs_jsx_v3.ml
@@ -87,7 +87,7 @@ let extractChildren ?(removeLastPositionUnit = false) ~loc propsAndChildren =
| [(Nolabel, {pexp_desc = Pexp_construct ({txt = Lident "()"}, None)})] ->
acc
| (Nolabel, {pexp_loc}) :: _rest ->
- React_jsx_common.raiseError ~loc:pexp_loc
+ Jsx_common.raiseError ~loc:pexp_loc
"JSX: found non-labelled argument before the last position"
| arg :: rest -> allButLast_ rest (arg :: acc)
in
@@ -104,7 +104,7 @@ let extractChildren ?(removeLastPositionUnit = false) ~loc propsAndChildren =
| [(_, childrenExpr)], props ->
(childrenExpr, if removeLastPositionUnit then allButLast props else props)
| _ ->
- React_jsx_common.raiseError ~loc
+ Jsx_common.raiseError ~loc
"JSX: somehow there's more than one `children` label"
let unerasableIgnore loc =
@@ -122,7 +122,7 @@ let rec getFnName binding =
| {ppat_desc = Ppat_var {txt}} -> txt
| {ppat_desc = Ppat_constraint (pat, _)} -> getFnName pat
| {ppat_loc} ->
- React_jsx_common.raiseError ~loc:ppat_loc
+ Jsx_common.raiseError ~loc:ppat_loc
"react.component calls cannot be destructured."
let makeNewBinding binding expression newName =
@@ -136,7 +136,7 @@ let makeNewBinding binding expression newName =
pvb_attributes = [merlinFocus];
}
| {pvb_loc} ->
- React_jsx_common.raiseError ~loc:pvb_loc
+ Jsx_common.raiseError ~loc:pvb_loc
"react.component calls cannot be destructured."
(* Lookup the value of `props` otherwise raise Invalid_argument error *)
@@ -145,7 +145,7 @@ let getPropsNameValue _acc (loc, exp) =
| {txt = Lident "props"}, {pexp_desc = Pexp_ident {txt = Lident str}} ->
{propsName = str}
| {txt; loc}, _ ->
- React_jsx_common.raiseError ~loc
+ Jsx_common.raiseError ~loc
"react.component only accepts props as an option, given: { %s }"
(Longident.last txt)
@@ -170,7 +170,7 @@ let getPropsAttr payload =
:: _rest)) ->
{propsName = "props"}
| Some (PStr ({pstr_desc = Pstr_eval (_, _); pstr_loc} :: _rest)) ->
- React_jsx_common.raiseError ~loc:pstr_loc
+ Jsx_common.raiseError ~loc:pstr_loc
"react.component accepts a record config with props as an options."
| _ -> defaultProps
@@ -368,7 +368,7 @@ let jsxMapper ~config =
| Lident path -> Lident (path ^ "Props")
| Ldot (ident, path) -> Ldot (ident, path ^ "Props")
| _ ->
- React_jsx_common.raiseError ~loc
+ Jsx_common.raiseError ~loc
"JSX name can't be the result of function applications"
in
let props =
@@ -407,7 +407,7 @@ let jsxMapper ~config =
"createDOMElementVariadic"
(* [@JSX] div(~children= value), coming from ...(value)
*)
| {pexp_loc} ->
- React_jsx_common.raiseError ~loc:pexp_loc
+ Jsx_common.raiseError ~loc:pexp_loc
"A spread as a DOM element's children don't make sense written \
together. You can simply remove the spread."
in
@@ -450,11 +450,11 @@ let jsxMapper ~config =
match expr.pexp_desc with
(* TODO: make this show up with a loc. *)
| Pexp_fun (Labelled "key", _, _, _) | Pexp_fun (Optional "key", _, _, _) ->
- React_jsx_common.raiseError ~loc:expr.pexp_loc
+ Jsx_common.raiseError ~loc:expr.pexp_loc
"Key cannot be accessed inside of a component. Don't worry - you can \
always key a component from its parent!"
| Pexp_fun (Labelled "ref", _, _, _) | Pexp_fun (Optional "ref", _, _, _) ->
- React_jsx_common.raiseError ~loc:expr.pexp_loc
+ Jsx_common.raiseError ~loc:expr.pexp_loc
"Ref cannot be passed as a normal prop. Either give the prop a \
different name or use the `forwardRef` API instead."
| Pexp_fun (arg, default, pattern, expression)
@@ -594,10 +594,10 @@ let jsxMapper ~config =
({pval_name = {txt = fnName}; pval_attributes; pval_type} as
value_description);
} as pstr -> (
- match List.filter React_jsx_common.hasAttr pval_attributes with
+ match List.filter Jsx_common.hasAttr pval_attributes with
| [] -> [item]
| [_] ->
- let pval_type = React_jsx_common.extractUncurried pval_type in
+ let pval_type = Jsx_common.extractUncurried pval_type in
let rec getPropTypes types ({ptyp_loc; ptyp_desc} as fullType) =
match ptyp_desc with
| Ptyp_arrow (name, type_, ({ptyp_desc = Ptyp_arrow _} as rest))
@@ -641,15 +641,15 @@ let jsxMapper ~config =
in
[externalPropsDecl; newStructure]
| _ ->
- React_jsx_common.raiseError ~loc:pstr_loc
+ Jsx_common.raiseError ~loc:pstr_loc
"Only one react.component call can exist on a component at one time")
(* let component = ... *)
| {pstr_loc; pstr_desc = Pstr_value (recFlag, valueBindings)} -> (
let fileName = filenameFromLoc pstr_loc in
let emptyLoc = Location.in_file fileName in
let mapBinding binding =
- if React_jsx_common.hasAttrOnBinding binding then
- let binding = React_jsx_common.removeArity binding in
+ if Jsx_common.hasAttrOnBinding binding then
+ let binding = Jsx_common.removeArity binding in
let bindingLoc = binding.pvb_loc in
let bindingPatLoc = binding.pvb_pat.ppat_loc in
let binding =
@@ -689,7 +689,7 @@ let jsxMapper ~config =
| {pexp_desc = Pexp_constraint (innerFunctionExpression, _typ)} ->
spelunkForFunExpression innerFunctionExpression
| {pexp_loc} ->
- React_jsx_common.raiseError ~loc:pexp_loc
+ Jsx_common.raiseError ~loc:pexp_loc
"react.component calls can only be on function definitions \
or component wrappers (forwardRef, memo)."
in
@@ -814,7 +814,7 @@ let jsxMapper ~config =
in
let bindingWrapper, hasUnit, expression = modifiedBinding binding in
let reactComponentAttribute =
- try Some (List.find React_jsx_common.hasAttr binding.pvb_attributes)
+ try Some (List.find Jsx_common.hasAttr binding.pvb_attributes)
with Not_found -> None
in
let _attr_loc, payload =
@@ -1037,10 +1037,10 @@ let jsxMapper ~config =
({pval_name = {txt = fnName}; pval_attributes; pval_type} as
psig_desc);
} as psig -> (
- match List.filter React_jsx_common.hasAttr pval_attributes with
+ match List.filter Jsx_common.hasAttr pval_attributes with
| [] -> [item]
| [_] ->
- let pval_type = React_jsx_common.extractUncurried pval_type in
+ let pval_type = Jsx_common.extractUncurried pval_type in
let rec getPropTypes types ({ptyp_loc; ptyp_desc} as fullType) =
match ptyp_desc with
| Ptyp_arrow (name, type_, ({ptyp_desc = Ptyp_arrow _} as rest))
@@ -1084,7 +1084,7 @@ let jsxMapper ~config =
in
[externalPropsDecl; newStructure]
| _ ->
- React_jsx_common.raiseError ~loc:psig_loc
+ Jsx_common.raiseError ~loc:psig_loc
"Only one react.component call can exist on a component at one time")
| _ -> [item]
in
@@ -1094,37 +1094,35 @@ let jsxMapper ~config =
| Pexp_ident caller -> (
match caller with
| {txt = Lident "createElement"; loc} ->
- React_jsx_common.raiseError ~loc
+ Jsx_common.raiseError ~loc
"JSX: `createElement` should be preceeded by a module name."
(* Foo.createElement(~prop1=foo, ~prop2=bar, ~children=[], ()) *)
| {loc; txt = Ldot (modulePath, ("createElement" | "make"))} -> (
- match config.React_jsx_common.version with
+ match config.Jsx_common.version with
| 3 ->
transformUppercaseCall3 modulePath mapper loc attrs callExpression
callArguments
- | _ ->
- React_jsx_common.raiseError ~loc "JSX: the JSX version must be 3")
+ | _ -> Jsx_common.raiseError ~loc "JSX: the JSX version must be 3")
(* div(~prop1=foo, ~prop2=bar, ~children=[bla], ()) *)
(* turn that into
ReactDOMRe.createElement(~props=ReactDOMRe.props(~props1=foo, ~props2=bar, ()), [|bla|]) *)
| {loc; txt = Lident id} -> (
match config.version with
| 3 -> transformLowercaseCall3 mapper loc attrs callArguments id
- | _ -> React_jsx_common.raiseError ~loc "JSX: the JSX version must be 3"
- )
+ | _ -> Jsx_common.raiseError ~loc "JSX: the JSX version must be 3")
| {txt = Ldot (_, anythingNotCreateElementOrMake); loc} ->
- React_jsx_common.raiseError ~loc
+ Jsx_common.raiseError ~loc
"JSX: the JSX attribute should be attached to a \
`YourModuleName.createElement` or `YourModuleName.make` call. We \
saw `%s` instead"
anythingNotCreateElementOrMake
| {txt = Lapply _; loc} ->
(* don't think there's ever a case where this is reached *)
- React_jsx_common.raiseError ~loc
+ Jsx_common.raiseError ~loc
"JSX: encountered a weird case while processing the code. Please \
report this!")
| _ ->
- React_jsx_common.raiseError ~loc:callExpression.pexp_loc
+ Jsx_common.raiseError ~loc:callExpression.pexp_loc
"JSX: `createElement` should be preceeded by a simple, direct module \
name."
in