diff --git a/src/compiler/moduleNameResolver.ts b/src/compiler/moduleNameResolver.ts index ddffe876d80..84256b3a1b1 100644 --- a/src/compiler/moduleNameResolver.ts +++ b/src/compiler/moduleNameResolver.ts @@ -976,8 +976,8 @@ namespace ts { } function loadModuleFromNodeModulesFolder(extensions: Extensions, moduleName: string, nodeModulesFolder: string, nodeModulesFolderExists: boolean, failedLookupLocations: Push, state: ModuleResolutionState): Resolved | undefined { - const { top, rest } = getNameOfTopDirectory(moduleName); - const packageRootPath = combinePaths(nodeModulesFolder, top); + const { packageName, rest } = getPackageName(moduleName); + const packageRootPath = combinePaths(nodeModulesFolder, packageName); const { packageJsonContent, packageId } = getPackageJsonInfo(packageRootPath, rest, failedLookupLocations, !nodeModulesFolderExists, state); const candidate = normalizePath(combinePaths(nodeModulesFolder, moduleName)); const pathAndExtension = loadModuleFromFile(extensions, candidate, failedLookupLocations, !nodeModulesFolderExists, state) || @@ -985,9 +985,12 @@ namespace ts { return withPackageId(packageId, pathAndExtension); } - function getNameOfTopDirectory(name: string): { top: string, rest: string } { - const idx = name.indexOf(directorySeparator); - return idx === -1 ? { top: name, rest: "" } : { top: name.slice(0, idx), rest: name.slice(idx + 1) }; + function getPackageName(moduleName: string): { packageName: string, rest: string } { + let idx = moduleName.indexOf(directorySeparator); + if (moduleName[0] === "@") { + idx = moduleName.indexOf(directorySeparator, idx + 1); + } + return idx === -1 ? { packageName: moduleName, rest: "" } : { packageName: moduleName.slice(0, idx), rest: moduleName.slice(idx + 1) }; } function loadModuleFromNodeModules(extensions: Extensions, moduleName: string, directory: string, failedLookupLocations: Push, state: ModuleResolutionState, cache: NonRelativeModuleNameResolutionCache): SearchResult { diff --git a/tests/baselines/reference/moduleResolution_packageJson_scopedPackage.js b/tests/baselines/reference/moduleResolution_packageJson_scopedPackage.js new file mode 100644 index 00000000000..32495ee1ab3 --- /dev/null +++ b/tests/baselines/reference/moduleResolution_packageJson_scopedPackage.js @@ -0,0 +1,15 @@ +//// [tests/cases/compiler/moduleResolution_packageJson_scopedPackage.ts] //// + +//// [package.json] +{ "types": "types.d.ts" } + +//// [types.d.ts] +export const x: number; + +//// [a.ts] +import { x } from "@foo/bar"; + + +//// [a.js] +"use strict"; +exports.__esModule = true; diff --git a/tests/baselines/reference/moduleResolution_packageJson_scopedPackage.symbols b/tests/baselines/reference/moduleResolution_packageJson_scopedPackage.symbols new file mode 100644 index 00000000000..4522817e78f --- /dev/null +++ b/tests/baselines/reference/moduleResolution_packageJson_scopedPackage.symbols @@ -0,0 +1,8 @@ +=== /a.ts === +import { x } from "@foo/bar"; +>x : Symbol(x, Decl(a.ts, 0, 8)) + +=== /node_modules/@foo/bar/types.d.ts === +export const x: number; +>x : Symbol(x, Decl(types.d.ts, 0, 12)) + diff --git a/tests/baselines/reference/moduleResolution_packageJson_scopedPackage.trace.json b/tests/baselines/reference/moduleResolution_packageJson_scopedPackage.trace.json new file mode 100644 index 00000000000..69dcfca4eb6 --- /dev/null +++ b/tests/baselines/reference/moduleResolution_packageJson_scopedPackage.trace.json @@ -0,0 +1,14 @@ +[ + "======== Resolving module '@foo/bar' from '/a.ts'. ========", + "Module resolution kind is not specified, using 'NodeJs'.", + "Loading module '@foo/bar' from 'node_modules' folder, target file type 'TypeScript'.", + "Found 'package.json' at '/node_modules/@foo/bar/package.json'.", + "File '/node_modules/@foo/bar.ts' does not exist.", + "File '/node_modules/@foo/bar.tsx' does not exist.", + "File '/node_modules/@foo/bar.d.ts' does not exist.", + "'package.json' does not have a 'typings' field.", + "'package.json' has 'types' field 'types.d.ts' that references '/node_modules/@foo/bar/types.d.ts'.", + "File '/node_modules/@foo/bar/types.d.ts' exist - use it as a name resolution result.", + "Resolving real path for '/node_modules/@foo/bar/types.d.ts', result '/node_modules/@foo/bar/types.d.ts'.", + "======== Module name '@foo/bar' was successfully resolved to '/node_modules/@foo/bar/types.d.ts'. ========" +] \ No newline at end of file diff --git a/tests/baselines/reference/moduleResolution_packageJson_scopedPackage.types b/tests/baselines/reference/moduleResolution_packageJson_scopedPackage.types new file mode 100644 index 00000000000..b2d16a70c2e --- /dev/null +++ b/tests/baselines/reference/moduleResolution_packageJson_scopedPackage.types @@ -0,0 +1,8 @@ +=== /a.ts === +import { x } from "@foo/bar"; +>x : number + +=== /node_modules/@foo/bar/types.d.ts === +export const x: number; +>x : number + diff --git a/tests/baselines/reference/scopedPackages.trace.json b/tests/baselines/reference/scopedPackages.trace.json index a2b8af48266..1844f8c6c8d 100644 --- a/tests/baselines/reference/scopedPackages.trace.json +++ b/tests/baselines/reference/scopedPackages.trace.json @@ -2,7 +2,7 @@ "======== Resolving module '@cow/boy' from '/a.ts'. ========", "Module resolution kind is not specified, using 'NodeJs'.", "Loading module '@cow/boy' from 'node_modules' folder, target file type 'TypeScript'.", - "File '/node_modules/@cow/package.json' does not exist.", + "File '/node_modules/@cow/boy/package.json' does not exist.", "File '/node_modules/@cow/boy.ts' does not exist.", "File '/node_modules/@cow/boy.tsx' does not exist.", "File '/node_modules/@cow/boy.d.ts' does not exist.", diff --git a/tests/cases/compiler/moduleResolution_packageJson_scopedPackage.ts b/tests/cases/compiler/moduleResolution_packageJson_scopedPackage.ts new file mode 100644 index 00000000000..624d21b4d71 --- /dev/null +++ b/tests/cases/compiler/moduleResolution_packageJson_scopedPackage.ts @@ -0,0 +1,11 @@ +// @noImplicitReferences: true +// @traceResolution: true + +// @Filename: /node_modules/@foo/bar/package.json +{ "types": "types.d.ts" } + +// @Filename: /node_modules/@foo/bar/types.d.ts +export const x: number; + +// @Filename: /a.ts +import { x } from "@foo/bar";