Skip to content

Commit ad2fbaa

Browse files
committed
Watch extended configs if present
1 parent b5b0437 commit ad2fbaa

File tree

8 files changed

+600
-0
lines changed

8 files changed

+600
-0
lines changed

src/compiler/watchPublic.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ namespace ts {
246246

247247
let builderProgram: T;
248248
let reloadLevel: ConfigFileProgramReloadLevel; // level to indicate if the program needs to be reloaded from config file/just filenames etc
249+
let extendedConfigFilesMap: ESMap<Path, FileWatcher>; // Map of file watchers for the extended config files
249250
let missingFilesMap: ESMap<Path, FileWatcher>; // Map of file watchers for the missing files
250251
let watchedWildcardDirectories: ESMap<string, WildcardDirectoryWatcher>; // map of watchers for the wild card directories in the config file
251252
let timerToUpdateProgram: any; // timer callback to recompile the program
@@ -354,6 +355,10 @@ namespace ts {
354355
configFileWatcher.close();
355356
configFileWatcher = undefined;
356357
}
358+
if (extendedConfigFilesMap) {
359+
clearMap(extendedConfigFilesMap, closeFileWatcher);
360+
extendedConfigFilesMap = undefined!;
361+
}
357362
if (watchedWildcardDirectories) {
358363
clearMap(watchedWildcardDirectories, closeFileWatcherOf);
359364
watchedWildcardDirectories = undefined!;
@@ -419,6 +424,7 @@ namespace ts {
419424
resolutionCache.finishCachingPerDirectoryResolution();
420425

421426
// Update watches
427+
updateExtendedConfigFilePathsWatch(builderProgram.getProgram(), extendedConfigFilesMap || (extendedConfigFilesMap = new Map()), watchExtendedConfigFile);
422428
updateMissingFilePathsWatch(builderProgram.getProgram(), missingFilesMap || (missingFilesMap = new Map()), watchMissingFilePath);
423429
if (needsUpdateInTypeRootWatch) {
424430
resolutionCache.updateTypeRootsWatch();
@@ -706,6 +712,10 @@ namespace ts {
706712
}
707713
}
708714

715+
function watchExtendedConfigFile(extendedConfigFile: string) {
716+
return watchFile(extendedConfigFile, scheduleProgramReload, PollingInterval.High, watchOptions, WatchType.ConfigFile);
717+
}
718+
709719
function watchMissingFilePath(missingFilePath: Path) {
710720
return watchFilePath(missingFilePath, missingFilePath, onMissingFileChange, PollingInterval.Medium, watchOptions, WatchType.MissingFile);
711721
}

src/compiler/watchUtilities.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,30 @@ namespace ts {
257257
Full
258258
}
259259

260+
/**
261+
* Updates the extended config file watches with the new set of extended config files after new program is created
262+
*/
263+
export function updateExtendedConfigFilePathsWatch(
264+
program: Program,
265+
extendedConfigFilesMap: ESMap<string, FileWatcher>,
266+
createExtendedConfigFileWatch: (extendedConfigPath: string) => FileWatcher,
267+
) {
268+
const extendedSourceFiles = program.getCompilerOptions().configFile?.extendedSourceFiles || [];
269+
// TODO(rbuckton): Should be a `Set` but that requires changing the below code that uses `mutateMap`
270+
const newExtendedConfigFilesMap = arrayToMap(extendedSourceFiles, identity, returnTrue);
271+
// Update the extended config files watcher
272+
mutateMap(
273+
extendedConfigFilesMap,
274+
newExtendedConfigFilesMap,
275+
{
276+
// Watch the extended config files
277+
createNewValue: createExtendedConfigFileWatch,
278+
// Config files that are no longer extended should no longer be watched.
279+
onDeleteValue: closeFileWatcher
280+
}
281+
);
282+
}
283+
260284
/**
261285
* Updates the existing missing file watches with the new set of missing files after new program is created
262286
*/

src/testRunner/unittests/tscWatch/watchEnvironment.ts

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,5 +497,161 @@ namespace ts.tscWatch {
497497
verifyWorker("-extendedDiagnostics");
498498
});
499499
});
500+
501+
describe("handles watch for extended configs", () => {
502+
verifyTscWatch({
503+
scenario,
504+
subScenario: "watchExtends/with several extended configs",
505+
commandLineArgs: ["-w", "-p", "/a/b/tsconfig.json"],
506+
sys: () => {
507+
const firstExtendedFile: File = {
508+
path: "/a/b/first.tsconfig.json",
509+
content: JSON.stringify({
510+
compilerOptions: {
511+
strict: false,
512+
}
513+
})
514+
};
515+
const secondExtendedFile: File = {
516+
path: "/a/b/second.tsconfig.json",
517+
content: JSON.stringify({
518+
extends: "./first.tsconfig.json",
519+
compilerOptions: {
520+
strictNullChecks: true,
521+
}
522+
})
523+
};
524+
const thirdExtendedFile: File = {
525+
path: "/a/b/third.tsconfig.json",
526+
content: JSON.stringify({
527+
extends: "./second.tsconfig.json",
528+
compilerOptions: {
529+
strictBindCallApply: true,
530+
}
531+
})
532+
};
533+
const fourthExtendedFile: File = {
534+
path: "/a/b/fourth.tsconfig.json",
535+
content: JSON.stringify({
536+
extends: "./third.tsconfig.json",
537+
compilerOptions: {
538+
strictFunctionTypes: true,
539+
}
540+
})
541+
};
542+
const configFile: File = {
543+
path: "/a/b/tsconfig.json",
544+
content: JSON.stringify({
545+
extends: "./fourth.tsconfig.json",
546+
compilerOptions: {
547+
strictPropertyInitialization: true,
548+
}
549+
})
550+
};
551+
const files = [
552+
libFile, commonFile1, commonFile2, firstExtendedFile, secondExtendedFile, thirdExtendedFile,
553+
fourthExtendedFile, configFile
554+
];
555+
return createWatchedSystem(files);
556+
},
557+
changes: emptyArray
558+
});
559+
560+
verifyTscWatch({
561+
scenario,
562+
subScenario: "watchExtends/with watchFile option",
563+
commandLineArgs: ["-w", "-p", "/a/b/tsconfig.json"],
564+
sys: () => {
565+
const extendedFile: File = {
566+
path: "/a/b/extended.tsconfig.json",
567+
content: JSON.stringify({
568+
watchOptions: {
569+
watchFile: "UseFsEvents"
570+
}
571+
})
572+
};
573+
const configFile: File = {
574+
path: "/a/b/tsconfig.json",
575+
content: JSON.stringify({
576+
extends: "./extended.tsconfig.json"
577+
})
578+
};
579+
const files = [libFile, commonFile1, commonFile2, extendedFile, configFile];
580+
return createWatchedSystem(files);
581+
},
582+
changes: emptyArray
583+
});
584+
585+
verifyTscWatch({
586+
scenario,
587+
subScenario: "watchExtends/with watchDirectory option",
588+
commandLineArgs: ["-w", "-p", "/a/b/tsconfig.json"],
589+
sys: () => {
590+
const extendedFile: File = {
591+
path: "/a/b/extended.tsconfig.json",
592+
content: JSON.stringify({
593+
watchOptions: {
594+
watchDirectory: "UseFsEvents"
595+
}
596+
})
597+
};
598+
const configFile: File = {
599+
path: "/a/b/tsconfig.json",
600+
content: JSON.stringify({
601+
extends: "./extended.tsconfig.json"
602+
})
603+
};
604+
const files = [libFile, commonFile1, commonFile2, extendedFile, configFile];
605+
return createWatchedSystem(files, { runWithoutRecursiveWatches: true });
606+
},
607+
changes: emptyArray
608+
});
609+
610+
verifyTscWatch({
611+
scenario,
612+
subScenario: "watchExtends/with fallbackPolling option",
613+
commandLineArgs: ["-w", "-p", "/a/b/tsconfig.json"],
614+
sys: () => {
615+
const extendedFile: File = {
616+
path: "/a/b/extended.tsconfig.json",
617+
content: JSON.stringify({
618+
watchOptions: {
619+
fallbackPolling: "PriorityInterval"
620+
}
621+
})
622+
};
623+
const configFile: File = {
624+
path: "/a/b/tsconfig.json",
625+
content: JSON.stringify({
626+
extends: "./extended.tsconfig.json"
627+
})
628+
};
629+
const files = [libFile, commonFile1, commonFile2, extendedFile, configFile];
630+
return createWatchedSystem(files, { runWithoutRecursiveWatches: true, runWithFallbackPolling: true });
631+
},
632+
changes: emptyArray
633+
});
634+
635+
verifyTscWatch({
636+
scenario,
637+
subScenario: "watchExtends/with watchFile as watch options to extend",
638+
commandLineArgs: ["-w", "-p", "/a/b/tsconfig.json", "--watchFile", "UseFsEvents"],
639+
sys: () => {
640+
const extendedFile: File = {
641+
path: "/a/b/extended.tsconfig.json",
642+
content: "{}"
643+
};
644+
const configFile: File = {
645+
path: "/a/b/tsconfig.json",
646+
content: JSON.stringify({
647+
extends: "./extended.tsconfig.json"
648+
})
649+
};
650+
const files = [libFile, commonFile1, commonFile2, extendedFile, configFile];
651+
return createWatchedSystem(files);
652+
},
653+
changes: emptyArray
654+
});
655+
});
500656
});
501657
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
Input::
2+
//// [/a/lib/lib.d.ts]
3+
/// <reference no-default-lib="true"/>
4+
interface Boolean {}
5+
interface Function {}
6+
interface CallableFunction {}
7+
interface NewableFunction {}
8+
interface IArguments {}
9+
interface Number { toExponential: any; }
10+
interface Object {}
11+
interface RegExp {}
12+
interface String { charAt: any; }
13+
interface Array<T> { length: number; [n: number]: T; }
14+
15+
//// [/a/b/commonFile1.ts]
16+
let x = 1
17+
18+
//// [/a/b/commonFile2.ts]
19+
let y = 1
20+
21+
//// [/a/b/extended.tsconfig.json]
22+
{"watchOptions":{"fallbackPolling":"PriorityInterval"}}
23+
24+
//// [/a/b/tsconfig.json]
25+
{"extends":"./extended.tsconfig.json"}
26+
27+
28+
/a/lib/tsc.js -w -p /a/b/tsconfig.json
29+
Output::
30+
>> Screen clear
31+
[12:00:19 AM] Starting compilation in watch mode...
32+
33+
[12:00:24 AM] Found 0 errors. Watching for file changes.
34+
35+
36+
37+
Program root files: ["/a/b/commonFile1.ts","/a/b/commonFile2.ts"]
38+
Program options: {"watch":true,"project":"/a/b/tsconfig.json","configFilePath":"/a/b/tsconfig.json"}
39+
Program structureReused: Not
40+
Program files::
41+
/a/lib/lib.d.ts
42+
/a/b/commonFile1.ts
43+
/a/b/commonFile2.ts
44+
45+
Semantic diagnostics in builder refreshed for::
46+
/a/lib/lib.d.ts
47+
/a/b/commonFile1.ts
48+
/a/b/commonFile2.ts
49+
50+
WatchedFiles::
51+
/a/b/tsconfig.json:
52+
{"fileName":"/a/b/tsconfig.json","pollingInterval":250}
53+
/a/b/commonfile1.ts:
54+
{"fileName":"/a/b/commonFile1.ts","pollingInterval":250}
55+
/a/b/commonfile2.ts:
56+
{"fileName":"/a/b/commonFile2.ts","pollingInterval":250}
57+
/a/lib/lib.d.ts:
58+
{"fileName":"/a/lib/lib.d.ts","pollingInterval":250}
59+
/a/b/extended.tsconfig.json:
60+
{"fileName":"/a/b/extended.tsconfig.json","pollingInterval":250}
61+
/a/b/node_modules/@types:
62+
{"fileName":"/a/b/node_modules/@types","pollingInterval":500}
63+
/a/b:
64+
{"fileName":"/a/b","pollingInterval":500}
65+
66+
FsWatches::
67+
68+
FsWatchesRecursive::
69+
70+
exitCode:: ExitStatus.undefined
71+
72+
//// [/a/b/commonFile1.js]
73+
var x = 1;
74+
75+
76+
//// [/a/b/commonFile2.js]
77+
var y = 1;
78+
79+

0 commit comments

Comments
 (0)