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