1namespace ts.projectSystem { 2 describe("unittests:: tsserver:: projects with references: invoking when references are already built", () => { 3 it("on sample project", () => { 4 const coreConfig = TestFSWithWatch.getTsBuildProjectFile("sample1", "core/tsconfig.json"); 5 const coreIndex = TestFSWithWatch.getTsBuildProjectFile("sample1", "core/index.ts"); 6 const coreAnotherModule = TestFSWithWatch.getTsBuildProjectFile("sample1", "core/anotherModule.ts"); 7 const coreSomeDecl = TestFSWithWatch.getTsBuildProjectFile("sample1", "core/some_decl.d.ts"); 8 const logicConfig = TestFSWithWatch.getTsBuildProjectFile("sample1", "logic/tsconfig.json"); 9 const logicIndex = TestFSWithWatch.getTsBuildProjectFile("sample1", "logic/index.ts"); 10 const testsConfig = TestFSWithWatch.getTsBuildProjectFile("sample1", "tests/tsconfig.json"); 11 const testsIndex = TestFSWithWatch.getTsBuildProjectFile("sample1", "tests/index.ts"); 12 const host = createServerHost([libFile, coreConfig, coreIndex, coreAnotherModule, coreSomeDecl, logicConfig, logicIndex, testsConfig, testsIndex]); 13 const logger = createLoggerWithInMemoryLogs(host); 14 const service = createProjectService(host, { logger }); 15 service.openClientFile(testsIndex.path); 16 17 // local edit in ts file 18 host.appendFile(logicIndex.path, `function foo() {}`); 19 host.checkTimeoutQueueLengthAndRun(2); 20 21 // non local edit in ts file 22 host.appendFile(logicIndex.path, `export function gfoo() {}`); 23 host.checkTimeoutQueueLengthAndRun(2); 24 25 // change in project reference config file 26 host.writeFile(logicConfig.path, JSON.stringify({ 27 compilerOptions: { composite: true, declaration: true, declarationDir: "decls" }, 28 references: [{ path: "../core" }] 29 })); 30 host.checkTimeoutQueueLengthAndRun(2); 31 baselineTsserverLogs("projectsWithReferences", "sample project", service); 32 }); 33 34 describe("on transitive references in different folders", () => { 35 function createService() { 36 const aConfig: File = { 37 path: `${tscWatch.projectRoot}/a/tsconfig.json`, 38 content: JSON.stringify({ 39 compilerOptions: { composite: true }, 40 files: ["index.ts"] 41 }), 42 }; 43 const bConfig: File = { 44 path: `${tscWatch.projectRoot}/b/tsconfig.json`, 45 content: JSON.stringify({ 46 compilerOptions: { composite: true, baseUrl: "./", paths: { "@ref/*": ["../*"] } }, 47 files: ["index.ts"], 48 references: [{ path: `../a` }] 49 }), 50 }; 51 const cConfig: File = { 52 path: `${tscWatch.projectRoot}/c/tsconfig.json`, 53 content: JSON.stringify({ 54 compilerOptions: { baseUrl: "./", paths: { "@ref/*": ["../refs/*"] } }, 55 files: ["index.ts"], 56 references: [{ path: `../b` }] 57 }), 58 }; 59 const aTs: File = { 60 path: `${tscWatch.projectRoot}/a/index.ts`, 61 content: `export class A {}`, 62 }; 63 const bTs: File = { 64 path: `${tscWatch.projectRoot}/b/index.ts`, 65 content: `import {A} from '@ref/a'; 66export const b = new A();`, 67 }; 68 const cTs: File = { 69 path: `${tscWatch.projectRoot}/c/index.ts`, 70 content: `import {b} from '../b'; 71import {X} from "@ref/a"; 72b; 73X;`, 74 }; 75 const refsTs: File = { 76 path: `${tscWatch.projectRoot}/refs/a.d.ts`, 77 content: `export class X {} 78export class A {}` 79 }; 80 const host = createServerHost([libFile, aConfig, bConfig, cConfig, aTs, bTs, cTs, refsTs]); 81 const service = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); 82 service.openClientFile(cTs.path); 83 return { host, service, aConfig, bConfig, cConfig, aTs, bTs, cTs, refsTs }; 84 } 85 86 it("non local edit", () => { 87 const { host, service, bTs } = createService(); 88 checkNumberOfProjects(service, { configuredProjects: 1 }); 89 90 // non local edit 91 host.appendFile(bTs.path, `export function gFoo() { }`); 92 host.checkTimeoutQueueLengthAndRun(2); 93 baselineTsserverLogs("projectsWithReferences", "transitive references with non local edit", service); 94 }); 95 96 it("edit on config file", () => { 97 const { host, service, cConfig, refsTs } = createService(); 98 const nRefsTs: File = { 99 path: `${tscWatch.projectRoot}/nrefs/a.d.ts`, 100 content: refsTs.content 101 }; 102 const cTsConfigJson = JSON.parse(cConfig.content); 103 host.ensureFileOrFolder(nRefsTs); 104 cTsConfigJson.compilerOptions.paths = { "@ref/*": ["../nrefs/*"] }; 105 host.writeFile(cConfig.path, JSON.stringify(cTsConfigJson)); 106 host.checkTimeoutQueueLengthAndRun(2); 107 108 // revert the edit on config file 109 host.writeFile(cConfig.path, cConfig.content); 110 host.checkTimeoutQueueLengthAndRun(2); 111 baselineTsserverLogs("projectsWithReferences", "transitive references with edit on config file", service); 112 }); 113 114 it("edit in referenced config file", () => { 115 const { host, service, bConfig, refsTs } = createService(); 116 const nRefsTs: File = { 117 path: `${tscWatch.projectRoot}/nrefs/a.d.ts`, 118 content: refsTs.content 119 }; 120 const bTsConfigJson = JSON.parse(bConfig.content); 121 host.ensureFileOrFolder(nRefsTs); 122 bTsConfigJson.compilerOptions.paths = { "@ref/*": ["../nrefs/*"] }; 123 host.writeFile(bConfig.path, JSON.stringify(bTsConfigJson)); 124 host.checkTimeoutQueueLengthAndRun(2); 125 126 // revert the edit on config file 127 host.writeFile(bConfig.path, bConfig.content); 128 host.checkTimeoutQueueLengthAndRun(2); 129 baselineTsserverLogs("projectsWithReferences", "transitive references with edit in referenced config file", service); 130 }); 131 132 it("deleting referenced config file", () => { 133 const { host, service, bConfig } = createService(); 134 host.deleteFile(bConfig.path); 135 host.checkTimeoutQueueLengthAndRun(3); // Schedules failed lookup invalidation 136 137 // revert 138 host.writeFile(bConfig.path, bConfig.content); 139 host.checkTimeoutQueueLengthAndRun(3); // Schedules failed lookup invalidation 140 baselineTsserverLogs("projectsWithReferences", "transitive references with deleting referenced config file", service); 141 }); 142 143 it("deleting transitively referenced config file", () => { 144 const { host, service, aConfig } = createService(); 145 host.deleteFile(aConfig.path); 146 host.checkTimeoutQueueLengthAndRun(3); // Schedules failed lookup invalidation 147 148 // revert 149 host.writeFile(aConfig.path, aConfig.content); 150 host.checkTimeoutQueueLengthAndRun(3); // Schedules failed lookup invalidation 151 baselineTsserverLogs("projectsWithReferences", "transitive references with deleting transitively referenced config file", service); 152 }); 153 }); 154 155 describe("on transitive references in different folders without files", () => { 156 function createService() { 157 const aConfig: File = { 158 path: `${tscWatch.projectRoot}/a/tsconfig.json`, 159 content: JSON.stringify({ compilerOptions: { composite: true } }), 160 }; 161 const bConfig: File = { 162 path: `${tscWatch.projectRoot}/b/tsconfig.json`, 163 content: JSON.stringify({ 164 compilerOptions: { composite: true, baseUrl: "./", paths: { "@ref/*": ["../*"] } }, 165 references: [{ path: `../a` }] 166 }), 167 }; 168 const cConfig: File = { 169 path: `${tscWatch.projectRoot}/c/tsconfig.json`, 170 content: JSON.stringify({ 171 compilerOptions: { baseUrl: "./", paths: { "@ref/*": ["../refs/*"] } }, 172 references: [{ path: `../b` }] 173 }), 174 }; 175 const aTs: File = { 176 path: `${tscWatch.projectRoot}/a/index.ts`, 177 content: `export class A {}`, 178 }; 179 const bTs: File = { 180 path: `${tscWatch.projectRoot}/b/index.ts`, 181 content: `import {A} from '@ref/a'; 182export const b = new A();`, 183 }; 184 const cTs: File = { 185 path: `${tscWatch.projectRoot}/c/index.ts`, 186 content: `import {b} from '../b'; 187import {X} from "@ref/a"; 188b; 189X;`, 190 }; 191 const refsTs: File = { 192 path: `${tscWatch.projectRoot}/refs/a.d.ts`, 193 content: `export class X {} 194export class A {}` 195 }; 196 const host = createServerHost([libFile, aConfig, bConfig, cConfig, aTs, bTs, cTs, refsTs]); 197 const service = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); 198 service.openClientFile(cTs.path); 199 return { host, service, aConfig, bConfig, cConfig, aTs, bTs, cTs, refsTs }; 200 } 201 202 it("non local edit", () => { 203 const { host, service, bTs } = createService(); 204 205 // non local edit 206 host.appendFile(bTs.path, `export function gFoo() { }`); 207 host.checkTimeoutQueueLengthAndRun(2); 208 baselineTsserverLogs("projectsWithReferences", "trasitive references without files with non local edit", service); 209 }); 210 211 it("edit on config file", () => { 212 const { host, service, cConfig, refsTs } = createService(); 213 const nRefsTs: File = { 214 path: `${tscWatch.projectRoot}/nrefs/a.d.ts`, 215 content: refsTs.content 216 }; 217 const cTsConfigJson = JSON.parse(cConfig.content); 218 host.ensureFileOrFolder(nRefsTs); 219 cTsConfigJson.compilerOptions.paths = { "@ref/*": ["../nrefs/*"] }; 220 host.writeFile(cConfig.path, JSON.stringify(cTsConfigJson)); 221 host.checkTimeoutQueueLengthAndRun(2); 222 223 // revert the edit on config file 224 host.writeFile(cConfig.path, cConfig.content); 225 host.checkTimeoutQueueLengthAndRun(2); 226 baselineTsserverLogs("projectsWithReferences", "trasitive references without files with edit on config file", service); 227 }); 228 229 it("edit in referenced config file", () => { 230 const { host, service, bConfig, refsTs } = createService(); 231 const nRefsTs: File = { 232 path: `${tscWatch.projectRoot}/nrefs/a.d.ts`, 233 content: refsTs.content 234 }; 235 const bTsConfigJson = JSON.parse(bConfig.content); 236 host.ensureFileOrFolder(nRefsTs); 237 bTsConfigJson.compilerOptions.paths = { "@ref/*": ["../nrefs/*"] }; 238 host.writeFile(bConfig.path, JSON.stringify(bTsConfigJson)); 239 host.checkTimeoutQueueLengthAndRun(2); 240 241 // revert the edit on config file 242 host.writeFile(bConfig.path, bConfig.content); 243 host.checkTimeoutQueueLengthAndRun(2); 244 baselineTsserverLogs("projectsWithReferences", "trasitive references without files with edit in referenced config file", service); 245 }); 246 247 it("deleting referenced config file", () => { 248 const { host, service, bConfig } = createService(); 249 host.deleteFile(bConfig.path); 250 host.checkTimeoutQueueLengthAndRun(3); // Schedules failed lookup invalidation 251 252 // revert 253 host.writeFile(bConfig.path, bConfig.content); 254 host.checkTimeoutQueueLengthAndRun(3); // Schedules failed lookup invalidation 255 baselineTsserverLogs("projectsWithReferences", "trasitive references without files with deleting referenced config file", service); 256 }); 257 258 it("deleting transitively referenced config file", () => { 259 const { host, service, aConfig } = createService(); 260 host.deleteFile(aConfig.path); 261 host.checkTimeoutQueueLengthAndRun(3); // Schedules failed lookup invalidation 262 263 // revert 264 host.writeFile(aConfig.path, aConfig.content); 265 host.checkTimeoutQueueLengthAndRun(3); // Schedules failed lookup invalidation 266 baselineTsserverLogs("projectsWithReferences", "trasitive references without files with deleting transitively referenced config file", service); 267 }); 268 }); 269 }); 270}