Skip to content

Add support for prop completion for JSX V4 #579

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 9, 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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@

## master

#### :rocket: New Feature

- Add support for prop completion for JSX V4 https://github.com/rescript-lang/rescript-vscode/pull/579

## v1.6.0

#### :rocket: New Feature
Expand Down
51 changes: 43 additions & 8 deletions analysis/src/CompletionBackEnd.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1427,16 +1427,39 @@ let processCompletable ~debug ~package ~scope ~env ~pos ~forHover
| Cjsx (componentPath, prefix, identsSeen) ->
let labels =
match componentPath @ ["make"] |> findTypeOfValue with
| Some (typ, _env) ->
let rec getFields (texp : Types.type_expr) =
| Some (typ, make_env) ->
let rec getFieldsV3 (texp : Types.type_expr) =
match texp.desc with
| Tfield (name, _, t1, t2) ->
let fields = t2 |> getFields in
let fields = t2 |> getFieldsV3 in
if name = "children" then fields else (name, t1) :: fields
| Tlink te | Tsubst te | Tpoly (te, []) -> te |> getFields
| Tlink te | Tsubst te | Tpoly (te, []) -> te |> getFieldsV3
| Tvar None -> []
| _ -> []
in
let getFieldsV4 ~path ~typeArgs =
match References.digConstructor ~env:make_env ~package path with
| Some
( _env,
{
item =
{
decl =
{
type_kind = Type_record (labelDecls, _repr);
type_params = typeParams;
};
};
} ) ->
labelDecls
|> List.map (fun (ld : Types.label_declaration) ->
let name = Ident.name ld.ld_id in
let t =
ld.ld_type |> instantiateType ~typeParams ~typeArgs
in
(name, t))
| _ -> []
in
let rec getLabels (t : Types.type_expr) =
match t.desc with
| Tlink t1 | Tsubst t1 | Tpoly (t1, []) -> getLabels t1
Expand All @@ -1449,9 +1472,14 @@ let processCompletable ~debug ~package ~scope ~env ~pos ~forHover
},
_,
_ ) ->
getFields tObj
(* JSX V3 *)
getFieldsV3 tObj
| Tarrow (Nolabel, {desc = Tconstr (path, typeArgs, _)}, _, _)
when Path.last path = "props" ->
(* JSX V4 *)
getFieldsV4 ~path ~typeArgs
| Tconstr
( path,
( clPath,
[
{
desc =
Expand All @@ -1461,8 +1489,14 @@ let processCompletable ~debug ~package ~scope ~env ~pos ~forHover
_;
],
_ )
when Path.name path = "React.componentLike" ->
getFields tObj
when Path.name clPath = "React.componentLike" ->
(* JSX V3 external or interface *)
getFieldsV3 tObj
| Tconstr (clPath, [{desc = Tconstr (path, typeArgs, _)}; _], _)
when Path.name clPath = "React.componentLike"
&& Path.last path = "props" ->
(* JSX V4 external or interface *)
getFieldsV4 ~path ~typeArgs
| _ -> []
in
typ |> getLabels
Expand All @@ -1480,6 +1514,7 @@ let processCompletable ~debug ~package ~scope ~env ~pos ~forHover
(labels
|> List.filter (fun (name, _t) ->
Utils.startsWith name prefix
&& name <> "key"
&& (forHover || not (List.mem name identsSeen)))
|> List.map mkLabel)
@ keyLabels
Expand Down
12 changes: 12 additions & 0 deletions analysis/tests/src/JsxV4.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
@@jsxConfig({version: 4})

module M4 = {
@react.component
let make = (~first, ~fun="", ~second="") => React.string(first ++ fun ++ second)
}

let _ = <M4 first="abc" />
// ^def

// <M4 first="abc" f
// ^com
18 changes: 18 additions & 0 deletions analysis/tests/src/expected/JsxV4.res.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
Definition src/JsxV4.res 7:9
getLocItem #9: heuristic for JSX variadic, e.g. <C> {x} {y} </C>
heuristic for: [React.null, makeProps, make, createElementVariadic], give the loc of `make`
n1:() n2:makeProps n3:make n4:createElement
{"uri": "JsxV4.res", "range": {"start": {"line": 4, "character": 6}, "end": {"line": 4, "character": 10}}}

Complete src/JsxV4.res 10:20
posCursor:[10:20] posNoWhite:[10:19] Found expr:[10:4->10:20]
JSX <M4:[10:4->10:6] first[10:7->10:12]=...[10:13->10:18] f[10:19->10:20]=...[10:19->10:20]> _children:None
Completable: Cjsx([M4], f, [first, f])
[{
"label": "fun",
"kind": 4,
"tags": [],
"detail": "option<string>",
"documentation": null
}]