Skip to content

Commit 30db300

Browse files
authored
Fix module specifier case handling for declaration emit (microsoft#25110)
1 parent 374fefe commit 30db300

8 files changed

+186
-1
lines changed

src/compiler/moduleSpecifiers.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,10 +150,11 @@ namespace ts.moduleSpecifiers {
150150
const result = createMap<string>();
151151
if (symlinks) {
152152
const currentDirectory = host.getCurrentDirectory ? host.getCurrentDirectory() : "";
153+
const compareStrings = (!host.useCaseSensitiveFileNames || host.useCaseSensitiveFileNames()) ? compareStringsCaseSensitive : compareStringsCaseInsensitive;
153154
for (const [resolvedPath, originalPath] of symlinks) {
154155
const resolvedParts = getPathComponents(toPath(resolvedPath, currentDirectory, getCanonicalFileName));
155156
const originalParts = getPathComponents(toPath(originalPath, currentDirectory, getCanonicalFileName));
156-
while (resolvedParts[resolvedParts.length - 1] === originalParts[originalParts.length - 1]) {
157+
while (compareStrings(resolvedParts[resolvedParts.length - 1], originalParts[originalParts.length - 1]) === Comparison.EqualTo) {
157158
resolvedParts.pop();
158159
originalParts.pop();
159160
}

src/compiler/program.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1248,6 +1248,7 @@ namespace ts {
12481248
return host.fileExists(f);
12491249
},
12501250
...(host.directoryExists ? { directoryExists: f => host.directoryExists!(f) } : {}),
1251+
useCaseSensitiveFileNames: () => host.useCaseSensitiveFileNames(),
12511252
};
12521253
}
12531254

src/compiler/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5045,6 +5045,7 @@ namespace ts {
50455045
/* @internal */
50465046
export interface EmitHost extends ScriptReferenceHost, ModuleSpecifierResolutionHost {
50475047
getSourceFiles(): ReadonlyArray<SourceFile>;
5048+
useCaseSensitiveFileNames(): boolean;
50485049
getCurrentDirectory(): string;
50495050

50505051
/* @internal */

tests/baselines/reference/api/tsserverlibrary.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4278,6 +4278,7 @@ declare namespace ts {
42784278
}
42794279
interface EmitHost extends ScriptReferenceHost, ModuleSpecifierResolutionHost {
42804280
getSourceFiles(): ReadonlyArray<SourceFile>;
4281+
useCaseSensitiveFileNames(): boolean;
42814282
getCurrentDirectory(): string;
42824283
isSourceFileFromExternalLibrary(file: SourceFile): boolean;
42834284
getCommonSourceDirectory(): string;
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
//// [tests/cases/compiler/caseInsensitiveFileSystemWithCapsImportTypeDeclarations.ts] ////
2+
3+
//// [index.ts]
4+
import { TypeB } from './type-b';
5+
6+
export class Broken {
7+
method () {
8+
return { } as TypeB;
9+
}
10+
}
11+
//// [type-b.ts]
12+
import { Merge } from './types';
13+
import { TypeA } from './type-a';
14+
15+
export type TypeB = Merge<TypeA, {
16+
b: string;
17+
}>;
18+
//// [type-a.ts]
19+
export type TypeA = {
20+
a: string;
21+
}
22+
//// [types.ts]
23+
export type Merge<T, U> = T & U;
24+
25+
26+
//// [types.js]
27+
"use strict";
28+
exports.__esModule = true;
29+
//// [type-a.js]
30+
"use strict";
31+
exports.__esModule = true;
32+
//// [type-b.js]
33+
"use strict";
34+
exports.__esModule = true;
35+
//// [index.js]
36+
"use strict";
37+
exports.__esModule = true;
38+
var Broken = /** @class */ (function () {
39+
function Broken() {
40+
}
41+
Broken.prototype.method = function () {
42+
return {};
43+
};
44+
return Broken;
45+
}());
46+
exports.Broken = Broken;
47+
48+
49+
//// [types.d.ts]
50+
export declare type Merge<T, U> = T & U;
51+
//// [type-a.d.ts]
52+
export declare type TypeA = {
53+
a: string;
54+
};
55+
//// [type-b.d.ts]
56+
import { Merge } from './types';
57+
import { TypeA } from './type-a';
58+
export declare type TypeB = Merge<TypeA, {
59+
b: string;
60+
}>;
61+
//// [index.d.ts]
62+
export declare class Broken {
63+
method(): import("./types").Merge<import("./type-a").TypeA, {
64+
b: string;
65+
}>;
66+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
=== tests/cases/compiler/Uppercased_Dir/src/index.ts ===
2+
import { TypeB } from './type-b';
3+
>TypeB : Symbol(TypeB, Decl(index.ts, 0, 8))
4+
5+
export class Broken {
6+
>Broken : Symbol(Broken, Decl(index.ts, 0, 33))
7+
8+
method () {
9+
>method : Symbol(Broken.method, Decl(index.ts, 2, 21))
10+
11+
return { } as TypeB;
12+
>TypeB : Symbol(TypeB, Decl(index.ts, 0, 8))
13+
}
14+
}
15+
=== tests/cases/compiler/Uppercased_Dir/src/type-b.ts ===
16+
import { Merge } from './types';
17+
>Merge : Symbol(Merge, Decl(type-b.ts, 0, 8))
18+
19+
import { TypeA } from './type-a';
20+
>TypeA : Symbol(TypeA, Decl(type-b.ts, 1, 8))
21+
22+
export type TypeB = Merge<TypeA, {
23+
>TypeB : Symbol(TypeB, Decl(type-b.ts, 1, 33))
24+
>Merge : Symbol(Merge, Decl(type-b.ts, 0, 8))
25+
>TypeA : Symbol(TypeA, Decl(type-b.ts, 1, 8))
26+
27+
b: string;
28+
>b : Symbol(b, Decl(type-b.ts, 3, 34))
29+
30+
}>;
31+
=== tests/cases/compiler/Uppercased_Dir/src/type-a.ts ===
32+
export type TypeA = {
33+
>TypeA : Symbol(TypeA, Decl(type-a.ts, 0, 0))
34+
35+
a: string;
36+
>a : Symbol(a, Decl(type-a.ts, 0, 21))
37+
}
38+
=== tests/cases/compiler/Uppercased_Dir/src/types.ts ===
39+
export type Merge<T, U> = T & U;
40+
>Merge : Symbol(Merge, Decl(types.ts, 0, 0))
41+
>T : Symbol(T, Decl(types.ts, 0, 18))
42+
>U : Symbol(U, Decl(types.ts, 0, 20))
43+
>T : Symbol(T, Decl(types.ts, 0, 18))
44+
>U : Symbol(U, Decl(types.ts, 0, 20))
45+
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
=== tests/cases/compiler/Uppercased_Dir/src/index.ts ===
2+
import { TypeB } from './type-b';
3+
>TypeB : any
4+
5+
export class Broken {
6+
>Broken : Broken
7+
8+
method () {
9+
>method : () => import("tests/cases/compiler/Uppercased_Dir/src/types").Merge<import("tests/cases/compiler/Uppercased_Dir/src/type-a").TypeA, { b: string; }>
10+
11+
return { } as TypeB;
12+
>{ } as TypeB : import("tests/cases/compiler/Uppercased_Dir/src/types").Merge<import("tests/cases/compiler/Uppercased_Dir/src/type-a").TypeA, { b: string; }>
13+
>{ } : {}
14+
>TypeB : import("tests/cases/compiler/Uppercased_Dir/src/types").Merge<import("tests/cases/compiler/Uppercased_Dir/src/type-a").TypeA, { b: string; }>
15+
}
16+
}
17+
=== tests/cases/compiler/Uppercased_Dir/src/type-b.ts ===
18+
import { Merge } from './types';
19+
>Merge : any
20+
21+
import { TypeA } from './type-a';
22+
>TypeA : any
23+
24+
export type TypeB = Merge<TypeA, {
25+
>TypeB : Merge<TypeA, { b: string; }>
26+
>Merge : Merge<T, U>
27+
>TypeA : TypeA
28+
29+
b: string;
30+
>b : string
31+
32+
}>;
33+
=== tests/cases/compiler/Uppercased_Dir/src/type-a.ts ===
34+
export type TypeA = {
35+
>TypeA : TypeA
36+
37+
a: string;
38+
>a : string
39+
}
40+
=== tests/cases/compiler/Uppercased_Dir/src/types.ts ===
41+
export type Merge<T, U> = T & U;
42+
>Merge : Merge<T, U>
43+
>T : T
44+
>U : U
45+
>T : T
46+
>U : U
47+
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// @declaration: true
2+
// @useCaseSensitiveFileNames: false
3+
// @filename: Uppercased_Dir/src/index.ts
4+
import { TypeB } from './type-b';
5+
6+
export class Broken {
7+
method () {
8+
return { } as TypeB;
9+
}
10+
}
11+
// @filename: Uppercased_Dir/src/type-b.ts
12+
import { Merge } from './types';
13+
import { TypeA } from './type-a';
14+
15+
export type TypeB = Merge<TypeA, {
16+
b: string;
17+
}>;
18+
// @filename: Uppercased_Dir/src/type-a.ts
19+
export type TypeA = {
20+
a: string;
21+
}
22+
// @filename: Uppercased_Dir/src/types.ts
23+
export type Merge<T, U> = T & U;

0 commit comments

Comments
 (0)