diff --git a/README.md b/README.md index aace39c..55164b0 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,7 @@ function third (instance, opts, cb) { * instance.use() * instance.after() * instance.ready() + * instance.override() * boot.express() ------------------------------------------------------- @@ -200,6 +201,47 @@ boot(app, { }) ``` +------------------------------------------------------- + + +### app.override(server) + +Allows to override the instance of the server for each loading +plugin. It allows the creation of an inheritance chain for the +server instances. + +```js +const boot = require('avvio') +const assert = require('assert') +const server = { count: 0 } +const app = boot(server) + +console.log(app !== server, 'override must be set on the Avvio instance') + +app.override = function (s) { + // create a new instance with the + // server as the prototype + const res = Object.create(s) + res.count = res.count + 1 + + return res +} + +app.use(function first (s1, opts, cb) { + assert(s1 !== server) + assert(server.isPrototypeOf(s1)) + assert(s1.count === 1) + s1.use(second, cb) + + function second (s2, opts, cb) { + assert(s2 !== s1) + assert(s1.isPrototypeOf(s2)) + assert(s2.count === 2) + cb() + } +}) +``` + ------------------------------------------------------- ## Acknowledgements diff --git a/boot.js b/boot.js index 06ff961..5e18b40 100644 --- a/boot.js +++ b/boot.js @@ -103,6 +103,11 @@ Boot.prototype._init = function () { } } +// allows to override the instance of a server, given a plugin +Boot.prototype.override = function (server) { + return server +} + // load a plugin Boot.prototype.use = function (plugin, opts, callback) { if (typeof opts === 'function') { @@ -181,7 +186,8 @@ function Plugin (parent, func, opts, callback) { Plugin.prototype.exec = function (server, cb) { const func = this.func - func(server, this.opts, cb) + this.server = this.parent.override(server) + func(this.server, this.opts, cb) } Plugin.prototype.finish = function (err, cb) { @@ -192,9 +198,10 @@ Plugin.prototype.finish = function (err, cb) { // loads a plugin function loadPlugin (toLoad, cb) { + const last = this._current[0] // place the plugin at the top of _current this._current.unshift(toLoad) - toLoad.exec(this._server, (err) => { + toLoad.exec(last && last.server || this._server, (err) => { if (err || !(toLoad.q.length() > 0 || toLoad.q.running() > 0)) { // finish now, because there is nothing left to do this._current.shift() diff --git a/test/override.js b/test/override.js new file mode 100644 index 0000000..933c739 --- /dev/null +++ b/test/override.js @@ -0,0 +1,100 @@ +'use strict' + +const test = require('tap').test +const boot = require('..') + +test('custom inheritance', (t) => { + t.plan(3) + + const server = { my: 'server' } + const app = boot(server) + + app.override = function (s) { + t.equal(s, server) + + const res = Object.create(s) + res.b = 42 + + return res + } + + app.use(function first (s, opts, cb) { + t.notEqual(s, server) + t.ok(server.isPrototypeOf(s)) + cb() + }) +}) + +test('custom inheritance multiple levels', (t) => { + t.plan(6) + + const server = { count: 0 } + const app = boot(server) + + app.override = function (s) { + const res = Object.create(s) + res.count = res.count + 1 + + return res + } + + app.use(function first (s1, opts, cb) { + t.notEqual(s1, server) + t.ok(server.isPrototypeOf(s1)) + t.equal(s1.count, 1) + s1.use(second, cb) + + function second (s2, opts, cb) { + t.notEqual(s2, s1) + t.ok(s1.isPrototypeOf(s2)) + t.equal(s2.count, 2) + cb() + } + }) +}) + +test('custom inheritance multiple levels with multiple heads', (t) => { + t.plan(13) + + const server = { count: 0 } + const app = boot(server) + + app.override = function (s) { + const res = Object.create(s) + res.count = res.count + 1 + + return res + } + + app.use(function first (s1, opts, cb) { + t.notEqual(s1, server) + t.ok(server.isPrototypeOf(s1)) + t.equal(s1.count, 1) + s1.use(second, cb) + + function second (s2, opts, cb) { + t.notEqual(s2, s1) + t.ok(s1.isPrototypeOf(s2)) + t.equal(s2.count, 2) + cb() + } + }) + + app.use(function third (s1, opts, cb) { + t.notEqual(s1, server) + t.ok(server.isPrototypeOf(s1)) + t.equal(s1.count, 1) + s1.use(fourth, cb) + + function fourth (s2, opts, cb) { + t.notEqual(s2, s1) + t.ok(s1.isPrototypeOf(s2)) + t.equal(s2.count, 2) + cb() + } + }) + + app.ready(function () { + t.equal(server.count, 0) + }) +})