Skip to content

Commit 2d1742a

Browse files
authored
complete payload of @module attribute (#879)
1 parent 089ee0f commit 2d1742a

8 files changed

+140
-1
lines changed

Diff for: analysis/src/CompletionBackEnd.ml

+79
Original file line numberDiff line numberDiff line change
@@ -1516,6 +1516,8 @@ let rec completeTypedValue ~full ~prefix ~completionContext ~mode
15161516
]
15171517
| Tpromise _ -> []
15181518

1519+
module StringSet = Set.Make (String)
1520+
15191521
let rec processCompletable ~debug ~full ~scope ~env ~pos ~forHover completable =
15201522
if debug then
15211523
Printf.printf "Completable: %s\n" (Completable.toString completable);
@@ -1571,6 +1573,83 @@ let rec processCompletable ~debug ~full ~scope ~env ~pos ~forHover completable =
15711573
&& (forHover || not (List.mem name identsSeen)))
15721574
|> List.map mkLabel)
15731575
@ keyLabels
1576+
| CdecoratorPayload (Module prefix) ->
1577+
let packageJsonPath =
1578+
Utils.findPackageJson (full.package.rootPath |> Uri.fromPath)
1579+
in
1580+
let itemsFromPackageJson =
1581+
match packageJsonPath with
1582+
| None ->
1583+
if debug then
1584+
Printf.printf
1585+
"Did not find package.json, started looking (going upwards) from: %s\n"
1586+
full.package.rootPath;
1587+
[]
1588+
| Some path -> (
1589+
match Files.readFile path with
1590+
| None ->
1591+
if debug then print_endline "Could not read package.json";
1592+
[]
1593+
| Some s -> (
1594+
match Json.parse s with
1595+
| Some (Object items) ->
1596+
items
1597+
|> List.filter_map (fun (key, t) ->
1598+
match (key, t) with
1599+
| ("dependencies" | "devDependencies"), Json.Object o ->
1600+
Some
1601+
(o
1602+
|> List.filter_map (fun (pkgName, _) ->
1603+
match pkgName with
1604+
| "rescript" -> None
1605+
| pkgName -> Some pkgName))
1606+
| _ -> None)
1607+
|> List.flatten
1608+
| _ ->
1609+
if debug then print_endline "Could not parse package.json";
1610+
[]))
1611+
in
1612+
(* TODO: Resolve relatives? *)
1613+
let localItems =
1614+
try
1615+
let files =
1616+
Sys.readdir (Filename.dirname (env.file.uri |> Uri.toPath))
1617+
|> Array.to_list
1618+
in
1619+
(* Try to filter out compiled in source files *)
1620+
let resFiles =
1621+
StringSet.of_list
1622+
(files
1623+
|> List.filter_map (fun f ->
1624+
if Filename.extension f = ".res" then
1625+
Some (try Filename.chop_extension f with _ -> f)
1626+
else None))
1627+
in
1628+
files
1629+
|> List.filter_map (fun fileName ->
1630+
let withoutExtension =
1631+
try Filename.chop_extension fileName with _ -> fileName
1632+
in
1633+
if
1634+
String.ends_with fileName ~suffix:package.suffix
1635+
&& resFiles |> StringSet.mem withoutExtension
1636+
then None
1637+
else
1638+
match Filename.extension fileName with
1639+
| ".js" | ".mjs" -> Some ("./" ^ fileName)
1640+
| _ -> None)
1641+
with _ ->
1642+
if debug then print_endline "Could not read relative directory";
1643+
[]
1644+
in
1645+
let items = itemsFromPackageJson @ localItems in
1646+
items
1647+
|> List.filter (fun name -> Utils.startsWith name prefix)
1648+
|> List.map (fun name ->
1649+
let isLocal = Utils.startsWith name "./" in
1650+
Completion.create name
1651+
~kind:(Label (if isLocal then "Local file" else "Package"))
1652+
~env)
15741653
| Cdecorator prefix ->
15751654
let mkDecorator (name, docstring) =
15761655
{(Completion.create name ~kind:(Label "") ~env) with docstring}

Diff for: analysis/src/CompletionFrontEnd.ml

