diff --git a/cli/reactjs_jsx_v4.ml b/cli/reactjs_jsx_v4.ml
index b118406e..edb19ba9 100644
--- a/cli/reactjs_jsx_v4.ml
+++ b/cli/reactjs_jsx_v4.ml
@@ -175,6 +175,7 @@ let makeModuleName fileName nestedModules fnName =
(* make record from props and spread props if exists *)
let recordFromProps ~loc ~removeKey callArguments =
+ let spreadPropsLabel = "_spreadProps" in
let rec removeLastPositionUnitAux props acc =
match props with
| [] -> acc
@@ -183,7 +184,16 @@ let recordFromProps ~loc ~removeKey callArguments =
| (Nolabel, {pexp_loc}) :: _rest ->
React_jsx_common.raiseError ~loc:pexp_loc
"JSX: found non-labelled argument before the last position"
- | prop :: rest -> removeLastPositionUnitAux rest (prop :: acc)
+ | ((Labelled txt, {pexp_loc}) as prop) :: rest
+ | ((Optional txt, {pexp_loc}) as prop) :: rest ->
+ if txt = spreadPropsLabel then
+ match acc with
+ | [] -> removeLastPositionUnitAux rest (prop :: acc)
+ | _ ->
+ React_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)
in
let props, propsToSpread =
removeLastPositionUnitAux callArguments []
@@ -208,20 +218,17 @@ let recordFromProps ~loc ~removeKey callArguments =
let spreadFields =
propsToSpread |> List.map (fun (_, expression) -> expression)
in
- match spreadFields with
- | [] ->
+ match (fields, spreadFields) with
+ | [], [spreadProps] | [], spreadProps :: _ -> spreadProps
+ | _, [] ->
{
pexp_desc = Pexp_record (fields, None);
pexp_loc = loc;
pexp_attributes = [];
}
- | [spreadProps] ->
- {
- pexp_desc = Pexp_record (fields, Some spreadProps);
- pexp_loc = loc;
- pexp_attributes = [];
- }
- | spreadProps :: _ ->
+ | _, [spreadProps]
+ (* take the first spreadProps only *)
+ | _, spreadProps :: _ ->
{
pexp_desc = Pexp_record (fields, Some spreadProps);
pexp_loc = loc;
diff --git a/tests/ppx/react/expected/spreadProps.res.txt b/tests/ppx/react/expected/spreadProps.res.txt
new file mode 100644
index 00000000..d43f50db
--- /dev/null
+++ b/tests/ppx/react/expected/spreadProps.res.txt
@@ -0,0 +1,25 @@
+@@jsxConfig({version: 4, mode: "classic"})
+// Error: spreadProps should be first in order than other props
+// let c0 =
+
+// Error: multiple spreadProps not allowed
+// let c0 =
+
+// only spread props
+let c1 = React.createElement(A.make, p)
+
+// reversed order
+let c2 = React.createElement(A.make, {...p, x: "x"})
+
+@@jsxConfig({version: 4, mode: "automatic"})
+// Error: spreadProps should be first in order than other props
+// let c0 =
+
+// Error: multiple spreadProps not allowed
+// let c0 =
+
+// only spread props
+let c1 = React.jsx(A.make, p)
+
+// reversed order
+let c2 = React.jsx(A.make, {...p, x: "x"})
diff --git a/tests/ppx/react/spreadProps.res b/tests/ppx/react/spreadProps.res
new file mode 100644
index 00000000..b50f5c08
--- /dev/null
+++ b/tests/ppx/react/spreadProps.res
@@ -0,0 +1,25 @@
+@@jsxConfig({version:4, mode: "classic"})
+// Error: spreadProps should be first in order than other props
+// let c0 =
+
+// Error: multiple spreadProps not allowed
+// let c0 =
+
+// only spread props
+let c1 =
+
+// reversed order
+let c2 =
+
+@@jsxConfig({version:4, mode: "automatic"})
+// Error: spreadProps should be first in order than other props
+// let c0 =
+
+// Error: multiple spreadProps not allowed
+// let c0 =
+
+// only spread props
+let c1 =
+
+// reversed order
+let c2 =