Skip to content

Commit d4788f5

Browse files
authored
Merge pull request microsoft#22520 from Microsoft/betterDelete
Do not send first missing file event as well, Do not close typing installers watches just to recreate them
2 parents 984aaa3 + e48ed3f commit d4788f5

File tree

2 files changed

+45
-25
lines changed

2 files changed

+45
-25
lines changed

src/compiler/sys.ts

+5-4
Original file line numberDiff line numberDiff line change
@@ -752,16 +752,17 @@ namespace ts {
752752
};
753753

754754
function fileChanged(curr: any, prev: any) {
755+
// previous event kind check is to ensure we recongnize the file as previously also missing when it is restored or renamed twice (that is it disappears and reappears)
756+
// In such case, prevTime returned is same as prev time of event when file was deleted as per node documentation
757+
const isPreviouslyDeleted = +prev.mtime === 0 || eventKind === FileWatcherEventKind.Deleted;
755758
if (+curr.mtime === 0) {
756-
if (eventKind === FileWatcherEventKind.Deleted) {
759+
if (isPreviouslyDeleted) {
757760
// Already deleted file, no need to callback again
758761
return;
759762
}
760763
eventKind = FileWatcherEventKind.Deleted;
761764
}
762-
// previous event kind check is to ensure we send created event when file is restored or renamed twice (that is it disappears and reappears)
763-
// since in that case the prevTime returned is same as prev time of event when file was deleted as per node documentation
764-
else if (+prev.mtime === 0 || eventKind === FileWatcherEventKind.Deleted) {
765+
else if (isPreviouslyDeleted) {
765766
eventKind = FileWatcherEventKind.Created;
766767
}
767768
// If there is no change in modified time, ignore the event

src/server/typingsInstaller/typingsInstaller.ts

+40-21
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ namespace ts.server.typingsInstaller {
4343
private readonly packageNameToTypingLocation: Map<JsTyping.CachedTyping> = createMap<JsTyping.CachedTyping>();
4444
private readonly missingTypingsSet: Map<true> = createMap<true>();
4545
private readonly knownCachesSet: Map<true> = createMap<true>();
46-
private readonly projectWatchers: Map<FileWatcher[]> = createMap<FileWatcher[]>();
46+
private readonly projectWatchers = createMap<Map<FileWatcher>>();
4747
private safeList: JsTyping.SafeList | undefined;
4848
readonly pendingRunRequests: PendingRequest[] = [];
4949

@@ -80,10 +80,7 @@ namespace ts.server.typingsInstaller {
8080
}
8181
return;
8282
}
83-
for (const w of watchers) {
84-
w.close();
85-
}
86-
83+
clearMap(watchers, closeFileWatcher);
8784
this.projectWatchers.delete(projectName);
8885

8986
if (this.log.isEnabled()) {
@@ -345,27 +342,49 @@ namespace ts.server.typingsInstaller {
345342

346343
private watchFiles(projectName: string, files: string[]) {
347344
if (!files.length) {
345+
// shut down existing watchers
346+
this.closeWatchers(projectName);
348347
return;
349348
}
350-
// shut down existing watchers
351-
this.closeWatchers(projectName);
349+
350+
let watchers = this.projectWatchers.get(projectName);
351+
if (!watchers) {
352+
watchers = createMap();
353+
this.projectWatchers.set(projectName, watchers);
354+
}
352355

353356
// handler should be invoked once for the entire set of files since it will trigger full rediscovery of typings
354357
let isInvoked = false;
355-
const watchers: FileWatcher[] = [];
356-
for (const file of files) {
357-
const w = this.installTypingHost.watchFile(file, f => {
358-
if (this.log.isEnabled()) {
359-
this.log.writeLine(`Got FS notification for ${f}, handler is already invoked '${isInvoked}'`);
360-
}
361-
if (!isInvoked) {
362-
this.sendResponse({ projectName, kind: ActionInvalidate });
363-
isInvoked = true;
364-
}
365-
}, /*pollingInterval*/ 2000);
366-
watchers.push(w);
367-
}
368-
this.projectWatchers.set(projectName, watchers);
358+
const isLoggingEnabled = this.log.isEnabled();
359+
mutateMap(
360+
watchers,
361+
arrayToSet(files),
362+
{
363+
// Watch the missing files
364+
createNewValue: file => {
365+
if (isLoggingEnabled) {
366+
this.log.writeLine(`FileWatcher:: Added:: WatchInfo: ${file}`);
367+
}
368+
const watcher = this.installTypingHost.watchFile(file, (f, eventKind) => {
369+
if (isLoggingEnabled) {
370+
this.log.writeLine(`FileWatcher:: Triggered with ${f} eventKind: ${FileWatcherEventKind[eventKind]}:: WatchInfo: ${file}:: handler is already invoked '${isInvoked}'`);
371+
}
372+
if (!isInvoked) {
373+
this.sendResponse({ projectName, kind: ActionInvalidate });
374+
isInvoked = true;
375+
}
376+
}, /*pollingInterval*/ 2000);
377+
return isLoggingEnabled ? {
378+
close: () => {
379+
this.log.writeLine(`FileWatcher:: Closed:: WatchInfo: ${file}`);
380+
}
381+
} : watcher;
382+
},
383+
// Files that are no longer missing (e.g. because they are no longer required)
384+
// should no longer be watched.
385+
onDeleteValue: closeFileWatcher
386+
}
387+
);
369388
}
370389

371390
private createSetTypings(request: DiscoverTypings, typings: string[]): SetTypings {

0 commit comments

Comments
 (0)