Skip to content

Commit c67c68e

Browse files
committed
Sort the paths for module specifier by closeness to importing file path
Fixes #32970
1 parent 2d62050 commit c67c68e

File tree

2 files changed

+47
-3
lines changed

2 files changed

+47
-3
lines changed

src/compiler/moduleSpecifiers.ts

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,18 @@ namespace ts.moduleSpecifiers {
186186
return result;
187187
}
188188

189+
function numberOfDirectorySeparators(str: string) {
190+
const match = str.match(/\//g);
191+
return match ? match.length : 0;
192+
}
193+
194+
function comparePathsByNumberOfDirectrorySeparators(a: string, b: string) {
195+
return compareValues(
196+
numberOfDirectorySeparators(a),
197+
numberOfDirectorySeparators(b)
198+
);
199+
}
200+
189201
/**
190202
* Looks for existing imports that use symlinks to this module.
191203
* Symlinks will be returned first so they are preferred over the real path.
@@ -214,7 +226,32 @@ namespace ts.moduleSpecifiers {
214226
}
215227
});
216228
result.push(...targets);
217-
return result;
229+
if (result.length < 2) return result;
230+
231+
// Sort by paths closest to importing file Name directory
232+
const allFileNames = arrayToMap(result, identity, getCanonicalFileName);
233+
const sortedPaths: string[] = [];
234+
for (
235+
let directory = getDirectoryPath(toPath(importingFileName, cwd, getCanonicalFileName));
236+
allFileNames.size !== 0;
237+
directory = getDirectoryPath(directory)
238+
) {
239+
const directoryStart = ensureTrailingDirectorySeparator(directory);
240+
let pathsInDirectory: string[] | undefined;
241+
allFileNames.forEach((canonicalFileName, fileName) => {
242+
if (startsWith(canonicalFileName, directoryStart)) {
243+
(pathsInDirectory || (pathsInDirectory = [])).push(fileName);
244+
allFileNames.delete(fileName);
245+
}
246+
});
247+
if (pathsInDirectory) {
248+
if (pathsInDirectory.length > 1) {
249+
pathsInDirectory.sort(comparePathsByNumberOfDirectrorySeparators);
250+
}
251+
sortedPaths.push(...pathsInDirectory);
252+
}
253+
}
254+
return sortedPaths;
218255
}
219256

220257
function tryGetModuleNameFromAmbientModule(moduleSymbol: Symbol): string | undefined {

tests/baselines/reference/tsc/declarationEmit/initial-build/when-same-version-is-referenced-through-source-and-another-symlinked-package.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
//// [/lib/initial-buildOutput.txt]
22
/lib/tsc -p plugin-one --listFiles
3-
plugin-one/action.ts(4,14): error TS2742: The inferred type of 'actions' cannot be named without a reference to 'plugin-two/node_modules/typescript-fsa'. This is likely not portable. A type annotation is necessary.
43
/lib/lib.d.ts
54
/plugin-one/node_modules/typescript-fsa/index.d.ts
65
/plugin-one/action.ts
76
/plugin-two/node_modules/typescript-fsa/index.d.ts -> /plugin-one/node_modules/typescript-fsa/index.d.ts
87
/plugin-two/index.d.ts
98
/plugin-one/index.ts
10-
exitCode:: 1
9+
exitCode:: 0
10+
11+
12+
//// [/plugin-one/action.d.ts]
13+
export declare const actions: {
14+
featureOne: import("typescript-fsa").ActionCreator<{
15+
route: string;
16+
}>;
17+
};
1118

1219

1320
//// [/plugin-one/action.js]

0 commit comments

Comments
 (0)