Skip to content

Commit 7bb5fc2

Browse files
authored
Merge pull request #20427 from JoshuaKGoldberg/watch-immediate-clears
Added console clearing with a message to --watch starts
2 parents 7de6083 + cf9b8ba commit 7bb5fc2

File tree

3 files changed

+81
-44
lines changed

3 files changed

+81
-44
lines changed

src/compiler/diagnosticMessages.json

+4
Original file line numberDiff line numberDiff line change
@@ -2828,6 +2828,10 @@
28282828
"category": "Message",
28292829
"code": 6030
28302830
},
2831+
"Starting compilation in watch mode...": {
2832+
"category": "Message",
2833+
"code": 6031
2834+
},
28312835
"File change detected. Starting incremental compilation...": {
28322836
"category": "Message",
28332837
"code": 6032

src/compiler/watch.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,8 @@ namespace ts {
302302
// There is no extra check needed since we can just rely on the program to decide emit
303303
const builder = createBuilder({ getCanonicalFileName, computeHash });
304304

305+
clearHostScreen();
306+
reportWatchDiagnostic(createCompilerDiagnostic(Diagnostics.Starting_compilation_in_watch_mode));
305307
synchronizeProgram();
306308

307309
// Update the wild card directory watch
@@ -492,10 +494,14 @@ namespace ts {
492494
scheduleProgramUpdate();
493495
}
494496

495-
function updateProgram() {
497+
function clearHostScreen() {
496498
if (watchingHost.system.clearScreen) {
497499
watchingHost.system.clearScreen();
498500
}
501+
}
502+
503+
function updateProgram() {
504+
clearHostScreen();
499505

500506
timerToUpdateProgram = undefined;
501507
reportWatchDiagnostic(createCompilerDiagnostic(Diagnostics.File_change_detected_Starting_incremental_compilation));

src/harness/unittests/tscWatchMode.ts

+70-43
Original file line numberDiff line numberDiff line change
@@ -80,20 +80,47 @@ namespace ts.tscWatch {
8080
checkOutputDoesNotContain(host, expectedNonAffectedFiles);
8181
}
8282

83-
function checkOutputErrors(host: WatchedSystem, errors: ReadonlyArray<Diagnostic>, isInitial?: true, skipWaiting?: true) {
83+
enum ExpectedOutputErrorsPosition {
84+
BeforeCompilationStarts,
85+
AfterCompilationStarting,
86+
AfterFileChangeDetected
87+
}
88+
89+
function checkOutputErrors(
90+
host: WatchedSystem,
91+
errors: ReadonlyArray<Diagnostic>,
92+
errorsPosition: ExpectedOutputErrorsPosition,
93+
skipWaiting?: true
94+
) {
8495
const outputs = host.getOutput();
85-
const expectedOutputCount = (isInitial ? 0 : 1) + errors.length + (skipWaiting ? 0 : 1);
96+
const expectedOutputCount = errors.length + (skipWaiting ? 0 : 1) + 1;
8697
assert.equal(outputs.length, expectedOutputCount, "Outputs = " + outputs.toString());
87-
let index = 0;
88-
if (!isInitial) {
89-
assertWatchDiagnosticAt(host, index, Diagnostics.File_change_detected_Starting_incremental_compilation);
90-
index++;
98+
let index: number;
99+
100+
switch (errorsPosition) {
101+
case ExpectedOutputErrorsPosition.AfterCompilationStarting:
102+
assertWatchDiagnosticAt(host, 0, Diagnostics.Starting_compilation_in_watch_mode);
103+
index = 1;
104+
break;
105+
case ExpectedOutputErrorsPosition.AfterFileChangeDetected:
106+
assertWatchDiagnosticAt(host, 0, Diagnostics.File_change_detected_Starting_incremental_compilation);
107+
index = 1;
108+
break;
109+
case ExpectedOutputErrorsPosition.BeforeCompilationStarts:
110+
assertWatchDiagnosticAt(host, errors.length, Diagnostics.Starting_compilation_in_watch_mode);
111+
index = 0;
112+
break;
91113
}
114+
92115
forEach(errors, error => {
93116
assertDiagnosticAt(host, index, error);
94117
index++;
95118
});
96119
if (!skipWaiting) {
120+
if (errorsPosition === ExpectedOutputErrorsPosition.BeforeCompilationStarts) {
121+
assertWatchDiagnosticAt(host, index, ts.Diagnostics.Starting_compilation_in_watch_mode);
122+
index += 1;
123+
}
97124
assertWatchDiagnosticAt(host, index, Diagnostics.Compilation_complete_Watching_for_file_changes);
98125
}
99126
host.clearOutput();
@@ -333,13 +360,13 @@ namespace ts.tscWatch {
333360
checkOutputErrors(host, [
334361
getDiagnosticOfFileFromProgram(watch(), file1.path, file1.content.indexOf(commonFile2Name), commonFile2Name.length, Diagnostics.File_0_not_found, commonFile2.path),
335362
getDiagnosticOfFileFromProgram(watch(), file1.path, file1.content.indexOf("y"), 1, Diagnostics.Cannot_find_name_0, "y")
336-
], /*isInitial*/ true);
363+
], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
337364

338365
host.reloadFS([file1, commonFile2, libFile]);
339366
host.runQueuedTimeoutCallbacks();
340367
checkProgramRootFiles(watch(), [file1.path]);
341368
checkProgramActualFiles(watch(), [file1.path, libFile.path, commonFile2.path]);
342-
checkOutputErrors(host, emptyArray);
369+
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
343370
});
344371

345372
it("should reflect change in config file", () => {
@@ -667,15 +694,15 @@ namespace ts.tscWatch {
667694
const watch = createWatchModeWithConfigFile(config.path, host);
668695

669696
checkProgramActualFiles(watch(), [file1.path, file2.path, libFile.path]);
670-
checkOutputErrors(host, emptyArray, /*isInitial*/ true);
697+
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
671698

672699
host.reloadFS([file1, file2, libFile]);
673700
host.checkTimeoutQueueLengthAndRun(1);
674701

675702
assert.equal(host.exitCode, ExitStatus.DiagnosticsPresent_OutputsSkipped);
676703
checkOutputErrors(host, [
677704
getDiagnosticWithoutFile(Diagnostics.File_0_not_found, config.path)
678-
], /*isInitial*/ undefined, /*skipWaiting*/ true);
705+
], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected, /*skipWaiting*/ true);
679706
});
680707

681708
it("Proper errors: document is not contained in project", () => {
@@ -778,7 +805,7 @@ namespace ts.tscWatch {
778805
};
779806
const host = createWatchedSystem([moduleFile, file1, libFile]);
780807
const watch = createWatchModeWithoutConfigFile([file1.path], host);
781-
checkOutputErrors(host, emptyArray, /*isInitial*/ true);
808+
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
782809

783810
const moduleFileOldPath = moduleFile.path;
784811
const moduleFileNewPath = "/a/b/moduleFile1.ts";
@@ -787,12 +814,12 @@ namespace ts.tscWatch {
787814
host.runQueuedTimeoutCallbacks();
788815
checkOutputErrors(host, [
789816
getDiagnosticModuleNotFoundOfFile(watch(), file1, "./moduleFile")
790-
]);
817+
], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
791818

792819
moduleFile.path = moduleFileOldPath;
793820
host.reloadFS([moduleFile, file1, libFile]);
794821
host.runQueuedTimeoutCallbacks();
795-
checkOutputErrors(host, emptyArray);
822+
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
796823
});
797824

798825
it("rename a module file and rename back should restore the states for configured projects", () => {
@@ -810,7 +837,7 @@ namespace ts.tscWatch {
810837
};
811838
const host = createWatchedSystem([moduleFile, file1, configFile, libFile]);
812839
const watch = createWatchModeWithConfigFile(configFile.path, host);
813-
checkOutputErrors(host, emptyArray, /*isInitial*/ true);
840+
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
814841

815842
const moduleFileOldPath = moduleFile.path;
816843
const moduleFileNewPath = "/a/b/moduleFile1.ts";
@@ -819,12 +846,12 @@ namespace ts.tscWatch {
819846
host.runQueuedTimeoutCallbacks();
820847
checkOutputErrors(host, [
821848
getDiagnosticModuleNotFoundOfFile(watch(), file1, "./moduleFile")
822-
]);
849+
], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
823850

824851
moduleFile.path = moduleFileOldPath;
825852
host.reloadFS([moduleFile, file1, configFile, libFile]);
826853
host.runQueuedTimeoutCallbacks();
827-
checkOutputErrors(host, emptyArray);
854+
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
828855
});
829856

830857
it("types should load from config file path if config exists", () => {
@@ -863,11 +890,11 @@ namespace ts.tscWatch {
863890

864891
checkOutputErrors(host, [
865892
getDiagnosticModuleNotFoundOfFile(watch(), file1, "./moduleFile")
866-
], /*isInitial*/ true);
893+
], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
867894

868895
host.reloadFS([file1, moduleFile, libFile]);
869896
host.runQueuedTimeoutCallbacks();
870-
checkOutputErrors(host, emptyArray);
897+
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
871898
});
872899

873900
it("Configure file diagnostics events are generated when the config file has errors", () => {
@@ -890,7 +917,7 @@ namespace ts.tscWatch {
890917
checkOutputErrors(host, [
891918
getUnknownCompilerOption(watch(), configFile, "foo"),
892919
getUnknownCompilerOption(watch(), configFile, "allowJS")
893-
], /*isInitial*/ true);
920+
], /*errorsPosition*/ ExpectedOutputErrorsPosition.BeforeCompilationStarts);
894921
});
895922

896923
it("If config file doesnt have errors, they are not reported", () => {
@@ -907,7 +934,7 @@ namespace ts.tscWatch {
907934

908935
const host = createWatchedSystem([file, configFile, libFile]);
909936
createWatchModeWithConfigFile(configFile.path, host);
910-
checkOutputErrors(host, emptyArray, /*isInitial*/ true);
937+
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
911938
});
912939

913940
it("Reports errors when the config file changes", () => {
@@ -924,7 +951,7 @@ namespace ts.tscWatch {
924951

925952
const host = createWatchedSystem([file, configFile, libFile]);
926953
const watch = createWatchModeWithConfigFile(configFile.path, host);
927-
checkOutputErrors(host, emptyArray, /*isInitial*/ true);
954+
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
928955

929956
configFile.content = `{
930957
"compilerOptions": {
@@ -935,14 +962,14 @@ namespace ts.tscWatch {
935962
host.runQueuedTimeoutCallbacks();
936963
checkOutputErrors(host, [
937964
getUnknownCompilerOption(watch(), configFile, "haha")
938-
]);
965+
], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
939966

940967
configFile.content = `{
941968
"compilerOptions": {}
942969
}`;
943970
host.reloadFS([file, configFile, libFile]);
944971
host.runQueuedTimeoutCallbacks();
945-
checkOutputErrors(host, emptyArray);
972+
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
946973
});
947974

948975
it("non-existing directories listed in config file input array should be tolerated without crashing the server", () => {
@@ -1030,13 +1057,13 @@ namespace ts.tscWatch {
10301057
getDiagnosticOfFile(watch().getCompilerOptions().configFile, configFile.content.indexOf('"declaration"'), '"declaration"'.length, Diagnostics.Option_0_cannot_be_specified_with_option_1, "allowJs", "declaration")
10311058
];
10321059
const intialErrors = errors();
1033-
checkOutputErrors(host, intialErrors, /*isInitial*/ true);
1060+
checkOutputErrors(host, intialErrors, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
10341061

10351062
configFile.content = configFileContentWithoutCommentLine;
10361063
host.reloadFS(files);
10371064
host.runQueuedTimeoutCallbacks();
10381065
const nowErrors = errors();
1039-
checkOutputErrors(host, nowErrors);
1066+
checkOutputErrors(host, nowErrors, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
10401067
assert.equal(nowErrors[0].start, intialErrors[0].start - configFileContentComment.length);
10411068
assert.equal(nowErrors[1].start, intialErrors[1].start - configFileContentComment.length);
10421069
});
@@ -1667,7 +1694,7 @@ namespace ts.tscWatch {
16671694
const cannotFindFoo = getDiagnosticOfFileFromProgram(watch(), imported.path, imported.content.indexOf("foo"), "foo".length, Diagnostics.Cannot_find_name_0, "foo");
16681695

16691696
// ensure that imported file was found
1670-
checkOutputErrors(host, [f1IsNotModule, cannotFindFoo], /*isInitial*/ true);
1697+
checkOutputErrors(host, [f1IsNotModule, cannotFindFoo], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
16711698

16721699
const originalFileExists = host.fileExists;
16731700
{
@@ -1687,7 +1714,7 @@ namespace ts.tscWatch {
16871714
f1IsNotModule,
16881715
getDiagnosticOfFileFromProgram(watch(), root.path, newContent.indexOf("var x") + "var ".length, "x".length, Diagnostics.Type_0_is_not_assignable_to_type_1, 1, "string"),
16891716
cannotFindFoo
1690-
]);
1717+
], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
16911718
}
16921719
{
16931720
let fileExistsIsCalled = false;
@@ -1709,7 +1736,7 @@ namespace ts.tscWatch {
17091736
// ensure file has correct number of errors after edit
17101737
checkOutputErrors(host, [
17111738
getDiagnosticModuleNotFoundOfFile(watch(), root, "f2")
1712-
]);
1739+
], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
17131740

17141741
assert(fileExistsIsCalled);
17151742
}
@@ -1730,7 +1757,7 @@ namespace ts.tscWatch {
17301757
host.reloadFS(files);
17311758
host.runQueuedTimeoutCallbacks();
17321759

1733-
checkOutputErrors(host, [f1IsNotModule, cannotFindFoo]);
1760+
checkOutputErrors(host, [f1IsNotModule, cannotFindFoo], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
17341761
assert(fileExistsCalled);
17351762
}
17361763
});
@@ -1767,15 +1794,15 @@ namespace ts.tscWatch {
17671794
assert(fileExistsCalledForBar, "'fileExists' should be called");
17681795
checkOutputErrors(host, [
17691796
getDiagnosticModuleNotFoundOfFile(watch(), root, "bar")
1770-
], /*isInitial*/ true);
1797+
], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
17711798

17721799
fileExistsCalledForBar = false;
17731800
root.content = `import {y} from "bar"`;
17741801
host.reloadFS(files.concat(imported));
17751802

17761803
host.runQueuedTimeoutCallbacks();
1804+
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
17771805
assert(fileExistsCalledForBar, "'fileExists' should be called.");
1778-
checkOutputErrors(host, emptyArray);
17791806
});
17801807

17811808
it("should compile correctly when resolved module goes missing and then comes back (module is not part of the root)", () => {
@@ -1807,21 +1834,21 @@ namespace ts.tscWatch {
18071834
const watch = createWatchModeWithoutConfigFile([root.path], host, { module: ModuleKind.AMD });
18081835

18091836
assert(fileExistsCalledForBar, "'fileExists' should be called");
1810-
checkOutputErrors(host, emptyArray, /*isInitial*/ true);
1837+
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
18111838

18121839
fileExistsCalledForBar = false;
18131840
host.reloadFS(files);
18141841
host.runQueuedTimeoutCallbacks();
18151842
assert(fileExistsCalledForBar, "'fileExists' should be called.");
18161843
checkOutputErrors(host, [
18171844
getDiagnosticModuleNotFoundOfFile(watch(), root, "bar")
1818-
]);
1845+
], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
18191846

18201847
fileExistsCalledForBar = false;
18211848
host.reloadFS(filesWithImported);
18221849
host.checkTimeoutQueueLengthAndRun(1);
1850+
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
18231851
assert(fileExistsCalledForBar, "'fileExists' should be called.");
1824-
checkOutputErrors(host, emptyArray);
18251852
});
18261853

18271854
it("works when module resolution changes to ambient module", () => {
@@ -1857,11 +1884,11 @@ declare module "fs" {
18571884

18581885
checkOutputErrors(host, [
18591886
getDiagnosticModuleNotFoundOfFile(watch(), root, "fs")
1860-
], /*isInitial*/ true);
1887+
], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
18611888

18621889
host.reloadFS(filesWithNodeType);
18631890
host.runQueuedTimeoutCallbacks();
1864-
checkOutputErrors(host, emptyArray);
1891+
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
18651892
});
18661893

18671894
it("works when included file with ambient module changes", () => {
@@ -1899,12 +1926,12 @@ declare module "fs" {
18991926

19001927
checkOutputErrors(host, [
19011928
getDiagnosticModuleNotFoundOfFile(watch(), root, "fs")
1902-
], /*isInitial*/ true);
1929+
], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
19031930

19041931
file.content += fileContentWithFS;
19051932
host.reloadFS(files);
19061933
host.runQueuedTimeoutCallbacks();
1907-
checkOutputErrors(host, emptyArray);
1934+
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
19081935
});
19091936

19101937
it("works when reusing program with files from external library", () => {
@@ -1939,7 +1966,7 @@ declare module "fs" {
19391966
const host = createWatchedSystem(programFiles.concat(configFile), { currentDirectory: "/a/b/projects/myProject/" });
19401967
const watch = createWatchModeWithConfigFile(configFile.path, host);
19411968
checkProgramActualFiles(watch(), programFiles.map(f => f.path));
1942-
checkOutputErrors(host, emptyArray, /*isInitial*/ true);
1969+
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
19431970
const expectedFiles: ExpectedFile[] = [
19441971
createExpectedEmittedFile(file1),
19451972
createExpectedEmittedFile(file2),
@@ -1958,7 +1985,7 @@ declare module "fs" {
19581985
host.reloadFS(programFiles.concat(configFile));
19591986
host.runQueuedTimeoutCallbacks();
19601987
checkProgramActualFiles(watch(), programFiles.map(f => f.path));
1961-
checkOutputErrors(host, emptyArray);
1988+
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
19621989
verifyExpectedFiles(expectedFiles);
19631990

19641991

@@ -2029,7 +2056,7 @@ declare module "fs" {
20292056
});
20302057

20312058
describe("tsc-watch console clearing", () => {
2032-
it("doesn't clear the console when it starts", () => {
2059+
it("clears the console when it starts", () => {
20332060
const file = {
20342061
path: "f.ts",
20352062
content: ""
@@ -2039,7 +2066,7 @@ declare module "fs" {
20392066
createWatchModeWithoutConfigFile([file.path], host);
20402067
host.runQueuedTimeoutCallbacks();
20412068

2042-
host.checkScreenClears(0);
2069+
host.checkScreenClears(1);
20432070
});
20442071

20452072
it("clears the console on recompile", () => {
@@ -2057,7 +2084,7 @@ declare module "fs" {
20572084
host.reloadFS([modifiedFile]);
20582085
host.runQueuedTimeoutCallbacks();
20592086

2060-
host.checkScreenClears(1);
2087+
host.checkScreenClears(2);
20612088
});
20622089
});
20632090
}

0 commit comments

Comments
 (0)