1namespace ts.projectSystem { 2 describe("unittests:: tsserver:: searching for config file", () => { 3 it("should stop at projectRootPath if given", () => { 4 const f1 = { 5 path: "/a/file1.ts", 6 content: "" 7 }; 8 const configFile = { 9 path: "/tsconfig.json", 10 content: "{}" 11 }; 12 const host = createServerHost([f1, configFile]); 13 const service = createProjectService(host); 14 service.openClientFile(f1.path, /*fileContent*/ undefined, /*scriptKind*/ undefined, "/a"); 15 16 checkNumberOfConfiguredProjects(service, 0); 17 checkNumberOfInferredProjects(service, 1); 18 19 service.closeClientFile(f1.path); 20 service.openClientFile(f1.path); 21 checkNumberOfConfiguredProjects(service, 1); 22 checkNumberOfInferredProjects(service, 0); 23 }); 24 25 it("should use projectRootPath when searching for inferred project again", () => { 26 const projectDir = "/a/b/projects/project"; 27 const configFileLocation = `${projectDir}/src`; 28 const f1 = { 29 path: `${configFileLocation}/file1.ts`, 30 content: "" 31 }; 32 const configFile = { 33 path: `${configFileLocation}/tsconfig.json`, 34 content: "{}" 35 }; 36 const configFile2 = { 37 path: "/a/b/projects/tsconfig.json", 38 content: "{}" 39 }; 40 const host = createServerHost([f1, libFile, configFile, configFile2]); 41 const service = createProjectService(host); 42 service.openClientFile(f1.path, /*fileContent*/ undefined, /*scriptKind*/ undefined, projectDir); 43 checkNumberOfProjects(service, { configuredProjects: 1 }); 44 assert.isDefined(service.configuredProjects.get(configFile.path)); 45 checkWatchedFiles(host, [libFile.path, configFile.path]); 46 checkWatchedDirectories(host, [], /*recursive*/ false); 47 const typeRootLocations = getTypeRootsFromLocation(configFileLocation); 48 checkWatchedDirectories(host, typeRootLocations.concat(configFileLocation), /*recursive*/ true); 49 50 // Delete config file - should create inferred project and not configured project 51 host.deleteFile(configFile.path); 52 host.runQueuedTimeoutCallbacks(); 53 checkNumberOfProjects(service, { inferredProjects: 1 }); 54 checkWatchedFiles(host, [libFile.path, configFile.path, `${configFileLocation}/jsconfig.json`, `${projectDir}/tsconfig.json`, `${projectDir}/jsconfig.json`]); 55 checkWatchedDirectories(host, [], /*recursive*/ false); 56 checkWatchedDirectories(host, typeRootLocations, /*recursive*/ true); 57 }); 58 59 it("should use projectRootPath when searching for inferred project again 2", () => { 60 const projectDir = "/a/b/projects/project"; 61 const configFileLocation = `${projectDir}/src`; 62 const f1 = { 63 path: `${configFileLocation}/file1.ts`, 64 content: "" 65 }; 66 const configFile = { 67 path: `${configFileLocation}/tsconfig.json`, 68 content: "{}" 69 }; 70 const configFile2 = { 71 path: "/a/b/projects/tsconfig.json", 72 content: "{}" 73 }; 74 const host = createServerHost([f1, libFile, configFile, configFile2]); 75 const service = createProjectService(host, { useSingleInferredProject: true, useInferredProjectPerProjectRoot: true }); 76 service.openClientFile(f1.path, /*fileContent*/ undefined, /*scriptKind*/ undefined, projectDir); 77 checkNumberOfProjects(service, { configuredProjects: 1 }); 78 assert.isDefined(service.configuredProjects.get(configFile.path)); 79 checkWatchedFiles(host, [libFile.path, configFile.path]); 80 checkWatchedDirectories(host, [], /*recursive*/ false); 81 checkWatchedDirectories(host, getTypeRootsFromLocation(configFileLocation).concat(configFileLocation), /*recursive*/ true); 82 83 // Delete config file - should create inferred project with project root path set 84 host.deleteFile(configFile.path); 85 host.runQueuedTimeoutCallbacks(); 86 checkNumberOfProjects(service, { inferredProjects: 1 }); 87 assert.equal(service.inferredProjects[0].projectRootPath, projectDir); 88 checkWatchedFiles(host, [libFile.path, configFile.path, `${configFileLocation}/jsconfig.json`, `${projectDir}/tsconfig.json`, `${projectDir}/jsconfig.json`]); 89 checkWatchedDirectories(host, [], /*recursive*/ false); 90 checkWatchedDirectories(host, getTypeRootsFromLocation(projectDir), /*recursive*/ true); 91 }); 92 93 describe("when the opened file is not from project root", () => { 94 const projectRoot = "/a/b/projects/project"; 95 const file: File = { 96 path: `${projectRoot}/src/index.ts`, 97 content: "let y = 10" 98 }; 99 const tsconfig: File = { 100 path: `${projectRoot}/tsconfig.json`, 101 content: "{}" 102 }; 103 const dirOfFile = getDirectoryPath(file.path); 104 105 function openClientFile(files: File[]) { 106 const host = createServerHost(files); 107 const projectService = createProjectService(host); 108 109 projectService.openClientFile(file.path, /*fileContent*/ undefined, /*scriptKind*/ undefined, "/a/b/projects/proj"); 110 return { host, projectService }; 111 } 112 113 function verifyConfiguredProject(host: TestServerHost, projectService: TestProjectService, orphanInferredProject?: boolean) { 114 projectService.checkNumberOfProjects({ configuredProjects: 1, inferredProjects: orphanInferredProject ? 1 : 0 }); 115 const project = Debug.checkDefined(projectService.configuredProjects.get(tsconfig.path)); 116 117 if (orphanInferredProject) { 118 const inferredProject = projectService.inferredProjects[0]; 119 assert.isTrue(inferredProject.isOrphan()); 120 } 121 122 checkProjectActualFiles(project, [file.path, libFile.path, tsconfig.path]); 123 checkWatchedFiles(host, [libFile.path, tsconfig.path]); 124 checkWatchedDirectories(host, emptyArray, /*recursive*/ false); 125 checkWatchedDirectories(host, (orphanInferredProject ? [projectRoot, `${dirOfFile}/node_modules/@types`] : [projectRoot]).concat(getTypeRootsFromLocation(projectRoot)), /*recursive*/ true); 126 } 127 128 function verifyInferredProject(host: TestServerHost, projectService: TestProjectService) { 129 projectService.checkNumberOfProjects({ inferredProjects: 1 }); 130 const project = projectService.inferredProjects[0]; 131 assert.isDefined(project); 132 133 const filesToWatch = [libFile.path, ...getConfigFilesToWatch(dirOfFile)]; 134 135 checkProjectActualFiles(project, [file.path, libFile.path]); 136 checkWatchedFiles(host, filesToWatch); 137 checkWatchedDirectories(host, emptyArray, /*recursive*/ false); 138 checkWatchedDirectories(host, getTypeRootsFromLocation(dirOfFile), /*recursive*/ true); 139 } 140 141 it("tsconfig for the file exists", () => { 142 const { host, projectService } = openClientFile([file, libFile, tsconfig]); 143 verifyConfiguredProject(host, projectService); 144 145 host.deleteFile(tsconfig.path); 146 host.runQueuedTimeoutCallbacks(); 147 verifyInferredProject(host, projectService); 148 149 host.writeFile(tsconfig.path, tsconfig.content); 150 host.runQueuedTimeoutCallbacks(); 151 verifyConfiguredProject(host, projectService, /*orphanInferredProject*/ true); 152 }); 153 154 it("tsconfig for the file does not exist", () => { 155 const { host, projectService } = openClientFile([file, libFile]); 156 verifyInferredProject(host, projectService); 157 158 host.writeFile(tsconfig.path, tsconfig.content); 159 host.runQueuedTimeoutCallbacks(); 160 verifyConfiguredProject(host, projectService, /*orphanInferredProject*/ true); 161 162 host.deleteFile(tsconfig.path); 163 host.runQueuedTimeoutCallbacks(); 164 verifyInferredProject(host, projectService); 165 }); 166 }); 167 168 describe("should not search and watch config files from directories that cannot be watched", () => { 169 const root = "/root/teams/VSCode68/Shared Documents/General/jt-ts-test-workspace"; 170 function verifyConfigFileWatch(projectRootPath: string | undefined) { 171 const path = `${root}/x.js`; 172 const host = createServerHost([libFile, { path, content: "const x = 10" }], { useCaseSensitiveFileNames: true }); 173 const service = createProjectService(host); 174 service.openClientFile(path, /*fileContent*/ undefined, /*scriptKind*/ undefined, projectRootPath); 175 checkNumberOfProjects(service, { inferredProjects: 1 }); 176 checkProjectActualFiles(service.inferredProjects[0], [path, libFile.path]); 177 checkWatchedFilesDetailed(host, [libFile.path, ...getConfigFilesToWatch(root)], 1); 178 } 179 180 it("when projectRootPath is not present", () => { 181 verifyConfigFileWatch(/*projectRootPath*/ undefined); 182 }); 183 it("when projectRootPath is present but file is not from project root", () => { 184 verifyConfigFileWatch("/a/b"); 185 }); 186 }); 187 }); 188} 189