Skip to content

Commit

Permalink
Fix legacy boom object support
Browse files Browse the repository at this point in the history
  • Loading branch information
kanongil committed Dec 6, 2023
1 parent 60893c0 commit 964a429
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 38 deletions.
77 changes: 42 additions & 35 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,16 @@ exports.Boom = class Boom extends Error {
return this.output.statusCode >= 500;
}

set isServer(value) {} // Allow for compatiblity with legacy boom

constructor(message, options = {}) {

const { statusCode = 500, data, headers, ctor = exports.Boom } = options;

super(message ?? internals.codes.get(statusCode) ?? 'Unknown', options);
Error.captureStackTrace(this, ctor); // Filter the stack to our external API

this.#apply(data, statusCode, headers);
internals.apply(this, data, statusCode, headers);
}

static [Symbol.hasInstance](instance) {
Expand All @@ -102,53 +104,58 @@ exports.Boom = class Boom extends Error {
this.output.payload = new internals.PayloadObject(this, this.output.statusCode, debug);
}

#apply(data, statusCode, headers, message) {
static {
Object.defineProperty(this.prototype, 'name', { value: 'Boom', writable: true, configurable: true });
Object.defineProperty(this.prototype, 'isBoom', { value: true, writable: true, configurable: true });

if (data !== undefined) {
this.data = data;
}
exports.isBoom = function (err, statusCode) {

if (statusCode) {
const numberCode = parseInt(statusCode, 10);
if (isNaN(numberCode) || numberCode < 400) {
throw new TypeError(`statusCode must be a number (400+): ${statusCode}`);
}
return err instanceof Error && !!err.isBoom && (!statusCode || err.output.statusCode === statusCode);
};

if (message) {
this.message = `${message}: ${this.message}`;
}
}
};

const payload = new internals.PayloadObject(this, numberCode, false);
this.output = new internals.BoomOutput(numberCode, payload, headers);
}

exports.boomify = function (err, options = {}) {

const { override, data, statusCode, message } = options;

if (!err?.isBoom) {
return new exports.Boom(message, { statusCode, cause: err, data });
}

static {
Object.defineProperty(this.prototype, 'name', { value: 'Boom', writable: true, configurable: true });
Object.defineProperty(this.prototype, 'isBoom', { value: true, configurable: true });
if (override === false) { // Defaults to true
internals.apply(err, data);
}
else {
internals.apply(err, data, statusCode ?? err.output.statusCode, {}, message);
}

exports.isBoom = function (err, statusCode) {
err.isServer = err.output.statusCode >= 500; // Assign, in case it is a legacy boom object

return err instanceof Error && !!err.isBoom && (!statusCode || err.output.statusCode === statusCode);
};
return err;
};

exports.boomify = function (err, options = {}) {

const { override, data, statusCode, message } = options;
internals.apply = function (boom, data, statusCode, headers, message) {

if (!err?.isBoom) {
return new exports.Boom(message, { statusCode, cause: err, data });
}
if (data !== undefined) {
boom.data = data;
}

if (override === false) { // Defaults to true
err.#apply(data);
}
else {
err.#apply(data, statusCode ?? err.output.statusCode, {}, message);
}
if (statusCode) {
const numberCode = parseInt(statusCode, 10);
if (isNaN(numberCode) || numberCode < 400) {
throw new TypeError(`statusCode must be a number (400+): ${statusCode}`);
}

return err;
};
if (message) {
boom.message = `${message}: ${boom.message}`;
}

const payload = new internals.PayloadObject(boom, numberCode, false);
boom.output = new internals.BoomOutput(numberCode, payload, headers);
}
};

Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,11 @@
"@hapi/eslint-plugin": "*",
"@hapi/lab": "^25.1.0",
"@types/node": "^17.0.31",
"typescript": "~4.6.4"
"typescript": "~4.6.4",
"@hapi/boom10": "npm:@hapi/boom@^10.0.1"
},
"scripts": {
"test": "lab -a @hapi/code -t 100 -L -Y",
"test": "lab -a @hapi/code -t 100 -L",
"test-cov-html": "lab -a @hapi/code -t 100 -L -r html -o coverage.html"
},
"license": "BSD-3-Clause"
Expand Down
36 changes: 35 additions & 1 deletion test/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict';

const Boom = require('..');
const Boom10 = require('@hapi/boom10');
const Code = require('@hapi/code');
const Lab = require('@hapi/lab');

Expand Down Expand Up @@ -107,6 +108,7 @@ describe('Boom', () => {
const BadaBoom = class extends Boom.Boom {};

expect(new Boom.Boom('oops')).to.be.instanceOf(Boom.Boom);
expect(new Boom10.Boom('oops')).to.be.instanceOf(Boom.Boom);
expect(new BadaBoom('oops')).to.be.instanceOf(Boom.Boom);
expect(Boom.badRequest('oops')).to.be.instanceOf(Boom.Boom);
expect(new Error('oops')).to.not.be.instanceOf(Boom.Boom);
Expand All @@ -128,6 +130,12 @@ describe('Boom', () => {
expect(new Boom.Boom('oops')).to.not.be.instanceOf(BadaBoom);
expect(Boom.badRequest('oops')).to.not.be.instanceOf(BadaBoom);
});

it('works from legacy boom', () => {

expect(new Boom.Boom('oops')).to.be.instanceOf(Boom10.Boom);
expect(new Boom10.Boom('oops')).to.be.instanceOf(Boom10.Boom);
});
});

describe('isBoom()', () => {
Expand All @@ -137,6 +145,7 @@ describe('Boom', () => {
// Success

expect(Boom.isBoom(new Boom.Boom('oops'))).to.be.true();
expect(Boom.isBoom(new Boom10.Boom('oops'))).to.be.true();

// Fail

Expand All @@ -148,11 +157,19 @@ describe('Boom', () => {
it('returns true for valid boom object and valid status code', () => {

expect(Boom.isBoom(Boom.notFound(),404)).to.be.true();
expect(Boom.isBoom(Boom10.notFound(), 404)).to.be.true();
});

it('returns false for valid boom object and wrong status code', () => {

expect(Boom.isBoom(Boom.notFound(),503)).to.be.false();
expect(Boom.isBoom(Boom.notFound(), 503)).to.be.false();
expect(Boom.isBoom(Boom10.notFound(), 503)).to.be.false();
});

it('works from legacy boom', () => {

expect(Boom10.isBoom(new Boom.Boom('oops'))).to.be.true();
expect(Boom10.isBoom(new Boom10.Boom('oops'))).to.be.true();
});
});

Expand Down Expand Up @@ -272,6 +289,23 @@ describe('Boom', () => {
expect(boom.output.payload.message).to.equal('Hello: 123');
expect(boom.output.statusCode).to.equal(400);
});

it('works with legacy boom', () => {

const boom = Boom.boomify(new Boom10.Boom(null, { statusCode: 404 }), { statusCode: 501, message: 'Override' });

expect(boom.cause).to.be.undefined();
expect(boom.message).to.equal('Override: Not Found');
expect(boom.isServer).to.be.true();
expect(boom.output.statusCode).to.equal(501);

const boom10 = Boom10.boomify(new Boom.Boom(null, { statusCode: 404 }), { statusCode: 501, message: 'Override' });

expect(boom10.cause).to.be.undefined();
expect(boom10.message).to.equal('Override: Not Found');
expect(boom10.isServer).to.be.true();
expect(boom10.output.statusCode).to.equal(501);
});
});

describe('create()', () => {
Expand Down

0 comments on commit 964a429

Please sign in to comment.