Skip to content

Commit

Permalink
Nested VError causes (pinojs#108)
Browse files Browse the repository at this point in the history
* Failing test: support nested cause serialization for VError type errors

* Support VError type errors for nested serialization

Extracts evaluateCause from inside err-helpers and reuses it in error serialization to support nested causes where .cause is a function.
  • Loading branch information
hypesystem authored Jun 10, 2022
1 parent f876857 commit 5b88f7e
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 17 deletions.
30 changes: 15 additions & 15 deletions lib/err-helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,22 @@
const getErrorCause = (err) => {
if (!err) return

/** @type {unknown} */
// @ts-ignore
const cause = err.cause
const cause = evaluateCause(err.cause)

// VError / NError style causes
if (typeof cause === 'function') {
// @ts-ignore
const causeResult = err.cause()
return cause instanceof Error
? cause
: undefined
}

return causeResult instanceof Error
? causeResult
: undefined
} else {
return cause instanceof Error
? cause
: undefined
}
/**
* @param {unknown|(()=>err)} cause
* @returns {Error|undefined}
*/
const evaluateCause = (cause) => {
// VError / NError style causes are functions
return typeof cause === 'function'
? cause()
: cause
}

/**
Expand Down Expand Up @@ -108,6 +107,7 @@ const messageWithCauses = (err) => _messageWithCauses(err, new Set())

module.exports = {
getErrorCause,
evaluateCause,
stackWithCauses,
messageWithCauses
}
5 changes: 3 additions & 2 deletions lib/err.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

module.exports = errSerializer

const { messageWithCauses, stackWithCauses } = require('./err-helpers')
const { messageWithCauses, stackWithCauses, evaluateCause } = require('./err-helpers')

const { toString } = Object.prototype
const seen = Symbol('circular-ref-tag')
Expand Down Expand Up @@ -66,7 +66,8 @@ function errSerializer (err) {
}

if (err.cause) {
_err.cause = errSerializer(err.cause)
const cause = evaluateCause(err.cause)
_err.cause = errSerializer(cause)
}

for (const key in err) {
Expand Down
28 changes: 28 additions & 0 deletions test/err.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -218,3 +218,31 @@ test('serializes causes', function (t) {
t.equal(serialized.cause.cause.message, 'baz')
t.match(serialized.cause.cause.stack, /err\.test\.js:/)
})

test('serializes causes with VError support', function (t) {
t.plan(11)

// Fake VError-style setup
const err = Error('foo: bar')
err.cause = () => {
const err = Error('bar')
err.cause = Error('abc')
return err
}

const serialized = serializer(err)

t.equal(serialized.type, 'Error')
t.equal(serialized.message, 'foo: bar: abc') // message serialization already walks cause-chain
t.match(serialized.stack, /err\.test\.js:/)

t.ok(serialized.cause)
t.equal(serialized.cause.type, 'Error')
t.equal(serialized.cause.message, 'bar: abc')
t.match(serialized.cause.stack, /err\.test\.js:/)

t.ok(serialized.cause.cause)
t.equal(serialized.cause.cause.type, 'Error')
t.equal(serialized.cause.cause.message, 'abc')
t.match(serialized.cause.cause.stack, /err\.test\.js:/)
})

0 comments on commit 5b88f7e

Please sign in to comment.