1namespace ts.tscWatch { 2 describe("unittests:: tsbuild:: watchEnvironment:: tsbuild:: watchMode:: with different watch environments", () => { 3 describe("when watchFile can create multiple watchers per file", () => { 4 verifyWatchFileOnMultipleProjects(/*singleWatchPerFile*/ false); 5 }); 6 7 describe("when watchFile is single watcher per file", () => { 8 verifyWatchFileOnMultipleProjects( 9 /*singleWatchPerFile*/ true, 10 arrayToMap(["TSC_WATCHFILE"], identity, () => TestFSWithWatch.Tsc_WatchFile.SingleFileWatcherPerName) 11 ); 12 }); 13 14 function verifyWatchFileOnMultipleProjects(singleWatchPerFile: boolean, environmentVariables?: ESMap<string, string>) { 15 it("watchFile on same file multiple times because file is part of multiple projects", () => { 16 const project = `${TestFSWithWatch.tsbuildProjectsLocation}/myproject`; 17 let maxPkgs = 4; 18 const configPath = `${project}/tsconfig.json`; 19 const typing: File = { 20 path: `${project}/typings/xterm.d.ts`, 21 content: "export const typing = 10;" 22 }; 23 24 const allPkgFiles = pkgs(pkgFiles); 25 const system = createWatchedSystem([libFile, typing, ...flatArray(allPkgFiles)], { currentDirectory: project, environmentVariables }); 26 writePkgReferences(); 27 const host = createSolutionBuilderWithWatchHost(system); 28 const solutionBuilder = createSolutionBuilderWithWatch(host, ["tsconfig.json"], { watch: true, verbose: true }); 29 solutionBuilder.build(); 30 checkOutputErrorsInitial(system, emptyArray, /*disableConsoleClears*/ undefined, [ 31 `Projects in this build: \r\n${ 32 concatenate( 33 pkgs(index => ` * pkg${index}/tsconfig.json`), 34 [" * tsconfig.json"] 35 ).join("\r\n")}\n\n`, 36 ...flatArray(pkgs(index => [ 37 `Project 'pkg${index}/tsconfig.json' is out of date because output file 'pkg${index}/index.js' does not exist\n\n`, 38 `Building project '${project}/pkg${index}/tsconfig.json'...\n\n` 39 ])) 40 ]); 41 42 const watchFilesDetailed = arrayToMap(flatArray(allPkgFiles), f => f.path, () => 1); 43 watchFilesDetailed.set(configPath, 1); 44 watchFilesDetailed.set(typing.path, singleWatchPerFile ? 1 : maxPkgs); 45 checkWatchedFilesDetailed(system, watchFilesDetailed); 46 system.writeFile(typing.path, `${typing.content}export const typing1 = 10;`); 47 verifyInvoke(); 48 49 // Make change 50 maxPkgs--; 51 writePkgReferences(); 52 system.checkTimeoutQueueLengthAndRun(1); 53 checkOutputErrorsIncremental(system, emptyArray); 54 const lastFiles = last(allPkgFiles); 55 lastFiles.forEach(f => watchFilesDetailed.delete(f.path)); 56 watchFilesDetailed.set(typing.path, singleWatchPerFile ? 1 : maxPkgs); 57 checkWatchedFilesDetailed(system, watchFilesDetailed); 58 system.writeFile(typing.path, typing.content); 59 verifyInvoke(); 60 61 // Make change to remove all the watches 62 maxPkgs = 0; 63 writePkgReferences(); 64 system.checkTimeoutQueueLengthAndRun(1); 65 checkOutputErrorsIncremental(system, [ 66 `tsconfig.json(1,10): error TS18002: The 'files' list in config file '${configPath}' is empty.\n` 67 ]); 68 checkWatchedFilesDetailed(system, [configPath], 1); 69 70 system.writeFile(typing.path, `${typing.content}export const typing1 = 10;`); 71 system.checkTimeoutQueueLength(0); 72 73 function flatArray<T>(arr: T[][]): readonly T[] { 74 return flatMap(arr, identity); 75 } 76 function pkgs<T>(cb: (index: number) => T): T[] { 77 const result: T[] = []; 78 for (let index = 0; index < maxPkgs; index++) { 79 result.push(cb(index)); 80 } 81 return result; 82 } 83 function createPkgReference(index: number) { 84 return { path: `./pkg${index}` }; 85 } 86 function pkgFiles(index: number): File[] { 87 return [ 88 { 89 path: `${project}/pkg${index}/index.ts`, 90 content: `export const pkg${index} = ${index};` 91 }, 92 { 93 path: `${project}/pkg${index}/tsconfig.json`, 94 content: JSON.stringify({ 95 complerOptions: { composite: true }, 96 include: [ 97 "**/*.ts", 98 "../typings/xterm.d.ts" 99 ] 100 }) 101 } 102 ]; 103 } 104 function writePkgReferences() { 105 system.writeFile(configPath, JSON.stringify({ 106 files: [], 107 include: [], 108 references: pkgs(createPkgReference) 109 })); 110 } 111 function verifyInvoke() { 112 pkgs(() => system.checkTimeoutQueueLengthAndRun(1)); 113 checkOutputErrorsIncremental(system, emptyArray, /*disableConsoleClears*/ undefined, /*logsBeforeWatchDiagnostics*/ undefined, [ 114 ...flatArray(pkgs(index => [ 115 `Project 'pkg${index}/tsconfig.json' is out of date because oldest output 'pkg${index}/index.js' is older than newest input 'typings/xterm.d.ts'\n\n`, 116 `Building project '${project}/pkg${index}/tsconfig.json'...\n\n`, 117 `Updating unchanged output timestamps of project '${project}/pkg${index}/tsconfig.json'...\n\n` 118 ])) 119 ]); 120 } 121 }); 122 } 123 }); 124} 125