Skip to content

Commit b78f466

Browse files
authored
Fix ESM/CJS resolution cache collision in non-nodenext resolution modes (#60910)
1 parent 8da951c commit b78f466

File tree

8 files changed

+578
-1
lines changed

8 files changed

+578
-1
lines changed

src/compiler/moduleNameResolver.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -2989,7 +2989,7 @@ function loadModuleFromNearestNodeModulesDirectoryTypesScope(moduleName: string,
29892989
}
29902990

29912991
function loadModuleFromNearestNodeModulesDirectoryWorker(extensions: Extensions, moduleName: string, directory: string, state: ModuleResolutionState, typesScopeOnly: boolean, cache: ModuleResolutionCache | undefined, redirectedReference: ResolvedProjectReference | undefined): SearchResult<Resolved> {
2992-
const mode = state.features === 0 ? undefined : state.features & NodeResolutionFeatures.EsmMode ? ModuleKind.ESNext : ModuleKind.CommonJS;
2992+
const mode = state.features === 0 ? undefined : (state.features & NodeResolutionFeatures.EsmMode || state.conditions.includes("import")) ? ModuleKind.ESNext : ModuleKind.CommonJS;
29932993
// Do (up to) two passes through node_modules:
29942994
// 1. For each ancestor node_modules directory, try to find:
29952995
// i. TS/DTS files in the implementation package

src/testRunner/unittests/tsserver/inferredProjects.ts

+23
Original file line numberDiff line numberDiff line change
@@ -322,4 +322,27 @@ describe("unittests:: tsserver:: inferredProjects::", () => {
322322
}], session);
323323
baselineTsserverLogs("inferredProjects", "when existing inferred project has no root files", session);
324324
});
325+
326+
it("closing file with shared resolutions", () => {
327+
const host = TestServerHost.createServerHost({
328+
"/user/username/projects/myproject/unrelated.ts": dedent`
329+
export {};
330+
`,
331+
"/user/username/projects/myproject/app.ts": dedent`
332+
import type { y } from "pkg" assert { "resolution-mode": "require" };
333+
import type { x } from "pkg" assert { "resolution-mode": "import" };
334+
`,
335+
});
336+
const session = new TestSession(host);
337+
openFilesForSession([{
338+
file: "/user/username/projects/myproject/unrelated.ts",
339+
projectRootPath: "/user/username/projects/myproject",
340+
}], session);
341+
openFilesForSession([{
342+
file: "/user/username/projects/myproject/app.ts",
343+
projectRootPath: "/user/username/projects/myproject",
344+
}], session);
345+
closeFilesForSession(["/user/username/projects/myproject/app.ts"], session);
346+
baselineTsserverLogs("inferredProjects", "closing file with shared resolutions", session);
347+
});
325348
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/index.ts(3,1): error TS1361: 'pkgRequire' cannot be used as a value because it was imported using 'import type'.
2+
/index.ts(4,1): error TS1361: 'pkgImport' cannot be used as a value because it was imported using 'import type'.
3+
4+
5+
==== /node_modules/pkg/package.json (0 errors) ====
6+
{
7+
"name": "pkg",
8+
"version": "1.0.0",
9+
"exports": {
10+
".": {
11+
"import": "./index.mjs",
12+
"require": "./index.js"
13+
}
14+
}
15+
}
16+
17+
==== /node_modules/pkg/index.d.mts (0 errors) ====
18+
declare const _default: "esm";
19+
export default _default;
20+
21+
==== /node_modules/pkg/index.d.ts (0 errors) ====
22+
declare const _exports: "cjs";
23+
export = _exports;
24+
25+
==== /index.ts (2 errors) ====
26+
import type pkgRequire from "pkg" with { "resolution-mode": "require" };
27+
import type pkgImport from "pkg" with { "resolution-mode": "import" };
28+
pkgRequire;
29+
~~~~~~~~~~
30+
!!! error TS1361: 'pkgRequire' cannot be used as a value because it was imported using 'import type'.
31+
!!! related TS1376 /index.ts:1:8: 'pkgRequire' was imported here.
32+
pkgImport;
33+
~~~~~~~~~
34+
!!! error TS1361: 'pkgImport' cannot be used as a value because it was imported using 'import type'.
35+
!!! related TS1376 /index.ts:2:8: 'pkgImport' was imported here.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//// [tests/cases/conformance/moduleResolution/resolutionModeCache.ts] ////
2+
3+
=== /node_modules/pkg/index.d.mts ===
4+
declare const _default: "esm";
5+
>_default : Symbol(_default, Decl(index.d.mts, 0, 13))
6+
7+
export default _default;
8+
>_default : Symbol(_default, Decl(index.d.mts, 0, 13))
9+
10+
=== /node_modules/pkg/index.d.ts ===
11+
declare const _exports: "cjs";
12+
>_exports : Symbol(_exports, Decl(index.d.ts, 0, 13))
13+
14+
export = _exports;
15+
>_exports : Symbol(_exports, Decl(index.d.ts, 0, 13))
16+
17+
=== /index.ts ===
18+
import type pkgRequire from "pkg" with { "resolution-mode": "require" };
19+
>pkgRequire : Symbol(pkgRequire, Decl(index.ts, 0, 6))
20+
21+
import type pkgImport from "pkg" with { "resolution-mode": "import" };
22+
>pkgImport : Symbol(pkgImport, Decl(index.ts, 1, 6))
23+
24+
pkgRequire;
25+
>pkgRequire : Symbol(pkgRequire, Decl(index.ts, 0, 6))
26+
27+
pkgImport;
28+
>pkgImport : Symbol(pkgImport, Decl(index.ts, 1, 6))
29+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
[
2+
"Found 'package.json' at '/node_modules/pkg/package.json'.",
3+
"======== Resolving module 'pkg' from '/index.ts'. ========",
4+
"Explicitly specified module resolution kind: 'Bundler'.",
5+
"Resolving in CJS mode with conditions 'require', 'types'.",
6+
"File '/package.json' does not exist.",
7+
"Loading module 'pkg' from 'node_modules' folder, target file types: TypeScript, JavaScript, Declaration, JSON.",
8+
"Searching all ancestor node_modules directories for preferred extensions: TypeScript, Declaration.",
9+
"File '/node_modules/pkg/package.json' exists according to earlier cached lookups.",
10+
"Entering conditional exports.",
11+
"Saw non-matching condition 'import'.",
12+
"Matched 'exports' condition 'require'.",
13+
"Using 'exports' subpath '.' with target './index.js'.",
14+
"File name '/node_modules/pkg/index.js' has a '.js' extension - stripping it.",
15+
"File '/node_modules/pkg/index.ts' does not exist.",
16+
"File '/node_modules/pkg/index.tsx' does not exist.",
17+
"File '/node_modules/pkg/index.d.ts' exists - use it as a name resolution result.",
18+
"'package.json' does not have a 'peerDependencies' field.",
19+
"Resolved under condition 'require'.",
20+
"Exiting conditional exports.",
21+
"Resolving real path for '/node_modules/pkg/index.d.ts', result '/node_modules/pkg/index.d.ts'.",
22+
"======== Module name 'pkg' was successfully resolved to '/node_modules/pkg/index.d.ts' with Package ID 'pkg/[email protected]'. ========",
23+
"======== Resolving module 'pkg' from '/index.ts'. ========",
24+
"Explicitly specified module resolution kind: 'Bundler'.",
25+
"Resolving in CJS mode with conditions 'import', 'types'.",
26+
"File '/package.json' does not exist according to earlier cached lookups.",
27+
"Loading module 'pkg' from 'node_modules' folder, target file types: TypeScript, JavaScript, Declaration, JSON.",
28+
"Searching all ancestor node_modules directories for preferred extensions: TypeScript, Declaration.",
29+
"File '/node_modules/pkg/package.json' exists according to earlier cached lookups.",
30+
"Entering conditional exports.",
31+
"Matched 'exports' condition 'import'.",
32+
"Using 'exports' subpath '.' with target './index.mjs'.",
33+
"File name '/node_modules/pkg/index.mjs' has a '.mjs' extension - stripping it.",
34+
"File '/node_modules/pkg/index.mts' does not exist.",
35+
"File '/node_modules/pkg/index.d.mts' exists - use it as a name resolution result.",
36+
"Resolved under condition 'import'.",
37+
"Exiting conditional exports.",
38+
"Resolving real path for '/node_modules/pkg/index.d.mts', result '/node_modules/pkg/index.d.mts'.",
39+
"======== Module name 'pkg' was successfully resolved to '/node_modules/pkg/index.d.mts' with Package ID 'pkg/[email protected]'. ========",
40+
"======== Resolving module '@typescript/lib-es5' from '/.src/__lib_node_modules_lookup_lib.es5.d.ts__.ts'. ========",
41+
"Explicitly specified module resolution kind: 'Node10'.",
42+
"Loading module '@typescript/lib-es5' from 'node_modules' folder, target file types: TypeScript, Declaration.",
43+
"Searching all ancestor node_modules directories for preferred extensions: TypeScript, Declaration.",
44+
"Directory '/.src/node_modules' does not exist, skipping all lookups in it.",
45+
"Scoped package detected, looking in 'typescript__lib-es5'",
46+
"Directory '/node_modules/@types' does not exist, skipping all lookups in it.",
47+
"Scoped package detected, looking in 'typescript__lib-es5'",
48+
"Loading module '@typescript/lib-es5' from 'node_modules' folder, target file types: JavaScript.",
49+
"Searching all ancestor node_modules directories for fallback extensions: JavaScript.",
50+
"Directory '/.src/node_modules' does not exist, skipping all lookups in it.",
51+
"======== Module name '@typescript/lib-es5' was not resolved. ========",
52+
"======== Resolving module '@typescript/lib-decorators' from '/.src/__lib_node_modules_lookup_lib.decorators.d.ts__.ts'. ========",
53+
"Explicitly specified module resolution kind: 'Node10'.",
54+
"Loading module '@typescript/lib-decorators' from 'node_modules' folder, target file types: TypeScript, Declaration.",
55+
"Searching all ancestor node_modules directories for preferred extensions: TypeScript, Declaration.",
56+
"Directory '/.src/node_modules' does not exist, skipping all lookups in it.",
57+
"Scoped package detected, looking in 'typescript__lib-decorators'",
58+
"Directory '/node_modules/@types' does not exist, skipping all lookups in it.",
59+
"Scoped package detected, looking in 'typescript__lib-decorators'",
60+
"Loading module '@typescript/lib-decorators' from 'node_modules' folder, target file types: JavaScript.",
61+
"Searching all ancestor node_modules directories for fallback extensions: JavaScript.",
62+
"Directory '/.src/node_modules' does not exist, skipping all lookups in it.",
63+
"======== Module name '@typescript/lib-decorators' was not resolved. ========",
64+
"======== Resolving module '@typescript/lib-decorators/legacy' from '/.src/__lib_node_modules_lookup_lib.decorators.legacy.d.ts__.ts'. ========",
65+
"Explicitly specified module resolution kind: 'Node10'.",
66+
"Loading module '@typescript/lib-decorators/legacy' from 'node_modules' folder, target file types: TypeScript, Declaration.",
67+
"Searching all ancestor node_modules directories for preferred extensions: TypeScript, Declaration.",
68+
"Directory '/.src/node_modules' does not exist, skipping all lookups in it.",
69+
"Scoped package detected, looking in 'typescript__lib-decorators/legacy'",
70+
"Directory '/node_modules/@types' does not exist, skipping all lookups in it.",
71+
"Scoped package detected, looking in 'typescript__lib-decorators/legacy'",
72+
"Loading module '@typescript/lib-decorators/legacy' from 'node_modules' folder, target file types: JavaScript.",
73+
"Searching all ancestor node_modules directories for fallback extensions: JavaScript.",
74+
"Directory '/.src/node_modules' does not exist, skipping all lookups in it.",
75+
"======== Module name '@typescript/lib-decorators/legacy' was not resolved. ========",
76+
"======== Resolving module '@typescript/lib-dom' from '/.src/__lib_node_modules_lookup_lib.dom.d.ts__.ts'. ========",
77+
"Explicitly specified module resolution kind: 'Node10'.",
78+
"Loading module '@typescript/lib-dom' from 'node_modules' folder, target file types: TypeScript, Declaration.",
79+
"Searching all ancestor node_modules directories for preferred extensions: TypeScript, Declaration.",
80+
"Directory '/.src/node_modules' does not exist, skipping all lookups in it.",
81+
"Scoped package detected, looking in 'typescript__lib-dom'",
82+
"Directory '/node_modules/@types' does not exist, skipping all lookups in it.",
83+
"Scoped package detected, looking in 'typescript__lib-dom'",
84+
"Loading module '@typescript/lib-dom' from 'node_modules' folder, target file types: JavaScript.",
85+
"Searching all ancestor node_modules directories for fallback extensions: JavaScript.",
86+
"Directory '/.src/node_modules' does not exist, skipping all lookups in it.",
87+
"======== Module name '@typescript/lib-dom' was not resolved. ========",
88+
"======== Resolving module '@typescript/lib-webworker/importscripts' from '/.src/__lib_node_modules_lookup_lib.webworker.importscripts.d.ts__.ts'. ========",
89+
"Explicitly specified module resolution kind: 'Node10'.",
90+
"Loading module '@typescript/lib-webworker/importscripts' from 'node_modules' folder, target file types: TypeScript, Declaration.",
91+
"Searching all ancestor node_modules directories for preferred extensions: TypeScript, Declaration.",
92+
"Directory '/.src/node_modules' does not exist, skipping all lookups in it.",
93+
"Scoped package detected, looking in 'typescript__lib-webworker/importscripts'",
94+
"Directory '/node_modules/@types' does not exist, skipping all lookups in it.",
95+
"Scoped package detected, looking in 'typescript__lib-webworker/importscripts'",
96+
"Loading module '@typescript/lib-webworker/importscripts' from 'node_modules' folder, target file types: JavaScript.",
97+
"Searching all ancestor node_modules directories for fallback extensions: JavaScript.",
98+
"Directory '/.src/node_modules' does not exist, skipping all lookups in it.",
99+
"======== Module name '@typescript/lib-webworker/importscripts' was not resolved. ========",
100+
"======== Resolving module '@typescript/lib-scripthost' from '/.src/__lib_node_modules_lookup_lib.scripthost.d.ts__.ts'. ========",
101+
"Explicitly specified module resolution kind: 'Node10'.",
102+
"Loading module '@typescript/lib-scripthost' from 'node_modules' folder, target file types: TypeScript, Declaration.",
103+
"Searching all ancestor node_modules directories for preferred extensions: TypeScript, Declaration.",
104+
"Directory '/.src/node_modules' does not exist, skipping all lookups in it.",
105+
"Scoped package detected, looking in 'typescript__lib-scripthost'",
106+
"Directory '/node_modules/@types' does not exist, skipping all lookups in it.",
107+
"Scoped package detected, looking in 'typescript__lib-scripthost'",
108+
"Loading module '@typescript/lib-scripthost' from 'node_modules' folder, target file types: JavaScript.",
109+
"Searching all ancestor node_modules directories for fallback extensions: JavaScript.",
110+
"Directory '/.src/node_modules' does not exist, skipping all lookups in it.",
111+
"======== Module name '@typescript/lib-scripthost' was not resolved. ========"
112+
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//// [tests/cases/conformance/moduleResolution/resolutionModeCache.ts] ////
2+
3+
=== /node_modules/pkg/index.d.mts ===
4+
declare const _default: "esm";
5+
>_default : "esm"
6+
> : ^^^^^
7+
8+
export default _default;
9+
>_default : "esm"
10+
> : ^^^^^
11+
12+
=== /node_modules/pkg/index.d.ts ===
13+
declare const _exports: "cjs";
14+
>_exports : "cjs"
15+
> : ^^^^^
16+
17+
export = _exports;
18+
>_exports : "cjs"
19+
> : ^^^^^
20+
21+
=== /index.ts ===
22+
import type pkgRequire from "pkg" with { "resolution-mode": "require" };
23+
>pkgRequire : any
24+
> : ^^^
25+
26+
import type pkgImport from "pkg" with { "resolution-mode": "import" };
27+
>pkgImport : any
28+
> : ^^^
29+
30+
pkgRequire;
31+
>pkgRequire : "cjs"
32+
> : ^^^^^
33+
34+
pkgImport;
35+
>pkgImport : "esm"
36+
> : ^^^^^
37+

0 commit comments

Comments
 (0)