Skip to content

Commit 29dc7b2

Browse files
authored
Merge pull request #28300 from Microsoft/prettyErrorSummary
Report error summary in pretty mode during normal compilation
2 parents eabbaa4 + 77ef9ce commit 29dc7b2

18 files changed

+134
-53
lines changed

src/compiler/commandLineParser.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,13 @@ namespace ts {
104104
category: Diagnostics.Advanced_Options,
105105
description: Diagnostics.Print_names_of_generated_files_part_of_the_compilation
106106
},
107+
{
108+
name: "pretty",
109+
type: "boolean",
110+
showInSimplifiedHelpView: true,
111+
category: Diagnostics.Command_line_Options,
112+
description: Diagnostics.Stylize_errors_and_messages_using_color_and_context_experimental
113+
},
107114

108115
{
109116
name: "traceResolution",
@@ -157,13 +164,6 @@ namespace ts {
157164
category: Diagnostics.Command_line_Options,
158165
description: Diagnostics.Build_one_or_more_projects_and_their_dependencies_if_out_of_date
159166
},
160-
{
161-
name: "pretty",
162-
type: "boolean",
163-
showInSimplifiedHelpView: true,
164-
category: Diagnostics.Command_line_Options,
165-
description: Diagnostics.Stylize_errors_and_messages_using_color_and_context_experimental
166-
},
167167
{
168168
name: "showConfig",
169169
type: "boolean",

src/compiler/diagnosticMessages.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3771,6 +3771,14 @@
37713771
"category": "Message",
37723772
"code": 6215
37733773
},
3774+
"Found 1 error.": {
3775+
"category": "Message",
3776+
"code": 6216
3777+
},
3778+
"Found {0} errors.": {
3779+
"category": "Message",
3780+
"code": 6217
3781+
},
37743782

37753783
"Projects to reference": {
37763784
"category": "Message",

src/compiler/tsbuild.ts

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ namespace ts {
2929
preserveWatchOutput?: boolean;
3030
listEmittedFiles?: boolean;
3131
listFiles?: boolean;
32+
pretty?: boolean;
33+
34+
traceResolution?: boolean;
3235
}
3336

3437
enum BuildResultFlags {
@@ -316,7 +319,7 @@ namespace ts {
316319
return fileExtensionIs(fileName, Extension.Dts);
317320
}
318321

319-
export interface SolutionBuilderHost extends CompilerHost {
322+
export interface SolutionBuilderHostBase extends CompilerHost {
320323
getModifiedTime(fileName: string): Date | undefined;
321324
setModifiedTime(fileName: string, date: Date): void;
322325
deleteFile(fileName: string): void;
@@ -325,13 +328,18 @@ namespace ts {
325328
reportSolutionBuilderStatus: DiagnosticReporter;
326329
}
327330

328-
export interface SolutionBuilderWithWatchHost extends SolutionBuilderHost, WatchHost {
331+
export interface SolutionBuilderHost extends SolutionBuilderHostBase {
332+
reportErrorSummary?: ReportEmitErrorSummary;
333+
}
334+
335+
export interface SolutionBuilderWithWatchHost extends SolutionBuilderHostBase, WatchHost {
329336
}
330337

331338
export interface SolutionBuilder {
332339
buildAllProjects(): ExitStatus;
333340
cleanAllProjects(): ExitStatus;
334341

342+
// TODO:: All the below ones should technically only be in watch mode. but thats for later time
335343
/*@internal*/ resolveProjectName(name: string): ResolvedConfigFileName;
336344
/*@internal*/ getUpToDateStatusOfFile(configFileName: ResolvedConfigFileName): UpToDateStatus;
337345
/*@internal*/ getBuildGraph(configFileNames: ReadonlyArray<string>): DependencyGraph;
@@ -340,7 +348,9 @@ namespace ts {
340348
/*@internal*/ buildInvalidatedProject(): void;
341349

342350
/*@internal*/ resetBuildContext(opts?: BuildOptions): void;
351+
}
343352

353+
export interface SolutionBuilderWithWatch extends SolutionBuilder {
344354
/*@internal*/ startWatching(): void;
345355
}
346356

@@ -355,8 +365,8 @@ namespace ts {
355365
};
356366
}
357367

358-
export function createSolutionBuilderHost(system = sys, reportDiagnostic?: DiagnosticReporter, reportSolutionBuilderStatus?: DiagnosticReporter) {
359-
const host = createCompilerHostWorker({}, /*setParentNodes*/ undefined, system) as SolutionBuilderHost;
368+
function createSolutionBuilderHostBase(system = sys, reportDiagnostic?: DiagnosticReporter, reportSolutionBuilderStatus?: DiagnosticReporter) {
369+
const host = createCompilerHostWorker({}, /*setParentNodes*/ undefined, system) as SolutionBuilderHostBase;
360370
host.getModifiedTime = system.getModifiedTime ? path => system.getModifiedTime!(path) : () => undefined;
361371
host.setModifiedTime = system.setModifiedTime ? (path, date) => system.setModifiedTime!(path, date) : noop;
362372
host.deleteFile = system.deleteFile ? path => system.deleteFile!(path) : noop;
@@ -365,8 +375,14 @@ namespace ts {
365375
return host;
366376
}
367377

368-
export function createSolutionBuilderWithWatchHost(system = sys, reportDiagnostic?: DiagnosticReporter, reportSolutionBuilderStatus?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter) {
369-
const host = createSolutionBuilderHost(system, reportDiagnostic, reportSolutionBuilderStatus) as SolutionBuilderWithWatchHost;
378+
export function createSolutionBuilderHost(system = sys, reportDiagnostic?: DiagnosticReporter, reportSolutionBuilderStatus?: DiagnosticReporter, reportErrorSummary?: ReportEmitErrorSummary) {
379+
const host = createSolutionBuilderHostBase(system, reportDiagnostic, reportSolutionBuilderStatus) as SolutionBuilderHost;
380+
host.reportErrorSummary = reportErrorSummary;
381+
return host;
382+
}
383+
384+
export function createSolutionBuilderWithWatchHost(system?: System, reportDiagnostic?: DiagnosticReporter, reportSolutionBuilderStatus?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter) {
385+
const host = createSolutionBuilderHostBase(system, reportDiagnostic, reportSolutionBuilderStatus) as SolutionBuilderWithWatchHost;
370386
const watchHost = createWatchHost(system, reportWatchStatus);
371387
host.onWatchStatusChange = watchHost.onWatchStatusChange;
372388
host.watchFile = watchHost.watchFile;
@@ -390,7 +406,9 @@ namespace ts {
390406
* TODO: use SolutionBuilderWithWatchHost => watchedSolution
391407
* use SolutionBuilderHost => Solution
392408
*/
393-
export function createSolutionBuilder(host: SolutionBuilderHost, rootNames: ReadonlyArray<string>, defaultOptions: BuildOptions): SolutionBuilder {
409+
export function createSolutionBuilder(host: SolutionBuilderHost, rootNames: ReadonlyArray<string>, defaultOptions: BuildOptions): SolutionBuilder;
410+
export function createSolutionBuilder(host: SolutionBuilderWithWatchHost, rootNames: ReadonlyArray<string>, defaultOptions: BuildOptions): SolutionBuilderWithWatch;
411+
export function createSolutionBuilder(host: SolutionBuilderHost | SolutionBuilderWithWatchHost, rootNames: ReadonlyArray<string>, defaultOptions: BuildOptions): SolutionBuilderWithWatch {
394412
const hostWithWatch = host as SolutionBuilderWithWatchHost;
395413
const currentDirectory = host.getCurrentDirectory();
396414
const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames());
@@ -803,9 +821,7 @@ namespace ts {
803821
globalDependencyGraph = undefined;
804822
}
805823
projectStatus.removeKey(resolved);
806-
if (options.watch) {
807-
diagnostics.removeKey(resolved);
808-
}
824+
diagnostics.removeKey(resolved);
809825

810826
addProjToQueue(resolved, reloadLevel);
811827
}
@@ -874,16 +890,21 @@ namespace ts {
874890
}
875891

876892
function reportErrorSummary() {
877-
if (options.watch) {
893+
if (options.watch || (host as SolutionBuilderHost).reportErrorSummary) {
878894
// Report errors from the other projects
879895
getGlobalDependencyGraph().buildQueue.forEach(project => {
880896
if (!projectErrorsReported.hasKey(project)) {
881897
reportErrors(diagnostics.getValue(project) || emptyArray);
882898
}
883899
});
884900
let totalErrors = 0;
885-
diagnostics.forEach(singleProjectErrors => totalErrors += singleProjectErrors.filter(diagnostic => diagnostic.category === DiagnosticCategory.Error).length);
886-
reportWatchStatus(totalErrors === 1 ? Diagnostics.Found_1_error_Watching_for_file_changes : Diagnostics.Found_0_errors_Watching_for_file_changes, totalErrors);
901+
diagnostics.forEach(singleProjectErrors => totalErrors += getErrorCountForSummary(singleProjectErrors));
902+
if (options.watch) {
903+
reportWatchStatus(getWatchErrorSummaryDiagnosticMessage(totalErrors), totalErrors);
904+
}
905+
else {
906+
(host as SolutionBuilderHost).reportErrorSummary!(totalErrors);
907+
}
887908
}
888909
}
889910

@@ -1066,9 +1087,7 @@ namespace ts {
10661087
type: UpToDateStatusType.UpToDate,
10671088
newestDeclarationFileContentChangedTime: anyDtsChanged ? maximumDate : newestDeclarationFileContentChangedTime
10681089
};
1069-
if (options.watch) {
1070-
diagnostics.removeKey(proj);
1071-
}
1090+
diagnostics.removeKey(proj);
10721091
projectStatus.setValue(proj, status);
10731092
return resultFlags;
10741093

@@ -1207,10 +1226,8 @@ namespace ts {
12071226

12081227
function reportAndStoreErrors(proj: ResolvedConfigFileName, errors: ReadonlyArray<Diagnostic>) {
12091228
reportErrors(errors);
1210-
if (options.watch) {
1211-
projectErrorsReported.setValue(proj, true);
1212-
diagnostics.setValue(proj, errors);
1213-
}
1229+
projectErrorsReported.setValue(proj, true);
1230+
diagnostics.setValue(proj, errors);
12141231
}
12151232

12161233
function reportErrors(errors: ReadonlyArray<Diagnostic>) {

src/compiler/watch.ts

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,21 @@ namespace ts {
106106

107107
export type ReportEmitErrorSummary = (errorCount: number) => void;
108108

109+
export function getErrorCountForSummary(diagnostics: ReadonlyArray<Diagnostic>) {
110+
return countWhere(diagnostics, diagnostic => diagnostic.category === DiagnosticCategory.Error);
111+
}
112+
113+
export function getWatchErrorSummaryDiagnosticMessage(errorCount: number) {
114+
return errorCount === 1 ?
115+
Diagnostics.Found_1_error_Watching_for_file_changes :
116+
Diagnostics.Found_0_errors_Watching_for_file_changes;
117+
}
118+
119+
export function getErrorSummaryText(errorCount: number, newLine: string) {
120+
const d = createCompilerDiagnostic(errorCount === 1 ? Diagnostics.Found_1_error : Diagnostics.Found_0_errors, errorCount);
121+
return `${newLine}${flattenDiagnosticMessageText(d.messageText, newLine)}${newLine}${newLine}`;
122+
}
123+
109124
/**
110125
* Helper that emit files, report diagnostics and lists emitted and/or source files depending on compiler options
111126
*/
@@ -151,7 +166,7 @@ namespace ts {
151166
}
152167

153168
if (reportSummary) {
154-
reportSummary(diagnostics.filter(diagnostic => diagnostic.category === DiagnosticCategory.Error).length);
169+
reportSummary(getErrorCountForSummary(diagnostics));
155170
}
156171

157172
if (emitSkipped && diagnostics.length > 0) {
@@ -227,16 +242,16 @@ namespace ts {
227242
const compilerOptions = builderProgram.getCompilerOptions();
228243
const newLine = getNewLineCharacter(compilerOptions, () => system.newLine);
229244

230-
const reportSummary = (errorCount: number) => {
231-
if (errorCount === 1) {
232-
onWatchStatusChange!(createCompilerDiagnostic(Diagnostics.Found_1_error_Watching_for_file_changes, errorCount), newLine, compilerOptions);
233-
}
234-
else {
235-
onWatchStatusChange!(createCompilerDiagnostic(Diagnostics.Found_0_errors_Watching_for_file_changes, errorCount, errorCount), newLine, compilerOptions);
236-
}
237-
};
238-
239-
emitFilesAndReportErrors(builderProgram, reportDiagnostic, writeFileName, reportSummary);
245+
emitFilesAndReportErrors(
246+
builderProgram,
247+
reportDiagnostic,
248+
writeFileName,
249+
errorCount => onWatchStatusChange!(
250+
createCompilerDiagnostic(getWatchErrorSummaryDiagnosticMessage(errorCount), errorCount),
251+
newLine,
252+
compilerOptions
253+
)
254+
);
240255
}
241256
}
242257

src/harness/harness.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1325,6 +1325,9 @@ namespace Harness {
13251325
const [, content] = value;
13261326
outputLines += content;
13271327
}
1328+
if (pretty) {
1329+
outputLines += ts.getErrorSummaryText(ts.getErrorCountForSummary(diagnostics), IO.newLine());
1330+
}
13281331
return outputLines;
13291332
}
13301333

src/tsc/tsc.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -200,19 +200,28 @@ namespace ts {
200200
}
201201

202202
// TODO: change this to host if watch => watchHost otherwiue without wathc
203-
const builder = createSolutionBuilder(createSolutionBuilderWithWatchHost(sys, reportDiagnostic, createBuilderStatusReporter(sys, shouldBePretty()), createWatchStatusReporter()), projects, buildOptions);
203+
const builder = createSolutionBuilder(buildOptions.watch ?
204+
createSolutionBuilderWithWatchHost(sys, reportDiagnostic, createBuilderStatusReporter(sys, shouldBePretty()), createWatchStatusReporter()) :
205+
createSolutionBuilderHost(sys, reportDiagnostic, createBuilderStatusReporter(sys, shouldBePretty()), createReportErrorSummary(buildOptions)),
206+
projects, buildOptions);
204207
if (buildOptions.clean) {
205208
return sys.exit(builder.cleanAllProjects());
206209
}
207210

208211
if (buildOptions.watch) {
209212
builder.buildAllProjects();
210-
return builder.startWatching();
213+
return (builder as SolutionBuilderWithWatch).startWatching();
211214
}
212215

213216
return sys.exit(builder.buildAllProjects());
214217
}
215218

219+
function createReportErrorSummary(options: CompilerOptions | BuildOptions): ReportEmitErrorSummary | undefined {
220+
return shouldBePretty(options) ?
221+
errorCount => sys.write(getErrorSummaryText(errorCount, sys.newLine)) :
222+
undefined;
223+
}
224+
216225
function performCompilation(rootNames: string[], projectReferences: ReadonlyArray<ProjectReference> | undefined, options: CompilerOptions, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>) {
217226
const host = createCompilerHost(options);
218227
enableStatistics(options);
@@ -225,7 +234,12 @@ namespace ts {
225234
configFileParsingDiagnostics
226235
};
227236
const program = createProgram(programOptions);
228-
const exitStatus = emitFilesAndReportErrors(program, reportDiagnostic, s => sys.write(s + sys.newLine));
237+
const exitStatus = emitFilesAndReportErrors(
238+
program,
239+
reportDiagnostic,
240+
s => sys.write(s + sys.newLine),
241+
createReportErrorSummary(options)
242+
);
229243
reportStatistics(program);
230244
return sys.exit(exitStatus);
231245
}

tests/baselines/reference/deeplyNestedAssignabilityIssue.errors.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,6 @@
5858
}
5959
}
6060
}
61-
61+
62+
Found 2 errors.
63+

tests/baselines/reference/duplicateIdentifierRelatedSpans1.errors.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,6 @@
9191
~~~
9292
!!! error TS2451: Cannot redeclare block-scoped variable 'Bar'.
9393
!!! related TS6203 tests/cases/compiler/file1.ts:2:7: 'Bar' was also declared here.
94-
94+
95+
Found 6 errors.
96+

tests/baselines/reference/duplicateIdentifierRelatedSpans2.errors.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,6 @@
4444
class G { }
4545
class H { }
4646
class I { }
47-
47+
48+
Found 2 errors.
49+

tests/baselines/reference/duplicateIdentifierRelatedSpans3.errors.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,4 +84,6 @@
8484
!!! error TS2300: Duplicate identifier 'duplicate3'.
8585
!!! related TS6203 tests/cases/compiler/file1.ts:4:5: 'duplicate3' was also declared here.
8686
}
87-
87+
88+
Found 6 errors.
89+

0 commit comments

Comments
 (0)