diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 49f61981d72..7a4adf9ff08 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -8,8 +8,6 @@ namespace ts { const emptyArray: any[] = []; - const defaultTypeRoots = ["node_modules/@types"]; - export function findConfigFile(searchPath: string, fileExists: (fileName: string) => boolean): string { while (true) { const fileName = combinePaths(searchPath, "tsconfig.json"); @@ -168,7 +166,7 @@ namespace ts { const typeReferenceExtensions = [".d.ts"]; - function getEffectiveTypeRoots(options: CompilerOptions, host: ModuleResolutionHost) { + function getEffectiveTypeRoots(options: CompilerOptions, host: ModuleResolutionHost): string[] | undefined { if (options.typeRoots) { return options.typeRoots; } @@ -181,10 +179,33 @@ namespace ts { currentDirectory = host.getCurrentDirectory(); } - if (!currentDirectory) { - return undefined; + return currentDirectory && getDefaultTypeRoots(currentDirectory, host); + } + + function getDefaultTypeRoots(currentDirectory: string, host: ModuleResolutionHost): string[] | undefined { + const nodeModules = getNearestNodeModules(currentDirectory, host); + return nodeModules && [combinePaths(nodeModules, "@types")]; + } + + function getNearestNodeModules(currentDirectory: string, host: ModuleResolutionHost): string | undefined { + if (!host.directoryExists) { + return combinePaths(currentDirectory, "node_modules"); + // And if it doesn't exist, tough. + } + + while (true) { + const nodeModules = combinePaths(currentDirectory, "node_modules"); + if (host.directoryExists(nodeModules)) { + return nodeModules; + } + else { + const parent = getDirectoryPath(currentDirectory); + if (parent === currentDirectory) { + return undefined; + } + currentDirectory = parent; + } } - return map(defaultTypeRoots, d => combinePaths(currentDirectory, d)); } /** diff --git a/tests/baselines/reference/typeRootsFromNodeModulesInParentDirectory.js b/tests/baselines/reference/typeRootsFromNodeModulesInParentDirectory.js new file mode 100644 index 00000000000..9e93755d1f0 --- /dev/null +++ b/tests/baselines/reference/typeRootsFromNodeModulesInParentDirectory.js @@ -0,0 +1,17 @@ +//// [tests/cases/compiler/typeRootsFromNodeModulesInParentDirectory.ts] //// + +//// [index.d.ts] + +declare module "xyz" { + export const x: number; +} + +//// [a.ts] +import { x } from "xyz"; +x; + + +//// [a.js] +"use strict"; +var xyz_1 = require("xyz"); +xyz_1.x; diff --git a/tests/baselines/reference/typeRootsFromNodeModulesInParentDirectory.symbols b/tests/baselines/reference/typeRootsFromNodeModulesInParentDirectory.symbols new file mode 100644 index 00000000000..10cbdaa3c53 --- /dev/null +++ b/tests/baselines/reference/typeRootsFromNodeModulesInParentDirectory.symbols @@ -0,0 +1,14 @@ +=== /src/a.ts === +import { x } from "xyz"; +>x : Symbol(x, Decl(a.ts, 0, 8)) + +x; +>x : Symbol(x, Decl(a.ts, 0, 8)) + +=== /node_modules/@types/foo/index.d.ts === + +declare module "xyz" { + export const x: number; +>x : Symbol(x, Decl(index.d.ts, 2, 16)) +} + diff --git a/tests/baselines/reference/typeRootsFromNodeModulesInParentDirectory.trace.json b/tests/baselines/reference/typeRootsFromNodeModulesInParentDirectory.trace.json new file mode 100644 index 00000000000..7782ffc4ebf --- /dev/null +++ b/tests/baselines/reference/typeRootsFromNodeModulesInParentDirectory.trace.json @@ -0,0 +1,39 @@ +[ + "======== Resolving module 'xyz' from '/src/a.ts'. ========", + "Module resolution kind is not specified, using 'NodeJs'.", + "Loading module 'xyz' from 'node_modules' folder.", + "File '/src/node_modules/xyz.ts' does not exist.", + "File '/src/node_modules/xyz.tsx' does not exist.", + "File '/src/node_modules/xyz.d.ts' does not exist.", + "File '/src/node_modules/xyz/package.json' does not exist.", + "File '/src/node_modules/xyz/index.ts' does not exist.", + "File '/src/node_modules/xyz/index.tsx' does not exist.", + "File '/src/node_modules/xyz/index.d.ts' does not exist.", + "File '/src/node_modules/@types/xyz.ts' does not exist.", + "File '/src/node_modules/@types/xyz.tsx' does not exist.", + "File '/src/node_modules/@types/xyz.d.ts' does not exist.", + "File '/src/node_modules/@types/xyz/package.json' does not exist.", + "File '/src/node_modules/@types/xyz/index.ts' does not exist.", + "File '/src/node_modules/@types/xyz/index.tsx' does not exist.", + "File '/src/node_modules/@types/xyz/index.d.ts' does not exist.", + "File '/node_modules/xyz.ts' does not exist.", + "File '/node_modules/xyz.tsx' does not exist.", + "File '/node_modules/xyz.d.ts' does not exist.", + "File '/node_modules/xyz/package.json' does not exist.", + "File '/node_modules/xyz/index.ts' does not exist.", + "File '/node_modules/xyz/index.tsx' does not exist.", + "File '/node_modules/xyz/index.d.ts' does not exist.", + "File '/node_modules/@types/xyz.ts' does not exist.", + "File '/node_modules/@types/xyz.tsx' does not exist.", + "File '/node_modules/@types/xyz.d.ts' does not exist.", + "File '/node_modules/@types/xyz/package.json' does not exist.", + "File '/node_modules/@types/xyz/index.ts' does not exist.", + "File '/node_modules/@types/xyz/index.tsx' does not exist.", + "File '/node_modules/@types/xyz/index.d.ts' does not exist.", + "======== Module name 'xyz' was not resolved. ========", + "======== Resolving type reference directive 'foo', containing file '/src/__inferred type names__.ts', root directory '/node_modules/@types'. ========", + "Resolving with primary search path '/node_modules/@types'", + "File '/node_modules/@types/foo/package.json' does not exist.", + "File '/node_modules/@types/foo/index.d.ts' exist - use it as a name resolution result.", + "======== Type reference directive 'foo' was successfully resolved to '/node_modules/@types/foo/index.d.ts', primary: true. ========" +] \ No newline at end of file diff --git a/tests/baselines/reference/typeRootsFromNodeModulesInParentDirectory.types b/tests/baselines/reference/typeRootsFromNodeModulesInParentDirectory.types new file mode 100644 index 00000000000..532a05fcb87 --- /dev/null +++ b/tests/baselines/reference/typeRootsFromNodeModulesInParentDirectory.types @@ -0,0 +1,14 @@ +=== /src/a.ts === +import { x } from "xyz"; +>x : number + +x; +>x : number + +=== /node_modules/@types/foo/index.d.ts === + +declare module "xyz" { + export const x: number; +>x : number +} + diff --git a/tests/cases/compiler/typeRootsFromNodeModulesInParentDirectory.ts b/tests/cases/compiler/typeRootsFromNodeModulesInParentDirectory.ts new file mode 100644 index 00000000000..59b7d6a3188 --- /dev/null +++ b/tests/cases/compiler/typeRootsFromNodeModulesInParentDirectory.ts @@ -0,0 +1,15 @@ +// @noImplicitReferences: true +// @traceResolution: true +// @currentDirectory: /src + +// @Filename: /node_modules/@types/foo/index.d.ts +declare module "xyz" { + export const x: number; +} + +// @Filename: /src/a.ts +import { x } from "xyz"; +x; + +// @Filename: /src/tsconfig.json +{}