import util from "node:util"; import debugUtil from "debug"; import ConsoleLogger from "../Util/ConsoleLogger.js"; import EleventyErrorUtil from "./EleventyErrorUtil.js"; const debug = debugUtil("Eleventy:EleventyErrorHandler"); class EleventyErrorHandler { constructor() { this._isVerbose = true; } get isVerbose() { return this._isVerbose; } set isVerbose(verbose) { this._isVerbose = !!verbose; this.logger.isVerbose = !!verbose; } get logger() { if (!this._logger) { this._logger = new ConsoleLogger(); this._logger.isVerbose = this.isVerbose; } return this._logger; } set logger(logger) { this._logger = logger; } warn(e, msg) { if (msg) { this.initialMessage(msg, "warn", "yellow"); } this.log(e, "warn"); } fatal(e, msg) { this.error(e, msg); process.exitCode = 1; } once(type, e, msg) { if (e.__errorAlreadyLogged) { return; } this[type || "error"](e, msg); Object.defineProperty(e, "__errorAlreadyLogged", { value: true, }); } error(e, msg) { if (msg) { this.initialMessage(msg, "error", "red", true); } this.log(e, "error", undefined, true); } static getTotalErrorCount(e) { let totalErrorCount = 0; let errorCountRef = e; while (errorCountRef) { totalErrorCount++; errorCountRef = errorCountRef.originalError; } return totalErrorCount; } //https://nodejs.org/api/process.html log(e, type = "log", chalkColor = "", forceToConsole = false) { if (process.env.DEBUG) { debug("Full error object: %o", util.inspect(e, { showHidden: false, depth: null })); } let showStack = true; if (e.skipOriginalStack) { // Don’t show the full error stack trace showStack = false; } let totalErrorCount = EleventyErrorHandler.getTotalErrorCount(e); let ref = e; let index = 1; while (ref) { let nextRef = ref.originalError; // Unwrap cause from error and assign it to what Eleventy expects if (nextRef?.cause) { nextRef.originalError = nextRef.cause?.originalError ?? nextRef?.cause; } if (!nextRef && EleventyErrorUtil.hasEmbeddedError(ref.message)) { nextRef = EleventyErrorUtil.deconvertErrorToObject(ref); } if (nextRef?.skipOriginalStack) { showStack = false; } this.logger.message( `${totalErrorCount > 1 ? `${index}. ` : ""}${( EleventyErrorUtil.cleanMessage(ref.message) || "(No error message provided)" ).trim()}${ref.name !== "Error" ? ` (via ${ref.name})` : ""}`, type, chalkColor, forceToConsole, ); if (process.env.DEBUG) { debug(`(${type} stack): ${ref.stack}`); } else if (!nextRef) { // last error in the loop // remove duplicate error messages if the stack contains the original message output above let stackStr = ref.stack || ""; if (e.removeDuplicateErrorStringFromOutput) { stackStr = stackStr.replace( `${ref.name}: ${ref.message}`, "(Repeated output has been truncated…)", ); } if (showStack) { this.logger.message( "\nOriginal error stack trace: " + stackStr, type, chalkColor, forceToConsole, ); } } ref = nextRef; index++; } } initialMessage(message, type = "log", chalkColor = "blue", forceToConsole = false) { if (message) { this.logger.message(message + ":", type, chalkColor, forceToConsole); } } } export { EleventyErrorHandler };