Skip to content

Commit ec9f6a4

Browse files
authored
Ensure self-name resolution uses same extension priorities as external imports (#52185)
1 parent 32da8a2 commit ec9f6a4

File tree

5 files changed

+136
-1
lines changed

5 files changed

+136
-1
lines changed

src/compiler/moduleNameResolver.ts

+12-1
Original file line numberDiff line numberDiff line change
@@ -2313,7 +2313,18 @@ function loadModuleFromSelfNameReference(extensions: Extensions, moduleName: str
23132313
return undefined;
23142314
}
23152315
const trailingParts = parts.slice(nameParts.length);
2316-
return loadModuleFromExports(scope, extensions, !length(trailingParts) ? "." : `.${directorySeparator}${trailingParts.join(directorySeparator)}`, state, cache, redirectedReference);
2316+
const subpath = !length(trailingParts) ? "." : `.${directorySeparator}${trailingParts.join(directorySeparator)}`;
2317+
// Maybe TODO: splitting extensions into two priorities should be unnecessary, except
2318+
// https://github.com/microsoft/TypeScript/issues/50762 makes the behavior different.
2319+
// As long as that bug exists, we need to do two passes here in self-name loading
2320+
// in order to be consistent with (non-self) library-name loading in
2321+
// `loadModuleFromNearestNodeModulesDirectoryWorker`, which uses two passes in order
2322+
// to prioritize `@types` packages higher up the directory tree over untyped
2323+
// implementation packages.
2324+
const priorityExtensions = extensions & (Extensions.TypeScript | Extensions.Declaration);
2325+
const secondaryExtensions = extensions & ~(Extensions.TypeScript | Extensions.Declaration);
2326+
return loadModuleFromExports(scope, priorityExtensions, subpath, state, cache, redirectedReference)
2327+
|| loadModuleFromExports(scope, secondaryExtensions, subpath, state, cache, redirectedReference);
23172328
}
23182329

