Skip to content

Commit

Permalink
util: add support for error subclassing and null handling
Browse files Browse the repository at this point in the history
  • Loading branch information
antsmartian committed Oct 24, 2018
1 parent c979fad commit 5887e9f
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 4 deletions.
33 changes: 29 additions & 4 deletions lib/internal/util/inspect.js
Original file line number Diff line number Diff line change
Expand Up @@ -643,7 +643,7 @@ function formatRaw(ctx, value, recurseTimes) {
base = dateToISOString(value);
} else if (isError(value)) {
// Make error with message first say the error.
base = formatError(value);
base = formatError(value, getPrefix(constructor, '', 'Error'));
// Wrap the error in brackets in case it has no stack trace.
const stackStart = base.indexOf('\n at');
if (stackStart === -1) {
Expand All @@ -652,7 +652,8 @@ function formatRaw(ctx, value, recurseTimes) {
// 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, getPrefix(constructor, '', 'Error'))
.replace(/\n/g, `\n${indentation}`);
}
if (keys.length === 0)
return base;
Expand Down Expand Up @@ -861,8 +862,32 @@ function formatPrimitive(fn, value, ctx) {
return fn(value.toString(), 'symbol');
}

function formatError(value) {
return value.stack || errorToString(value);
function formatError(value, constructorName) {

if (value.stack) {
let stack = value.stack;
if (!stack.startsWith(constructorName) &&
!(stack.startsWith('file:') && !constructorName.startsWith('file'))) {
const stackStart = value.stack.indexOf('\n at');
const errorAndMessage = value.stack.slice(0, stackStart);
const messageStart = errorAndMessage.indexOf(':');
if (stack && stackStart !== -1) {
stack = stack.slice(stackStart, stack.length);
if (messageStart !== -1) {
const message = errorAndMessage.slice(messageStart + 2,
stackStart.length);
// Reconstruct the stack
stack = constructorName.trim() + ': ' + message.trim() + stack;
} else {
stack = constructorName.trim() + stack;
}
}

return stack;
}
return stack;
}
return errorToString(value);
}

function formatNamespaceObject(ctx, value, recurseTimes, keys) {
Expand Down
34 changes: 34 additions & 0 deletions test/parallel/test-util-inspect.js
Original file line number Diff line number Diff line change
Expand Up @@ -1772,3 +1772,37 @@ assert.strictEqual(
});
assert.strictEqual(util.inspect(obj), '[Set: null prototype] { 1, 2 }');
}

// error subclassing and null prototype checks
{
const error = new Error('My Message');
assert.ok(util.inspect(error).includes('Error: My Message'));

Object.setPrototypeOf(error, null);
assert.ok(util.inspect(error)
.includes('[Error: null prototype]: My Message'));
}

{
class MyCustomError extends Error {}
const customErr = new MyCustomError('custom message');
assert.ok(util.inspect(customErr)
.includes('MyCustomError: custom message'));

Object.setPrototypeOf(customErr, null);
assert.ok(util.inspect(customErr)
.includes('[Error: null prototype]: custom message'));
}

// Check custom errors with name `File`
// works
{
class FileCustomError extends Error {}
const customErr = new FileCustomError();
assert.ok(util.inspect(customErr)
.includes('FileCustomError'));

Object.setPrototypeOf(customErr, null);
assert.ok(util.inspect(customErr)
.includes('[Error: null prototype]'));
}

0 comments on commit 5887e9f

Please sign in to comment.