vite-esbuild-typescript-checker
Version:
* Speeds up [TypeScript](https://github.com/Microsoft/TypeScript) type checking * Supports [Vue Single File Component](https://vuejs.org/v2/guide/single-file-components.html) * Displays nice error messages with the [code frame](https://babeljs.io/docs/en/
139 lines (138 loc) • 5.28 kB
JavaScript
import path from 'path';
import ts from 'typescript';
export class Reporter {
basedir;
postMessage;
start;
constructor(basedir, postMessage = ()=>{}){
this.basedir = basedir;
this.postMessage = postMessage;
this.start = Date.now();
this.reportBuildStart = ({ build = false, watch = false } = {})=>{
this.postMessage({
type: 'start',
build,
watch
});
};
this.reportBuildDone = (errorCount)=>{
this.postMessage({
type: 'done',
errorCount,
duration: Date.now() - this.start
});
};
this.reportDiagnostic = (diagnostic)=>{
this.reportDiagnostics([
diagnostic
]);
};
this.reportDiagnostics = (diagnostics)=>{
this.postMessage({
type: 'diagnostic',
diagnostics: Array.from(Reporter.transformDiagnostics(this.basedir, diagnostics)),
output: Reporter.getOutput(diagnostics)
});
};
this.reportSummaryDiagnostic = (diagnostic)=>{
switch(diagnostic.code){
case 6193:
case 6194:
if (typeof diagnostic.messageText === 'string') {
const errorCount = Reporter.extractErrorCount(diagnostic.messageText);
this.reportBuildDone(errorCount);
break;
}
case 6032:
this.reportBuildStart();
this.markBuildStart(); // If the watcher decides to start on its own, we need to record the start time
break;
case 6031:
return; // Don't log these
default:
this.postMessage({
type: 'summary',
diagnostics: Array.from(Reporter.transformDiagnostics(this.basedir, [
diagnostic
])),
output: Reporter.getOutput([
diagnostic
])
});
break;
}
};
}
markBuildStart() {
this.start = Date.now();
}
reportBuildStart;
reportBuildDone;
reportDiagnostic;
reportDiagnostics;
reportSummaryDiagnostic;
static formatHost = {
getCanonicalFileName: (path)=>path,
getCurrentDirectory: ts.sys.getCurrentDirectory,
getNewLine: ()=>ts.sys.newLine
};
static extractErrorCount(msg) {
const match = /Found (\d+) errors?/.exec(msg);
return match ? Number(match[1]) : 0;
}
static getOutput(diagnostics) {
return {
pretty: ts.formatDiagnosticsWithColorAndContext(diagnostics, Reporter.formatHost),
standard: ts.formatDiagnostics(diagnostics, Reporter.formatHost)
};
}
static *transformDiagnostics(basedir, diagnostics) {
for (const diagnostic of diagnostics){
const type = diagnostic.category === ts.DiagnosticCategory.Error ? 'error' : diagnostic.category === ts.DiagnosticCategory.Warning ? 'warning' : undefined;
if (!type) continue;
const { file, length, messageText, start } = diagnostic;
if (!file) continue;
if (typeof messageText !== 'string') continue;
if (start === undefined || length === undefined) {
yield {
type,
message: {
id: `TS${diagnostic.code}`,
detail: diagnostic.relatedInformation,
location: null,
notes: [],
pluginName: 'esbuild-plugin-typecheck',
text: messageText
}
};
continue;
}
const { line, character } = ts.getLineAndCharacterOfPosition(file, start);
const lastLineInFile = ts.getLineAndCharacterOfPosition(file, file.text.length).line;
const lineStart = ts.getPositionOfLineAndCharacter(file, line, 0);
const lineEnd = line < lastLineInFile ? ts.getPositionOfLineAndCharacter(file, line + 1, 0) : file.text.length;
const lineText = file.text.slice(lineStart, lineEnd).trimEnd();
const safeLength = character + length > lineEnd - lineStart ? lineEnd - lineStart - character : length;
const message = {
id: `TS${diagnostic.code}`,
detail: undefined,
location: {
column: character,
file: path.relative(basedir, file.fileName),
length: safeLength,
line,
lineText,
namespace: '',
suggestion: ''
},
pluginName: 'esbuild-plugin-typecheck',
notes: [],
text: messageText
};
yield {
type,
message
};
}
}
}