diff --git a/API.md b/API.md index 8a12f0a92..bf492c338 100755 --- a/API.md +++ b/API.md @@ -5,6 +5,7 @@ - [Server properties](#server-properties) - [`server.app`](#serverapp) - [`server.connections`](#serverconnections) + - [`server.decorations`](#serverdecorations) - [`server.info`](#serverinfo) - [`server.load`](#serverload) - [`server.listener`](#serverlistener) @@ -272,6 +273,30 @@ Each connection object contains: - `lookup()` - - `match()` - +### `server.decorations` + +Provides access to the decorations already applied to various framework interfaces. The object +must not be modified directly, but only through [`server.decorate`](#serverdecoratetype-property-method-options) +- `type` - the decorated interface. Supported types: + - `'request'` - decorations on the [Request object](#request-object). + - `'reply'` - decorations on the [reply interface](#reply-interface). + - `'server'` - decorations on the [Server](#server) object. + +```js +const Hapi = require('hapi'); +const server = new Hapi.Server(); +server.connection({ port: 80 }); + +const success = function () { + + return this.response({ status: 'ok' }); +}; + +server.decorate('reply', 'success', success); +return server.decorations.reply; +// returns ['success'] +``` + #### `server.info` diff --git a/lib/plugin.js b/lib/plugin.js index 43cd11143..ed6c5f5b2 100755 --- a/lib/plugin.js +++ b/lib/plugin.js @@ -366,7 +366,8 @@ internals.Plugin.prototype.decorate = function (type, property, method, options) // Request if (type === 'request') { - return this.root._requestor.decorate(property, method, options); + this.root._requestor.decorate(property, method, options); + return this.root.decorations[type].push(property); } Hoek.assert(!options, 'Cannot specify options for non-request decoration'); @@ -374,7 +375,8 @@ internals.Plugin.prototype.decorate = function (type, property, method, options) // Reply if (type === 'reply') { - return this.root._replier.decorate(property, method); + this.root._replier.decorate(property, method); + return this.root.decorations[type].push(property); } // Server @@ -383,6 +385,7 @@ internals.Plugin.prototype.decorate = function (type, property, method, options) Hoek.assert(this[property] === undefined && this.root[property] === undefined, 'Cannot override the built-in server interface method:', property); this.root._decorations[property] = method; + this.root.decorations[type].push(property); this[property] = method; let parent = this._parent; @@ -392,7 +395,6 @@ internals.Plugin.prototype.decorate = function (type, property, method, options) } }; - internals.Plugin.prototype.dependency = function (dependencies, after) { Hoek.assert(this.realm.plugin, 'Cannot call dependency() outside of a plugin'); diff --git a/lib/reply.js b/lib/reply.js index 3648bb924..d3bb2a0da 100755 --- a/lib/reply.js +++ b/lib/reply.js @@ -26,7 +26,6 @@ internals.Reply.prototype.decorate = function (property, method) { this._decorations[property] = method; }; - /* const handler = function (request, reply) { diff --git a/lib/server.js b/lib/server.js index 94c6a2e70..bd90f46cc 100755 --- a/lib/server.js +++ b/lib/server.js @@ -48,6 +48,11 @@ exports = module.exports = internals.Server = function (options) { this._replier = new Reply(); this._requestor = new Request(); this._decorations = {}; + this.decorations = { + request: [], + reply: [], + server: [] + }; this._plugins = {}; // Exposed plugin properties by name this._app = {}; this._registring = false; // true while register() is waiting for plugin callbacks diff --git a/test/plugin.js b/test/plugin.js index b64e7df79..4681da7e2 100755 --- a/test/plugin.js +++ b/test/plugin.js @@ -2594,6 +2594,158 @@ describe('Plugin', () => { }); }); + describe('decorations ()', () => { + + it('shows decorations on request (empty array)', (done) => { + + const server = new Hapi.Server(); + server.connection(); + + expect(server.decorations.request).to.be.empty(); + done(); + }); + + it('shows decorations on request (single)', (done) => { + + const server = new Hapi.Server(); + server.connection(); + + server.decorate('request', 'a', () => { }); + + expect(server.decorations.request).to.equal(['a']); + done(); + }); + + it('shows decorations on request (many)', (done) => { + + const server = new Hapi.Server(); + server.connection(); + + server.decorate('request', 'a', () => { }); + server.decorate('request', 'b', () => { }); + + expect(server.decorations.request).to.equal(['a', 'b']); + done(); + }); + + it('shows decorations on request (multiple connections)', (done) => { + + const server = new Hapi.Server(); + + server.connection({ labels: ['alpha'] }); + server.connection({ labels: ['beta'] }); + + const conn1 = server.select('alpha'); + const conn2 = server.select('beta'); + + conn1.decorate('request', 'a', () => { }); + conn2.decorate('request', 'b', () => { }); + + expect(server.decorations.request).to.equal(['a', 'b']); + done(); + }); + + it('shows decorations on reply (empty array)', (done) => { + + const server = new Hapi.Server(); + server.connection(); + + expect(server.decorations.reply).to.be.empty(); + done(); + }); + + it('shows decorations on reply (single)', (done) => { + + const server = new Hapi.Server(); + server.connection(); + + server.decorate('reply', 'a', () => { }); + + expect(server.decorations.reply).to.equal(['a']); + done(); + }); + + it('shows decorations on reply (many)', (done) => { + + const server = new Hapi.Server(); + server.connection(); + + server.decorate('reply', 'a', () => { }); + server.decorate('reply', 'b', () => { }); + + expect(server.decorations.reply).to.equal(['a', 'b']); + done(); + }); + + it('shows decorations on reply (multiple connections)', (done) => { + + const server = new Hapi.Server(); + + server.connection({ labels: ['alpha'] }); + server.connection({ labels: ['beta'] }); + + expect(server.connections.length).to.equal(2); + + const conn1 = server.select('alpha'); + const conn2 = server.select('beta'); + + conn1.decorate('reply', 'a', () => { }); + conn2.decorate('reply', 'b', () => { }); + + expect(server.decorations.reply).to.equal(['a', 'b']); + done(); + }); + + it('shows decorations on server (empty array)', (done) => { + + const server = new Hapi.Server(); + server.connection(); + + expect(server.decorations.server).to.be.empty(); + done(); + }); + + it('shows decorations on server (single)', (done) => { + + const server = new Hapi.Server(); + server.connection(); + + server.decorate('server', 'a', () => { }); + + expect(server.decorations.server).to.equal(['a']); + done(); + }); + + it('shows decorations on server (many)', (done) => { + + const server = new Hapi.Server(); + server.connection(); + + server.decorate('server', 'a', () => { }); + server.decorate('server', 'b', () => { }); + + expect(server.decorations.server).to.equal(['a', 'b']); + done(); + }); + + it('shows decorations on server (multiple connections)', (done) => { + + const server = new Hapi.Server(); + + server.connection({ labels: ['alpha'] }); + server.connection({ labels: ['beta'] }); + + const conn1 = server.select('alpha'); + const conn2 = server.select('beta'); + + conn1.decorate('server', 'a', () => { }); + conn2.decorate('server', 'b', () => { }); + + expect(server.decorations.server).to.equal(['a', 'b']); + done(); + }); + }); + describe('dependency()', () => { it('fails to register single plugin with dependencies', (done) => {