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 =