astro-ghostcms/.pnpm-store/v3/files/cc/9c6b9698b416dcf7093fc97ba65...

160 lines
6.4 KiB
Plaintext
Raw Normal View History

2024-02-14 14:10:47 +00:00
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 <script> tag outside of the frontmatter, so the code runs on the client." : "If the code is in a framework component, try to access these objects after rendering using lifecycle methods or use a `client:only` directive to make the component exclusively run on the client."}
See https://docs.astro.build/en/guides/troubleshooting/#document-or-window-is-not-defined for more information.
`;
return hint;
}
return err.hint;
}
function collectInfoFromStacktrace(error) {
let stackInfo = {
stack: error.stack,
plugin: error.plugin,
pluginCode: error.pluginCode,
loc: error.loc
};
stackInfo.stack = normalizeLF(error.stack);
const stackText = stripAnsi(error.stack);
if (!stackInfo.loc || !stackInfo.loc.column && !stackInfo.loc.line) {
const possibleFilePath = error.loc?.file || error.pluginCode || error.id || // TODO: this could be better, `src` might be something else
stackText.split("\n").find((ln) => ln.includes("src") || ln.includes("node_modules"));
const source = possibleFilePath?.replace(/^[^(]+\(([^)]+).*$/, "$1").replace(/^\s+at\s+/, "");
let file = source?.replace(/:\d+/g, "");
const location = /:(\d+):(\d+)/.exec(source) ?? [];
const line = location[1];
const column = location[2];
if (file && line && column) {
try {
file = fileURLToPath(file);
} catch {
}
stackInfo.loc = {
file,
line: Number.parseInt(line),
column: Number.parseInt(column)
};
}
}
if (!stackInfo.plugin) {
stackInfo.plugin = /withastro\/astro\/packages\/integrations\/([\w-]+)/i.exec(stackText)?.at(1) || /(@astrojs\/[\w-]+)\/(server|client|index)/i.exec(stackText)?.at(1) || void 0;
}
stackInfo.stack = cleanErrorStack(error.stack);
return stackInfo;
}
function cleanErrorStack(stack) {
return stack.split(/\n/).map((l) => l.replace(/\/@fs\//g, "/")).join("\n");
}
function getDocsForError(err) {
if (err.name !== "UnknownError" && err.name in AstroErrorData) {
return `https://docs.astro.build/en/reference/errors/${getKebabErrorName(err.name)}/`;
}
return void 0;
function getKebabErrorName(errorName) {
return errorName.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
}
}
function renderErrorMarkdown(markdown, target) {
const linkRegex = /\[([^[]+)\]\((.*)\)/g;
const boldRegex = /\*\*(.+)\*\*/g;
const urlRegex = / ((?:https?|ftp):\/\/[-\w+&@#\\/%?=~|!:,.;]*[-\w+&@#\\/%=~|])/gi;
const codeRegex = /`([^`]+)`/g;
if (target === "html") {
return escape(markdown).replace(linkRegex, `<a href="$2" target="_blank">$1</a>`).replace(boldRegex, "<b>$1</b>").replace(urlRegex, ' <a href="$1" target="_blank">$1</a>').replace(codeRegex, "<code>$1</code>");
} else {
return markdown.replace(linkRegex, (_, m1, m2) => `${bold(m1)} ${underline(m2)}`).replace(urlRegex, (fullMatch) => ` ${underline(fullMatch.trim())}`).replace(boldRegex, (_, m1) => `${bold(m1)}`);
}
}
export {
collectErrorMetadata,
getDocsForError,
renderErrorMarkdown
};