• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1namespace ts.tscWatch {
2    describe("unittests:: tsc-watch:: program updates", () => {
3        const scenario = "programUpdates";
4        const configFilePath = "/a/b/tsconfig.json";
5        const configFile: File = {
6            path: configFilePath,
7            content: `{}`
8        };
9        verifyTscWatch({
10            scenario,
11            subScenario: "create watch without config file",
12            commandLineArgs: ["-w", "/a/b/c/app.ts"],
13            sys: () => {
14                const appFile: File = {
15                    path: "/a/b/c/app.ts",
16                    content: `
17                import {f} from "./module"
18                console.log(f)
19                `
20                };
21
22                const moduleFile: File = {
23                    path: "/a/b/c/module.d.ts",
24                    content: `export let x: number`
25                };
26                return createWatchedSystem([appFile, moduleFile, libFile]);
27            },
28            changes: emptyArray
29        });
30
31        verifyTscWatch({
32            scenario,
33            subScenario: "can handle tsconfig file name with difference casing",
34            commandLineArgs: ["-w", "-p", "/A/B/tsconfig.json"],
35            sys: () => {
36                const f1 = {
37                    path: "/a/b/app.ts",
38                    content: "let x = 1"
39                };
40                const config = {
41                    path: configFilePath,
42                    content: JSON.stringify({
43                        include: ["app.ts"]
44                    })
45                };
46                return createWatchedSystem([f1, libFile, config], { useCaseSensitiveFileNames: false });
47            },
48            changes: emptyArray
49        });
50
51        verifyTscWatch({
52            scenario,
53            subScenario: "create configured project without file list",
54            commandLineArgs: ["-w", "-p", configFilePath],
55            sys: () => {
56                const configFile: File = {
57                    path: configFilePath,
58                    content: `
59                {
60                    "compilerOptions": {},
61                    "exclude": [
62                        "e"
63                    ]
64                }`
65                };
66                const file1: File = {
67                    path: "/a/b/c/f1.ts",
68                    content: "let x = 1"
69                };
70                const file2: File = {
71                    path: "/a/b/d/f2.ts",
72                    content: "let y = 1"
73                };
74                const file3: File = {
75                    path: "/a/b/e/f3.ts",
76                    content: "let z = 1"
77                };
78                return createWatchedSystem([configFile, libFile, file1, file2, file3]);
79            },
80            changes: emptyArray
81        });
82
83        verifyTscWatch({
84            scenario,
85            subScenario: "add new files to a configured program without file list",
86            commandLineArgs: ["-w", "-p", configFilePath],
87            sys: () => createWatchedSystem([commonFile1, libFile, configFile]),
88            changes: [
89                {
90                    caption: "Create commonFile2",
91                    change: sys => sys.writeFile(commonFile2.path, commonFile2.content),
92                    timeouts: checkSingleTimeoutQueueLengthAndRun,
93                }
94            ]
95        });
96
97        verifyTscWatch({
98            scenario,
99            subScenario: "should ignore non-existing files specified in the config file",
100            commandLineArgs: ["-w", "-p", configFilePath],
101            sys: () => {
102                const configFile: File = {
103                    path: configFilePath,
104                    content: `{
105                    "compilerOptions": {},
106                    "files": [
107                        "commonFile1.ts",
108                        "commonFile3.ts"
109                    ]
110                }`
111                };
112                return createWatchedSystem([commonFile1, commonFile2, libFile, configFile]);
113            },
114            changes: emptyArray
115        });
116
117        verifyTscWatch({
118            scenario,
119            subScenario: "handle recreated files correctly",
120            commandLineArgs: ["-w", "-p", configFilePath, "--explainFiles"],
121            sys: () => {
122                return createWatchedSystem([libFile, commonFile1, commonFile2, configFile]);
123            },
124            changes: [
125                {
126                    caption: "delete file2",
127                    change: sys => sys.deleteFile(commonFile2.path),
128                    timeouts: checkSingleTimeoutQueueLengthAndRun,
129                },
130                {
131                    caption: "recreate file2",
132                    change: sys => sys.writeFile(commonFile2.path, commonFile2.content),
133                    timeouts: checkSingleTimeoutQueueLengthAndRun,
134                }
135            ]
136        });
137
138        verifyTscWatch({
139            scenario,
140            subScenario: "handles the missing files - that were added to program because they were added with tripleSlashRefs",
141            commandLineArgs: ["-w", "/a/b/commonFile1.ts"],
142            sys: () => {
143                const file1: File = {
144                    path: commonFile1.path,
145                    content: `/// <reference path="commonFile2.ts"/>
146                    let x = y`
147                };
148                return createWatchedSystem([file1, libFile]);
149            },
150            changes: [
151                {
152                    caption: "create file2",
153                    change: sys => sys.writeFile(commonFile2.path, commonFile2.content),
154                    timeouts: checkSingleTimeoutQueueLengthAndRun,
155                }
156            ]
157        });
158
159        verifyTscWatch({
160            scenario,
161            subScenario: "should reflect change in config file",
162            commandLineArgs: ["-w", "-p", configFilePath, "--explainFiles"],
163            sys: () => {
164                const configFile: File = {
165                    path: configFilePath,
166                    content: `{
167                    "compilerOptions": {},
168                    "files": ["${commonFile1.path}", "${commonFile2.path}"]
169                }`
170                };
171                return createWatchedSystem([libFile, commonFile1, commonFile2, configFile]);
172            },
173            changes: [
174                {
175                    caption: "Change config",
176                    change: sys => sys.writeFile(configFilePath, `{
177                        "compilerOptions": {},
178                        "files": ["${commonFile1.path}"]
179                    }`),
180                    timeouts: checkSingleTimeoutQueueLengthAndRun,
181                }
182            ]
183        });
184
185        verifyTscWatch({
186            scenario,
187            subScenario: "works correctly when config file is changed but its content havent",
188            commandLineArgs: ["-w", "-p", configFilePath],
189            sys: () => {
190                const configFile: File = {
191                    path: configFilePath,
192                    content: `{
193                        "compilerOptions": {},
194                        "files": ["${commonFile1.path}", "${commonFile2.path}"]
195                    }`
196                };
197                return createWatchedSystem([libFile, commonFile1, commonFile2, configFile]);
198            },
199            changes: [
200                {
201                    caption: "Modify config without changing content",
202                    change: sys => sys.modifyFile(configFilePath, `{
203                        "compilerOptions": {},
204                        "files": ["${commonFile1.path}", "${commonFile2.path}"]
205                    }`),
206                    timeouts: checkSingleTimeoutQueueLengthAndRun,
207                }
208            ]
209        });
210
211        verifyTscWatch({
212            scenario,
213            subScenario: "Updates diagnostics when '--noUnusedLabels' changes",
214            commandLineArgs: ["-w", "-p", "/tsconfig.json"],
215            sys: () => {
216                const aTs: File = {
217                    path: "/a.ts",
218                    content: "label: while (1) {}"
219                };
220                const tsconfig: File = {
221                    path: "/tsconfig.json",
222                    content: JSON.stringify({
223                        compilerOptions: { allowUnusedLabels: true }
224                    })
225                };
226                return createWatchedSystem([libFile, aTs, tsconfig]);
227            },
228            changes: [
229                {
230                    caption: "Disable  allowUnsusedLabels",
231                    change: sys => sys.modifyFile("/tsconfig.json", JSON.stringify({
232                        compilerOptions: { allowUnusedLabels: false }
233                    })),
234                    timeouts: checkSingleTimeoutQueueLengthAndRun
235                },
236                {
237                    caption: "Enable  allowUnsusedLabels",
238                    change: sys => sys.modifyFile("/tsconfig.json", JSON.stringify({
239                        compilerOptions: { allowUnusedLabels: true }
240                    })),
241                    timeouts: checkSingleTimeoutQueueLengthAndRun,
242                }
243            ]
244        });
245
246        verifyTscWatch({
247            scenario,
248            subScenario: "updates diagnostics and emit for decorators",
249            commandLineArgs: ["-w"],
250            sys: () => {
251                const aTs: File = {
252                    path: "/a.ts",
253                    content: `import {B} from './b'
254@((_) => {})
255export class A {
256    constructor(p: B) {}
257}`,
258                };
259                const bTs: File = {
260                    path: "/b.ts",
261                    content: `export class B {}`,
262                };
263                const tsconfig: File = {
264                    path: "/tsconfig.json",
265                    content: JSON.stringify({
266                        compilerOptions: { target: "es6", importsNotUsedAsValues: "error" }
267                    })
268                };
269                return createWatchedSystem([libFile, aTs, bTs, tsconfig]);
270            },
271            changes: [
272                {
273                    caption: "Enable experimentalDecorators",
274                    change: sys => sys.modifyFile("/tsconfig.json", JSON.stringify({
275                        compilerOptions: { target: "es6", importsNotUsedAsValues: "error", experimentalDecorators: true }
276                    })),
277                    timeouts: checkSingleTimeoutQueueLengthAndRun,
278
279                },
280                {
281                    caption: "Enable emitDecoratorMetadata",
282                    change: sys => sys.modifyFile("/tsconfig.json", JSON.stringify({
283                        compilerOptions: { target: "es6", importsNotUsedAsValues: "error", experimentalDecorators: true, emitDecoratorMetadata: true }
284                    })),
285                    timeouts: checkSingleTimeoutQueueLengthAndRun,
286                }
287            ]
288        });
289
290        verifyTscWatch({
291            scenario,
292            subScenario: "files explicitly excluded in config file",
293            commandLineArgs: ["-w", "-p", configFilePath],
294            sys: () => {
295                const configFile: File = {
296                    path: configFilePath,
297                    content: `{
298                    "compilerOptions": {},
299                    "exclude": ["/a/c"]
300                }`
301                };
302                const excludedFile1: File = {
303                    path: "/a/c/excluedFile1.ts",
304                    content: `let t = 1;`
305                };
306                return createWatchedSystem([libFile, commonFile1, commonFile2, excludedFile1, configFile]);
307            },
308            changes: emptyArray
309        });
310
311        verifyTscWatch({
312            scenario,
313            subScenario: "should properly handle module resolution changes in config file",
314            commandLineArgs: ["-w", "-p", configFilePath],
315            sys: () => {
316                const file1: File = {
317                    path: "/a/b/file1.ts",
318                    content: `import { T } from "module1";`
319                };
320                const nodeModuleFile: File = {
321                    path: "/a/b/node_modules/module1.ts",
322                    content: `export interface T {}`
323                };
324                const classicModuleFile: File = {
325                    path: "/a/module1.ts",
326                    content: `export interface T {}`
327                };
328                const configFile: File = {
329                    path: configFilePath,
330                    content: `{
331                    "compilerOptions": {
332                        "moduleResolution": "node"
333                    },
334                    "files": ["${file1.path}"]
335                }`
336                };
337                return createWatchedSystem([libFile, file1, nodeModuleFile, classicModuleFile, configFile]);
338            },
339            changes: [
340                {
341                    caption: "Change module resolution to classic",
342                    change: sys => sys.writeFile(configFile.path, `{
343                        "compilerOptions": {
344                            "moduleResolution": "classic"
345                        },
346                        "files": ["/a/b/file1.ts"]
347                    }`),
348                    timeouts: checkSingleTimeoutQueueLengthAndRun,
349                }
350            ]
351        });
352
353        verifyTscWatch({
354            scenario,
355            subScenario: "should tolerate config file errors and still try to build a project",
356            commandLineArgs: ["-w", "-p", configFilePath],
357            sys: () => {
358                const configFile: File = {
359                    path: configFilePath,
360                    content: `{
361                        "compilerOptions": {
362                            "module": "none",
363                            "allowAnything": true
364                        },
365                        "someOtherProperty": {}
366                    }`
367                };
368                return createWatchedSystem([commonFile1, commonFile2, libFile, configFile]);
369            },
370            changes: emptyArray
371        });
372
373        verifyTscWatch({
374            scenario,
375            subScenario: "changes in files are reflected in project structure",
376            commandLineArgs: ["-w", "/a/b/f1.ts", "--explainFiles"],
377            sys: () => {
378                const file1 = {
379                    path: "/a/b/f1.ts",
380                    content: `export * from "./f2"`
381                };
382                const file2 = {
383                    path: "/a/b/f2.ts",
384                    content: `export let x = 1`
385                };
386                const file3 = {
387                    path: "/a/c/f3.ts",
388                    content: `export let y = 1;`
389                };
390                return createWatchedSystem([file1, file2, file3, libFile]);
391            },
392            changes: [
393                {
394                    caption: "Modify f2 to include f3",
395                    // now inferred project should inclule file3
396                    change: sys => sys.modifyFile("/a/b/f2.ts", `export * from "../c/f3"`),
397                    timeouts: checkSingleTimeoutQueueLengthAndRun,
398                }
399            ]
400        });
401
402        verifyTscWatch({
403            scenario,
404            subScenario: "deleted files affect project structure",
405            commandLineArgs: ["-w", "/a/b/f1.ts", "--noImplicitAny"],
406            sys: () => {
407                const file1 = {
408                    path: "/a/b/f1.ts",
409                    content: `export * from "./f2"`
410                };
411                const file2 = {
412                    path: "/a/b/f2.ts",
413                    content: `export * from "../c/f3"`
414                };
415                const file3 = {
416                    path: "/a/c/f3.ts",
417                    content: `export let y = 1;`
418                };
419                return createWatchedSystem([file1, file2, file3, libFile]);
420            },
421            changes: [
422                {
423                    caption: "Delete f2",
424                    change: sys => sys.deleteFile("/a/b/f2.ts"),
425                    timeouts: checkSingleTimeoutQueueLengthAndRun,
426                }
427            ]
428        });
429
430        verifyTscWatch({
431            scenario,
432            subScenario: "deleted files affect project structure-2",
433            commandLineArgs: ["-w", "/a/b/f1.ts", "/a/c/f3.ts", "--noImplicitAny"],
434            sys: () => {
435                const file1 = {
436                    path: "/a/b/f1.ts",
437                    content: `export * from "./f2"`
438                };
439                const file2 = {
440                    path: "/a/b/f2.ts",
441                    content: `export * from "../c/f3"`
442                };
443                const file3 = {
444                    path: "/a/c/f3.ts",
445                    content: `export let y = 1;`
446                };
447                return createWatchedSystem([file1, file2, file3, libFile]);
448            },
449            changes: [
450                {
451                    caption: "Delete f2",
452                    change: sys => sys.deleteFile("/a/b/f2.ts"),
453                    timeouts: checkSingleTimeoutQueueLengthAndRun,
454                }
455            ]
456        });
457
458        verifyTscWatch({
459            scenario,
460            subScenario: "config file includes the file",
461            commandLineArgs: ["-w", "-p", "/a/c/tsconfig.json"],
462            sys: () => {
463                const file1 = {
464                    path: "/a/b/f1.ts",
465                    content: "export let x = 5"
466                };
467                const file2 = {
468                    path: "/a/c/f2.ts",
469                    content: `import {x} from "../b/f1"`
470                };
471                const file3 = {
472                    path: "/a/c/f3.ts",
473                    content: "export let y = 1"
474                };
475                const configFile = {
476                    path: "/a/c/tsconfig.json",
477                    content: JSON.stringify({ compilerOptions: {}, files: ["f2.ts", "f3.ts"] })
478                };
479                return createWatchedSystem([file1, file2, file3, libFile, configFile]);
480            },
481            changes: emptyArray
482        });
483
484        verifyTscWatch({
485            scenario,
486            subScenario: "change module to none",
487            commandLineArgs: ["-w", "-p", configFilePath],
488            sys: () => {
489                const file1 = {
490                    path: "/a/b/f1.ts",
491                    content: "export {}\ndeclare global {}"
492                };
493                return createWatchedSystem([file1, libFile, configFile]);
494            },
495            changes: [{
496                caption: "change `module` to 'none'",
497                timeouts: checkSingleTimeoutQueueLengthAndRun,
498                change: sys => {
499                    sys.writeFile(configFilePath, JSON.stringify({ compilerOptions: { module: "none" } }));
500                }
501            }]
502        });
503
504        it("correctly migrate files between projects", () => {
505            const file1 = {
506                path: "/a/b/f1.ts",
507                content: `
508                export * from "../c/f2";
509                export * from "../d/f3";`
510            };
511            const file2 = {
512                path: "/a/c/f2.ts",
513                content: "export let x = 1;"
514            };
515            const file3 = {
516                path: "/a/d/f3.ts",
517                content: "export let y = 1;"
518            };
519            const host = createWatchedSystem([file1, file2, file3]);
520            const watch = createWatchOfFilesAndCompilerOptions([file2.path, file3.path], host);
521            checkProgramActualFiles(watch.getCurrentProgram().getProgram(), [file2.path, file3.path]);
522
523            const watch2 = createWatchOfFilesAndCompilerOptions([file1.path], host);
524            checkProgramActualFiles(watch2.getCurrentProgram().getProgram(), [file1.path, file2.path, file3.path]);
525
526            // Previous program shouldnt be updated
527            checkProgramActualFiles(watch.getCurrentProgram().getProgram(), [file2.path, file3.path]);
528            host.checkTimeoutQueueLength(0);
529        });
530
531        verifyTscWatch({
532            scenario,
533            subScenario: "can correctly update configured project when set of root files has changed (new file on disk)",
534            commandLineArgs: ["-w", "-p", configFilePath],
535            sys: () => {
536                const file1 = {
537                    path: "/a/b/f1.ts",
538                    content: "let x = 1"
539                };
540                return createWatchedSystem([file1, libFile, configFile]);
541            },
542            changes: [
543                {
544                    caption: "Write f2",
545                    change: sys => sys.writeFile("/a/b/f2.ts", "let y = 1"),
546                    timeouts: checkSingleTimeoutQueueLengthAndRun,
547                }
548            ]
549        });
550
551        verifyTscWatch({
552            scenario,
553            subScenario: "can correctly update configured project when set of root files has changed (new file in list of files)",
554            commandLineArgs: ["-w", "-p", configFilePath],
555            sys: () => {
556                const file1 = {
557                    path: "/a/b/f1.ts",
558                    content: "let x = 1"
559                };
560                const file2 = {
561                    path: "/a/b/f2.ts",
562                    content: "let y = 1"
563                };
564                const configFile = {
565                    path: configFilePath,
566                    content: JSON.stringify({ compilerOptions: {}, files: ["f1.ts"] })
567                };
568                return createWatchedSystem([file1, file2, libFile, configFile]);
569            },
570            changes: [
571                {
572                    caption: "Modify config to make f2 as root too",
573                    change: sys => sys.writeFile(configFilePath, JSON.stringify({ compilerOptions: {}, files: ["f1.ts", "f2.ts"] })),
574                    timeouts: checkSingleTimeoutQueueLengthAndRun,
575                }
576            ]
577        });
578
579        verifyTscWatch({
580            scenario,
581            subScenario: "can correctly update configured project when set of root files has changed through include",
582            commandLineArgs: ["-w", "-p", "."],
583            sys: () => {
584                const file1 = {
585                    path: `${projectRoot}/Project/file1.ts`,
586                    content: "export const x = 10;"
587                };
588                const configFile = {
589                    path: `${projectRoot}/Project/tsconfig.json`,
590                    content: JSON.stringify({ include: [".", "./**/*.json"] })
591                };
592                return createWatchedSystem([file1, libFile, configFile], { currentDirectory: `${projectRoot}/Project` });
593            },
594            changes: [
595                {
596                    caption: "Write file2",
597                    change: sys => sys.writeFile(`${projectRoot}/Project/file2.ts`, "export const y = 10;"),
598                    timeouts: checkSingleTimeoutQueueLengthAndRun
599                }
600            ]
601        });
602
603        verifyTscWatch({
604            scenario,
605            subScenario: "can update configured project when set of root files was not changed",
606            commandLineArgs: ["-w", "-p", configFilePath],
607            sys: () => {
608                const file1 = {
609                    path: "/a/b/f1.ts",
610                    content: "let x = 1"
611                };
612                const file2 = {
613                    path: "/a/b/f2.ts",
614                    content: "let y = 1"
615                };
616                const configFile = {
617                    path: configFilePath,
618                    content: JSON.stringify({ compilerOptions: {}, files: ["f1.ts", "f2.ts"] })
619                };
620                return createWatchedSystem([file1, file2, libFile, configFile]);
621            },
622            changes: [
623                {
624                    caption: "Modify config to set outFile option",
625                    change: sys => sys.writeFile(configFilePath, JSON.stringify({ compilerOptions: { outFile: "out.js" }, files: ["f1.ts", "f2.ts"] })),
626                    timeouts: checkSingleTimeoutQueueLengthAndRun,
627                }
628            ]
629        });
630
631        verifyTscWatch({
632            scenario,
633            subScenario: "config file is deleted",
634            commandLineArgs: ["-w", "-p", configFilePath],
635            sys: () => {
636                const file1 = {
637                    path: "/a/b/f1.ts",
638                    content: "let x = 1;"
639                };
640                const file2 = {
641                    path: "/a/b/f2.ts",
642                    content: "let y = 2;"
643                };
644                return createWatchedSystem([file1, file2, libFile, configFile]);
645            },
646            changes: [
647                {
648                    caption: "Delete config file",
649                    change: sys => sys.deleteFile(configFilePath),
650                    timeouts: checkSingleTimeoutQueueLengthAndRun,
651                }
652            ]
653        });
654
655        verifyTscWatch({
656            scenario,
657            subScenario: "Proper errors document is not contained in project",
658            commandLineArgs: ["-w", "-p", configFilePath],
659            sys: () => {
660                const file1 = {
661                    path: "/a/b/app.ts",
662                    content: ""
663                };
664                const corruptedConfig = {
665                    path: configFilePath,
666                    content: "{"
667                };
668                return createWatchedSystem([file1, libFile, corruptedConfig]);
669            },
670            changes: emptyArray
671        });
672
673        verifyTscWatch({
674            scenario,
675            subScenario: "correctly handles changes in lib section of config file",
676            commandLineArgs: ["-w", "-p", "/src/tsconfig.json"],
677            sys: () => {
678                const libES5 = {
679                    path: "/compiler/lib.es5.d.ts",
680                    content: `${libFile.content}
681declare const eval: any`
682                };
683                const libES2015Promise = {
684                    path: "/compiler/lib.es2015.promise.d.ts",
685                    content: `declare class Promise<T> {}`
686                };
687                const app = {
688                    path: "/src/app.ts",
689                    content: "var x: Promise<string>;"
690                };
691                const config1 = {
692                    path: "/src/tsconfig.json",
693                    content: JSON.stringify(
694                        {
695                            compilerOptions: {
696                                module: "commonjs",
697                                target: "es5",
698                                noImplicitAny: true,
699                                sourceMap: false,
700                                lib: [
701                                    "es5"
702                                ]
703                            }
704                        })
705                };
706                return createWatchedSystem([libES5, libES2015Promise, app, config1], { executingFilePath: "/compiler/tsc.js" });
707            },
708            changes: [
709                {
710                    caption: "Change the lib in config",
711                    change: sys => sys.writeFile("/src/tsconfig.json", JSON.stringify(
712                        {
713                            compilerOptions: {
714                                module: "commonjs",
715                                target: "es5",
716                                noImplicitAny: true,
717                                sourceMap: false,
718                                lib: [
719                                    "es5",
720                                    "es2015.promise"
721                                ]
722                            }
723                        })
724                    ),
725                    timeouts: checkSingleTimeoutQueueLengthAndRun,
726                }
727            ]
728        });
729
730        verifyTscWatch({
731            scenario,
732            subScenario: "should handle non-existing directories in config file",
733            commandLineArgs: ["-w", "-p", "/a/tsconfig.json"],
734            sys: () => {
735                const f = {
736                    path: "/a/src/app.ts",
737                    content: "let x = 1;"
738                };
739                const config = {
740                    path: "/a/tsconfig.json",
741                    content: JSON.stringify({
742                        compilerOptions: {},
743                        include: [
744                            "src/**/*",
745                            "notexistingfolder/*"
746                        ]
747                    })
748                };
749                return createWatchedSystem([f, config, libFile]);
750            },
751            changes: emptyArray
752        });
753
754        function runQueuedTimeoutCallbacksTwice(sys: WatchedSystem) {
755            sys.runQueuedTimeoutCallbacks(); // Scheduled invalidation of resolutions
756            sys.runQueuedTimeoutCallbacks(); // Actual update
757        }
758
759        const changeModuleFileToModuleFile1: TscWatchCompileChange = {
760            caption: "Rename moduleFile to moduleFile1",
761            change: sys => {
762                sys.renameFile("/a/b/moduleFile.ts", "/a/b/moduleFile1.ts");
763                sys.deleteFile("/a/b/moduleFile.js");
764            },
765            timeouts: runQueuedTimeoutCallbacksTwice
766        };
767        const changeModuleFile1ToModuleFile: TscWatchCompileChange = {
768            caption: "Rename moduleFile1 back to moduleFile",
769            change: sys => sys.renameFile("/a/b/moduleFile1.ts", "/a/b/moduleFile.ts"),
770            timeouts: runQueuedTimeoutCallbacksTwice,
771        };
772
773        verifyTscWatch({
774            scenario,
775            subScenario: "rename a module file and rename back should restore the states for inferred projects",
776            commandLineArgs: ["-w", "/a/b/file1.ts"],
777            sys: () => {
778                const moduleFile = {
779                    path: "/a/b/moduleFile.ts",
780                    content: "export function bar() { };"
781                };
782                const file1 = {
783                    path: "/a/b/file1.ts",
784                    content: 'import * as T from "./moduleFile"; T.bar();'
785                };
786                return createWatchedSystem([moduleFile, file1, libFile]);
787            },
788            changes: [
789                changeModuleFileToModuleFile1,
790                changeModuleFile1ToModuleFile
791            ]
792        });
793
794        verifyTscWatch({
795            scenario,
796            subScenario: "rename a module file and rename back should restore the states for configured projects",
797            commandLineArgs: ["-w", "-p", configFilePath],
798            sys: () => {
799                const moduleFile = {
800                    path: "/a/b/moduleFile.ts",
801                    content: "export function bar() { };"
802                };
803                const file1 = {
804                    path: "/a/b/file1.ts",
805                    content: 'import * as T from "./moduleFile"; T.bar();'
806                };
807                return createWatchedSystem([moduleFile, file1, configFile, libFile]);
808            },
809            changes: [
810                changeModuleFileToModuleFile1,
811                changeModuleFile1ToModuleFile
812            ]
813        });
814
815        verifyTscWatch({
816            scenario,
817            subScenario: "types should load from config file path if config exists",
818            commandLineArgs: ["-w", "-p", configFilePath],
819            sys: () => {
820                const f1 = {
821                    path: "/a/b/app.ts",
822                    content: "let x = 1"
823                };
824                const config = {
825                    path: configFilePath,
826                    content: JSON.stringify({ compilerOptions: { types: ["node"], typeRoots: [] } })
827                };
828                const node = {
829                    path: "/a/b/node_modules/@types/node/index.d.ts",
830                    content: "declare var process: any"
831                };
832                const cwd = {
833                    path: "/a/c"
834                };
835                return createWatchedSystem([f1, config, node, cwd, libFile], { currentDirectory: cwd.path });
836            },
837            changes: emptyArray
838        });
839
840        verifyTscWatch({
841            scenario,
842            subScenario: "add the missing module file for inferred project-should remove the module not found error",
843            commandLineArgs: ["-w", "/a/b/file1.ts"],
844            sys: () => {
845                const file1 = {
846                    path: "/a/b/file1.ts",
847                    content: 'import * as T from "./moduleFile"; T.bar();'
848                };
849                return createWatchedSystem([file1, libFile]);
850            },
851            changes: [
852                {
853                    caption: "Create module file",
854                    change: sys => sys.writeFile("/a/b/moduleFile.ts", "export function bar() { }"),
855                    timeouts: runQueuedTimeoutCallbacksTwice,
856                }
857            ]
858        });
859
860        verifyTscWatch({
861            scenario,
862            subScenario: "Configure file diagnostics events are generated when the config file has errors",
863            commandLineArgs: ["-w", "-p", configFilePath],
864            sys: () => {
865                const file = {
866                    path: "/a/b/app.ts",
867                    content: "let x = 10"
868                };
869                const configFile = {
870                    path: configFilePath,
871                    content: `{
872                        "compilerOptions": {
873                            "foo": "bar",
874                            "allowJS": true
875                        }
876                    }`
877                };
878                return createWatchedSystem([file, configFile, libFile]);
879            },
880            changes: emptyArray
881        });
882
883        verifyTscWatch({
884            scenario,
885            subScenario: "if config file doesnt have errors, they are not reported",
886            commandLineArgs: ["-w", "-p", configFilePath],
887            sys: () => {
888                const file = {
889                    path: "/a/b/app.ts",
890                    content: "let x = 10"
891                };
892                const configFile = {
893                    path: configFilePath,
894                    content: `{
895                        "compilerOptions": {}
896                    }`
897                };
898                return createWatchedSystem([file, configFile, libFile]);
899            },
900            changes: emptyArray
901        });
902
903        verifyTscWatch({
904            scenario,
905            subScenario: "Reports errors when the config file changes",
906            commandLineArgs: ["-w", "-p", configFilePath],
907            sys: () => {
908                const file = {
909                    path: "/a/b/app.ts",
910                    content: "let x = 10"
911                };
912                return createWatchedSystem([file, configFile, libFile]);
913            },
914            changes: [
915                {
916                    caption: "change config file to add error",
917                    change: sys => sys.writeFile(configFilePath, `{
918                        "compilerOptions": {
919                            "haha": 123
920                        }
921                    }`),
922                    timeouts: runQueuedTimeoutCallbacks,
923                },
924                {
925                    caption: "change config file to remove error",
926                    change: sys => sys.writeFile(configFilePath, `{
927                        "compilerOptions": {
928                        }
929                    }`),
930                    timeouts: runQueuedTimeoutCallbacks,
931                }
932            ]
933        });
934
935        verifyTscWatch({
936            scenario,
937            subScenario: "non-existing directories listed in config file input array should be tolerated without crashing the server",
938            commandLineArgs: ["-w", "-p", configFilePath],
939            sys: () => {
940                const configFile = {
941                    path: configFilePath,
942                    content: `{
943                        "compilerOptions": {},
944                        "include": ["app/*", "test/**/*", "something"]
945                    }`
946                };
947                const file1 = {
948                    path: "/a/b/file1.ts",
949                    content: "let t = 10;"
950                };
951                return createWatchedSystem([file1, configFile, libFile]);
952            },
953            changes: emptyArray
954        });
955
956        verifyTscWatch({
957            scenario,
958            subScenario: "non-existing directories listed in config file input array should be able to handle @types if input file list is empty",
959            commandLineArgs: ["-w", "-p", "/a/tsconfig.json"],
960            sys: () => {
961                const f = {
962                    path: "/a/app.ts",
963                    content: "let x = 1"
964                };
965                const config = {
966                    path: "/a/tsconfig.json",
967                    content: JSON.stringify({
968                        compiler: {},
969                        files: []
970                    })
971                };
972                const t1 = {
973                    path: "/a/node_modules/@types/typings/index.d.ts",
974                    content: `export * from "./lib"`
975                };
976                const t2 = {
977                    path: "/a/node_modules/@types/typings/lib.d.ts",
978                    content: `export const x: number`
979                };
980                return createWatchedSystem([f, config, t1, t2, libFile], { currentDirectory: getDirectoryPath(f.path) });
981            },
982            changes: emptyArray
983        });
984
985        it("should support files without extensions", () => {
986            const f = {
987                path: "/a/compile",
988                content: "let x = 1"
989            };
990            const host = createWatchedSystem([f, libFile]);
991            const watch = createWatchOfFilesAndCompilerOptions([f.path], host, { allowNonTsExtensions: true });
992            checkProgramActualFiles(watch.getCurrentProgram().getProgram(), [f.path, libFile.path]);
993        });
994
995        verifyTscWatch({
996            scenario,
997            subScenario: "Options Diagnostic locations reported correctly with changes in configFile contents when options change",
998            commandLineArgs: ["-w", "-p", configFilePath],
999            sys: () => {
1000                const file = {
1001                    path: "/a/b/app.ts",
1002                    content: "let x = 10"
1003                };
1004                const configFile = {
1005                    path: configFilePath,
1006                    content: `
1007{
1008    // comment
1009    // More comment
1010    "compilerOptions": {
1011        "inlineSourceMap": true,
1012        "mapRoot": "./"
1013    }
1014}`
1015                };
1016                return createWatchedSystem([file, libFile, configFile]);
1017            },
1018            changes: [
1019                {
1020                    caption: "Remove the comment from config file",
1021                    change: sys => sys.writeFile(configFilePath, `
1022{
1023    "compilerOptions": {
1024        "inlineSourceMap": true,
1025        "mapRoot": "./"
1026    }
1027}`),
1028                    timeouts: runQueuedTimeoutCallbacks,
1029                }
1030            ]
1031        });
1032
1033        describe("should not trigger recompilation because of program emit", () => {
1034            function verifyWithOptions(subScenario: string, options: CompilerOptions) {
1035                verifyTscWatch({
1036                    scenario,
1037                    subScenario: `should not trigger recompilation because of program emit/${subScenario}`,
1038                    commandLineArgs: ["-w", "-p", `${projectRoot}/tsconfig.json`],
1039                    sys: () => {
1040                        const file1: File = {
1041                            path: `${projectRoot}/file1.ts`,
1042                            content: "export const c = 30;"
1043                        };
1044                        const file2: File = {
1045                            path: `${projectRoot}/src/file2.ts`,
1046                            content: `import {c} from "file1"; export const d = 30;`
1047                        };
1048                        const tsconfig: File = {
1049                            path: `${projectRoot}/tsconfig.json`,
1050                            content: generateTSConfig(options, emptyArray, "\n")
1051                        };
1052                        return createWatchedSystem([file1, file2, libFile, tsconfig], { currentDirectory: projectRoot });
1053                    },
1054                    changes: [
1055                        noopChange,
1056                        {
1057                            caption: "Add new file",
1058                            change: sys => sys.writeFile(`${projectRoot}/src/file3.ts`, `export const y = 10;`),
1059                            timeouts: sys => sys.checkTimeoutQueueLengthAndRun(2), // To update program and failed lookups
1060                        },
1061                        noopChange,
1062                    ]
1063                });
1064            }
1065
1066            verifyWithOptions(
1067                "without outDir or outFile is specified",
1068                { module: ModuleKind.AMD }
1069            );
1070
1071            verifyWithOptions(
1072                "with outFile",
1073                { module: ModuleKind.AMD, outFile: "build/outFile.js" }
1074            );
1075
1076            verifyWithOptions(
1077                "when outDir is specified",
1078                { module: ModuleKind.AMD, outDir: "build" }
1079            );
1080
1081            verifyWithOptions(
1082                "without outDir or outFile is specified with declaration enabled",
1083                { module: ModuleKind.AMD, declaration: true }
1084            );
1085
1086            verifyWithOptions(
1087                "when outDir and declarationDir is specified",
1088                { module: ModuleKind.AMD, outDir: "build", declaration: true, declarationDir: "decls" }
1089            );
1090
1091            verifyWithOptions(
1092                "declarationDir is specified",
1093                { module: ModuleKind.AMD, declaration: true, declarationDir: "decls" }
1094            );
1095        });
1096
1097        verifyTscWatch({
1098            scenario,
1099            subScenario: "shouldnt report error about unused function incorrectly when file changes from global to module",
1100            commandLineArgs: ["-w", "/a/b/file.ts", "--noUnusedLocals"],
1101            sys: () => {
1102                const file: File = {
1103                    path: "/a/b/file.ts",
1104                    content: `function one() {}
1105function two() {
1106    return function three() {
1107        one();
1108    }
1109}`
1110                };
1111                return createWatchedSystem([file, libFile]);
1112            },
1113            changes: [
1114                {
1115                    caption: "Change file to module",
1116                    change: sys => sys.writeFile("/a/b/file.ts", `function one() {}
1117export function two() {
1118    return function three() {
1119        one();
1120    }
1121}`),
1122                    timeouts: runQueuedTimeoutCallbacks,
1123
1124                }
1125            ]
1126        });
1127
1128        verifyTscWatch({
1129            scenario,
1130            subScenario: "watched files when file is deleted and new file is added as part of change",
1131            commandLineArgs: ["-w", "-p", "/home/username/project/tsconfig.json"],
1132            sys: () => {
1133                const projectLocation = "/home/username/project";
1134                const file: File = {
1135                    path: `${projectLocation}/src/file1.ts`,
1136                    content: "var a = 10;"
1137                };
1138                const configFile: File = {
1139                    path: `${projectLocation}/tsconfig.json`,
1140                    content: "{}"
1141                };
1142                return createWatchedSystem([file, libFile, configFile]);
1143            },
1144            changes: [
1145                {
1146                    caption: "Rename file1 to file2",
1147                    change: sys => sys.renameFile("/home/username/project/src/file1.ts", "/home/username/project/src/file2.ts"),
1148                    timeouts: runQueuedTimeoutCallbacks,
1149                }
1150            ]
1151        });
1152
1153        function changeParameterTypeOfBFile(parameterName: string, toType: string): TscWatchCompileChange {
1154            return {
1155                caption: `Changed ${parameterName} type to ${toType}`,
1156                change: sys => replaceFileText(sys, `${projectRoot}/b.ts`, new RegExp(`${parameterName}\: [a-z]*`), `${parameterName}: ${toType}`),
1157                timeouts: runQueuedTimeoutCallbacks,
1158            };
1159        }
1160
1161        verifyTscWatch({
1162            scenario,
1163            subScenario: "updates errors correctly when declaration emit is disabled in compiler options",
1164            commandLineArgs: ["-w"],
1165            sys: () => {
1166                const aFile: File = {
1167                    path: `${projectRoot}/a.ts`,
1168                    content: `import test from './b';
1169test(4, 5);`
1170                };
1171                const bFile: File = {
1172                    path: `${projectRoot}/b.ts`,
1173                    content: `function test(x: number, y: number) {
1174    return x + y / 5;
1175}
1176export default test;`
1177                };
1178                const tsconfigFile: File = {
1179                    path: `${projectRoot}/tsconfig.json`,
1180                    content: JSON.stringify({
1181                        compilerOptions: {
1182                            module: "commonjs",
1183                            noEmit: true,
1184                            strict: true,
1185                        }
1186                    })
1187                };
1188                return createWatchedSystem([aFile, bFile, libFile, tsconfigFile], { currentDirectory: projectRoot });
1189            },
1190            changes: [
1191                changeParameterTypeOfBFile("x", "string"),
1192                changeParameterTypeOfBFile("x", "number"),
1193                changeParameterTypeOfBFile("y", "string"),
1194                changeParameterTypeOfBFile("y", "number"),
1195            ]
1196        });
1197
1198        verifyTscWatch({
1199            scenario,
1200            subScenario: "updates errors when strictNullChecks changes",
1201            commandLineArgs: ["-w"],
1202            sys: () => {
1203                const aFile: File = {
1204                    path: `${projectRoot}/a.ts`,
1205                    content: `declare function foo(): null | { hello: any };
1206foo().hello`
1207                };
1208                const config: File = {
1209                    path: `${projectRoot}/tsconfig.json`,
1210                    content: JSON.stringify({ compilerOptions: {} })
1211                };
1212                return createWatchedSystem([aFile, config, libFile], { currentDirectory: projectRoot });
1213            },
1214            changes: [
1215                {
1216                    caption: "Enable strict null checks",
1217                    change: sys => sys.writeFile(`${projectRoot}/tsconfig.json`, JSON.stringify({ compilerOptions: { strictNullChecks: true } })),
1218                    timeouts: runQueuedTimeoutCallbacks,
1219                },
1220                {
1221                    caption: "Set always strict false",
1222                    change: sys => sys.writeFile(`${projectRoot}/tsconfig.json`, JSON.stringify({ compilerOptions: { strict: true, alwaysStrict: false } })), // Avoid changing 'alwaysStrict' or must re-bind
1223                    timeouts: runQueuedTimeoutCallbacks,
1224                },
1225                {
1226                    caption: "Disable strict",
1227                    change: sys => sys.writeFile(`${projectRoot}/tsconfig.json`, JSON.stringify({ compilerOptions: {} })),
1228                    timeouts: runQueuedTimeoutCallbacks,
1229                },
1230            ]
1231        });
1232
1233        verifyTscWatch({
1234            scenario,
1235            subScenario: "updates errors when noErrorTruncation changes",
1236            commandLineArgs: ["-w"],
1237            sys: () => {
1238                const aFile: File = {
1239                    path: `${projectRoot}/a.ts`,
1240                    content: `declare var v: {
1241    reallyLongPropertyName1: string | number | boolean | object | symbol | bigint;
1242    reallyLongPropertyName2: string | number | boolean | object | symbol | bigint;
1243    reallyLongPropertyName3: string | number | boolean | object | symbol | bigint;
1244    reallyLongPropertyName4: string | number | boolean | object | symbol | bigint;
1245    reallyLongPropertyName5: string | number | boolean | object | symbol | bigint;
1246    reallyLongPropertyName6: string | number | boolean | object | symbol | bigint;
1247    reallyLongPropertyName7: string | number | boolean | object | symbol | bigint;
1248};
1249v === 'foo';`
1250                };
1251                const config: File = {
1252                    path: `${projectRoot}/tsconfig.json`,
1253                    content: JSON.stringify({ compilerOptions: {} })
1254                };
1255                return createWatchedSystem([aFile, config, libFile], { currentDirectory: projectRoot });
1256            },
1257            changes: [
1258                {
1259                    caption: "Enable noErrorTruncation",
1260                    change: sys => sys.writeFile(`${projectRoot}/tsconfig.json`, JSON.stringify({ compilerOptions: { noErrorTruncation: true } })),
1261                    timeouts: runQueuedTimeoutCallbacks,
1262                },
1263            ]
1264        });
1265
1266        verifyTscWatch({
1267            scenario,
1268            subScenario: "updates diagnostics and emit when useDefineForClassFields changes",
1269            commandLineArgs: ["-w"],
1270            sys: () => {
1271                const aFile: File = {
1272                    path: `/a.ts`,
1273                    content: `class C { get prop() { return 1; } }
1274class D extends C { prop = 1; }`
1275                };
1276                const config: File = {
1277                    path: `/tsconfig.json`,
1278                    content: JSON.stringify({ compilerOptions: { target: "es6" } })
1279                };
1280                return createWatchedSystem([aFile, config, libFile]);
1281            },
1282            changes: [
1283                {
1284                    caption: "Enable useDefineForClassFields",
1285                    change: sys => sys.writeFile(`/tsconfig.json`, JSON.stringify({ compilerOptions: { target: "es6", useDefineForClassFields: true } })),
1286                    timeouts: runQueuedTimeoutCallbacks,
1287                },
1288            ]
1289        });
1290
1291        verifyTscWatch({
1292            scenario,
1293            subScenario: "updates errors and emit when importsNotUsedAsValues changes",
1294            commandLineArgs: ["-w"],
1295            sys: () => {
1296                const aFile: File = {
1297                    path: `${projectRoot}/a.ts`,
1298                    content: `export class C {}`
1299                };
1300                const bFile: File = {
1301                    path: `${projectRoot}/b.ts`,
1302                    content: `import {C} from './a';
1303export function f(p: C) { return p; }`
1304                };
1305                const config: File = {
1306                    path: `${projectRoot}/tsconfig.json`,
1307                    content: JSON.stringify({ compilerOptions: {} })
1308                };
1309                return createWatchedSystem([aFile, bFile, config, libFile], { currentDirectory: projectRoot });
1310            },
1311            changes: [
1312                {
1313                    caption: 'Set to "remove"',
1314                    change: sys => sys.writeFile(`${projectRoot}/tsconfig.json`, JSON.stringify({ compilerOptions: { importsNotUsedAsValues: "remove" } })),
1315                    timeouts: runQueuedTimeoutCallbacks,
1316                },
1317                {
1318                    caption: 'Set to "error"',
1319                    change: sys => sys.writeFile(`${projectRoot}/tsconfig.json`, JSON.stringify({ compilerOptions: { importsNotUsedAsValues: "error" } })),
1320                    timeouts: runQueuedTimeoutCallbacks,
1321                },
1322                {
1323                    caption: 'Set to "preserve"',
1324                    change: sys => sys.writeFile(`${projectRoot}/tsconfig.json`, JSON.stringify({ compilerOptions: { importsNotUsedAsValues: "preserve" } })),
1325                    timeouts: runQueuedTimeoutCallbacks,
1326                },
1327            ]
1328        });
1329
1330
1331        verifyTscWatch({
1332            scenario,
1333            subScenario: "updates errors when forceConsistentCasingInFileNames changes",
1334            commandLineArgs: ["-w"],
1335            sys: () => {
1336                const aFile: File = {
1337                    path: `/a.ts`,
1338                    content: `export class C {}`
1339                };
1340                const bFile: File = {
1341                    path: `/b.ts`,
1342                    content: `import {C} from './a'; import * as A from './A';`
1343                };
1344                const config: File = {
1345                    path: `/tsconfig.json`,
1346                    content: JSON.stringify({ compilerOptions: {} })
1347                };
1348                return createWatchedSystem([aFile, bFile, config, libFile], { useCaseSensitiveFileNames: false });
1349            },
1350            changes: [
1351                {
1352                    caption: "Enable forceConsistentCasingInFileNames",
1353                    change: sys => sys.writeFile(`/tsconfig.json`, JSON.stringify({ compilerOptions: { forceConsistentCasingInFileNames: true } })),
1354                    timeouts: runQueuedTimeoutCallbacks,
1355                },
1356            ]
1357        });
1358
1359        verifyTscWatch({
1360            scenario,
1361            subScenario: "updates moduleResolution when resolveJsonModule changes",
1362            commandLineArgs: ["-w"],
1363            sys: () => {
1364                const aFile: File = {
1365                    path: `${projectRoot}/a.ts`,
1366                    content: `import * as data from './data.json'`
1367                };
1368                const jsonFile: File = {
1369                    path: `${projectRoot}/data.json`,
1370                    content: `{ "foo": 1 }`
1371                };
1372                const config: File = {
1373                    path: `${projectRoot}/tsconfig.json`,
1374                    content: JSON.stringify({ compilerOptions: { moduleResolution: "node" } })
1375                };
1376                return createWatchedSystem([aFile, jsonFile, config, libFile], { currentDirectory: projectRoot });
1377            },
1378            changes: [
1379                {
1380                    caption: "Enable resolveJsonModule",
1381                    change: sys => sys.writeFile(`${projectRoot}/tsconfig.json`, JSON.stringify({ compilerOptions: { moduleResolution: "node", resolveJsonModule: true } })),
1382                    timeouts: runQueuedTimeoutCallbacks,
1383                },
1384            ]
1385        });
1386
1387        verifyTscWatch({
1388            scenario,
1389            subScenario: "updates errors when ambient modules of program changes",
1390            commandLineArgs: ["-w"],
1391            sys: () => {
1392                const aFile: File = {
1393                    path: `${projectRoot}/a.ts`,
1394                    content: `declare module 'a' {
1395  type foo = number;
1396}`
1397                };
1398                const config: File = {
1399                    path: `${projectRoot}/tsconfig.json`,
1400                    content: "{}"
1401                };
1402                return createWatchedSystem([aFile, config, libFile], { currentDirectory: projectRoot });
1403            },
1404            changes: [
1405                {
1406                    caption: "Create b.ts with same content",
1407                    // Create bts with same file contents
1408                    change: sys => sys.writeFile(`${projectRoot}/b.ts`, `declare module 'a' {
1409  type foo = number;
1410}`),
1411                    timeouts: runQueuedTimeoutCallbacks,
1412                },
1413                {
1414                    caption: "Delete b.ts",
1415                    change: sys => sys.deleteFile(`${projectRoot}/b.ts`),
1416                    timeouts: runQueuedTimeoutCallbacks,
1417                },
1418            ]
1419        });
1420
1421        describe("updates errors in lib file", () => {
1422            const field = "fullscreen";
1423            const fieldWithoutReadonly = `interface Document {
1424    ${field}: boolean;
1425}`;
1426
1427            const libFileWithDocument: File = {
1428                path: libFile.path,
1429                content: `${libFile.content}
1430interface Document {
1431    readonly ${field}: boolean;
1432}`
1433            };
1434
1435            function verifyLibFileErrorsWith(subScenario: string, aFile: File) {
1436                function verifyLibErrors(subScenario: string, commandLineOptions: readonly string[]) {
1437                    verifyTscWatch({
1438                        scenario,
1439                        subScenario: `updates errors in lib file/${subScenario}`,
1440                        commandLineArgs: ["-w", aFile.path, ...commandLineOptions],
1441                        sys: () => createWatchedSystem([aFile, libFileWithDocument], { currentDirectory: projectRoot }),
1442                        changes: [
1443                            {
1444                                caption: "Remove document declaration from file",
1445                                change: sys => sys.writeFile(aFile.path, aFile.content.replace(fieldWithoutReadonly, "var x: string;")),
1446                                timeouts: runQueuedTimeoutCallbacks,
1447                            },
1448                            {
1449                                caption: "Rever the file to contain document declaration",
1450                                change: sys => sys.writeFile(aFile.path, aFile.content),
1451                                timeouts: runQueuedTimeoutCallbacks,
1452                            },
1453                        ]
1454                    });
1455                }
1456
1457                verifyLibErrors(`${subScenario}/with default options`, emptyArray);
1458                verifyLibErrors(`${subScenario}/with skipLibCheck`, ["--skipLibCheck"]);
1459                verifyLibErrors(`${subScenario}/with skipDefaultLibCheck`, ["--skipDefaultLibCheck"]);
1460            }
1461
1462            describe("when non module file changes", () => {
1463                const aFile: File = {
1464                    path: `${projectRoot}/a.ts`,
1465                    content: `${fieldWithoutReadonly}
1466var y: number;`
1467                };
1468                verifyLibFileErrorsWith("when non module file changes", aFile);
1469            });
1470
1471            describe("when module file with global definitions changes", () => {
1472                const aFile: File = {
1473                    path: `${projectRoot}/a.ts`,
1474                    content: `export {}
1475declare global {
1476${fieldWithoutReadonly}
1477var y: number;
1478}`
1479                };
1480                verifyLibFileErrorsWith("when module file with global definitions changes", aFile);
1481            });
1482        });
1483
1484        function changeWhenLibCheckChanges(compilerOptions: CompilerOptions): TscWatchCompileChange {
1485            const configFileContent = JSON.stringify({ compilerOptions });
1486            return {
1487                caption: `Changing config to ${configFileContent}`,
1488                change: sys => sys.writeFile(`${projectRoot}/tsconfig.json`, configFileContent),
1489                timeouts: runQueuedTimeoutCallbacks,
1490            };
1491        }
1492
1493        verifyTscWatch({
1494            scenario,
1495            subScenario: "when skipLibCheck and skipDefaultLibCheck changes",
1496            commandLineArgs: ["-w"],
1497            sys: () => {
1498                const field = "fullscreen";
1499                const aFile: File = {
1500                    path: `${projectRoot}/a.ts`,
1501                    content: `interface Document {
1502    ${field}: boolean;
1503}`
1504                };
1505                const bFile: File = {
1506                    path: `${projectRoot}/b.d.ts`,
1507                    content: `interface Document {
1508    ${field}: boolean;
1509}`
1510                };
1511                const libFileWithDocument: File = {
1512                    path: libFile.path,
1513                    content: `${libFile.content}
1514interface Document {
1515    readonly ${field}: boolean;
1516}`
1517                };
1518                const configFile: File = {
1519                    path: `${projectRoot}/tsconfig.json`,
1520                    content: "{}"
1521                };
1522                return createWatchedSystem([aFile, bFile, configFile, libFileWithDocument], { currentDirectory: projectRoot });
1523            },
1524            changes: [
1525                changeWhenLibCheckChanges({ skipLibCheck: true }),
1526                changeWhenLibCheckChanges({ skipDefaultLibCheck: true }),
1527                changeWhenLibCheckChanges({}),
1528                changeWhenLibCheckChanges({ skipDefaultLibCheck: true }),
1529                changeWhenLibCheckChanges({ skipLibCheck: true }),
1530                changeWhenLibCheckChanges({}),
1531            ]
1532        });
1533
1534        verifyTscWatch({
1535            scenario,
1536            subScenario: "reports errors correctly with isolatedModules",
1537            commandLineArgs: ["-w"],
1538            sys: () => {
1539                const aFile: File = {
1540                    path: `${projectRoot}/a.ts`,
1541                    content: `export const a: string = "";`
1542                };
1543                const bFile: File = {
1544                    path: `${projectRoot}/b.ts`,
1545                    content: `import { a } from "./a";
1546const b: string = a;`
1547                };
1548                const configFile: File = {
1549                    path: `${projectRoot}/tsconfig.json`,
1550                    content: JSON.stringify({
1551                        compilerOptions: {
1552                            isolatedModules: true
1553                        }
1554                    })
1555                };
1556                return createWatchedSystem([aFile, bFile, configFile, libFile], { currentDirectory: projectRoot });
1557            },
1558            changes: [
1559                {
1560                    caption: "Change shape of a",
1561                    change: sys => sys.writeFile(`${projectRoot}/a.ts`, `export const a: number = 1`),
1562                    timeouts: runQueuedTimeoutCallbacks,
1563                },
1564            ]
1565        });
1566
1567        verifyTscWatch({
1568            scenario,
1569            subScenario: "reports errors correctly with file not in rootDir",
1570            commandLineArgs: ["-w"],
1571            sys: () => {
1572                const aFile: File = {
1573                    path: `${projectRoot}/a.ts`,
1574                    content: `import { x } from "../b";`
1575                };
1576                const bFile: File = {
1577                    path: `/user/username/projects/b.ts`,
1578                    content: `export const x = 10;`
1579                };
1580                const configFile: File = {
1581                    path: `${projectRoot}/tsconfig.json`,
1582                    content: JSON.stringify({
1583                        compilerOptions: {
1584                            rootDir: ".",
1585                            outDir: "lib"
1586                        }
1587                    })
1588                };
1589                return createWatchedSystem([aFile, bFile, configFile, libFile], { currentDirectory: projectRoot });
1590            },
1591            changes: [
1592                {
1593                    caption: "Make changes to file a",
1594                    change: sys => sys.writeFile(`${projectRoot}/a.ts`, `
1595
1596import { x } from "../b";`),
1597                    timeouts: runQueuedTimeoutCallbacks,
1598                },
1599            ]
1600        });
1601
1602        verifyTscWatch({
1603            scenario,
1604            subScenario: "updates emit on jsx option change",
1605            commandLineArgs: ["-w"],
1606            sys: () => {
1607                const index: File = {
1608                    path: `${projectRoot}/index.tsx`,
1609                    content: `declare var React: any;\nconst d = <div />;`
1610                };
1611                const configFile: File = {
1612                    path: `${projectRoot}/tsconfig.json`,
1613                    content: JSON.stringify({
1614                        compilerOptions: {
1615                            jsx: "preserve"
1616                        }
1617                    })
1618                };
1619                return createWatchedSystem([index, configFile, libFile], { currentDirectory: projectRoot });
1620            },
1621            changes: [
1622                {
1623                    caption: "Update 'jsx' to 'react'",
1624                    change: sys => sys.writeFile(`${projectRoot}/tsconfig.json`, '{ "compilerOptions": { "jsx": "react" } }'),
1625                    timeouts: runQueuedTimeoutCallbacks,
1626                },
1627            ]
1628        });
1629
1630        verifyTscWatch({
1631            scenario,
1632            subScenario: "extended source files are watched",
1633            commandLineArgs: ["-w", "-p", configFilePath],
1634            sys: () => {
1635                const firstExtendedConfigFile: File = {
1636                    path: "/a/b/first.tsconfig.json",
1637                    content: JSON.stringify({
1638                        compilerOptions: {
1639                            strict: true
1640                        }
1641                    })
1642                };
1643                const secondExtendedConfigFile: File = {
1644                    path: "/a/b/second.tsconfig.json",
1645                    content: JSON.stringify({
1646                        extends: "./first.tsconfig.json"
1647                    })
1648                };
1649                const configFile: File = {
1650                    path: configFilePath,
1651                    content: JSON.stringify({
1652                        compilerOptions: {},
1653                        files: [commonFile1.path, commonFile2.path]
1654                    })
1655                };
1656                return createWatchedSystem([
1657                    libFile, commonFile1, commonFile2, configFile, firstExtendedConfigFile, secondExtendedConfigFile
1658                ]);
1659            },
1660            changes: [
1661                {
1662                    caption: "Change config to extend another config",
1663                    change: sys => sys.modifyFile(configFilePath, JSON.stringify({
1664                        extends: "./second.tsconfig.json",
1665                        compilerOptions: {},
1666                        files: [commonFile1.path, commonFile2.path]
1667                    })),
1668                    timeouts: checkSingleTimeoutQueueLengthAndRun,
1669                },
1670                {
1671                    caption: "Change first extended config",
1672                    change: sys => sys.modifyFile("/a/b/first.tsconfig.json", JSON.stringify({
1673                        compilerOptions: {
1674                            strict: false,
1675                        }
1676                    })),
1677                    timeouts: checkSingleTimeoutQueueLengthAndRun,
1678                },
1679                {
1680                    caption: "Change second extended config",
1681                    change: sys => sys.modifyFile("/a/b/second.tsconfig.json", JSON.stringify({
1682                        extends: "./first.tsconfig.json",
1683                        compilerOptions: {
1684                            strictNullChecks: true,
1685                        }
1686                    })),
1687                    timeouts: checkSingleTimeoutQueueLengthAndRun,
1688                },
1689                {
1690                    caption: "Change config to stop extending another config",
1691                    change: sys => sys.modifyFile(configFilePath, JSON.stringify({
1692                        compilerOptions: {},
1693                        files: [commonFile1.path, commonFile2.path]
1694                    })),
1695                    timeouts: checkSingleTimeoutQueueLengthAndRun,
1696                },
1697            ]
1698        });
1699    });
1700}
1701