1namespace ts.tscWatch { 2 import projectsLocation = TestFSWithWatch.tsbuildProjectsLocation; 3 describe("unittests:: tsbuildWatch:: watchMode:: program updates", () => { 4 const enum SubProject { 5 core = "core", 6 logic = "logic", 7 tests = "tests", 8 ui = "ui" 9 } 10 type ReadonlyFile = Readonly<File>; 11 /** [tsconfig, index] | [tsconfig, index, anotherModule, someDecl] */ 12 type SubProjectFiles = [tsconfig: ReadonlyFile, index: ReadonlyFile] | [tsconfig: ReadonlyFile, index: ReadonlyFile, anotherModule: ReadonlyFile, someDecl: ReadonlyFile]; 13 function projectFilePath(subProject: SubProject, baseFileName: string) { 14 return `${TestFSWithWatch.getTsBuildProjectFilePath("sample1", subProject)}/${baseFileName.toLowerCase()}`; 15 } 16 17 function projectFile(subProject: SubProject, baseFileName: string): File { 18 return TestFSWithWatch.getTsBuildProjectFile("sample1", `${subProject}/${baseFileName}`); 19 } 20 21 function subProjectFiles(subProject: SubProject, anotherModuleAndSomeDecl?: true): SubProjectFiles { 22 const tsconfig = projectFile(subProject, "tsconfig.json"); 23 const index = projectFile(subProject, "index.ts"); 24 if (!anotherModuleAndSomeDecl) { 25 return [tsconfig, index]; 26 } 27 const anotherModule = projectFile(SubProject.core, "anotherModule.ts"); 28 const someDecl = projectFile(SubProject.core, "some_decl.ts"); 29 return [tsconfig, index, anotherModule, someDecl]; 30 } 31 32 function changeFile(fileName: string | (() => string), content: string | (() => string), caption: string): TscWatchCompileChange { 33 return { 34 caption, 35 change: sys => sys.writeFile(isString(fileName) ? fileName : fileName(), isString(content) ? content : content()), 36 timeouts: checkSingleTimeoutQueueLengthAndRun, // Builds core 37 }; 38 } 39 40 function changeCore(content: () => string, caption: string) { 41 return changeFile(() => core[1].path, content, caption); 42 } 43 44 let core: SubProjectFiles; 45 let logic: SubProjectFiles; 46 let tests: SubProjectFiles; 47 let ui: SubProjectFiles; 48 let allFiles: readonly File[]; 49 50 before(() => { 51 core = subProjectFiles(SubProject.core, /*anotherModuleAndSomeDecl*/ true); 52 logic = subProjectFiles(SubProject.logic); 53 tests = subProjectFiles(SubProject.tests); 54 ui = subProjectFiles(SubProject.ui); 55 allFiles = [libFile, ...core, ...logic, ...tests, ...ui]; 56 }); 57 58 after(() => { 59 core = undefined!; 60 logic = undefined!; 61 tests = undefined!; 62 ui = undefined!; 63 allFiles = undefined!; 64 }); 65 66 verifyTscWatch({ 67 scenario: "programUpdates", 68 subScenario: "creates solution in watch mode", 69 commandLineArgs: ["-b", "-w", `sample1/${SubProject.tests}`], 70 sys: () => createWatchedSystem(allFiles, { currentDirectory: projectsLocation }), 71 changes: emptyArray 72 }); 73 74 it("verify building references watches only those projects", () => { 75 const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline(createWatchedSystem(allFiles, { currentDirectory: projectsLocation })); 76 const host = createSolutionBuilderWithWatchHostForBaseline(sys, cb); 77 const solutionBuilder = createSolutionBuilderWithWatch(host, [`sample1/${SubProject.tests}`], { watch: true }); 78 solutionBuilder.buildReferences(`sample1/${SubProject.tests}`); 79 runWatchBaseline({ 80 scenario: "programUpdates", 81 subScenario: "verify building references watches only those projects", 82 commandLineArgs: ["--b", "--w"], 83 sys, 84 baseline, 85 oldSnap, 86 getPrograms, 87 changes: emptyArray, 88 watchOrSolution: solutionBuilder 89 }); 90 }); 91 92 describe("validates the changes and watched files", () => { 93 const newFileWithoutExtension = "newFile"; 94 const newFile: File = { 95 path: projectFilePath(SubProject.core, `${newFileWithoutExtension}.ts`), 96 content: `export const newFileConst = 30;` 97 }; 98 99 function verifyProjectChanges(subScenario: string, allFilesGetter: () => readonly File[]) { 100 const buildLogicAndTests: TscWatchCompileChange = { 101 caption: "Build logic and tests", 102 change: noop, 103 timeouts: checkSingleTimeoutQueueLengthAndRunAndVerifyNoTimeout, 104 }; 105 106 verifyTscWatch({ 107 scenario: "programUpdates", 108 subScenario: `${subScenario}/change builds changes and reports found errors message`, 109 commandLineArgs: ["-b", "-w", `sample1/${SubProject.tests}`], 110 sys: () => createWatchedSystem( 111 allFilesGetter(), 112 { currentDirectory: projectsLocation } 113 ), 114 changes: [ 115 changeCore(() => `${core[1].content} 116export class someClass { }`, "Make change to core"), 117 buildLogicAndTests, 118 // Another change requeues and builds it 119 changeCore(() => core[1].content, "Revert core file"), 120 buildLogicAndTests, 121 { 122 caption: "Make two changes", 123 change: sys => { 124 const change1 = `${core[1].content} 125export class someClass { }`; 126 sys.writeFile(core[1].path, change1); 127 assert.equal(sys.writtenFiles.size, 1); 128 sys.writtenFiles.clear(); 129 sys.writeFile(core[1].path, `${change1} 130export class someClass2 { }`); 131 }, 132 timeouts: checkSingleTimeoutQueueLengthAndRun, // Builds core 133 }, 134 buildLogicAndTests, 135 ] 136 }); 137 138 verifyTscWatch({ 139 scenario: "programUpdates", 140 subScenario: `${subScenario}/non local change does not start build of referencing projects`, 141 commandLineArgs: ["-b", "-w", `sample1/${SubProject.tests}`], 142 sys: () => createWatchedSystem( 143 allFilesGetter(), 144 { currentDirectory: projectsLocation } 145 ), 146 changes: [ 147 changeCore(() => `${core[1].content} 148function foo() { }`, "Make local change to core"), 149 ] 150 }); 151 152 function changeNewFile(newFileContent: string) { 153 return changeFile(newFile.path, newFileContent, "Change to new File and build core"); 154 } 155 verifyTscWatch({ 156 scenario: "programUpdates", 157 subScenario: `${subScenario}/builds when new file is added, and its subsequent updates`, 158 commandLineArgs: ["-b", "-w", `sample1/${SubProject.tests}`], 159 sys: () => createWatchedSystem( 160 allFilesGetter(), 161 { currentDirectory: projectsLocation } 162 ), 163 changes: [ 164 changeNewFile(newFile.content), 165 buildLogicAndTests, 166 changeNewFile(`${newFile.content} 167export class someClass2 { }`), 168 buildLogicAndTests, 169 ] 170 }); 171 } 172 173 describe("with simple project reference graph", () => { 174 verifyProjectChanges( 175 "with simple project reference graph", 176 () => allFiles 177 ); 178 }); 179 180 describe("with circular project reference", () => { 181 verifyProjectChanges( 182 "with circular project reference", 183 () => { 184 const [coreTsconfig, ...otherCoreFiles] = core; 185 const circularCoreConfig: File = { 186 path: coreTsconfig.path, 187 content: JSON.stringify({ 188 compilerOptions: { composite: true, declaration: true }, 189 references: [{ path: "../tests", circular: true }] 190 }) 191 }; 192 return [libFile, circularCoreConfig, ...otherCoreFiles, ...logic, ...tests]; 193 } 194 ); 195 }); 196 }); 197 198 verifyTscWatch({ 199 scenario: "programUpdates", 200 subScenario: "watches config files that are not present", 201 commandLineArgs: ["-b", "-w", `sample1/${SubProject.tests}`], 202 sys: () => createWatchedSystem( 203 [libFile, ...core, logic[1], ...tests], 204 { currentDirectory: projectsLocation } 205 ), 206 changes: [ 207 { 208 caption: "Write logic tsconfig and build logic", 209 change: sys => sys.writeFile(logic[0].path, logic[0].content), 210 timeouts: checkSingleTimeoutQueueLengthAndRun, // Builds logic 211 }, 212 { 213 caption: "Build Tests", 214 change: noop, 215 // Build tests 216 timeouts: checkSingleTimeoutQueueLengthAndRunAndVerifyNoTimeout, 217 } 218 ] 219 }); 220 221 describe("when referenced using prepend, builds referencing project even for non local change", () => { 222 let coreIndex: File; 223 before(() => { 224 coreIndex = { 225 path: core[1].path, 226 content: `function foo() { return 10; }` 227 }; 228 }); 229 after(() => { 230 coreIndex = undefined!; 231 }); 232 const buildLogic: TscWatchCompileChange = { 233 caption: "Build logic", 234 change: noop, 235 // Builds logic 236 timeouts: checkSingleTimeoutQueueLengthAndRunAndVerifyNoTimeout, 237 }; 238 verifyTscWatch({ 239 scenario: "programUpdates", 240 subScenario: "when referenced using prepend builds referencing project even for non local change", 241 commandLineArgs: ["-b", "-w", `sample1/${SubProject.logic}`], 242 sys: () => { 243 const coreTsConfig: File = { 244 path: core[0].path, 245 content: JSON.stringify({ 246 compilerOptions: { composite: true, declaration: true, outFile: "index.js" } 247 }) 248 }; 249 const logicTsConfig: File = { 250 path: logic[0].path, 251 content: JSON.stringify({ 252 compilerOptions: { composite: true, declaration: true, outFile: "index.js" }, 253 references: [{ path: "../core", prepend: true }] 254 }) 255 }; 256 const logicIndex: File = { 257 path: logic[1].path, 258 content: `function bar() { return foo() + 1 };` 259 }; 260 return createWatchedSystem([libFile, coreTsConfig, coreIndex, logicTsConfig, logicIndex], { currentDirectory: projectsLocation }); 261 }, 262 changes: [ 263 changeCore(() => `${coreIndex.content} 264function myFunc() { return 10; }`, "Make non local change and build core"), 265 buildLogic, 266 changeCore(() => `${coreIndex.content} 267function myFunc() { return 100; }`, "Make local change and build core"), 268 buildLogic, 269 ] 270 }); 271 }); 272 273 describe("when referenced project change introduces error in the down stream project and then fixes it", () => { 274 const subProjectLibrary = `${projectsLocation}/sample1/Library`; 275 const libraryTs: File = { 276 path: `${subProjectLibrary}/library.ts`, 277 content: ` 278interface SomeObject 279{ 280 message: string; 281} 282 283export function createSomeObject(): SomeObject 284{ 285 return { 286 message: "new Object" 287 }; 288}` 289 }; 290 verifyTscWatch({ 291 scenario: "programUpdates", 292 subScenario: "when referenced project change introduces error in the down stream project and then fixes it", 293 commandLineArgs: ["-b", "-w", "App"], 294 sys: () => { 295 const libraryTsconfig: File = { 296 path: `${subProjectLibrary}/tsconfig.json`, 297 content: JSON.stringify({ compilerOptions: { composite: true } }) 298 }; 299 const subProjectApp = `${projectsLocation}/sample1/App`; 300 const appTs: File = { 301 path: `${subProjectApp}/app.ts`, 302 content: `import { createSomeObject } from "../Library/library"; 303createSomeObject().message;` 304 }; 305 const appTsconfig: File = { 306 path: `${subProjectApp}/tsconfig.json`, 307 content: JSON.stringify({ references: [{ path: "../Library" }] }) 308 }; 309 310 const files = [libFile, libraryTs, libraryTsconfig, appTs, appTsconfig]; 311 return createWatchedSystem(files, { currentDirectory: `${projectsLocation}/sample1` }); 312 }, 313 changes: [ 314 { 315 caption: "Introduce error", 316 // Change message in library to message2 317 change: sys => sys.writeFile(libraryTs.path, libraryTs.content.replace(/message/g, "message2")), 318 timeouts: sys => { 319 sys.checkTimeoutQueueLengthAndRun(1); // Build library 320 sys.checkTimeoutQueueLengthAndRun(1); // Build App 321 }, 322 }, 323 { 324 caption: "Fix error", 325 // Revert library changes 326 change: sys => sys.writeFile(libraryTs.path, libraryTs.content), 327 timeouts: sys => { 328 sys.checkTimeoutQueueLengthAndRun(1); // Build library 329 sys.checkTimeoutQueueLengthAndRun(1); // Build App 330 }, 331 }, 332 ] 333 }); 334 335 }); 336 337 describe("reports errors in all projects on incremental compile", () => { 338 function verifyIncrementalErrors(subScenario: string, buildOptions: readonly string[]) { 339 verifyTscWatch({ 340 scenario: "programUpdates", 341 subScenario: `reportErrors/${subScenario}`, 342 commandLineArgs: ["-b", "-w", `sample1/${SubProject.tests}`, ...buildOptions], 343 sys: () => createWatchedSystem(allFiles, { currentDirectory: projectsLocation }), 344 changes: [ 345 { 346 caption: "change logic", 347 change: sys => sys.writeFile(logic[1].path, `${logic[1].content} 348let y: string = 10;`), 349 // Builds logic 350 timeouts: checkSingleTimeoutQueueLengthAndRunAndVerifyNoTimeout, 351 }, 352 { 353 caption: "change core", 354 change: sys => sys.writeFile(core[1].path, `${core[1].content} 355let x: string = 10;`), 356 // Builds core 357 timeouts: checkSingleTimeoutQueueLengthAndRunAndVerifyNoTimeout, 358 } 359 ] 360 }); 361 } 362 verifyIncrementalErrors("when preserveWatchOutput is not used", emptyArray); 363 verifyIncrementalErrors("when preserveWatchOutput is passed on command line", ["--preserveWatchOutput"]); 364 365 describe("when declaration emit errors are present", () => { 366 const solution = "solution"; 367 const subProject = "app"; 368 const subProjectLocation = `${projectsLocation}/${solution}/${subProject}`; 369 const fileWithError: File = { 370 path: `${subProjectLocation}/fileWithError.ts`, 371 content: `export var myClassWithError = class { 372 tags() { } 373 private p = 12 374 };` 375 }; 376 const fileWithFixedError: File = { 377 path: fileWithError.path, 378 content: fileWithError.content.replace("private p = 12", "") 379 }; 380 const fileWithoutError: File = { 381 path: `${subProjectLocation}/fileWithoutError.ts`, 382 content: `export class myClass { }` 383 }; 384 const tsconfig: File = { 385 path: `${subProjectLocation}/tsconfig.json`, 386 content: JSON.stringify({ compilerOptions: { composite: true } }) 387 }; 388 389 function incrementalBuild(sys: WatchedSystem) { 390 sys.checkTimeoutQueueLengthAndRun(1); // Build the app 391 sys.checkTimeoutQueueLength(0); 392 } 393 394 const fixError: TscWatchCompileChange = { 395 caption: "Fix error in fileWithError", 396 // Fix error 397 change: sys => sys.writeFile(fileWithError.path, fileWithFixedError.content), 398 timeouts: incrementalBuild 399 }; 400 401 const changeFileWithoutError: TscWatchCompileChange = { 402 caption: "Change fileWithoutError", 403 change: sys => sys.writeFile(fileWithoutError.path, fileWithoutError.content.replace(/myClass/g, "myClass2")), 404 timeouts: incrementalBuild 405 }; 406 407 verifyTscWatch({ 408 scenario: "programUpdates", 409 subScenario: "reportErrors/declarationEmitErrors/when fixing error files all files are emitted", 410 commandLineArgs: ["-b", "-w", subProject], 411 sys: () => createWatchedSystem( 412 [libFile, fileWithError, fileWithoutError, tsconfig], 413 { currentDirectory: `${projectsLocation}/${solution}` } 414 ), 415 changes: [ 416 fixError 417 ] 418 }); 419 420 verifyTscWatch({ 421 scenario: "programUpdates", 422 subScenario: "reportErrors/declarationEmitErrors/when file with no error changes", 423 commandLineArgs: ["-b", "-w", subProject], 424 sys: () => createWatchedSystem( 425 [libFile, fileWithError, fileWithoutError, tsconfig], 426 { currentDirectory: `${projectsLocation}/${solution}` } 427 ), 428 changes: [ 429 changeFileWithoutError 430 ] 431 }); 432 433 describe("when reporting errors on introducing error", () => { 434 const introduceError: TscWatchCompileChange = { 435 caption: "Introduce error", 436 change: sys => sys.writeFile(fileWithError.path, fileWithError.content), 437 timeouts: incrementalBuild, 438 }; 439 440 verifyTscWatch({ 441 scenario: "programUpdates", 442 subScenario: "reportErrors/declarationEmitErrors/introduceError/when fixing errors only changed file is emitted", 443 commandLineArgs: ["-b", "-w", subProject], 444 sys: () => createWatchedSystem( 445 [libFile, fileWithFixedError, fileWithoutError, tsconfig], 446 { currentDirectory: `${projectsLocation}/${solution}` } 447 ), 448 changes: [ 449 introduceError, 450 fixError 451 ] 452 }); 453 454 verifyTscWatch({ 455 scenario: "programUpdates", 456 subScenario: "reportErrors/declarationEmitErrors/introduceError/when file with no error changes", 457 commandLineArgs: ["-b", "-w", subProject], 458 sys: () => createWatchedSystem( 459 [libFile, fileWithFixedError, fileWithoutError, tsconfig], 460 { currentDirectory: `${projectsLocation}/${solution}` } 461 ), 462 changes: [ 463 introduceError, 464 changeFileWithoutError 465 ] 466 }); 467 }); 468 }); 469 }); 470 471 verifyTscWatch({ 472 scenario: "programUpdates", 473 subScenario: "incremental updates in verbose mode", 474 commandLineArgs: ["-b", "-w", `sample1/${SubProject.tests}`, "-verbose"], 475 sys: () => createWatchedSystem(allFiles, { currentDirectory: projectsLocation }), 476 changes: [ 477 { 478 caption: "Make non dts change", 479 change: sys => sys.writeFile(logic[1].path, `${logic[1].content} 480function someFn() { }`), 481 timeouts: sys => { 482 sys.checkTimeoutQueueLengthAndRun(1); // build logic and updates tests 483 sys.checkTimeoutQueueLength(0); 484 }, 485 }, 486 { 487 caption: "Make dts change", 488 change: sys => sys.writeFile(logic[1].path, `${logic[1].content} 489export function someFn() { }`), 490 timeouts: sys => { 491 sys.checkTimeoutQueueLengthAndRun(1); // build logic 492 sys.checkTimeoutQueueLengthAndRun(1); // build tests 493 }, 494 } 495 ], 496 }); 497 498 verifyTscWatch({ 499 scenario: "programUpdates", 500 subScenario: "works when noUnusedParameters changes to false", 501 commandLineArgs: ["-b", "-w"], 502 sys: () => { 503 const index: File = { 504 path: `${projectRoot}/index.ts`, 505 content: `const fn = (a: string, b: string) => b;` 506 }; 507 const configFile: File = { 508 path: `${projectRoot}/tsconfig.json`, 509 content: JSON.stringify({ 510 compilerOptions: { 511 noUnusedParameters: true 512 } 513 }) 514 }; 515 return createWatchedSystem([index, configFile, libFile], { currentDirectory: projectRoot }); 516 }, 517 changes: [ 518 { 519 caption: "Change tsconfig to set noUnusedParameters to false", 520 change: sys => sys.writeFile(`${projectRoot}/tsconfig.json`, JSON.stringify({ 521 compilerOptions: { 522 noUnusedParameters: false 523 } 524 })), 525 timeouts: runQueuedTimeoutCallbacks, 526 }, 527 ] 528 }); 529 530 verifyTscWatch({ 531 scenario: "programUpdates", 532 subScenario: "should not trigger recompilation because of program emit", 533 commandLineArgs: ["-b", "-w", `sample1/${SubProject.core}`, "-verbose"], 534 sys: () => createWatchedSystem([libFile, ...core], { currentDirectory: projectsLocation }), 535 changes: [ 536 noopChange, 537 { 538 caption: "Add new file", 539 change: sys => sys.writeFile(`sample1/${SubProject.core}/file3.ts`, `export const y = 10;`), 540 timeouts: checkSingleTimeoutQueueLengthAndRun 541 }, 542 noopChange, 543 ] 544 }); 545 546 verifyTscWatch({ 547 scenario: "programUpdates", 548 subScenario: "should not trigger recompilation because of program emit with outDir specified", 549 commandLineArgs: ["-b", "-w", `sample1/${SubProject.core}`, "-verbose"], 550 sys: () => { 551 const [coreConfig, ...rest] = core; 552 const newCoreConfig: File = { path: coreConfig.path, content: JSON.stringify({ compilerOptions: { composite: true, outDir: "outDir" } }) }; 553 return createWatchedSystem([libFile, newCoreConfig, ...rest], { currentDirectory: projectsLocation }); 554 }, 555 changes: [ 556 noopChange, 557 { 558 caption: "Add new file", 559 change: sys => sys.writeFile(`sample1/${SubProject.core}/file3.ts`, `export const y = 10;`), 560 timeouts: checkSingleTimeoutQueueLengthAndRun 561 }, 562 noopChange 563 ] 564 }); 565 566 verifyTscWatch({ 567 scenario: "programUpdates", 568 subScenario: "works with extended source files", 569 commandLineArgs: ["-b", "-w", "-v", "project1.tsconfig.json", "project2.tsconfig.json"], 570 sys: () => { 571 const alphaExtendedConfigFile: File = { 572 path: "/a/b/alpha.tsconfig.json", 573 content: "{}" 574 }; 575 const project1Config: File = { 576 path: "/a/b/project1.tsconfig.json", 577 content: JSON.stringify({ 578 extends: "./alpha.tsconfig.json", 579 compilerOptions: { 580 composite: true, 581 }, 582 files: [commonFile1.path, commonFile2.path] 583 }) 584 }; 585 const bravoExtendedConfigFile: File = { 586 path: "/a/b/bravo.tsconfig.json", 587 content: JSON.stringify({ 588 extends: "./alpha.tsconfig.json" 589 }) 590 }; 591 const otherFile: File = { 592 path: "/a/b/other.ts", 593 content: "let z = 0;", 594 }; 595 const project2Config: File = { 596 path: "/a/b/project2.tsconfig.json", 597 content: JSON.stringify({ 598 extends: "./bravo.tsconfig.json", 599 compilerOptions: { 600 composite: true, 601 }, 602 files: [otherFile.path] 603 }) 604 }; 605 return createWatchedSystem([ 606 libFile, 607 alphaExtendedConfigFile, project1Config, commonFile1, commonFile2, 608 bravoExtendedConfigFile, project2Config, otherFile 609 ], { currentDirectory: "/a/b" }); 610 }, 611 changes: [ 612 { 613 caption: "Modify alpha config", 614 change: sys => sys.writeFile("/a/b/alpha.tsconfig.json", JSON.stringify({ 615 compilerOptions: { strict: true } 616 })), 617 timeouts: checkSingleTimeoutQueueLengthAndRun // Build project1 618 }, 619 { 620 caption: "Build project 2", 621 change: noop, 622 timeouts: checkSingleTimeoutQueueLengthAndRunAndVerifyNoTimeout // Build project2 623 }, 624 { 625 caption: "change bravo config", 626 change: sys => sys.writeFile("/a/b/bravo.tsconfig.json", JSON.stringify({ 627 extends: "./alpha.tsconfig.json", 628 compilerOptions: { strict: false } 629 })), 630 timeouts: checkSingleTimeoutQueueLengthAndRunAndVerifyNoTimeout // Build project2 631 }, 632 { 633 caption: "project 2 extends alpha", 634 change: sys => sys.writeFile("/a/b/project2.tsconfig.json", JSON.stringify({ 635 extends: "./alpha.tsconfig.json", 636 })), 637 timeouts: checkSingleTimeoutQueueLengthAndRunAndVerifyNoTimeout // Build project2 638 }, 639 { 640 caption: "update aplha config", 641 change: sys => sys.writeFile("/a/b/alpha.tsconfig.json", "{}"), 642 timeouts: checkSingleTimeoutQueueLengthAndRun, // build project1 643 }, 644 { 645 caption: "Build project 2", 646 change: noop, 647 timeouts: checkSingleTimeoutQueueLengthAndRunAndVerifyNoTimeout // Build project2 648 }, 649 ] 650 }); 651 652 verifyTscWatch({ 653 scenario: "programUpdates", 654 subScenario: "works correctly when project with extended config is removed", 655 commandLineArgs: ["-b", "-w", "-v"], 656 sys: () => { 657 const alphaExtendedConfigFile: File = { 658 path: "/a/b/alpha.tsconfig.json", 659 content: JSON.stringify({ 660 compilerOptions: { 661 strict: true 662 } 663 }) 664 }; 665 const project1Config: File = { 666 path: "/a/b/project1.tsconfig.json", 667 content: JSON.stringify({ 668 extends: "./alpha.tsconfig.json", 669 compilerOptions: { 670 composite: true, 671 }, 672 files: [commonFile1.path, commonFile2.path] 673 }) 674 }; 675 const bravoExtendedConfigFile: File = { 676 path: "/a/b/bravo.tsconfig.json", 677 content: JSON.stringify({ 678 compilerOptions: { 679 strict: true 680 } 681 }) 682 }; 683 const otherFile: File = { 684 path: "/a/b/other.ts", 685 content: "let z = 0;", 686 }; 687 const project2Config: File = { 688 path: "/a/b/project2.tsconfig.json", 689 content: JSON.stringify({ 690 extends: "./bravo.tsconfig.json", 691 compilerOptions: { 692 composite: true, 693 }, 694 files: [otherFile.path] 695 }) 696 }; 697 const configFile: File = { 698 path: "/a/b/tsconfig.json", 699 content: JSON.stringify({ 700 references: [ 701 { 702 path: "./project1.tsconfig.json", 703 }, 704 { 705 path: "./project2.tsconfig.json", 706 }, 707 ], 708 files: [], 709 }) 710 }; 711 return createWatchedSystem([ 712 libFile, configFile, 713 alphaExtendedConfigFile, project1Config, commonFile1, commonFile2, 714 bravoExtendedConfigFile, project2Config, otherFile 715 ], { currentDirectory: "/a/b" }); 716 }, 717 changes: [ 718 { 719 caption: "Remove project2 from base config", 720 change: sys => sys.modifyFile("/a/b/tsconfig.json", JSON.stringify({ 721 references: [ 722 { 723 path: "./project1.tsconfig.json", 724 }, 725 ], 726 files: [], 727 })), 728 timeouts: checkSingleTimeoutQueueLengthAndRunAndVerifyNoTimeout, 729 } 730 ] 731 }); 732 733 verifyTscWatch({ 734 scenario: "programUpdates", 735 subScenario: "tsbuildinfo has error", 736 sys: () => createWatchedSystem({ 737 "/src/project/main.ts": "export const x = 10;", 738 "/src/project/tsconfig.json": "{}", 739 "/src/project/tsconfig.tsbuildinfo": "Some random string", 740 [libFile.path]: libFile.content, 741 }), 742 commandLineArgs: ["--b", "src/project", "-i", "-w"], 743 changes: emptyArray 744 }); 745 }); 746}