• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1namespace ts.projectSystem {
2    describe("unittests:: tsserver:: forceConsistentCasingInFileNames", () => {
3        it("works when extends is specified with a case insensitive file system", () => {
4            const rootPath = "/Users/username/dev/project";
5            const file1: File = {
6                path: `${rootPath}/index.ts`,
7                content: 'import {x} from "file2";',
8            };
9            const file2: File = {
10                path: `${rootPath}/file2.js`,
11                content: "",
12            };
13            const file2Dts: File = {
14                path: `${rootPath}/types/file2/index.d.ts`,
15                content: "export declare const x: string;",
16            };
17            const tsconfigAll: File = {
18                path: `${rootPath}/tsconfig.all.json`,
19                content: JSON.stringify({
20                    compilerOptions: {
21                        baseUrl: ".",
22                        paths: { file2: ["./file2.js"] },
23                        typeRoots: ["./types"],
24                        forceConsistentCasingInFileNames: true,
25                    },
26                }),
27            };
28            const tsconfig: File = {
29                path: `${rootPath}/tsconfig.json`,
30                content: JSON.stringify({ extends: "./tsconfig.all.json" }),
31            };
32
33            const host = createServerHost([file1, file2, file2Dts, libFile, tsconfig, tsconfigAll], { useCaseSensitiveFileNames: false });
34            const session = createSession(host);
35
36            openFilesForSession([file1], session);
37            const projectService = session.getProjectService();
38
39            checkNumberOfProjects(projectService, { configuredProjects: 1 });
40
41            const diagnostics = configuredProjectAt(projectService, 0).getLanguageService().getCompilerOptionsDiagnostics();
42            assert.deepEqual(diagnostics, []);
43        });
44
45        it("works when renaming file with different casing", () => {
46            const loggerFile: File = {
47                path: `${tscWatch.projectRoot}/Logger.ts`,
48                content: `export class logger { }`
49            };
50            const anotherFile: File = {
51                path: `${tscWatch.projectRoot}/another.ts`,
52                content: `import { logger } from "./Logger"; new logger();`
53            };
54            const tsconfig: File = {
55                path: `${tscWatch.projectRoot}/tsconfig.json`,
56                content: JSON.stringify({
57                    compilerOptions: { forceConsistentCasingInFileNames: true }
58                })
59            };
60
61            const host = createServerHost([loggerFile, anotherFile, tsconfig, libFile, tsconfig]);
62            const session = createSession(host, { canUseEvents: true });
63            openFilesForSession([{ file: loggerFile, projectRootPath: tscWatch.projectRoot }], session);
64            const service = session.getProjectService();
65            checkNumberOfProjects(service, { configuredProjects: 1 });
66            const project = service.configuredProjects.get(tsconfig.path)!;
67            checkProjectActualFiles(project, [loggerFile.path, anotherFile.path, libFile.path, tsconfig.path]);
68            verifyGetErrRequestNoErrors({ session, host, files: [loggerFile] });
69
70            const newLoggerPath = loggerFile.path.toLowerCase();
71            host.renameFile(loggerFile.path, newLoggerPath);
72            closeFilesForSession([loggerFile], session);
73            openFilesForSession([{ file: newLoggerPath, content: loggerFile.content, projectRootPath: tscWatch.projectRoot }], session);
74
75            // Apply edits for rename
76            openFilesForSession([{ file: anotherFile, projectRootPath: tscWatch.projectRoot }], session);
77            session.executeCommandSeq<protocol.UpdateOpenRequest>({
78                command: protocol.CommandTypes.UpdateOpen,
79                arguments: {
80                    changedFiles: [{
81                        fileName: anotherFile.path,
82                        textChanges: [{
83                            newText: "./logger",
84                            ...protocolTextSpanFromSubstring(
85                                anotherFile.content,
86                                "./Logger"
87                            )
88                        }]
89                    }]
90                }
91            });
92
93            // Check errors in both files
94            verifyGetErrRequestNoErrors({ session, host, files: [newLoggerPath, anotherFile] });
95        });
96
97        it("when changing module name with different casing", () => {
98            const loggerFile: File = {
99                path: `${tscWatch.projectRoot}/Logger.ts`,
100                content: `export class logger { }`
101            };
102            const anotherFile: File = {
103                path: `${tscWatch.projectRoot}/another.ts`,
104                content: `import { logger } from "./Logger"; new logger();`
105            };
106            const tsconfig: File = {
107                path: `${tscWatch.projectRoot}/tsconfig.json`,
108                content: JSON.stringify({
109                    compilerOptions: { forceConsistentCasingInFileNames: true }
110                })
111            };
112
113            const host = createServerHost([loggerFile, anotherFile, tsconfig, libFile, tsconfig]);
114            const session = createSession(host, { canUseEvents: true });
115            openFilesForSession([{ file: anotherFile, projectRootPath: tscWatch.projectRoot }], session);
116            const service = session.getProjectService();
117            checkNumberOfProjects(service, { configuredProjects: 1 });
118            const project = service.configuredProjects.get(tsconfig.path)!;
119            checkProjectActualFiles(project, [loggerFile.path, anotherFile.path, libFile.path, tsconfig.path]);
120            verifyGetErrRequestNoErrors({ session, host, files: [anotherFile] });
121
122            session.executeCommandSeq<protocol.UpdateOpenRequest>({
123                command: protocol.CommandTypes.UpdateOpen,
124                arguments: {
125                    changedFiles: [{
126                        fileName: anotherFile.path,
127                        textChanges: [{
128                            newText: "./logger",
129                            ...protocolTextSpanFromSubstring(
130                                anotherFile.content,
131                                "./Logger"
132                            )
133                        }]
134                    }]
135                }
136            });
137
138            const location = protocolTextSpanFromSubstring(anotherFile.content, `"./Logger"`);
139            // Check errors in both files
140            verifyGetErrRequest({
141                host,
142                session,
143                expected: [{
144                    file: anotherFile.path,
145                    syntax: [],
146                    semantic: [createDiagnostic(
147                        location.start,
148                        location.end,
149                        {
150                            message: Diagnostics.File_name_0_differs_from_already_included_file_name_1_only_in_casing,
151                            args: [loggerFile.path.toLowerCase(), loggerFile.path],
152                            next: [{
153                                message: Diagnostics.The_file_is_in_the_program_because_Colon,
154                                next: [
155                                    { message: Diagnostics.Matched_by_include_pattern_0_in_1, args: ["**/*", tsconfig.path] },
156                                    { message: Diagnostics.Imported_via_0_from_file_1, args: [`"./logger"`, anotherFile.path] }
157                                ]
158                            }]
159                        }
160                    )],
161                    suggestion: []
162                }]
163            });
164        });
165    });
166}
167