Skip to content

Commit d7d03ae

Browse files
committed
complete lowercase JSX labels from the domProps type
1 parent 2d1742a commit d7d03ae

File tree

5 files changed

+86
-27
lines changed

5 files changed

+86
-27
lines changed

analysis/src/CompletionBackEnd.ml

Lines changed: 63 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,24 @@ let getCompletionsForPath ~debug ~package ~opens ~full ~pos ~exact ~scope
544544
findAllCompletions ~env ~prefix ~exact ~namesUsed ~completionContext
545545
| None -> [])
546546

547+
let rec digToRecordFieldsForCompletion ~debug ~package ~opens ~full ~pos ~env
548+
~scope path =
549+
match
550+
path
551+
|> getCompletionsForPath ~debug ~completionContext:Type ~exact:true ~package
552+
~opens ~full ~pos ~env ~scope
553+
with
554+
| {kind = Type {kind = Abstract (Some (p, _))}} :: _ ->
555+
(* This case happens when what we're looking for is a type alias.
556+
This is the case in newer rescript-react versions where
557+
ReactDOM.domProps is an alias for JsxEvent.t. *)
558+
let pathRev = p |> Utils.expandPath in
559+
pathRev |> List.rev
560+
|> digToRecordFieldsForCompletion ~debug ~package ~opens ~full ~pos ~env
561+
~scope
562+
| {kind = Type {kind = Record fields}} :: _ -> Some fields
563+
| _ -> None
564+
547565
let mkItem ~name ~kind ~detail ~deprecated ~docstring =
548566
let docContent =
549567
(match deprecated with
@@ -567,7 +585,7 @@ let mkItem ~name ~kind ~detail ~deprecated ~docstring =
567585
detail;
568586
documentation =
569587
(if docContent = "" then None
570-
else Some {kind = "markdown"; value = docContent});
588+
else Some {kind = "markdown"; value = docContent});
571589
sortText = None;
572590
insertText = None;
573591
insertTextFormat = None;
@@ -1039,25 +1057,16 @@ and getCompletionsForContextPath ~debug ~full ~opens ~rawOpens ~pos ~env ~exact
10391057
in
10401058
let targetLabel =
10411059
if lowercaseComponent then
1042-
let rec digToTypeForCompletion path =
1043-
match
1044-
path
1045-
|> getCompletionsForPath ~debug ~completionContext:Type ~exact:true
1046-
~package ~opens ~full ~pos ~env ~scope
1047-
with
1048-
| {kind = Type {kind = Abstract (Some (p, _))}} :: _ ->
1049-
(* This case happens when what we're looking for is a type alias.
1050-
This is the case in newer rescript-react versions where
1051-
ReactDOM.domProps is an alias for JsxEvent.t. *)
1052-
let pathRev = p |> Utils.expandPath in
1053-
pathRev |> List.rev |> digToTypeForCompletion
1054-
| {kind = Type {kind = Record fields}} :: _ -> (
1055-
match fields |> List.find_opt (fun f -> f.fname.txt = propName) with
1056-
| None -> None
1057-
| Some f -> Some (f.fname.txt, f.typ, env))
1058-
| _ -> None
1059-
in
1060-
["ReactDOM"; "domProps"] |> digToTypeForCompletion
1060+
match
1061+
["ReactDOM"; "domProps"]
1062+
|> digToRecordFieldsForCompletion ~debug ~package ~opens ~full ~pos
1063+
~env ~scope
1064+
with
1065+
| None -> None
1066+
| Some fields -> (
1067+
match fields |> List.find_opt (fun f -> f.fname.txt = propName) with
1068+
| None -> None
1069+
| Some f -> Some (f.fname.txt, f.typ, env))
10611070
else
10621071
CompletionJsx.getJsxLabels ~componentPath:pathToComponent
10631072
~findTypeOfValue ~package
@@ -1537,20 +1546,47 @@ let rec processCompletable ~debug ~full ~scope ~env ~pos ~forHover completable =
15371546
contextPath
15381547
|> getCompletionsForContextPath ~debug ~full ~opens ~rawOpens ~pos ~env
15391548
~exact:forHover ~scope
1540-
| Cjsx ([id], prefix, identsSeen) when String.uncapitalize_ascii id = id ->
1549+
| Cjsx ([id], prefix, identsSeen) when String.uncapitalize_ascii id = id -> (
15411550
(* Lowercase JSX tag means builtin *)
15421551
let mkLabel (name, typString) =
15431552
Completion.create name ~kind:(Label typString) ~env
15441553
in
15451554
let keyLabels =
15461555
if Utils.startsWith "key" prefix then [mkLabel ("key", "string")] else []
15471556
in
1548-
(CompletionJsx.domLabels
1549-
|> List.filter (fun (name, _t) ->
1550-
Utils.startsWith name prefix
1551-
&& (forHover || not (List.mem name identsSeen)))
1552-
|> List.map mkLabel)
1553-
@ keyLabels
1557+
(* We always try to look up completion from the actual domProps type first.
1558+
This works in JSXv4. For JSXv3, we have a backup hardcoded list of dom
1559+
labels we can use for completion. *)
1560+
let fromDomProps =
1561+
match
1562+
["ReactDOM"; "domProps"]
1563+
|> digToRecordFieldsForCompletion ~debug ~package ~opens ~full ~pos ~env
1564+
~scope
1565+
with
1566+
| None -> None
1567+
| Some fields ->
1568+
Some
1569+
(fields
1570+
|> List.filter_map (fun (f : field) ->
1571+
if
1572+
Utils.startsWith f.fname.txt prefix
1573+
&& (forHover || not (List.mem f.fname.txt identsSeen))
1574+
then
1575+
Some
1576+
( f.fname.txt,
1577+
Shared.typeToString (Utils.unwrapIfOption f.typ) )
1578+
else None)
1579+
|> List.map mkLabel)
1580+
in
1581+
match fromDomProps with
1582+
| Some domProps -> domProps
1583+
| None ->
1584+
(CompletionJsx.domLabels
1585+
|> List.filter (fun (name, _t) ->
1586+
Utils.startsWith name prefix
1587+
&& (forHover || not (List.mem name identsSeen)))
1588+
|> List.map mkLabel)
1589+
@ keyLabels)
15541590
| Cjsx (componentPath, prefix, identsSeen) ->
15551591
let labels =
15561592
CompletionJsx.getJsxLabels ~componentPath ~findTypeOfValue ~package

