Skip to content

Commit 2ac4cb7

Browse files
authored
Fix prioritization of paths specifiers over node_modules package specifiers (#60238)
1 parent db8eacd commit 2ac4cb7

File tree

2 files changed

+62
-38
lines changed

2 files changed

+62
-38
lines changed

src/compiler/moduleSpecifiers.ts

Lines changed: 36 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -508,46 +508,44 @@ function computeModuleSpecifiers(
508508
}
509509
}
510510

511-
if (!specifier) {
512-
const local = getLocalModuleSpecifier(
513-
modulePath.path,
514-
info,
515-
compilerOptions,
516-
host,
517-
options.overrideImportMode || importingSourceFile.impliedNodeFormat,
518-
preferences,
519-
/*pathsOnly*/ modulePath.isRedirect,
520-
);
521-
if (!local || forAutoImport && isExcludedByRegex(local, preferences.excludeRegexes)) {
522-
continue;
523-
}
524-
if (modulePath.isRedirect) {
525-
redirectPathsSpecifiers = append(redirectPathsSpecifiers, local);
526-
}
527-
else if (pathIsBareSpecifier(local)) {
528-
if (pathContainsNodeModules(local)) {
529-
// We could be in this branch due to inappropriate use of `baseUrl`, not intentional `paths`
530-
// usage. It's impossible to reason about where to prioritize baseUrl-generated module
531-
// specifiers, but if they contain `/node_modules/`, they're going to trigger a portability
532-
// error, so *at least* don't prioritize those.
533-
relativeSpecifiers = append(relativeSpecifiers, local);
534-
}
535-
else {
536-
pathsSpecifiers = append(pathsSpecifiers, local);
537-
}
538-
}
539-
else if (forAutoImport || !importedFileIsInNodeModules || modulePath.isInNodeModules) {
540-
// Why this extra conditional, not just an `else`? If some path to the file contained
541-
// 'node_modules', but we can't create a non-relative specifier (e.g. "@foo/bar/path/to/file"),
542-
// that means we had to go through a *sibling's* node_modules, not one we can access directly.
543-
// If some path to the file was in node_modules but another was not, this likely indicates that
544-
// we have a monorepo structure with symlinks. In this case, the non-node_modules path is
545-
// probably the realpath, e.g. "../bar/path/to/file", but a relative path to another package
546-
// in a monorepo is probably not portable. So, the module specifier we actually go with will be
547-
// the relative path through node_modules, so that the declaration emitter can produce a
548-
// portability error. (See declarationEmitReexportedSymlinkReference3)
511+
const local = getLocalModuleSpecifier(
512+
modulePath.path,
513+
info,
514+
compilerOptions,
515+
host,
516+
options.overrideImportMode || importingSourceFile.impliedNodeFormat,
517+
preferences,
518+
/*pathsOnly*/ modulePath.isRedirect || !!specifier,
519+
);
520+
if (!local || forAutoImport && isExcludedByRegex(local, preferences.excludeRegexes)) {
521+
continue;
522+
}
523+
if (modulePath.isRedirect) {
524+
redirectPathsSpecifiers = append(redirectPathsSpecifiers, local);
525+
}
526+
else if (pathIsBareSpecifier(local)) {
527+
if (pathContainsNodeModules(local)) {
528+
// We could be in this branch due to inappropriate use of `baseUrl`, not intentional `paths`
529+
// usage. It's impossible to reason about where to prioritize baseUrl-generated module
530+
// specifiers, but if they contain `/node_modules/`, they're going to trigger a portability
531+
// error, so *at least* don't prioritize those.
549532
relativeSpecifiers = append(relativeSpecifiers, local);
550533
}
534+
else {
535+
pathsSpecifiers = append(pathsSpecifiers, local);
536+
}
537+
}
538+
else if (forAutoImport || !importedFileIsInNodeModules || modulePath.isInNodeModules) {
539+
// Why this extra conditional, not just an `else`? If some path to the file contained
540+
// 'node_modules', but we can't create a non-relative specifier (e.g. "@foo/bar/path/to/file"),
541+
// that means we had to go through a *sibling's* node_modules, not one we can access directly.
542+
// If some path to the file was in node_modules but another was not, this likely indicates that
543+
// we have a monorepo structure with symlinks. In this case, the non-node_modules path is
544+
// probably the realpath, e.g. "../bar/path/to/file", but a relative path to another package
545+
// in a monorepo is probably not portable. So, the module specifier we actually go with will be
546+
// the relative path through node_modules, so that the declaration emitter can produce a
547+
// portability error. (See declarationEmitReexportedSymlinkReference3)
548+
relativeSpecifiers = append(relativeSpecifiers, local);
551549
}
552550
}
553551

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @Filename: tsconfig.json
4+
//// {
5+
//// "compilerOptions": {
6+
//// "module": "amd",
7+
//// "moduleResolution": "node",
8+
//// "rootDir": "ts",
9+
//// "baseUrl": ".",
10+
//// "paths": {
11+
//// "*": ["node_modules/@woltlab/wcf/ts/*"]
12+
//// }
13+
//// },
14+
//// "include": [
15+
//// "ts",
16+
//// "node_modules/@woltlab/wcf/ts",
17+
//// ]
18+
//// }
19+
20+
// @Filename: node_modules/@woltlab/wcf/ts/WoltLabSuite/Core/Component/Dialog.ts
21+
//// export class Dialog {}
22+
23+
// @Filename: ts/main.ts
24+
//// Dialog/**/
25+
26+
verify.importFixModuleSpecifiers("", ["WoltLabSuite/Core/Component/Dialog"]);

0 commit comments

Comments
 (0)