import { escape } from "html-escaper"; import { bold, underline } from "kleur/colors"; import * as fs from "node:fs"; import { isAbsolute, join } from "node:path"; import { fileURLToPath } from "node:url"; import stripAnsi from "strip-ansi"; import { normalizePath } from "vite"; import { removeLeadingForwardSlashWindows } from "../../path.js"; import { AggregateError } from "../errors.js"; import { AstroErrorData } from "../index.js"; import { codeFrame } from "../printer.js"; import { normalizeLF } from "../utils.js"; function collectErrorMetadata(e, rootFolder) { const err = AggregateError.is(e) || Array.isArray(e.errors) ? e.errors : [e]; err.forEach((error) => { if (e.stack) { const stackInfo = collectInfoFromStacktrace(e); error.stack = stripAnsi(stackInfo.stack); error.loc = stackInfo.loc; error.plugin = stackInfo.plugin; error.pluginCode = stackInfo.pluginCode; } const normalizedFile = normalizePath(error.loc?.file || ""); const normalizedRootFolder = removeLeadingForwardSlashWindows(rootFolder?.pathname || ""); if (error.loc?.file && rootFolder && (!normalizedFile?.startsWith(normalizedRootFolder) || !isAbsolute(normalizedFile))) { error.loc.file = join(fileURLToPath(rootFolder), error.loc.file); } if (error.loc && (!error.frame || !error.fullCode)) { try { const fileContents = fs.readFileSync(error.loc.file, "utf8"); if (!error.frame) { const frame = codeFrame(fileContents, error.loc); error.frame = stripAnsi(frame); } if (!error.fullCode) { error.fullCode = fileContents; } } catch { } } error.hint = generateHint(e); if (error.message) { error.message = stripAnsi(error.message); } }); if (!AggregateError.is(e) && Array.isArray(e.errors)) { e.errors.forEach((buildError, i) => { const { location, pluginName, text } = buildError; if (text) { err[i].message = text; } if (location) { err[i].loc = { file: location.file, line: location.line, column: location.column }; err[i].id = err[0].id || location?.file; } if (err[i].frame) { const errorLines = err[i].frame?.trim().split("\n"); if (errorLines) { err[i].frame = !/^\d/.test(errorLines[0]) ? errorLines?.slice(1).join("\n") : err[i].frame; } } const possibleFilePath = location?.file ?? err[i].id; if (possibleFilePath && err[i].loc && (!err[i].frame || !err[i].fullCode)) { try { const fileContents = fs.readFileSync(possibleFilePath, "utf8"); if (!err[i].frame) { err[i].frame = codeFrame(fileContents, { ...err[i].loc, file: possibleFilePath }); } err[i].fullCode = fileContents; } catch { err[i].fullCode = err[i].pluginCode; } } if (pluginName) { err[i].plugin = pluginName; } err[i].hint = generateHint(err[0]); }); } return err[0]; } function generateHint(err) { const commonBrowserAPIs = ["document", "window"]; if (/Unknown file extension \"\.(jsx|vue|svelte|astro|css)\" for /.test(err.message)) { return "You likely need to add this package to `vite.ssr.noExternal` in your astro config file."; } else if (commonBrowserAPIs.some((api) => err.toString().includes(api))) { const hint = `Browser APIs are not available on the server. ${err.loc?.file?.endsWith(".astro") ? "Move your code to a