From 1255eb47d9b4ca3a2d56c7570d09c5152238c5cd Mon Sep 17 00:00:00 2001 From: Woonki Moon Date: Wed, 14 Dec 2022 10:05:55 +0900 Subject: [PATCH 1/4] add test --- .../ppx/react/expected/mangleKeyword.res.txt | 68 +++++++++++++++++++ tests/ppx/react/mangleKeyword.res | 43 ++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 tests/ppx/react/expected/mangleKeyword.res.txt create mode 100644 tests/ppx/react/mangleKeyword.res diff --git a/tests/ppx/react/expected/mangleKeyword.res.txt b/tests/ppx/react/expected/mangleKeyword.res.txt new file mode 100644 index 00000000..ca1e2bcc --- /dev/null +++ b/tests/ppx/react/expected/mangleKeyword.res.txt @@ -0,0 +1,68 @@ +@@jsxConfig({version: 3}) + +module C0 = { + @obj external makeProps: (~_open: 'T_open, ~key: string=?, unit) => {"_open": 'T_open} = "" + + @react.component let make = (@warning("-16") ~_open) => React.string(_open) + let make = { + let \"MangleKeyword$C0" = (\"Props": {"_open": 'T_open}) => make(~_open=\"Props"["_open"]) + \"MangleKeyword$C0" + } +} +module C1 = { + @obj external makeProps: (~_open: string, ~key: string=?, unit) => {"_open": string} = "" + external make: React.componentLike<{"_open": string}, React.element> = "default" +} + +let c0 = React.createElement(C0.make, C0.makeProps(~_open="x", ())) +let c1 = React.createElement(C1.make, C1.makeProps(~_open="x", ())) + +@@jsxConfig({version: 4, mode: "classic"}) + +module C0 = { + type props<'T_open> = { + _open: 'T_open, + } + + @react.component let make = ({_open, _}: props<'T_open>) => React.string(_open) + let make = { + let \"MangleKeyword$C0" = (props: props<_>) => make(props) + + \"MangleKeyword$C0" + } +} +module C1 = { + type props<'T_open> = { + _open: 'T_open, + } + + external make: @as("open") React.componentLike, React.element> = "default" +} + +let c0 = React.createElement(C0.make, {_open: "x"}) +let c1 = React.createElement(C1.make, {_open: "x"}) + +@@jsxConfig({version: 4, mode: "automatic"}) + +module C0 = { + type props<'T_open> = { + _open: 'T_open, + } + + @react.component let make = ({_open, _}: props<'T_open>) => React.string(_open) + let make = { + let \"MangleKeyword$C0" = (props: props<_>) => make(props) + + \"MangleKeyword$C0" + } +} +module C1 = { + type props<'T_open> = { + _open: 'T_open, + } + + external make: @as("open") React.componentLike, React.element> = "default" +} + +let c0 = React.jsx(C0.make, {_open: "x"}) +let c1 = React.jsx(C1.make, {_open: "x"}) diff --git a/tests/ppx/react/mangleKeyword.res b/tests/ppx/react/mangleKeyword.res new file mode 100644 index 00000000..bc149220 --- /dev/null +++ b/tests/ppx/react/mangleKeyword.res @@ -0,0 +1,43 @@ +@@jsxConfig({version: 3}) + +module C0 = { + @react.component + let make = (~_open) => React.string(_open) +} +module C1 = { + @react.component + external make: (~_open: string) => React.element = "default" +} + +let c0 = +let c1 = + +@@jsxConfig({version: 4, mode: "classic"}) + +module C0 = { + @react.component + let make = + (@as("open") ~_open) => React.string(_open) +} +module C1 = { + @react.component + external make: (@as("open") ~_open: string) => React.element = "default" +} + +let c0 = +let c1 = + +@@jsxConfig({version: 4, mode: "automatic"}) + +module C0 = { + @react.component + let make = + (@as("open") ~_open) => React.string(_open) +} +module C1 = { + @react.component + external make: (@as("open") ~_open: string) => React.element = "default" +} + +let c0 = +let c1 = \ No newline at end of file From a1f8081c4464733294c9c844a83fb0a5bda16aa6 Mon Sep 17 00:00:00 2001 From: Woonki Moon Date: Thu, 15 Dec 2022 08:15:25 +0900 Subject: [PATCH 2/4] make record type for props with attrs --- cli/reactjs_jsx_v4.ml | 49 ++++++++++++------- .../ppx/react/expected/mangleKeyword.res.txt | 42 +++++++++------- tests/ppx/react/mangleKeyword.res | 18 ++++--- 3 files changed, 65 insertions(+), 44 deletions(-) diff --git a/cli/reactjs_jsx_v4.ml b/cli/reactjs_jsx_v4.ml index 040bc54c..a8ccbd51 100644 --- a/cli/reactjs_jsx_v4.ml +++ b/cli/reactjs_jsx_v4.ml @@ -289,14 +289,15 @@ let makePropsTypeParams ?(stripExplicitOption = false) let makeLabelDecls ~loc namedTypeList = namedTypeList - |> List.map (fun (isOptional, label, _, interiorType) -> + |> List.map (fun (isOptional, label, attrs, interiorType) -> if label = "key" then - Type.field ~loc ~attrs:optionalAttrs {txt = label; loc} interiorType + Type.field ~loc ~attrs:(optionalAttrs @ attrs) {txt = label; loc} + interiorType else if isOptional then - Type.field ~loc ~attrs:optionalAttrs {txt = label; loc} + Type.field ~loc ~attrs:(optionalAttrs @ attrs) {txt = label; loc} (Typ.var @@ safeTypeFromValue @@ Labelled label) else - Type.field ~loc {txt = label; loc} + Type.field ~loc ~attrs {txt = label; loc} (Typ.var @@ safeTypeFromValue @@ Labelled label)) let makeTypeDecls propsName loc namedTypeList = @@ -681,7 +682,9 @@ let newtypeToVar newtype type_ = mapper.typ mapper type_ let argToType ~newtypes ~(typeConstraints : core_type option) types - (name, default, _noLabelName, _alias, loc, type_) = + ((name, default, {ppat_attributes = attrs}, _alias, loc, type_) : + arg_label * expression option * pattern * label * 'loc * core_type option) + = let rec getType name coreType = match coreType with | {ptyp_desc = Ptyp_arrow (arg, c1, c2)} -> @@ -699,17 +702,18 @@ let argToType ~newtypes ~(typeConstraints : core_type option) types in match (type_, name, default) with | Some type_, name, _ when isOptional name -> - (true, getLabel name, [], {type_ with ptyp_attributes = optionalAttrs}) + (true, getLabel name, attrs, {type_ with ptyp_attributes = optionalAttrs}) :: types - | Some type_, name, _ -> (false, getLabel name, [], type_) :: types + | Some type_, name, _ -> (false, getLabel name, attrs, type_) :: types | None, name, _ when isOptional name -> ( true, getLabel name, - [], + attrs, Typ.var ~loc ~attrs:optionalAttrs (safeTypeFromValue name) ) :: types | None, name, _ when isLabelled name -> - (false, getLabel name, [], Typ.var ~loc (safeTypeFromValue name)) :: types + (false, getLabel name, attrs, Typ.var ~loc (safeTypeFromValue name)) + :: types | _ -> types let argWithDefaultValue (name, default, _, _, _, _) = @@ -717,10 +721,10 @@ let argWithDefaultValue (name, default, _, _, _, _) = | Some default when isOptional name -> Some (getLabel name, default) | _ -> None -let argToConcreteType types (name, _loc, type_) = +let argToConcreteType types (name, attrs, _loc, type_) = match name with - | name when isLabelled name -> (false, getLabel name, [], type_) :: types - | name when isOptional name -> (true, getLabel name, [], type_) :: types + | name when isLabelled name -> (false, getLabel name, attrs, type_) :: types + | name when isOptional name -> (true, getLabel name, attrs, type_) :: types | _ -> types let check_string_int_attribute_iter = @@ -757,15 +761,19 @@ let transformStructureItem ~config mapper item = |> Option.map React_jsx_common.typVarsOfCoreType |> Option.value ~default:[] in - let rec getPropTypes types ({ptyp_loc; ptyp_desc} as fullType) = + let rec getPropTypes types + ({ptyp_loc; ptyp_desc; ptyp_attributes} as fullType) = match ptyp_desc with | Ptyp_arrow (name, type_, ({ptyp_desc = Ptyp_arrow _} as rest)) when isLabelled name || isOptional name -> - getPropTypes ((name, ptyp_loc, type_) :: types) rest + getPropTypes + ((name, ptyp_attributes, ptyp_loc, type_) :: types) + rest | Ptyp_arrow (Nolabel, _type, rest) -> getPropTypes types rest | Ptyp_arrow (name, type_, returnValue) when isLabelled name || isOptional name -> - (returnValue, (name, returnValue.ptyp_loc, type_) :: types) + ( returnValue, + (name, ptyp_attributes, returnValue.ptyp_loc, type_) :: types ) | _ -> (fullType, types) in let innerType, propTypes = getPropTypes [] pval_type in @@ -1237,9 +1245,12 @@ let transformSignatureItem ~config _mapper item = 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)) + | Ptyp_arrow + ( name, + ({ptyp_attributes = attrs} as type_), + ({ptyp_desc = Ptyp_arrow _} as rest) ) when isOptional name || isLabelled name -> - getPropTypes ((name, ptyp_loc, type_) :: types) rest + getPropTypes ((name, attrs, ptyp_loc, type_) :: types) rest | Ptyp_arrow (Nolabel, {ptyp_desc = Ptyp_constr ({txt = Lident "unit"}, _)}, rest) -> @@ -1247,9 +1258,9 @@ let transformSignatureItem ~config _mapper item = | Ptyp_arrow (Nolabel, _type, rest) -> hasForwardRef := true; getPropTypes types rest - | Ptyp_arrow (name, type_, returnValue) + | Ptyp_arrow (name, ({ptyp_attributes = attrs} as type_), returnValue) when isOptional name || isLabelled name -> - (returnValue, (name, returnValue.ptyp_loc, type_) :: types) + (returnValue, (name, attrs, returnValue.ptyp_loc, type_) :: types) | _ -> (fullType, types) in let innerType, propTypes = getPropTypes [] pval_type in diff --git a/tests/ppx/react/expected/mangleKeyword.res.txt b/tests/ppx/react/expected/mangleKeyword.res.txt index ca1e2bcc..ff8804e3 100644 --- a/tests/ppx/react/expected/mangleKeyword.res.txt +++ b/tests/ppx/react/expected/mangleKeyword.res.txt @@ -3,7 +3,7 @@ module C0 = { @obj external makeProps: (~_open: 'T_open, ~key: string=?, unit) => {"_open": 'T_open} = "" - @react.component let make = (@warning("-16") ~_open) => React.string(_open) + @react.component let make = @warning("-16") (~_open) => React.string(_open) let make = { let \"MangleKeyword$C0" = (\"Props": {"_open": 'T_open}) => make(~_open=\"Props"["_open"]) \"MangleKeyword$C0" @@ -20,11 +20,14 @@ let c1 = React.createElement(C1.make, C1.makeProps(~_open="x", ())) @@jsxConfig({version: 4, mode: "classic"}) module C0 = { - type props<'T_open> = { - _open: 'T_open, + type props<'T_open, 'T_type> = { + @as("open") _open: 'T_open, + @as("type") _type: 'T_type, } - @react.component let make = ({_open, _}: props<'T_open>) => React.string(_open) + @react.component + let make = ({@as("open") _open, @as("type") _type, _}: props<'T_open, string>) => + React.string(_open) let make = { let \"MangleKeyword$C0" = (props: props<_>) => make(props) @@ -32,24 +35,28 @@ module C0 = { } } module C1 = { - type props<'T_open> = { - _open: 'T_open, + type props<'T_open, 'T_type> = { + @as("open") _open: 'T_open, + @as("type") _type: 'T_type, } - external make: @as("open") React.componentLike, React.element> = "default" + external make: @as("open") React.componentLike, React.element> = "default" } -let c0 = React.createElement(C0.make, {_open: "x"}) -let c1 = React.createElement(C1.make, {_open: "x"}) +let c0 = React.createElement(C0.make, {_open: "x", _type: "t"}) +let c1 = React.createElement(C1.make, {_open: "x", _type: "t"}) @@jsxConfig({version: 4, mode: "automatic"}) module C0 = { - type props<'T_open> = { - _open: 'T_open, + type props<'T_open, 'T_type> = { + @as("open") _open: 'T_open, + @as("type") _type: 'T_type, } - @react.component let make = ({_open, _}: props<'T_open>) => React.string(_open) + @react.component + let make = ({@as("open") _open, @as("type") _type, _}: props<'T_open, string>) => + React.string(_open) let make = { let \"MangleKeyword$C0" = (props: props<_>) => make(props) @@ -57,12 +64,13 @@ module C0 = { } } module C1 = { - type props<'T_open> = { - _open: 'T_open, + type props<'T_open, 'T_type> = { + @as("open") _open: 'T_open, + @as("type") _type: 'T_type, } - external make: @as("open") React.componentLike, React.element> = "default" + external make: @as("open") React.componentLike, React.element> = "default" } -let c0 = React.jsx(C0.make, {_open: "x"}) -let c1 = React.jsx(C1.make, {_open: "x"}) +let c0 = React.jsx(C0.make, {_open: "x", _type: "t"}) +let c1 = React.jsx(C1.make, {_open: "x", _type: "t"}) diff --git a/tests/ppx/react/mangleKeyword.res b/tests/ppx/react/mangleKeyword.res index bc149220..c40da3b4 100644 --- a/tests/ppx/react/mangleKeyword.res +++ b/tests/ppx/react/mangleKeyword.res @@ -17,27 +17,29 @@ let c1 = module C0 = { @react.component let make = - (@as("open") ~_open) => React.string(_open) + (@as("open") ~_open, @as("type") ~_type: string) => React.string(_open) } module C1 = { @react.component - external make: (@as("open") ~_open: string) => React.element = "default" + external make: (@as("open") ~_open: string, @as("type") ~_type: string) => React.element = + "default" } -let c0 = -let c1 = +let c0 = +let c1 = @@jsxConfig({version: 4, mode: "automatic"}) module C0 = { @react.component let make = - (@as("open") ~_open) => React.string(_open) + (@as("open") ~_open, @as("type") ~_type: string) => React.string(_open) } module C1 = { @react.component - external make: (@as("open") ~_open: string) => React.element = "default" + external make: (@as("open") ~_open: string, @as("type") ~_type: string) => React.element = + "default" } -let c0 = -let c1 = \ No newline at end of file +let c0 = +let c1 = From d9e940f6bfbd2e414390dcc02a9a9db484af6e67 Mon Sep 17 00:00:00 2001 From: Woonki Moon Date: Thu, 15 Dec 2022 08:20:57 +0900 Subject: [PATCH 3/4] clean up test --- .../ppx/react/expected/mangleKeyword.res.txt | 36 +++++++++---------- tests/ppx/react/mangleKeyword.res | 24 ++++++------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/tests/ppx/react/expected/mangleKeyword.res.txt b/tests/ppx/react/expected/mangleKeyword.res.txt index ff8804e3..78108dd0 100644 --- a/tests/ppx/react/expected/mangleKeyword.res.txt +++ b/tests/ppx/react/expected/mangleKeyword.res.txt @@ -1,25 +1,25 @@ @@jsxConfig({version: 3}) -module C0 = { +module C30 = { @obj external makeProps: (~_open: 'T_open, ~key: string=?, unit) => {"_open": 'T_open} = "" @react.component let make = @warning("-16") (~_open) => React.string(_open) let make = { - let \"MangleKeyword$C0" = (\"Props": {"_open": 'T_open}) => make(~_open=\"Props"["_open"]) - \"MangleKeyword$C0" + let \"MangleKeyword$C30" = (\"Props": {"_open": 'T_open}) => make(~_open=\"Props"["_open"]) + \"MangleKeyword$C30" } } -module C1 = { +module C31 = { @obj external makeProps: (~_open: string, ~key: string=?, unit) => {"_open": string} = "" external make: React.componentLike<{"_open": string}, React.element> = "default" } -let c0 = React.createElement(C0.make, C0.makeProps(~_open="x", ())) -let c1 = React.createElement(C1.make, C1.makeProps(~_open="x", ())) +let c30 = React.createElement(C30.make, C30.makeProps(~_open="x", ())) +let c31 = React.createElement(C31.make, C31.makeProps(~_open="x", ())) @@jsxConfig({version: 4, mode: "classic"}) -module C0 = { +module C4C0 = { type props<'T_open, 'T_type> = { @as("open") _open: 'T_open, @as("type") _type: 'T_type, @@ -29,12 +29,12 @@ module C0 = { let make = ({@as("open") _open, @as("type") _type, _}: props<'T_open, string>) => React.string(_open) let make = { - let \"MangleKeyword$C0" = (props: props<_>) => make(props) + let \"MangleKeyword$C4C0" = (props: props<_>) => make(props) - \"MangleKeyword$C0" + \"MangleKeyword$C4C0" } } -module C1 = { +module C4C1 = { type props<'T_open, 'T_type> = { @as("open") _open: 'T_open, @as("type") _type: 'T_type, @@ -43,12 +43,12 @@ module C1 = { external make: @as("open") React.componentLike, React.element> = "default" } -let c0 = React.createElement(C0.make, {_open: "x", _type: "t"}) -let c1 = React.createElement(C1.make, {_open: "x", _type: "t"}) +let c4c0 = React.createElement(C4C0.make, {_open: "x", _type: "t"}) +let c4c1 = React.createElement(C4C1.make, {_open: "x", _type: "t"}) @@jsxConfig({version: 4, mode: "automatic"}) -module C0 = { +module C4A0 = { type props<'T_open, 'T_type> = { @as("open") _open: 'T_open, @as("type") _type: 'T_type, @@ -58,12 +58,12 @@ module C0 = { let make = ({@as("open") _open, @as("type") _type, _}: props<'T_open, string>) => React.string(_open) let make = { - let \"MangleKeyword$C0" = (props: props<_>) => make(props) + let \"MangleKeyword$C4A0" = (props: props<_>) => make(props) - \"MangleKeyword$C0" + \"MangleKeyword$C4A0" } } -module C1 = { +module C4A1 = { type props<'T_open, 'T_type> = { @as("open") _open: 'T_open, @as("type") _type: 'T_type, @@ -72,5 +72,5 @@ module C1 = { external make: @as("open") React.componentLike, React.element> = "default" } -let c0 = React.jsx(C0.make, {_open: "x", _type: "t"}) -let c1 = React.jsx(C1.make, {_open: "x", _type: "t"}) +let c4a0 = React.jsx(C4A0.make, {_open: "x", _type: "t"}) +let c4a1 = React.jsx(C4A1.make, {_open: "x", _type: "t"}) diff --git a/tests/ppx/react/mangleKeyword.res b/tests/ppx/react/mangleKeyword.res index c40da3b4..2e0fa7c3 100644 --- a/tests/ppx/react/mangleKeyword.res +++ b/tests/ppx/react/mangleKeyword.res @@ -1,45 +1,45 @@ @@jsxConfig({version: 3}) -module C0 = { +module C30 = { @react.component let make = (~_open) => React.string(_open) } -module C1 = { +module C31 = { @react.component external make: (~_open: string) => React.element = "default" } -let c0 = -let c1 = +let c30 = +let c31 = @@jsxConfig({version: 4, mode: "classic"}) -module C0 = { +module C4C0 = { @react.component let make = (@as("open") ~_open, @as("type") ~_type: string) => React.string(_open) } -module C1 = { +module C4C1 = { @react.component external make: (@as("open") ~_open: string, @as("type") ~_type: string) => React.element = "default" } -let c0 = -let c1 = +let c4c0 = +let c4c1 = @@jsxConfig({version: 4, mode: "automatic"}) -module C0 = { +module C4A0 = { @react.component let make = (@as("open") ~_open, @as("type") ~_type: string) => React.string(_open) } -module C1 = { +module C4A1 = { @react.component external make: (@as("open") ~_open: string, @as("type") ~_type: string) => React.element = "default" } -let c0 = -let c1 = +let c4a0 = +let c4a1 = From 822f082e86e4aa8be97ac75550a843e6fe76644b Mon Sep 17 00:00:00 2001 From: Woonki Moon Date: Thu, 15 Dec 2022 08:21:04 +0900 Subject: [PATCH 4/4] update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9250e5a7..7627335c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,6 +54,7 @@ - Treat await as almost-unary operator weaker than pipe so `await foo->bar` means `await (foo->bar)` https://github.com/rescript-lang/syntax/pull/711 - Fix build error where aliasing arguments to `_` in the make function with JSX V4. https://github.com/rescript-lang/syntax/pull/720 - Fix parsing of spread props as an expression in JSX V4 https://github.com/rescript-lang/syntax/pull/721 +- Fix dropping attributes from props in make function in JSX V4 https://github.com/rescript-lang/syntax/pull/723 #### :eyeglasses: Spec Compliance