Skip to content
This repository has been archived by the owner on Jun 15, 2023. It is now read-only.

Fix dropping attributes of props in JSX v4 #723

Merged
merged 4 commits into from
Dec 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
49 changes: 30 additions & 19 deletions cli/reactjs_jsx_v4.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down Expand Up @@ -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)} ->
Expand All @@ -699,28 +702,29 @@ 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, _, _, _, _) =
match default with
| 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 =
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -1237,19 +1245,22 @@ 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)
->
getPropTypes types rest
| 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
Expand Down
76 changes: 76 additions & 0 deletions tests/ppx/react/expected/mangleKeyword.res.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
@@jsxConfig({version: 3})

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$C30" = (\"Props": {"_open": 'T_open}) => make(~_open=\"Props"["_open"])
\"MangleKeyword$C30"
}
}
module C31 = {
@obj external makeProps: (~_open: string, ~key: string=?, unit) => {"_open": string} = ""
external make: React.componentLike<{"_open": string}, React.element> = "default"
}

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 C4C0 = {
type props<'T_open, 'T_type> = {
@as("open") _open: 'T_open,
@as("type") _type: 'T_type,
}

@react.component
let make = ({@as("open") _open, @as("type") _type, _}: props<'T_open, string>) =>
React.string(_open)
let make = {
let \"MangleKeyword$C4C0" = (props: props<_>) => make(props)

\"MangleKeyword$C4C0"
}
}
module C4C1 = {
type props<'T_open, 'T_type> = {
@as("open") _open: 'T_open,
@as("type") _type: 'T_type,
}

external make: @as("open") React.componentLike<props<string, string>, React.element> = "default"
}

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 C4A0 = {
type props<'T_open, 'T_type> = {
@as("open") _open: 'T_open,
@as("type") _type: 'T_type,
}

@react.component
let make = ({@as("open") _open, @as("type") _type, _}: props<'T_open, string>) =>
React.string(_open)
let make = {
let \"MangleKeyword$C4A0" = (props: props<_>) => make(props)

\"MangleKeyword$C4A0"
}
}
module C4A1 = {
type props<'T_open, 'T_type> = {
@as("open") _open: 'T_open,
@as("type") _type: 'T_type,
}

external make: @as("open") React.componentLike<props<string, string>, React.element> = "default"
}

let c4a0 = React.jsx(C4A0.make, {_open: "x", _type: "t"})
let c4a1 = React.jsx(C4A1.make, {_open: "x", _type: "t"})
45 changes: 45 additions & 0 deletions tests/ppx/react/mangleKeyword.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
@@jsxConfig({version: 3})

module C30 = {
@react.component
let make = (~_open) => React.string(_open)
}
module C31 = {
@react.component
external make: (~_open: string) => React.element = "default"
}

let c30 = <C30 _open="x" />
let c31 = <C31 _open="x" />

@@jsxConfig({version: 4, mode: "classic"})

module C4C0 = {
@react.component
let make =
(@as("open") ~_open, @as("type") ~_type: string) => React.string(_open)
}
module C4C1 = {
@react.component
external make: (@as("open") ~_open: string, @as("type") ~_type: string) => React.element =
"default"
}

let c4c0 = <C4C0 _open="x" _type="t" />
let c4c1 = <C4C1 _open="x" _type="t" />

@@jsxConfig({version: 4, mode: "automatic"})

module C4A0 = {
@react.component
let make =
(@as("open") ~_open, @as("type") ~_type: string) => React.string(_open)
}
module C4A1 = {
@react.component
external make: (@as("open") ~_open: string, @as("type") ~_type: string) => React.element =
"default"
}

let c4a0 = <C4A0 _open="x" _type="t" />
let c4a1 = <C4A1 _open="x" _type="t" />