From 566e70cd2232a52087f1133b8ce7ddfa66a963f3 Mon Sep 17 00:00:00 2001 From: Gil Pedersen Date: Thu, 28 Aug 2025 13:26:57 +0200 Subject: [PATCH 1/2] Make more web usage friendly --- lib/assertions.js | 17 +++++++++++++++++ lib/index.js | 16 +++++----------- 2 files changed, 22 insertions(+), 11 deletions(-) create mode 100644 lib/assertions.js 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..e77195e 100755 --- a/lib/index.js +++ b/lib/index.js @@ -1,9 +1,9 @@ '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 = { @@ -18,13 +18,7 @@ const internals = { TypeError, URIError, - // Node - - Assert.AssertionError, - - // Hoek - - Hoek.AssertError + ...Assertions ] }; @@ -135,7 +129,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; } } From 0683e812761b3aacccb104cebf4c15c7e5e64efa Mon Sep 17 00:00:00 2001 From: Gil Pedersen Date: Thu, 28 Aug 2025 13:50:03 +0200 Subject: [PATCH 2/2] Use prototype manipulation to enable much faster system check --- lib/index.js | 31 ++++++++++++++++++++++++++++++- test/index.js | 20 ++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/lib/index.js b/lib/index.js index e77195e..ad58580 100755 --- a/lib/index.js +++ b/lib/index.js @@ -7,6 +7,7 @@ const Assertions = require('./assertions'); const internals = { + symbol: Symbol('SystemError'), system: [ // JavaScript @@ -23,6 +24,30 @@ const internals = { }; +internals.slow = (() => { + + // Add hidden property to prototype that all instances will have + + 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 = {}) { return internals.catch(err, types, options, true); @@ -99,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; } 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();