Skip to content

Commit

Permalink
path mappings now supports rooted disk paths and urls - fixes microso…
Browse files Browse the repository at this point in the history
  • Loading branch information
EECOLOR committed Nov 1, 2018
1 parent 7b5ef64 commit a361e89
Show file tree
Hide file tree
Showing 48 changed files with 1,142 additions and 41 deletions.
32 changes: 22 additions & 10 deletions src/compiler/moduleNameResolver.ts
Expand Up @@ -675,6 +675,9 @@ namespace ts {
function tryLoadModuleUsingOptionalResolutionSettings(extensions: Extensions, moduleName: string, containingDirectory: string, loader: ResolutionKindSpecificLoader,
state: ModuleResolutionState): Resolved | undefined {

const resolved = tryLoadModuleUsingPathsIfEligible(extensions, moduleName, loader, state);
if (resolved) return resolved.value;

if (!isExternalModuleNameRelative(moduleName)) {
return tryLoadModuleUsingBaseUrl(extensions, moduleName, loader, state);
}
Expand All @@ -683,6 +686,24 @@ namespace ts {
}
}

function tryLoadModuleUsingPathsIfEligible(extensions: Extensions, moduleName: string, loader: ResolutionKindSpecificLoader, state: ModuleResolutionState) {
const { baseUrl, paths } = state.compilerOptions;
if (baseUrl && paths && isEligibleForPathMapping(moduleName, paths)) {
if (state.traceEnabled) trace(state.host, Diagnostics.paths_option_is_specified_looking_for_a_pattern_to_match_module_name_0, moduleName);
return tryLoadModuleUsingPaths(extensions, moduleName, baseUrl, paths, loader, /*onlyRecordFailures*/ false, state);
}
}

function isEligibleForPathMapping(moduleName: string, paths: MapLike<string[]>): boolean {
if (isRootedDiskPath(moduleName) || isUrl(moduleName)) {
// check for potential alias otherwise { '*': './src/*' } will match
const root = moduleName.slice(0, getRootLength(moduleName));
const potentialAlias = getOwnKeys(paths).find(path => path.startsWith(root));
return Boolean(potentialAlias);
}
else return !pathIsRelative(moduleName);
}

function tryLoadModuleUsingRootDirs(extensions: Extensions, moduleName: string, containingDirectory: string, loader: ResolutionKindSpecificLoader,
state: ModuleResolutionState): Resolved | undefined {

Expand Down Expand Up @@ -761,22 +782,13 @@ namespace ts {
}

function tryLoadModuleUsingBaseUrl(extensions: Extensions, moduleName: string, loader: ResolutionKindSpecificLoader, state: ModuleResolutionState): Resolved | undefined {
const { baseUrl, paths } = state.compilerOptions;
const { baseUrl } = state.compilerOptions;
if (!baseUrl) {
return undefined;
}
if (state.traceEnabled) {
trace(state.host, Diagnostics.baseUrl_option_is_set_to_0_using_this_value_to_resolve_non_relative_module_name_1, baseUrl, moduleName);
}
if (paths) {
if (state.traceEnabled) {
trace(state.host, Diagnostics.paths_option_is_specified_looking_for_a_pattern_to_match_module_name_0, moduleName);
}
const resolved = tryLoadModuleUsingPaths(extensions, moduleName, baseUrl, paths, loader, /*onlyRecordFailures*/ false, state);
if (resolved) {
return resolved.value;
}
}
const candidate = normalizePath(combinePaths(baseUrl, moduleName));
if (state.traceEnabled) {
trace(state.host, Diagnostics.Resolving_module_name_0_relative_to_base_url_1_2, moduleName, baseUrl, candidate);
Expand Down
24 changes: 18 additions & 6 deletions src/services/pathCompletions.ts
Expand Up @@ -26,21 +26,33 @@ namespace ts.Completions.PathCompletions {
const scriptPath = sourceFile.path;
const scriptDirectory = getDirectoryPath(scriptPath);

if (isPathRelativeToScript(literalValue) || isRootedDiskPath(literalValue)) {
const extensions = getSupportedExtensionsForModuleResolution(compilerOptions);
if (compilerOptions.rootDirs) {
return getCompletionEntriesForDirectoryFragmentWithRootDirs(
compilerOptions.rootDirs, literalValue, scriptDirectory, extensions, /*includeExtensions*/ false, compilerOptions, host, scriptPath);
if (isRootedDiskPath(literalValue) || isUrl(literalValue)) {
if (compilerOptions.baseUrl) {
return getCompletionEntriesForNonRelativeModules(literalValue, scriptDirectory, compilerOptions, host, typeChecker);
}
else {
return getCompletionEntriesForDirectoryFragment(literalValue, scriptDirectory, extensions, /*includeExtensions*/ false, host, scriptPath);
return getCompletionEntriesForRelativeModules(literalValue, scriptDirectory, compilerOptions, host, scriptPath);
}
}
else if (isPathRelativeToScript(literalValue)) {
return getCompletionEntriesForRelativeModules(literalValue, scriptDirectory, compilerOptions, host, scriptPath);
}
else {
return getCompletionEntriesForNonRelativeModules(literalValue, scriptDirectory, compilerOptions, host, typeChecker);
}
}

function getCompletionEntriesForRelativeModules(literalValue: string, scriptDirectory: string, compilerOptions: CompilerOptions, host: LanguageServiceHost, scriptPath: Path) {
const extensions = getSupportedExtensionsForModuleResolution(compilerOptions);
if (compilerOptions.rootDirs) {
return getCompletionEntriesForDirectoryFragmentWithRootDirs(
compilerOptions.rootDirs, literalValue, scriptDirectory, extensions, /*includeExtensions*/ false, compilerOptions, host, scriptPath);
}
else {
return getCompletionEntriesForDirectoryFragment(literalValue, scriptDirectory, extensions, /*includeExtensions*/ false, host, scriptPath);
}
}

function getSupportedExtensionsForModuleResolution(compilerOptions: CompilerOptions) {
const extensions = getSupportedExtensions(compilerOptions);
return compilerOptions.resolveJsonModule && getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.NodeJs ?
Expand Down
8 changes: 8 additions & 0 deletions src/testRunner/unittests/moduleResolution.ts
Expand Up @@ -757,6 +757,9 @@ import b = require("./moduleB");
],
"somefolder/*": [
"someanotherfolder/*"
],
"/rooted/*": [
"generated/*"
]
}
};
Expand All @@ -773,6 +776,7 @@ import b = require("./moduleB");
"/root/folder1/file2/index.d.ts",
// then first attempt on 'generated/*' was successful
]);
check("/rooted/folder1/file2", file2, []);
check("folder2/file3", file3, [
// first try '*'
"/root/folder2/file3.ts",
Expand Down Expand Up @@ -900,6 +904,9 @@ import b = require("./moduleB");
],
"somefolder/*": [
"someanotherfolder/*"
],
"/rooted/*": [
"generated/*"
]
}
};
Expand All @@ -911,6 +918,7 @@ import b = require("./moduleB");
"/root/folder1/file2.d.ts",
// success when using 'generated/*'
]);
check("/rooted/folder1/file2", file2, []);
check("folder1/file3", file3, [
// first try '*'
"/root/folder1/file3.ts",
Expand Down
@@ -1,15 +1,13 @@
[
"======== Resolving module 'folder2/file1' from 'c:/root/folder1/file1.ts'. ========",
"Module resolution kind is not specified, using 'Classic'.",
"'baseUrl' option is set to 'c:/root', using this value to resolve non-relative module name 'folder2/file1'.",
"'paths' option is specified, looking for a pattern to match module name 'folder2/file1'.",
"Module name 'folder2/file1', matched pattern '*'.",
"Trying substitution '*', candidate module location: 'folder2/file1'.",
"File 'c:/root/folder2/file1.ts' exist - use it as a name resolution result.",
"======== Module name 'folder2/file1' was successfully resolved to 'c:/root/folder2/file1.ts'. ========",
"======== Resolving module 'folder3/file2' from 'c:/root/folder1/file1.ts'. ========",
"Module resolution kind is not specified, using 'Classic'.",
"'baseUrl' option is set to 'c:/root', using this value to resolve non-relative module name 'folder3/file2'.",
"'paths' option is specified, looking for a pattern to match module name 'folder3/file2'.",
"Module name 'folder3/file2', matched pattern '*'.",
"Trying substitution '*', candidate module location: 'folder3/file2'.",
Expand All @@ -18,15 +16,13 @@
"======== Module name 'folder3/file2' was successfully resolved to 'c:/root/generated/folder3/file2.ts'. ========",
"======== Resolving module 'components/file3' from 'c:/root/folder1/file1.ts'. ========",
"Module resolution kind is not specified, using 'Classic'.",
"'baseUrl' option is set to 'c:/root', using this value to resolve non-relative module name 'components/file3'.",
"'paths' option is specified, looking for a pattern to match module name 'components/file3'.",
"Module name 'components/file3', matched pattern 'components/*'.",
"Trying substitution 'shared/components/*', candidate module location: 'shared/components/file3'.",
"File 'c:/root/shared/components/file3.ts' exist - use it as a name resolution result.",
"======== Module name 'components/file3' was successfully resolved to 'c:/root/shared/components/file3.ts'. ========",
"======== Resolving module 'file4' from 'c:/root/folder1/file1.ts'. ========",
"Module resolution kind is not specified, using 'Classic'.",
"'baseUrl' option is set to 'c:/root', using this value to resolve non-relative module name 'file4'.",
"'paths' option is specified, looking for a pattern to match module name 'file4'.",
"Module name 'file4', matched pattern '*'.",
"Trying substitution '*', candidate module location: 'file4'.",
Expand Down
@@ -1,7 +1,6 @@
[
"======== Resolving module 'folder2/file1' from 'c:/root/folder1/file1.ts'. ========",
"Module resolution kind is not specified, using 'NodeJs'.",
"'baseUrl' option is set to 'c:/root', using this value to resolve non-relative module name 'folder2/file1'.",
"'paths' option is specified, looking for a pattern to match module name 'folder2/file1'.",
"Module name 'folder2/file1', matched pattern '*'.",
"Trying substitution '*', candidate module location: 'folder2/file1'.",
Expand All @@ -10,7 +9,6 @@
"======== Module name 'folder2/file1' was successfully resolved to 'c:/root/folder2/file1.ts'. ========",
"======== Resolving module 'folder3/file2' from 'c:/root/folder1/file1.ts'. ========",
"Module resolution kind is not specified, using 'NodeJs'.",
"'baseUrl' option is set to 'c:/root', using this value to resolve non-relative module name 'folder3/file2'.",
"'paths' option is specified, looking for a pattern to match module name 'folder3/file2'.",
"Module name 'folder3/file2', matched pattern '*'.",
"Trying substitution '*', candidate module location: 'folder3/file2'.",
Expand All @@ -21,7 +19,6 @@
"======== Module name 'folder3/file2' was successfully resolved to 'c:/root/generated/folder3/file2.ts'. ========",
"======== Resolving module 'components/file3' from 'c:/root/folder1/file1.ts'. ========",
"Module resolution kind is not specified, using 'NodeJs'.",
"'baseUrl' option is set to 'c:/root', using this value to resolve non-relative module name 'components/file3'.",
"'paths' option is specified, looking for a pattern to match module name 'components/file3'.",
"Module name 'components/file3', matched pattern 'components/*'.",
"Trying substitution 'shared/components/*', candidate module location: 'shared/components/file3'.",
Expand All @@ -36,7 +33,6 @@
"======== Module name 'components/file3' was successfully resolved to 'c:/root/shared/components/file3/index.d.ts'. ========",
"======== Resolving module 'file4' from 'c:/root/folder1/file1.ts'. ========",
"Module resolution kind is not specified, using 'NodeJs'.",
"'baseUrl' option is set to 'c:/root', using this value to resolve non-relative module name 'file4'.",
"'paths' option is specified, looking for a pattern to match module name 'file4'.",
"Module name 'file4', matched pattern '*'.",
"Trying substitution '*', candidate module location: 'file4'.",
Expand Down
Expand Up @@ -12,7 +12,6 @@
"======== Module name './project/file2' was successfully resolved to 'c:/root/generated/src/project/file2.ts'. ========",
"======== Resolving module 'module3' from 'c:/root/src/file1.ts'. ========",
"Module resolution kind is not specified, using 'Classic'.",
"'baseUrl' option is set to 'c:/root/', using this value to resolve non-relative module name 'module3'.",
"'paths' option is specified, looking for a pattern to match module name 'module3'.",
"Module name 'module3', matched pattern '*'.",
"Trying substitution '*', candidate module location: 'module3'.",
Expand All @@ -35,7 +34,6 @@
"======== Module name 'module3' was successfully resolved to 'c:/module3.d.ts'. ========",
"======== Resolving module 'module1' from 'c:/root/generated/src/project/file2.ts'. ========",
"Module resolution kind is not specified, using 'Classic'.",
"'baseUrl' option is set to 'c:/root/', using this value to resolve non-relative module name 'module1'.",
"'paths' option is specified, looking for a pattern to match module name 'module1'.",
"Module name 'module1', matched pattern '*'.",
"Trying substitution '*', candidate module location: 'module1'.",
Expand All @@ -49,7 +47,6 @@
"======== Module name 'module1' was successfully resolved to 'c:/shared/module1.d.ts'. ========",
"======== Resolving module 'templates/module2' from 'c:/root/generated/src/project/file2.ts'. ========",
"Module resolution kind is not specified, using 'Classic'.",
"'baseUrl' option is set to 'c:/root/', using this value to resolve non-relative module name 'templates/module2'.",
"'paths' option is specified, looking for a pattern to match module name 'templates/module2'.",
"Module name 'templates/module2', matched pattern 'templates/*'.",
"Trying substitution 'generated/src/templates/*', candidate module location: 'generated/src/templates/module2'.",
Expand Down
Expand Up @@ -15,7 +15,6 @@
"======== Module name './project/file2' was successfully resolved to 'c:/root/generated/src/project/file2.ts'. ========",
"======== Resolving module 'module3' from 'c:/root/src/file1.ts'. ========",
"Module resolution kind is not specified, using 'NodeJs'.",
"'baseUrl' option is set to 'c:/root/', using this value to resolve non-relative module name 'module3'.",
"'paths' option is specified, looking for a pattern to match module name 'module3'.",
"Module name 'module3', matched pattern '*'.",
"Trying substitution '*', candidate module location: 'module3'.",
Expand All @@ -40,7 +39,6 @@
"======== Module name 'module3' was successfully resolved to 'c:/node_modules/module3.d.ts'. ========",
"======== Resolving module 'module1' from 'c:/root/generated/src/project/file2.ts'. ========",
"Module resolution kind is not specified, using 'NodeJs'.",
"'baseUrl' option is set to 'c:/root/', using this value to resolve non-relative module name 'module1'.",
"'paths' option is specified, looking for a pattern to match module name 'module1'.",
"Module name 'module1', matched pattern '*'.",
"Trying substitution '*', candidate module location: 'module1'.",
Expand All @@ -61,7 +59,6 @@
"======== Module name 'module1' was successfully resolved to 'c:/shared/module1/index.d.ts'. ========",
"======== Resolving module 'templates/module2' from 'c:/root/generated/src/project/file2.ts'. ========",
"Module resolution kind is not specified, using 'NodeJs'.",
"'baseUrl' option is set to 'c:/root/', using this value to resolve non-relative module name 'templates/module2'.",
"'paths' option is specified, looking for a pattern to match module name 'templates/module2'.",
"Module name 'templates/module2', matched pattern 'templates/*'.",
"Trying substitution 'generated/src/templates/*', candidate module location: 'generated/src/templates/module2'.",
Expand Down
@@ -1,7 +1,6 @@
[
"======== Resolving module '@speedy/folder1/testing' from 'c:/root/index.ts'. ========",
"Explicitly specified module resolution kind: 'Classic'.",
"'baseUrl' option is set to 'c:/root', using this value to resolve non-relative module name '@speedy/folder1/testing'.",
"'paths' option is specified, looking for a pattern to match module name '@speedy/folder1/testing'.",
"Module name '@speedy/folder1/testing', matched pattern '@speedy/*/testing'.",
"Trying substitution '*/dist/index.ts', candidate module location: 'folder1/dist/index.ts'.",
Expand Down
@@ -1,7 +1,6 @@
[
"======== Resolving module '@speedy/folder1/testing' from 'c:/root/index.ts'. ========",
"Explicitly specified module resolution kind: 'NodeJs'.",
"'baseUrl' option is set to 'c:/root', using this value to resolve non-relative module name '@speedy/folder1/testing'.",
"'paths' option is specified, looking for a pattern to match module name '@speedy/folder1/testing'.",
"Module name '@speedy/folder1/testing', matched pattern '@speedy/*/testing'.",
"Trying substitution '*/dist/index.ts', candidate module location: 'folder1/dist/index.ts'.",
Expand Down
@@ -0,0 +1,26 @@
//// [tests/cases/compiler/pathMappingBasedModuleResolution_rootImport_aliasWithRoot.ts] ////

//// [foo.ts]
export function foo() {}

//// [bar.js]
export function bar() {}

//// [a.ts]
import { foo } from "/foo";
import { bar } from "/bar";


//// [foo.js]
"use strict";
exports.__esModule = true;
function foo() { }
exports.foo = foo;
//// [bar.js]
"use strict";
exports.__esModule = true;
function bar() { }
exports.bar = bar;
//// [a.js]
"use strict";
exports.__esModule = true;
@@ -0,0 +1,15 @@
=== /root/a.ts ===
import { foo } from "/foo";
>foo : Symbol(foo, Decl(a.ts, 0, 8))

import { bar } from "/bar";
>bar : Symbol(bar, Decl(a.ts, 1, 8))

=== /root/src/foo.ts ===
export function foo() {}
>foo : Symbol(foo, Decl(foo.ts, 0, 0))

=== /root/src/bar.js ===
export function bar() {}
>bar : Symbol(bar, Decl(bar.js, 0, 0))

0 comments on commit a361e89

Please sign in to comment.