js: Add utility to improve error message formatting

Previously, when we formatted SyntaxErrors with toString(), they
wouldn't display the file/line/column where the syntax error occurred.
This adds a utility function that performs a more comprehensive
formatting that displays location information for SyntaxErrors, as well
as the .cause property of the error if it is present. This formatting is
equivalent to what we do in gjs-console when logging an error.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/3041>
This commit is contained in:
Philip Chimento 2024-01-02 16:16:00 -08:00 committed by Florian Müllner
parent 5fe6e5c865
commit a1a320d3d1
2 changed files with 63 additions and 0 deletions

View File

@ -19,6 +19,7 @@
<file>misc/dateUtils.js</file>
<file>misc/dbusUtils.js</file>
<file>misc/dependencies.js</file>
<file>misc/errorUtils.js</file>
<file>misc/extensionUtils.js</file>
<file>misc/fileUtils.js</file>
<file>misc/gnomeSession.js</file>

62
js/misc/errorUtils.js Normal file
View File

@ -0,0 +1,62 @@
// Common code for displaying errors to the user in various dialogs
function formatSyntaxErrorLocation(error) {
const {fileName = '<unknown>', lineNumber = 0, columnNumber = 0} = error;
return ` @ ${fileName}:${lineNumber}:${columnNumber}`;
}
function formatExceptionStack(error) {
const {stack} = error;
if (!stack)
return '\n\n(No stack trace)';
const indentedStack = stack.split('\n').map(line => ` ${line}`).join('\n');
return `\n\nStack trace:\n${indentedStack}`;
}
function formatExceptionWithCause(error, seenCauses) {
let fmt = formatExceptionStack(error);
const {cause} = error;
if (!cause)
return fmt;
fmt += `\nCaused by: ${cause}`;
if (cause !== null && typeof cause === 'object') {
if (seenCauses.has(cause))
return fmt; // avoid recursion
seenCauses.add(cause);
fmt += formatExceptionWithCause(cause, seenCauses);
}
return fmt;
}
/**
* Formats a thrown exception into a string, including the stack, taking the
* location where a SyntaxError was thrown into account.
*
* @param {Error} error The error to format
* @returns {string} The formatted string
*/
export function formatError(error) {
try {
let fmt = `${error}`;
if (error === null || typeof error !== 'object')
return fmt;
if (error instanceof SyntaxError) {
fmt += formatSyntaxErrorLocation(error);
fmt += formatExceptionStack(error);
return fmt;
}
const seenCauses = new Set([error]);
fmt += formatExceptionWithCause(error, seenCauses);
return fmt;
} catch (e) {
return `(could not display error: ${e})`;
}
}