Skip to content

Commit 357f0d6

Browse files
authored
Merge pull request #25521 from Microsoft/dontWatchAmbientModules
Do not watch modules that get resolved by ambient modules
2 parents 3d64b9d + f941226 commit 357f0d6

File tree

2 files changed

+65
-27
lines changed

2 files changed

+65
-27
lines changed

src/compiler/resolutionCache.ts

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ namespace ts {
8181
let filesWithInvalidatedResolutions: Map<true> | undefined;
8282
let filesWithInvalidatedNonRelativeUnresolvedImports: Map<ReadonlyArray<string>> | undefined;
8383
let allFilesHaveInvalidatedResolution = false;
84+
const nonRelativeExternalModuleResolutions = createMultiMap<ResolutionWithFailedLookupLocations>();
8485

8586
const getCurrentDirectory = memoize(() => resolutionHost.getCurrentDirectory!()); // TODO: GH#18217
8687
const cachedDirectoryStructureHost = resolutionHost.getCachedDirectoryStructureHost();
@@ -154,6 +155,7 @@ namespace ts {
154155
function clear() {
155156
clearMap(directoryWatchesOfFailedLookups, closeFileWatcherOf);
156157
customFailedLookupPaths.clear();
158+
nonRelativeExternalModuleResolutions.clear();
157159
closeTypeRootsWatch();
158160
resolvedModuleNames.clear();
159161
resolvedTypeReferenceDirectives.clear();
@@ -199,19 +201,20 @@ namespace ts {
199201
perDirectoryResolvedModuleNames.clear();
200202
nonRelaticeModuleNameCache.clear();
201203
perDirectoryResolvedTypeReferenceDirectives.clear();
204+
nonRelativeExternalModuleResolutions.forEach(watchFailedLookupLocationOfNonRelativeModuleResolutions);
205+
nonRelativeExternalModuleResolutions.clear();
202206
}
203207

204208
function finishCachingPerDirectoryResolution() {
205209
allFilesHaveInvalidatedResolution = false;
206210
filesWithInvalidatedNonRelativeUnresolvedImports = undefined;
211+
clearPerDirectoryResolutions();
207212
directoryWatchesOfFailedLookups.forEach((watcher, path) => {
208213
if (watcher.refCount === 0) {
209214
directoryWatchesOfFailedLookups.delete(path);
210215
watcher.watcher.close();
211216
}
212217
});
213-
214-
clearPerDirectoryResolutions();
215218
}
216219

217220
function resolveModuleName(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost): CachedResolvedModuleWithFailedLookupLocations {
@@ -275,7 +278,7 @@ namespace ts {
275278
perDirectoryResolution.set(name, resolution);
276279
}
277280
resolutionsInFile.set(name, resolution);
278-
watchFailedLookupLocationOfResolution(resolution);
281+
watchFailedLookupLocationsOfExternalModuleResolutions(name, resolution);
279282
if (existingResolution) {
280283
stopWatchFailedLookupLocationOfResolution(existingResolution);
281284
}
@@ -441,18 +444,27 @@ namespace ts {
441444
return fileExtensionIsOneOf(path, failedLookupDefaultExtensions);
442445
}
443446

444-
function watchFailedLookupLocationOfResolution(resolution: ResolutionWithFailedLookupLocations) {
447+
function watchFailedLookupLocationsOfExternalModuleResolutions(name: string, resolution: ResolutionWithFailedLookupLocations) {
445448
// No need to set the resolution refCount
446-
if (!resolution.failedLookupLocations || !resolution.failedLookupLocations.length) {
447-
return;
449+
if (resolution.failedLookupLocations && resolution.failedLookupLocations.length) {
450+
if (resolution.refCount) {
451+
resolution.refCount++;
452+
}
453+
else {
454+
resolution.refCount = 1;
455+
if (isExternalModuleNameRelative(name)) {
456+
watchFailedLookupLocationOfResolution(resolution);
457+
}
458+
else {
459+
nonRelativeExternalModuleResolutions.add(name, resolution);
460+
}
461+
}
448462
}
463+
}
449464

450-
if (resolution.refCount !== undefined) {
451-
resolution.refCount++;
452-
return;
453-
}
465+
function watchFailedLookupLocationOfResolution(resolution: ResolutionWithFailedLookupLocations) {
466+
Debug.assert(!!resolution.refCount);
454467

455-
resolution.refCount = 1;
456468
const { failedLookupLocations } = resolution;
457469
let setAtRoot = false;
458470
for (const failedLookupLocation of failedLookupLocations) {
@@ -480,6 +492,16 @@ namespace ts {
480492
}
481493
}
482494

495+
function setRefCountToUndefined(resolution: ResolutionWithFailedLookupLocations) {
496+
resolution.refCount = undefined;
497+
}
498+
499+
function watchFailedLookupLocationOfNonRelativeModuleResolutions(resolutions: ResolutionWithFailedLookupLocations[], name: string) {
500+
const updateResolution = resolutionHost.getCurrentProgram().getTypeChecker().tryFindAmbientModuleWithoutAugmentations(name) ?
501+
setRefCountToUndefined : watchFailedLookupLocationOfResolution;
502+
resolutions.forEach(updateResolution);
503+
}
504+
483505
function setDirectoryWatcher(dir: string, dirPath: Path, nonRecursive?: boolean) {
484506
const dirWatcher = directoryWatchesOfFailedLookups.get(dirPath);
485507
if (dirWatcher) {
@@ -492,11 +514,11 @@ namespace ts {
492514
}
493515

494516
function stopWatchFailedLookupLocationOfResolution(resolution: ResolutionWithFailedLookupLocations) {
495-
if (!resolution.failedLookupLocations || !resolution.failedLookupLocations.length) {
517+
if (!resolution.refCount) {
496518
return;
497519
}
498520

499-
resolution.refCount!--;
521+
resolution.refCount--;
500522
if (resolution.refCount) {
501523
return;
502524
}

src/testRunner/unittests/tsserverProjectSystem.ts

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8486,7 +8486,7 @@ new C();`
84868486
});
84878487
});
84888488

8489-
it("when watching directories for failed lookup locations in amd resolution", () => {
8489+
describe("when watching directories for failed lookup locations in amd resolution", () => {
84908490
const projectRoot = "/user/username/projects/project";
84918491
const nodeFile: File = {
84928492
path: `${projectRoot}/src/typings/node.d.ts`,
@@ -8530,19 +8530,35 @@ export const x = 10;`
85308530
}
85318531
})
85328532
};
8533-
const files = [nodeFile, electronFile, srcFile, moduleFile, configFile, libFile];
8534-
const host = createServerHost(files);
8535-
const service = createProjectService(host);
8536-
service.openClientFile(srcFile.path, srcFile.content, ScriptKind.TS, projectRoot);
8537-
checkProjectActualFiles(service.configuredProjects.get(configFile.path)!, files.map(f => f.path));
8538-
checkWatchedFilesDetailed(host, mapDefined(files, f => f === srcFile ? undefined : f.path), 1);
8539-
checkWatchedDirectoriesDetailed(host, [`${projectRoot}`], 1, /*recursive*/ false); // failed lookup for fs
8540-
const expectedWatchedDirectories = createMap<number>();
8541-
expectedWatchedDirectories.set(`${projectRoot}/src`, 2); // Wild card and failed lookup
8542-
expectedWatchedDirectories.set(`${projectRoot}/somefolder`, 1); // failed lookup for somefolder/module2
8543-
expectedWatchedDirectories.set(`${projectRoot}/node_modules`, 1); // failed lookup for with node_modules/@types/fs
8544-
expectedWatchedDirectories.set(`${projectRoot}/src/typings`, 1); // typeroot directory
8545-
checkWatchedDirectoriesDetailed(host, expectedWatchedDirectories, /*recursive*/ true);
8533+
8534+
function verifyModuleResolution(useNodeFile: boolean) {
8535+
const files = [...(useNodeFile ? [nodeFile] : []), electronFile, srcFile, moduleFile, configFile, libFile];
8536+
const host = createServerHost(files);
8537+
const service = createProjectService(host);
8538+
service.openClientFile(srcFile.path, srcFile.content, ScriptKind.TS, projectRoot);
8539+
checkProjectActualFiles(service.configuredProjects.get(configFile.path)!, files.map(f => f.path));
8540+
checkWatchedFilesDetailed(host, mapDefined(files, f => f === srcFile ? undefined : f.path), 1);
8541+
if (useNodeFile) {
8542+
checkWatchedDirectories(host, emptyArray, /*recursive*/ false); // since fs resolves to ambient module, shouldnt watch failed lookup
8543+
}
8544+
else {
8545+
checkWatchedDirectoriesDetailed(host, [`${projectRoot}`], 1, /*recursive*/ false); // failed lookup for fs
8546+
}
8547+
const expectedWatchedDirectories = createMap<number>();
8548+
expectedWatchedDirectories.set(`${projectRoot}/src`, 2); // Wild card and failed lookup
8549+
expectedWatchedDirectories.set(`${projectRoot}/somefolder`, 1); // failed lookup for somefolder/module2
8550+
expectedWatchedDirectories.set(`${projectRoot}/node_modules`, 1); // failed lookup for with node_modules/@types/fs
8551+
expectedWatchedDirectories.set(`${projectRoot}/src/typings`, 1); // typeroot directory
8552+
checkWatchedDirectoriesDetailed(host, expectedWatchedDirectories, /*recursive*/ true);
8553+
}
8554+
8555+
it("when resolves to ambient module", () => {
8556+
verifyModuleResolution(/*useNodeFile*/ true);
8557+
});
8558+
8559+
it("when resolution fails", () => {
8560+
verifyModuleResolution(/*useNodeFile*/ false);
8561+
});
85468562
});
85478563
});
85488564

0 commit comments

Comments
 (0)