Add support to update module resolutions on watches from mono repo like setup with path mapping

Fixes #22349
This commit is contained in:
Sheetal Nandi 2018-05-04 15:38:26 -07:00
parent 528bf84a7a
commit 1a2fda0f56
2 changed files with 54 additions and 12 deletions

View File

@ -59,12 +59,15 @@ 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;
@ -393,18 +396,20 @@ namespace ts {
}
// Use some ancestor of the root directory
let subDirectory: Path | 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;
dirPath = parentPath;
dir = getDirectoryPath(dir);
}
}
return filterFSRootDirectoriesToWatch({ dir, dirPath }, dirPath);
return filterFSRootDirectoriesToWatch({ dir, dirPath, subDirectory }, dirPath);
}
function isPathWithDefaultFailedLookupExtension(path: Path) {
@ -427,7 +432,7 @@ namespace ts {
let setAtRoot = false;
for (const failedLookupLocation of failedLookupLocations) {
const failedLookupLocationPath = resolutionHost.toPath(failedLookupLocation);
const { dir, dirPath, ignore } = getDirectoryToWatchFailedLookupLocation(failedLookupLocation, failedLookupLocationPath);
const { dir, dirPath, ignore , subDirectory } = getDirectoryToWatchFailedLookupLocation(failedLookupLocation, failedLookupLocationPath);
if (!ignore) {
// If the failed lookup location path is not one of the supported extensions,
// store it in the custom path
@ -439,7 +444,7 @@ namespace ts {
setAtRoot = true;
}
else {
setDirectoryWatcher(dir, dirPath);
setDirectoryWatcher(dir, dirPath, subDirectory);
}
}
}
@ -449,13 +454,20 @@ namespace ts {
}
}
function setDirectoryWatcher(dir: string, dirPath: Path) {
const dirWatcher = directoryWatchesOfFailedLookups.get(dirPath);
function setDirectoryWatcher(dir: string, dirPath: Path, subDirectory?: Path) {
let dirWatcher = directoryWatchesOfFailedLookups.get(dirPath);
if (dirWatcher) {
dirWatcher.refCount++;
}
else {
directoryWatchesOfFailedLookups.set(dirPath, { watcher: createDirectoryWatcher(dir, dirPath), refCount: 1 });
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);
}
}
@ -473,7 +485,7 @@ namespace ts {
let removeAtRoot = false;
for (const failedLookupLocation of failedLookupLocations) {
const failedLookupLocationPath = resolutionHost.toPath(failedLookupLocation);
const { dirPath, ignore } = getDirectoryToWatchFailedLookupLocation(failedLookupLocation, failedLookupLocationPath);
const { dirPath, ignore, subDirectory } = getDirectoryToWatchFailedLookupLocation(failedLookupLocation, failedLookupLocationPath);
if (!ignore) {
const refCount = customFailedLookupPaths.get(failedLookupLocationPath);
if (refCount) {
@ -490,7 +502,7 @@ namespace ts {
removeAtRoot = true;
}
else {
removeDirectoryWatcher(dirPath);
removeDirectoryWatcher(dirPath, subDirectory);
}
}
}
@ -499,12 +511,30 @@ namespace ts {
}
}
function removeDirectoryWatcher(dirPath: string) {
function removeDirectoryWatcher(dirPath: string, subDirectory?: Path) {
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);
@ -516,7 +546,7 @@ namespace ts {
// 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) {
(dirPath === rootPath || isNodeModulesDirectory(dirPath) || getDirectoryPath(fileOrDirectoryPath) === dirPath || inWatchedSubdirectory(dirPath, fileOrDirectoryPath))) {
if (invalidateResolutionOfFailedLookupLocation(fileOrDirectoryPath, dirPath === fileOrDirectoryPath)) {
resolutionHost.onInvalidatedResolution();
}

View File

@ -7861,7 +7861,13 @@ new C();`
host.reloadFS(filesAfterCompilation);
host.runQueuedTimeoutCallbacks();
verifyProjectWithResolvedModule(session);
if (withPathMapping) {
verifyProjectWithResolvedModule(session);
}
else {
// Cannot handle the resolution update
verifyProjectWithUnresolvedModule(session);
}
});
it("when project recompiles after deleting generated folders", () => {
@ -7878,7 +7884,13 @@ new C();`
host.ensureFileOrFolder(recongnizerTextDistTypingFile);
host.runQueuedTimeoutCallbacks();
verifyProjectWithResolvedModule(session);
if (withPathMapping) {
verifyProjectWithResolvedModule(session);
}
else {
// Cannot handle the resolution update
verifyProjectWithUnresolvedModule(session);
}
});
});
}