Merge pull request #19239 from Microsoft/reduceWatchedDirectories
Do not watch root folders for failed lookup locations and effective type roots
This commit is contained in:
commit
314172a988
4 changed files with 213 additions and 76 deletions
|
@ -64,6 +64,7 @@ namespace ts {
|
|||
interface DirectoryOfFailedLookupWatch {
|
||||
dir: string;
|
||||
dirPath: Path;
|
||||
ignore?: true;
|
||||
}
|
||||
|
||||
export const maxNumberOfFilesToIterateForInvalidation = 256;
|
||||
|
@ -319,6 +320,33 @@ namespace ts {
|
|||
return endsWith(dirPath, "/node_modules");
|
||||
}
|
||||
|
||||
function isDirectoryAtleastAtLevelFromFSRoot(dirPath: Path, minLevels: number) {
|
||||
for (let searchIndex = getRootLength(dirPath); minLevels > 0; minLevels--) {
|
||||
searchIndex = dirPath.indexOf(directorySeparator, searchIndex) + 1;
|
||||
if (searchIndex === 0) {
|
||||
// Folder isnt at expected minimun levels
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function canWatchDirectory(dirPath: Path) {
|
||||
return isDirectoryAtleastAtLevelFromFSRoot(dirPath,
|
||||
// When root is "/" do not watch directories like:
|
||||
// "/", "/user", "/user/username", "/user/username/folderAtRoot"
|
||||
// When root is "c:/" do not watch directories like:
|
||||
// "c:/", "c:/folderAtRoot"
|
||||
dirPath.charCodeAt(0) === CharacterCodes.slash ? 3 : 1);
|
||||
}
|
||||
|
||||
function filterFSRootDirectoriesToWatch(watchPath: DirectoryOfFailedLookupWatch, dirPath: Path): DirectoryOfFailedLookupWatch {
|
||||
if (!canWatchDirectory(dirPath)) {
|
||||
watchPath.ignore = true;
|
||||
}
|
||||
return watchPath;
|
||||
}
|
||||
|
||||
function getDirectoryToWatchFailedLookupLocation(failedLookupLocation: string, failedLookupLocationPath: Path): DirectoryOfFailedLookupWatch {
|
||||
if (isInDirectoryPath(rootPath, failedLookupLocationPath)) {
|
||||
return { dir: rootDir, dirPath: rootPath };
|
||||
|
@ -335,7 +363,7 @@ namespace ts {
|
|||
|
||||
// If the directory is node_modules use it to watch
|
||||
if (isNodeModulesDirectory(dirPath)) {
|
||||
return { dir, dirPath };
|
||||
return filterFSRootDirectoriesToWatch({ dir, dirPath }, getDirectoryPath(dirPath));
|
||||
}
|
||||
|
||||
// Use some ancestor of the root directory
|
||||
|
@ -350,7 +378,7 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
|
||||
return { dir, dirPath };
|
||||
return filterFSRootDirectoriesToWatch({ dir, dirPath }, dirPath);
|
||||
}
|
||||
|
||||
function isPathWithDefaultFailedLookupExtension(path: Path) {
|
||||
|
@ -391,13 +419,15 @@ namespace ts {
|
|||
const refCount = customFailedLookupPaths.get(failedLookupLocationPath) || 0;
|
||||
customFailedLookupPaths.set(failedLookupLocationPath, refCount + 1);
|
||||
}
|
||||
const { dir, dirPath } = getDirectoryToWatchFailedLookupLocation(failedLookupLocation, failedLookupLocationPath);
|
||||
const dirWatcher = directoryWatchesOfFailedLookups.get(dirPath);
|
||||
if (dirWatcher) {
|
||||
dirWatcher.refCount++;
|
||||
}
|
||||
else {
|
||||
directoryWatchesOfFailedLookups.set(dirPath, { watcher: createDirectoryWatcher(dir, dirPath), refCount: 1 });
|
||||
const { dir, dirPath, ignore } = getDirectoryToWatchFailedLookupLocation(failedLookupLocation, failedLookupLocationPath);
|
||||
if (!ignore) {
|
||||
const dirWatcher = directoryWatchesOfFailedLookups.get(dirPath);
|
||||
if (dirWatcher) {
|
||||
dirWatcher.refCount++;
|
||||
}
|
||||
else {
|
||||
directoryWatchesOfFailedLookups.set(dirPath, { watcher: createDirectoryWatcher(dir, dirPath), refCount: 1 });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -422,10 +452,12 @@ namespace ts {
|
|||
customFailedLookupPaths.set(failedLookupLocationPath, refCount - 1);
|
||||
}
|
||||
}
|
||||
const { dirPath } = getDirectoryToWatchFailedLookupLocation(failedLookupLocation, failedLookupLocationPath);
|
||||
const dirWatcher = directoryWatchesOfFailedLookups.get(dirPath);
|
||||
// Do not close the watcher yet since it might be needed by other failed lookup locations.
|
||||
dirWatcher.refCount--;
|
||||
const { dirPath, ignore } = getDirectoryToWatchFailedLookupLocation(failedLookupLocation, failedLookupLocationPath);
|
||||
if (!ignore) {
|
||||
const dirWatcher = directoryWatchesOfFailedLookups.get(dirPath);
|
||||
// Do not close the watcher yet since it might be needed by other failed lookup locations.
|
||||
dirWatcher.refCount--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -577,7 +609,8 @@ namespace ts {
|
|||
}
|
||||
|
||||
// we need to assume the directories exist to ensure that we can get all the type root directories that get included
|
||||
const typeRoots = getEffectiveTypeRoots(options, { directoryExists: returnTrue, getCurrentDirectory });
|
||||
// But filter directories that are at root level to say directory doesnt exist, so that we arent watching them
|
||||
const typeRoots = getEffectiveTypeRoots(options, { directoryExists: directoryExistsForTypeRootWatch, getCurrentDirectory });
|
||||
if (typeRoots) {
|
||||
mutateMap(
|
||||
typeRootsWatches,
|
||||
|
@ -592,5 +625,16 @@ namespace ts {
|
|||
closeTypeRootsWatch();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this function to return if directory exists to get type roots to watch
|
||||
* If we return directory exists then only the paths will be added to type roots
|
||||
* Hence return true for all directories except root directories which are filtered from watching
|
||||
*/
|
||||
function directoryExistsForTypeRootWatch(nodeTypesDirectory: string) {
|
||||
const dir = getDirectoryPath(getDirectoryPath(nodeTypesDirectory));
|
||||
const dirPath = resolutionHost.toPath(dir);
|
||||
return dirPath === rootPath || canWatchDirectory(dirPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -254,7 +254,7 @@ namespace ts.tscWatch {
|
|||
checkProgramRootFiles(watch(), [file1.path, file2.path]);
|
||||
checkWatchedFiles(host, [configFile.path, file1.path, file2.path, libFile.path]);
|
||||
const configDir = getDirectoryPath(configFile.path);
|
||||
checkWatchedDirectories(host, projectSystem.getTypeRootsFromLocation(configDir).concat(configDir), /*recursive*/ true);
|
||||
checkWatchedDirectories(host, [configDir, combinePaths(configDir, projectSystem.nodeModulesAtTypes)], /*recursive*/ true);
|
||||
});
|
||||
|
||||
// TODO: if watching for config file creation
|
||||
|
@ -269,7 +269,7 @@ namespace ts.tscWatch {
|
|||
const host = createWatchedSystem([commonFile1, libFile, configFile]);
|
||||
const watch = createWatchModeWithConfigFile(configFile.path, host);
|
||||
const configDir = getDirectoryPath(configFile.path);
|
||||
checkWatchedDirectories(host, projectSystem.getTypeRootsFromLocation(configDir).concat(configDir), /*recursive*/ true);
|
||||
checkWatchedDirectories(host, [configDir, combinePaths(configDir, projectSystem.nodeModulesAtTypes)], /*recursive*/ true);
|
||||
|
||||
checkProgramRootFiles(watch(), [commonFile1.path]);
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -28,6 +28,7 @@ namespace ts.TestFSWithWatch {
|
|||
executingFilePath?: string;
|
||||
currentDirectory?: string;
|
||||
newLine?: string;
|
||||
useWindowsStylePaths?: boolean;
|
||||
}
|
||||
|
||||
export function createWatchedSystem(fileOrFolderList: ReadonlyArray<FileOrFolder>, params?: TestServerHostCreationParameters): TestServerHost {
|
||||
|
@ -39,7 +40,8 @@ namespace ts.TestFSWithWatch {
|
|||
params.executingFilePath || getExecutingFilePathFromLibFile(),
|
||||
params.currentDirectory || "/",
|
||||
fileOrFolderList,
|
||||
params.newLine);
|
||||
params.newLine,
|
||||
params.useWindowsStylePaths);
|
||||
return host;
|
||||
}
|
||||
|
||||
|
@ -52,7 +54,8 @@ namespace ts.TestFSWithWatch {
|
|||
params.executingFilePath || getExecutingFilePathFromLibFile(),
|
||||
params.currentDirectory || "/",
|
||||
fileOrFolderList,
|
||||
params.newLine);
|
||||
params.newLine,
|
||||
params.useWindowsStylePaths);
|
||||
return host;
|
||||
}
|
||||
|
||||
|
@ -230,11 +233,14 @@ namespace ts.TestFSWithWatch {
|
|||
readonly watchedDirectories = createMultiMap<TestDirectoryWatcher>();
|
||||
readonly watchedDirectoriesRecursive = createMultiMap<TestDirectoryWatcher>();
|
||||
readonly watchedFiles = createMultiMap<TestFileWatcher>();
|
||||
private readonly executingFilePath: string;
|
||||
private readonly currentDirectory: string;
|
||||
|
||||
constructor(public withSafeList: boolean, public useCaseSensitiveFileNames: boolean, private executingFilePath: string, private currentDirectory: string, fileOrFolderList: ReadonlyArray<FileOrFolder>, public readonly newLine = "\n") {
|
||||
constructor(public withSafeList: boolean, public useCaseSensitiveFileNames: boolean, executingFilePath: string, currentDirectory: string, fileOrFolderList: ReadonlyArray<FileOrFolder>, public readonly newLine = "\n", public readonly useWindowsStylePath?: boolean) {
|
||||
this.getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames);
|
||||
this.toPath = s => toPath(s, currentDirectory, this.getCanonicalFileName);
|
||||
|
||||
this.executingFilePath = this.getHostSpecificPath(executingFilePath);
|
||||
this.currentDirectory = this.getHostSpecificPath(currentDirectory);
|
||||
this.reloadFS(fileOrFolderList);
|
||||
}
|
||||
|
||||
|
@ -250,11 +256,24 @@ namespace ts.TestFSWithWatch {
|
|||
return this.toPath(this.toNormalizedAbsolutePath(s));
|
||||
}
|
||||
|
||||
getHostSpecificPath(s: string) {
|
||||
if (this.useWindowsStylePath && s.startsWith(directorySeparator)) {
|
||||
return "c:/" + s.substring(1);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
reloadFS(fileOrFolderList: ReadonlyArray<FileOrFolder>) {
|
||||
const mapNewLeaves = createMap<true>();
|
||||
const isNewFs = this.fs.size === 0;
|
||||
// always inject safelist file in the list of files
|
||||
for (const fileOrDirectory of fileOrFolderList.concat(this.withSafeList ? safeList : [])) {
|
||||
fileOrFolderList = fileOrFolderList.concat(this.withSafeList ? safeList : []);
|
||||
const filesOrFoldersToLoad: ReadonlyArray<FileOrFolder> = !this.useWindowsStylePath ? fileOrFolderList :
|
||||
fileOrFolderList.map<FileOrFolder>(f => {
|
||||
const result = clone(f);
|
||||
result.path = this.getHostSpecificPath(f.path);
|
||||
return result;
|
||||
});
|
||||
for (const fileOrDirectory of filesOrFoldersToLoad) {
|
||||
const path = this.toFullPath(fileOrDirectory.path);
|
||||
mapNewLeaves.set(path, true);
|
||||
// If its a change
|
||||
|
|
Loading…
Reference in a new issue