diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 0bf047c770d..ffb4fd95812 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3516,6 +3516,14 @@ "category": "Error", "code": 6192 }, + "Found 1 error.": { + "category": "Message", + "code": 6193 + }, + "Found {0} errors.": { + "category": "Message", + "code": 6194 + }, "Variable '{0}' implicitly has an '{1}' type.": { "category": "Error", "code": 7005 diff --git a/src/compiler/watch.ts b/src/compiler/watch.ts index ed5276e49a4..f53f01e3eb2 100644 --- a/src/compiler/watch.ts +++ b/src/compiler/watch.ts @@ -31,12 +31,19 @@ namespace ts { }; } + /** @internal */ + export const nonClearingMessageCodes: number[] = [ + Diagnostics.Compilation_complete_Watching_for_file_changes.code, + Diagnostics.Found_1_error.code, + Diagnostics.Found_0_errors.code + ]; + function clearScreenIfNotWatchingForFileChanges(system: System, diagnostic: Diagnostic, options: CompilerOptions) { if (system.clearScreen && !options.preserveWatchOutput && - diagnostic.code !== Diagnostics.Compilation_complete_Watching_for_file_changes.code && !options.extendedDiagnostics && - !options.diagnostics) { + !options.diagnostics && + !contains(nonClearingMessageCodes, diagnostic.code)) { system.clearScreen(); } } @@ -115,10 +122,12 @@ namespace ts { emit(): EmitResult; } + export type ReportEmitErrorSummary = (errorCount: number) => void; + /** * Helper that emit files, report diagnostics and lists emitted and/or source files depending on compiler options */ - export function emitFilesAndReportErrors(program: ProgramToEmitFilesAndReportErrors, reportDiagnostic: DiagnosticReporter, writeFileName?: (s: string) => void) { + export function emitFilesAndReportErrors(program: ProgramToEmitFilesAndReportErrors, reportDiagnostic: DiagnosticReporter, writeFileName?: (s: string) => void, reportSummary?: ReportEmitErrorSummary) { // First get and report any syntactic errors. const diagnostics = program.getConfigFileParsingDiagnostics().slice(); const configFileParsingDiagnosticsLength = diagnostics.length; @@ -159,6 +168,10 @@ namespace ts { } } + if (reportSummary) { + reportSummary(diagnostics.filter(diagnostic => diagnostic.category === DiagnosticCategory.Error).length); + } + if (emitSkipped && diagnostics.length > 0) { // If the emitter didn't emit anything, then pass that value along. return ExitStatus.DiagnosticsPresent_OutputsSkipped; @@ -184,6 +197,7 @@ namespace ts { let host: DirectoryStructureHost = system; const useCaseSensitiveFileNames = () => system.useCaseSensitiveFileNames; const writeFileName = (s: string) => system.write(s + system.newLine); + const onWatchStatusChange = reportWatchStatus || createWatchStatusReporter(system); return { useCaseSensitiveFileNames, getNewLine: () => system.newLine, @@ -202,7 +216,7 @@ namespace ts { setTimeout: system.setTimeout ? ((callback, ms, ...args: any[]) => system.setTimeout.call(system, callback, ms, ...args)) : noop, clearTimeout: system.clearTimeout ? (timeoutId => system.clearTimeout(timeoutId)) : noop, trace: s => system.write(s), - onWatchStatusChange: reportWatchStatus || createWatchStatusReporter(system), + onWatchStatusChange, createDirectory: path => system.createDirectory(path), writeFile: (path, data, writeByteOrderMark) => system.writeFile(path, data, writeByteOrderMark), onCachedDirectoryStructureHostCreate: cacheHost => host = cacheHost || system, @@ -216,7 +230,19 @@ namespace ts { } function emitFilesAndReportErrorUsingBuilder(builderProgram: BuilderProgram) { - emitFilesAndReportErrors(builderProgram, reportDiagnostic, writeFileName); + const compilerOptions = builderProgram.getCompilerOptions(); + const newLine = getNewLineCharacter(compilerOptions, () => system.newLine); + + const reportSummary = (errorCount: number) => { + if (errorCount === 1) { + onWatchStatusChange(createCompilerDiagnostic(Diagnostics.Found_1_error, errorCount), newLine, compilerOptions); + } + else { + onWatchStatusChange(createCompilerDiagnostic(Diagnostics.Found_0_errors, errorCount, errorCount), newLine, compilerOptions); + } + }; + + emitFilesAndReportErrors(builderProgram, reportDiagnostic, writeFileName, reportSummary); } } diff --git a/src/harness/unittests/tscWatchMode.ts b/src/harness/unittests/tscWatchMode.ts index f9bb0612f41..99bad3e3091 100644 --- a/src/harness/unittests/tscWatchMode.ts +++ b/src/harness/unittests/tscWatchMode.ts @@ -76,11 +76,11 @@ namespace ts.tscWatch { function checkOutputErrors( host: WatchedSystem, logsBeforeWatchDiagnostic: string[] | undefined, - preErrorsWatchDiagnostic: DiagnosticMessage, + preErrorsWatchDiagnostic: Diagnostic, logsBeforeErrors: string[] | undefined, errors: ReadonlyArray, disableConsoleClears?: boolean | undefined, - ...postErrorsWatchDiagnostics: DiagnosticMessage[] + ...postErrorsWatchDiagnostics: Diagnostic[] ) { let screenClears = 0; const outputs = host.getOutput(); @@ -109,9 +109,9 @@ namespace ts.tscWatch { index++; } - function assertWatchDiagnostic(diagnosticMessage: DiagnosticMessage) { - const expected = getWatchDiagnosticWithoutDate(diagnosticMessage); - if (!disableConsoleClears && diagnosticMessage.code !== Diagnostics.Compilation_complete_Watching_for_file_changes.code) { + function assertWatchDiagnostic(diagnostic: Diagnostic) { + const expected = getWatchDiagnosticWithoutDate(diagnostic); + if (!disableConsoleClears && !contains(nonClearingMessageCodes, diagnostic.code)) { assert.equal(host.screenClears[screenClears], index, `Expected screen clear at this diagnostic: ${expected}`); screenClears++; } @@ -120,24 +120,52 @@ namespace ts.tscWatch { } function getOutputAtFailedMessage(caption: string, expectedOutput: string) { - return `Expected ${caption}: ${expectedOutput} at ${index} in ${JSON.stringify(outputs)}`; + return `Expected ${caption}: ${JSON.stringify(expectedOutput)} at ${index} in ${JSON.stringify(outputs)}`; } - function getWatchDiagnosticWithoutDate(diagnosticMessage: DiagnosticMessage) { - return ` - ${flattenDiagnosticMessageText(getLocaleSpecificMessage(diagnosticMessage), host.newLine)}${host.newLine + host.newLine + host.newLine}`; + function getWatchDiagnosticWithoutDate(diagnostic: Diagnostic) { + return ` - ${flattenDiagnosticMessageText(diagnostic.messageText, host.newLine)}${host.newLine + host.newLine + host.newLine}`; } } + function createErrorsFoundCompilerDiagnostic(errors: ReadonlyArray) { + return errors.length === 1 + ? createCompilerDiagnostic(Diagnostics.Found_1_error) + : createCompilerDiagnostic(Diagnostics.Found_0_errors, errors.length); + } + function checkOutputErrorsInitial(host: WatchedSystem, errors: ReadonlyArray, disableConsoleClears?: boolean, logsBeforeErrors?: string[]) { - checkOutputErrors(host, /*logsBeforeWatchDiagnostic*/ undefined, Diagnostics.Starting_compilation_in_watch_mode, logsBeforeErrors, errors, disableConsoleClears, Diagnostics.Compilation_complete_Watching_for_file_changes); + checkOutputErrors( + host, + /*logsBeforeWatchDiagnostic*/ undefined, + createCompilerDiagnostic(Diagnostics.Starting_compilation_in_watch_mode), + logsBeforeErrors, + errors, + disableConsoleClears, + createErrorsFoundCompilerDiagnostic(errors), + createCompilerDiagnostic(Diagnostics.Compilation_complete_Watching_for_file_changes)); } function checkOutputErrorsIncremental(host: WatchedSystem, errors: ReadonlyArray, disableConsoleClears?: boolean, logsBeforeWatchDiagnostic?: string[], logsBeforeErrors?: string[]) { - checkOutputErrors(host, logsBeforeWatchDiagnostic, Diagnostics.File_change_detected_Starting_incremental_compilation, logsBeforeErrors, errors, disableConsoleClears, Diagnostics.Compilation_complete_Watching_for_file_changes); + checkOutputErrors( + host, + logsBeforeWatchDiagnostic, + createCompilerDiagnostic(Diagnostics.File_change_detected_Starting_incremental_compilation), + logsBeforeErrors, + errors, + disableConsoleClears, + createErrorsFoundCompilerDiagnostic(errors), + createCompilerDiagnostic(Diagnostics.Compilation_complete_Watching_for_file_changes)); } function checkOutputErrorsIncrementalWithExit(host: WatchedSystem, errors: ReadonlyArray, expectedExitCode: ExitStatus, disableConsoleClears?: boolean, logsBeforeWatchDiagnostic?: string[], logsBeforeErrors?: string[]) { - checkOutputErrors(host, logsBeforeWatchDiagnostic, Diagnostics.File_change_detected_Starting_incremental_compilation, logsBeforeErrors, errors, disableConsoleClears); + checkOutputErrors( + host, + logsBeforeWatchDiagnostic, + createCompilerDiagnostic(Diagnostics.File_change_detected_Starting_incremental_compilation), + logsBeforeErrors, + errors, + disableConsoleClears); assert.equal(host.exitCode, expectedExitCode); }