Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/build/lib/reporter.ts
5256 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import es from 'event-stream';
7
import fancyLog from 'fancy-log';
8
import ansiColors from 'ansi-colors';
9
import fs from 'fs';
10
import path from 'path';
11
12
class ErrorLog {
13
public id: string;
14
15
constructor(id: string) {
16
this.id = id;
17
}
18
allErrors: string[][] = [];
19
startTime: number | null = null;
20
count = 0;
21
22
onStart(): void {
23
if (this.count++ > 0) {
24
return;
25
}
26
27
this.startTime = new Date().getTime();
28
fancyLog(`Starting ${ansiColors.green('compilation')}${this.id ? ansiColors.blue(` ${this.id}`) : ''}...`);
29
}
30
31
onEnd(): void {
32
if (--this.count > 0) {
33
return;
34
}
35
36
this.log();
37
}
38
39
log(): void {
40
const errors = this.allErrors.flat();
41
const seen = new Set<string>();
42
43
errors.map(err => {
44
if (!seen.has(err)) {
45
seen.add(err);
46
fancyLog(`${ansiColors.red('Error')}: ${err}`);
47
}
48
});
49
50
fancyLog(`Finished ${ansiColors.green('compilation')}${this.id ? ansiColors.blue(` ${this.id}`) : ''} with ${errors.length} errors after ${ansiColors.magenta((new Date().getTime() - this.startTime!) + ' ms')}`);
51
52
const regex = /^([^(]+)\((\d+),(\d+)\): (.*)$/s;
53
const messages = errors
54
.map(err => regex.exec(err))
55
.filter(match => !!match)
56
.map(x => x as string[])
57
.map(([, path, line, column, message]) => ({ path, line: parseInt(line), column: parseInt(column), message }));
58
59
try {
60
const logFileName = 'log' + (this.id ? `_${this.id}` : '');
61
fs.writeFileSync(path.join(buildLogFolder, logFileName), JSON.stringify(messages));
62
} catch (err) {
63
//noop
64
}
65
}
66
67
}
68
69
const errorLogsById = new Map<string, ErrorLog>();
70
function getErrorLog(id: string = '') {
71
let errorLog = errorLogsById.get(id);
72
if (!errorLog) {
73
errorLog = new ErrorLog(id);
74
errorLogsById.set(id, errorLog);
75
}
76
return errorLog;
77
}
78
79
const buildLogFolder = path.join(path.dirname(path.dirname(import.meta.dirname)), '.build');
80
81
try {
82
fs.mkdirSync(buildLogFolder);
83
} catch (err) {
84
// ignore
85
}
86
87
export interface IReporter {
88
(err: string): void;
89
hasErrors(): boolean;
90
end(emitError: boolean): NodeJS.ReadWriteStream;
91
}
92
93
class ReporterError extends Error {
94
__reporter__ = true;
95
}
96
97
interface Errors extends Array<string> {
98
__logged__?: boolean;
99
}
100
101
export function createReporter(id?: string): IReporter {
102
const errorLog = getErrorLog(id);
103
104
const errors: Errors = [];
105
errorLog.allErrors.push(errors);
106
107
const result = (err: string) => errors.push(err);
108
109
result.hasErrors = () => errors.length > 0;
110
111
result.end = (emitError: boolean): NodeJS.ReadWriteStream => {
112
errors.length = 0;
113
errorLog.onStart();
114
115
return es.through(undefined, function () {
116
errorLog.onEnd();
117
118
if (emitError && errors.length > 0) {
119
if (!errors.__logged__) {
120
errorLog.log();
121
}
122
123
errors.__logged__ = true;
124
125
const err = new ReporterError(`Found ${errors.length} errors`);
126
this.emit('error', err);
127
} else {
128
this.emit('end');
129
}
130
});
131
};
132
133
return result;
134
}
135
136