Allow a path mapping to provide a file extension

This commit is contained in:
Andy Hanson
2016-11-08 06:56:24 -08:00
parent 2282477012
commit 1c64615e32
11 changed files with 157 additions and 8 deletions

View File

@@ -2210,6 +2210,17 @@ namespace ts {
* Path must have a valid extension.
*/
export function extensionFromPath(path: string): Extension {
const ts = tryGetTypeScriptExtensionFromPath(path);
if (ts !== undefined) {
return ts;
}
const js = tryGetJavaScriptExtensionFromPath(path);
if (js !== undefined) {
return js;
}
Debug.fail(`File ${path} has unknown extension.`);
}
export function tryGetTypeScriptExtensionFromPath(path: string): Extension | undefined {
if (fileExtensionIs(path, ".d.ts")) {
return Extension.Dts;
}
@@ -2219,13 +2230,13 @@ namespace ts {
if (fileExtensionIs(path, ".tsx")) {
return Extension.Tsx;
}
}
function tryGetJavaScriptExtensionFromPath(path: string): Extension | undefined {
if (fileExtensionIs(path, ".js")) {
return Extension.Js;
}
if (fileExtensionIs(path, ".jsx")) {
return Extension.Jsx;
}
Debug.fail(`File ${path} has unknown extension.`);
return Extension.Js;
}
}

View File

@@ -514,18 +514,21 @@ namespace ts {
if (state.traceEnabled) {
trace(state.host, Diagnostics.Module_name_0_matched_pattern_1, moduleName, matchedPatternText);
}
for (const subst of state.compilerOptions.paths[matchedPatternText]) {
return forEach(state.compilerOptions.paths[matchedPatternText], subst => {
const path = matchedStar ? subst.replace("*", matchedStar) : subst;
const candidate = normalizePath(combinePaths(state.compilerOptions.baseUrl, path));
if (state.traceEnabled) {
trace(state.host, Diagnostics.Trying_substitution_0_candidate_module_location_Colon_1, subst, path);
}
const resolved = loader(extensions, candidate, failedLookupLocations, !directoryProbablyExists(getDirectoryPath(candidate), state.host), state);
if (resolved) {
return resolved;
// A path mapping may have a ".ts" extension; in contrast to an import, which should omit it.
const tsExtension = tryGetTypeScriptExtensionFromPath(candidate);
if (tsExtension !== undefined) {
const path = tryFile(candidate, failedLookupLocations, /*onlyRecordFailures*/false, state);
return path && { path, extension: tsExtension };
}
}
return undefined;
return loader(extensions, candidate, failedLookupLocations, !directoryProbablyExists(getDirectoryPath(candidate), state.host), state);
});
}
else {
const candidate = normalizePath(combinePaths(state.compilerOptions.baseUrl, moduleName));

View File

@@ -0,0 +1,16 @@
//// [tests/cases/compiler/pathMappingBasedModuleResolution_withExtension.ts] ////
//// [foo.ts]
export function foo() {}
//// [a.ts]
import { foo } from "foo";
//// [foo.js]
"use strict";
function foo() { }
exports.foo = foo;
//// [a.js]
"use strict";

View File

@@ -0,0 +1,9 @@
=== /a.ts ===
import { foo } from "foo";
>foo : Symbol(foo, Decl(a.ts, 0, 8))
=== /foo/foo.ts ===
export function foo() {}
>foo : Symbol(foo, Decl(foo.ts, 0, 0))

View File

@@ -0,0 +1,11 @@
[
"======== Resolving module 'foo' from '/a.ts'. ========",
"Module resolution kind is not specified, using 'NodeJs'.",
"'baseUrl' option is set to '/', using this value to resolve non-relative module name 'foo'",
"'paths' option is specified, looking for a pattern to match module name 'foo'.",
"Module name 'foo', matched pattern 'foo'.",
"Trying substitution 'foo/foo.ts', candidate module location: 'foo/foo.ts'.",
"File '/foo/foo.ts' exist - use it as a name resolution result.",
"Resolving real path for '/foo/foo.ts', result '/foo/foo.ts'",
"======== Module name 'foo' was successfully resolved to '/foo/foo.ts'. ========"
]

View File

@@ -0,0 +1,9 @@
=== /a.ts ===
import { foo } from "foo";
>foo : () => void
=== /foo/foo.ts ===
export function foo() {}
>foo : () => void

View File

@@ -0,0 +1,9 @@
/a.ts(2,21): error TS2307: Cannot find module 'foo'.
==== /a.ts (1 errors) ====
import { foo } from "foo";
~~~~~
!!! error TS2307: Cannot find module 'foo'.

View File

@@ -0,0 +1,7 @@
//// [a.ts]
import { foo } from "foo";
//// [a.js]
"use strict";

View File

@@ -0,0 +1,41 @@
[
"======== Resolving module 'foo' from '/a.ts'. ========",
"Module resolution kind is not specified, using 'NodeJs'.",
"'baseUrl' option is set to '/', using this value to resolve non-relative module name 'foo'",
"'paths' option is specified, looking for a pattern to match module name 'foo'.",
"Module name 'foo', matched pattern 'foo'.",
"Trying substitution 'foo/foo.ts', candidate module location: 'foo/foo.ts'.",
"File '/foo/foo.ts' does not exist.",
"Loading module 'foo' from 'node_modules' folder.",
"File '/node_modules/foo.ts' does not exist.",
"File '/node_modules/foo.tsx' does not exist.",
"File '/node_modules/foo.d.ts' does not exist.",
"File '/node_modules/foo/package.json' does not exist.",
"File '/node_modules/foo/index.ts' does not exist.",
"File '/node_modules/foo/index.tsx' does not exist.",
"File '/node_modules/foo/index.d.ts' does not exist.",
"File '/node_modules/@types/foo.ts' does not exist.",
"File '/node_modules/@types/foo.tsx' does not exist.",
"File '/node_modules/@types/foo.d.ts' does not exist.",
"File '/node_modules/@types/foo/package.json' does not exist.",
"File '/node_modules/@types/foo/index.ts' does not exist.",
"File '/node_modules/@types/foo/index.tsx' does not exist.",
"File '/node_modules/@types/foo/index.d.ts' does not exist.",
"'baseUrl' option is set to '/', using this value to resolve non-relative module name 'foo'",
"'paths' option is specified, looking for a pattern to match module name 'foo'.",
"Module name 'foo', matched pattern 'foo'.",
"Trying substitution 'foo/foo.ts', candidate module location: 'foo/foo.ts'.",
"File '/foo/foo.ts' does not exist.",
"Loading module 'foo' from 'node_modules' folder.",
"File '/node_modules/foo.js' does not exist.",
"File '/node_modules/foo.jsx' does not exist.",
"File '/node_modules/foo/package.json' does not exist.",
"File '/node_modules/foo/index.js' does not exist.",
"File '/node_modules/foo/index.jsx' does not exist.",
"File '/node_modules/@types/foo.js' does not exist.",
"File '/node_modules/@types/foo.jsx' does not exist.",
"File '/node_modules/@types/foo/package.json' does not exist.",
"File '/node_modules/@types/foo/index.js' does not exist.",
"File '/node_modules/@types/foo/index.jsx' does not exist.",
"======== Module name 'foo' was not resolved. ========"
]

View File

@@ -0,0 +1,18 @@
// @noImplicitReferences: true
// @traceResolution: true
// @Filename: /foo/foo.ts
export function foo() {}
// @Filename: /a.ts
import { foo } from "foo";
// @Filename: /tsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"foo": ["foo/foo.ts"]
}
}
}

View File

@@ -0,0 +1,15 @@
// @noImplicitReferences: true
// @traceResolution: true
// @Filename: /a.ts
import { foo } from "foo";
// @Filename: /tsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"foo": ["foo/foo.ts"]
}
}
}