Skip to content

Commit 8cf1a34

Browse files
author
Zhengbo Li
committed
enable more than one callbacks for a watched file
1 parent 56a7217 commit 8cf1a34

1 file changed

Lines changed: 42 additions & 19 deletions

File tree

src/compiler/sys.ts

Lines changed: 42 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -307,15 +307,21 @@ namespace ts {
307307
function createWatchedFileSet() {
308308
const dirWatchers = createFileMap<DirWatcher>();
309309
const recursiveDirWatchers = createFileMap<DirWatcher>();
310-
const fileWatcherCallbacks = createFileMap<FileWatcherCallback>();
311-
const dirWatcherCallbacks = createFileMap<DirWatcherCallback>();
310+
// One file can have multiple watchers
311+
const fileWatcherCallbacks = createFileMap<FileWatcherCallback[]>();
312+
const dirWatcherCallbacks = createFileMap<DirWatcherCallback[]>();
312313

313314
const currentDirectory = process.cwd();
314315
return { addFile, removeFile, addDir };
315316

316317
function addDir(dirName: string, callback: DirWatcherCallback, recursive?: boolean) {
317318
const dirPath = toPath(dirName, currentDirectory, getCanonicalPath);
318-
dirWatcherCallbacks.set(dirPath, callback);
319+
if (!dirWatcherCallbacks.contains(dirPath)) {
320+
dirWatcherCallbacks.set(dirPath, [callback]);
321+
}
322+
else {
323+
dirWatcherCallbacks.get(dirPath).push(callback);
324+
}
319325
const { watcher, isRecursive } = addDirWatcher(dirPath, recursive);
320326
return {
321327
close: () => reduceDirWatcherRefCount(watcher, dirPath, isRecursive)
@@ -341,7 +347,8 @@ namespace ts {
341347

342348
// Node 4.0 `fs.watch` function supports the "recursive" option on both OSX and Windows
343349
// (ref: https://github.com/nodejs/node/pull/2649 and https://github.com/Microsoft/TypeScript/issues/4643)
344-
if (isNode4OrLater() && recursive === true) {
350+
if (isNode4OrLater() && recursive === true &&
351+
(process.platform === "win32" || process.platform === "darwin")) {
345352
if (recursiveDirWatchers.contains(dirPath)) {
346353
const watcher = recursiveDirWatchers.get(dirPath);
347354
watcher.referenceCount += 1;
@@ -357,12 +364,13 @@ namespace ts {
357364
return { watcher, isRecursive: false };
358365
}
359366
watchers = dirWatchers;
367+
options.recursive = false;
360368
}
361369

362370
const watcher: DirWatcher = _fs.watch(dirPath, options, (eventName: string, relativeFileName: string) => fileEventHandler(eventName, relativeFileName, dirPath));
363371
watcher.referenceCount = 1;
364372
watchers.set(dirPath, watcher);
365-
return { watcher, isRecursive: false };
373+
return { watcher, isRecursive: options.recursive };
366374
}
367375

368376
function findDirWatcherForFile(filePath: Path): { watcher: DirWatcher, watcherPath: Path, isRecursive: boolean } {
@@ -389,24 +397,37 @@ namespace ts {
389397

390398
function addFile(fileName: string, callback: FileWatcherCallback): WatchedFile {
391399
const filePath = toPath(fileName, currentDirectory, getCanonicalPath);
392-
const { watcher } = findDirWatcherForFile(filePath);
393-
if (!watcher) {
394-
addDirWatcher(getDirectoryPath(filePath));
400+
401+
if (fileWatcherCallbacks.contains(filePath)) {
402+
fileWatcherCallbacks.get(filePath).push(callback);
395403
}
396404
else {
397-
watcher.referenceCount += 1;
405+
const { watcher } = findDirWatcherForFile(filePath);
406+
if (!watcher) {
407+
addDirWatcher(getDirectoryPath(filePath));
408+
}
409+
else {
410+
watcher.referenceCount += 1;
411+
}
412+
fileWatcherCallbacks.set(filePath, [callback]);
398413
}
399-
fileWatcherCallbacks.set(filePath, callback);
400414
return { fileName, callback };
401415
}
402416

403417
function removeFile(file: WatchedFile) {
404418
const filePath = toPath(file.fileName, currentDirectory, getCanonicalPath);
405-
fileWatcherCallbacks.remove(filePath);
406-
407-
const { watcher, watcherPath, isRecursive } = findDirWatcherForFile(filePath);
408-
if (watcher) {
409-
reduceDirWatcherRefCount(watcher, watcherPath, isRecursive);
419+
if (fileWatcherCallbacks.contains(filePath)) {
420+
const newCallbacks = copyListRemovingItem(file.callback, fileWatcherCallbacks.get(filePath));
421+
if (newCallbacks.length === 0) {
422+
fileWatcherCallbacks.remove(filePath);
423+
const { watcher, watcherPath, isRecursive } = findDirWatcherForFile(filePath);
424+
if (watcher) {
425+
reduceDirWatcherRefCount(watcher, watcherPath, isRecursive);
426+
}
427+
}
428+
else {
429+
fileWatcherCallbacks.set(filePath, newCallbacks);
430+
}
410431
}
411432
}
412433

@@ -419,12 +440,14 @@ namespace ts {
419440
// Directory callbacks are not set for file content changes, they are more often used for
420441
// adding/removing/renaming files, which corresponds to the "rename" event
421442
if (eventName === "rename" && dirWatcherCallbacks.contains(baseDirPath)) {
422-
const dirCallback = dirWatcherCallbacks.get(baseDirPath);
423-
dirCallback(filePath);
443+
for (const dirCallback of dirWatcherCallbacks.get(baseDirPath)) {
444+
dirCallback(filePath);
445+
}
424446
}
425447
if (fileWatcherCallbacks.contains(filePath)) {
426-
const fileCallback = fileWatcherCallbacks.get(filePath);
427-
fileCallback(filePath);
448+
for (const fileCallback of fileWatcherCallbacks.get(filePath)) {
449+
fileCallback(filePath);
450+
}
428451
}
429452
}
430453
}

0 commit comments

Comments
 (0)