mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Don't allow .ts to appear in an import
This commit is contained in:
+36
-25
@@ -668,24 +668,37 @@ namespace ts {
|
||||
* @param {boolean} onlyRecordFailures - if true then function won't try to actually load files but instead record all attempts as failures. This flag is necessary
|
||||
* 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 {
|
||||
// First try to keep/add an extension: importing "./foo.ts" can be matched by a file "./foo.ts", and "./foo" by "./foo.d.ts"
|
||||
const resolvedByAddingOrKeepingExtension = loadModuleFromFileWorker(candidate, extensions, failedLookupLocation, onlyRecordFailures, state);
|
||||
if (resolvedByAddingOrKeepingExtension) {
|
||||
return resolvedByAddingOrKeepingExtension;
|
||||
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);
|
||||
}
|
||||
// Then try stripping a ".js" or ".jsx" extension and replacing it with a TypeScript one, e.g. "./foo.js" can be matched by "./foo.ts" or "./foo.d.ts"
|
||||
|
||||
// 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".
|
||||
const resolvedByAddingExtension = tryAddingExtensions(candidate, extensions, failedLookupLocation, onlyRecordFailures, state);
|
||||
if (resolvedByAddingExtension) {
|
||||
return resolvedByAddingExtension;
|
||||
}
|
||||
|
||||
// If that didn't work, try stripping a ".js" or ".jsx" extension and replacing it with a TypeScript one;
|
||||
// e.g. "./foo.js" can be matched by "./foo.ts" or "./foo.d.ts"
|
||||
if (hasJavaScriptFileExtension(candidate)) {
|
||||
const extensionless = removeFileExtension(candidate);
|
||||
if (state.traceEnabled) {
|
||||
const extension = candidate.substring(extensionless.length);
|
||||
trace(state.host, Diagnostics.File_name_0_has_a_1_extension_stripping_it, candidate, extension);
|
||||
}
|
||||
return loadModuleFromFileWorker(extensionless, extensions, failedLookupLocation, onlyRecordFailures, state);
|
||||
return tryAddingExtensions(extensionless, extensions, failedLookupLocation, onlyRecordFailures, state);
|
||||
}
|
||||
}
|
||||
|
||||
function loadModuleFromFileWorker(candidate: string, extensions: string[], failedLookupLocation: string[], onlyRecordFailures: boolean, state: ModuleResolutionState): string {
|
||||
/** Try to return an existing file that adds one of the `extensions` to `candidate`. */
|
||||
function tryAddingExtensions(candidate: string, extensions: string[], failedLookupLocation: string[], onlyRecordFailures: boolean, state: ModuleResolutionState): string | undefined {
|
||||
if (!onlyRecordFailures) {
|
||||
// check if containing folder exists - if it doesn't then just record failures for all supported extensions without disk probing
|
||||
const directory = getDirectoryPath(candidate);
|
||||
@@ -693,26 +706,24 @@ namespace ts {
|
||||
onlyRecordFailures = !directoryProbablyExists(directory, state.host);
|
||||
}
|
||||
}
|
||||
return forEach(extensions, tryLoad);
|
||||
return forEach(extensions, ext =>
|
||||
!(state.skipTsx && isJsxOrTsxExtension(ext)) && tryFile(candidate + ext, failedLookupLocation, onlyRecordFailures, state));
|
||||
}
|
||||
|
||||
function tryLoad(ext: string): string {
|
||||
if (state.skipTsx && isJsxOrTsxExtension(ext)) {
|
||||
return undefined;
|
||||
/** Return the file if it exists. */
|
||||
function tryFile(fileName: string, failedLookupLocation: string[], onlyRecordFailures: boolean, state: ModuleResolutionState): string | undefined {
|
||||
if (!onlyRecordFailures && state.host.fileExists(fileName)) {
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.File_0_exist_use_it_as_a_name_resolution_result, fileName);
|
||||
}
|
||||
const fileName = fileExtensionIs(candidate, ext) ? candidate : candidate + ext;
|
||||
if (!onlyRecordFailures && state.host.fileExists(fileName)) {
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.File_0_exist_use_it_as_a_name_resolution_result, fileName);
|
||||
}
|
||||
return fileName;
|
||||
}
|
||||
else {
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.File_0_does_not_exist, fileName);
|
||||
}
|
||||
failedLookupLocation.push(fileName);
|
||||
return undefined;
|
||||
return fileName;
|
||||
}
|
||||
else {
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.File_0_does_not_exist, fileName);
|
||||
}
|
||||
failedLookupLocation.push(fileName);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -465,8 +465,8 @@ export = C;
|
||||
"/a/B/c/moduleB.ts": `import a = require("./moduleC")`,
|
||||
"/a/B/c/moduleC.ts": "export var x",
|
||||
"/a/B/c/moduleD.ts": `
|
||||
import a = require("./moduleA.ts");
|
||||
import b = require("./moduleB.ts");
|
||||
import a = require("./moduleA");
|
||||
import b = require("./moduleB");
|
||||
`
|
||||
};
|
||||
test(files, { module: ts.ModuleKind.CommonJS, forceConsistentCasingInFileNames: true }, "/a/B/c", /*useCaseSensitiveFileNames*/ false, ["moduleD.ts"], [1149]);
|
||||
@@ -477,8 +477,8 @@ import b = require("./moduleB.ts");
|
||||
"/a/B/c/moduleB.ts": `import a = require("./moduleC")`,
|
||||
"/a/B/c/moduleC.ts": "export var x",
|
||||
"/a/B/c/moduleD.ts": `
|
||||
import a = require("./moduleA.ts");
|
||||
import b = require("./moduleB.ts");
|
||||
import a = require("./moduleA");
|
||||
import b = require("./moduleB");
|
||||
`
|
||||
};
|
||||
test(files, { module: ts.ModuleKind.CommonJS, forceConsistentCasingInFileNames: true }, "/a/B/c", /*useCaseSensitiveFileNames*/ false, ["moduleD.ts"], []);
|
||||
|
||||
@@ -4,7 +4,7 @@ tests/cases/compiler/missingFunctionImplementation2_b.ts(1,17): error TS2391: Fu
|
||||
|
||||
==== tests/cases/compiler/missingFunctionImplementation2_a.ts (1 errors) ====
|
||||
export {};
|
||||
declare module "./missingFunctionImplementation2_b.ts" {
|
||||
declare module "./missingFunctionImplementation2_b" {
|
||||
export function f(a, b): void;
|
||||
~
|
||||
!!! error TS2384: Overload signatures must all be ambient or non-ambient.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
//// [missingFunctionImplementation2_a.ts]
|
||||
export {};
|
||||
declare module "./missingFunctionImplementation2_b.ts" {
|
||||
declare module "./missingFunctionImplementation2_b" {
|
||||
export function f(a, b): void;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
tests/cases/compiler/user.ts(1,15): error TS2307: Cannot find module './m.ts'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/m.ts (0 errors) ====
|
||||
export default 0;
|
||||
|
||||
==== tests/cases/compiler/user.ts (1 errors) ====
|
||||
import x from "./m.ts";
|
||||
~~~~~~~~
|
||||
!!! error TS2307: Cannot find module './m.ts'.
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
//// [tests/cases/compiler/moduleResolutionNoTs.ts] ////
|
||||
|
||||
//// [m.ts]
|
||||
export default 0;
|
||||
|
||||
//// [user.ts]
|
||||
import x from "./m.ts";
|
||||
|
||||
|
||||
//// [m.js]
|
||||
"use strict";
|
||||
exports.__esModule = true;
|
||||
exports["default"] = 0;
|
||||
//// [user.js]
|
||||
"use strict";
|
||||
@@ -8,10 +8,6 @@ export default 0;
|
||||
//// [b.ts]
|
||||
import a from './a';
|
||||
|
||||
// Matching extension
|
||||
//// [c.ts]
|
||||
import a from './a.ts';
|
||||
|
||||
// '.js' extension: stripped and replaced with '.ts'
|
||||
//// [d.ts]
|
||||
import a from './a.js';
|
||||
@@ -36,9 +32,6 @@ exports["default"] = 0;
|
||||
// No extension: '.ts' added
|
||||
//// [b.js]
|
||||
"use strict";
|
||||
// Matching extension
|
||||
//// [c.js]
|
||||
"use strict";
|
||||
// '.js' extension: stripped and replaced with '.ts'
|
||||
//// [d.js]
|
||||
"use strict";
|
||||
|
||||
@@ -7,11 +7,6 @@ No type information for this code.=== /src/b.ts ===
|
||||
import a from './a';
|
||||
>a : Symbol(a, Decl(b.ts, 0, 6))
|
||||
|
||||
// Matching extension
|
||||
=== /src/c.ts ===
|
||||
import a from './a.ts';
|
||||
>a : Symbol(a, Decl(c.ts, 0, 6))
|
||||
|
||||
// '.js' extension: stripped and replaced with '.ts'
|
||||
=== /src/d.ts ===
|
||||
import a from './a.js';
|
||||
|
||||
@@ -5,12 +5,6 @@
|
||||
"File '/src/a.ts' exist - use it as a name resolution result.",
|
||||
"Resolving real path for '/src/a.ts', result '/src/a.ts'",
|
||||
"======== Module name './a' was successfully resolved to '/src/a.ts'. ========",
|
||||
"======== Resolving module './a.ts' from '/src/c.ts'. ========",
|
||||
"Module resolution kind is not specified, using 'NodeJs'.",
|
||||
"Loading module as file / folder, candidate module location '/src/a.ts'.",
|
||||
"File '/src/a.ts' exist - use it as a name resolution result.",
|
||||
"Resolving real path for '/src/a.ts', result '/src/a.ts'",
|
||||
"======== Module name './a.ts' was successfully resolved to '/src/a.ts'. ========",
|
||||
"======== Resolving module './a.js' from '/src/d.ts'. ========",
|
||||
"Module resolution kind is not specified, using 'NodeJs'.",
|
||||
"Loading module as file / folder, candidate module location '/src/a.js'.",
|
||||
|
||||
@@ -7,11 +7,6 @@ No type information for this code.=== /src/b.ts ===
|
||||
import a from './a';
|
||||
>a : number
|
||||
|
||||
// Matching extension
|
||||
=== /src/c.ts ===
|
||||
import a from './a.ts';
|
||||
>a : number
|
||||
|
||||
// '.js' extension: stripped and replaced with '.ts'
|
||||
=== /src/d.ts ===
|
||||
import a from './a.js';
|
||||
|
||||
@@ -4,7 +4,7 @@ tests/cases/compiler/staticInstanceResolution5_1.ts(6,16): error TS2304: Cannot
|
||||
|
||||
|
||||
==== tests/cases/compiler/staticInstanceResolution5_1.ts (3 errors) ====
|
||||
import WinJS = require('staticInstanceResolution5_0.ts');
|
||||
import WinJS = require('staticInstanceResolution5_0');
|
||||
|
||||
// these 3 should be errors
|
||||
var x = (w1: WinJS) => { };
|
||||
|
||||
@@ -8,7 +8,7 @@ export class Promise {
|
||||
}
|
||||
|
||||
//// [staticInstanceResolution5_1.ts]
|
||||
import WinJS = require('staticInstanceResolution5_0.ts');
|
||||
import WinJS = require('staticInstanceResolution5_0');
|
||||
|
||||
// these 3 should be errors
|
||||
var x = (w1: WinJS) => { };
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// @Filename: missingFunctionImplementation2_a.ts
|
||||
export {};
|
||||
declare module "./missingFunctionImplementation2_b.ts" {
|
||||
declare module "./missingFunctionImplementation2_b" {
|
||||
export function f(a, b): void;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
// @filename: m.ts
|
||||
export default 0;
|
||||
|
||||
// @filename: user.ts
|
||||
import x from "./m.ts";
|
||||
@@ -7,7 +7,7 @@ export class Promise {
|
||||
}
|
||||
|
||||
// @Filename: staticInstanceResolution5_1.ts
|
||||
import WinJS = require('staticInstanceResolution5_0.ts');
|
||||
import WinJS = require('staticInstanceResolution5_0');
|
||||
|
||||
// these 3 should be errors
|
||||
var x = (w1: WinJS) => { };
|
||||
|
||||
@@ -7,10 +7,6 @@ export default 0;
|
||||
// @Filename: /src/b.ts
|
||||
import a from './a';
|
||||
|
||||
// Matching extension
|
||||
// @Filename: /src/c.ts
|
||||
import a from './a.ts';
|
||||
|
||||
// '.js' extension: stripped and replaced with '.ts'
|
||||
// @Filename: /src/d.ts
|
||||
import a from './a.js';
|
||||
|
||||
Reference in New Issue
Block a user