diff --git a/libraries/o-error/README.md b/libraries/o-error/README.md index e5944432ea..cf6582b854 100644 --- a/libraries/o-error/README.md +++ b/libraries/o-error/README.md @@ -442,7 +442,7 @@ async function cleanup() { ### OError.getFullInfo(error) ⇒ Object -The merged info from any `tag`s on the given error. +The merged info from any `tag`s and causes on the given error. If an info property is repeated, the last one wins. @@ -450,7 +450,7 @@ If an info property is repeated, the last one wins. | Param | Type | Description | | --- | --- | --- | -| error | Error \| null \| undefined | any errror (may or may not be an `OError`) | +| error | Error \| null \| undefined | any error (may or may not be an `OError`) | diff --git a/libraries/o-error/index.d.ts b/libraries/o-error/index.d.ts index 44332e887b..005be4e078 100644 --- a/libraries/o-error/index.d.ts +++ b/libraries/o-error/index.d.ts @@ -63,11 +63,11 @@ declare namespace OError { */ export function tag(error: Error, message?: string, info?: any): Error; /** - * The merged info from any `tag`s on the given error. + * The merged info from any `tag`s and causes on the given error. * * If an info property is repeated, the last one wins. * - * @param {Error | null | undefined} error any errror (may or may not be an `OError`) + * @param {Error | null | undefined} error any error (may or may not be an `OError`) * @return {Object} */ export function getFullInfo(error: Error): any; diff --git a/libraries/o-error/index.js b/libraries/o-error/index.js index 8af8d1deba..5da737181f 100644 --- a/libraries/o-error/index.js +++ b/libraries/o-error/index.js @@ -98,11 +98,11 @@ class OError extends Error { } /** - * The merged info from any `tag`s on the given error. + * The merged info from any `tag`s and causes on the given error. * * If an info property is repeated, the last one wins. * - * @param {Error | null | undefined} error any errror (may or may not be an `OError`) + * @param {Error | null | undefined} error any error (may or may not be an `OError`) * @return {Object} */ static getFullInfo(error) { @@ -112,6 +112,8 @@ class OError extends Error { const oError = /** @type{OError} */ (error) + if (oError.cause) Object.assign(info, OError.getFullInfo(oError.cause)) + if (typeof oError.info === 'object') Object.assign(info, oError.info) if (oError._oErrorTags) { diff --git a/libraries/o-error/test/o-error-util.test.js b/libraries/o-error/test/o-error-util.test.js index b82c1093e6..67ecf0875e 100644 --- a/libraries/o-error/test/o-error-util.test.js +++ b/libraries/o-error/test/o-error-util.test.js @@ -282,12 +282,38 @@ describe('OError.getFullInfo', function () { }) }) - it('does not merge info from a cause', function () { + it('merges info from a cause', function () { const err1 = new Error('foo') const err2 = new Error('bar') err1.cause = err2 err2.info = { userId: 123 } - expect(OError.getFullInfo(err1)).to.deep.equal({}) + expect(OError.getFullInfo(err1)).to.deep.equal({ userId: 123 }) + }) + + it('merges info from a nested cause', function () { + const err1 = new Error('foo') + const err2 = new Error('bar') + const err3 = new Error('baz') + err1.cause = err2 + err2.info = { userId: 123 } + err2.cause = err3 + err3.info = { foo: 42 } + expect(OError.getFullInfo(err1)).to.deep.equal({ + userId: 123, + foo: 42, + }) + }) + + it('merges info from cause with duplicate keys', function () { + const err1 = new Error('foo') + const err2 = new Error('bar') + err1.info = { userId: 42, foo: 1337 } + err1.cause = err2 + err2.info = { userId: 1 } + expect(OError.getFullInfo(err1)).to.deep.equal({ + userId: 42, + foo: 1337, + }) }) it('merges info from tags with duplicate keys', function () { @@ -371,8 +397,8 @@ describe('OError.getFullStack', function () { ' TaggedError: failed to foo', ]) - // The info from the wrapped cause should not leak out. - expect(OError.getFullInfo(error)).to.eql({ bat: 1 }) + // The info from the wrapped cause should be picked up for logging. + expect(OError.getFullInfo(error)).to.eql({ bat: 1, foo: 1 }) // But it should still be recorded. expect(OError.getFullInfo(error.cause)).to.eql({ foo: 1 })