analysis/tests/src/CompletionJsx.res

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,6 @@ module CompWithoutJsxPpx = {
4848

4949
// <SomeComponent someProp=>
5050
// ^com
51+
52+
// <h1 hidd
53+
// ^com

analysis/tests/src/expected/Completion.res.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1684,6 +1684,8 @@ Completable: Cjsx([div], name, [name])
16841684
Raw opens: 2 Shadow.B.place holder ... Shadow.A.place holder
16851685
Package opens Pervasives.JsxModules.place holder
16861686
Resolved opens 3 pervasives Completion.res Completion.res
1687+
Path ReactDOM.domProps
1688+
Path Pervasives.JsxDOM.domProps
16871689
{"contents": {"kind": "markdown", "value": "```rescript\nstring\n```"}}
16881690

16891691
Hover src/Completion.res 349:17

analysis/tests/src/expected/CompletionJsx.res.txt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,3 +492,19 @@ Path SomeComponent.make
492492
"insertTextFormat": 2
493493
}]
494494

495+
Complete src/CompletionJsx.res 51:11
496+
posCursor:[51:11] posNoWhite:[51:10] Found expr:[51:4->51:11]
497+
JSX <h1:[51:4->51:6] hidd[51:7->51:11]=...[51:7->51:11]> _children:None
498+
Completable: Cjsx([h1], hidd, [hidd])
499+
Package opens Pervasives.JsxModules.place holder
500+
Resolved opens 1 pervasives
501+
Path ReactDOM.domProps
502+
Path Pervasives.JsxDOM.domProps
503+
[{
504+
"label": "hidden",
505+
"kind": 4,
506+
"tags": [],
507+
"detail": "bool",
508+
"documentation": null
509+
}]
510+

analysis/tests/src/expected/Div.res.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ JSX <div:[3:4->3:7] dangerous[3:8->3:17]=...[3:8->3:17]> _children:None
88
Completable: Cjsx([div], dangerous, [dangerous])
99
Package opens Pervasives.JsxModules.place holder
1010
Resolved opens 1 pervasives
11+
Path ReactDOM.domProps
12+
Path Pervasives.JsxDOM.domProps
1113
[{
1214
"label": "dangerouslySetInnerHTML",
1315
"kind": 4,

0 commit comments

Comments
 (0)