From 359c8b12ef3a8339940edd9203dcb2a10c08615b Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Wed, 3 Aug 2016 07:12:10 -0700 Subject: [PATCH] Don't allow ".d.ts" extension in an import either. --- src/compiler/checker.ts | 8 ++-- src/compiler/core.ts | 3 +- src/compiler/diagnosticMessages.json | 2 +- src/compiler/program.ts | 16 ++------ src/compiler/utilities.ts | 6 ++- src/harness/compilerRunner.ts | 2 +- .../reference/moduleResolutionNoTs.errors.txt | 40 +++++++++++-------- .../reference/moduleResolutionNoTs.js | 11 ++--- tests/cases/compiler/moduleResolutionNoTs.ts | 9 +++-- 9 files changed, 50 insertions(+), 47 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 290fa257da..6dd2747e33 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1366,10 +1366,10 @@ namespace ts { if (moduleNotFoundError) { // report errors only if it was requested - const nonDtsExtension = tryExtractTypeScriptExtensionNonDts(moduleName); - if (nonDtsExtension) { - const diag = Diagnostics.An_import_path_should_not_end_with_a_0_extension_Consider_importing_1_instead; - error(moduleReferenceLiteral, diag, nonDtsExtension, removeExtension(moduleName, nonDtsExtension)); + const tsExtension = tryExtractTypeScriptExtension(moduleName); + if (tsExtension) { + const diag = Diagnostics.An_import_path_cannot_end_with_a_0_extension_Consider_importing_1_instead; + error(moduleReferenceLiteral, diag, tsExtension, removeExtension(moduleName, tsExtension)); } else { error(moduleReferenceLiteral, moduleNotFoundError, moduleName); diff --git a/src/compiler/core.ts b/src/compiler/core.ts index d77036660b..869cddb2d4 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -1198,8 +1198,7 @@ namespace ts { /** * List of supported extensions in order of file resolution precedence. */ - export const supportedTypeScriptExtensionsNonDts = [".ts", ".tsx"]; - export const supportedTypeScriptExtensions = supportedTypeScriptExtensionsNonDts.concat([".d.ts"]); + export const supportedTypeScriptExtensions = [".ts", ".tsx", ".d.ts"]; export const supportedJavascriptExtensions = [".js", ".jsx"]; const allSupportedExtensions = supportedTypeScriptExtensions.concat(supportedJavascriptExtensions); diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 93bd6c608f..8975e5daa0 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1951,7 +1951,7 @@ "category": "Error", "code": 2690 }, - "An import path should not end with a '{0}' extension. Consider importing '{1}' instead.": { + "An import path cannot end with a '{0}' extension. Consider importing '{1}' instead.": { "category": "Error", "code": 2691 }, diff --git a/src/compiler/program.ts b/src/compiler/program.ts index a2674d7978..d35ce64412 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -669,17 +669,7 @@ namespace ts { * in cases when we know upfront that all load attempts will fail (because containing folder does not exists) however we still need to record all failed lookup locations. */ function loadModuleFromFile(candidate: string, extensions: string[], failedLookupLocation: string[], onlyRecordFailures: boolean, state: ModuleResolutionState): string | undefined { - // If the candidate already has an extension load that or quit. - if (hasTypeScriptFileExtension(candidate)) { - // Don't allow `.ts` to appear at the end - if (!fileExtensionIs(candidate, ".d.ts")) { - return undefined; - } - return tryFile(candidate, failedLookupLocation, onlyRecordFailures, state); - } - - // Next, try adding an extension. - // We don't allow an import of "foo.ts" to be matched by "foo.ts.ts", but we do allow "foo.js" to be matched by "foo.js.ts". + // First, try adding an extension. An import of "foo" could be matched by a file "foo.ts", or "foo.js" by "foo.js.ts" const resolvedByAddingExtension = tryAddingExtensions(candidate, extensions, failedLookupLocation, onlyRecordFailures, state); if (resolvedByAddingExtension) { return resolvedByAddingExtension; @@ -736,7 +726,9 @@ namespace ts { } const typesFile = tryReadTypesSection(packageJsonPath, candidate, state); if (typesFile) { - const result = loadModuleFromFile(typesFile, extensions, failedLookupLocation, !directoryProbablyExists(getDirectoryPath(typesFile), state.host), state); + const onlyRecordFailures = !directoryProbablyExists(getDirectoryPath(typesFile), state.host); + // The package.json "typings" property must specify the file with extension, so just try that exact filename. + const result = tryFile(typesFile, failedLookupLocation, onlyRecordFailures, state); if (result) { return result; } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index b92037b7e5..22c9355072 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -2727,9 +2727,11 @@ namespace ts { } /** Return ".ts" or ".tsx" if that is the extension. */ - export function tryExtractTypeScriptExtensionNonDts(fileName: string): string | undefined { - return find(supportedTypeScriptExtensionsNonDts, extension => fileExtensionIs(fileName, extension)); + export function tryExtractTypeScriptExtension(fileName: string): string | undefined { + return find(supportedTypescriptExtensionsWithDtsFirst, extension => fileExtensionIs(fileName, extension)); } + // Must have '.d.ts' first because if '.ts' goes first, that will be detected as the extension instead of '.d.ts'. + const supportedTypescriptExtensionsWithDtsFirst = supportedTypeScriptExtensions.slice().reverse(); /** * Replace each instance of non-ascii characters by one, two, three, or four escape sequences diff --git a/src/harness/compilerRunner.ts b/src/harness/compilerRunner.ts index ecdc18394b..b8467adda5 100644 --- a/src/harness/compilerRunner.ts +++ b/src/harness/compilerRunner.ts @@ -52,7 +52,7 @@ class CompilerBaselineRunner extends RunnerBase { private makeUnitName(name: string, root: string) { const path = ts.toPath(name, root, (fileName) => Harness.Compiler.getCanonicalFileName(fileName)); const pathStart = ts.toPath(Harness.IO.getCurrentDirectory(), "", (fileName) => Harness.Compiler.getCanonicalFileName(fileName)); - return path.replace(pathStart, "/"); + return pathStart === "" ? path : path.replace(pathStart, "/"); }; public checkTestCodeOutput(fileName: string) { diff --git a/tests/baselines/reference/moduleResolutionNoTs.errors.txt b/tests/baselines/reference/moduleResolutionNoTs.errors.txt index 2a9b74a1af..c054330731 100644 --- a/tests/baselines/reference/moduleResolutionNoTs.errors.txt +++ b/tests/baselines/reference/moduleResolutionNoTs.errors.txt @@ -1,25 +1,31 @@ -tests/cases/compiler/user.ts(4,15): error TS2691: An import path should not end with a '.ts' extension. Consider importing './x' instead. -tests/cases/compiler/user.ts(5,15): error TS2691: An import path should not end with a '.tsx' extension. Consider importing './y' instead. +tests/cases/compiler/user.ts(1,15): error TS2691: An import path cannot end with a '.ts' extension. Consider importing './x' instead. +tests/cases/compiler/user.ts(2,15): error TS2691: An import path cannot end with a '.tsx' extension. Consider importing './y' instead. +tests/cases/compiler/user.ts(3,15): error TS2691: An import path cannot end with a '.d.ts' extension. Consider importing './z' instead. -==== tests/cases/compiler/user.ts (2 errors) ==== - // '.ts' extension is OK in a reference - /// - - import x from "./x.ts"; - ~~~~~~~~ -!!! error TS2691: An import path should not end with a '.ts' extension. Consider importing './x' instead. - import y from "./y.tsx"; - ~~~~~~~~~ -!!! error TS2691: An import path should not end with a '.tsx' extension. Consider importing './y' instead. - - // Making sure the suggested fixes are valid: - import x2 from "./x"; - import y2 from "./y"; - ==== tests/cases/compiler/x.ts (0 errors) ==== export default 0; ==== tests/cases/compiler/y.tsx (0 errors) ==== export default 0; + +==== tests/cases/compiler/z.d.ts (0 errors) ==== + declare const x: number; + export default x; + +==== tests/cases/compiler/user.ts (3 errors) ==== + import x from "./x.ts"; + ~~~~~~~~ +!!! error TS2691: An import path cannot end with a '.ts' extension. Consider importing './x' instead. + import y from "./y.tsx"; + ~~~~~~~~~ +!!! error TS2691: An import path cannot end with a '.tsx' extension. Consider importing './y' instead. + import z from "./z.d.ts"; + ~~~~~~~~~~ +!!! error TS2691: An import path cannot end with a '.d.ts' extension. Consider importing './z' instead. + + // Making sure the suggested fixes are valid: + import x2 from "./x"; + import y2 from "./y"; + import z2 from "./z"; \ No newline at end of file diff --git a/tests/baselines/reference/moduleResolutionNoTs.js b/tests/baselines/reference/moduleResolutionNoTs.js index d9d918f560..9ff33d688e 100644 --- a/tests/baselines/reference/moduleResolutionNoTs.js +++ b/tests/baselines/reference/moduleResolutionNoTs.js @@ -6,16 +6,19 @@ export default 0; //// [y.tsx] export default 0; +//// [z.d.ts] +declare const x: number; +export default x; + //// [user.ts] -// '.ts' extension is OK in a reference -/// - import x from "./x.ts"; import y from "./y.tsx"; +import z from "./z.d.ts"; // Making sure the suggested fixes are valid: import x2 from "./x"; import y2 from "./y"; +import z2 from "./z"; //// [x.js] @@ -27,6 +30,4 @@ exports["default"] = 0; exports.__esModule = true; exports["default"] = 0; //// [user.js] -// '.ts' extension is OK in a reference -/// "use strict"; diff --git a/tests/cases/compiler/moduleResolutionNoTs.ts b/tests/cases/compiler/moduleResolutionNoTs.ts index 683f6630d9..2051bc259b 100644 --- a/tests/cases/compiler/moduleResolutionNoTs.ts +++ b/tests/cases/compiler/moduleResolutionNoTs.ts @@ -4,13 +4,16 @@ export default 0; // @filename: y.tsx export default 0; -// @filename: user.ts -// '.ts' extension is OK in a reference -/// +// @filename: z.d.ts +declare const x: number; +export default x; +// @filename: user.ts import x from "./x.ts"; import y from "./y.tsx"; +import z from "./z.d.ts"; // Making sure the suggested fixes are valid: import x2 from "./x"; import y2 from "./y"; +import z2 from "./z";