aboutsummaryrefslogtreecommitdiff
path: root/lib/internal/util
diff options
context:
space:
mode:
authorRuben Bridgewater <ruben@bridgewater.de>2019-03-26 14:45:40 +0100
committerMichaël Zasso <targos@protonmail.com>2019-03-30 13:11:06 +0100
commite54f237afe53324ff6d6f1504a40f26b9fe7711c (patch)
tree24b1b0bd1602eccc51ab30a9b03e80a684988f6e /lib/internal/util
parent68b04274ca79c632ca7ff480e5d3738163c962d1 (diff)
downloadandroid-node-v8-e54f237afe53324ff6d6f1504a40f26b9fe7711c.tar.gz
android-node-v8-e54f237afe53324ff6d6f1504a40f26b9fe7711c.tar.bz2
android-node-v8-e54f237afe53324ff6d6f1504a40f26b9fe7711c.zip
util: add subclass and null prototype support for errors in inspect
This adds support to visualize the difference between errors with null prototype or subclassed errors. This has a couple safeguards to be sure that the output is not intrusive. PR-URL: https://github.com/nodejs/node/pull/26923 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Michaël Zasso <targos@protonmail.com>
Diffstat (limited to 'lib/internal/util')
-rw-r--r--lib/internal/util/inspect.js69
1 files changed, 47 insertions, 22 deletions
diff --git a/lib/internal/util/inspect.js b/lib/internal/util/inspect.js
index 1ced171fd9..281ef2c87c 100644
--- a/lib/internal/util/inspect.js
+++ b/lib/internal/util/inspect.js
@@ -666,25 +666,9 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
return ctx.stylize(base, 'date');
}
} else if (isError(value)) {
- // Make error with message first say the error.
- base = formatError(value);
- // Wrap the error in brackets in case it has no stack trace.
- const stackStart = base.indexOf('\n at');
- if (stackStart === -1) {
- base = `[${base}]`;
- }
- // The message and the stack have to be indented as well!
- if (ctx.indentationLvl !== 0) {
- const indentation = ' '.repeat(ctx.indentationLvl);
- base = formatError(value).replace(/\n/g, `\n${indentation}`);
- }
+ base = formatError(value, constructor, tag, ctx);
if (keys.length === 0)
return base;
-
- if (ctx.compact === false && stackStart !== -1) {
- braces[0] += `${base.slice(stackStart)}`;
- base = `[${base.slice(0, stackStart)}]`;
- }
} else if (isAnyArrayBuffer(value)) {
// Fast path for ArrayBuffer and SharedArrayBuffer.
// Can't do the same for DataView because it has a non-primitive
@@ -844,6 +828,52 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
return res;
}
+function formatError(err, constructor, tag, ctx) {
+ // TODO(BridgeAR): Always show the error code if present.
+ let stack = err.stack || errorToString(err);
+
+ // A stack trace may contain arbitrary data. Only manipulate the output
+ // for "regular errors" (errors that "look normal") for now.
+ const name = err.name || 'Error';
+ let len = name.length;
+ if (constructor === null ||
+ name.endsWith('Error') &&
+ stack.startsWith(name) &&
+ (stack.length === len || stack[len] === ':' || stack[len] === '\n')) {
+ let fallback = 'Error';
+ if (constructor === null) {
+ const start = stack.match(/^([A-Z][a-z_ A-Z0-9[\]()-]+)(?::|\n {4}at)/) ||
+ stack.match(/^([a-z_A-Z0-9-]*Error)$/);
+ fallback = start && start[1] || '';
+ len = fallback.length;
+ fallback = fallback || 'Error';
+ }
+ const prefix = getPrefix(constructor, tag, fallback).slice(0, -1);
+ if (name !== prefix) {
+ if (prefix.includes(name)) {
+ if (len === 0) {
+ stack = `${prefix}: ${stack}`;
+ } else {
+ stack = `${prefix}${stack.slice(len)}`;
+ }
+ } else {
+ stack = `${prefix} [${name}]${stack.slice(len)}`;
+ }
+ }
+ }
+ // Wrap the error in brackets in case it has no stack trace.
+ const stackStart = stack.indexOf('\n at');
+ if (stackStart === -1) {
+ stack = `[${stack}]`;
+ }
+ // The message and the stack have to be indented as well!
+ if (ctx.indentationLvl !== 0) {
+ const indentation = ' '.repeat(ctx.indentationLvl);
+ stack = stack.replace(/\n/g, `\n${indentation}`);
+ }
+ return stack;
+}
+
function groupArrayElements(ctx, output) {
let totalLength = 0;
let maxLength = 0;
@@ -991,11 +1021,6 @@ function formatPrimitive(fn, value, ctx) {
return fn(value.toString(), 'symbol');
}
-function formatError(value) {
- // TODO(BridgeAR): Always show the error code if present.
- return value.stack || errorToString(value);
-}
-
function formatNamespaceObject(ctx, value, recurseTimes, keys) {
const output = new Array(keys.length);
for (var i = 0; i < keys.length; i++) {