enable more than one callbacks for a watched file
This commit is contained in:
parent
56a7217241
commit
8cf1a34f70
1 changed files with 42 additions and 19 deletions
|
@ -307,15 +307,21 @@ namespace ts {
|
|||
function createWatchedFileSet() {
|
||||
const dirWatchers = createFileMap<DirWatcher>();
|
||||
const recursiveDirWatchers = createFileMap<DirWatcher>();
|
||||
const fileWatcherCallbacks = createFileMap<FileWatcherCallback>();
|
||||
const dirWatcherCallbacks = createFileMap<DirWatcherCallback>();
|
||||
// One file can have multiple watchers
|
||||
const fileWatcherCallbacks = createFileMap<FileWatcherCallback[]>();
|
||||
const dirWatcherCallbacks = createFileMap<DirWatcherCallback[]>();
|
||||
|
||||
const currentDirectory = process.cwd();
|
||||
return { addFile, removeFile, addDir };
|
||||
|
||||
function addDir(dirName: string, callback: DirWatcherCallback, recursive?: boolean) {
|
||||
const dirPath = toPath(dirName, currentDirectory, getCanonicalPath);
|
||||
dirWatcherCallbacks.set(dirPath, callback);
|
||||
if (!dirWatcherCallbacks.contains(dirPath)) {
|
||||
dirWatcherCallbacks.set(dirPath, [callback]);
|
||||
}
|
||||
else {
|
||||
dirWatcherCallbacks.get(dirPath).push(callback);
|
||||
}
|
||||
const { watcher, isRecursive } = addDirWatcher(dirPath, recursive);
|
||||
return {
|
||||
close: () => reduceDirWatcherRefCount(watcher, dirPath, isRecursive)
|
||||
|
@ -341,7 +347,8 @@ namespace ts {
|
|||
|
||||
// Node 4.0 `fs.watch` function supports the "recursive" option on both OSX and Windows
|
||||
// (ref: https://github.com/nodejs/node/pull/2649 and https://github.com/Microsoft/TypeScript/issues/4643)
|
||||
if (isNode4OrLater() && recursive === true) {
|
||||
if (isNode4OrLater() && recursive === true &&
|
||||
(process.platform === "win32" || process.platform === "darwin")) {
|
||||
if (recursiveDirWatchers.contains(dirPath)) {
|
||||
const watcher = recursiveDirWatchers.get(dirPath);
|
||||
watcher.referenceCount += 1;
|
||||
|
@ -357,12 +364,13 @@ namespace ts {
|
|||
return { watcher, isRecursive: false };
|
||||
}
|
||||
watchers = dirWatchers;
|
||||
options.recursive = false;
|
||||
}
|
||||
|
||||
const watcher: DirWatcher = _fs.watch(dirPath, options, (eventName: string, relativeFileName: string) => fileEventHandler(eventName, relativeFileName, dirPath));
|
||||
watcher.referenceCount = 1;
|
||||
watchers.set(dirPath, watcher);
|
||||
return { watcher, isRecursive: false };
|
||||
return { watcher, isRecursive: options.recursive };
|
||||
}
|
||||
|
||||
function findDirWatcherForFile(filePath: Path): { watcher: DirWatcher, watcherPath: Path, isRecursive: boolean } {
|
||||
|
@ -389,6 +397,11 @@ namespace ts {
|
|||
|
||||
function addFile(fileName: string, callback: FileWatcherCallback): WatchedFile {
|
||||
const filePath = toPath(fileName, currentDirectory, getCanonicalPath);
|
||||
|
||||
if (fileWatcherCallbacks.contains(filePath)) {
|
||||
fileWatcherCallbacks.get(filePath).push(callback);
|
||||
}
|
||||
else {
|
||||
const { watcher } = findDirWatcherForFile(filePath);
|
||||
if (!watcher) {
|
||||
addDirWatcher(getDirectoryPath(filePath));
|
||||
|
@ -396,19 +409,27 @@ namespace ts {
|
|||
else {
|
||||
watcher.referenceCount += 1;
|
||||
}
|
||||
fileWatcherCallbacks.set(filePath, callback);
|
||||
fileWatcherCallbacks.set(filePath, [callback]);
|
||||
}
|
||||
return { fileName, callback };
|
||||
}
|
||||
|
||||
function removeFile(file: WatchedFile) {
|
||||
const filePath = toPath(file.fileName, currentDirectory, getCanonicalPath);
|
||||
if (fileWatcherCallbacks.contains(filePath)) {
|
||||
const newCallbacks = copyListRemovingItem(file.callback, fileWatcherCallbacks.get(filePath));
|
||||
if (newCallbacks.length === 0) {
|
||||
fileWatcherCallbacks.remove(filePath);
|
||||
|
||||
const { watcher, watcherPath, isRecursive } = findDirWatcherForFile(filePath);
|
||||
if (watcher) {
|
||||
reduceDirWatcherRefCount(watcher, watcherPath, isRecursive);
|
||||
}
|
||||
}
|
||||
else {
|
||||
fileWatcherCallbacks.set(filePath, newCallbacks);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param watcherPath is the path from which the watcher is triggered.
|
||||
|
@ -419,15 +440,17 @@ namespace ts {
|
|||
// Directory callbacks are not set for file content changes, they are more often used for
|
||||
// adding/removing/renaming files, which corresponds to the "rename" event
|
||||
if (eventName === "rename" && dirWatcherCallbacks.contains(baseDirPath)) {
|
||||
const dirCallback = dirWatcherCallbacks.get(baseDirPath);
|
||||
for (const dirCallback of dirWatcherCallbacks.get(baseDirPath)) {
|
||||
dirCallback(filePath);
|
||||
}
|
||||
}
|
||||
if (fileWatcherCallbacks.contains(filePath)) {
|
||||
const fileCallback = fileWatcherCallbacks.get(filePath);
|
||||
for (const fileCallback of fileWatcherCallbacks.get(filePath)) {
|
||||
fileCallback(filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// REVIEW: for now this implementation uses polling.
|
||||
// The advantage of polling is that it works reliably
|
||||
|
|
Loading…
Reference in a new issue