Skip to content

Commit 1546974

Browse files
author
Andy
authored
Merge pull request microsoft#9676 from Microsoft/relative_module
Treat "." and ".." as relative module names
2 parents 9eeb69d + df59058 commit 1546974

10 files changed

Lines changed: 188 additions & 33 deletions

src/compiler/core.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -900,9 +900,7 @@ namespace ts {
900900
}
901901

902902
export function fileExtensionIs(path: string, extension: string): boolean {
903-
const pathLen = path.length;
904-
const extLen = extension.length;
905-
return pathLen > extLen && path.substr(pathLen - extLen, extLen) === extension;
903+
return path.length > extension.length && endsWith(path, extension);
906904
}
907905

908906
export function fileExtensionIsAny(path: string, extensions: string[]): boolean {
@@ -915,7 +913,6 @@ namespace ts {
915913
return false;
916914
}
917915

918-
919916
// Reserved characters, forces escaping of any non-word (or digit), non-whitespace character.
920917
// It may be inefficient (we could just match (/[-[\]{}()*+?.,\\^$|#\s]/g), but this is future
921918
// proof.

src/compiler/program.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -112,13 +112,7 @@ namespace ts {
112112
}
113113

114114
function moduleHasNonRelativeName(moduleName: string): boolean {
115-
if (isRootedDiskPath(moduleName)) {
116-
return false;
117-
}
118-
119-
const i = moduleName.lastIndexOf("./", 1);
120-
const startsWithDotSlashOrDotDotSlash = i === 0 || (i === 1 && moduleName.charCodeAt(0) === CharacterCodes.dot);
121-
return !startsWithDotSlashOrDotDotSlash;
115+
return !(isRootedDiskPath(moduleName) || isExternalModuleNameRelative(moduleName));
122116
}
123117

124118
interface ModuleResolutionState {

src/compiler/utilities.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1218,7 +1218,7 @@ namespace ts {
12181218
export function isExternalModuleNameRelative(moduleName: string): boolean {
12191219
// TypeScript 1.0 spec (April 2014): 11.2.1
12201220
// An external module name is "relative" if the first term is "." or "..".
1221-
return moduleName.substr(0, 2) === "./" || moduleName.substr(0, 3) === "../" || moduleName.substr(0, 2) === ".\\" || moduleName.substr(0, 3) === "..\\";
1221+
return /^\.\.?($|[\\/])/.test(moduleName);
12221222
}
12231223

12241224
export function isInstantiatedModule(node: ModuleDeclaration, preserveConstEnums: boolean) {
@@ -3120,6 +3120,6 @@ namespace ts {
31203120

31213121
export function endsWith(str: string, suffix: string): boolean {
31223122
const expectedPos = str.length - suffix.length;
3123-
return str.indexOf(suffix, expectedPos) === expectedPos;
3123+
return expectedPos >= 0 && str.indexOf(suffix, expectedPos) === expectedPos;
31243124
}
31253125
}

src/harness/harness.ts

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1377,31 +1377,27 @@ namespace Harness {
13771377
writeByteOrderMark: boolean;
13781378
}
13791379

1380-
function stringEndsWith(str: string, end: string) {
1381-
return str.substr(str.length - end.length) === end;
1382-
}
1383-
13841380
export function isTS(fileName: string) {
1385-
return stringEndsWith(fileName, ".ts");
1381+
return ts.endsWith(fileName, ".ts");
13861382
}
13871383

13881384
export function isTSX(fileName: string) {
1389-
return stringEndsWith(fileName, ".tsx");
1385+
return ts.endsWith(fileName, ".tsx");
13901386
}
13911387

13921388
export function isDTS(fileName: string) {
1393-
return stringEndsWith(fileName, ".d.ts");
1389+
return ts.endsWith(fileName, ".d.ts");
13941390
}
13951391

13961392
export function isJS(fileName: string) {
1397-
return stringEndsWith(fileName, ".js");
1393+
return ts.endsWith(fileName, ".js");
13981394
}
13991395
export function isJSX(fileName: string) {
1400-
return stringEndsWith(fileName, ".jsx");
1396+
return ts.endsWith(fileName, ".jsx");
14011397
}
14021398

14031399
export function isJSMap(fileName: string) {
1404-
return stringEndsWith(fileName, ".js.map") || stringEndsWith(fileName, ".jsx.map");
1400+
return ts.endsWith(fileName, ".js.map") || ts.endsWith(fileName, ".jsx.map");
14051401
}
14061402

14071403
/** Contains the code and errors of a compilation and some helper methods to check its status. */

src/services/patternMatcher.ts

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -514,16 +514,6 @@ namespace ts {
514514
return str === str.toLowerCase();
515515
}
516516

517-
function startsWith(string: string, search: string) {
518-
for (let i = 0, n = search.length; i < n; i++) {
519-
if (string.charCodeAt(i) !== search.charCodeAt(i)) {
520-
return false;
521-
}
522-
}
523-
524-
return true;
525-
}
526-
527517
// Assumes 'value' is already lowercase.
528518
function indexOfIgnoringCase(string: string, value: string): number {
529519
for (let i = 0, n = string.length - value.length; i <= n; i++) {
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//// [tests/cases/compiler/relativeModuleWithoutSlash.ts] ////
2+
3+
//// [a.ts]
4+
5+
export default { a: 0 };
6+
7+
//// [index.ts]
8+
export default { aIndex: 0 };
9+
10+
//// [test.ts]
11+
import a from ".";
12+
import aIndex from "./";
13+
a.a;
14+
aIndex.a; //aIndex.aIndex; See GH#9690
15+
16+
//// [test.ts]
17+
import a from "..";
18+
import aIndex from "../";
19+
a.a;
20+
aIndex.a; //aIndex.aIndex;
21+
22+
23+
//// [a.js]
24+
"use strict";
25+
exports.__esModule = true;
26+
exports["default"] = { a: 0 };
27+
//// [index.js]
28+
"use strict";
29+
exports.__esModule = true;
30+
exports["default"] = { aIndex: 0 };
31+
//// [test.js]
32+
"use strict";
33+
var _1 = require(".");
34+
var _2 = require("./");
35+
_1["default"].a;
36+
_2["default"].a; //aIndex.aIndex; See GH#9690
37+
//// [test.js]
38+
"use strict";
39+
var __1 = require("..");
40+
var _1 = require("../");
41+
__1["default"].a;
42+
_1["default"].a; //aIndex.aIndex;
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
=== tests/cases/compiler/a.ts ===
2+
3+
export default { a: 0 };
4+
>a : Symbol(a, Decl(a.ts, 1, 16))
5+
6+
=== tests/cases/compiler/a/index.ts ===
7+
export default { aIndex: 0 };
8+
>aIndex : Symbol(aIndex, Decl(index.ts, 0, 16))
9+
10+
=== tests/cases/compiler/a/test.ts ===
11+
import a from ".";
12+
>a : Symbol(a, Decl(test.ts, 0, 6))
13+
14+
import aIndex from "./";
15+
>aIndex : Symbol(aIndex, Decl(test.ts, 1, 6))
16+
17+
a.a;
18+
>a.a : Symbol(a, Decl(a.ts, 1, 16))
19+
>a : Symbol(a, Decl(test.ts, 0, 6))
20+
>a : Symbol(a, Decl(a.ts, 1, 16))
21+
22+
aIndex.a; //aIndex.aIndex; See GH#9690
23+
>aIndex.a : Symbol(a, Decl(a.ts, 1, 16))
24+
>aIndex : Symbol(aIndex, Decl(test.ts, 1, 6))
25+
>a : Symbol(a, Decl(a.ts, 1, 16))
26+
27+
=== tests/cases/compiler/a/b/test.ts ===
28+
import a from "..";
29+
>a : Symbol(a, Decl(test.ts, 0, 6))
30+
31+
import aIndex from "../";
32+
>aIndex : Symbol(aIndex, Decl(test.ts, 1, 6))
33+
34+
a.a;
35+
>a.a : Symbol(a, Decl(a.ts, 1, 16))
36+
>a : Symbol(a, Decl(test.ts, 0, 6))
37+
>a : Symbol(a, Decl(a.ts, 1, 16))
38+
39+
aIndex.a; //aIndex.aIndex;
40+
>aIndex.a : Symbol(a, Decl(a.ts, 1, 16))
41+
>aIndex : Symbol(aIndex, Decl(test.ts, 1, 6))
42+
>a : Symbol(a, Decl(a.ts, 1, 16))
43+
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
[
2+
"======== Resolving module '.' from 'C:/Users/anhans/work/TypeScript/tests/cases/compiler/a/test.ts'. ========",
3+
"Explicitly specified module resolution kind: 'NodeJs'.",
4+
"Loading module as file / folder, candidate module location 'C:/Users/anhans/work/TypeScript/tests/cases/compiler/a'.",
5+
"File 'C:/Users/anhans/work/TypeScript/tests/cases/compiler/a.ts' exist - use it as a name resolution result.",
6+
"Resolving real path for 'C:/Users/anhans/work/TypeScript/tests/cases/compiler/a.ts', result 'c:/users/anhans/work/typescript/tests/cases/compiler/a.ts'",
7+
"======== Module name '.' was successfully resolved to 'c:/users/anhans/work/typescript/tests/cases/compiler/a.ts'. ========",
8+
"======== Resolving module './' from 'C:/Users/anhans/work/TypeScript/tests/cases/compiler/a/test.ts'. ========",
9+
"Explicitly specified module resolution kind: 'NodeJs'.",
10+
"Loading module as file / folder, candidate module location 'C:/Users/anhans/work/TypeScript/tests/cases/compiler/a'.",
11+
"File 'C:/Users/anhans/work/TypeScript/tests/cases/compiler/a.ts' exist - use it as a name resolution result.",
12+
"Resolving real path for 'C:/Users/anhans/work/TypeScript/tests/cases/compiler/a.ts', result 'c:/users/anhans/work/typescript/tests/cases/compiler/a.ts'",
13+
"======== Module name './' was successfully resolved to 'c:/users/anhans/work/typescript/tests/cases/compiler/a.ts'. ========",
14+
"======== Resolving module '..' from 'C:/Users/anhans/work/TypeScript/tests/cases/compiler/a/b/test.ts'. ========",
15+
"Explicitly specified module resolution kind: 'NodeJs'.",
16+
"Loading module as file / folder, candidate module location 'C:/Users/anhans/work/TypeScript/tests/cases/compiler/a'.",
17+
"File 'C:/Users/anhans/work/TypeScript/tests/cases/compiler/a.ts' exist - use it as a name resolution result.",
18+
"Resolving real path for 'C:/Users/anhans/work/TypeScript/tests/cases/compiler/a.ts', result 'c:/users/anhans/work/typescript/tests/cases/compiler/a.ts'",
19+
"======== Module name '..' was successfully resolved to 'c:/users/anhans/work/typescript/tests/cases/compiler/a.ts'. ========",
20+
"======== Resolving module '../' from 'C:/Users/anhans/work/TypeScript/tests/cases/compiler/a/b/test.ts'. ========",
21+
"Explicitly specified module resolution kind: 'NodeJs'.",
22+
"Loading module as file / folder, candidate module location 'C:/Users/anhans/work/TypeScript/tests/cases/compiler/a'.",
23+
"File 'C:/Users/anhans/work/TypeScript/tests/cases/compiler/a.ts' exist - use it as a name resolution result.",
24+
"Resolving real path for 'C:/Users/anhans/work/TypeScript/tests/cases/compiler/a.ts', result 'c:/users/anhans/work/typescript/tests/cases/compiler/a.ts'",
25+
"======== Module name '../' was successfully resolved to 'c:/users/anhans/work/typescript/tests/cases/compiler/a.ts'. ========"
26+
]
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
=== tests/cases/compiler/a.ts ===
2+
3+
export default { a: 0 };
4+
>{ a: 0 } : { a: number; }
5+
>a : number
6+
>0 : number
7+
8+
=== tests/cases/compiler/a/index.ts ===
9+
export default { aIndex: 0 };
10+
>{ aIndex: 0 } : { aIndex: number; }
11+
>aIndex : number
12+
>0 : number
13+
14+
=== tests/cases/compiler/a/test.ts ===
15+
import a from ".";
16+
>a : { a: number; }
17+
18+
import aIndex from "./";
19+
>aIndex : { a: number; }
20+
21+
a.a;
22+
>a.a : number
23+
>a : { a: number; }
24+
>a : number
25+
26+
aIndex.a; //aIndex.aIndex; See GH#9690
27+
>aIndex.a : number
28+
>aIndex : { a: number; }
29+
>a : number
30+
31+
=== tests/cases/compiler/a/b/test.ts ===
32+
import a from "..";
33+
>a : { a: number; }
34+
35+
import aIndex from "../";
36+
>aIndex : { a: number; }
37+
38+
a.a;
39+
>a.a : number
40+
>a : { a: number; }
41+
>a : number
42+
43+
aIndex.a; //aIndex.aIndex;
44+
>aIndex.a : number
45+
>aIndex : { a: number; }
46+
>a : number
47+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// @traceResolution: true
2+
// @moduleResolution: node
3+
4+
// @Filename: a.ts
5+
export default { a: 0 };
6+
7+
// @Filename: a/index.ts
8+
export default { aIndex: 0 };
9+
10+
// @Filename: a/test.ts
11+
import a from ".";
12+
import aIndex from "./";
13+
a.a;
14+
aIndex.a; //aIndex.aIndex; See GH#9690
15+
16+
// @Filename: a/b/test.ts
17+
import a from "..";
18+
import aIndex from "../";
19+
a.a;
20+
aIndex.a; //aIndex.aIndex;

0 commit comments

Comments
 (0)