Added an errors summary for --pretty --watch results

Reports a "Found X error(s) across Y file(s)." message on each recompile if in both pretty and watch modes.
This commit intentionally doesn't include tests as I have a few questions about implementation details. Will ask in PR first.
This commit is contained in:
Josh Goldberg
2018-02-28 15:16:44 -08:00
parent b31aa4e012
commit e0d067b48f
3 changed files with 78 additions and 9 deletions

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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<boolean>();
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);
}
}
}