diff options
author | Ruben Bridgewater <ruben@bridgewater.de> | 2019-03-26 14:45:40 +0100 |
---|---|---|
committer | Michaël Zasso <targos@protonmail.com> | 2019-03-30 13:11:06 +0100 |
commit | e54f237afe53324ff6d6f1504a40f26b9fe7711c (patch) | |
tree | 24b1b0bd1602eccc51ab30a9b03e80a684988f6e /lib/internal/util | |
parent | 68b04274ca79c632ca7ff480e5d3738163c962d1 (diff) | |
download | android-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.js | 69 |
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++) { |