diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 9801da54a5f..edb2917f7eb 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3472,6 +3472,18 @@ "category": "Message", "code": 6190 }, + "Found 1 error in 1 file.": { + "category": "Message", + "code": 6191 + }, + "Found {0} errors in 1 file.": { + "category": "Message", + "code": 6192 + }, + "Found {0} errors in {1} files.": { + "category": "Message", + "code": 6193 + }, "Variable '{0}' implicitly has an '{1}' type.": { "category": "Error", "code": 7005 diff --git a/src/compiler/tsc.ts b/src/compiler/tsc.ts index 15e4867d7f7..2b0008f19c6 100644 --- a/src/compiler/tsc.ts +++ b/src/compiler/tsc.ts @@ -144,7 +144,8 @@ namespace ts { enableStatistics(compilerOptions); const program = createProgram(rootFileNames, compilerOptions, compilerHost); - const exitStatus = emitFilesAndReportErrors(program, reportDiagnostic, s => sys.write(s + sys.newLine)); + const diagnosticsAndEmit = getProgramDiagnosticsAndEmit(program); + const exitStatus = reportDiagnosticErrors(program, diagnosticsAndEmit, reportDiagnostic, s => sys.write(s + sys.newLine)); reportStatistics(program); return sys.exit(exitStatus); } diff --git a/src/compiler/watch.ts b/src/compiler/watch.ts index ff21c750089..138ac628e6d 100644 --- a/src/compiler/watch.ts +++ b/src/compiler/watch.ts @@ -31,11 +31,18 @@ namespace ts { }; } + const nonClearingMessageCodes: number[] = [ + Diagnostics.Compilation_complete_Watching_for_file_changes.code, + Diagnostics.Found_1_error_in_1_file.code, + Diagnostics.Found_0_errors_in_1_file.code, + Diagnostics.Found_0_errors_in_1_files.code, + ]; + function clearScreenIfNotWatchingForFileChanges(system: System, diagnostic: Diagnostic, options: CompilerOptions) { if (system.clearScreen && - diagnostic.code !== Diagnostics.Compilation_complete_Watching_for_file_changes.code && !options.extendedDiagnostics && - !options.diagnostics) { + !options.diagnostics && + !contains(nonClearingMessageCodes, diagnostic.code)) { system.clearScreen(); } } @@ -120,10 +127,15 @@ namespace ts { emit(): EmitResult; } - /** - * 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) { + /** @internal */ + export interface ProgramDiagnosticsAndEmit { + diagnostics: Diagnostic[]; + emittedFiles: string[]; + emitSkipped: boolean; + } + + /** @internal */ + export function getProgramDiagnosticsAndEmit(program: ProgramToEmitFilesAndReportErrors): ProgramDiagnosticsAndEmit { // First get and report any syntactic errors. const diagnostics = program.getSyntacticDiagnostics().slice(); let reportSemanticDiagnostics = false; @@ -147,6 +159,15 @@ namespace ts { addRange(diagnostics, program.getSemanticDiagnostics()); } + return { diagnostics, emittedFiles, emitSkipped }; + } + + /** + * Helper that emit files, report diagnostics and lists emitted and/or source files depending on compiler options + */ + export function reportDiagnosticErrors(program: ProgramToEmitFilesAndReportErrors, diagnosticsAndEmit: ProgramDiagnosticsAndEmit, reportDiagnostic: DiagnosticReporter, writeFileName?: (s: string) => void) { + const { diagnostics, emittedFiles, emitSkipped } = diagnosticsAndEmit; + sortAndDeduplicateDiagnostics(diagnostics).forEach(reportDiagnostic); if (writeFileName) { const currentDir = program.getCurrentDirectory(); @@ -174,6 +195,34 @@ namespace ts { return ExitStatus.Success; } + function summarizeDiagnosticsAcrossFiles(diagnostics: Diagnostic[], reporter: WatchStatusReporter, newLine: string, compilerOptions: CompilerOptions): void { + if (diagnostics.length === 1) { + reporter(createCompilerDiagnostic(Diagnostics.Found_1_error_in_1_file), newLine, compilerOptions); + return; + } + + const uniqueFileNamesCount = countUniqueDiagnosticFileNames(diagnostics); + + if (uniqueFileNamesCount === 1) { + reporter(createCompilerDiagnostic(Diagnostics.Found_0_errors_in_1_file, diagnostics.length), newLine, compilerOptions); + } + else if (uniqueFileNamesCount !== 0) { + reporter(createCompilerDiagnostic(Diagnostics.Found_0_errors_in_1_files, diagnostics.length, uniqueFileNamesCount), newLine, compilerOptions); + } + } + + function countUniqueDiagnosticFileNames(diagnostics: Diagnostic[]): number { + const fileNames = createMap(); + + for (const diagnostic of diagnostics) { + if (diagnostic.file) { + fileNames.set(diagnostic.file.fileName, true); + } + } + + return fileNames.size; + } + const noopFileWatcher: FileWatcher = { close: noop }; /** @@ -187,6 +236,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, @@ -205,7 +255,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, @@ -219,7 +269,13 @@ namespace ts { } function emitFilesAndReportErrorUsingBuilder(builderProgram: BuilderProgram) { - emitFilesAndReportErrors(builderProgram, reportDiagnostic, writeFileName); + const diagnosticsAndEmit = getProgramDiagnosticsAndEmit(builderProgram); + reportDiagnosticErrors(builderProgram, diagnosticsAndEmit, reportDiagnostic, writeFileName); + + const compilerOptions = builderProgram.getCompilerOptions(); + if (compilerOptions.pretty) { + summarizeDiagnosticsAcrossFiles(diagnosticsAndEmit.diagnostics, onWatchStatusChange, system.newLine, compilerOptions); + } } }