Skip to content

Commit 8c024e8

Browse files
committed
fix: emit JS for newly created files without requiring didSave
FileCreated events now also schedule a file_build (FullCompile) after the project_build. LLMs and external tools write files directly to disk without opening them in the editor, so no didSave follows — the project_build alone only runs TypecheckOnly and never emits JS.
1 parent c9d0b63 commit 8c024e8

3 files changed

Lines changed: 104 additions & 13 deletions

File tree

rewatch/src/lsp/queue.rs

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -450,8 +450,20 @@ impl PendingState {
450450
);
451451
}
452452
} else {
453-
// Genuinely new file — needs full project rebuild.
454-
self.build_projects.created_files.insert(file_path);
453+
// Genuinely new file — needs full project rebuild
454+
// plus file_build to emit JS (no didSave will follow
455+
// for files created by LLMs or external tools).
456+
self.build_projects.created_files.insert(file_path.clone());
457+
if let Ok(uri) = Url::from_file_path(&file_path) {
458+
self.compile_files.insert(
459+
uri,
460+
PendingFileBuild {
461+
file_path,
462+
buffer_content: None,
463+
generation: 0,
464+
},
465+
);
466+
}
455467
}
456468
}
457469
QueueEvent::FileDeleted { file_path } => {
@@ -826,7 +838,7 @@ mod tests {
826838
}
827839

828840
#[test]
829-
fn file_created_removes_pending_build() {
841+
fn file_created_supersedes_pending_save() {
830842
let mut state = PendingState::new();
831843
state.merge(QueueEvent::FileChangedOnDisk {
832844
uri: test_uri("A.res"),
@@ -836,7 +848,17 @@ mod tests {
836848
file_path: test_path("A.res"),
837849
});
838850

839-
assert!(state.compile_files.is_empty());
851+
// FileCreated clears the old save entry and re-adds a fresh one
852+
// (no buffer_content), plus triggers project_build.
853+
assert!(state.compile_files.contains_key(&test_uri("A.res")));
854+
assert!(
855+
state
856+
.compile_files
857+
.get(&test_uri("A.res"))
858+
.unwrap()
859+
.buffer_content
860+
.is_none()
861+
);
840862
assert!(state.build_projects.created_files.contains(&test_path("A.res")));
841863
}
842864

@@ -993,7 +1015,7 @@ mod tests {
9931015
}
9941016

9951017
#[test]
996-
fn create_without_prior_delete_not_in_compile_files() {
1018+
fn create_without_prior_delete_also_in_compile_files() {
9971019
let mut state = PendingState::new();
9981020

9991021
// Brand new file, no prior delete
@@ -1002,8 +1024,9 @@ mod tests {
10021024
});
10031025

10041026
assert!(state.build_projects.created_files.contains(&test_path("New.res")));
1005-
// Should NOT be in compile_files — it's genuinely new
1006-
assert!(state.compile_files.is_empty());
1027+
// Also in compile_files — LLMs and external tools won't send
1028+
// didSave, so file_build must emit JS after project_build.
1029+
assert!(state.compile_files.contains_key(&test_uri("New.res")));
10071030
}
10081031

10091032
#[test]

tests/rewatch_tests/tests/lsp/__snapshots__/did-change-watched-files.test.mjs.snap

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ exports[`lsp didChangeWatchedFiles > clears diagnostics for a deleted file after
279279
" build.typecheck_wave[file_count=1]",
280280
" build.typecheck_file[module=Root, package=rewatch-test-fixture]",
281281
" lsp.did_change_watched_files[file_count=1]",
282-
" lsp.flush[project_builds=created: src/Temporary.res]",
282+
" lsp.flush[project_builds=created: src/Temporary.res, incremental_builds=src/Temporary.res]",
283283
" lsp.flush.project_build[project=rewatch-test-fixture]",
284284
" build.load_package_sources[package=@rewatch-test/app]",
285285
" build.load_package_sources[package=@rewatch-test/library]",
@@ -293,6 +293,20 @@ exports[`lsp didChangeWatchedFiles > clears diagnostics for a deleted file after
293293
" build.typecheck_wave[file_count=1]",
294294
" build.typecheck_file[module=Temporary, package=rewatch-test-fixture]",
295295
" build.compile_error",
296+
" lsp.flush.file_build.batch[modules=["Temporary"], error_count=1]",
297+
" lsp.flush.file_build.compile_dependencies[error_count=1]",
298+
" build.parse[dirty_modules=1]",
299+
" build.parse_file[module=Temporary, package=rewatch-test-fixture]",
300+
" compile_dependencies[module_count=5, output=lsp]",
301+
" build.compile",
302+
" build.compile_wave[file_count=1]",
303+
" build.compile_file[module=Temporary, package=rewatch-test-fixture, suffix=.mjs, module_system=esmodule]",
304+
" build.compile_error",
305+
" lsp.flush.file_build.typecheck_dependents[dependent_count=0]",
306+
" typecheck_dependents[module_count=5, output=lsp]",
307+
" build.typecheck",
308+
" build.typecheck_wave[file_count=0]",
309+
" lsp.flush.file_build.compile_resolved",
296310
" lsp.did_change_watched_files[file_count=1]",
297311
" lsp.flush[project_builds=deleted: src/Temporary.res]",
298312
" lsp.flush.project_build[project=rewatch-test-fixture]",
@@ -587,7 +601,7 @@ exports[`lsp didChangeWatchedFiles > deleting a .res file also removes its .resi
587601
" build.typecheck_wave[file_count=1]",
588602
" build.typecheck_file[module=Root, package=rewatch-test-fixture]",
589603
" lsp.did_change_watched_files[file_count=2]",
590-
" lsp.flush[project_builds=created: src/Foo.res, src/Foo.resi]",
604+
" lsp.flush[project_builds=created: src/Foo.res, src/Foo.resi, incremental_builds=src/Foo.res, src/Foo.resi]",
591605
" lsp.flush.project_build[project=rewatch-test-fixture]",
592606
" build.load_package_sources[package=@rewatch-test/app]",
593607
" build.load_package_sources[package=@rewatch-test/library]",
@@ -601,6 +615,20 @@ exports[`lsp didChangeWatchedFiles > deleting a .res file also removes its .resi
601615
" build.typecheck",
602616
" build.typecheck_wave[file_count=1]",
603617
" build.typecheck_file[module=Foo, package=rewatch-test-fixture]",
618+
" lsp.flush.file_build.batch[modules=["Foo", "Foo"]]",
619+
" lsp.flush.file_build.compile_dependencies",
620+
" build.parse[dirty_modules=1]",
621+
" build.parse_file[module=Foo, package=rewatch-test-fixture]",
622+
" build.parse_file[module=Foo, package=rewatch-test-fixture]",
623+
" compile_dependencies[module_count=5, output=lsp]",
624+
" build.compile",
625+
" build.compile_wave[file_count=1]",
626+
" build.compile_file[module=Foo, package=rewatch-test-fixture, suffix=.mjs, module_system=esmodule]",
627+
" lsp.flush.file_build.typecheck_dependents[dependent_count=0]",
628+
" typecheck_dependents[module_count=5, output=lsp]",
629+
" build.typecheck",
630+
" build.typecheck_wave[file_count=0]",
631+
" lsp.flush.file_build.compile_resolved",
604632
" lsp.did_change_watched_files[file_count=1]",
605633
" lsp.flush[incremental_builds=src/Foo.res]",
606634
" lsp.flush.file_build.batch[modules=["Foo"]]",
@@ -911,7 +939,7 @@ exports[`lsp didChangeWatchedFiles > deleting a .resi file does not remove the .
911939
" build.typecheck_wave[file_count=1]",
912940
" build.typecheck_file[module=Root, package=rewatch-test-fixture]",
913941
" lsp.did_change_watched_files[file_count=2]",
914-
" lsp.flush[project_builds=created: src/Bar.res, src/Bar.resi]",
942+
" lsp.flush[project_builds=created: src/Bar.res, src/Bar.resi, incremental_builds=src/Bar.res, src/Bar.resi]",
915943
" lsp.flush.project_build[project=rewatch-test-fixture]",
916944
" build.load_package_sources[package=@rewatch-test/app]",
917945
" build.load_package_sources[package=@rewatch-test/library]",
@@ -925,6 +953,20 @@ exports[`lsp didChangeWatchedFiles > deleting a .resi file does not remove the .
925953
" build.typecheck",
926954
" build.typecheck_wave[file_count=1]",
927955
" build.typecheck_file[module=Bar, package=rewatch-test-fixture]",
956+
" lsp.flush.file_build.batch[modules=["Bar", "Bar"]]",
957+
" lsp.flush.file_build.compile_dependencies",
958+
" build.parse[dirty_modules=1]",
959+
" build.parse_file[module=Bar, package=rewatch-test-fixture]",
960+
" build.parse_file[module=Bar, package=rewatch-test-fixture]",
961+
" compile_dependencies[module_count=5, output=lsp]",
962+
" build.compile",
963+
" build.compile_wave[file_count=1]",
964+
" build.compile_file[module=Bar, package=rewatch-test-fixture, suffix=.mjs, module_system=esmodule]",
965+
" lsp.flush.file_build.typecheck_dependents[dependent_count=0]",
966+
" typecheck_dependents[module_count=5, output=lsp]",
967+
" build.typecheck",
968+
" build.typecheck_wave[file_count=0]",
969+
" lsp.flush.file_build.compile_resolved",
928970
" lsp.did_change_watched_files[file_count=1]",
929971
" lsp.flush[project_builds=deleted: src/Bar.resi]",
930972
" lsp.flush.project_build[project=rewatch-test-fixture]",
@@ -1221,7 +1263,7 @@ exports[`lsp didChangeWatchedFiles > picks up a newly created file after a Creat
12211263
" build.typecheck_wave[file_count=1]",
12221264
" build.typecheck_file[module=Root, package=rewatch-test-fixture]",
12231265
" lsp.did_change_watched_files[file_count=1]",
1224-
" lsp.flush[project_builds=created: src/NewModule.res]",
1266+
" lsp.flush[project_builds=created: src/NewModule.res, incremental_builds=src/NewModule.res]",
12251267
" lsp.flush.project_build[project=rewatch-test-fixture]",
12261268
" build.load_package_sources[package=@rewatch-test/app]",
12271269
" build.load_package_sources[package=@rewatch-test/library]",
@@ -1235,6 +1277,20 @@ exports[`lsp didChangeWatchedFiles > picks up a newly created file after a Creat
12351277
" build.typecheck_wave[file_count=1]",
12361278
" build.typecheck_file[module=NewModule, package=rewatch-test-fixture]",
12371279
" build.compile_error",
1280+
" lsp.flush.file_build.batch[modules=["NewModule"], error_count=1]",
1281+
" lsp.flush.file_build.compile_dependencies[error_count=1]",
1282+
" build.parse[dirty_modules=1]",
1283+
" build.parse_file[module=NewModule, package=rewatch-test-fixture]",
1284+
" compile_dependencies[module_count=5, output=lsp]",
1285+
" build.compile",
1286+
" build.compile_wave[file_count=1]",
1287+
" build.compile_file[module=NewModule, package=rewatch-test-fixture, suffix=.mjs, module_system=esmodule]",
1288+
" build.compile_error",
1289+
" lsp.flush.file_build.typecheck_dependents[dependent_count=0]",
1290+
" typecheck_dependents[module_count=5, output=lsp]",
1291+
" build.typecheck",
1292+
" build.typecheck_wave[file_count=0]",
1293+
" lsp.flush.file_build.compile_resolved",
12381294
]
12391295
`;
12401296

tests/rewatch_tests/tests/lsp/__snapshots__/did-save.test.mjs.snap

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -591,7 +591,7 @@ exports[`lsp didSave > compiles correctly when saving a file that uses a newly c
591591
" build.typecheck_wave[file_count=1]",
592592
" build.typecheck_file[module=Root, package=rewatch-test-fixture]",
593593
" lsp.did_change_watched_files[file_count=1]",
594-
" lsp.flush[project_builds=created: src/MathHelper.res]",
594+
" lsp.flush[project_builds=created: src/MathHelper.res, incremental_builds=src/MathHelper.res]",
595595
" lsp.flush.project_build[project=rewatch-test-fixture]",
596596
" build.load_package_sources[package=@rewatch-test/app]",
597597
" build.load_package_sources[package=@rewatch-test/library]",
@@ -604,6 +604,19 @@ exports[`lsp didSave > compiles correctly when saving a file that uses a newly c
604604
" build.typecheck",
605605
" build.typecheck_wave[file_count=1]",
606606
" build.typecheck_file[module=MathHelper, package=rewatch-test-fixture]",
607+
" lsp.flush.file_build.batch[modules=["MathHelper"]]",
608+
" lsp.flush.file_build.compile_dependencies",
609+
" build.parse[dirty_modules=1]",
610+
" build.parse_file[module=MathHelper, package=rewatch-test-fixture]",
611+
" compile_dependencies[module_count=5, output=lsp]",
612+
" build.compile",
613+
" build.compile_wave[file_count=1]",
614+
" build.compile_file[module=MathHelper, package=rewatch-test-fixture, suffix=.mjs, module_system=esmodule]",
615+
" lsp.flush.file_build.typecheck_dependents[dependent_count=0]",
616+
" typecheck_dependents[module_count=5, output=lsp]",
617+
" build.typecheck",
618+
" build.typecheck_wave[file_count=0]",
619+
" lsp.flush.file_build.compile_resolved",
607620
" lsp.did_save[file=src/Root.res]",
608621
" lsp.flush[incremental_builds=src/Root.res]",
609622
" lsp.flush.file_build.batch[modules=["Root"]]",
@@ -613,7 +626,6 @@ exports[`lsp didSave > compiles correctly when saving a file that uses a newly c
613626
" compile_dependencies[module_count=5, output=lsp]",
614627
" build.compile",
615628
" build.compile_wave[file_count=1]",
616-
" build.compile_file[module=MathHelper, package=rewatch-test-fixture, suffix=.mjs, module_system=esmodule]",
617629
" build.compile_wave[file_count=1]",
618630
" build.compile_file[module=Root, package=rewatch-test-fixture, suffix=.mjs, module_system=esmodule]",
619631
" lsp.flush.file_build.typecheck_dependents[dependent_count=0]",

0 commit comments

Comments
 (0)