Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added console clearing with a message to --watch starts #20427

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 7 additions & 1 deletion src/compiler/watch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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));
Expand Down
113 changes: 70 additions & 43 deletions src/harness/unittests/tscWatchMode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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", () => {
Expand Down Expand Up @@ -667,15 +694,15 @@ 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);

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", () => {
Expand Down Expand Up @@ -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";
Expand All @@ -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", () => {
Expand All @@ -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";
Expand All @@ -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", () => {
Expand Down Expand Up @@ -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", () => {
Expand All @@ -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", () => {
Expand All @@ -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", () => {
Expand All @@ -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": {
Expand All @@ -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", () => {
Expand Down Expand Up @@ -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);
});
Expand Down Expand Up @@ -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;
{
Expand All @@ -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;
Expand All @@ -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);
}
Expand All @@ -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);
}
});
Expand Down Expand Up @@ -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)", () => {
Expand Down Expand Up @@ -1807,21 +1834,21 @@ 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);
host.runQueuedTimeoutCallbacks();
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", () => {
Expand Down Expand Up @@ -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", () => {
Expand Down Expand Up @@ -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", () => {
Expand Down Expand Up @@ -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),
Expand All @@ -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);


Expand Down Expand Up @@ -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: ""
Expand All @@ -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", () => {
Expand All @@ -2057,7 +2084,7 @@ declare module "fs" {
host.reloadFS([modifiedFile]);
host.runQueuedTimeoutCallbacks();

host.checkScreenClears(1);
host.checkScreenClears(2);
});
});
}