diff --git a/src/compiler/moduleNameResolver.ts b/src/compiler/moduleNameResolver.ts index 8bb65e57616d5..510fc096297a7 100644 --- a/src/compiler/moduleNameResolver.ts +++ b/src/compiler/moduleNameResolver.ts @@ -1012,8 +1012,10 @@ namespace ts { } else { const jsPath = tryReadPackageJsonFields(/*readTypes*/ false, packageJsonContent, nodeModuleDirectory, state); - if (typeof jsPath === "string") { - subModuleName = removeExtension(removeExtension(jsPath.substring(nodeModuleDirectory.length + 1), Extension.Js), Extension.Jsx) + Extension.Dts; + if (typeof jsPath === "string" && jsPath.length > nodeModuleDirectory.length) { + const potentialSubModule = jsPath.substring(nodeModuleDirectory.length + 1); + subModuleName = (forEach(supportedJavascriptExtensions, extension => + tryRemoveExtension(potentialSubModule, extension)) || potentialSubModule) + Extension.Dts; } else { subModuleName = "index.d.ts"; @@ -1047,9 +1049,18 @@ namespace ts { } function loadModuleFromPackageJson(jsonContent: PackageJsonPathFields, extensions: Extensions, candidate: string, failedLookupLocations: Push, state: ModuleResolutionState): PathAndExtension | undefined { - const file = tryReadPackageJsonFields(extensions !== Extensions.JavaScript && extensions !== Extensions.Json, jsonContent, candidate, state); + let file = tryReadPackageJsonFields(extensions !== Extensions.JavaScript && extensions !== Extensions.Json, jsonContent, candidate, state); if (!file) { - return undefined; + if (extensions === Extensions.TypeScript) { + // When resolving typescript modules, try resolving using main field as well + file = tryReadPackageJsonFields(/*readTypes*/ false, jsonContent, candidate, state); + if (!file) { + return undefined; + } + } + else { + return undefined; + } } const onlyRecordFailures = !directoryProbablyExists(getDirectoryPath(file), state.host); diff --git a/src/harness/unittests/moduleResolution.ts b/src/harness/unittests/moduleResolution.ts index fc1811420d34b..b5c527aa246df 100644 --- a/src/harness/unittests/moduleResolution.ts +++ b/src/harness/unittests/moduleResolution.ts @@ -181,6 +181,13 @@ namespace ts { "/a/b/foo.ts", "/a/b/foo.tsx", "/a/b/foo.d.ts", + "/c/d", + "/c/d.ts", + "/c/d.tsx", + "/c/d.d.ts", + "/c/d/index.ts", + "/c/d/index.tsx", + "/c/d/index.d.ts", "/a/b/foo/index.ts", "/a/b/foo/index.tsx", ]); diff --git a/tests/baselines/reference/duplicatePackage_relativeImportWithinPackage.trace.json b/tests/baselines/reference/duplicatePackage_relativeImportWithinPackage.trace.json index d592022e2e177..d75683d210f83 100644 --- a/tests/baselines/reference/duplicatePackage_relativeImportWithinPackage.trace.json +++ b/tests/baselines/reference/duplicatePackage_relativeImportWithinPackage.trace.json @@ -40,6 +40,7 @@ "File '/node_modules/a/node_modules/foo.d.ts' does not exist.", "'package.json' does not have a 'typings' field.", "'package.json' does not have a 'types' field.", + "'package.json' does not have a 'main' field.", "File '/node_modules/a/node_modules/foo/index.ts' does not exist.", "File '/node_modules/a/node_modules/foo/index.tsx' does not exist.", "File '/node_modules/a/node_modules/foo/index.d.ts' exist - use it as a name resolution result.", diff --git a/tests/baselines/reference/duplicatePackage_relativeImportWithinPackage_scoped.trace.json b/tests/baselines/reference/duplicatePackage_relativeImportWithinPackage_scoped.trace.json index 108873d70f900..7b07ecd66e49d 100644 --- a/tests/baselines/reference/duplicatePackage_relativeImportWithinPackage_scoped.trace.json +++ b/tests/baselines/reference/duplicatePackage_relativeImportWithinPackage_scoped.trace.json @@ -40,6 +40,7 @@ "File '/node_modules/a/node_modules/@foo/bar.d.ts' does not exist.", "'package.json' does not have a 'typings' field.", "'package.json' does not have a 'types' field.", + "'package.json' does not have a 'main' field.", "File '/node_modules/a/node_modules/@foo/bar/index.ts' does not exist.", "File '/node_modules/a/node_modules/@foo/bar/index.tsx' does not exist.", "File '/node_modules/a/node_modules/@foo/bar/index.d.ts' exist - use it as a name resolution result.", diff --git a/tests/baselines/reference/moduleResolutionWithExtensions_unexpected.trace.json b/tests/baselines/reference/moduleResolutionWithExtensions_unexpected.trace.json index 5f32a4bf511ef..60cdab44a29fc 100644 --- a/tests/baselines/reference/moduleResolutionWithExtensions_unexpected.trace.json +++ b/tests/baselines/reference/moduleResolutionWithExtensions_unexpected.trace.json @@ -11,6 +11,14 @@ "File '/node_modules/normalize.css.d.ts' does not exist.", "'package.json' does not have a 'typings' field.", "'package.json' does not have a 'types' field.", + "'package.json' has 'main' field 'normalize.css' that references '/node_modules/normalize.css/normalize.css'.", + "File '/node_modules/normalize.css/normalize.css' exist - use it as a name resolution result.", + "File '/node_modules/normalize.css/normalize.css' has an unsupported extension, so skipping it.", + "Loading module as file / folder, candidate module location '/node_modules/normalize.css/normalize.css', target file type 'TypeScript'.", + "File '/node_modules/normalize.css/normalize.css.ts' does not exist.", + "File '/node_modules/normalize.css/normalize.css.tsx' does not exist.", + "File '/node_modules/normalize.css/normalize.css.d.ts' does not exist.", + "Directory '/node_modules/normalize.css/normalize.css' does not exist, skipping all lookups in it.", "File '/node_modules/normalize.css/index.ts' does not exist.", "File '/node_modules/normalize.css/index.tsx' does not exist.", "File '/node_modules/normalize.css/index.d.ts' does not exist.", diff --git a/tests/baselines/reference/moduleResolution_packageJson_yesAtPackageRoot_mainFieldInSubDirectory.js b/tests/baselines/reference/moduleResolution_packageJson_yesAtPackageRoot_mainFieldInSubDirectory.js new file mode 100644 index 0000000000000..1aa0a624d8dbc --- /dev/null +++ b/tests/baselines/reference/moduleResolution_packageJson_yesAtPackageRoot_mainFieldInSubDirectory.js @@ -0,0 +1,15 @@ +//// [tests/cases/compiler/moduleResolution_packageJson_yesAtPackageRoot_mainFieldInSubDirectory.ts] //// + +//// [package.json] +{ "name": "foo", "version": "1.2.3", "main": "src/index.js" } + +//// [index.d.ts] +export const x: number; + +//// [index.ts] +import { x } from "foo"; + + +//// [index.js] +"use strict"; +exports.__esModule = true; diff --git a/tests/baselines/reference/moduleResolution_packageJson_yesAtPackageRoot_mainFieldInSubDirectory.symbols b/tests/baselines/reference/moduleResolution_packageJson_yesAtPackageRoot_mainFieldInSubDirectory.symbols new file mode 100644 index 0000000000000..7a5c1d7ea2788 --- /dev/null +++ b/tests/baselines/reference/moduleResolution_packageJson_yesAtPackageRoot_mainFieldInSubDirectory.symbols @@ -0,0 +1,8 @@ +=== /node_modules/foo/src/index.d.ts === +export const x: number; +>x : Symbol(x, Decl(index.d.ts, 0, 12)) + +=== /index.ts === +import { x } from "foo"; +>x : Symbol(x, Decl(index.ts, 0, 8)) + diff --git a/tests/baselines/reference/moduleResolution_packageJson_yesAtPackageRoot_mainFieldInSubDirectory.trace.json b/tests/baselines/reference/moduleResolution_packageJson_yesAtPackageRoot_mainFieldInSubDirectory.trace.json new file mode 100644 index 0000000000000..849b65ee59ff6 --- /dev/null +++ b/tests/baselines/reference/moduleResolution_packageJson_yesAtPackageRoot_mainFieldInSubDirectory.trace.json @@ -0,0 +1,26 @@ +[ + "======== Resolving module 'foo' from '/index.ts'. ========", + "Module resolution kind is not specified, using 'NodeJs'.", + "Loading module 'foo' from 'node_modules' folder, target file type 'TypeScript'.", + "'package.json' does not have a 'typings' field.", + "'package.json' does not have a 'types' field.", + "'package.json' has 'main' field 'src/index.js' that references '/node_modules/foo/src/index.js'.", + "Found 'package.json' at '/node_modules/foo/package.json'. Package ID is 'foo/src/index.d.ts@1.2.3'.", + "File '/node_modules/foo.ts' does not exist.", + "File '/node_modules/foo.tsx' does not exist.", + "File '/node_modules/foo.d.ts' does not exist.", + "'package.json' does not have a 'typings' field.", + "'package.json' does not have a 'types' field.", + "'package.json' has 'main' field 'src/index.js' that references '/node_modules/foo/src/index.js'.", + "File '/node_modules/foo/src/index.js' does not exist.", + "Loading module as file / folder, candidate module location '/node_modules/foo/src/index.js', target file type 'TypeScript'.", + "File '/node_modules/foo/src/index.js.ts' does not exist.", + "File '/node_modules/foo/src/index.js.tsx' does not exist.", + "File '/node_modules/foo/src/index.js.d.ts' does not exist.", + "File name '/node_modules/foo/src/index.js' has a '.js' extension - stripping it.", + "File '/node_modules/foo/src/index.ts' does not exist.", + "File '/node_modules/foo/src/index.tsx' does not exist.", + "File '/node_modules/foo/src/index.d.ts' exist - use it as a name resolution result.", + "Resolving real path for '/node_modules/foo/src/index.d.ts', result '/node_modules/foo/src/index.d.ts'.", + "======== Module name 'foo' was successfully resolved to '/node_modules/foo/src/index.d.ts'. ========" +] \ No newline at end of file diff --git a/tests/baselines/reference/moduleResolution_packageJson_yesAtPackageRoot_mainFieldInSubDirectory.types b/tests/baselines/reference/moduleResolution_packageJson_yesAtPackageRoot_mainFieldInSubDirectory.types new file mode 100644 index 0000000000000..e0ae051e59f17 --- /dev/null +++ b/tests/baselines/reference/moduleResolution_packageJson_yesAtPackageRoot_mainFieldInSubDirectory.types @@ -0,0 +1,8 @@ +=== /node_modules/foo/src/index.d.ts === +export const x: number; +>x : number + +=== /index.ts === +import { x } from "foo"; +>x : number + diff --git a/tests/baselines/reference/packageJsonMain.trace.json b/tests/baselines/reference/packageJsonMain.trace.json index 6d39b9d4a7b7a..06c8cff66431b 100644 --- a/tests/baselines/reference/packageJsonMain.trace.json +++ b/tests/baselines/reference/packageJsonMain.trace.json @@ -11,6 +11,13 @@ "File '/node_modules/foo.d.ts' does not exist.", "'package.json' does not have a 'typings' field.", "'package.json' does not have a 'types' field.", + "'package.json' has 'main' field 'oof' that references '/node_modules/foo/oof'.", + "File '/node_modules/foo/oof' does not exist.", + "Loading module as file / folder, candidate module location '/node_modules/foo/oof', target file type 'TypeScript'.", + "File '/node_modules/foo/oof.ts' does not exist.", + "File '/node_modules/foo/oof.tsx' does not exist.", + "File '/node_modules/foo/oof.d.ts' does not exist.", + "Directory '/node_modules/foo/oof' does not exist, skipping all lookups in it.", "File '/node_modules/foo/index.ts' does not exist.", "File '/node_modules/foo/index.tsx' does not exist.", "File '/node_modules/foo/index.d.ts' does not exist.", @@ -40,6 +47,18 @@ "File '/node_modules/bar.d.ts' does not exist.", "'package.json' does not have a 'typings' field.", "'package.json' does not have a 'types' field.", + "'package.json' has 'main' field 'rab.js' that references '/node_modules/bar/rab.js'.", + "File '/node_modules/bar/rab.js' exist - use it as a name resolution result.", + "File '/node_modules/bar/rab.js' has an unsupported extension, so skipping it.", + "Loading module as file / folder, candidate module location '/node_modules/bar/rab.js', target file type 'TypeScript'.", + "File '/node_modules/bar/rab.js.ts' does not exist.", + "File '/node_modules/bar/rab.js.tsx' does not exist.", + "File '/node_modules/bar/rab.js.d.ts' does not exist.", + "File name '/node_modules/bar/rab.js' has a '.js' extension - stripping it.", + "File '/node_modules/bar/rab.ts' does not exist.", + "File '/node_modules/bar/rab.tsx' does not exist.", + "File '/node_modules/bar/rab.d.ts' does not exist.", + "Directory '/node_modules/bar/rab.js' does not exist, skipping all lookups in it.", "File '/node_modules/bar/index.ts' does not exist.", "File '/node_modules/bar/index.tsx' does not exist.", "File '/node_modules/bar/index.d.ts' does not exist.", @@ -67,6 +86,15 @@ "File '/node_modules/baz.d.ts' does not exist.", "'package.json' does not have a 'typings' field.", "'package.json' does not have a 'types' field.", + "'package.json' has 'main' field 'zab' that references '/node_modules/baz/zab'.", + "File '/node_modules/baz/zab' does not exist.", + "Loading module as file / folder, candidate module location '/node_modules/baz/zab', target file type 'TypeScript'.", + "File '/node_modules/baz/zab.ts' does not exist.", + "File '/node_modules/baz/zab.tsx' does not exist.", + "File '/node_modules/baz/zab.d.ts' does not exist.", + "File '/node_modules/baz/zab/index.ts' does not exist.", + "File '/node_modules/baz/zab/index.tsx' does not exist.", + "File '/node_modules/baz/zab/index.d.ts' does not exist.", "File '/node_modules/baz/index.ts' does not exist.", "File '/node_modules/baz/index.tsx' does not exist.", "File '/node_modules/baz/index.d.ts' does not exist.", diff --git a/tests/baselines/reference/packageJsonMain_isNonRecursive.trace.json b/tests/baselines/reference/packageJsonMain_isNonRecursive.trace.json index 81f5be11a6d76..a2878a2a4fed5 100644 --- a/tests/baselines/reference/packageJsonMain_isNonRecursive.trace.json +++ b/tests/baselines/reference/packageJsonMain_isNonRecursive.trace.json @@ -11,6 +11,15 @@ "File '/node_modules/foo.d.ts' does not exist.", "'package.json' does not have a 'typings' field.", "'package.json' does not have a 'types' field.", + "'package.json' has 'main' field 'oof' that references '/node_modules/foo/oof'.", + "File '/node_modules/foo/oof' does not exist.", + "Loading module as file / folder, candidate module location '/node_modules/foo/oof', target file type 'TypeScript'.", + "File '/node_modules/foo/oof.ts' does not exist.", + "File '/node_modules/foo/oof.tsx' does not exist.", + "File '/node_modules/foo/oof.d.ts' does not exist.", + "File '/node_modules/foo/oof/index.ts' does not exist.", + "File '/node_modules/foo/oof/index.tsx' does not exist.", + "File '/node_modules/foo/oof/index.d.ts' does not exist.", "File '/node_modules/foo/index.ts' does not exist.", "File '/node_modules/foo/index.tsx' does not exist.", "File '/node_modules/foo/index.d.ts' does not exist.", diff --git a/tests/cases/compiler/moduleResolution_packageJson_yesAtPackageRoot_mainFieldInSubDirectory.ts b/tests/cases/compiler/moduleResolution_packageJson_yesAtPackageRoot_mainFieldInSubDirectory.ts new file mode 100644 index 0000000000000..4af56e48e1c3e --- /dev/null +++ b/tests/cases/compiler/moduleResolution_packageJson_yesAtPackageRoot_mainFieldInSubDirectory.ts @@ -0,0 +1,10 @@ +// @traceResolution: true + +// @Filename: /node_modules/foo/package.json +{ "name": "foo", "version": "1.2.3", "main": "src/index.js" } + +// @Filename: /node_modules/foo/src/index.d.ts +export const x: number; + +// @Filename: /index.ts +import { x } from "foo";