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)
+ })
+})