diff --git a/cli/reactjs_jsx_ppx.ml b/cli/reactjs_jsx_ppx.ml
index bc8ea02c..7b3a0096 100644
--- a/cli/reactjs_jsx_ppx.ml
+++ b/cli/reactjs_jsx_ppx.ml
@@ -78,6 +78,13 @@ let hasAttr (loc, _) = loc.txt = "react.component"
let hasAttrOnBinding {pvb_attributes} =
List.find_opt hasAttr pvb_attributes <> None
+let raiseError ~loc msg = Location.raise_errorf ~loc msg
+
+let raiseErrorMultipleReactComponent ~loc =
+ raiseError ~loc
+ "Only one component definition is allowed for each module. Move to a \
+ submodule or other file if necessary."
+
module V3 = struct
let nolabel = Nolabel
@@ -163,10 +170,9 @@ module V3 = struct
| [] -> []
| [(Nolabel, {pexp_desc = Pexp_construct ({txt = Lident "()"}, None)})] ->
acc
- | (Nolabel, _) :: _rest ->
- raise
- (Invalid_argument
- "JSX: found non-labelled argument before the last position")
+ | (Nolabel, {pexp_loc}) :: _rest ->
+ raiseError ~loc:pexp_loc
+ "JSX: found non-labelled argument before the last position"
| arg :: rest -> allButLast_ rest (arg :: acc)
[@@raises Invalid_argument]
in
@@ -185,9 +191,7 @@ module V3 = struct
if removeLastPositionUnit then allButLast props else props )
| [(_, childrenExpr)], props ->
(childrenExpr, if removeLastPositionUnit then allButLast props else props)
- | _ ->
- raise
- (Invalid_argument "JSX: somehow there's more than one `children` label")
+ | _ -> raiseError ~loc "JSX: somehow there's more than one `children` label"
[@@raises Invalid_argument]
let unerasableIgnore loc =
@@ -204,8 +208,8 @@ module V3 = struct
match binding with
| {ppat_desc = Ppat_var {txt}} -> txt
| {ppat_desc = Ppat_constraint (pat, _)} -> getFnName pat
- | _ ->
- raise (Invalid_argument "react.component calls cannot be destructured.")
+ | {ppat_loc} ->
+ raiseError ~loc:ppat_loc "react.component calls cannot be destructured."
[@@raises Invalid_argument]
let makeNewBinding binding expression newName =
@@ -218,8 +222,8 @@ module V3 = struct
pvb_expr = expression;
pvb_attributes = [merlinFocus];
}
- | _ ->
- raise (Invalid_argument "react.component calls cannot be destructured.")
+ | {pvb_loc} ->
+ raiseError ~loc:pvb_loc "react.component calls cannot be destructured."
[@@raises Invalid_argument]
(* Lookup the value of `props` otherwise raise Invalid_argument error *)
@@ -227,11 +231,10 @@ module V3 = struct
match (loc, exp) with
| {txt = Lident "props"}, {pexp_desc = Pexp_ident {txt = Lident str}} ->
{propsName = str}
- | {txt}, _ ->
- raise
- (Invalid_argument
- ("react.component only accepts props as an option, given: "
- ^ Longident.last txt))
+ | {txt; loc}, _ ->
+ raiseError ~loc
+ "react.component only accepts props as an option, given: { %s }"
+ (Longident.last txt)
[@@raises Invalid_argument]
(* Lookup the `props` record or string as part of [@react.component] and store the name for use when rewriting *)
@@ -254,10 +257,9 @@ module V3 = struct
}
:: _rest)) ->
{propsName = "props"}
- | Some (PStr ({pstr_desc = Pstr_eval (_, _)} :: _rest)) ->
- raise
- (Invalid_argument
- "react.component accepts a record config with props as an options.")
+ | Some (PStr ({pstr_desc = Pstr_eval (_, _); pstr_loc} :: _rest)) ->
+ raiseError ~loc:pstr_loc
+ "react.component accepts a record config with props as an options."
| _ -> defaultProps
[@@raises Invalid_argument]
@@ -470,9 +472,8 @@ module V3 = struct
| Lident path -> Lident (path ^ "Props")
| Ldot (ident, path) -> Ldot (ident, path ^ "Props")
| _ ->
- raise
- (Invalid_argument
- "JSX name can't be the result of function applications")
+ raiseError ~loc
+ "JSX name can't be the result of function applications"
in
let props =
Exp.apply ~attrs ~loc (Exp.ident ~loc {loc; txt = propsIdent}) args
@@ -511,11 +512,10 @@ module V3 = struct
} ->
"createDOMElementVariadic"
(* [@JSX] div(~children= value), coming from
...(value)
*)
- | _ ->
- raise
- (Invalid_argument
- "A spread as a DOM element's children don't make sense written \
- together. You can simply remove the spread.")
+ | {pexp_loc} ->
+ 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
let args =
match nonChildrenProps with
@@ -560,16 +560,14 @@ module V3 = struct
(* TODO: make this show up with a loc. *)
| Pexp_fun (Labelled "key", _, _, _) | Pexp_fun (Optional "key", _, _, _)
->
- raise
- (Invalid_argument
- "Key cannot be accessed inside of a component. Don't worry - you \
- can always key a component from its parent!")
+ 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", _, _, _)
->
- raise
- (Invalid_argument
- "Ref cannot be passed as a normal prop. Please use `forwardRef` \
- API instead.")
+ raiseError ~loc:expr.pexp_loc
+ "Ref cannot be passed as a normal prop. Please use `forwardRef` API \
+ instead."
| Pexp_fun (arg, default, pattern, expression)
when isOptional arg || isLabelled arg ->
let () =
@@ -759,10 +757,9 @@ module V3 = struct
in
[externalPropsDecl; newStructure]
| _ ->
- raise
- (Invalid_argument
- "Only one react.component call can exist on a component at one \
- time"))
+ 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
@@ -810,11 +807,10 @@ module V3 = struct
| {pexp_desc = Pexp_constraint (innerFunctionExpression, _typ)}
->
spelunkForFunExpression innerFunctionExpression
- | _ ->
- raise
- (Invalid_argument
- "react.component calls can only be on function \
- definitions or component wrappers (forwardRef, memo).")
+ | {pexp_loc} ->
+ raiseError ~loc:pexp_loc
+ "react.component calls can only be on function definitions \
+ or component wrappers (forwardRef, memo)."
[@@raises Invalid_argument]
in
spelunkForFunExpression expression
@@ -1207,10 +1203,9 @@ module V3 = struct
in
[externalPropsDecl; newStructure]
| _ ->
- raise
- (Invalid_argument
- "Only one react.component call can exist on a component at one \
- time"))
+ raiseError ~loc:psig_loc
+ "Only one react.component call can exist on a component at one time"
+ )
| _ -> [item]
[@@raises Invalid_argument]
in
@@ -1219,41 +1214,38 @@ module V3 = struct
match callExpression.pexp_desc with
| Pexp_ident caller -> (
match caller with
- | {txt = Lident "createElement"} ->
- raise
- (Invalid_argument
- "JSX: `createElement` should be preceeded by a module name.")
+ | {txt = Lident "createElement"; loc} ->
+ 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.version with
| 3 ->
transformUppercaseCall3 modulePath mapper loc attrs callExpression
callArguments
- | _ -> raise (Invalid_argument "JSX: the JSX version must be 3"))
+ | _ -> 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
- | _ -> raise (Invalid_argument "JSX: the JSX version must be 3"))
- | {txt = Ldot (_, anythingNotCreateElementOrMake)} ->
- raise
- (Invalid_argument
- ("JSX: the JSX attribute should be attached to a \
- `YourModuleName.createElement` or `YourModuleName.make` call. \
- We saw `" ^ anythingNotCreateElementOrMake ^ "` instead"))
- | {txt = Lapply _} ->
+ | _ -> raiseError ~loc "JSX: the JSX version must be 3")
+ | {txt = Ldot (_, anythingNotCreateElementOrMake); loc} ->
+ 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 *)
- raise
- (Invalid_argument
- "JSX: encountered a weird case while processing the code. \
- Please report this!"))
+ raiseError ~loc
+ "JSX: encountered a weird case while processing the code. Please \
+ report this!")
| _ ->
- raise
- (Invalid_argument
- "JSX: `createElement` should be preceeded by a simple, direct \
- module name.")
+ raiseError ~loc:callExpression.pexp_loc
+ "JSX: `createElement` should be preceeded by a simple, direct module \
+ name."
[@@raises Invalid_argument]
in
@@ -1385,7 +1377,7 @@ module V4 = struct
type 'a children = ListLiteral of 'a | Exact of 'a
(* if children is a list, convert it to an array while mapping each element. If not, just map over it, as usual *)
- let transformChildrenIfListUpper ~loc ~mapper theList =
+ let transformChildrenIfListUpper ~mapper theList =
let rec transformChildren_ theList accum =
(* not in the sense of converting a list to an array; convert the AST
reprensentation of a list to the AST reprensentation of an array *)
@@ -1393,7 +1385,7 @@ module V4 = struct
| {pexp_desc = Pexp_construct ({txt = Lident "[]"}, None)} -> (
match accum with
| [singleElement] -> Exact singleElement
- | accum -> ListLiteral (Exp.array ~loc (List.rev accum)))
+ | accum -> ListLiteral (Exp.array (List.rev accum)))
| {
pexp_desc =
Pexp_construct
@@ -1404,13 +1396,13 @@ module V4 = struct
in
transformChildren_ theList []
- let transformChildrenIfList ~loc ~mapper theList =
+ let transformChildrenIfList ~mapper theList =
let rec transformChildren_ theList accum =
(* not in the sense of converting a list to an array; convert the AST
reprensentation of a list to the AST reprensentation of an array *)
match theList with
| {pexp_desc = Pexp_construct ({txt = Lident "[]"}, None)} ->
- Exp.array ~loc (List.rev accum)
+ Exp.array (List.rev accum)
| {
pexp_desc =
Pexp_construct
@@ -1427,10 +1419,9 @@ module V4 = struct
| [] -> []
| [(Nolabel, {pexp_desc = Pexp_construct ({txt = Lident "()"}, None)})] ->
acc
- | (Nolabel, _) :: _rest ->
- raise
- (Invalid_argument
- "JSX: found non-labelled argument before the last position")
+ | (Nolabel, {pexp_loc}) :: _rest ->
+ raiseError ~loc:pexp_loc
+ "JSX: found non-labelled argument before the last position"
| arg :: rest -> allButLast_ rest (arg :: acc)
[@@raises Invalid_argument]
in
@@ -1445,13 +1436,11 @@ module V4 = struct
with
| [], props ->
(* no children provided? Place a placeholder list *)
- ( Exp.construct ~loc {loc; txt = Lident "[]"} None,
+ ( Exp.construct {loc = Location.none; txt = Lident "[]"} None,
if removeLastPositionUnit then allButLast props else props )
| [(_, childrenExpr)], props ->
(childrenExpr, if removeLastPositionUnit then allButLast props else props)
- | _ ->
- raise
- (Invalid_argument "JSX: somehow there's more than one `children` label")
+ | _ -> raiseError ~loc "JSX: somehow there's more than one `children` label"
[@@raises Invalid_argument]
let merlinFocus = ({loc = Location.none; txt = "merlin.focus"}, PStr [])
@@ -1464,8 +1453,8 @@ module V4 = struct
match binding with
| {ppat_desc = Ppat_var {txt}} -> txt
| {ppat_desc = Ppat_constraint (pat, _)} -> getFnName pat
- | _ ->
- raise (Invalid_argument "react.component calls cannot be destructured.")
+ | {ppat_loc} ->
+ raiseError ~loc:ppat_loc "react.component calls cannot be destructured."
[@@raises Invalid_argument]
let makeNewBinding binding expression newName =
@@ -1478,8 +1467,8 @@ module V4 = struct
pvb_expr = expression;
pvb_attributes = [merlinFocus];
}
- | _ ->
- raise (Invalid_argument "react.component calls cannot be destructured.")
+ | {pvb_loc} ->
+ raiseError ~loc:pvb_loc "react.component calls cannot be destructured."
[@@raises Invalid_argument]
(* Lookup the filename from the location information on the AST node and turn it into a valid module identifier *)
@@ -1510,12 +1499,6 @@ module V4 = struct
let fullModuleName = String.concat "$" fullModuleName in
fullModuleName
- let raiseError ~loc msg = Location.raise_errorf ~loc msg
-
- let raiseErrorMultipleReactComponent ~loc =
- raiseError ~loc
- "Only one component definition is allowed for each module. Move to a \
- submodule or other file if necessary."
(*
AST node builders
These functions help us build AST nodes that are needed when transforming a [@react.component] into a
@@ -1523,16 +1506,15 @@ module V4 = struct
*)
(* make record from props and spread props if exists *)
- let recordFromProps ?(removeKey = false) callArguments =
+ let recordFromProps ~loc ?(removeKey = false) callArguments =
let rec removeLastPositionUnitAux props acc =
match props with
| [] -> acc
| [(Nolabel, {pexp_desc = Pexp_construct ({txt = Lident "()"}, None)})] ->
acc
- | (Nolabel, _) :: _rest ->
- raise
- (Invalid_argument
- "JSX: found non-labelled argument before the last position")
+ | (Nolabel, {pexp_loc}) :: _rest ->
+ raiseError ~loc:pexp_loc
+ "JSX: found non-labelled argument before the last position"
| prop :: rest -> removeLastPositionUnitAux rest (prop :: acc)
in
let props, propsToSpread =
@@ -1561,19 +1543,19 @@ module V4 = struct
| [] ->
{
pexp_desc = Pexp_record (fields, None);
- pexp_loc = Location.none;
+ pexp_loc = loc;
pexp_attributes = [];
}
| [spreadProps] ->
{
pexp_desc = Pexp_record (fields, Some spreadProps);
- pexp_loc = Location.none;
+ pexp_loc = loc;
pexp_attributes = [];
}
| spreadProps :: _ ->
{
pexp_desc = Pexp_record (fields, Some spreadProps);
- pexp_loc = Location.none;
+ pexp_loc = loc;
pexp_attributes = [];
}
@@ -1640,13 +1622,13 @@ module V4 = struct
let makePropsRecordTypeSig propsName loc namedTypeList =
Sig.type_ Nonrecursive (makeTypeDecls propsName loc namedTypeList)
- let transformUppercaseCall3 ~config modulePath mapper loc attrs callArguments
- =
+ let transformUppercaseCall3 ~config modulePath mapper jsxExprLoc callExprLoc
+ attrs callArguments =
let children, argsWithLabels =
- extractChildren ~loc ~removeLastPositionUnit:true callArguments
+ extractChildren ~removeLastPositionUnit:true ~loc:jsxExprLoc callArguments
in
let argsForMake = argsWithLabels in
- let childrenExpr = transformChildrenIfListUpper ~loc ~mapper children in
+ let childrenExpr = transformChildrenIfListUpper ~mapper children in
let recursivelyTransformedArgsForMake =
argsForMake
|> List.map (fun (label, expression) ->
@@ -1674,7 +1656,8 @@ module V4 = struct
| _ ->
[
( labelled "children",
- Exp.ident ~loc {loc; txt = Ldot (Lident "React", "null")} );
+ Exp.ident
+ {loc = Location.none; txt = Ldot (Lident "React", "null")} );
])
in
@@ -1702,9 +1685,10 @@ module V4 = struct
match config.mode with
(* The new jsx transform *)
| "automatic" ->
- let record = recordFromProps ~removeKey:true args in
+ let record = recordFromProps ~loc:jsxExprLoc ~removeKey:true args in
let props =
- if isEmptyRecord record then recordWithOnlyKey ~loc else record
+ if isEmptyRecord record then recordWithOnlyKey ~loc:jsxExprLoc
+ else record
in
let keyProp =
args |> List.filter (fun (arg_label, _) -> "key" = getLabel arg_label)
@@ -1727,22 +1711,30 @@ module V4 = struct
[] )
in
Exp.apply ~attrs jsxExpr
- ([(nolabel, Exp.ident {txt = ident; loc}); (nolabel, props)] @ key)
+ ([
+ (nolabel, Exp.ident {txt = ident; loc = callExprLoc});
+ (nolabel, props);
+ ]
+ @ key)
| _ -> (
- let record = recordFromProps args in
+ let record = recordFromProps ~loc:jsxExprLoc args in
(* check if record which goes to Foo.make({ ... } as record) empty or not
if empty then change it to {key: @optional None} only for upper case jsx
This would be redundant regarding PR progress https://github.com/rescript-lang/syntax/pull/299
*)
let props =
- if isEmptyRecord record then recordWithOnlyKey ~loc else record
+ if isEmptyRecord record then recordWithOnlyKey ~loc:jsxExprLoc
+ else record
in
match !childrenArg with
| None ->
Exp.apply ~attrs
(Exp.ident
{loc = Location.none; txt = Ldot (Lident "React", "createElement")})
- [(nolabel, Exp.ident {txt = ident; loc}); (nolabel, props)]
+ [
+ (nolabel, Exp.ident {txt = ident; loc = callExprLoc});
+ (nolabel, props);
+ ]
| Some children ->
Exp.apply ~attrs
(Exp.ident
@@ -1751,22 +1743,24 @@ module V4 = struct
txt = Ldot (Lident "React", "createElementVariadic");
})
[
- (nolabel, Exp.ident {txt = ident; loc});
+ (nolabel, Exp.ident {txt = ident; loc = callExprLoc});
(nolabel, props);
(nolabel, children);
])
[@@raises Invalid_argument]
- let transformLowercaseCall3 ~config mapper loc attrs callArguments id =
- let componentNameExpr = constantString ~loc id in
+ let transformLowercaseCall3 ~config mapper jsxExprLoc callExprLoc attrs
+ callArguments id =
+ let componentNameExpr = constantString ~loc:callExprLoc id in
match config.mode with
(* the new jsx transform *)
| "automatic" ->
let children, nonChildrenProps =
- extractChildren ~removeLastPositionUnit:true ~loc callArguments
+ extractChildren ~removeLastPositionUnit:true ~loc:jsxExprLoc
+ callArguments
in
let argsForMake = nonChildrenProps in
- let childrenExpr = transformChildrenIfListUpper ~loc ~mapper children in
+ let childrenExpr = transformChildrenIfListUpper ~mapper children in
let recursivelyTransformedArgsForMake =
argsForMake
|> List.map (fun (label, expression) ->
@@ -1795,9 +1789,10 @@ module V4 = struct
| Pexp_record (labelDecls, _) when List.length labelDecls = 0 -> true
| _ -> false
in
- let record = recordFromProps ~removeKey:true args in
+ let record = recordFromProps ~loc:jsxExprLoc ~removeKey:true args in
let props =
- if isEmptyRecord record then recordWithOnlyKey ~loc else record
+ if isEmptyRecord record then recordWithOnlyKey ~loc:jsxExprLoc
+ else record
in
let keyProp =
args |> List.filter (fun (arg_label, _) -> "key" = getLabel arg_label)
@@ -1805,21 +1800,29 @@ module V4 = struct
let jsxExpr, key =
match (!childrenArg, keyProp) with
| None, (_, keyExpr) :: _ ->
- ( Exp.ident ~loc {loc; txt = Ldot (Lident "ReactDOM", "jsxKeyed")},
+ ( Exp.ident
+ {loc = Location.none; txt = Ldot (Lident "ReactDOM", "jsxKeyed")},
[(nolabel, keyExpr)] )
| None, [] ->
- (Exp.ident ~loc {loc; txt = Ldot (Lident "ReactDOM", "jsx")}, [])
+ ( Exp.ident
+ {loc = Location.none; txt = Ldot (Lident "ReactDOM", "jsx")},
+ [] )
| Some _, (_, keyExpr) :: _ ->
- ( Exp.ident ~loc {loc; txt = Ldot (Lident "ReactDOM", "jsxsKeyed")},
+ ( Exp.ident
+ {loc = Location.none; txt = Ldot (Lident "ReactDOM", "jsxsKeyed")},
[(nolabel, keyExpr)] )
| Some _, [] ->
- (Exp.ident ~loc {loc; txt = Ldot (Lident "ReactDOM", "jsxs")}, [])
+ ( Exp.ident
+ {loc = Location.none; txt = Ldot (Lident "ReactDOM", "jsxs")},
+ [] )
in
- Exp.apply ~loc ~attrs jsxExpr
+ Exp.apply ~attrs jsxExpr
([(nolabel, componentNameExpr); (nolabel, props)] @ key)
| _ ->
- let children, nonChildrenProps = extractChildren ~loc callArguments in
- let childrenExpr = transformChildrenIfList ~loc ~mapper children in
+ let children, nonChildrenProps =
+ extractChildren ~loc:jsxExprLoc callArguments
+ in
+ let childrenExpr = transformChildrenIfList ~mapper children in
let createElementCall =
match children with
(* [@JSX] div(~children=[a]), coming from a
*)
@@ -1831,11 +1834,10 @@ module V4 = struct
} ->
"createDOMElementVariadic"
(* [@JSX] div(~children= value), coming from ...(value)
*)
- | _ ->
- raise
- (Invalid_argument
- "A spread as a DOM element's children don't make sense written \
- together. You can simply remove the spread.")
+ | {pexp_loc} ->
+ 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
let args =
match nonChildrenProps with
@@ -1848,9 +1850,12 @@ module V4 = struct
]
| nonEmptyProps ->
let propsCall =
- Exp.apply ~loc
- (Exp.ident ~loc
- {loc; txt = Ldot (Lident "ReactDOMRe", "domProps")})
+ Exp.apply
+ (Exp.ident
+ {
+ loc = Location.none;
+ txt = Ldot (Lident "ReactDOMRe", "domProps");
+ })
(nonEmptyProps
|> List.map (fun (label, expression) ->
(label, mapper.expr mapper expression)))
@@ -1864,12 +1869,13 @@ module V4 = struct
(nolabel, childrenExpr);
]
in
- Exp.apply
- ~loc (* throw away the [@JSX] attribute and keep the others, if any *)
- ~attrs
+ Exp.apply ~loc:jsxExprLoc ~attrs
(* ReactDOMRe.createElement *)
- (Exp.ident ~loc
- {loc; txt = Ldot (Lident "ReactDOMRe", createElementCall)})
+ (Exp.ident
+ {
+ loc = Location.none;
+ txt = Ldot (Lident "ReactDOMRe", createElementCall);
+ })
args
[@@raises Invalid_argument]
@@ -1879,15 +1885,13 @@ module V4 = struct
match expr.pexp_desc with
(* TODO: make this show up with a loc. *)
| Pexp_fun (Labelled "key", _, _, _) | Pexp_fun (Optional "key", _, _, _) ->
- raise
- (Invalid_argument
- "Key cannot be accessed inside of a component. Don't worry - you \
- can always key a component from its parent!")
+ 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", _, _, _) ->
- raise
- (Invalid_argument
- "Ref cannot be passed as a normal prop. Please use `forwardRef` API \
- instead.")
+ raiseError ~loc:expr.pexp_loc
+ "Ref cannot be passed as a normal prop. Please use `forwardRef` API \
+ instead."
| Pexp_fun (arg, default, pattern, expression)
when isOptional arg || isLabelled arg ->
let () =
@@ -2070,10 +2074,8 @@ module V4 = struct
in
[propsRecordType; newStructure])
| _ ->
- raise
- (Invalid_argument
- "Only one react.component call can exist on a component at one \
- time"))
+ 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
@@ -2125,11 +2127,10 @@ module V4 = struct
| {pexp_desc = Pexp_constraint (innerFunctionExpression, _typ)}
->
spelunkForFunExpression innerFunctionExpression
- | _ ->
- raise
- (Invalid_argument
- "react.component calls can only be on function \
- definitions or component wrappers (forwardRef, memo).")
+ | {pexp_loc} ->
+ raiseError ~loc:pexp_loc
+ "react.component calls can only be on function definitions \
+ or component wrappers (forwardRef, memo)."
[@@raises Invalid_argument]
in
spelunkForFunExpression expression
@@ -2540,54 +2541,54 @@ module V4 = struct
in
[propsRecordType; newStructure]
| _ ->
- raise
- (Invalid_argument
- "Only one react.component call can exist on a component at one \
- time"))
+ raiseError ~loc:psig_loc
+ "Only one react.component call can exist on a component at one time")
| _ -> [item]
[@@raises Invalid_argument]
- let transformJsxCall ~config mapper callExpression callArguments attrs =
+ let transformJsxCall ~config mapper callExpression callArguments jsxExprLoc
+ attrs =
match callExpression.pexp_desc with
| Pexp_ident caller -> (
match caller with
- | {txt = Lident "createElement"} ->
- raise
- (Invalid_argument
- "JSX: `createElement` should be preceeded by a module name.")
+ | {txt = Lident "createElement"; loc} ->
+ raiseError ~loc
+ "JSX: `createElement` should be preceeded by a module name."
(* Foo.createElement(~prop1=foo, ~prop2=bar, ~children=[], ()) *)
| {loc; txt = Ldot (modulePath, ("createElement" | "make"))} ->
- transformUppercaseCall3 ~config modulePath mapper loc attrs
+ transformUppercaseCall3 ~config modulePath mapper jsxExprLoc loc attrs
callArguments
(* div(~prop1=foo, ~prop2=bar, ~children=[bla], ()) *)
(* turn that into
ReactDOMRe.createElement(~props=ReactDOMRe.props(~props1=foo, ~props2=bar, ()), [|bla|]) *)
| {loc; txt = Lident id} ->
- transformLowercaseCall3 ~config mapper loc attrs callArguments id
- | {txt = Ldot (_, anythingNotCreateElementOrMake)} ->
- raise
- (Invalid_argument
- ("JSX: the JSX attribute should be attached to a \
- `YourModuleName.createElement` or `YourModuleName.make` call. \
- We saw `" ^ anythingNotCreateElementOrMake ^ "` instead"))
- | {txt = Lapply _} ->
+ transformLowercaseCall3 ~config mapper jsxExprLoc loc attrs
+ callArguments id
+ | {txt = Ldot (_, anythingNotCreateElementOrMake); loc} ->
+ 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 *)
- raise
- (Invalid_argument
- "JSX: encountered a weird case while processing the code. Please \
- report this!"))
+ raiseError ~loc
+ "JSX: encountered a weird case while processing the code. Please \
+ report this!")
| _ ->
- raise
- (Invalid_argument
- "JSX: `createElement` should be preceeded by a simple, direct \
- module name.")
+ raiseError ~loc:callExpression.pexp_loc
+ "JSX: `createElement` should be preceeded by a simple, direct module \
+ name."
[@@raises Invalid_argument]
let expr ~config mapper expression =
match expression with
(* Does the function application have the @JSX attribute? *)
- | {pexp_desc = Pexp_apply (callExpression, callArguments); pexp_attributes}
- -> (
+ | {
+ pexp_desc = Pexp_apply (callExpression, callArguments);
+ pexp_attributes;
+ pexp_loc;
+ } -> (
let jsxAttribute, nonJSXAttributes =
List.partition
(fun (attribute, _) -> attribute.txt = "JSX")
@@ -2597,7 +2598,7 @@ module V4 = struct
(* no JSX attribute *)
| [], _ -> default_mapper.expr mapper expression
| _, nonJSXAttributes ->
- transformJsxCall ~config mapper callExpression callArguments
+ transformJsxCall ~config mapper callExpression callArguments pexp_loc
nonJSXAttributes)
(* is it a list with jsx attribute? Reason <>foo> desugars to [@JSX][foo]*)
| {
@@ -2624,7 +2625,7 @@ module V4 = struct
| "classic" | _ ->
Exp.ident ~loc {loc; txt = Ldot (Lident "ReasonReact", "fragment")}
in
- let childrenExpr = transformChildrenIfList ~loc ~mapper listItems in
+ let childrenExpr = transformChildrenIfList ~mapper listItems in
let args =
[
(nolabel, fragment);
diff --git a/tests/ppx/react/expected/forwardRef.res.txt b/tests/ppx/react/expected/forwardRef.res.txt
index 3bd5e497..b0804f13 100644
--- a/tests/ppx/react/expected/forwardRef.res.txt
+++ b/tests/ppx/react/expected/forwardRef.res.txt
@@ -157,7 +157,6 @@ module V4A = {
@react.component
let make = (_: props) => {
let input = React.useRef(Js.Nullable.null)
-
ReactDOM.jsx(
"div",
{