23192330
function loadModuleFromExports(scope: PackageJsonInfo, extensions: Extensions, subpath: string, state: ModuleResolutionState, cache: ModuleResolutionCache | undefined, redirectedReference: ResolvedProjectReference | undefined): SearchResult<Resolved> {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
=== /node_modules/acorn-walk/dist/walk.d.ts ===
2+
export {};
3+
declare module 'acorn-walk' {
4+
>'acorn-walk' : Symbol("/node_modules/acorn-walk/dist/walk", Decl(walk.d.ts, 0, 0), Decl(walk.d.ts, 0, 10))
5+
6+
export function simple(node: any, visitors: any, base?: any, state?: any): any;
7+
>simple : Symbol(simple, Decl(walk.d.ts, 1, 29))
8+
>node : Symbol(node, Decl(walk.d.ts, 2, 25))
9+
>visitors : Symbol(visitors, Decl(walk.d.ts, 2, 35))
10+
>base : Symbol(base, Decl(walk.d.ts, 2, 50))
11+
>state : Symbol(state, Decl(walk.d.ts, 2, 62))
12+
}
13+
14+
=== /node_modules/acorn-walk/dist/walk.mjs ===
15+
16+
export {};
17+
18+
=== /index.ts ===
19+
import { simple } from 'acorn-walk';
20+
>simple : Symbol(simple, Decl(index.ts, 0, 8))
21+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
[
2+
"======== Resolving module 'acorn-walk' from '/node_modules/acorn-walk/dist/walk.d.ts'. ========",
3+
"Explicitly specified module resolution kind: 'Bundler'.",
4+
"File '/node_modules/acorn-walk/dist/package.json' does not exist.",
5+
"Found 'package.json' at '/node_modules/acorn-walk/package.json'.",
6+
"Matched 'exports' condition 'import'.",
7+
"Using 'exports' subpath '.' with target './dist/walk.mjs'.",
8+
"File name '/node_modules/acorn-walk/dist/walk.mjs' has a '.mjs' extension - stripping it.",
9+
"File '/node_modules/acorn-walk/dist/walk.mts' does not exist.",
10+
"File '/node_modules/acorn-walk/dist/walk.d.mts' does not exist.",
11+
"Saw non-matching condition 'require'.",
12+
"Matched 'exports' condition 'default'.",
13+
"Using 'exports' subpath '.' with target './dist/walk.js'.",
14+
"File name '/node_modules/acorn-walk/dist/walk.js' has a '.js' extension - stripping it.",
15+
"File '/node_modules/acorn-walk/dist/walk.ts' does not exist.",
16+
"File '/node_modules/acorn-walk/dist/walk.tsx' does not exist.",
17+
"File '/node_modules/acorn-walk/dist/walk.d.ts' exist - use it as a name resolution result.",
18+
"Resolving real path for '/node_modules/acorn-walk/dist/walk.d.ts', result '/node_modules/acorn-walk/dist/walk.d.ts'.",
19+
"======== Module name 'acorn-walk' was successfully resolved to '/node_modules/acorn-walk/dist/walk.d.ts' with Package ID 'acorn-walk/dist/[email protected]'. ========",
20+
"======== Resolving module 'acorn-walk' from '/index.ts'. ========",
21+
"Explicitly specified module resolution kind: 'Bundler'.",
22+
"File '/package.json' does not exist.",
23+
"Loading module 'acorn-walk' from 'node_modules' folder, target file types: TypeScript, JavaScript, Declaration, JSON.",
24+
"File '/node_modules/acorn-walk/package.json' exists according to earlier cached lookups.",
25+
"Matched 'exports' condition 'import'.",
26+
"Using 'exports' subpath '.' with target './dist/walk.mjs'.",
27+
"File name '/node_modules/acorn-walk/dist/walk.mjs' has a '.mjs' extension - stripping it.",
28+
"File '/node_modules/acorn-walk/dist/walk.mts' does not exist.",
29+
"File '/node_modules/acorn-walk/dist/walk.d.mts' does not exist.",
30+
"Saw non-matching condition 'require'.",
31+
"Matched 'exports' condition 'default'.",
32+
"Using 'exports' subpath '.' with target './dist/walk.js'.",
33+
"File name '/node_modules/acorn-walk/dist/walk.js' has a '.js' extension - stripping it.",
34+
"File '/node_modules/acorn-walk/dist/walk.ts' does not exist.",
35+
"File '/node_modules/acorn-walk/dist/walk.tsx' does not exist.",
36+
"File '/node_modules/acorn-walk/dist/walk.d.ts' exist - use it as a name resolution result.",
37+
"Resolving real path for '/node_modules/acorn-walk/dist/walk.d.ts', result '/node_modules/acorn-walk/dist/walk.d.ts'.",
38+
"======== Module name 'acorn-walk' was successfully resolved to '/node_modules/acorn-walk/dist/walk.d.ts' with Package ID 'acorn-walk/dist/[email protected]'. ========"
39+
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
=== /node_modules/acorn-walk/dist/walk.d.ts ===
2+
export {};
3+
declare module 'acorn-walk' {
4+
>'acorn-walk' : typeof import("/node_modules/acorn-walk/dist/walk")
5+
6+
export function simple(node: any, visitors: any, base?: any, state?: any): any;
7+
>simple : (node: any, visitors: any, base?: any, state?: any) => any
8+
>node : any
9+
>visitors : any
10+
>base : any
11+
>state : any
12+
}
13+
14+
=== /node_modules/acorn-walk/dist/walk.mjs ===
15+
16+
export {};
17+
18+
=== /index.ts ===
19+
import { simple } from 'acorn-walk';
20+
>simple : (node: any, visitors: any, base?: any, state?: any) => any
21+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// @moduleResolution: bundler
2+
// @allowJs: true
3+
// @noEmit: true
4+
// @traceResolution: true
5+
6+
// @Filename: /node_modules/acorn-walk/package.json
7+
{
8+
"name": "acorn-walk",
9+
"version": "8.2.0",
10+
"main": "dist/walk.js",
11+
"types": "dist/walk.d.ts",
12+
"exports": {
13+
".": [
14+
{
15+
"import": "./dist/walk.mjs",
16+
"require": "./dist/walk.js",
17+
"default": "./dist/walk.js"
18+
},
19+
"./dist/walk.js"
20+
],
21+
"./package.json": "./package.json"
22+
}
23+
}
24+
25+
// The correct behavior for this test would be for both the module augmentation
26+
// and the import to resolve to `walk.mjs` (triggering at least one implicit any
27+
// error, I think?). However, https://github.com/microsoft/TypeScript/issues/50762
28+
// causes the import to resolve through the `default` condition, replacing `.js`
29+
// with `.d.ts` to find `walk.d.ts`. While this is incorrect, it's important that
30+
// the module augmentation, which resolves through self-name resolution, resolves
31+
// to the same module as the external import.
32+
33+
// @Filename: /node_modules/acorn-walk/dist/walk.d.ts
34+
export {};
35+
declare module 'acorn-walk' {
36+
export function simple(node: any, visitors: any, base?: any, state?: any): any;
37+
}
38+
39+
// @Filename: /node_modules/acorn-walk/dist/walk.mjs
40+
export {};
41+
42+
// @Filename: /index.ts
43+
import { simple } from 'acorn-walk';

0 commit comments

Comments
 (0)