UNPKG

vite-esbuild-typescript-checker

Version:
222 lines (189 loc) 10.3 kB
import { workerData, parentPort } from 'worker_threads'; import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'; import { composeReporterRpcClients, createAggregatedReporter, FilesChange, FilesMatch, Report, ReporterRpcClient } from "fork-ts-checker-webpack-plugin/lib/reporter"; import { createEsLintReporterRpcClient } from "fork-ts-checker-webpack-plugin/lib/eslint-reporter/reporter/EsLintReporterRpcClient"; import { assertEsLintSupport } from "fork-ts-checker-webpack-plugin/lib/eslint-reporter/assertEsLintSupport"; import { createTypeScriptReporterRpcClient } from "fork-ts-checker-webpack-plugin/lib/typescript-reporter/reporter/TypeScriptReporterRpcClient"; import { assertTypeScriptSupport } from "fork-ts-checker-webpack-plugin/lib/typescript-reporter/TypeScriptSupport"; import { createForkTsCheckerWebpackPluginState, ForkTsCheckerWebpackPluginState } from "fork-ts-checker-webpack-plugin/lib/ForkTsCheckerWebpackPluginState"; import { ForkTsCheckerWebpackPluginConfiguration } from "fork-ts-checker-webpack-plugin/lib/ForkTsCheckerWebpackPluginConfiguration"; import { ForkTsCheckerWebpackPluginOptions } from "fork-ts-checker-webpack-plugin/lib/ForkTsCheckerWebpackPluginOptions"; import { createTypeScriptReporterConfiguration } from "fork-ts-checker-webpack-plugin/lib/typescript-reporter/TypeScriptReporterConfiguration"; import { createEsLintReporterConfiguration } from "fork-ts-checker-webpack-plugin/lib/eslint-reporter/EsLintReporterConfiguration"; import { createFormatterConfiguration } from "fork-ts-checker-webpack-plugin/lib/formatter"; import { createIssueConfiguration } from "fork-ts-checker-webpack-plugin/lib/issue/IssueConfiguration"; import { createLoggerConfiguration } from "fork-ts-checker-webpack-plugin/lib/logger/LoggerConfiguration"; import { Issue } from "fork-ts-checker-webpack-plugin/lib/issue"; import isPending from "fork-ts-checker-webpack-plugin/lib/utils/async/isPending"; import wait from "fork-ts-checker-webpack-plugin/lib/utils/async/wait"; import chalk from "chalk"; import moment from "moment"; export interface IssueCustom extends Issue { formatted?: string | undefined; formattedColor?: string | undefined; } export interface ForkTsCheckerWebpackPluginStateCustom extends ForkTsCheckerWebpackPluginState { reportPromise: Promise<Report | undefined>; } const config = Object.assign({}, { async: true as boolean, typescript: { configFile: `./tsconfig.json`, extensions: { vue: { enabled: false, compiler: '@vue/compiler-sfc' } } } } as ForkTsCheckerWebpackPluginOptions, workerData as ForkTsCheckerWebpackPluginOptions) as ForkTsCheckerWebpackPluginOptions; export class Checker { constructor() { console.log(chalk.yellow(`[${moment().format('Y-MM-DD H:mm:ss')}] Started checker`)); this.main().then(() => { if (config.async) console.log(chalk.magenta(`[${moment().format('Y-MM-DD H:mm:ss')}] Checker loaded`)); }); } createForkTsCheckerWebpackPluginConfiguration( options: ForkTsCheckerWebpackPluginOptions = {} ): ForkTsCheckerWebpackPluginConfiguration { const compiler: any = { options: { context: process.cwd() } } return { async: options.async as boolean, typescript: createTypeScriptReporterConfiguration(compiler, options.typescript), eslint: createEsLintReporterConfiguration(compiler, options.eslint), issue: createIssueConfiguration(compiler, options.issue), formatter: createFormatterConfiguration(options.formatter), logger: createLoggerConfiguration(compiler, options.logger), }; } async main() { const configuration = this.createForkTsCheckerWebpackPluginConfiguration(config); const state = createForkTsCheckerWebpackPluginState() as ForkTsCheckerWebpackPluginStateCustom; const reporters: ReporterRpcClient[] = []; state.watching = config.async ?? true; if (configuration.typescript.enabled) { assertTypeScriptSupport(configuration.typescript); reporters.push(createTypeScriptReporterRpcClient(configuration.typescript)); } if (configuration.eslint.enabled) { assertEsLintSupport(configuration.eslint); reporters.push(createEsLintReporterRpcClient(configuration.eslint)); } if (reporters.length) { const reporter = createAggregatedReporter(composeReporterRpcClients(reporters)); if (state.watching) { parentPort?.on('message', async (message: any) => { if (message.type === 'changedFiles') { const startTime = (new Date()).getTime(); this.compilation(state, reporter, configuration, message.files); if (await isPending(state.issuesPromise)) { console.log(chalk.cyan(`[${moment().format('Y-MM-DD H:mm:ss')}] Issues checking in progress...`)); } state.issuesPromise.then(async (issues) => { if (!issues) issues = []; issues = issues?.filter(configuration.issue.predicate); const doneTime = (new Date()).getTime(); parentPort?.postMessage({ type: 'issueList', issues: issues, time: doneTime - startTime }); }).catch((e) => { console.log(chalk.bgRed(`[${moment().format('Y-MM-DD H:mm:ss')}] CATCH state.issuesPromise`), e) }); } }); } else { this.compilation(state, reporter, configuration, { changedFiles: [], deletedFiles: [] }); await this.run(state, reporter, configuration); await this.done(state, reporter, configuration); } } } async done(state: ForkTsCheckerWebpackPluginStateCustom, reporter: ReporterRpcClient, configuration: ForkTsCheckerWebpackPluginConfiguration) { await reporter.disconnect(); } compilation(state: ForkTsCheckerWebpackPluginStateCustom, reporter: ReporterRpcClient, configuration: ForkTsCheckerWebpackPluginConfiguration, change: FilesChange) { let resolveDependencies: (dependencies: FilesMatch | undefined) => void; let rejectedDependencies: (error: Error) => void; let resolveIssues: (issues: Issue[] | undefined) => void; let rejectIssues: (error: Error) => void; state.dependenciesPromise = new Promise((resolve, reject) => { resolveDependencies = resolve; rejectedDependencies = reject; }); state.issuesPromise = new Promise((resolve, reject) => { resolveIssues = resolve; rejectIssues = reject; }); const previousReportPromise = state.reportPromise; state.reportPromise = ForkTsCheckerWebpackPlugin.pool.submit( (done: any) => new Promise(async (resolve) => { try { await reporter.connect(); const previousReport = await previousReportPromise; if (previousReport) { await previousReport.close(); } const report = await reporter.getReport(change); resolve(report); report .getDependencies() .then(resolveDependencies) .catch(rejectedDependencies) .finally(() => { report.getIssues().then(resolveIssues).catch(rejectIssues).finally(done); }); } catch (error) { resolve(undefined); resolveDependencies(undefined); resolveIssues(undefined); done(); } }) ); } async run(state: ForkTsCheckerWebpackPluginStateCustom, reporter: ReporterRpcClient, configuration: ForkTsCheckerWebpackPluginConfiguration) { if (!state.initialized) { state.initialized = true; console.log(chalk.cyan(`[${moment().format('Y-MM-DD H:mm:ss')}] Issues checking in progress...`)); const reportPromise = state.reportPromise; const issuesPromise = state.issuesPromise; const startTime = (new Date()).getTime(); let issues: Issue[] | undefined = []; try { if (state.watching) { if (await isPending(issuesPromise)) { console.log(chalk.cyan(`[${moment().format('Y-MM-DD H:mm:ss')}] Issues checking in progress...`)); } else { await wait(10); } } issues = await issuesPromise; } catch (error) { console.log({ error: error, xx: chalk.bgRed('!!!!!!!!!!!!') }) return; } if (!issues) issues = []; if (state.watching) { if (reportPromise !== state.reportPromise) { return; } } issues = issues.filter(configuration.issue.predicate); const doneTime = (new Date()).getTime(); parentPort?.postMessage({ type: 'issueList', issues: issues, time: doneTime - startTime }); } } } export const checker = new Checker;