UNPKG

zarbis

Version:

Configuration-less build tool

169 lines 6.82 kB
import { codeFrameColumns } from '@babel/code-frame'; const PLUGIN_NAME = 'ErrorFormatter'; const SHIT = 'SHIT '; const HINT = 'HINT '; export default class ErrorFormatter { logger; doConsoleClear; constructor(logger, doConsoleClear, explain = true) { this.logger = logger; this.doConsoleClear = doConsoleClear; } apply(compiler) { this.clearConsole(); this.logger.info(`Initial compilation in progress...`); compiler.hooks.emit.tapAsync(PLUGIN_NAME, (stats, callback) => { this.clearConsole(); this.logger.info(`Emitting...`); callback(); }); let self = this; compiler.hooks.compile.tap(PLUGIN_NAME, (params) => { self.clearConsole(); this.logger.info(`The compiler is starting to compile...`); }); compiler.hooks.compilation.tap(PLUGIN_NAME, function (compilation) { self.clearConsole(); self.logger.info(`The compiler is starting a new compilation...`); compilation.hooks.optimize.tap(PLUGIN_NAME, function () { self.logger.info(`The compilation is starting to optimize files...`); }); }); compiler.hooks.done.tap(PLUGIN_NAME, (stats) => { this.clearConsole(); const hasErrors = stats.hasErrors(); const hasWarnings = stats.hasWarnings(); if (!hasErrors && !hasWarnings) { this.displaySuccess(stats); return true; } if (hasErrors) { this.displayErrors(extractErrorsFromStats(stats, 'errors'), 'error'); return true; } if (hasWarnings) { this.displayErrors(extractErrorsFromStats(stats, 'warnings'), 'warning'); return true; } }); compiler.hooks.invalid.tap(PLUGIN_NAME, (fileName) => { this.clearConsole(); this.logger.info(`Invalid (${fileName} changed), compilation in progress...`); }); } clearConsole() { } displaySuccess(stats) { const time = getCompileTime(stats); this.logger.info(`Compiled successfully in ${time}ms`); } displayErrors(errors, severity) { const nbErrors = errors.length; const isError = severity === 'error'; const subtitle = isError ? `Failed to compile with ${nbErrors} ${severity}s` : `Compiled with ${nbErrors} ${severity}s`; if (isError) this.logger.error(subtitle); else this.logger.warn(subtitle); let missingModules = []; errors.forEach(error => { if (error.error === undefined) error.error = error; if (error.error.message.startsWith('Critical dependency:')) { this.logger.warn(`Critical dependency near ${error.module.userRequest}:${error.loc.end.line}`); this.logger.warn(codeFrameColumns(error.module._source._value, error.loc, { message: error.error.message.replace('Critical dependency:', '').trim(), highlightCode: true, })); //at ${error.module.userRequest}:${error.loc.end.line}:${error.loc.end.column} } else if (error.error.message.startsWith('Can\'t resolve \'')) { if (error.dependencies instanceof Array) { missingModules.push(...error.dependencies.map(dep => dep.request)); } else { const dep = error.error.message.match(/Can't resolve '(.+?)'/); if (dep !== null) { missingModules.push(dep[1]); } } this.logger.error(SHIT + error.error.message); } else if (error.error.stack === undefined) { this.logger.error(error.message); } else if (error.message.startsWith('SyntaxError: ')) { const lines = error.stack.toString().split('\n'); let found = false; const firstStackLine = lines.length - lines.slice().reverse().filter(line => { if (line.trim().startsWith('at ') && !found) { return true; } else { found = true; return false; } }).length; this.logger.error(lines.slice(0, firstStackLine).join('\n')); } else { if (isError) this.logger.error(error); else this.logger.warn(error.message); } }); missingModules = [...new Set(missingModules.map(e => { if (e.startsWith('@')) return e.split('/').slice(0, 2).join('/'); return e.split('/')[0]; }))].sort().filter(e => !e.startsWith('.') && !e.startsWith('/') && !e.startsWith('~')); const modules = missingModules.join(' '); if (missingModules.length > 0 && modules.trim() != '') { this.logger.warn(`${HINT}Found ${missingModules.length} missing dependencies, you can try to install them with`); this.logger.warn(`${HINT}yarn add ${modules}`); } } } function extractErrorsFromStats(stats, type) { if (isMultiStats(stats)) { const errors = stats.stats .reduce((errors, stats) => errors.concat(extractErrorsFromStats(stats, type)), []); return uniqueBy(errors, error => error.message); } return stats.compilation[type]; } function getCompileTime(stats) { if (isMultiStats(stats)) { return stats.stats .reduce((time, stats) => Math.max(time, getCompileTime(stats)), 0); } return stats.endTime - stats.startTime; } function isMultiStats(stats) { return stats.stats; } function getMaxSeverityErrors(errors) { const maxSeverity = getMaxInt(errors, 'severity'); return errors.filter(e => e.severity === maxSeverity); } function getMaxInt(collection, propertyName) { return collection.reduce((res, curr) => { return curr[propertyName] > res ? curr[propertyName] : res; }, 0); } function concat() { const args = Array.from(arguments).filter(e => e != null); const baseArray = Array.isArray(args[0]) ? args[0] : [args[0]]; return Array.prototype.concat.apply(baseArray, args.slice(1)); } function uniqueBy(arr, fun) { const seen = {}; return arr.filter(el => { const e = fun(el); return !(e in seen) && (seen[e] = 1); }); } //# sourceMappingURL=ErrorFormatter.js.map