From 121b04ee36da2ad1d958e5b0fffc907460673529 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Fri, 16 Sep 2016 15:49:20 -0700 Subject: [PATCH] (lshost): run second module resolution pass if first pass yielded non-ts file (#10959) * (lshost): run second module resolution pass if first pass yielded non-ts file * use length check --- .../unittests/tsserverProjectSystem.ts | 28 +++++++++++++++++++ src/server/lsHost.ts | 16 +++++++++-- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/harness/unittests/tsserverProjectSystem.ts b/src/harness/unittests/tsserverProjectSystem.ts index b455c0d216..cf5208628c 100644 --- a/src/harness/unittests/tsserverProjectSystem.ts +++ b/src/harness/unittests/tsserverProjectSystem.ts @@ -1881,4 +1881,32 @@ namespace ts.projectSystem { projectService.checkNumberOfProjects({}); }); }); + + describe("prefer typings to js", () => { + it("during second resolution pass", () => { + const typingsCacheLocation = "/a/typings"; + const f1 = { + path: "/a/b/app.js", + content: "var x = require('bar')" + }; + const barjs = { + path: "/a/b/node_modules/bar/index.js", + content: "export let x = 1" + }; + const barTypings = { + path: `${typingsCacheLocation}/node_modules/@types/bar/index.d.ts`, + content: "export let y: number" + }; + const config = { + path: "/a/b/jsconfig.json", + content: JSON.stringify({ compilerOptions: { allowJs: true }, exclude: ["node_modules"] }) + }; + const host = createServerHost([f1, barjs, barTypings, config]); + const projectService = createProjectService(host, { typingsInstaller: new TestTypingsInstaller(typingsCacheLocation, host) }); + + projectService.openClientFile(f1.path); + projectService.checkNumberOfProjects({ configuredProjects: 1 }); + checkProjectActualFiles(projectService.configuredProjects[0], [f1.path, barTypings.path]); + }); + }); } \ No newline at end of file diff --git a/src/server/lsHost.ts b/src/server/lsHost.ts index fd933bace1..f6530953a5 100644 --- a/src/server/lsHost.ts +++ b/src/server/lsHost.ts @@ -24,8 +24,15 @@ namespace ts.server { this.resolveModuleName = (moduleName, containingFile, compilerOptions, host) => { const primaryResult = resolveModuleName(moduleName, containingFile, compilerOptions, host); if (primaryResult.resolvedModule) { - return primaryResult; + // return result immediately only if it is .ts, .tsx or .d.ts + // otherwise try to load typings from @types + if (fileExtensionIsAny(primaryResult.resolvedModule.resolvedFileName, supportedTypeScriptExtensions)) { + return primaryResult; + } } + // create different collection of failed lookup locations for second pass + // if it will fail and we've already found something during the first pass - we don't want to pollute its results + const secondaryLookupFailedLookupLocations: string[] = []; const globalCache = this.project.projectService.typingsInstaller.globalTypingsCacheLocation; if (this.project.getTypingOptions().enableAutoDiscovery && globalCache) { const traceEnabled = isTraceEnabled(compilerOptions, host); @@ -33,11 +40,14 @@ namespace ts.server { trace(host, Diagnostics.Auto_discovery_for_typings_is_enabled_in_project_0_Running_extra_resolution_pass_for_module_1_using_cache_location_2, this.project.getProjectName(), moduleName, globalCache); } const state: ModuleResolutionState = { compilerOptions, host, skipTsx: false, traceEnabled }; - const resolvedName = loadModuleFromNodeModules(moduleName, globalCache, primaryResult.failedLookupLocations, state, /*checkOneLevel*/ true); + const resolvedName = loadModuleFromNodeModules(moduleName, globalCache, secondaryLookupFailedLookupLocations, state, /*checkOneLevel*/ true); if (resolvedName) { - return createResolvedModule(resolvedName, /*isExternalLibraryImport*/ true, primaryResult.failedLookupLocations); + return createResolvedModule(resolvedName, /*isExternalLibraryImport*/ true, primaryResult.failedLookupLocations.concat(secondaryLookupFailedLookupLocations)); } } + if (!primaryResult.resolvedModule && secondaryLookupFailedLookupLocations.length) { + primaryResult.failedLookupLocations = primaryResult.failedLookupLocations.concat(secondaryLookupFailedLookupLocations); + } return primaryResult; }; }