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, logger: createLoggerWithInMemoryLogs(host) }); 63 openFilesForSession([{ file: loggerFile, projectRootPath: tscWatch.projectRoot }], session); 64 verifyGetErrRequest({ session, host, files: [loggerFile] }); 65 66 const newLoggerPath = loggerFile.path.toLowerCase(); 67 host.renameFile(loggerFile.path, newLoggerPath); 68 closeFilesForSession([loggerFile], session); 69 openFilesForSession([{ file: newLoggerPath, content: loggerFile.content, projectRootPath: tscWatch.projectRoot }], session); 70 71 // Apply edits for rename 72 openFilesForSession([{ file: anotherFile, projectRootPath: tscWatch.projectRoot }], session); 73 session.executeCommandSeq<protocol.UpdateOpenRequest>({ 74 command: protocol.CommandTypes.UpdateOpen, 75 arguments: { 76 changedFiles: [{ 77 fileName: anotherFile.path, 78 textChanges: [{ 79 newText: "./logger", 80 ...protocolTextSpanFromSubstring( 81 anotherFile.content, 82 "./Logger" 83 ) 84 }] 85 }] 86 } 87 }); 88 89 // Check errors in both files 90 verifyGetErrRequest({ session, host, files: [newLoggerPath, anotherFile] }); 91 baselineTsserverLogs("forceConsistentCasingInFileNames", "works when renaming file with different casing", session); 92 }); 93 94 it("when changing module name with different casing", () => { 95 const loggerFile: File = { 96 path: `${tscWatch.projectRoot}/Logger.ts`, 97 content: `export class logger { }` 98 }; 99 const anotherFile: File = { 100 path: `${tscWatch.projectRoot}/another.ts`, 101 content: `import { logger } from "./Logger"; new logger();` 102 }; 103 const tsconfig: File = { 104 path: `${tscWatch.projectRoot}/tsconfig.json`, 105 content: JSON.stringify({ 106 compilerOptions: { forceConsistentCasingInFileNames: true } 107 }) 108 }; 109 110 const host = createServerHost([loggerFile, anotherFile, tsconfig, libFile, tsconfig]); 111 const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); 112 openFilesForSession([{ file: anotherFile, projectRootPath: tscWatch.projectRoot }], session); 113 verifyGetErrRequest({ session, host, files: [anotherFile] }); 114 115 session.executeCommandSeq<protocol.UpdateOpenRequest>({ 116 command: protocol.CommandTypes.UpdateOpen, 117 arguments: { 118 changedFiles: [{ 119 fileName: anotherFile.path, 120 textChanges: [{ 121 newText: "./logger", 122 ...protocolTextSpanFromSubstring( 123 anotherFile.content, 124 "./Logger" 125 ) 126 }] 127 }] 128 } 129 }); 130 131 // Check errors in both files 132 verifyGetErrRequest({ host, session, files: [anotherFile] }); 133 baselineTsserverLogs("forceConsistentCasingInFileNames", "when changing module name with different casing", session); 134 }); 135 }); 136} 137