mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-29 16:29:19 -05:00
Instead of creating filter for subDirectories to watch in the ancestor directory of root, watch those subDirectories for failed lookup locations
Before this change, when failed lookup location didnt fall in root directory, we tried to find the ancestor directory of the rootDirectory to watch. We also created subDirectory map for the directories that are being watched so we dont go through invalidation if path is unwanted directory With this change, we will watch those subdirectories instead of root. On windows node supports file system level recursive watching so the earlier approach was better because we reduced number of watches created But on other os, since node doesnt support it, we create the watches for existing folders outselves, so earlier approach becomes expensive. This should be better compromize to satisfy both types of OS. Fixes #24434
This commit is contained in:
@@ -60,15 +60,12 @@ namespace ts {
|
||||
watcher: FileWatcher;
|
||||
/** ref count keeping this directory watch alive */
|
||||
refCount: number;
|
||||
/** map of refcount for the subDirectory */
|
||||
subDirectoryMap?: Map<number>;
|
||||
}
|
||||
|
||||
interface DirectoryOfFailedLookupWatch {
|
||||
dir: string;
|
||||
dirPath: Path;
|
||||
ignore?: true;
|
||||
subDirectory?: Path;
|
||||
}
|
||||
|
||||
export const maxNumberOfFilesToIterateForInvalidation = 256;
|
||||
@@ -403,20 +400,21 @@ namespace ts {
|
||||
}
|
||||
|
||||
// Use some ancestor of the root directory
|
||||
let subDirectory: Path | undefined;
|
||||
let subDirectoryPath: Path | undefined, subDirectory: string | undefined;
|
||||
if (rootPath !== undefined) {
|
||||
while (!isInDirectoryPath(dirPath, rootPath)) {
|
||||
const parentPath = getDirectoryPath(dirPath);
|
||||
if (parentPath === dirPath) {
|
||||
break;
|
||||
}
|
||||
subDirectory = dirPath.slice(parentPath.length + directorySeparator.length) as Path;
|
||||
subDirectoryPath = dirPath;
|
||||
subDirectory = dir;
|
||||
dirPath = parentPath;
|
||||
dir = getDirectoryPath(dir);
|
||||
}
|
||||
}
|
||||
|
||||
return filterFSRootDirectoriesToWatch({ dir, dirPath, subDirectory }, dirPath);
|
||||
return filterFSRootDirectoriesToWatch({ dir: subDirectory || dir, dirPath: subDirectoryPath || dirPath }, dirPath);
|
||||
}
|
||||
|
||||
function isPathWithDefaultFailedLookupExtension(path: Path) {
|
||||
@@ -439,7 +437,7 @@ namespace ts {
|
||||
let setAtRoot = false;
|
||||
for (const failedLookupLocation of failedLookupLocations) {
|
||||
const failedLookupLocationPath = resolutionHost.toPath(failedLookupLocation);
|
||||
const { dir, dirPath, ignore , subDirectory } = getDirectoryToWatchFailedLookupLocation(failedLookupLocation, failedLookupLocationPath);
|
||||
const { dir, dirPath, ignore } = getDirectoryToWatchFailedLookupLocation(failedLookupLocation, failedLookupLocationPath);
|
||||
if (!ignore) {
|
||||
// If the failed lookup location path is not one of the supported extensions,
|
||||
// store it in the custom path
|
||||
@@ -451,7 +449,7 @@ namespace ts {
|
||||
setAtRoot = true;
|
||||
}
|
||||
else {
|
||||
setDirectoryWatcher(dir, dirPath, subDirectory);
|
||||
setDirectoryWatcher(dir, dirPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -461,20 +459,13 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function setDirectoryWatcher(dir: string, dirPath: Path, subDirectory?: Path) {
|
||||
let dirWatcher = directoryWatchesOfFailedLookups.get(dirPath);
|
||||
function setDirectoryWatcher(dir: string, dirPath: Path) {
|
||||
const dirWatcher = directoryWatchesOfFailedLookups.get(dirPath);
|
||||
if (dirWatcher) {
|
||||
dirWatcher.refCount++;
|
||||
}
|
||||
else {
|
||||
dirWatcher = { watcher: createDirectoryWatcher(dir, dirPath), refCount: 1 };
|
||||
directoryWatchesOfFailedLookups.set(dirPath, dirWatcher);
|
||||
}
|
||||
|
||||
if (subDirectory) {
|
||||
const subDirectoryMap = dirWatcher.subDirectoryMap || (dirWatcher.subDirectoryMap = createMap());
|
||||
const existing = subDirectoryMap.get(subDirectory) || 0;
|
||||
subDirectoryMap.set(subDirectory, existing + 1);
|
||||
directoryWatchesOfFailedLookups.set(dirPath, { watcher: createDirectoryWatcher(dir, dirPath), refCount: 1 });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -492,7 +483,7 @@ namespace ts {
|
||||
let removeAtRoot = false;
|
||||
for (const failedLookupLocation of failedLookupLocations) {
|
||||
const failedLookupLocationPath = resolutionHost.toPath(failedLookupLocation);
|
||||
const { dirPath, ignore, subDirectory } = getDirectoryToWatchFailedLookupLocation(failedLookupLocation, failedLookupLocationPath);
|
||||
const { dirPath, ignore } = getDirectoryToWatchFailedLookupLocation(failedLookupLocation, failedLookupLocationPath);
|
||||
if (!ignore) {
|
||||
const refCount = customFailedLookupPaths.get(failedLookupLocationPath);
|
||||
if (refCount) {
|
||||
@@ -509,7 +500,7 @@ namespace ts {
|
||||
removeAtRoot = true;
|
||||
}
|
||||
else {
|
||||
removeDirectoryWatcher(dirPath, subDirectory);
|
||||
removeDirectoryWatcher(dirPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -518,30 +509,12 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function removeDirectoryWatcher(dirPath: string, subDirectory?: Path) {
|
||||
function removeDirectoryWatcher(dirPath: string) {
|
||||
const dirWatcher = directoryWatchesOfFailedLookups.get(dirPath)!;
|
||||
if (subDirectory) {
|
||||
const existing = dirWatcher.subDirectoryMap!.get(subDirectory)!;
|
||||
if (existing === 1) {
|
||||
dirWatcher.subDirectoryMap!.delete(subDirectory);
|
||||
}
|
||||
else {
|
||||
dirWatcher.subDirectoryMap!.set(subDirectory, existing - 1);
|
||||
}
|
||||
}
|
||||
// Do not close the watcher yet since it might be needed by other failed lookup locations.
|
||||
dirWatcher.refCount--;
|
||||
}
|
||||
|
||||
function inWatchedSubdirectory(dirPath: Path, fileOrDirectoryPath: Path) {
|
||||
const dirWatcher = directoryWatchesOfFailedLookups.get(dirPath);
|
||||
if (!dirWatcher || !dirWatcher.subDirectoryMap) return false;
|
||||
return forEachKey(dirWatcher.subDirectoryMap, subDirectory => {
|
||||
const fullSubDirectory = `${dirPath}/${subDirectory}` as Path;
|
||||
return fullSubDirectory === fileOrDirectoryPath || isInDirectoryPath(fullSubDirectory, fileOrDirectoryPath);
|
||||
});
|
||||
}
|
||||
|
||||
function createDirectoryWatcher(directory: string, dirPath: Path) {
|
||||
return resolutionHost.watchDirectoryOfFailedLookupLocation(directory, fileOrDirectory => {
|
||||
const fileOrDirectoryPath = resolutionHost.toPath(fileOrDirectory);
|
||||
@@ -550,13 +523,8 @@ namespace ts {
|
||||
cachedDirectoryStructureHost.addOrDeleteFileOrDirectory(fileOrDirectory, fileOrDirectoryPath);
|
||||
}
|
||||
|
||||
// If the files are added to project root or node_modules directory, always run through the invalidation process
|
||||
// Otherwise run through invalidation only if adding to the immediate directory
|
||||
if (!allFilesHaveInvalidatedResolution &&
|
||||
(dirPath === rootPath || isNodeModulesDirectory(dirPath) || getDirectoryPath(fileOrDirectoryPath) === dirPath || inWatchedSubdirectory(dirPath, fileOrDirectoryPath))) {
|
||||
if (invalidateResolutionOfFailedLookupLocation(fileOrDirectoryPath, dirPath === fileOrDirectoryPath)) {
|
||||
resolutionHost.onInvalidatedResolution();
|
||||
}
|
||||
if (!allFilesHaveInvalidatedResolution && invalidateResolutionOfFailedLookupLocation(fileOrDirectoryPath, dirPath === fileOrDirectoryPath)) {
|
||||
resolutionHost.onInvalidatedResolution();
|
||||
}
|
||||
}, WatchDirectoryFlags.Recursive);
|
||||
}
|
||||
|
||||
@@ -2533,7 +2533,7 @@ declare module "fs" {
|
||||
createWatchOfConfigFile("tsconfig.json", host);
|
||||
checkWatchedFilesDetailed(host, [libFile.path, mainFile.path, config.path, linkedPackageIndex.path, linkedPackageOther.path], 1);
|
||||
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
|
||||
checkWatchedDirectoriesDetailed(host, [mainPackageRoot, projectRoot, `${mainPackageRoot}/node_modules/@types`, `${projectRoot}/node_modules/@types`], 1, /*recursive*/ true);
|
||||
checkWatchedDirectoriesDetailed(host, [mainPackageRoot, linkedPackageRoot, `${mainPackageRoot}/node_modules/@types`, `${projectRoot}/node_modules/@types`], 1, /*recursive*/ true);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7839,7 +7839,7 @@ new C();`
|
||||
const filesAfterCompilation = [...filesWithNodeModulesSetup, recongnizerTextDistTypingFile];
|
||||
|
||||
const watchedDirectoriesWithResolvedModule = [`${recognizersDateTime}/src`, withPathMapping ? packages : recognizersDateTime, ...getTypeRootsFromLocation(recognizersDateTime)];
|
||||
const watchedDirectoriesWithUnresolvedModule = [recognizersDateTime, ...watchedDirectoriesWithResolvedModule, ...getNodeModuleDirectories(packages)];
|
||||
const watchedDirectoriesWithUnresolvedModule = [recognizersDateTime, ...(withPathMapping ? [recognizersText] : emptyArray), ...watchedDirectoriesWithResolvedModule, ...getNodeModuleDirectories(packages)];
|
||||
|
||||
function verifyProjectWithResolvedModule(session: TestSession) {
|
||||
const projectService = session.getProjectService();
|
||||
|
||||
Reference in New Issue
Block a user