Skip to content

Commit

Permalink
package.json exports should have priority over typesVersions (#50890
Browse files Browse the repository at this point in the history
)

* package.json `exports` should have priority over `typesVersions`

* Test some versioned conditions too
  • Loading branch information
andrewbranch committed Sep 22, 2022
1 parent acb8977 commit 221cf55
Show file tree
Hide file tree
Showing 12 changed files with 1,022 additions and 18 deletions.
35 changes: 17 additions & 18 deletions src/compiler/moduleNameResolver.ts
Expand Up @@ -2437,12 +2437,7 @@ namespace ts {
}
}

const { packageName, rest } = parsePackageName(moduleName);
const loader: ResolutionKindSpecificLoader = (extensions, candidate, onlyRecordFailures, state) => {
// package exports are higher priority than file/directory lookups (and, if there's exports present, blocks them)
if (packageInfo && packageInfo.contents.packageJsonContent.exports && state.features & NodeResolutionFeatures.Exports) {
return loadModuleFromExports(packageInfo, extensions, combinePaths(".", rest), state, cache, redirectedReference)?.value;
}
let pathAndExtension =
loadModuleFromFile(extensions, candidate, onlyRecordFailures, state) ||
loadNodeModuleFromDirectoryWorker(
Expand All @@ -2466,20 +2461,24 @@ namespace ts {
return withPackageId(packageInfo, pathAndExtension);
};

if (rest !== "") { // If "rest" is empty, we just did this search above.
const packageDirectory = combinePaths(nodeModulesDirectory, packageName);

// Don't use a "types" or "main" from here because we're not loading the root, but a subdirectory -- just here for the packageId and path mappings.
const { packageName, rest } = parsePackageName(moduleName);
const packageDirectory = combinePaths(nodeModulesDirectory, packageName);
if (rest !== "") {
// Previous `packageInfo` may have been from a nested package.json; ensure we have the one from the package root now.
packageInfo = getPackageJsonInfo(packageDirectory, !nodeModulesDirectoryExists, state);
if (packageInfo && packageInfo.contents.versionPaths) {
if (state.traceEnabled) {
trace(state.host, Diagnostics.package_json_has_a_typesVersions_entry_0_that_matches_compiler_version_1_looking_for_a_pattern_to_match_module_name_2, packageInfo.contents.versionPaths.version, version, rest);
}
const packageDirectoryExists = nodeModulesDirectoryExists && directoryProbablyExists(packageDirectory, state.host);
const fromPaths = tryLoadModuleUsingPaths(extensions, rest, packageDirectory, packageInfo.contents.versionPaths.paths, /*pathPatterns*/ undefined, loader, !packageDirectoryExists, state);
if (fromPaths) {
return fromPaths.value;
}
}
// package exports are higher priority than file/directory/typesVersions lookups and (and, if there's exports present, blocks them)
if (packageInfo && packageInfo.contents.packageJsonContent.exports && state.features & NodeResolutionFeatures.Exports) {
return loadModuleFromExports(packageInfo, extensions, combinePaths(".", rest), state, cache, redirectedReference)?.value;
}
if (rest !== "" && packageInfo && packageInfo.contents.versionPaths) {
if (state.traceEnabled) {
trace(state.host, Diagnostics.package_json_has_a_typesVersions_entry_0_that_matches_compiler_version_1_looking_for_a_pattern_to_match_module_name_2, packageInfo.contents.versionPaths.version, version, rest);
}
const packageDirectoryExists = nodeModulesDirectoryExists && directoryProbablyExists(packageDirectory, state.host);
const fromPaths = tryLoadModuleUsingPaths(extensions, rest, packageDirectory, packageInfo.contents.versionPaths.paths, /*pathPatterns*/ undefined, loader, !packageDirectoryExists, state);
if (fromPaths) {
return fromPaths.value;
}
}

Expand Down
@@ -0,0 +1,92 @@
error TS6504: File '/node_modules/exports-and-types-versions/dist/foo.js' is a JavaScript file. Did you mean to enable the 'allowJs' option?
The file is in the program because:
Root file specified for compilation
/main.cts(1,16): error TS7016: Could not find a declaration file for module 'exports-and-types-versions/foo'. '/node_modules/exports-and-types-versions/dist/foo.js' implicitly has an 'any' type.
If the 'exports-and-types-versions' package actually exposes this module, try adding a new declaration (.d.ts) file containing `declare module 'exports-and-types-versions/foo';`
/main.cts(2,16): error TS2307: Cannot find module 'exports-and-types-versions/nope' or its corresponding type declarations.
/main.cts(5,16): error TS2307: Cannot find module 'exports-and-types-versions/versioned-nah' or its corresponding type declarations.
/main.mts(1,16): error TS7016: Could not find a declaration file for module 'exports-and-types-versions/foo'. '/node_modules/exports-and-types-versions/dist/foo.js' implicitly has an 'any' type.
If the 'exports-and-types-versions' package actually exposes this module, try adding a new declaration (.d.ts) file containing `declare module 'exports-and-types-versions/foo';`
/main.mts(2,16): error TS2307: Cannot find module 'exports-and-types-versions/nope' or its corresponding type declarations.
/main.mts(5,16): error TS2307: Cannot find module 'exports-and-types-versions/versioned-nah' or its corresponding type declarations.


!!! error TS6504: File '/node_modules/exports-and-types-versions/dist/foo.js' is a JavaScript file. Did you mean to enable the 'allowJs' option?
!!! error TS6504: The file is in the program because:
!!! error TS6504: Root file specified for compilation
==== /node_modules/exports-and-types-versions/package.json (0 errors) ====
{
"name": "exports-and-types-versions",
"version": "1.0.0",
"exports": {
"./foo": "./dist/foo.js",
"./yep": {
"types": "./types/foo.d.ts",
"default": "./dist/foo.js"
},
"./versioned-yep": {
"types@>=4": "./types/foo.d.ts"
},
"./versioned-nah": {
"types@<4": "./types/foo.d.ts"
}
},
"typesVersions": {
"*": {
"foo": ["./types/foo.d.ts"],
"nope": ["./types/foo.d.ts"],
"versioned-nah": ["./types/foo.d.ts"]
}
}
}

==== /node_modules/exports-and-types-versions/dist/foo.js (0 errors) ====
module.exports = {};

==== /node_modules/exports-and-types-versions/types/foo.d.ts (0 errors) ====
export {};

==== /node_modules/just-types-versions/package.json (0 errors) ====
{
"name": "just-types-versions",
"version": "1.0.0",
"typesVersions": {
"*": {
"foo": ["./types/foo.d.ts"]
}
}
}

==== /node_modules/just-types-versions/types/foo.d.ts (0 errors) ====
export {};

==== /main.cts (3 errors) ====
import {} from "exports-and-types-versions/foo";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS7016: Could not find a declaration file for module 'exports-and-types-versions/foo'. '/node_modules/exports-and-types-versions/dist/foo.js' implicitly has an 'any' type.
!!! error TS7016: If the 'exports-and-types-versions' package actually exposes this module, try adding a new declaration (.d.ts) file containing `declare module 'exports-and-types-versions/foo';`
import {} from "exports-and-types-versions/nope";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2307: Cannot find module 'exports-and-types-versions/nope' or its corresponding type declarations.
import {} from "exports-and-types-versions/yep";
import {} from "exports-and-types-versions/versioned-yep";
import {} from "exports-and-types-versions/versioned-nah";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2307: Cannot find module 'exports-and-types-versions/versioned-nah' or its corresponding type declarations.
import {} from "just-types-versions/foo";

==== /main.mts (3 errors) ====
import {} from "exports-and-types-versions/foo";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS7016: Could not find a declaration file for module 'exports-and-types-versions/foo'. '/node_modules/exports-and-types-versions/dist/foo.js' implicitly has an 'any' type.
!!! error TS7016: If the 'exports-and-types-versions' package actually exposes this module, try adding a new declaration (.d.ts) file containing `declare module 'exports-and-types-versions/foo';`
import {} from "exports-and-types-versions/nope";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2307: Cannot find module 'exports-and-types-versions/nope' or its corresponding type declarations.
import {} from "exports-and-types-versions/yep";
import {} from "exports-and-types-versions/versioned-yep";
import {} from "exports-and-types-versions/versioned-nah";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2307: Cannot find module 'exports-and-types-versions/versioned-nah' or its corresponding type declarations.
import {} from "just-types-versions/foo";

@@ -0,0 +1,70 @@
//// [tests/cases/conformance/node/nodeModulesExportsBlocksTypesVersions.ts] ////

//// [package.json]
{
"name": "exports-and-types-versions",
"version": "1.0.0",
"exports": {
"./foo": "./dist/foo.js",
"./yep": {
"types": "./types/foo.d.ts",
"default": "./dist/foo.js"
},
"./versioned-yep": {
"types@>=4": "./types/foo.d.ts"
},
"./versioned-nah": {
"types@<4": "./types/foo.d.ts"
}
},
"typesVersions": {
"*": {
"foo": ["./types/foo.d.ts"],
"nope": ["./types/foo.d.ts"],
"versioned-nah": ["./types/foo.d.ts"]
}
}
}

//// [foo.js]
module.exports = {};

//// [foo.d.ts]
export {};

//// [package.json]
{
"name": "just-types-versions",
"version": "1.0.0",
"typesVersions": {
"*": {
"foo": ["./types/foo.d.ts"]
}
}
}

//// [foo.d.ts]
export {};

//// [main.cts]
import {} from "exports-and-types-versions/foo";
import {} from "exports-and-types-versions/nope";
import {} from "exports-and-types-versions/yep";
import {} from "exports-and-types-versions/versioned-yep";
import {} from "exports-and-types-versions/versioned-nah";
import {} from "just-types-versions/foo";

//// [main.mts]
import {} from "exports-and-types-versions/foo";
import {} from "exports-and-types-versions/nope";
import {} from "exports-and-types-versions/yep";
import {} from "exports-and-types-versions/versioned-yep";
import {} from "exports-and-types-versions/versioned-nah";
import {} from "just-types-versions/foo";


//// [main.cjs]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//// [main.mjs]
export {};
@@ -0,0 +1,23 @@
=== /node_modules/exports-and-types-versions/types/foo.d.ts ===
export {};
No type information for this code.
No type information for this code.=== /node_modules/just-types-versions/types/foo.d.ts ===
export {};
No type information for this code.
No type information for this code.=== /main.cts ===
import {} from "exports-and-types-versions/foo";
No type information for this code.import {} from "exports-and-types-versions/nope";
No type information for this code.import {} from "exports-and-types-versions/yep";
No type information for this code.import {} from "exports-and-types-versions/versioned-yep";
No type information for this code.import {} from "exports-and-types-versions/versioned-nah";
No type information for this code.import {} from "just-types-versions/foo";
No type information for this code.
No type information for this code.=== /main.mts ===
import {} from "exports-and-types-versions/foo";
No type information for this code.import {} from "exports-and-types-versions/nope";
No type information for this code.import {} from "exports-and-types-versions/yep";
No type information for this code.import {} from "exports-and-types-versions/versioned-yep";
No type information for this code.import {} from "exports-and-types-versions/versioned-nah";
No type information for this code.import {} from "just-types-versions/foo";
No type information for this code.
No type information for this code.

0 comments on commit 221cf55

Please sign in to comment.