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

Commit 536e1b6

Browse files
authored
Add loc to each props in JSX4 (#728)
1 parent fff41d1 commit 536e1b6

16 files changed

+64
-112
lines changed

cli/reactjs_jsx_v4.ml

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -242,9 +242,9 @@ let recordFromProps ~loc ~removeKey callArguments =
242242
(* let make = ({id, name, children}: props<'id, 'name, 'children>) *)
243243
let makePropsTypeParamsTvar namedTypeList =
244244
namedTypeList
245-
|> List.filter_map (fun (_isOptional, label, _, _interiorType) ->
245+
|> List.filter_map (fun (_isOptional, label, _, loc, _interiorType) ->
246246
if label = "key" then None
247-
else Some (Typ.var @@ safeTypeFromValue (Labelled label)))
247+
else Some (Typ.var ~loc @@ safeTypeFromValue (Labelled label)))
248248

249249
let stripOption coreType =
250250
match coreType with
@@ -268,7 +268,7 @@ let stripJsNullable coreType =
268268
let makePropsTypeParams ?(stripExplicitOption = false)
269269
?(stripExplicitJsNullableOfRef = false) namedTypeList =
270270
namedTypeList
271-
|> List.filter_map (fun (isOptional, label, _, interiorType) ->
271+
|> List.filter_map (fun (isOptional, label, _, loc, interiorType) ->
272272
if label = "key" then None
273273
(* TODO: Worth thinking how about "ref_" or "_ref" usages *)
274274
else if label = "ref" then
@@ -277,7 +277,7 @@ let makePropsTypeParams ?(stripExplicitOption = false)
277277
For example, if JSX ppx is used for React Native, type would be different.
278278
*)
279279
match interiorType with
280-
| {ptyp_desc = Ptyp_var "ref"} -> Some (refType Location.none)
280+
| {ptyp_desc = Ptyp_var "ref"} -> Some (refType loc)
281281
| _ ->
282282
(* Strip explicit Js.Nullable.t in case of forwardRef *)
283283
if stripExplicitJsNullableOfRef then stripJsNullable interiorType
@@ -287,9 +287,25 @@ let makePropsTypeParams ?(stripExplicitOption = false)
287287
else if isOptional && stripExplicitOption then stripOption interiorType
288288
else Some interiorType)
289289

290-
let makeLabelDecls ~loc namedTypeList =
290+
let makeLabelDecls namedTypeList =
291+
let rec checkDuplicatedLabel l =
292+
let rec mem_label ((_, (la : string), _, _, _) as x) = function
293+
| [] -> false
294+
| (_, (lb : string), _, _, _) :: l -> lb = la || mem_label x l
295+
in
296+
match l with
297+
| [] -> ()
298+
| hd :: tl ->
299+
if mem_label hd tl then
300+
let _, label, _, loc, _ = hd in
301+
React_jsx_common.raiseError ~loc "JSX: found the duplicated prop `%s`"
302+
label
303+
else checkDuplicatedLabel tl
304+
in
305+
let () = namedTypeList |> List.rev |> checkDuplicatedLabel in
306+
291307
namedTypeList
292-
|> List.map (fun (isOptional, label, attrs, interiorType) ->
308+
|> List.map (fun (isOptional, label, attrs, loc, interiorType) ->
293309
if label = "key" then
294310
Type.field ~loc ~attrs:(optionalAttrs @ attrs) {txt = label; loc}
295311
interiorType
@@ -301,7 +317,7 @@ let makeLabelDecls ~loc namedTypeList =
301317
(Typ.var @@ safeTypeFromValue @@ Labelled label))
302318

303319
let makeTypeDecls propsName loc namedTypeList =
304-
let labelDeclList = makeLabelDecls ~loc namedTypeList in
320+
let labelDeclList = makeLabelDecls namedTypeList in
305321
(* 'id, 'className, ... *)
306322
let params =
307323
makePropsTypeParamsTvar namedTypeList
@@ -702,17 +718,22 @@ let argToType ~newtypes ~(typeConstraints : core_type option) types
702718
in
703719
match (type_, name, default) with
704720
| Some type_, name, _ when isOptional name ->
705-
(true, getLabel name, attrs, {type_ with ptyp_attributes = optionalAttrs})
721+
( true,
722+
getLabel name,
723+
attrs,
724+
loc,
725+
{type_ with ptyp_attributes = optionalAttrs} )
706726
:: types
707-
| Some type_, name, _ -> (false, getLabel name, attrs, type_) :: types
727+
| Some type_, name, _ -> (false, getLabel name, attrs, loc, type_) :: types
708728
| None, name, _ when isOptional name ->
709729
( true,
710730
getLabel name,
711731
attrs,
732+
loc,
712733
Typ.var ~loc ~attrs:optionalAttrs (safeTypeFromValue name) )
713734
:: types
714735
| None, name, _ when isLabelled name ->
715-
(false, getLabel name, attrs, Typ.var ~loc (safeTypeFromValue name))
736+
(false, getLabel name, attrs, loc, Typ.var ~loc (safeTypeFromValue name))
716737
:: types
717738
| _ -> types
718739

@@ -721,10 +742,12 @@ let argWithDefaultValue (name, default, _, _, _, _) =
721742
| Some default when isOptional name -> Some (getLabel name, default)
722743
| _ -> None
723744

724-
let argToConcreteType types (name, attrs, _loc, type_) =
745+
let argToConcreteType types (name, attrs, loc, type_) =
725746
match name with
726-
| name when isLabelled name -> (false, getLabel name, attrs, type_) :: types
727-
| name when isOptional name -> (true, getLabel name, attrs, type_) :: types
747+
| name when isLabelled name ->
748+
(false, getLabel name, attrs, loc, type_) :: types
749+
| name when isOptional name ->
750+
(true, getLabel name, attrs, loc, type_) :: types
728751
| _ -> types
729752

730753
let check_string_int_attribute_iter =
@@ -1279,7 +1302,8 @@ let transformSignatureItem ~config _mapper item =
12791302
makePropsRecordTypeSig ~coreTypeOfAttr ~typVarsOfCoreType "props"
12801303
psig_loc
12811304
((* If there is Nolabel arg, regard the type as ref in forwardRef *)
1282-
(if !hasForwardRef then [(true, "ref", [], refType Location.none)]
1305+
(if !hasForwardRef then
1306+
[(true, "ref", [], Location.none, refType Location.none)]
12831307
else [])
12841308
@ namedTypeList)
12851309
in

tests/ppx/react/expected/aliasProps.res.txt

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
@@jsxConfig({version: 4, mode: "automatic"})
22

33
module C0 = {
4-
type props<'priority, 'text> = {
5-
priority: 'priority,
6-
text?: 'text,
7-
}
4+
type props<'priority, 'text> = {priority: 'priority, text?: 'text}
85

96
@react.component
107
let make = ({priority: _, ?text, _}: props<'priority, 'text>) => {
@@ -23,10 +20,7 @@ module C0 = {
2320
}
2421

2522
module C1 = {
26-
type props<'priority, 'text> = {
27-
priority: 'priority,
28-
text?: 'text,
29-
}
23+
type props<'priority, 'text> = {priority: 'priority, text?: 'text}
3024

3125
@react.component
3226
let make = ({priority: p, ?text, _}: props<'priority, 'text>) => {

tests/ppx/react/expected/commentAtTop.res.txt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
type props<'msg> = { // test React JSX file
2-
msg: 'msg,
3-
}
1+
type props<'msg> = {msg: 'msg} // test React JSX file
42

53
@react.component
64
let make = ({msg, _}: props<'msg>) => {

tests/ppx/react/expected/externalWithCustomName.res.txt

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,7 @@ let t = React.createElement(Foo.component, Foo.componentProps(~a=1, ~b={"1"}, ()
1313
@@jsxConfig({version: 4, mode: "classic"})
1414

1515
module Foo = {
16-
type props<'a, 'b> = {
17-
a: 'a,
18-
b: 'b,
19-
}
16+
type props<'a, 'b> = {a: 'a, b: 'b}
2017

2118
@module("Foo")
2219
external component: React.componentLike<props<int, string>, React.element> = "component"
@@ -27,10 +24,7 @@ let t = React.createElement(Foo.component, {a: 1, b: "1"})
2724
@@jsxConfig({version: 4, mode: "automatic"})
2825

2926
module Foo = {
30-
type props<'a, 'b> = {
31-
a: 'a,
32-
b: 'b,
33-
}
27+
type props<'a, 'b> = {a: 'a, b: 'b}
3428

3529
@module("Foo")
3630
external component: React.componentLike<props<int, string>, React.element> = "component"

tests/ppx/react/expected/fileLevelConfig.res.txt

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,7 @@ module V3 = {
1818
@@jsxConfig({version: 4, mode: "classic"})
1919

2020
module V4C = {
21-
type props<'msg> = {
22-
msg: 'msg,
23-
}
21+
type props<'msg> = {msg: 'msg}
2422

2523
@react.component
2624
let make = ({msg, _}: props<'msg>) => {
@@ -36,9 +34,7 @@ module V4C = {
3634
@@jsxConfig({version: 4, mode: "automatic"})
3735

3836
module V4A = {
39-
type props<'msg> = {
40-
msg: 'msg,
41-
}
37+
type props<'msg> = {msg: 'msg}
4238

4339
@react.component
4440
let make = ({msg, _}: props<'msg>) => {

tests/ppx/react/expected/interface.res.txt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
module A = {
2-
type props<'x> = {
3-
x: 'x,
4-
}
2+
type props<'x> = {x: 'x}
53
@react.component let make = ({x, _}: props<'x>) => React.string(x)
64
let make = {
75
let \"Interface$A" = (props: props<_>) => make(props)

tests/ppx/react/expected/interface.resi.txt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
module A: {
2-
type props<'x> = {
3-
x: 'x,
4-
}
2+
type props<'x> = {x: 'x}
53
let make: React.componentLike<props<string>, React.element>
64
}
75

tests/ppx/react/expected/interfaceWithRef.res.txt

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
type props<'x, 'ref> = {
2-
x: 'x,
3-
ref?: 'ref,
4-
}
1+
type props<'x, 'ref> = {x: 'x, ref?: 'ref}
52
@react.component
63
let make = (
74
{x, _}: props<string, ReactDOM.Ref.currentDomRef>,
Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,2 @@
1-
type props<'x, 'ref> = {
2-
x: 'x,
3-
ref?: 'ref,
4-
}
1+
type props<'x, 'ref> = {x: 'x, ref?: 'ref}
52
let make: React.componentLike<props<string, ReactDOM.Ref.currentDomRef>, React.element>

tests/ppx/react/expected/mangleKeyword.res.txt

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,7 @@ let c31 = React.createElement(C31.make, C31.makeProps(~_open="x", ()))
2020
@@jsxConfig({version: 4, mode: "classic"})
2121

2222
module C4C0 = {
23-
type props<'T_open, 'T_type> = {
24-
@as("open") _open: 'T_open,
25-
@as("type") _type: 'T_type,
26-
}
23+
type props<'T_open, 'T_type> = {@as("open") _open: 'T_open, @as("type") _type: 'T_type}
2724

2825
@react.component
2926
let make = ({@as("open") _open, @as("type") _type, _}: props<'T_open, string>) =>
@@ -35,10 +32,7 @@ module C4C0 = {
3532
}
3633
}
3734
module C4C1 = {
38-
type props<'T_open, 'T_type> = {
39-
@as("open") _open: 'T_open,
40-
@as("type") _type: 'T_type,
41-
}
35+
type props<'T_open, 'T_type> = {@as("open") _open: 'T_open, @as("type") _type: 'T_type}
4236

4337
external make: @as("open") React.componentLike<props<string, string>, React.element> = "default"
4438
}
@@ -49,10 +43,7 @@ let c4c1 = React.createElement(C4C1.make, {_open: "x", _type: "t"})
4943
@@jsxConfig({version: 4, mode: "automatic"})
5044

5145
module C4A0 = {
52-
type props<'T_open, 'T_type> = {
53-
@as("open") _open: 'T_open,
54-
@as("type") _type: 'T_type,
55-
}
46+
type props<'T_open, 'T_type> = {@as("open") _open: 'T_open, @as("type") _type: 'T_type}
5647

5748
@react.component
5849
let make = ({@as("open") _open, @as("type") _type, _}: props<'T_open, string>) =>
@@ -64,10 +55,7 @@ module C4A0 = {
6455
}
6556
}
6657
module C4A1 = {
67-
type props<'T_open, 'T_type> = {
68-
@as("open") _open: 'T_open,
69-
@as("type") _type: 'T_type,
70-
}
58+
type props<'T_open, 'T_type> = {@as("open") _open: 'T_open, @as("type") _type: 'T_type}
7159

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

tests/ppx/react/expected/newtype.res.txt

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,7 @@ module V3 = {
2424
@@jsxConfig({version: 4, mode: "classic"})
2525

2626
module V4C = {
27-
type props<'a, 'b, 'c> = {
28-
a: 'a,
29-
b: 'b,
30-
c: 'c,
31-
}
27+
type props<'a, 'b, 'c> = {a: 'a, b: 'b, c: 'c}
3228

3329
@react.component
3430
let make = ({a, b, c, _}: props<'\"type-a", array<option<[#Foo('\"type-a")]>>, 'a>) =>
@@ -43,11 +39,7 @@ module V4C = {
4339
@@jsxConfig({version: 4, mode: "automatic"})
4440

4541
module V4A = {
46-
type props<'a, 'b, 'c> = {
47-
a: 'a,
48-
b: 'b,
49-
c: 'c,
50-
}
42+
type props<'a, 'b, 'c> = {a: 'a, b: 'b, c: 'c}
5143

5244
@react.component
5345
let make = ({a, b, c, _}: props<'\"type-a", array<option<[#Foo('\"type-a")]>>, 'a>) =>

tests/ppx/react/expected/optimizeAutomaticMode.res.txt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@ module User = {
44
type t = {firstName: string, lastName: string}
55

66
let format = user => "Dr." ++ user.lastName
7-
type props<'doctor> = {
8-
doctor: 'doctor,
9-
}
7+
type props<'doctor> = {doctor: 'doctor}
108

119
@react.component
1210
let make = ({doctor, _}: props<'doctor>) => {

tests/ppx/react/expected/removedKeyProp.res.txt

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
@@jsxConfig({version: 4, mode: "classic"})
22

33
module Foo = {
4-
type props<'x, 'y> = {
5-
x: 'x,
6-
y: 'y,
7-
}
4+
type props<'x, 'y> = {x: 'x, y: 'y}
85

96
@react.component let make = ({x, y, _}: props<'x, 'y>) => React.string(x ++ y)
107
let make = {
@@ -15,9 +12,7 @@ module Foo = {
1512
}
1613

1714
module HasChildren = {
18-
type props<'children> = {
19-
children: 'children,
20-
}
15+
type props<'children> = {children: 'children}
2116

2217
@react.component
2318
let make = ({children, _}: props<'children>) => ReactDOM.createElement(React.fragment, [children])

tests/ppx/react/expected/topLevel.res.txt

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,7 @@ module V3 = {
2222
@@jsxConfig({version: 4, mode: "classic"})
2323

2424
module V4C = {
25-
type props<'a, 'b> = {
26-
a: 'a,
27-
b: 'b,
28-
}
25+
type props<'a, 'b> = {a: 'a, b: 'b}
2926

3027
@react.component
3128
let make = ({a, b, _}: props<'a, 'b>) => {
@@ -42,10 +39,7 @@ module V4C = {
4239
@@jsxConfig({version: 4, mode: "automatic"})
4340

4441
module V4A = {
45-
type props<'a, 'b> = {
46-
a: 'a,
47-
b: 'b,
48-
}
42+
type props<'a, 'b> = {a: 'a, b: 'b}
4943

5044
@react.component
5145
let make = ({a, b, _}: props<'a, 'b>) => {

tests/ppx/react/expected/typeConstraint.res.txt

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,7 @@ module V3 = {
1717
@@jsxConfig({version: 4, mode: "classic"})
1818

1919
module V4C = {
20-
type props<'a, 'b> = {
21-
a: 'a,
22-
b: 'b,
23-
}
20+
type props<'a, 'b> = {a: 'a, b: 'b}
2421

2522
@react.component
2623
let make = ({a, b, _}: props<'\"type-a", '\"type-a">) =>
@@ -35,10 +32,7 @@ module V4C = {
3532
@@jsxConfig({version: 4, mode: "automatic"})
3633

3734
module V4A = {
38-
type props<'a, 'b> = {
39-
a: 'a,
40-
b: 'b,
41-
}
35+
type props<'a, 'b> = {a: 'a, b: 'b}
4236

4337
@react.component let make = ({a, b, _}: props<'\"type-a", '\"type-a">) => ReactDOM.jsx("div", {})
4438
let make = {

0 commit comments

Comments
 (0)