Skip to content

Commit aadfa61

Browse files
committed
path mappings now supports rooted disk paths and urls - fixes #13730
1 parent eabbaa4 commit aadfa61

File tree

48 files changed

+1142
-41
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1142
-41
lines changed

src/compiler/moduleNameResolver.ts

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -730,6 +730,9 @@ namespace ts {
730730
function tryLoadModuleUsingOptionalResolutionSettings(extensions: Extensions, moduleName: string, containingDirectory: string, loader: ResolutionKindSpecificLoader,
731731
state: ModuleResolutionState): Resolved | undefined {
732732

733+
const resolved = tryLoadModuleUsingPathsIfEligible(extensions, moduleName, loader, state);
734+
if (resolved) return resolved.value;
735+
733736
if (!isExternalModuleNameRelative(moduleName)) {
734737
return tryLoadModuleUsingBaseUrl(extensions, moduleName, loader, state);
735738
}
@@ -738,6 +741,24 @@ namespace ts {
738741
}
739742
}
740743

744+
function tryLoadModuleUsingPathsIfEligible(extensions: Extensions, moduleName: string, loader: ResolutionKindSpecificLoader, state: ModuleResolutionState) {
745+
const { baseUrl, paths } = state.compilerOptions;
746+
if (baseUrl && paths && isEligibleForPathMapping(moduleName, paths)) {
747+
if (state.traceEnabled) trace(state.host, Diagnostics.paths_option_is_specified_looking_for_a_pattern_to_match_module_name_0, moduleName);
748+
return tryLoadModuleUsingPaths(extensions, moduleName, baseUrl, paths, loader, /*onlyRecordFailures*/ false, state);
749+
}
750+
}
751+
752+
function isEligibleForPathMapping(moduleName: string, paths: MapLike<string[]>): boolean {
753+
if (isRootedDiskPath(moduleName) || isUrl(moduleName)) {
754+
// check for potential alias otherwise { '*': './src/*' } will match
755+
const root = moduleName.slice(0, getRootLength(moduleName));
756+
const potentialAlias = find(getOwnKeys(paths), path => startsWith(path, root));
757+
return !!potentialAlias;
758+
}
759+
else return !pathIsRelative(moduleName);
760+
}
761+
741762
function tryLoadModuleUsingRootDirs(extensions: Extensions, moduleName: string, containingDirectory: string, loader: ResolutionKindSpecificLoader,
742763
state: ModuleResolutionState): Resolved | undefined {
743764

@@ -816,22 +837,13 @@ namespace ts {
816837
}
817838

818839
function tryLoadModuleUsingBaseUrl(extensions: Extensions, moduleName: string, loader: ResolutionKindSpecificLoader, state: ModuleResolutionState): Resolved | undefined {
819-
const { baseUrl, paths } = state.compilerOptions;
840+
const { baseUrl } = state.compilerOptions;
820841
if (!baseUrl) {
821842
return undefined;
822843
}
823844
if (state.traceEnabled) {
824845
trace(state.host, Diagnostics.baseUrl_option_is_set_to_0_using_this_value_to_resolve_non_relative_module_name_1, baseUrl, moduleName);
825846
}
826-
if (paths) {
827-
if (state.traceEnabled) {
828-
trace(state.host, Diagnostics.paths_option_is_specified_looking_for_a_pattern_to_match_module_name_0, moduleName);
829-
}
830-
const resolved = tryLoadModuleUsingPaths(extensions, moduleName, baseUrl, paths, loader, /*onlyRecordFailures*/ false, state);
831-
if (resolved) {
832-
return resolved.value;
833-
}
834-
}
835847
const candidate = normalizePath(combinePaths(baseUrl, moduleName));
836848
if (state.traceEnabled) {
837849
trace(state.host, Diagnostics.Resolving_module_name_0_relative_to_base_url_1_2, moduleName, baseUrl, candidate);

src/services/stringCompletions.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -247,16 +247,17 @@ namespace ts.Completions.StringCompletions {
247247
const scriptPath = sourceFile.path;
248248
const scriptDirectory = getDirectoryPath(scriptPath);
249249

250-
const extensionOptions = getExtensionOptions(compilerOptions);
251-
if (isPathRelativeToScript(literalValue) || isRootedDiskPath(literalValue)) {
252-
if (compilerOptions.rootDirs) {
253-
return getCompletionEntriesForDirectoryFragmentWithRootDirs(
254-
compilerOptions.rootDirs, literalValue, scriptDirectory, extensionOptions, compilerOptions, host, scriptPath);
250+
if (isRootedDiskPath(literalValue) || isUrl(literalValue)) {
251+
if (compilerOptions.baseUrl) {
252+
return getCompletionEntriesForNonRelativeModules(literalValue, scriptDirectory, compilerOptions, host, typeChecker);
255253
}
256254
else {
257-
return getCompletionEntriesForDirectoryFragment(literalValue, scriptDirectory, extensionOptions, host, scriptPath);
255+
return getCompletionEntriesForRelativeModules(literalValue, scriptDirectory, compilerOptions, host, scriptPath);
258256
}
259257
}
258+
else if (isPathRelativeToScript(literalValue)) {
259+
return getCompletionEntriesForRelativeModules(literalValue, scriptDirectory, compilerOptions, host, scriptPath);
260+
}
260261
else {
261262
return getCompletionEntriesForNonRelativeModules(literalValue, scriptDirectory, compilerOptions, host, typeChecker);
262263
}
@@ -269,6 +270,17 @@ namespace ts.Completions.StringCompletions {
269270
function getExtensionOptions(compilerOptions: CompilerOptions, includeExtensions = false): ExtensionOptions {
270271
return { extensions: getSupportedExtensionsForModuleResolution(compilerOptions), includeExtensions };
271272
}
273+
function getCompletionEntriesForRelativeModules(literalValue: string, scriptDirectory: string, compilerOptions: CompilerOptions, host: LanguageServiceHost, scriptPath: Path) {
274+
const extensionOptions = getExtensionOptions(compilerOptions);
275+
if (compilerOptions.rootDirs) {
276+
return getCompletionEntriesForDirectoryFragmentWithRootDirs(
277+
compilerOptions.rootDirs, literalValue, scriptDirectory, extensionOptions, compilerOptions, host, scriptPath);
278+
}
279+
else {
280+
return getCompletionEntriesForDirectoryFragment(literalValue, scriptDirectory, extensionOptions, host, scriptPath);
281+
}
282+
}
283+
272284
function getSupportedExtensionsForModuleResolution(compilerOptions: CompilerOptions): ReadonlyArray<Extension> {
273285
const extensions = getSupportedExtensions(compilerOptions);
274286
return compilerOptions.resolveJsonModule && getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.NodeJs ?

src/testRunner/unittests/moduleResolution.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -757,6 +757,9 @@ import b = require("./moduleB");
757757
],
758758
"somefolder/*": [
759759
"someanotherfolder/*"
760+
],
761+
"/rooted/*": [
762+
"generated/*"
760763
]
761764
}
762765
};
@@ -773,6 +776,7 @@ import b = require("./moduleB");
773776
"/root/folder1/file2/index.d.ts",
774777
// then first attempt on 'generated/*' was successful
775778
]);
779+
check("/rooted/folder1/file2", file2, []);
776780
check("folder2/file3", file3, [
777781
// first try '*'
778782
"/root/folder2/file3.ts",
@@ -900,6 +904,9 @@ import b = require("./moduleB");
900904
],
901905
"somefolder/*": [
902906
"someanotherfolder/*"
907+
],
908+
"/rooted/*": [
909+
"generated/*"
903910
]
904911
}
905912
};
@@ -911,6 +918,7 @@ import b = require("./moduleB");
911918
"/root/folder1/file2.d.ts",
912919
// success when using 'generated/*'
913920
]);
921+
check("/rooted/folder1/file2", file2, []);
914922
check("folder1/file3", file3, [
915923
// first try '*'
916924
"/root/folder1/file3.ts",

tests/baselines/reference/pathMappingBasedModuleResolution5_classic.trace.json

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
[
22
"======== Resolving module 'folder2/file1' from 'c:/root/folder1/file1.ts'. ========",
33
"Module resolution kind is not specified, using 'Classic'.",
4-
"'baseUrl' option is set to 'c:/root', using this value to resolve non-relative module name 'folder2/file1'.",
54
"'paths' option is specified, looking for a pattern to match module name 'folder2/file1'.",
65
"Module name 'folder2/file1', matched pattern '*'.",
76
"Trying substitution '*', candidate module location: 'folder2/file1'.",
87
"File 'c:/root/folder2/file1.ts' exist - use it as a name resolution result.",
98
"======== Module name 'folder2/file1' was successfully resolved to 'c:/root/folder2/file1.ts'. ========",
109
"======== Resolving module 'folder3/file2' from 'c:/root/folder1/file1.ts'. ========",
1110
"Module resolution kind is not specified, using 'Classic'.",
12-
"'baseUrl' option is set to 'c:/root', using this value to resolve non-relative module name 'folder3/file2'.",
1311
"'paths' option is specified, looking for a pattern to match module name 'folder3/file2'.",
1412
"Module name 'folder3/file2', matched pattern '*'.",
1513
"Trying substitution '*', candidate module location: 'folder3/file2'.",
@@ -18,15 +16,13 @@
1816
"======== Module name 'folder3/file2' was successfully resolved to 'c:/root/generated/folder3/file2.ts'. ========",
1917
"======== Resolving module 'components/file3' from 'c:/root/folder1/file1.ts'. ========",
2018
"Module resolution kind is not specified, using 'Classic'.",
21-
"'baseUrl' option is set to 'c:/root', using this value to resolve non-relative module name 'components/file3'.",
2219
"'paths' option is specified, looking for a pattern to match module name 'components/file3'.",
2320
"Module name 'components/file3', matched pattern 'components/*'.",
2421
"Trying substitution 'shared/components/*', candidate module location: 'shared/components/file3'.",
2522
"File 'c:/root/shared/components/file3.ts' exist - use it as a name resolution result.",
2623
"======== Module name 'components/file3' was successfully resolved to 'c:/root/shared/components/file3.ts'. ========",
2724
"======== Resolving module 'file4' from 'c:/root/folder1/file1.ts'. ========",
2825
"Module resolution kind is not specified, using 'Classic'.",
29-
"'baseUrl' option is set to 'c:/root', using this value to resolve non-relative module name 'file4'.",
3026
"'paths' option is specified, looking for a pattern to match module name 'file4'.",
3127
"Module name 'file4', matched pattern '*'.",
3228
"Trying substitution '*', candidate module location: 'file4'.",

tests/baselines/reference/pathMappingBasedModuleResolution5_node.trace.json

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
[
22
"======== Resolving module 'folder2/file1' from 'c:/root/folder1/file1.ts'. ========",
33
"Module resolution kind is not specified, using 'NodeJs'.",
4-
"'baseUrl' option is set to 'c:/root', using this value to resolve non-relative module name 'folder2/file1'.",
54
"'paths' option is specified, looking for a pattern to match module name 'folder2/file1'.",
65
"Module name 'folder2/file1', matched pattern '*'.",
76
"Trying substitution '*', candidate module location: 'folder2/file1'.",
@@ -10,7 +9,6 @@
109
"======== Module name 'folder2/file1' was successfully resolved to 'c:/root/folder2/file1.ts'. ========",
1110
"======== Resolving module 'folder3/file2' from 'c:/root/folder1/file1.ts'. ========",
1211
"Module resolution kind is not specified, using 'NodeJs'.",
13-
"'baseUrl' option is set to 'c:/root', using this value to resolve non-relative module name 'folder3/file2'.",
1412
"'paths' option is specified, looking for a pattern to match module name 'folder3/file2'.",
1513
"Module name 'folder3/file2', matched pattern '*'.",
1614
"Trying substitution '*', candidate module location: 'folder3/file2'.",
@@ -21,7 +19,6 @@
2119
"======== Module name 'folder3/file2' was successfully resolved to 'c:/root/generated/folder3/file2.ts'. ========",
2220
"======== Resolving module 'components/file3' from 'c:/root/folder1/file1.ts'. ========",
2321
"Module resolution kind is not specified, using 'NodeJs'.",
24-
"'baseUrl' option is set to 'c:/root', using this value to resolve non-relative module name 'components/file3'.",
2522
"'paths' option is specified, looking for a pattern to match module name 'components/file3'.",
2623
"Module name 'components/file3', matched pattern 'components/*'.",
2724
"Trying substitution 'shared/components/*', candidate module location: 'shared/components/file3'.",
@@ -36,7 +33,6 @@
3633
"======== Module name 'components/file3' was successfully resolved to 'c:/root/shared/components/file3/index.d.ts'. ========",
3734
"======== Resolving module 'file4' from 'c:/root/folder1/file1.ts'. ========",
3835
"Module resolution kind is not specified, using 'NodeJs'.",
39-
"'baseUrl' option is set to 'c:/root', using this value to resolve non-relative module name 'file4'.",
4036
"'paths' option is specified, looking for a pattern to match module name 'file4'.",
4137
"Module name 'file4', matched pattern '*'.",
4238
"Trying substitution '*', candidate module location: 'file4'.",

tests/baselines/reference/pathMappingBasedModuleResolution7_classic.trace.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
"======== Module name './project/file2' was successfully resolved to 'c:/root/generated/src/project/file2.ts'. ========",
1313
"======== Resolving module 'module3' from 'c:/root/src/file1.ts'. ========",
1414
"Module resolution kind is not specified, using 'Classic'.",
15-
"'baseUrl' option is set to 'c:/root/', using this value to resolve non-relative module name 'module3'.",
1615
"'paths' option is specified, looking for a pattern to match module name 'module3'.",
1716
"Module name 'module3', matched pattern '*'.",
1817
"Trying substitution '*', candidate module location: 'module3'.",
@@ -35,7 +34,6 @@
3534
"======== Module name 'module3' was successfully resolved to 'c:/module3.d.ts'. ========",
3635
"======== Resolving module 'module1' from 'c:/root/generated/src/project/file2.ts'. ========",
3736
"Module resolution kind is not specified, using 'Classic'.",
38-
"'baseUrl' option is set to 'c:/root/', using this value to resolve non-relative module name 'module1'.",
3937
"'paths' option is specified, looking for a pattern to match module name 'module1'.",
4038
"Module name 'module1', matched pattern '*'.",
4139
"Trying substitution '*', candidate module location: 'module1'.",
@@ -49,7 +47,6 @@
4947
"======== Module name 'module1' was successfully resolved to 'c:/shared/module1.d.ts'. ========",
5048
"======== Resolving module 'templates/module2' from 'c:/root/generated/src/project/file2.ts'. ========",
5149
"Module resolution kind is not specified, using 'Classic'.",
52-
"'baseUrl' option is set to 'c:/root/', using this value to resolve non-relative module name 'templates/module2'.",
5350
"'paths' option is specified, looking for a pattern to match module name 'templates/module2'.",
5451
"Module name 'templates/module2', matched pattern 'templates/*'.",
5552
"Trying substitution 'generated/src/templates/*', candidate module location: 'generated/src/templates/module2'.",

tests/baselines/reference/pathMappingBasedModuleResolution7_node.trace.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
"======== Module name './project/file2' was successfully resolved to 'c:/root/generated/src/project/file2.ts'. ========",
1616
"======== Resolving module 'module3' from 'c:/root/src/file1.ts'. ========",
1717
"Module resolution kind is not specified, using 'NodeJs'.",
18-
"'baseUrl' option is set to 'c:/root/', using this value to resolve non-relative module name 'module3'.",
1918
"'paths' option is specified, looking for a pattern to match module name 'module3'.",
2019
"Module name 'module3', matched pattern '*'.",
2120
"Trying substitution '*', candidate module location: 'module3'.",
@@ -40,7 +39,6 @@
4039
"======== Module name 'module3' was successfully resolved to 'c:/node_modules/module3.d.ts'. ========",
4140
"======== Resolving module 'module1' from 'c:/root/generated/src/project/file2.ts'. ========",
4241
"Module resolution kind is not specified, using 'NodeJs'.",
43-
"'baseUrl' option is set to 'c:/root/', using this value to resolve non-relative module name 'module1'.",
4442
"'paths' option is specified, looking for a pattern to match module name 'module1'.",
4543
"Module name 'module1', matched pattern '*'.",
4644
"Trying substitution '*', candidate module location: 'module1'.",
@@ -61,7 +59,6 @@
6159
"======== Module name 'module1' was successfully resolved to 'c:/shared/module1/index.d.ts'. ========",
6260
"======== Resolving module 'templates/module2' from 'c:/root/generated/src/project/file2.ts'. ========",
6361
"Module resolution kind is not specified, using 'NodeJs'.",
64-
"'baseUrl' option is set to 'c:/root/', using this value to resolve non-relative module name 'templates/module2'.",
6562
"'paths' option is specified, looking for a pattern to match module name 'templates/module2'.",
6663
"Module name 'templates/module2', matched pattern 'templates/*'.",
6764
"Trying substitution 'generated/src/templates/*', candidate module location: 'generated/src/templates/module2'.",

tests/baselines/reference/pathMappingBasedModuleResolution8_classic.trace.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
[
22
"======== Resolving module '@speedy/folder1/testing' from 'c:/root/index.ts'. ========",
33
"Explicitly specified module resolution kind: 'Classic'.",
4-
"'baseUrl' option is set to 'c:/root', using this value to resolve non-relative module name '@speedy/folder1/testing'.",
54
"'paths' option is specified, looking for a pattern to match module name '@speedy/folder1/testing'.",
65
"Module name '@speedy/folder1/testing', matched pattern '@speedy/*/testing'.",
76
"Trying substitution '*/dist/index.ts', candidate module location: 'folder1/dist/index.ts'.",

tests/baselines/reference/pathMappingBasedModuleResolution8_node.trace.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
[
22
"======== Resolving module '@speedy/folder1/testing' from 'c:/root/index.ts'. ========",
33
"Explicitly specified module resolution kind: 'NodeJs'.",
4-
"'baseUrl' option is set to 'c:/root', using this value to resolve non-relative module name '@speedy/folder1/testing'.",
54
"'paths' option is specified, looking for a pattern to match module name '@speedy/folder1/testing'.",
65
"Module name '@speedy/folder1/testing', matched pattern '@speedy/*/testing'.",
76
"Trying substitution '*/dist/index.ts', candidate module location: 'folder1/dist/index.ts'.",
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//// [tests/cases/compiler/pathMappingBasedModuleResolution_rootImport_aliasWithRoot.ts] ////
2+
3+
//// [foo.ts]
4+
export function foo() {}
5+
6+
//// [bar.js]
7+
export function bar() {}
8+
9+
//// [a.ts]
10+
import { foo } from "/foo";
11+
import { bar } from "/bar";
12+
13+
14+
//// [foo.js]
15+
"use strict";
16+
exports.__esModule = true;
17+
function foo() { }
18+
exports.foo = foo;
19+
//// [bar.js]
20+
"use strict";
21+
exports.__esModule = true;
22+
function bar() { }
23+
exports.bar = bar;
24+
//// [a.js]
25+
"use strict";
26+
exports.__esModule = true;
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
=== /root/a.ts ===
2+
import { foo } from "/foo";
3+
>foo : Symbol(foo, Decl(a.ts, 0, 8))
4+
5+
import { bar } from "/bar";
6+
>bar : Symbol(bar, Decl(a.ts, 1, 8))
7+
8+
=== /root/src/foo.ts ===
9+
export function foo() {}
10+
>foo : Symbol(foo, Decl(foo.ts, 0, 0))
11+
12+
=== /root/src/bar.js ===
13+
export function bar() {}
14+
>bar : Symbol(bar, Decl(bar.js, 0, 0))
15+

0 commit comments

Comments
 (0)