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

Commit 3835042

Browse files
authored
Fix dropping attributes of props in JSX v4 (#723)
* add test * make record type for props with attrs * clean up test * update CHANGELOG.md
1 parent c1b478e commit 3835042

File tree

4 files changed

+152
-19
lines changed

4 files changed

+152
-19
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
- 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
5555
- Fix build error where aliasing arguments to `_` in the make function with JSX V4. https://github.com/rescript-lang/syntax/pull/720
5656
- Fix parsing of spread props as an expression in JSX V4 https://github.com/rescript-lang/syntax/pull/721
57+
- Fix dropping attributes from props in make function in JSX V4 https://github.com/rescript-lang/syntax/pull/723
5758

5859
#### :eyeglasses: Spec Compliance
5960

cli/reactjs_jsx_v4.ml

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -289,14 +289,15 @@ let makePropsTypeParams ?(stripExplicitOption = false)
289289

290290
let makeLabelDecls ~loc namedTypeList =
291291
namedTypeList
292-
|> List.map (fun (isOptional, label, _, interiorType) ->
292+
|> List.map (fun (isOptional, label, attrs, interiorType) ->
293293
if label = "key" then
294-
Type.field ~loc ~attrs:optionalAttrs {txt = label; loc} interiorType
294+
Type.field ~loc ~attrs:(optionalAttrs @ attrs) {txt = label; loc}
295+
interiorType
295296
else if isOptional then
296-
Type.field ~loc ~attrs:optionalAttrs {txt = label; loc}
297+
Type.field ~loc ~attrs:(optionalAttrs @ attrs) {txt = label; loc}
297298
(Typ.var @@ safeTypeFromValue @@ Labelled label)
298299
else
299-
Type.field ~loc {txt = label; loc}
300+
Type.field ~loc ~attrs {txt = label; loc}
300301
(Typ.var @@ safeTypeFromValue @@ Labelled label))
301302

302303
let makeTypeDecls propsName loc namedTypeList =
@@ -681,7 +682,9 @@ let newtypeToVar newtype type_ =
681682
mapper.typ mapper type_
682683

683684
let argToType ~newtypes ~(typeConstraints : core_type option) types
684-
(name, default, _noLabelName, _alias, loc, type_) =
685+
((name, default, {ppat_attributes = attrs}, _alias, loc, type_) :
686+
arg_label * expression option * pattern * label * 'loc * core_type option)
687+
=
685688
let rec getType name coreType =
686689
match coreType with
687690
| {ptyp_desc = Ptyp_arrow (arg, c1, c2)} ->
@@ -699,28 +702,29 @@ let argToType ~newtypes ~(typeConstraints : core_type option) types
699702
in
700703
match (type_, name, default) with
701704
| Some type_, name, _ when isOptional name ->
702-
(true, getLabel name, [], {type_ with ptyp_attributes = optionalAttrs})
705+
(true, getLabel name, attrs, {type_ with ptyp_attributes = optionalAttrs})
703706
:: types
704-
| Some type_, name, _ -> (false, getLabel name, [], type_) :: types
707+
| Some type_, name, _ -> (false, getLabel name, attrs, type_) :: types
705708
| None, name, _ when isOptional name ->
706709
( true,
707710
getLabel name,
708-
[],
711+
attrs,
709712
Typ.var ~loc ~attrs:optionalAttrs (safeTypeFromValue name) )
710713
:: types
711714
| None, name, _ when isLabelled name ->
712-
(false, getLabel name, [], Typ.var ~loc (safeTypeFromValue name)) :: types
715+
(false, getLabel name, attrs, Typ.var ~loc (safeTypeFromValue name))
716+
:: types
713717
| _ -> types
714718

715719
let argWithDefaultValue (name, default, _, _, _, _) =
716720
match default with
717721
| Some default when isOptional name -> Some (getLabel name, default)
718722
| _ -> None
719723

720-
let argToConcreteType types (name, _loc, type_) =
724+
let argToConcreteType types (name, attrs, _loc, type_) =
721725
match name with
722-
| name when isLabelled name -> (false, getLabel name, [], type_) :: types
723-
| name when isOptional name -> (true, getLabel name, [], type_) :: types
726+
| name when isLabelled name -> (false, getLabel name, attrs, type_) :: types
727+
| name when isOptional name -> (true, getLabel name, attrs, type_) :: types
724728
| _ -> types
725729

726730
let check_string_int_attribute_iter =
@@ -757,15 +761,19 @@ let transformStructureItem ~config mapper item =
757761
|> Option.map React_jsx_common.typVarsOfCoreType
758762
|> Option.value ~default:[]
759763
in
760-
let rec getPropTypes types ({ptyp_loc; ptyp_desc} as fullType) =
764+
let rec getPropTypes types
765+
({ptyp_loc; ptyp_desc; ptyp_attributes} as fullType) =
761766
match ptyp_desc with
762767
| Ptyp_arrow (name, type_, ({ptyp_desc = Ptyp_arrow _} as rest))
763768
when isLabelled name || isOptional name ->
764-
getPropTypes ((name, ptyp_loc, type_) :: types) rest
769+
getPropTypes
770+
((name, ptyp_attributes, ptyp_loc, type_) :: types)
771+
rest
765772
| Ptyp_arrow (Nolabel, _type, rest) -> getPropTypes types rest
766773
| Ptyp_arrow (name, type_, returnValue)
767774
when isLabelled name || isOptional name ->
768-
(returnValue, (name, returnValue.ptyp_loc, type_) :: types)
775+
( returnValue,
776+
(name, ptyp_attributes, returnValue.ptyp_loc, type_) :: types )
769777
| _ -> (fullType, types)
770778
in
771779
let innerType, propTypes = getPropTypes [] pval_type in
@@ -1237,19 +1245,22 @@ let transformSignatureItem ~config _mapper item =
12371245
in
12381246
let rec getPropTypes types ({ptyp_loc; ptyp_desc} as fullType) =
12391247
match ptyp_desc with
1240-
| Ptyp_arrow (name, type_, ({ptyp_desc = Ptyp_arrow _} as rest))
1248+
| Ptyp_arrow
1249+
( name,
1250+
({ptyp_attributes = attrs} as type_),
1251+
({ptyp_desc = Ptyp_arrow _} as rest) )
12411252
when isOptional name || isLabelled name ->
1242-
getPropTypes ((name, ptyp_loc, type_) :: types) rest
1253+
getPropTypes ((name, attrs, ptyp_loc, type_) :: types) rest
12431254
| Ptyp_arrow
12441255
(Nolabel, {ptyp_desc = Ptyp_constr ({txt = Lident "unit"}, _)}, rest)
12451256
->
12461257
getPropTypes types rest
12471258
| Ptyp_arrow (Nolabel, _type, rest) ->
12481259
hasForwardRef := true;
12491260
getPropTypes types rest
1250-
| Ptyp_arrow (name, type_, returnValue)
1261+
| Ptyp_arrow (name, ({ptyp_attributes = attrs} as type_), returnValue)
12511262
when isOptional name || isLabelled name ->
1252-
(returnValue, (name, returnValue.ptyp_loc, type_) :: types)
1263+
(returnValue, (name, attrs, returnValue.ptyp_loc, type_) :: types)
12531264
| _ -> (fullType, types)
12541265
in
12551266
let innerType, propTypes = getPropTypes [] pval_type in
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
@@jsxConfig({version: 3})
2+
3+
module C30 = {
4+
@obj external makeProps: (~_open: 'T_open, ~key: string=?, unit) => {"_open": 'T_open} = ""
5+
6+
@react.component let make = @warning("-16") (~_open) => React.string(_open)
7+
let make = {
8+
let \"MangleKeyword$C30" = (\"Props": {"_open": 'T_open}) => make(~_open=\"Props"["_open"])
9+
\"MangleKeyword$C30"
10+
}
11+
}
12+
module C31 = {
13+
@obj external makeProps: (~_open: string, ~key: string=?, unit) => {"_open": string} = ""
14+
external make: React.componentLike<{"_open": string}, React.element> = "default"
15+
}
16+
17+
let c30 = React.createElement(C30.make, C30.makeProps(~_open="x", ()))
18+
let c31 = React.createElement(C31.make, C31.makeProps(~_open="x", ()))
19+
20+
@@jsxConfig({version: 4, mode: "classic"})
21+
22+
module C4C0 = {
23+
type props<'T_open, 'T_type> = {
24+
@as("open") _open: 'T_open,
25+
@as("type") _type: 'T_type,
26+
}
27+
28+
@react.component
29+
let make = ({@as("open") _open, @as("type") _type, _}: props<'T_open, string>) =>
30+
React.string(_open)
31+
let make = {
32+
let \"MangleKeyword$C4C0" = (props: props<_>) => make(props)
33+
34+
\"MangleKeyword$C4C0"
35+
}
36+
}
37+
module C4C1 = {
38+
type props<'T_open, 'T_type> = {
39+
@as("open") _open: 'T_open,
40+
@as("type") _type: 'T_type,
41+
}
42+
43+
external make: @as("open") React.componentLike<props<string, string>, React.element> = "default"
44+
}
45+
46+
let c4c0 = React.createElement(C4C0.make, {_open: "x", _type: "t"})
47+
let c4c1 = React.createElement(C4C1.make, {_open: "x", _type: "t"})
48+
49+
@@jsxConfig({version: 4, mode: "automatic"})
50+
51+
module C4A0 = {
52+
type props<'T_open, 'T_type> = {
53+
@as("open") _open: 'T_open,
54+
@as("type") _type: 'T_type,
55+
}
56+
57+
@react.component
58+
let make = ({@as("open") _open, @as("type") _type, _}: props<'T_open, string>) =>
59+
React.string(_open)
60+
let make = {
61+
let \"MangleKeyword$C4A0" = (props: props<_>) => make(props)
62+
63+
\"MangleKeyword$C4A0"
64+
}
65+
}
66+
module C4A1 = {
67+
type props<'T_open, 'T_type> = {
68+
@as("open") _open: 'T_open,
69+
@as("type") _type: 'T_type,
70+
}
71+
72+
external make: @as("open") React.componentLike<props<string, string>, React.element> = "default"
73+
}
74+
75+
let c4a0 = React.jsx(C4A0.make, {_open: "x", _type: "t"})
76+
let c4a1 = React.jsx(C4A1.make, {_open: "x", _type: "t"})

tests/ppx/react/mangleKeyword.res

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
@@jsxConfig({version: 3})
2+
3+
module C30 = {
4+
@react.component
5+
let make = (~_open) => React.string(_open)
6+
}
7+
module C31 = {
8+
@react.component
9+
external make: (~_open: string) => React.element = "default"
10+
}
11+
12+
let c30 = <C30 _open="x" />
13+
let c31 = <C31 _open="x" />
14+
15+
@@jsxConfig({version: 4, mode: "classic"})
16+
17+
module C4C0 = {
18+
@react.component
19+
let make =
20+
(@as("open") ~_open, @as("type") ~_type: string) => React.string(_open)
21+
}
22+
module C4C1 = {
23+
@react.component
24+
external make: (@as("open") ~_open: string, @as("type") ~_type: string) => React.element =
25+
"default"
26+
}
27+
28+
let c4c0 = <C4C0 _open="x" _type="t" />
29+
let c4c1 = <C4C1 _open="x" _type="t" />
30+
31+
@@jsxConfig({version: 4, mode: "automatic"})
32+
33+
module C4A0 = {
34+
@react.component
35+
let make =
36+
(@as("open") ~_open, @as("type") ~_type: string) => React.string(_open)
37+
}
38+
module C4A1 = {
39+
@react.component
40+
external make: (@as("open") ~_open: string, @as("type") ~_type: string) => React.element =
41+
"default"
42+
}
43+
44+
let c4a0 = <C4A0 _open="x" _type="t" />
45+
let c4a1 = <C4A1 _open="x" _type="t" />

0 commit comments

Comments
 (0)