Merge pull request #20427 from JoshuaKGoldberg/watch-immediate-clears

Added console clearing with a message to --watch starts
This commit is contained in:
Sheetal Nandi
2017-12-05 10:54:54 -08:00
committed by GitHub
3 changed files with 81 additions and 44 deletions

View File

@@ -2828,6 +2828,10 @@
"category": "Message",
"code": 6030
},
"Starting compilation in watch mode...": {
"category": "Message",
"code": 6031
},
"File change detected. Starting incremental compilation...": {
"category": "Message",
"code": 6032

View File

@@ -302,6 +302,8 @@ namespace ts {
// There is no extra check needed since we can just rely on the program to decide emit
const builder = createBuilder({ getCanonicalFileName, computeHash });
clearHostScreen();
reportWatchDiagnostic(createCompilerDiagnostic(Diagnostics.Starting_compilation_in_watch_mode));
synchronizeProgram();
// Update the wild card directory watch
@@ -492,10 +494,14 @@ namespace ts {
scheduleProgramUpdate();
}
function updateProgram() {
function clearHostScreen() {
if (watchingHost.system.clearScreen) {
watchingHost.system.clearScreen();
}
}
function updateProgram() {
clearHostScreen();
timerToUpdateProgram = undefined;
reportWatchDiagnostic(createCompilerDiagnostic(Diagnostics.File_change_detected_Starting_incremental_compilation));

View File

@@ -80,20 +80,47 @@ namespace ts.tscWatch {
checkOutputDoesNotContain(host, expectedNonAffectedFiles);
}
function checkOutputErrors(host: WatchedSystem, errors: ReadonlyArray<Diagnostic>, isInitial?: true, skipWaiting?: true) {
enum ExpectedOutputErrorsPosition {
BeforeCompilationStarts,
AfterCompilationStarting,
AfterFileChangeDetected
}
function checkOutputErrors(
host: WatchedSystem,
errors: ReadonlyArray<Diagnostic>,
errorsPosition: ExpectedOutputErrorsPosition,
skipWaiting?: true
) {
const outputs = host.getOutput();
const expectedOutputCount = (isInitial ? 0 : 1) + errors.length + (skipWaiting ? 0 : 1);
const expectedOutputCount = errors.length + (skipWaiting ? 0 : 1) + 1;
assert.equal(outputs.length, expectedOutputCount, "Outputs = " + outputs.toString());
let index = 0;
if (!isInitial) {
assertWatchDiagnosticAt(host, index, Diagnostics.File_change_detected_Starting_incremental_compilation);
index++;
let index: number;
switch (errorsPosition) {
case ExpectedOutputErrorsPosition.AfterCompilationStarting:
assertWatchDiagnosticAt(host, 0, Diagnostics.Starting_compilation_in_watch_mode);
index = 1;
break;
case ExpectedOutputErrorsPosition.AfterFileChangeDetected:
assertWatchDiagnosticAt(host, 0, Diagnostics.File_change_detected_Starting_incremental_compilation);
index = 1;
break;
case ExpectedOutputErrorsPosition.BeforeCompilationStarts:
assertWatchDiagnosticAt(host, errors.length, Diagnostics.Starting_compilation_in_watch_mode);
index = 0;
break;
}
forEach(errors, error => {
assertDiagnosticAt(host, index, error);
index++;
});
if (!skipWaiting) {
if (errorsPosition === ExpectedOutputErrorsPosition.BeforeCompilationStarts) {
assertWatchDiagnosticAt(host, index, ts.Diagnostics.Starting_compilation_in_watch_mode);
index += 1;
}
assertWatchDiagnosticAt(host, index, Diagnostics.Compilation_complete_Watching_for_file_changes);
}
host.clearOutput();
@@ -333,13 +360,13 @@ namespace ts.tscWatch {
checkOutputErrors(host, [
getDiagnosticOfFileFromProgram(watch(), file1.path, file1.content.indexOf(commonFile2Name), commonFile2Name.length, Diagnostics.File_0_not_found, commonFile2.path),
getDiagnosticOfFileFromProgram(watch(), file1.path, file1.content.indexOf("y"), 1, Diagnostics.Cannot_find_name_0, "y")
], /*isInitial*/ true);
], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
host.reloadFS([file1, commonFile2, libFile]);
host.runQueuedTimeoutCallbacks();
checkProgramRootFiles(watch(), [file1.path]);
checkProgramActualFiles(watch(), [file1.path, libFile.path, commonFile2.path]);
checkOutputErrors(host, emptyArray);
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
});
it("should reflect change in config file", () => {
@@ -667,7 +694,7 @@ namespace ts.tscWatch {
const watch = createWatchModeWithConfigFile(config.path, host);
checkProgramActualFiles(watch(), [file1.path, file2.path, libFile.path]);
checkOutputErrors(host, emptyArray, /*isInitial*/ true);
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
host.reloadFS([file1, file2, libFile]);
host.checkTimeoutQueueLengthAndRun(1);
@@ -675,7 +702,7 @@ namespace ts.tscWatch {
assert.equal(host.exitCode, ExitStatus.DiagnosticsPresent_OutputsSkipped);
checkOutputErrors(host, [
getDiagnosticWithoutFile(Diagnostics.File_0_not_found, config.path)
], /*isInitial*/ undefined, /*skipWaiting*/ true);
], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected, /*skipWaiting*/ true);
});
it("Proper errors: document is not contained in project", () => {
@@ -778,7 +805,7 @@ namespace ts.tscWatch {
};
const host = createWatchedSystem([moduleFile, file1, libFile]);
const watch = createWatchModeWithoutConfigFile([file1.path], host);
checkOutputErrors(host, emptyArray, /*isInitial*/ true);
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
const moduleFileOldPath = moduleFile.path;
const moduleFileNewPath = "/a/b/moduleFile1.ts";
@@ -787,12 +814,12 @@ namespace ts.tscWatch {
host.runQueuedTimeoutCallbacks();
checkOutputErrors(host, [
getDiagnosticModuleNotFoundOfFile(watch(), file1, "./moduleFile")
]);
], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
moduleFile.path = moduleFileOldPath;
host.reloadFS([moduleFile, file1, libFile]);
host.runQueuedTimeoutCallbacks();
checkOutputErrors(host, emptyArray);
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
});
it("rename a module file and rename back should restore the states for configured projects", () => {
@@ -810,7 +837,7 @@ namespace ts.tscWatch {
};
const host = createWatchedSystem([moduleFile, file1, configFile, libFile]);
const watch = createWatchModeWithConfigFile(configFile.path, host);
checkOutputErrors(host, emptyArray, /*isInitial*/ true);
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
const moduleFileOldPath = moduleFile.path;
const moduleFileNewPath = "/a/b/moduleFile1.ts";
@@ -819,12 +846,12 @@ namespace ts.tscWatch {
host.runQueuedTimeoutCallbacks();
checkOutputErrors(host, [
getDiagnosticModuleNotFoundOfFile(watch(), file1, "./moduleFile")
]);
], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
moduleFile.path = moduleFileOldPath;
host.reloadFS([moduleFile, file1, configFile, libFile]);
host.runQueuedTimeoutCallbacks();
checkOutputErrors(host, emptyArray);
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
});
it("types should load from config file path if config exists", () => {
@@ -863,11 +890,11 @@ namespace ts.tscWatch {
checkOutputErrors(host, [
getDiagnosticModuleNotFoundOfFile(watch(), file1, "./moduleFile")
], /*isInitial*/ true);
], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
host.reloadFS([file1, moduleFile, libFile]);
host.runQueuedTimeoutCallbacks();
checkOutputErrors(host, emptyArray);
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
});
it("Configure file diagnostics events are generated when the config file has errors", () => {
@@ -890,7 +917,7 @@ namespace ts.tscWatch {
checkOutputErrors(host, [
getUnknownCompilerOption(watch(), configFile, "foo"),
getUnknownCompilerOption(watch(), configFile, "allowJS")
], /*isInitial*/ true);
], /*errorsPosition*/ ExpectedOutputErrorsPosition.BeforeCompilationStarts);
});
it("If config file doesnt have errors, they are not reported", () => {
@@ -907,7 +934,7 @@ namespace ts.tscWatch {
const host = createWatchedSystem([file, configFile, libFile]);
createWatchModeWithConfigFile(configFile.path, host);
checkOutputErrors(host, emptyArray, /*isInitial*/ true);
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
});
it("Reports errors when the config file changes", () => {
@@ -924,7 +951,7 @@ namespace ts.tscWatch {
const host = createWatchedSystem([file, configFile, libFile]);
const watch = createWatchModeWithConfigFile(configFile.path, host);
checkOutputErrors(host, emptyArray, /*isInitial*/ true);
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
configFile.content = `{
"compilerOptions": {
@@ -935,14 +962,14 @@ namespace ts.tscWatch {
host.runQueuedTimeoutCallbacks();
checkOutputErrors(host, [
getUnknownCompilerOption(watch(), configFile, "haha")
]);
], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
configFile.content = `{
"compilerOptions": {}
}`;
host.reloadFS([file, configFile, libFile]);
host.runQueuedTimeoutCallbacks();
checkOutputErrors(host, emptyArray);
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
});
it("non-existing directories listed in config file input array should be tolerated without crashing the server", () => {
@@ -1030,13 +1057,13 @@ namespace ts.tscWatch {
getDiagnosticOfFile(watch().getCompilerOptions().configFile, configFile.content.indexOf('"declaration"'), '"declaration"'.length, Diagnostics.Option_0_cannot_be_specified_with_option_1, "allowJs", "declaration")
];
const intialErrors = errors();
checkOutputErrors(host, intialErrors, /*isInitial*/ true);
checkOutputErrors(host, intialErrors, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
configFile.content = configFileContentWithoutCommentLine;
host.reloadFS(files);
host.runQueuedTimeoutCallbacks();
const nowErrors = errors();
checkOutputErrors(host, nowErrors);
checkOutputErrors(host, nowErrors, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
assert.equal(nowErrors[0].start, intialErrors[0].start - configFileContentComment.length);
assert.equal(nowErrors[1].start, intialErrors[1].start - configFileContentComment.length);
});
@@ -1667,7 +1694,7 @@ namespace ts.tscWatch {
const cannotFindFoo = getDiagnosticOfFileFromProgram(watch(), imported.path, imported.content.indexOf("foo"), "foo".length, Diagnostics.Cannot_find_name_0, "foo");
// ensure that imported file was found
checkOutputErrors(host, [f1IsNotModule, cannotFindFoo], /*isInitial*/ true);
checkOutputErrors(host, [f1IsNotModule, cannotFindFoo], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
const originalFileExists = host.fileExists;
{
@@ -1687,7 +1714,7 @@ namespace ts.tscWatch {
f1IsNotModule,
getDiagnosticOfFileFromProgram(watch(), root.path, newContent.indexOf("var x") + "var ".length, "x".length, Diagnostics.Type_0_is_not_assignable_to_type_1, 1, "string"),
cannotFindFoo
]);
], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
}
{
let fileExistsIsCalled = false;
@@ -1709,7 +1736,7 @@ namespace ts.tscWatch {
// ensure file has correct number of errors after edit
checkOutputErrors(host, [
getDiagnosticModuleNotFoundOfFile(watch(), root, "f2")
]);
], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
assert(fileExistsIsCalled);
}
@@ -1730,7 +1757,7 @@ namespace ts.tscWatch {
host.reloadFS(files);
host.runQueuedTimeoutCallbacks();
checkOutputErrors(host, [f1IsNotModule, cannotFindFoo]);
checkOutputErrors(host, [f1IsNotModule, cannotFindFoo], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
assert(fileExistsCalled);
}
});
@@ -1767,15 +1794,15 @@ namespace ts.tscWatch {
assert(fileExistsCalledForBar, "'fileExists' should be called");
checkOutputErrors(host, [
getDiagnosticModuleNotFoundOfFile(watch(), root, "bar")
], /*isInitial*/ true);
], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
fileExistsCalledForBar = false;
root.content = `import {y} from "bar"`;
host.reloadFS(files.concat(imported));
host.runQueuedTimeoutCallbacks();
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
assert(fileExistsCalledForBar, "'fileExists' should be called.");
checkOutputErrors(host, emptyArray);
});
it("should compile correctly when resolved module goes missing and then comes back (module is not part of the root)", () => {
@@ -1807,7 +1834,7 @@ namespace ts.tscWatch {
const watch = createWatchModeWithoutConfigFile([root.path], host, { module: ModuleKind.AMD });
assert(fileExistsCalledForBar, "'fileExists' should be called");
checkOutputErrors(host, emptyArray, /*isInitial*/ true);
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
fileExistsCalledForBar = false;
host.reloadFS(files);
@@ -1815,13 +1842,13 @@ namespace ts.tscWatch {
assert(fileExistsCalledForBar, "'fileExists' should be called.");
checkOutputErrors(host, [
getDiagnosticModuleNotFoundOfFile(watch(), root, "bar")
]);
], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
fileExistsCalledForBar = false;
host.reloadFS(filesWithImported);
host.checkTimeoutQueueLengthAndRun(1);
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
assert(fileExistsCalledForBar, "'fileExists' should be called.");
checkOutputErrors(host, emptyArray);
});
it("works when module resolution changes to ambient module", () => {
@@ -1857,11 +1884,11 @@ declare module "fs" {
checkOutputErrors(host, [
getDiagnosticModuleNotFoundOfFile(watch(), root, "fs")
], /*isInitial*/ true);
], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
host.reloadFS(filesWithNodeType);
host.runQueuedTimeoutCallbacks();
checkOutputErrors(host, emptyArray);
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
});
it("works when included file with ambient module changes", () => {
@@ -1899,12 +1926,12 @@ declare module "fs" {
checkOutputErrors(host, [
getDiagnosticModuleNotFoundOfFile(watch(), root, "fs")
], /*isInitial*/ true);
], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
file.content += fileContentWithFS;
host.reloadFS(files);
host.runQueuedTimeoutCallbacks();
checkOutputErrors(host, emptyArray);
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
});
it("works when reusing program with files from external library", () => {
@@ -1939,7 +1966,7 @@ declare module "fs" {
const host = createWatchedSystem(programFiles.concat(configFile), { currentDirectory: "/a/b/projects/myProject/" });
const watch = createWatchModeWithConfigFile(configFile.path, host);
checkProgramActualFiles(watch(), programFiles.map(f => f.path));
checkOutputErrors(host, emptyArray, /*isInitial*/ true);
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
const expectedFiles: ExpectedFile[] = [
createExpectedEmittedFile(file1),
createExpectedEmittedFile(file2),
@@ -1958,7 +1985,7 @@ declare module "fs" {
host.reloadFS(programFiles.concat(configFile));
host.runQueuedTimeoutCallbacks();
checkProgramActualFiles(watch(), programFiles.map(f => f.path));
checkOutputErrors(host, emptyArray);
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
verifyExpectedFiles(expectedFiles);
@@ -2029,7 +2056,7 @@ declare module "fs" {
});
describe("tsc-watch console clearing", () => {
it("doesn't clear the console when it starts", () => {
it("clears the console when it starts", () => {
const file = {
path: "f.ts",
content: ""
@@ -2039,7 +2066,7 @@ declare module "fs" {
createWatchModeWithoutConfigFile([file.path], host);
host.runQueuedTimeoutCallbacks();
host.checkScreenClears(0);
host.checkScreenClears(1);
});
it("clears the console on recompile", () => {
@@ -2057,7 +2084,7 @@ declare module "fs" {
host.reloadFS([modifiedFile]);
host.runQueuedTimeoutCallbacks();
host.checkScreenClears(1);
host.checkScreenClears(2);
});
});
}