UNPKG

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