From 1e66f071fd3aa8758a9041d1a0a423ef8ccadeeb Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Fri, 23 Mar 2018 14:42:16 -0700 Subject: [PATCH] Always include parent folder failed lookup locations --- src/compiler/moduleNameResolver.ts | 7 ++-- src/harness/unittests/moduleResolution.ts | 2 +- .../unittests/tsserverProjectSystem.ts | 41 +++++++++++++++++++ 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/src/compiler/moduleNameResolver.ts b/src/compiler/moduleNameResolver.ts index bd2b98116a1..e9f73e9ebfe 100644 --- a/src/compiler/moduleNameResolver.ts +++ b/src/compiler/moduleNameResolver.ts @@ -1118,7 +1118,7 @@ namespace ts { const perModuleNameCache = cache && cache.getOrCreateCacheForModuleName(moduleName); return forEachAncestorDirectory(normalizeSlashes(directory), ancestorDirectory => { if (getBaseFileName(ancestorDirectory) !== "node_modules") { - const resolutionFromCache = tryFindNonRelativeModuleNameInCache(perModuleNameCache, moduleName, ancestorDirectory, state.traceEnabled, state.host); + const resolutionFromCache = tryFindNonRelativeModuleNameInCache(perModuleNameCache, moduleName, ancestorDirectory, state.traceEnabled, state.host, failedLookupLocations); if (resolutionFromCache) { return resolutionFromCache; } @@ -1196,12 +1196,13 @@ namespace ts { typesPackageName; } - function tryFindNonRelativeModuleNameInCache(cache: PerModuleNameCache | undefined, moduleName: string, containingDirectory: string, traceEnabled: boolean, host: ModuleResolutionHost): SearchResult { + function tryFindNonRelativeModuleNameInCache(cache: PerModuleNameCache | undefined, moduleName: string, containingDirectory: string, traceEnabled: boolean, host: ModuleResolutionHost, failedLookupLocations: Push): SearchResult { const result = cache && cache.get(containingDirectory); if (result) { if (traceEnabled) { trace(host, Diagnostics.Resolution_for_module_0_was_found_in_cache_from_location_1, moduleName, containingDirectory); } + failedLookupLocations.push(...result.failedLookupLocations); return { value: result.resolvedModule && { path: result.resolvedModule.resolvedFileName, extension: result.resolvedModule.extension, packageId: result.resolvedModule.packageId } }; } } @@ -1226,7 +1227,7 @@ namespace ts { if (!isExternalModuleNameRelative(moduleName)) { // Climb up parent directories looking for a module. const resolved = forEachAncestorDirectory(containingDirectory, directory => { - const resolutionFromCache = tryFindNonRelativeModuleNameInCache(perModuleNameCache, moduleName, directory, traceEnabled, host); + const resolutionFromCache = tryFindNonRelativeModuleNameInCache(perModuleNameCache, moduleName, directory, traceEnabled, host, failedLookupLocations); if (resolutionFromCache) { return resolutionFromCache; } diff --git a/src/harness/unittests/moduleResolution.ts b/src/harness/unittests/moduleResolution.ts index 13ff6776a1f..fc1811420d3 100644 --- a/src/harness/unittests/moduleResolution.ts +++ b/src/harness/unittests/moduleResolution.ts @@ -16,7 +16,7 @@ namespace ts { export function checkResolvedModuleWithFailedLookupLocations(actual: ResolvedModuleWithFailedLookupLocations, expectedResolvedModule: ResolvedModuleFull, expectedFailedLookupLocations: string[]): void { assert.isTrue(actual.resolvedModule !== undefined, "module should be resolved"); checkResolvedModule(actual.resolvedModule, expectedResolvedModule); - assert.deepEqual(actual.failedLookupLocations, expectedFailedLookupLocations); + assert.deepEqual(actual.failedLookupLocations, expectedFailedLookupLocations, `Failed lookup locations should match - expected has ${expectedFailedLookupLocations.length}, actual has ${actual.failedLookupLocations.length}`); } export function createResolvedModule(resolvedFileName: string, isExternalLibraryImport = false): ResolvedModuleFull { diff --git a/src/harness/unittests/tsserverProjectSystem.ts b/src/harness/unittests/tsserverProjectSystem.ts index 68defb6c4a7..ac3a9644fb8 100644 --- a/src/harness/unittests/tsserverProjectSystem.ts +++ b/src/harness/unittests/tsserverProjectSystem.ts @@ -6045,6 +6045,47 @@ namespace ts.projectSystem { }); }); + describe("Subfolder invalidations correctly include parent folder failed lookup locations QJWOP", () => { + it("Includes the parent folder FLLs", () => { + const projectLocation = "/proj"; + const file1: FileOrFolder = { + path: `${projectLocation}/foo/boo/app.ts`, + content: `import * as debug from "debug"` + }; + const file2: FileOrFolder = { + path: `${projectLocation}/foo/boo/moo/app.ts`, + content: `import * as debug from "debug"` + }; + const tsconfig: FileOrFolder = { + path: `${projectLocation}/tsconfig.json`, + content: JSON.stringify({ + files: ["foo/boo/app.ts", "foo/boo/moo/app.ts"] + }) + }; + + const files = [file1, file2, tsconfig, libFile]; + const host = createServerHost(files); + const service = createProjectService(host); + service.openClientFile(file1.path); + + const project = service.configuredProjects.get(tsconfig.path); + checkProjectActualFiles(project, files.map(f => f.path)); + assert.deepEqual(project.getLanguageService().getSemanticDiagnostics(file1.path).map(diag => diag.messageText), ["Cannot find module 'debug'."]); + assert.deepEqual(project.getLanguageService().getSemanticDiagnostics(file2.path).map(diag => diag.messageText), ["Cannot find module 'debug'."]); + + const debugTypesFile: FileOrFolder = { + path: `${projectLocation}/node_modules/debug/index.d.ts`, + content: "export {}" + }; + files.push(debugTypesFile); + host.reloadFS(files); + host.runQueuedTimeoutCallbacks(); + checkProjectActualFiles(project, files.map(f => f.path)); + assert.deepEqual(project.getLanguageService().getSemanticDiagnostics(file1.path).map(diag => diag.messageText), []); + assert.deepEqual(project.getLanguageService().getSemanticDiagnostics(file2.path).map(diag => diag.messageText), []); + }); + }); + describe("Verify npm install in directory with tsconfig file works when", () => { function verifyNpmInstall(timeoutDuringPartialInstallation: boolean) { const root = "/user/username/rootfolder/otherfolder";