From 0fcb592c7f85f6abcd36ebe666364c6fa3b9e623 Mon Sep 17 00:00:00 2001 From: Uzlopak Date: Mon, 14 Aug 2023 17:26:54 +0200 Subject: [PATCH 01/19] chore: move example into examples folder (#233) --- example.js => examples/example.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename example.js => examples/example.js (98%) diff --git a/example.js b/examples/example.js similarity index 98% rename from example.js rename to examples/example.js index f607994..cbba32b 100644 --- a/example.js +++ b/examples/example.js @@ -1,6 +1,6 @@ 'use strict' -const avvio = require('.')() +const avvio = require('..')() function a (instance, opts, cb) { (opts.use || []).forEach(_ => { instance.use(_, { use: opts.subUse || [] }) }) From f94d4274c474660d7c59b5c1d8440a6dcd11c227 Mon Sep 17 00:00:00 2001 From: Uzlopak Date: Tue, 15 Aug 2023 09:08:26 +0200 Subject: [PATCH 02/19] chore: extract thenify and executeWithThenable (#229) --- boot.js | 50 ++--------- lib/executeWithThenable.js | 28 ++++++ lib/thenify.js | 60 +++++++++++++ test/lib/executeWithThenable.test.js | 82 ++++++++++++++++++ test/lib/thenify.test.js | 123 +++++++++++++++++++++++++++ 5 files changed, 298 insertions(+), 45 deletions(-) create mode 100644 lib/executeWithThenable.js create mode 100644 lib/thenify.js create mode 100644 test/lib/executeWithThenable.test.js create mode 100644 test/lib/thenify.test.js diff --git a/boot.js b/boot.js index af09afb..8b01f3a 100644 --- a/boot.js +++ b/boot.js @@ -11,8 +11,7 @@ const { } = require('./lib/errors') const { kAvvio, - kIsOnCloseHandler, - kThenifyDoNotWrap + kIsOnCloseHandler } = require('./lib/symbols') const { TimeTree } = require('./lib/time-tree') const { Plugin } = require('./lib/plugin') @@ -20,6 +19,8 @@ const { debug } = require('./lib/debug') const { validatePlugin } = require('./lib/validate-plugin') const { isBundledOrTypescriptPlugin } = require('./lib/is-bundled-or-typescript-plugin') const { isPromiseLike } = require('./lib/is-promise-like') +const { thenify } = require('./lib/thenify') +const { executeWithThenable } = require('./lib/executeWithThenable') function wrap (server, opts, instance) { const expose = opts.expose || {} @@ -435,58 +436,17 @@ Boot.prototype._loadPluginNextTick = function (plugin, callback) { function noop () { } -function thenify () { - // If the instance is ready, then there is - // nothing to await. This is true during - // await server.ready() as ready() resolves - // with the server, end we will end up here - // because of automatic promise chaining. - if (this.booted) { - debug('thenify returning null because we are already booted') - return - } - - // Calling resolve(this._server) would fetch the then - // property on the server, which will lead it here. - // If we do not break the recursion, we will loop - // forever. - if (this[kThenifyDoNotWrap]) { - this[kThenifyDoNotWrap] = false - return - } - - debug('thenify') - return (resolve, reject) => { - const p = this._loadRegistered() - return p.then(() => { - this[kThenifyDoNotWrap] = true - return resolve(this._server) - }, reject) - } -} - function callWithCbOrNextTick (func, cb) { const context = this._server const err = this._error - let res // with this the error will appear just in the next after/ready callback this._error = null if (func.length === 0) { this._error = err - res = func() - if (isPromiseLike(res) && !res[kAvvio]) { - res.then(() => process.nextTick(cb), (e) => process.nextTick(cb, e)) - } else { - process.nextTick(cb) - } + executeWithThenable(func, [], cb) } else if (func.length === 1) { - res = func(err) - if (isPromiseLike(res) && !res[kAvvio]) { - res.then(() => process.nextTick(cb), (e) => process.nextTick(cb, e)) - } else { - process.nextTick(cb) - } + executeWithThenable(func, [err], cb) } else { if (this._timeout === 0) { const wrapCb = (err) => { diff --git a/lib/executeWithThenable.js b/lib/executeWithThenable.js new file mode 100644 index 0000000..6e2c809 --- /dev/null +++ b/lib/executeWithThenable.js @@ -0,0 +1,28 @@ +'use strict' +const { isPromiseLike } = require('./is-promise-like') +const { kAvvio } = require('./symbols') + +/** + * @callback ExecuteWithThenableCallback + * @param {Error} error + * @returns {void} + */ + +/** + * @param {Function} func + * @param {Array} args + * @param {ExecuteWithThenableCallback} [callback] + */ +function executeWithThenable (func, args, callback) { + const result = func.apply(func, args) + if (isPromiseLike(result) && !result[kAvvio]) { + // process promise but not avvio mock thenable + result.then(() => process.nextTick(callback), (error) => process.nextTick(callback, error)) + } else if (callback) { + process.nextTick(callback) + } +} + +module.exports = { + executeWithThenable +} diff --git a/lib/thenify.js b/lib/thenify.js new file mode 100644 index 0000000..e1b614d --- /dev/null +++ b/lib/thenify.js @@ -0,0 +1,60 @@ +'use strict' + +const { debug } = require('./debug') +const { kThenifyDoNotWrap } = require('./symbols') + +/** + * @callback PromiseConstructorLikeResolve + * @param {any} value + * @returns {void} + */ + +/** + * @callback PromiseConstructorLikeReject + * @param {reason} error + * @returns {void} + */ + +/** + * @callback PromiseConstructorLike + * @param {PromiseConstructorLikeResolve} resolve + * @param {PromiseConstructorLikeReject} reject + * @returns {void} + */ + +/** + * @returns {PromiseConstructorLike} + */ +function thenify () { + // If the instance is ready, then there is + // nothing to await. This is true during + // await server.ready() as ready() resolves + // with the server, end we will end up here + // because of automatic promise chaining. + if (this.booted) { + debug('thenify returning undefined because we are already booted') + return + } + + // Calling resolve(this._server) would fetch the then + // property on the server, which will lead it here. + // If we do not break the recursion, we will loop + // forever. + if (this[kThenifyDoNotWrap]) { + this[kThenifyDoNotWrap] = false + return + } + + debug('thenify') + return (resolve, reject) => { + const p = this._loadRegistered() + return p.then(() => { + this[kThenifyDoNotWrap] = true + return resolve(this._server) + }, reject) + } +} + +module.exports = { + thenify +} diff --git a/test/lib/executeWithThenable.test.js b/test/lib/executeWithThenable.test.js new file mode 100644 index 0000000..24fa81a --- /dev/null +++ b/test/lib/executeWithThenable.test.js @@ -0,0 +1,82 @@ +'use strict' + +const { test } = require('tap') +const { executeWithThenable } = require('../../lib/executeWithThenable') +const { kAvvio } = require('../../lib/symbols') + +test('executeWithThenable', (t) => { + t.plan(6) + + t.test('passes the arguments to the function', (t) => { + t.plan(5) + + executeWithThenable((...args) => { + t.equal(args.length, 3) + t.equal(args[0], 1) + t.equal(args[1], 2) + t.equal(args[2], 3) + }, [1, 2, 3], (err) => { + t.error(err) + }) + }) + + t.test('function references this to itself', (t) => { + t.plan(2) + + const func = function () { + t.equal(this, func) + } + executeWithThenable(func, [], (err) => { + t.error(err) + }) + }) + + t.test('handle resolving Promise of func', (t) => { + t.plan(1) + + const fn = function () { + return Promise.resolve(42) + } + + executeWithThenable(fn, [], (err) => { + t.error(err) + }) + }) + + t.test('handle rejecting Promise of func', (t) => { + t.plan(1) + + const fn = function () { + return Promise.reject(new Error('Arbitrary Error')) + } + + executeWithThenable(fn, [], (err) => { + t.equal(err.message, 'Arbitrary Error') + }) + }) + + t.test('dont handle avvio mocks PromiseLike results but use callback if provided', (t) => { + t.plan(1) + + const fn = function () { + const result = Promise.resolve(42) + result[kAvvio] = true + } + + executeWithThenable(fn, [], (err) => { + t.error(err) + }) + }) + + t.test('dont handle avvio mocks Promises and if no callback is provided', (t) => { + t.plan(1) + + const fn = function () { + t.pass(1) + const result = Promise.resolve(42) + result[kAvvio] = true + } + + executeWithThenable(fn, []) + }) +}) diff --git a/test/lib/thenify.test.js b/test/lib/thenify.test.js new file mode 100644 index 0000000..b0c0c95 --- /dev/null +++ b/test/lib/thenify.test.js @@ -0,0 +1,123 @@ +'use strict' + +const { test, mock } = require('tap') +const { kThenifyDoNotWrap } = require('../../lib/symbols') + +test('thenify', (t) => { + t.plan(7) + + t.test('return undefined if booted', (t) => { + t.plan(2) + + const { thenify } = mock('../../lib/thenify', { + '../../lib/debug': { + debug: (message) => { t.equal(message, 'thenify returning undefined because we are already booted') } + } + }) + const result = thenify.call({ + booted: true + }) + t.equal(result, undefined) + }) + + t.test('return undefined if kThenifyDoNotWrap is true', (t) => { + t.plan(1) + + const { thenify } = require('../../lib/thenify') + const result = thenify.call({ + [kThenifyDoNotWrap]: true + }) + t.equal(result, undefined) + }) + + t.test('return PromiseConstructorLike if kThenifyDoNotWrap is false', (t) => { + t.plan(3) + + const { thenify } = mock('../../lib/thenify', { + '../../lib/debug': { + debug: (message) => { t.equal(message, 'thenify') } + } + }) + const promiseContructorLike = thenify.call({ + [kThenifyDoNotWrap]: false + }) + + t.type(promiseContructorLike, 'function') + t.equal(promiseContructorLike.length, 2) + }) + + t.test('return PromiseConstructorLike', (t) => { + t.plan(3) + + const { thenify } = mock('../../lib/thenify', { + '../../lib/debug': { + debug: (message) => { t.equal(message, 'thenify') } + } + }) + const promiseContructorLike = thenify.call({}) + + t.type(promiseContructorLike, 'function') + t.equal(promiseContructorLike.length, 2) + }) + + t.test('resolve should return _server', async (t) => { + t.plan(1) + + const { thenify } = require('../../lib/thenify') + + const server = { + _loadRegistered: () => { + return Promise.resolve() + }, + _server: 'server' + } + const promiseContructorLike = thenify.call(server) + + promiseContructorLike(function (value) { + t.equal(value, 'server') + }, function (reason) { + t.error(reason) + }) + }) + + t.test('resolving should set kThenifyDoNotWrap to true', async (t) => { + t.plan(1) + + const { thenify } = require('../../lib/thenify') + + const server = { + _loadRegistered: () => { + return Promise.resolve() + }, + [kThenifyDoNotWrap]: false, + _server: 'server' + } + const promiseContructorLike = thenify.call(server) + + promiseContructorLike(function (value) { + t.equal(server[kThenifyDoNotWrap], true) + }, function (reason) { + t.error(reason) + }) + }) + + t.test('rejection should pass through to reject', async (t) => { + t.plan(1) + + const { thenify } = require('../../lib/thenify') + + const server = { + _loadRegistered: () => { + return Promise.reject(new Error('Arbitrary rejection')) + }, + _server: 'server' + } + const promiseContructorLike = thenify.call(server) + + promiseContructorLike(function (value) { + t.error(value) + }, function (reason) { + t.equal(reason.message, 'Arbitrary rejection') + }) + }) +}) From ebb67dfafba2f5c7cbc023cf21c30443099d866b Mon Sep 17 00:00:00 2001 From: Uzlopak Date: Tue, 15 Aug 2023 09:54:58 +0200 Subject: [PATCH 03/19] chore: update license (#234) --- LICENSE | 3 +++ 1 file changed, 3 insertions(+) diff --git a/LICENSE b/LICENSE index 5eeaa1a..66c3f4a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,10 @@ MIT License +Copyright (c) 2020-2023 The Fastify Team Copyright (c) 2016-2020 Matteo Collina +The Fastify team members are listed at https://github.com/fastify/fastify#team. + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights From 9da3798005e4da0945c27428718b0e1a3395d017 Mon Sep 17 00:00:00 2001 From: Uzlopak Date: Tue, 15 Aug 2023 10:29:36 +0200 Subject: [PATCH 04/19] chore: move wrap to be method _expose() (#235) * chore: move wrap to be attribute _expose() * chore: move wrap to be attribute _expose() --- boot.js | 169 ++++++++++++++++++++++------------------- lib/errors.js | 6 +- test/chainable.test.js | 30 -------- test/errors.test.js | 1 + test/expose.test.js | 80 +++++++++++++++++++ 5 files changed, 175 insertions(+), 111 deletions(-) create mode 100644 test/expose.test.js diff --git a/boot.js b/boot.js index 8b01f3a..e2cc4be 100644 --- a/boot.js +++ b/boot.js @@ -7,7 +7,8 @@ const { AVV_ERR_EXPOSE_ALREADY_DEFINED, AVV_ERR_CALLBACK_NOT_FN, AVV_ERR_ROOT_PLG_BOOTED, - AVV_ERR_READY_TIMEOUT + AVV_ERR_READY_TIMEOUT, + AVV_ERR_ATTRIBUTE_ALREADY_DEFINED } = require('./lib/errors') const { kAvvio, @@ -22,72 +23,6 @@ const { isPromiseLike } = require('./lib/is-promise-like') const { thenify } = require('./lib/thenify') const { executeWithThenable } = require('./lib/executeWithThenable') -function wrap (server, opts, instance) { - const expose = opts.expose || {} - const useKey = expose.use || 'use' - const afterKey = expose.after || 'after' - const readyKey = expose.ready || 'ready' - const onCloseKey = expose.onClose || 'onClose' - const closeKey = expose.close || 'close' - - if (server[useKey]) { - throw new AVV_ERR_EXPOSE_ALREADY_DEFINED(useKey) - } - - if (server[afterKey]) { - throw new AVV_ERR_EXPOSE_ALREADY_DEFINED(afterKey) - } - - if (server[readyKey]) { - throw new AVV_ERR_EXPOSE_ALREADY_DEFINED(readyKey) - } - - server[useKey] = function (fn, opts) { - instance.use(fn, opts) - return this - } - - Object.defineProperty(server, 'then', { get: thenify.bind(instance) }) - server[kAvvio] = true - - server[afterKey] = function (func) { - if (typeof func !== 'function') { - return instance._loadRegistered() - } - instance.after(encapsulateThreeParam(func, this)) - return this - } - - server[readyKey] = function (func) { - if (func && typeof func !== 'function') { - throw new AVV_ERR_CALLBACK_NOT_FN(readyKey, typeof func) - } - return instance.ready(func ? encapsulateThreeParam(func, this) : undefined) - } - - server[onCloseKey] = function (func) { - if (typeof func !== 'function') { - throw new AVV_ERR_CALLBACK_NOT_FN(onCloseKey, typeof func) - } - instance.onClose(encapsulateTwoParam(func, this)) - return this - } - - server[closeKey] = function (func) { - if (func && typeof func !== 'function') { - throw new AVV_ERR_CALLBACK_NOT_FN(closeKey, typeof func) - } - - if (func) { - instance.close(encapsulateThreeParam(func, this)) - return this - } - - // this is a Promise - return instance.close() - } -} - function Boot (server, opts, done) { if (typeof server === 'function' && arguments.length === 1) { done = server @@ -101,23 +36,21 @@ function Boot (server, opts, done) { } opts = opts || {} + opts.autostart = opts.autostart !== false + opts.timeout = Number(opts.timeout) || 0 + opts.expose = opts.expose || {} if (!new.target) { return new Boot(server, opts, done) } - if (server) { - wrap(server, opts, this) - } + this._server = server || this + this._opts = opts - if (opts.autostart !== false) { - opts.autostart = true + if (server) { + this._expose() } - server = server || this - - this._timeout = Number(opts.timeout) || 0 - this._server = server /** * @type {Array} */ @@ -246,7 +179,7 @@ Boot.prototype._addPlugin = function (plugin, opts, isAfter) { // we always add plugins to load at the current element const current = this._current[0] - const obj = new Plugin(fastq(this, this._loadPluginNextTick, 1), plugin, opts, isAfter, this._timeout) + const obj = new Plugin(fastq(this, this._loadPluginNextTick, 1), plugin, opts, isAfter, this._opts.timeout) obj.once('start', (serverName, funcName, time) => { const nodeId = this.pluginTree.start(current.name, funcName, time) obj.once('loaded', (serverName, funcName, time) => { @@ -268,6 +201,82 @@ Boot.prototype._addPlugin = function (plugin, opts, isAfter) { return obj } +Boot.prototype._expose = function _expose () { + const instance = this + const server = instance._server + const { + use: useKey = 'use', + after: afterKey = 'after', + ready: readyKey = 'ready', + onClose: onCloseKey = 'onClose', + close: closeKey = 'close' + } = this._opts.expose + + if (server[useKey]) { + throw new AVV_ERR_EXPOSE_ALREADY_DEFINED(useKey, 'use') + } + server[useKey] = function (fn, opts) { + instance.use(fn, opts) + return this + } + + if (server[afterKey]) { + throw new AVV_ERR_EXPOSE_ALREADY_DEFINED(afterKey, 'after') + } + server[afterKey] = function (func) { + if (typeof func !== 'function') { + return instance._loadRegistered() + } + instance.after(encapsulateThreeParam(func, this)) + return this + } + + if (server[readyKey]) { + throw new AVV_ERR_EXPOSE_ALREADY_DEFINED(readyKey, 'ready') + } + server[readyKey] = function (func) { + if (func && typeof func !== 'function') { + throw new AVV_ERR_CALLBACK_NOT_FN(readyKey, typeof func) + } + return instance.ready(func ? encapsulateThreeParam(func, this) : undefined) + } + + if (server[onCloseKey]) { + throw new AVV_ERR_EXPOSE_ALREADY_DEFINED(onCloseKey, 'onClose') + } + server[onCloseKey] = function (func) { + if (typeof func !== 'function') { + throw new AVV_ERR_CALLBACK_NOT_FN(onCloseKey, typeof func) + } + instance.onClose(encapsulateTwoParam(func, this)) + return this + } + + if (server[closeKey]) { + throw new AVV_ERR_EXPOSE_ALREADY_DEFINED(closeKey, 'close') + } + server[closeKey] = function (func) { + if (func && typeof func !== 'function') { + throw new AVV_ERR_CALLBACK_NOT_FN(closeKey, typeof func) + } + + if (func) { + instance.close(encapsulateThreeParam(func, this)) + return this + } + + // this is a Promise + return instance.close() + } + + if (server.then) { + throw new AVV_ERR_ATTRIBUTE_ALREADY_DEFINED('then') + } + Object.defineProperty(server, 'then', { get: thenify.bind(instance) }) + + server[kAvvio] = true +} + Boot.prototype.after = function (func) { if (!func) { return this._loadRegistered() @@ -448,7 +457,7 @@ function callWithCbOrNextTick (func, cb) { } else if (func.length === 1) { executeWithThenable(func, [err], cb) } else { - if (this._timeout === 0) { + if (this._opts.timeout === 0) { const wrapCb = (err) => { this._error = err cb(this._error) @@ -467,7 +476,7 @@ function callWithCbOrNextTick (func, cb) { function timeoutCall (func, rootErr, context, cb) { const name = func.name - debug('setting up ready timeout', name, this._timeout) + debug('setting up ready timeout', name, this._opts.timeout) let timer = setTimeout(() => { debug('timed out', name) timer = null @@ -475,7 +484,7 @@ function timeoutCall (func, rootErr, context, cb) { toutErr.fn = func this._error = toutErr cb(toutErr) - }, this._timeout) + }, this._opts.timeout) if (func.length === 2) { func(rootErr, timeoutCb.bind(this)) diff --git a/lib/errors.js b/lib/errors.js index 1824290..9aa4c8a 100644 --- a/lib/errors.js +++ b/lib/errors.js @@ -5,7 +5,11 @@ const { createError } = require('@fastify/error') module.exports = { AVV_ERR_EXPOSE_ALREADY_DEFINED: createError( 'AVV_ERR_EXPOSE_ALREADY_DEFINED', - "'%s' () is already defined, specify an expose option" + "'%s' is already defined, specify an expose option for '%s'" + ), + AVV_ERR_ATTRIBUTE_ALREADY_DEFINED: createError( + 'AVV_ERR_ATTRIBUTE_ALREADY_DEFINED', + "'%s' is already defined" ), AVV_ERR_CALLBACK_NOT_FN: createError( 'AVV_ERR_CALLBACK_NOT_FN', diff --git a/test/chainable.test.js b/test/chainable.test.js index b889456..d07a7ac 100644 --- a/test/chainable.test.js +++ b/test/chainable.test.js @@ -40,36 +40,6 @@ test('chainable automatically binded', (t) => { t.equal(readyResult, undefined) }) -;['use', 'after', 'ready'].forEach((key) => { - test('throws if ' + key + ' is already there', (t) => { - t.plan(1) - - const app = {} - app[key] = () => {} - - try { - boot(app) - t.fail('error must happen') - } catch (err) { - t.equal(err.message, `'${key}' () is already defined, specify an expose option`) - } - }) - - test('support expose for ' + key, (t) => { - const app = {} - app[key] = () => {} - - const expose = {} - expose[key] = 'muahah' - - boot(app, { - expose - }) - - t.end() - }) -}) - test('chainable standalone with server', (t) => { t.plan(6) diff --git a/test/errors.test.js b/test/errors.test.js index 425ae4b..e181382 100644 --- a/test/errors.test.js +++ b/test/errors.test.js @@ -6,6 +6,7 @@ const errors = require('../lib/errors') test('Correct codes of AvvioErrors', t => { const testcases = [ 'AVV_ERR_EXPOSE_ALREADY_DEFINED', + 'AVV_ERR_ATTRIBUTE_ALREADY_DEFINED', 'AVV_ERR_CALLBACK_NOT_FN', 'AVV_ERR_PLUGIN_NOT_VALID', 'AVV_ERR_ROOT_PLG_BOOTED', diff --git a/test/expose.test.js b/test/expose.test.js new file mode 100644 index 0000000..422524e --- /dev/null +++ b/test/expose.test.js @@ -0,0 +1,80 @@ +'use strict' + +const { test } = require('tap') +const boot = require('..') +const { AVV_ERR_EXPOSE_ALREADY_DEFINED, AVV_ERR_ATTRIBUTE_ALREADY_DEFINED } = require('../lib/errors') +const { kAvvio } = require('../lib/symbols') + +for (const key of ['use', 'after', 'ready', 'onClose', 'close']) { + test('throws if ' + key + ' is by default already there', (t) => { + t.plan(1) + + const app = {} + app[key] = () => { } + + t.throws(() => boot(app), new AVV_ERR_EXPOSE_ALREADY_DEFINED(key, key)) + }) + + test('throws if ' + key + ' is already there', (t) => { + t.plan(1) + + const app = {} + app['cust' + key] = () => { } + + t.throws(() => boot(app, { expose: { [key]: 'cust' + key } }), new AVV_ERR_EXPOSE_ALREADY_DEFINED('cust' + key, key)) + }) + + test('support expose for ' + key, (t) => { + const app = {} + app[key] = () => { } + + const expose = {} + expose[key] = 'muahah' + + boot(app, { + expose + }) + + t.end() + }) +} + +test('set the kAvvio to true on the server', (t) => { + t.plan(1) + + const server = {} + boot(server) + + t.ok(server[kAvvio]) +}) + +test('.then()', t => { + t.plan(3) + + t.test('.then() can not be overwritten', (t) => { + t.plan(1) + + const server = { + then: () => {} + } + t.throws(() => boot(server), AVV_ERR_ATTRIBUTE_ALREADY_DEFINED('then')) + }) + + t.test('.then() is a function', (t) => { + t.plan(1) + + const server = {} + boot(server) + + t.type(server.then, 'function') + }) + + t.test('.then() can not be overwritten', (t) => { + t.plan(1) + + const server = {} + boot(server) + + t.throws(() => { server.then = 'invalid' }, TypeError('Cannot set property then of # which has only a getter')) + }) +}) From 16f0f5f83c8b4b5b60b0333fc422707e3d3c11c1 Mon Sep 17 00:00:00 2001 From: Uzlopak Date: Tue, 15 Aug 2023 13:35:32 +0200 Subject: [PATCH 05/19] chore: add _trackPluginLoading method and fix root name (#232) * chore: trackPluginLoading and fix root name * add jsdoc * fix merge error --- README.md | 6 ++-- boot.js | 63 ++++++++++++++++++---------------- test/gh-issues/bug-205.test.js | 2 +- test/plugin-name.test.js | 8 ++--- test/pretty-print.test.js | 2 +- test/to-json.test.js | 6 ++-- 6 files changed, 45 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 41b34cb..8251023 100644 --- a/README.md +++ b/README.md @@ -616,11 +616,11 @@ avvio.on('preReady', () => { The output is like this: ```json { - "label": "bound root", + "label": "root", "start": 1550245184665, "nodes": [ { - "parent": "bound root", + "parent": "root", "start": 1550245184665, "label": "first", "nodes": [ @@ -637,7 +637,7 @@ The output is like this: "diff": 44 }, { - "parent": "bound root", + "parent": "root", "start": 1550245184709, "label": "third", "nodes": [], diff --git a/boot.js b/boot.js index e2cc4be..c658afa 100644 --- a/boot.js +++ b/boot.js @@ -87,21 +87,22 @@ function Boot (server, opts, done) { } this._doStart = null - this._root = new Plugin(fastq(this, this._loadPluginNextTick, 1), root.bind(this), opts, false, 0) - this._root.once('start', (serverName, funcName, time) => { - const nodeId = this.pluginTree.start(null, funcName, time) - this._root.once('loaded', (serverName, funcName, time) => { - this.pluginTree.stop(nodeId, time) - }) - }) + + const instance = this + this._root = new Plugin(fastq(this, this._loadPluginNextTick, 1), function root (server, opts, done) { + instance._doStart = done + opts.autostart && instance.start() + }, opts, false, 0) + + this._trackPluginLoading(this._root) this._loadPlugin(this._root, (err) => { debug('root plugin ready') try { this.emit('preReady') this._root = null - } catch (prereadyError) { - err = err || this._error || prereadyError + } catch (preReadyError) { + err = err || this._error || preReadyError } if (err) { @@ -116,13 +117,6 @@ function Boot (server, opts, done) { }) } -function root (s, opts, done) { - this._doStart = done - if (opts.autostart) { - this.start() - } -} - inherits(Boot, EE) Boot.prototype.start = function () { @@ -165,11 +159,11 @@ Boot.prototype._loadRegistered = function () { Object.defineProperty(Boot.prototype, 'then', { get: thenify }) -Boot.prototype._addPlugin = function (plugin, opts, isAfter) { - if (isBundledOrTypescriptPlugin(plugin)) { - plugin = plugin.default +Boot.prototype._addPlugin = function (pluginFn, opts, isAfter) { + if (isBundledOrTypescriptPlugin(pluginFn)) { + pluginFn = pluginFn.default } - validatePlugin(plugin) + validatePlugin(pluginFn) opts = opts || {} if (this.booted) { @@ -179,26 +173,21 @@ Boot.prototype._addPlugin = function (plugin, opts, isAfter) { // we always add plugins to load at the current element const current = this._current[0] - const obj = new Plugin(fastq(this, this._loadPluginNextTick, 1), plugin, opts, isAfter, this._opts.timeout) - obj.once('start', (serverName, funcName, time) => { - const nodeId = this.pluginTree.start(current.name, funcName, time) - obj.once('loaded', (serverName, funcName, time) => { - this.pluginTree.stop(nodeId, time) - }) - }) + const plugin = new Plugin(fastq(this, this._loadPluginNextTick, 1), pluginFn, opts, isAfter, this._opts.timeout) + this._trackPluginLoading(plugin) if (current.loaded) { - throw new Error(obj.name, current.name) + throw new Error(plugin.name, current.name) } // we add the plugin to be loaded at the end of the current queue - current.enqueue(obj, (err) => { + current.enqueue(plugin, (err) => { if (err) { this._error = err } }) - return obj + return plugin } Boot.prototype._expose = function _expose () { @@ -370,6 +359,20 @@ Boot.prototype.ready = function (func) { }) } +/** + * @param {Plugin} plugin + * @returns {void} + */ +Boot.prototype._trackPluginLoading = function (plugin) { + const parentName = this._current[0]?.name || null + plugin.once('start', (serverName, funcName, time) => { + const nodeId = this.pluginTree.start(parentName || null, funcName, time) + plugin.once('loaded', (serverName, funcName, time) => { + this.pluginTree.stop(nodeId, time) + }) + }) +} + Boot.prototype.prettyPrint = function () { return this.pluginTree.prettyPrint() } diff --git a/test/gh-issues/bug-205.test.js b/test/gh-issues/bug-205.test.js index 2d92377..1dbd4df 100644 --- a/test/gh-issues/bug-205.test.js +++ b/test/gh-issues/bug-205.test.js @@ -9,7 +9,7 @@ test('should print the time tree', (t) => { app.use(function first (instance, opts, cb) { const out = instance.prettyPrint().split('\n') - t.equal(out[0], 'bound root -1 ms') + t.equal(out[0], 'root -1 ms') t.equal(out[1], '└── first -1 ms') cb() }) diff --git a/test/plugin-name.test.js b/test/plugin-name.test.js index 1008396..fa129a5 100644 --- a/test/plugin-name.test.js +++ b/test/plugin-name.test.js @@ -14,7 +14,7 @@ test('plugins get a name from the plugin metadata if it is set', async (t) => { await app.ready() t.match(app.toJSON(), { - label: 'bound root', + label: 'root', nodes: [ { label: 'a-test-plugin' } ] @@ -30,7 +30,7 @@ test('plugins get a name from the options if theres no metadata', async (t) => { await app.ready() t.match(app.toJSON(), { - label: 'bound root', + label: 'root', nodes: [ { label: 'test registration options name' } ] @@ -46,7 +46,7 @@ test('plugins get a name from the function name if theres no name in the options await app.ready() t.match(app.toJSON(), { - label: 'bound root', + label: 'root', nodes: [ { label: 'testPlugin' } ] @@ -61,7 +61,7 @@ test('plugins get a name from the function source if theres no other option', as await app.ready() t.match(app.toJSON(), { - label: 'bound root', + label: 'root', nodes: [ { label: '(app, opts, next) => next()' } ] diff --git a/test/pretty-print.test.js b/test/pretty-print.test.js index f4955f1..734ab08 100644 --- a/test/pretty-print.test.js +++ b/test/pretty-print.test.js @@ -15,7 +15,7 @@ test('pretty print', t => { .use(third).after(after) .use(duplicate, { count: 1 }) - const linesExpected = [/^bound root \d+ ms$/, + const linesExpected = [/^root \d+ ms$/, /^├── first \d+ ms$/, /^├─┬ duplicate \d+ ms$/, /^│ └─┬ duplicate \d+ ms$/, diff --git a/test/to-json.test.js b/test/to-json.test.js index d1b66ed..d37725a 100644 --- a/test/to-json.test.js +++ b/test/to-json.test.js @@ -14,7 +14,7 @@ test('to json', (t) => { const outJson = { id: 'root', - label: 'bound root', + label: 'root', start: /\d+/, nodes: [] } @@ -69,12 +69,12 @@ test('to json multi-level hierarchy', (t) => { const outJson = { id: 'root', - label: 'bound root', + label: 'root', start: /\d+/, nodes: [ { id: /.+/, - parent: 'bound root', + parent: 'root', start: /\d+/, label: 'first', nodes: [ From 7f17963bff7edac73a376753b03a7866b0829d07 Mon Sep 17 00:00:00 2001 From: Uzlopak Date: Tue, 15 Aug 2023 16:06:43 +0200 Subject: [PATCH 06/19] chore: simplify callback (#237) --- boot.js | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/boot.js b/boot.js index c658afa..9b732c4 100644 --- a/boot.js +++ b/boot.js @@ -181,11 +181,7 @@ Boot.prototype._addPlugin = function (pluginFn, opts, isAfter) { } // we add the plugin to be loaded at the end of the current queue - current.enqueue(plugin, (err) => { - if (err) { - this._error = err - } - }) + current.enqueue(obj, (err) => { err && (this._error = err) }) return plugin } @@ -289,11 +285,7 @@ Boot.prototype.onClose = function (func) { } func[this._isOnCloseHandlerKey] = true - this._closeQ.unshift(func, callback.bind(this)) - - function callback (err) { - if (err) this._error = err - } + this._closeQ.unshift(func, (err) => { err && (this._error = err) }) return this } From 3107f52310bcd27df72cf25aa7367e32db1d6d72 Mon Sep 17 00:00:00 2001 From: Uzlopak Date: Tue, 15 Aug 2023 16:16:55 +0200 Subject: [PATCH 07/19] fix: merge error (#238) --- boot.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boot.js b/boot.js index 9b732c4..a992f39 100644 --- a/boot.js +++ b/boot.js @@ -181,7 +181,7 @@ Boot.prototype._addPlugin = function (pluginFn, opts, isAfter) { } // we add the plugin to be loaded at the end of the current queue - current.enqueue(obj, (err) => { err && (this._error = err) }) + current.enqueue(plugin, (err) => { err && (this._error = err) }) return plugin } From 435018498b2ec2c7765434bb80e43615c7e8b92e Mon Sep 17 00:00:00 2001 From: Uzlopak Date: Tue, 15 Aug 2023 18:32:26 +0200 Subject: [PATCH 08/19] chore: remove _isOnCloseHandlerKey (#231) --- boot.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/boot.js b/boot.js index a992f39..ae81595 100644 --- a/boot.js +++ b/boot.js @@ -57,7 +57,7 @@ function Boot (server, opts, done) { this._current = [] this._error = null - this._isOnCloseHandlerKey = kIsOnCloseHandler + this._lastUsed = null this.setMaxListeners(0) @@ -284,7 +284,7 @@ Boot.prototype.onClose = function (func) { throw new Error('not a function') } - func[this._isOnCloseHandlerKey] = true + func[kIsOnCloseHandler] = true this._closeQ.unshift(func, (err) => { err && (this._error = err) }) return this @@ -501,7 +501,7 @@ function timeoutCall (func, rootErr, context, cb) { function closeWithCbOrNextTick (func, cb) { const context = this._server - const isOnCloseHandler = func[this._isOnCloseHandlerKey] + const isOnCloseHandler = func[kIsOnCloseHandler] if (func.length === 0 || func.length === 1) { let promise if (isOnCloseHandler) { From c3b50ef7408d54975fc40ba520a98146b6fdef09 Mon Sep 17 00:00:00 2001 From: Uzlopak Date: Tue, 15 Aug 2023 18:45:39 +0200 Subject: [PATCH 09/19] fix: throw AVV_ERR_CALLBACK_NOT_FN in onClose instead of generic Error (#239) * increase test coverage * throw AVV_ERR_CALLBACK_NOT_FN instead of generic Error --- boot.js | 2 +- test/basic.test.js | 15 ++++++++++++++- test/close.test.js | 3 ++- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/boot.js b/boot.js index ae81595..d661ee9 100644 --- a/boot.js +++ b/boot.js @@ -281,7 +281,7 @@ Boot.prototype.onClose = function (func) { // because they share the same queue but must be called with different signatures if (typeof func !== 'function') { - throw new Error('not a function') + throw new AVV_ERR_CALLBACK_NOT_FN('onClose', typeof func) } func[kIsOnCloseHandler] = true diff --git a/test/basic.test.js b/test/basic.test.js index 1f52f21..05a4810 100644 --- a/test/basic.test.js +++ b/test/basic.test.js @@ -61,7 +61,7 @@ test('boot an app with a promisified plugin', (t) => { }) }) -test('boot an app with a plugin and a callback', (t) => { +test('boot an app with a plugin and a callback /1', (t) => { t.plan(2) const app = boot(() => { @@ -74,6 +74,19 @@ test('boot an app with a plugin and a callback', (t) => { }) }) +test('boot an app with a plugin and a callback /2', (t) => { + t.plan(2) + + const app = boot({}, () => { + t.pass('booted') + }) + + app.use(function (server, opts, done) { + t.pass('plugin loaded') + done() + }) +}) + test('boot a plugin with a custom server', (t) => { t.plan(4) diff --git a/test/close.test.js b/test/close.test.js index 021ea9f..a02914b 100644 --- a/test/close.test.js +++ b/test/close.test.js @@ -2,6 +2,7 @@ const { test } = require('tap') const boot = require('..') +const { AVV_ERR_CALLBACK_NOT_FN } = require('../lib/errors') test('boot an app with a plugin', (t) => { t.plan(4) @@ -494,7 +495,7 @@ test('onClose callback must be a function', (t) => { const app = boot() app.use(function (server, opts, done) { - t.throws(() => app.onClose({}), { message: 'not a function' }) + t.throws(() => app.onClose({}), new AVV_ERR_CALLBACK_NOT_FN('onClose', 'object')) done() }) }) From 77c4b7898cb934ddb7dd9af1fd07d24292a0ff03 Mon Sep 17 00:00:00 2001 From: Uzlopak Date: Wed, 16 Aug 2023 16:31:32 +0200 Subject: [PATCH 10/19] loadedSoFar, add unit tests (#226) * add unit tests * improve failing test * remove unclear test * increase again coverage for time-tree.js --- lib/time-tree.js | 15 ++++-- test/lib/time-tree.test.js | 19 +++++++ test/plugin-loaded-so-far.test.js | 84 +++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+), 4 deletions(-) create mode 100644 test/plugin-loaded-so-far.test.js diff --git a/lib/time-tree.js b/lib/time-tree.js index 61e3ca3..5f02d68 100644 --- a/lib/time-tree.js +++ b/lib/time-tree.js @@ -72,8 +72,14 @@ class TimeTree { * @returns {TimeTreeNode} */ [kGetParent] (parent) { - const parentNode = this.tableLabel.get(parent) - return parentNode[parentNode.length - 1] + if (parent === null) { + return null + } else if (this.tableLabel.has(parent)) { + const parentNode = this.tableLabel.get(parent) + return parentNode[parentNode.length - 1] + } else { + return null + } } /** @@ -92,7 +98,9 @@ class TimeTree { * @returns {TimeTreeNode["id"]} */ [kAddNode] (parent, label, start) { - const isRoot = parent === null + const parentNode = this[kGetParent](parent) + const isRoot = parentNode === null + if (isRoot) { this.root = { parent: null, @@ -107,7 +115,6 @@ class TimeTree { return this.root.id } - const parentNode = this[kGetParent](parent) const nodeId = `${label}-${Math.random()}` /** * @type {TimeTreeNode} diff --git a/test/lib/time-tree.test.js b/test/lib/time-tree.test.js index c0cb1a4..8bef526 100644 --- a/test/lib/time-tree.test.js +++ b/test/lib/time-tree.test.js @@ -114,6 +114,25 @@ test('TimeTree#start is adding a root element when parent is null', t => { t.type(rootNode.diff, 'number') }) +test('TimeTree#start is adding a root element when parent does not exist', t => { + t.plan(9) + + const tree = new TimeTree() + tree.start('invalid', 'root') + + const rootNode = tree.root + + t.type(rootNode, 'object') + t.equal(Object.keys(rootNode).length, 7) + t.equal(rootNode.parent, null) + t.equal(rootNode.id, 'root') + t.equal(rootNode.label, 'root') + t.ok(Array.isArray(rootNode.nodes)) + t.equal(rootNode.nodes.length, 0) + t.ok(Number.isInteger(rootNode.start)) + t.type(rootNode.diff, 'number') +}) + test('TimeTree#start parameter start can override automatically generated start time', t => { t.plan(1) diff --git a/test/plugin-loaded-so-far.test.js b/test/plugin-loaded-so-far.test.js new file mode 100644 index 0000000..bdad133 --- /dev/null +++ b/test/plugin-loaded-so-far.test.js @@ -0,0 +1,84 @@ +'use strict' + +const { test } = require('tap') +const fastq = require('fastq') +const boot = require('..') +const { Plugin } = require('../lib/plugin') + +test('loadedSoFar resolves a Promise, if plugin.loaded is set to true', async (t) => { + t.plan(1) + const app = boot({}) + + const plugin = new Plugin(fastq(app, app._loadPluginNextTick, 1), function (instance, opts, done) { + done() + }, false, 0) + + plugin.loaded = true + + await t.resolves(plugin.loadedSoFar()) +}) + +test('loadedSoFar resolves a Promise, if plugin was loaded by avvio', async (t) => { + t.plan(2) + const app = boot({}) + + const plugin = new Plugin(fastq(app, app._loadPluginNextTick, 1), function (instance, opts, done) { + done() + }, false, 0) + + app._loadPlugin(plugin, function (err) { + t.equal(err, undefined) + }) + + await app.ready() + + await t.resolves(plugin.loadedSoFar()) +}) + +test('loadedSoFar resolves a Promise, if .after() has no error', async t => { + t.plan(1) + const app = boot() + + app.after = function (callback) { + callback(null, () => {}) + } + + const plugin = new Plugin(fastq(app, app._loadPluginNextTick, 1), function (instance, opts, done) { + done() + }, false, 0) + + app._loadPlugin(plugin, function () {}) + + await t.resolves(plugin.loadedSoFar()) +}) + +test('loadedSoFar rejects a Promise, if .after() has an error', async t => { + t.plan(1) + const app = boot() + + app.after = function (fn) { + fn(new Error('ArbitraryError'), () => {}) + } + + const plugin = new Plugin(fastq(app, app._loadPluginNextTick, 1), function (instance, opts, done) { + done() + }, false, 0) + + app._loadPlugin(plugin, function () {}) + + await t.rejects(plugin.loadedSoFar(), new Error('ArbitraryError')) +}) + +test('loadedSoFar resolves a Promise, if Plugin is attached to avvio after it the Plugin was instantiated', async t => { + t.plan(1) + + const plugin = new Plugin(fastq(null, null, 1), function (instance, opts, done) { + done() + }, false, 0) + + const promise = plugin.loadedSoFar() + + plugin.server = boot() + plugin.emit('start') + await t.resolves(promise) +}) From 523d7b549a3ba8aa4116f14022708a77d61cc749 Mon Sep 17 00:00:00 2001 From: Uzlopak Date: Wed, 16 Aug 2023 17:03:16 +0200 Subject: [PATCH 11/19] fix: filenames should be all kebab cased (#240) --- boot.js | 2 +- lib/{executeWithThenable.js => execute-with-thenable.js} | 0 ...xecuteWithThenable.test.js => execute-with-thenable.test.js} | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename lib/{executeWithThenable.js => execute-with-thenable.js} (100%) rename test/lib/{executeWithThenable.test.js => execute-with-thenable.test.js} (95%) diff --git a/boot.js b/boot.js index d661ee9..987f15c 100644 --- a/boot.js +++ b/boot.js @@ -21,7 +21,7 @@ const { validatePlugin } = require('./lib/validate-plugin') const { isBundledOrTypescriptPlugin } = require('./lib/is-bundled-or-typescript-plugin') const { isPromiseLike } = require('./lib/is-promise-like') const { thenify } = require('./lib/thenify') -const { executeWithThenable } = require('./lib/executeWithThenable') +const { executeWithThenable } = require('./lib/execute-with-thenable') function Boot (server, opts, done) { if (typeof server === 'function' && arguments.length === 1) { diff --git a/lib/executeWithThenable.js b/lib/execute-with-thenable.js similarity index 100% rename from lib/executeWithThenable.js rename to lib/execute-with-thenable.js diff --git a/test/lib/executeWithThenable.test.js b/test/lib/execute-with-thenable.test.js similarity index 95% rename from test/lib/executeWithThenable.test.js rename to test/lib/execute-with-thenable.test.js index 24fa81a..f51ac4e 100644 --- a/test/lib/executeWithThenable.test.js +++ b/test/lib/execute-with-thenable.test.js @@ -1,7 +1,7 @@ 'use strict' const { test } = require('tap') -const { executeWithThenable } = require('../../lib/executeWithThenable') +const { executeWithThenable } = require('../../lib/execute-with-thenable') const { kAvvio } = require('../../lib/symbols') test('executeWithThenable', (t) => { From 7ced1b62165e40b679b7c3321866d4de5f25445a Mon Sep 17 00:00:00 2001 From: Frazer Smith Date: Sun, 10 Sep 2023 09:33:25 +0100 Subject: [PATCH 12/19] perf: use `node:` prefix to bypass require.cache call for builtins (#241) * perf: use `node:` prefix to bypass require.cache call for builtins See https://github.com/fastify/fastify-static/pull/407 * docs: use `node:` prefix to bypass require.cache call for builtins --- README.md | 2 +- boot.js | 4 ++-- lib/debug.js | 2 +- lib/plugin.js | 4 ++-- test/await-after.test.js | 6 +++--- test/await-use.test.js | 2 +- test/express.test.js | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 8251023..571a171 100644 --- a/README.md +++ b/README.md @@ -472,7 +472,7 @@ It allows the creation of an inheritance chain for the server instances. The first parameter is the server instance and the second is the plugin function while the third is the options object that you give to use. ```js -const assert = require('assert') +const assert = require('node:assert') const server = { count: 0 } const app = require('avvio')(server) diff --git a/boot.js b/boot.js index 987f15c..beac001 100644 --- a/boot.js +++ b/boot.js @@ -1,8 +1,8 @@ 'use strict' const fastq = require('fastq') -const EE = require('events').EventEmitter -const inherits = require('util').inherits +const EE = require('node:events').EventEmitter +const inherits = require('node:util').inherits const { AVV_ERR_EXPOSE_ALREADY_DEFINED, AVV_ERR_CALLBACK_NOT_FN, diff --git a/lib/debug.js b/lib/debug.js index 5eccad3..e7cdc6f 100644 --- a/lib/debug.js +++ b/lib/debug.js @@ -1,6 +1,6 @@ 'use strict' -const { debuglog } = require('util') +const { debuglog } = require('node:util') /** * @callback DebugLogger diff --git a/lib/plugin.js b/lib/plugin.js index 058430d..2046636 100644 --- a/lib/plugin.js +++ b/lib/plugin.js @@ -1,7 +1,7 @@ 'use strict' -const { EventEmitter } = require('events') -const { inherits } = require('util') +const { EventEmitter } = require('node:events') +const { inherits } = require('node:util') const { debug } = require('./debug') const { createPromise } = require('./create-promise') const { AVV_ERR_PLUGIN_EXEC_TIMEOUT } = require('./errors') diff --git a/test/await-after.test.js b/test/await-after.test.js index d3216c3..eb801da 100644 --- a/test/await-after.test.js +++ b/test/await-after.test.js @@ -2,10 +2,10 @@ const { test } = require('tap') const boot = require('..') -const { promisify } = require('util') +const { promisify } = require('node:util') const sleep = promisify(setTimeout) -const fs = require('fs').promises -const path = require('path') +const fs = require('node:fs').promises +const path = require('node:path') test('await after - nested plugins with same tick callbacks', async (t) => { const app = {} diff --git a/test/await-use.test.js b/test/await-use.test.js index 2516e17..f8adee8 100644 --- a/test/await-use.test.js +++ b/test/await-use.test.js @@ -1,7 +1,7 @@ 'use strict' const { test } = require('tap') -const { promisify } = require('util') +const { promisify } = require('node:util') const sleep = promisify(setTimeout) const boot = require('..') diff --git a/test/express.test.js b/test/express.test.js index eb223cd..2caf4ff 100644 --- a/test/express.test.js +++ b/test/express.test.js @@ -2,7 +2,7 @@ const { test } = require('tap') const express = require('express') -const http = require('http') +const http = require('node:http') const boot = require('..') test('express support', (t) => { From 30e15301703a1eaeeac971f7bce81d4d836b7f84 Mon Sep 17 00:00:00 2001 From: Frazer Smith Date: Thu, 5 Oct 2023 17:16:14 +0100 Subject: [PATCH 13/19] chore: add `.gitattributes` file (#243) --- .gitattributes | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..a0e7df9 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Set default behavior to automatically convert line endings +* text=auto eol=lf From 763f091e0536da303fe36e9abd0368161bdfe6b9 Mon Sep 17 00:00:00 2001 From: Frazer Smith Date: Fri, 27 Oct 2023 14:47:49 +0100 Subject: [PATCH 14/19] chore(package): explicitly declare js module type (#244) --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index afb18d0..fa6ab30 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "8.2.1", "description": "Asynchronous bootstrapping of Node applications", "main": "boot.js", + "type": "commonjs", "scripts": { "lint": "standard", "lint:fix": "standard --fix", From 4f2e04b3be362c1f77e5b50abc2fbd987565dd44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aran=C4=91el=20=C5=A0arenac?= <11753867+big-kahuna-burger@users.noreply.github.com> Date: Mon, 20 Nov 2023 05:24:21 +0100 Subject: [PATCH 15/19] docs: fix broken link in readme (#247) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 571a171..a01eca5 100644 --- a/README.md +++ b/README.md @@ -685,4 +685,4 @@ This project was kindly sponsored by [nearForm](https://nearform.com). Copyright Matteo Collina 2016-2020, Licensed under [MIT][]. [MIT]: ./LICENSE -[example]: ./example.js +[example]: ./examples/example.js From e36b7ef2efcc7db9dcdbcfdf6743228ec55cb913 Mon Sep 17 00:00:00 2001 From: Matteo Granziera Date: Mon, 5 Feb 2024 15:37:45 +0100 Subject: [PATCH 16/19] fix: options as function type (#248) --- index.d.ts | 2 +- test/types/index.ts | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index fd28de2..9b04f4f 100644 --- a/index.d.ts +++ b/index.d.ts @@ -65,7 +65,7 @@ declare namespace avvio { } interface Use> { - (fn: avvio.Plugin, options?: O): C; + (fn: avvio.Plugin, options?: O | ((server: C) => O)): C; } interface Ready> { diff --git a/test/types/index.ts b/test/types/index.ts index a64b2e7..8b80d62 100644 --- a/test/types/index.ts +++ b/test/types/index.ts @@ -35,6 +35,18 @@ import * as avvio from "../../"; server.close; }); + app.use(async (server, options) => {}, + (server) => { + server.use; + server.after; + server.ready; + server.on; + server.start; + server.override; + server.onClose; + server.close; + }); + app.after(err => { if (err) throw err; }); @@ -156,6 +168,18 @@ import * as avvio from "../../"; server.close; }); + app.use(async (server, options) => {}, + (server) => { + server.use; + server.after; + server.ready; + server.on; + server.start; + server.override; + server.onClose; + server.close; + }); + app.after(err => { if (err) throw err; }); @@ -270,6 +294,14 @@ import * as avvio from "../../"; server.typescriptIs; }); + app.use(async (server, options) => {}, + ((server) => { + server.use; + server.after; + server.ready; + server.typescriptIs; + })); + app.after(err => { if (err) throw err; }); From f59cd9d5e701ac0efb82959f211aa15d4bcd6cd7 Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Mon, 5 Feb 2024 15:49:12 +0100 Subject: [PATCH 17/19] Bumped v8.3.0 Signed-off-by: Matteo Collina --- package.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index fa6ab30..c415fcd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "avvio", - "version": "8.2.1", + "version": "8.3.0", "description": "Asynchronous bootstrapping of Node applications", "main": "boot.js", "type": "commonjs", @@ -47,6 +47,8 @@ }, "dependencies": { "@fastify/error": "^3.3.0", - "fastq": "^1.6.1" + "archy": "^1.0.0", + "debug": "^4.0.0", + "fastq": "^1.17.1" } } From a153be8358ece6a1ed970d0bee2c28a8230175b9 Mon Sep 17 00:00:00 2001 From: Frazer Smith Date: Thu, 8 Feb 2024 19:58:12 +0000 Subject: [PATCH 18/19] chore(.gitignore): add .tap/ dir (#250) --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 3c21249..2b6aed4 100644 --- a/.gitignore +++ b/.gitignore @@ -147,3 +147,6 @@ yarn.lock # editor files .vscode .idea + +#tap files +.tap/ From 7207f16adc0a61612601705cbc27fad8a38e52f0 Mon Sep 17 00:00:00 2001 From: Aras Abbasi Date: Sat, 2 Mar 2024 16:29:33 +0100 Subject: [PATCH 19/19] chore: remove unused deps (#251) --- package.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/package.json b/package.json index c415fcd..fca1f04 100644 --- a/package.json +++ b/package.json @@ -47,8 +47,6 @@ }, "dependencies": { "@fastify/error": "^3.3.0", - "archy": "^1.0.0", - "debug": "^4.0.0", "fastq": "^1.17.1" } }