Skip to content

Commit 1f0f7c8

Browse files
authored
If resolvedFileName differs with realPath only in casing use the resolvedFileName before realpath so that errors can be reported with forceConsistentCasingInFileNames (#50364)
* Add tests when realpath supresses the casing error * Fix when real path results in value that differs only in case Fixes #49470 * Comment
1 parent ea36fb3 commit 1f0f7c8

File tree

6 files changed

+107
-12
lines changed

6 files changed

+107
-12
lines changed

src/compiler/moduleNameResolver.ts

+8-4
Original file line numberDiff line numberDiff line change
@@ -392,10 +392,12 @@ namespace ts {
392392
if (resolved) {
393393
const { fileName, packageId } = resolved;
394394
const resolvedFileName = options.preserveSymlinks ? fileName : realPath(fileName, host, traceEnabled);
395+
const pathsAreEqual = arePathsEqual(fileName, resolvedFileName, host);
395396
resolvedTypeReferenceDirective = {
396397
primary,
397-
resolvedFileName,
398-
originalPath: arePathsEqual(fileName, resolvedFileName, host) ? undefined : fileName,
398+
// If the fileName and realpath are differing only in casing prefer fileName so that we can issue correct errors for casing under forceConsistentCasingInFileNames
399+
resolvedFileName: pathsAreEqual ? fileName : resolvedFileName,
400+
originalPath: pathsAreEqual ? undefined : fileName,
399401
packageId,
400402
isExternalLibraryImport: pathContainsNodeModules(fileName),
401403
};
@@ -1406,8 +1408,10 @@ namespace ts {
14061408
let resolvedValue = resolved.value;
14071409
if (!compilerOptions.preserveSymlinks && resolvedValue && !resolvedValue.originalPath) {
14081410
const path = realPath(resolvedValue.path, host, traceEnabled);
1409-
const originalPath = arePathsEqual(path, resolvedValue.path, host) ? undefined : resolvedValue.path;
1410-
resolvedValue = { ...resolvedValue, path, originalPath };
1411+
const pathsAreEqual = arePathsEqual(path, resolvedValue.path, host);
1412+
const originalPath = pathsAreEqual ? undefined : resolvedValue.path;
1413+
// If the path and realpath are differing only in casing prefer path so that we can issue correct errors for casing under forceConsistentCasingInFileNames
1414+
resolvedValue = { ...resolvedValue, path: pathsAreEqual ? resolvedValue.path : path, originalPath };
14111415
}
14121416
// For node_modules lookups, get the real path so that multiple accesses to an `npm link`-ed module do not create duplicate files.
14131417
return { value: resolvedValue && { resolved: resolvedValue, isExternalLibraryImport: true } };

src/testRunner/tsconfig.json

+1
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@
151151
"unittests/tsc/cancellationToken.ts",
152152
"unittests/tsc/composite.ts",
153153
"unittests/tsc/declarationEmit.ts",
154+
"unittests/tsc/forceConsistentCasingInFileNames.ts",
154155
"unittests/tsc/incremental.ts",
155156
"unittests/tsc/listFilesOnly.ts",
156157
"unittests/tsc/projectReferences.ts",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
namespace ts {
2+
describe("unittests:: tsc:: forceConsistentCasingInFileNames::", () => {
3+
verifyTsc({
4+
scenario: "forceConsistentCasingInFileNames",
5+
subScenario: "with relative and non relative file resolutions",
6+
commandLineArgs: ["/src/project/src/struct.d.ts", "--forceConsistentCasingInFileNames", "--explainFiles"],
7+
fs: () => loadProjectFromFiles({
8+
"/src/project/src/struct.d.ts": Utils.dedent`
9+
import * as xs1 from "fp-ts/lib/Struct";
10+
import * as xs2 from "fp-ts/lib/struct";
11+
import * as xs3 from "./Struct";
12+
import * as xs4 from "./struct";
13+
`,
14+
"/src/project/node_modules/fp-ts/lib/struct.d.ts": `export function foo(): void`,
15+
}),
16+
});
17+
});
18+
}

src/testRunner/unittests/tscWatch/forceConsistentCasingInFileNames.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ export const Fragment: unique symbol;
113113
path: `${projectRoot}/tsconfig.json`,
114114
content: JSON.stringify({
115115
compilerOptions: { jsx: "react-jsx", jsxImportSource: "react", forceConsistentCasingInFileNames: true },
116-
files: ["node_modules/react/jsx-Runtime/index.d.ts", "index.tsx"] // NB: casing does not match disk
116+
files: ["node_modules/react/Jsx-Runtime/index.d.ts", "index.tsx"]
117117
})
118118
}
119119
], { currentDirectory: projectRoot }),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
Input::
2+
//// [/lib/lib.d.ts]
3+
/// <reference no-default-lib="true"/>
4+
interface Boolean {}
5+
interface Function {}
6+
interface CallableFunction {}
7+
interface NewableFunction {}
8+
interface IArguments {}
9+
interface Number { toExponential: any; }
10+
interface Object {}
11+
interface RegExp {}
12+
interface String { charAt: any; }
13+
interface Array<T> { length: number; [n: number]: T; }
14+
interface ReadonlyArray<T> {}
15+
declare const console: { log(msg: any): void; };
16+
17+
//// [/src/project/node_modules/fp-ts/lib/struct.d.ts]
18+
export function foo(): void
19+
20+
//// [/src/project/src/struct.d.ts]
21+
import * as xs1 from "fp-ts/lib/Struct";
22+
import * as xs2 from "fp-ts/lib/struct";
23+
import * as xs3 from "./Struct";
24+
import * as xs4 from "./struct";
25+
26+
27+
28+
29+
Output::
30+
/lib/tsc /src/project/src/struct.d.ts --forceConsistentCasingInFileNames --explainFiles
31+
src/project/src/struct.d.ts:2:22 - error TS1149: File name '/src/project/node_modules/fp-ts/lib/struct.d.ts' differs from already included file name '/src/project/node_modules/fp-ts/lib/Struct.d.ts' only in casing.
32+
The file is in the program because:
33+
Imported via "fp-ts/lib/Struct" from file '/src/project/src/struct.d.ts'
34+
Imported via "fp-ts/lib/struct" from file '/src/project/src/struct.d.ts'
35+
36+
2 import * as xs2 from "fp-ts/lib/struct";
37+
   ~~~~~~~~~~~~~~~~~~
38+
39+
src/project/src/struct.d.ts:1:22
40+
1 import * as xs1 from "fp-ts/lib/Struct";
41+
   ~~~~~~~~~~~~~~~~~~
42+
File is included via import here.
43+
44+
src/project/src/struct.d.ts:3:22 - error TS1149: File name '/src/project/src/Struct.d.ts' differs from already included file name '/src/project/src/struct.d.ts' only in casing.
45+
The file is in the program because:
46+
Root file specified for compilation
47+
Imported via "./Struct" from file '/src/project/src/struct.d.ts'
48+
Imported via "./struct" from file '/src/project/src/struct.d.ts'
49+
50+
3 import * as xs3 from "./Struct";
51+
   ~~~~~~~~~~
52+
53+
src/project/src/struct.d.ts:4:22
54+
4 import * as xs4 from "./struct";
55+
   ~~~~~~~~~~
56+
File is included via import here.
57+
58+
lib/lib.d.ts
59+
Default library for target 'es3'
60+
src/project/node_modules/fp-ts/lib/Struct.d.ts
61+
Imported via "fp-ts/lib/Struct" from file 'src/project/src/struct.d.ts'
62+
Imported via "fp-ts/lib/struct" from file 'src/project/src/struct.d.ts'
63+
src/project/src/struct.d.ts
64+
Root file specified for compilation
65+
Imported via "./Struct" from file 'src/project/src/struct.d.ts'
66+
Imported via "./struct" from file 'src/project/src/struct.d.ts'
67+
68+
Found 2 errors in the same file, starting at: src/project/src/struct.d.ts:2
69+
70+
exitCode:: ExitStatus.DiagnosticsPresent_OutputsGenerated
71+
72+

tests/baselines/reference/tscWatch/forceConsistentCasingInFileNames/jsxImportSource-option-changed.js

+7-7
Original file line numberDiff line numberDiff line change
@@ -33,27 +33,27 @@ export const Fragment: unique symbol;
3333
export const App = () => <div propA={true}></div>;
3434

3535
//// [/user/username/projects/myproject/tsconfig.json]
36-
{"compilerOptions":{"jsx":"react-jsx","jsxImportSource":"react","forceConsistentCasingInFileNames":true},"files":["node_modules/react/jsx-Runtime/index.d.ts","index.tsx"]}
36+
{"compilerOptions":{"jsx":"react-jsx","jsxImportSource":"react","forceConsistentCasingInFileNames":true},"files":["node_modules/react/Jsx-Runtime/index.d.ts","index.tsx"]}
3737

3838

3939
/a/lib/tsc.js --w --p . --explainFiles
4040
Output::
4141
>> Screen clear
4242
[12:00:31 AM] Starting compilation in watch mode...
4343

44-
[91merror[0m[90m TS1149: [0mFile name '/user/username/projects/myproject/node_modules/react/Jsx-runtime/index.d.ts' differs from already included file name '/user/username/projects/myproject/node_modules/react/jsx-Runtime/index.d.ts' only in casing.
44+
[91merror[0m[90m TS1149: [0mFile name '/user/username/projects/myproject/node_modules/react/jsx-runtime/index.d.ts' differs from already included file name '/user/username/projects/myproject/node_modules/react/Jsx-Runtime/index.d.ts' only in casing.
4545
The file is in the program because:
4646
Part of 'files' list in tsconfig.json
4747
Imported via "react/jsx-runtime" from file '/user/username/projects/myproject/index.tsx' with packageId 'react/jsx-runtime/index.d.ts@0.0.1' to import 'jsx' and 'jsxs' factory functions
4848

4949
tsconfig.json:1:115
50-
[7m1[0m {"compilerOptions":{"jsx":"react-jsx","jsxImportSource":"react","forceConsistentCasingInFileNames":true},"files":["node_modules/react/jsx-Runtime/index.d.ts","index.tsx"]}
50+
[7m1[0m {"compilerOptions":{"jsx":"react-jsx","jsxImportSource":"react","forceConsistentCasingInFileNames":true},"files":["node_modules/react/Jsx-Runtime/index.d.ts","index.tsx"]}
5151
   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5252
File is matched by 'files' list specified here.
5353

5454
../../../../a/lib/lib.d.ts
5555
Default library for target 'es3'
56-
node_modules/react/jsx-Runtime/index.d.ts
56+
node_modules/react/Jsx-Runtime/index.d.ts
5757
Part of 'files' list in tsconfig.json
5858
Imported via "react/jsx-runtime" from file 'index.tsx' with packageId 'react/jsx-runtime/index.d.ts@0.0.1' to import 'jsx' and 'jsxs' factory functions
5959
index.tsx
@@ -62,12 +62,12 @@ index.tsx
6262

6363

6464

65-
Program root files: ["/user/username/projects/myproject/node_modules/react/jsx-Runtime/index.d.ts","/user/username/projects/myproject/index.tsx"]
65+
Program root files: ["/user/username/projects/myproject/node_modules/react/Jsx-Runtime/index.d.ts","/user/username/projects/myproject/index.tsx"]
6666
Program options: {"jsx":4,"jsxImportSource":"react","forceConsistentCasingInFileNames":true,"watch":true,"project":"/user/username/projects/myproject","explainFiles":true,"configFilePath":"/user/username/projects/myproject/tsconfig.json"}
6767
Program structureReused: Not
6868
Program files::
6969
/a/lib/lib.d.ts
70-
/user/username/projects/myproject/node_modules/react/jsx-Runtime/index.d.ts
70+
/user/username/projects/myproject/node_modules/react/Jsx-Runtime/index.d.ts
7171
/user/username/projects/myproject/index.tsx
7272

7373
No cached semantic diagnostics in the builder::
@@ -81,7 +81,7 @@ WatchedFiles::
8181
/user/username/projects/myproject/tsconfig.json:
8282
{"fileName":"/user/username/projects/myproject/tsconfig.json","pollingInterval":250}
8383
/user/username/projects/myproject/node_modules/react/jsx-runtime/index.d.ts:
84-
{"fileName":"/user/username/projects/myproject/node_modules/react/jsx-Runtime/index.d.ts","pollingInterval":250}
84+
{"fileName":"/user/username/projects/myproject/node_modules/react/Jsx-Runtime/index.d.ts","pollingInterval":250}
8585
/user/username/projects/myproject/index.tsx:
8686
{"fileName":"/user/username/projects/myproject/index.tsx","pollingInterval":250}
8787
/a/lib/lib.d.ts:

0 commit comments

Comments
 (0)