diff --git a/lib/assertions.js b/lib/assertions.js new file mode 100644 index 0000000..e07a576 --- /dev/null +++ b/lib/assertions.js @@ -0,0 +1,17 @@ +'use strict'; + +const Assert = require('assert'); + +const AssertError = require('@hapi/hoek/assertError'); + + +module.exports = [ + + // Node + + Assert.AssertionError, + + // Hoek + + AssertError +]; diff --git a/lib/index.js b/lib/index.js index 357d850..ad58580 100755 --- a/lib/index.js +++ b/lib/index.js @@ -1,12 +1,13 @@ 'use strict'; -const Assert = require('assert'); - const Boom = require('@hapi/boom'); -const Hoek = require('@hapi/hoek'); +const Contain = require('@hapi/hoek/contain'); + +const Assertions = require('./assertions'); const internals = { + symbol: Symbol('SystemError'), system: [ // JavaScript @@ -18,15 +19,33 @@ const internals = { TypeError, URIError, - // Node + ...Assertions + ] +}; + - Assert.AssertionError, +internals.slow = (() => { - // Hoek + // Add hidden property to prototype that all instances will have - Hoek.AssertError - ] -}; + const slow = []; + const defaultHasInstance = Object[Symbol.hasInstance]; + for (const system of internals.system) { + if (system[Symbol.hasInstance] !== defaultHasInstance) { // Skip classes that use custom instanceof checks + slow.push(system); + continue; + } + + Object.defineProperty(system.prototype, internals.symbol, { + configurable: false, + enumerable: false, + writable: false, + value: true + }); + } + + return slow; +})(); exports.rethrow = function (err, types, options = {}) { @@ -105,7 +124,11 @@ exports.isSystem = function (err) { return false; } - for (const system of internals.system) { + if (err[internals.symbol] === true) { + return true; + } + + for (const system of internals.slow) { if (err instanceof system) { return true; } @@ -135,7 +158,7 @@ internals.match = function (err, types) { } } else if (typeof type === 'object') { - if (Hoek.contain(err, type, { deep: true, part: true })) { + if (Contain(err, type, { deep: true, part: true })) { return true; } } diff --git a/test/index.js b/test/index.js index b617e98..c4be694 100755 --- a/test/index.js +++ b/test/index.js @@ -1,5 +1,20 @@ 'use strict'; +// Add custom assertion to assertion list. Must be done before requiring Bounce + +class HasInstanceCheckError { + + static [Symbol.hasInstance](instance) { + + return instance.message === 'custom-error'; + } +} + +const Assertions = require('../lib/assertions'); + +Assertions.push(HasInstanceCheckError); + + const Assert = require('assert'); const Code = require('@hapi/code'); @@ -520,6 +535,11 @@ describe('Bounce', () => { expect(Bounce.isSystem(new Assert.AssertionError({}))).to.be.true(); }); + it('identifies custom assertion Error as system', () => { + + expect(Bounce.isSystem(new Error('custom-error'))).to.be.true(); + }); + it('identifies hoek Error as system', () => { expect(Bounce.isSystem(new Hoek.AssertError([]))).to.be.true();