UNPKG

@visulima/error

Version:

Error with more than just a message, stacktrace parsing.

166 lines (163 loc) 6.57 kB
import { existsSync, readFileSync } from 'node:fs'; import { relative } from 'node:path'; import { cwd } from 'node:process'; import { fileURLToPath } from 'node:url'; import { codeFrame } from '../code-frame/index.mjs'; import parse from './parseStacktrace-BKGoWCwC.mjs'; var __defProp = Object.defineProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); const getPrefix = /* @__PURE__ */ __name((prefix, indentation, deep) => { if (deep === 0) { return prefix + ""; } if (indentation === " ") { return prefix + " ".repeat(deep); } return prefix + " ".repeat(indentation * deep); }, "getPrefix"); const getRelativePath = /* @__PURE__ */ __name((filePath, cwdPath) => { const path = filePath.replace("async file:", "file:"); return relative(cwdPath, path.startsWith("file:") ? fileURLToPath(path) : path); }, "getRelativePath"); const getMessage = /* @__PURE__ */ __name((error, { color, hideErrorTitle, indentation, prefix }, deep) => getPrefix(prefix, indentation, deep) + (hideErrorTitle ? color.title(error.message) : color.title(error.name + (error.message ? ": " + error.message : ""))) + "\n", "getMessage"); const getHint = /* @__PURE__ */ __name((error, { color, indentation, prefix }, deep) => { if (error.hint === void 0) { return void 0; } const spaces = getPrefix(prefix, indentation, deep); let message = ""; if (Array.isArray(error.hint)) { for (const line of error.hint) { message += spaces + line + "\n"; } } else { message += spaces + error.hint; } return color.hint(message); }, "getHint"); const getMainFrame = /* @__PURE__ */ __name((trace, { color, cwd: cwdPath, displayShortPath, indentation, prefix }, deep = 0) => { const filePath = displayShortPath ? getRelativePath(trace.file, cwdPath) : trace.file; const { fileLine, method } = color; return getPrefix(prefix, indentation, deep) + "at " + (trace.methodName ? method(trace.methodName) + " " : "") + fileLine(filePath) + ":" + // eslint-disable-next-line @typescript-eslint/restrict-plus-operands fileLine(trace.line + ""); }, "getMainFrame"); const getCode = /* @__PURE__ */ __name((trace, { color, indentation, linesAbove, linesBelow, prefix, showGutter, showLineNumbers, tabWidth }, deep) => { if (trace.file === void 0) { return void 0; } const filePath = trace.file.replace("file://", ""); if (!existsSync(filePath)) { return void 0; } const fileContent = readFileSync(filePath, "utf8"); return codeFrame( fileContent, { start: { column: trace.column, line: trace.line } }, { color, linesAbove, linesBelow, prefix: getPrefix(prefix, indentation, deep), showGutter, showLineNumbers, tabWidth } ); }, "getCode"); const getErrors = /* @__PURE__ */ __name((error, options, deep) => { if (error.errors.length === 0) { return void 0; } let message = getPrefix(options.prefix, options.indentation, deep) + "Errors:\n\n"; let first = true; for (const error_ of error.errors) { if (first) { first = false; } else { message += "\n\n"; } message += internalRenderError( // eslint-disable-next-line @typescript-eslint/no-unsafe-argument error_, { ...options, framesMaxLimit: 1, hideErrorCodeView: options.hideErrorErrorsCodeView }, deep + 1 ); } return "\n" + message; }, "getErrors"); const getCause = /* @__PURE__ */ __name((error, options, deep) => { let message = getPrefix(options.prefix, options.indentation, deep) + "Caused by:\n\n"; const cause = error.cause; message += getMessage(cause, options, deep); const stacktrace = parse(cause); const mainFrame = stacktrace.shift(); const hint = getHint(cause, options, deep); if (hint) { message += hint + "\n"; } if (mainFrame) { message += getMainFrame(mainFrame, options, deep); if (!options.hideErrorCauseCodeView) { const code = getCode(mainFrame, options, deep); if (code !== void 0) { message += "\n" + code; } } } if (cause.cause) { message += "\n" + getCause(cause, options, deep + 1); } else if (cause instanceof AggregateError) { const errors = getErrors(cause, options, deep); if (errors !== void 0) { message += "\n" + errors; } } return "\n" + message; }, "getCause"); const getStacktrace = /* @__PURE__ */ __name((stack, options) => (stack.length > 0 ? "\n" : "") + stack.map((frame) => getMainFrame(frame, options)).join("\n"), "getStacktrace"); const internalRenderError = /* @__PURE__ */ __name((error, options, deep) => { const config = { cwd: cwd(), displayShortPath: false, filterStacktrace: void 0, framesMaxLimit: Number.POSITIVE_INFINITY, hideErrorCauseCodeView: false, hideErrorCodeView: false, hideErrorErrorsCodeView: false, hideErrorTitle: false, hideMessage: false, indentation: 4, linesAbove: 2, linesBelow: 3, prefix: "", showGutter: true, showLineNumbers: true, tabWidth: 4, ...options, color: { fileLine: /* @__PURE__ */ __name((value) => value, "fileLine"), gutter: /* @__PURE__ */ __name((value) => value, "gutter"), hint: /* @__PURE__ */ __name((value) => value, "hint"), marker: /* @__PURE__ */ __name((value) => value, "marker"), message: /* @__PURE__ */ __name((value) => value, "message"), method: /* @__PURE__ */ __name((value) => value, "method"), title: /* @__PURE__ */ __name((value) => value, "title"), ...options.color } }; const stack = parse(error, { filter: options.filterStacktrace, frameLimit: config.framesMaxLimit }); const mainFrame = stack.shift(); return [ options.hideMessage ? void 0 : getMessage(error, config, deep), getHint(error, config, deep), mainFrame ? getMainFrame(mainFrame, config, deep) : void 0, mainFrame && !config.hideErrorCodeView ? getCode(mainFrame, config, deep) : void 0, error instanceof AggregateError ? getErrors(error, config, deep) : void 0, error.cause === void 0 ? void 0 : getCause(error, config, deep), stack.length > 0 ? getStacktrace(stack, config) : void 0 ].filter(Boolean).join("\n").replaceAll("\\", "/"); }, "internalRenderError"); const renderError = /* @__PURE__ */ __name((error, options = {}) => { if (options.framesMaxLimit !== void 0 && options.framesMaxLimit <= 0) { throw new RangeError("The 'framesMaxLimit' option must be a positive number"); } return internalRenderError(error, options, 0); }, "renderError"); export { renderError };