Skip to content

Commit 0f179b8

Browse files
committed
Add rescript sync CLI command
Implements `rescript sync` which typechecks the project and writes module/type/value information to rescript.db for LLM agent queries. - rewatch/src/llm_index.rs: typecheck build, single analysis binary invocation via { "packages": [...] } wrapper, SQLite writer with normalized schema (types/fields/constructors/values/aliases) - analysis/src/LlmIndex.ml: process multiple package entries, remove namespace field from input format - Shared build_paths_for_module/build_file_sets/build_opens from lsp/analysis.rs (made pub(crate), parameterized OutputTarget) - Snapshot + integration tests in tests/rewatch_tests
1 parent 3834a65 commit 0f179b8

File tree

12 files changed

+915
-113
lines changed

12 files changed

+915
-113
lines changed

LLM_INDEX.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,6 @@ rescript build
190190
cat <<'EOF' | rescript-editor-analysis.exe rewatch llmIndex
191191
{
192192
"rootPath": "/path/to/your/rescript-project",
193-
"namespace": null,
194193
"suffix": ".mjs",
195194
"rescriptVersion": [13, 0],
196195
"genericJsxModule": null,
@@ -216,7 +215,6 @@ EOF
216215
cat <<'EOF' | /Users/nojaf/Projects/rescript/packages/@rescript/darwin-arm64/bin/rescript-editor-analysis.exe rewatch llmIndex
217216
{
218217
"rootPath": "/Users/nojaf/Projects/relocation",
219-
"namespace": null,
220218
"suffix": ".res.mjs",
221219
"rescriptVersion": [13, 0],
222220
"genericJsxModule": null,

analysis/src/LlmIndex.ml

Lines changed: 81 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -243,97 +243,94 @@ let parseOpens json =
243243
| _ -> None)
244244
| _ -> []
245245

246+
(** Process a single package entry from the stdin JSON. *)
247+
let processPackageEntry json =
248+
let rootPath = getString "rootPath" json in
249+
let suffix =
250+
match Json.get "suffix" json with
251+
| Some (Json.String s) -> s
252+
| _ -> ".js"
253+
in
254+
let rescriptVersion =
255+
match Json.get "rescriptVersion" json with
256+
| Some (Json.Array [Json.Number major; Json.Number minor]) ->
257+
(int_of_float major, int_of_float minor)
258+
| _ -> (13, 0)
259+
in
260+
let genericJsxModule =
261+
match Json.get "genericJsxModule" json with
262+
| Some (Json.String s) -> Some s
263+
| _ -> None
264+
in
265+
let opens = parseOpens (Json.get "opens" json) in
266+
let pathsForModule =
267+
match Json.get "pathsForModule" json with
268+
| Some obj -> parsePathsForModule obj
269+
| None -> Hashtbl.create 0
270+
in
271+
let projectFiles = parseFileSet (Json.get "projectFiles" json) in
272+
let dependenciesFiles = parseFileSet (Json.get "dependenciesFiles" json) in
273+
let package : SharedTypes.package =
274+
{
275+
genericJsxModule;
276+
suffix;
277+
rootPath;
278+
projectFiles;
279+
dependenciesFiles;
280+
pathsForModule;
281+
namespace = None;
282+
opens;
283+
rescriptVersion;
284+
autocomplete = Misc.StringMap.empty;
285+
}
286+
in
287+
let files =
288+
match Json.get "files" json with
289+
| Some (Json.Array items) ->
290+
items
291+
|> List.filter_map (fun item ->
292+
let moduleName = getString "moduleName" item in
293+
let cmt = getString "cmt" item in
294+
let cmti = getString "cmti" item in
295+
let path =
296+
if cmti <> "" then cmti else if cmt <> "" then cmt else ""
297+
in
298+
if moduleName <> "" && path <> "" then Some (moduleName, path)
299+
else None)
300+
| _ -> []
301+
in
302+
files
303+
|> List.filter_map (fun (moduleName, path) ->
304+
match Cmt.loadFullCmtWithPackage ~path ~package with
305+
| None ->
306+
prerr_endline ("llmIndex: failed to load cmt for " ^ path);
307+
None
308+
| Some full ->
309+
let sourceFilePath =
310+
match Hashtbl.find_opt package.pathsForModule moduleName with
311+
| Some paths ->
312+
let srcPath = sourcePathFromPaths paths in
313+
Files.relpath rootPath srcPath
314+
|> Files.split Filename.dir_sep
315+
|> String.concat "/"
316+
| None -> path
317+
in
318+
let moduleJson =
319+
extractModuleForIndex ~rootPath ~sourceFilePath full.file.structure
320+
in
321+
Some moduleJson)
322+
246323
let command () =
247324
let input = In_channel.input_all In_channel.stdin in
248325
match Json.parse input with
249326
| None ->
250327
prerr_endline "llmIndex: failed to parse JSON from stdin";
251328
print_endline "[]"
252329
| Some json ->
253-
(* Build the package from the context (same fields as rewatch context) *)
254-
let rootPath = getString "rootPath" json in
255-
let namespace =
256-
match Json.get "namespace" json with
257-
| Some (Json.String s) -> Some s
258-
| _ -> None
259-
in
260-
let suffix =
261-
match Json.get "suffix" json with
262-
| Some (Json.String s) -> s
263-
| _ -> ".js"
264-
in
265-
let rescriptVersion =
266-
match Json.get "rescriptVersion" json with
267-
| Some (Json.Array [Json.Number major; Json.Number minor]) ->
268-
(int_of_float major, int_of_float minor)
269-
| _ -> (13, 0)
270-
in
271-
let genericJsxModule =
272-
match Json.get "genericJsxModule" json with
273-
| Some (Json.String s) -> Some s
274-
| _ -> None
275-
in
276-
let opens = parseOpens (Json.get "opens" json) in
277-
let pathsForModule =
278-
match Json.get "pathsForModule" json with
279-
| Some obj -> parsePathsForModule obj
280-
| None -> Hashtbl.create 0
281-
in
282-
let projectFiles = parseFileSet (Json.get "projectFiles" json) in
283-
let dependenciesFiles = parseFileSet (Json.get "dependenciesFiles" json) in
284-
let package : SharedTypes.package =
285-
{
286-
genericJsxModule;
287-
suffix;
288-
rootPath;
289-
projectFiles;
290-
dependenciesFiles;
291-
pathsForModule;
292-
namespace;
293-
opens;
294-
rescriptVersion;
295-
autocomplete = Misc.StringMap.empty;
296-
}
297-
in
298-
(* Parse the files array *)
299-
let files =
300-
match Json.get "files" json with
301-
| Some (Json.Array items) ->
302-
items
303-
|> List.filter_map (fun item ->
304-
let moduleName = getString "moduleName" item in
305-
let cmt = getString "cmt" item in
306-
let cmti = getString "cmti" item in
307-
let path =
308-
if cmti <> "" then cmti else if cmt <> "" then cmt else ""
309-
in
310-
if moduleName <> "" && path <> "" then Some (moduleName, path)
311-
else None)
330+
let packageEntries =
331+
match Json.get "packages" json with
332+
| Some (Json.Array items) -> items
312333
| _ -> []
313334
in
314-
(* Process each file *)
315-
let results =
316-
files
317-
|> List.filter_map (fun (moduleName, path) ->
318-
match Cmt.loadFullCmtWithPackage ~path ~package with
319-
| None ->
320-
prerr_endline ("llmIndex: failed to load cmt for " ^ path);
321-
None
322-
| Some full ->
323-
(* Resolve source file path from pathsForModule *)
324-
let sourceFilePath =
325-
match Hashtbl.find_opt package.pathsForModule moduleName with
326-
| Some paths ->
327-
let srcPath = sourcePathFromPaths paths in
328-
Files.relpath rootPath srcPath
329-
|> Files.split Filename.dir_sep
330-
|> String.concat "/"
331-
| None -> path
332-
in
333-
let moduleJson =
334-
extractModuleForIndex ~rootPath ~sourceFilePath
335-
full.file.structure
336-
in
337-
Some moduleJson)
338-
in
335+
let results = packageEntries |> List.concat_map processPackageEntry in
339336
print_endline (Protocol.array results)

rewatch/Cargo.lock

Lines changed: 62 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rewatch/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ serde_json = { version = "1.0.93" }
2727
serde_ignored = "0.1.11"
2828
serde_path_to_error = "0.1.16"
2929
sysinfo = "0.29.10"
30+
rusqlite = { version = "0.31", features = ["bundled"] }
3031
tempfile = "3.10.1"
3132

3233
# OpenTelemetry for tracing

rewatch/src/cli.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,11 @@ pub enum Command {
418418
},
419419
/// Start the language server (communicates over stdio)
420420
Lsp,
421+
/// Build the project (typecheck) and write rescript.db
422+
Sync {
423+
#[command(flatten)]
424+
folder: FolderArg,
425+
},
421426
}
422427

423428
impl Deref for FolderArg {

rewatch/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ pub mod cmd;
44
pub mod config;
55
pub mod format;
66
pub mod helpers;
7+
pub mod llm_index;
78
pub mod lock;
89
pub mod lsp;
910
pub mod project_context;

0 commit comments

Comments
 (0)