+15-1
Original file line numberDiff line numberDiff line change
@@ -736,7 +736,21 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor
736736
Printf.printf "Attribute id:%s:%s label:%s\n" id.txt
737737
(Loc.toString id.loc) label;
738738
setResult (Completable.Cdecorator label)
739-
| _ -> ());
739+
| _ -> ()
740+
else if id.txt = "module" then
741+
(match payload with
742+
| PStr
743+
[
744+
{
745+
pstr_desc =
746+
Pstr_eval
747+
( {pexp_loc; pexp_desc = Pexp_constant (Pconst_string (s, _))},
748+
_ );
749+
};
750+
]
751+
when locHasCursor pexp_loc ->
752+
setResult (Completable.CdecoratorPayload (Module s))
753+
| _ -> ()));
740754
Ast_iterator.default_iterator.attribute iterator (id, payload)
741755
in
742756
let rec iterateFnArguments ~args ~iterator ~isPipe

Diff for: analysis/src/Packages.ml

+6
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ let newBsPackage ~rootPath =
4747
Some
4848
(let namespace = FindFiles.getNamespace config in
4949
let rescriptVersion = getReScriptVersion () in
50+
let suffix =
51+
match config |> Json.get "suffix" with
52+
| Some (String suffix) -> suffix
53+
| _ -> ".js"
54+
in
5055
let uncurried =
5156
let ns = config |> Json.get "uncurried" in
5257
match (rescriptVersion, ns) with
@@ -115,6 +120,7 @@ let newBsPackage ~rootPath =
115120
("Opens from ReScript config file: "
116121
^ (opens |> List.map pathToString |> String.concat " "));
117122
{
123+
suffix;
118124
rescriptVersion;
119125
rootPath;
120126
projectFiles =

Diff for: analysis/src/SharedTypes.ml

+5
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,7 @@ type builtInCompletionModules = {
489489
}
490490

491491
type package = {
492+
suffix: string;
492493
rootPath: filePath;
493494
projectFiles: FileSet.t;
494495
dependenciesFiles: FileSet.t;
@@ -619,8 +620,11 @@ module Completable = struct
619620

620621
type patternMode = Default | Destructuring
621622

623+
type decoratorPayload = Module of string
624+
622625
type t =
623626
| Cdecorator of string (** e.g. @module *)
627+
| CdecoratorPayload of decoratorPayload
624628
| CnamedArg of contextPath * string * string list
625629
(** e.g. (..., "label", ["l1", "l2"]) for ...(...~l1...~l2...~label...) *)
626630
| Cnone (** e.g. don't complete inside strings *)
@@ -701,6 +705,7 @@ module Completable = struct
701705
let toString = function
702706
| Cpath cp -> "Cpath " ^ contextPathToString cp
703707
| Cdecorator s -> "Cdecorator(" ^ str s ^ ")"
708+
| CdecoratorPayload (Module s) -> "CdecoratorPayload(module=" ^ s ^ ")"
704709
| CnamedArg (cp, s, sl2) ->
705710
"CnamedArg("
706711
^ (cp |> contextPathToString)

Diff for: analysis/src/Utils.ml

+13
Original file line numberDiff line numberDiff line change
@@ -260,3 +260,16 @@ let printMaybeExoticIdent ?(allowUident = false) txt =
260260
| _ -> "\"" ^ txt ^ "\""
261261
in
262262
if Res_token.isKeywordTxt txt then "\"" ^ txt ^ "\"" else loop 0
263+
264+
let findPackageJson root =
265+
let path = Uri.toPath root in
266+
267+
let rec loop path =
268+
if path = "/" then None
269+
else if Files.exists (Filename.concat path "package.json") then
270+
Some (Filename.concat path "package.json")
271+
else
272+
let parent = Filename.dirname path in
273+
if parent = path then (* reached root *) None else loop parent
274+
in
275+
loop path

Diff for: analysis/tests/src/CompletionAttributes.res

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// @module("") external doStuff: t = "test"
2+
// ^com
3+
+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Complete src/CompletionAttributes.res 0:12
2+
XXX Not found!
3+
Completable: CdecoratorPayload(module=)
4+
Package opens Pervasives.JsxModules.place holder
5+
Resolved opens 1 pervasives
6+
[{
7+
"label": "@rescript/react",
8+
"kind": 4,
9+
"tags": [],
10+
"detail": "Package",
11+
"documentation": null
12+
}, {
13+
"label": "./tst.js",
14+
"kind": 4,
15+
"tags": [],
16+
"detail": "Local file",
17+
"documentation": null
18+
}]
19+

Diff for: analysis/tests/src/tst.js

Whitespace-only changes.

0 commit comments

Comments
 (0)