diff --git a/boot.js b/boot.js index 201a94a..9aa0bc0 100644 --- a/boot.js +++ b/boot.js @@ -6,7 +6,6 @@ const inherits = require('util').inherits const { AVV_ERR_EXPOSE_ALREADY_DEFINED, AVV_ERR_CALLBACK_NOT_FN, - AVV_ERR_PLUGIN_NOT_VALID, AVV_ERR_ROOT_PLG_BOOTED, AVV_ERR_READY_TIMEOUT } = require('./lib/errors') @@ -18,6 +17,8 @@ const { const { TimeTree } = require('./lib/time-tree') const { Plugin } = require('./plugin') const { debug } = require('./lib/debug') +const { validatePlugin } = require('./lib/validate-plugin') +const { isBundledOrTypescriptPlugin } = require('./lib/is-bundled-or-typescript-plugin') const { loadPlugin } = require('./lib/load-plugin') function wrap (server, opts, instance) { @@ -201,18 +202,6 @@ Boot.prototype.override = function (server, func, opts) { return server } -function assertPlugin (plugin) { - // Faux modules are modules built with TypeScript - // or Babel that they export a .default property. - if (plugin && typeof plugin === 'object' && typeof plugin.default === 'function') { - plugin = plugin.default - } - if (!(plugin && (typeof plugin === 'function' || typeof plugin.then === 'function'))) { - throw new AVV_ERR_PLUGIN_NOT_VALID(typeof plugin) - } - return plugin -} - Boot.prototype[kAvvio] = true // load a plugin @@ -241,7 +230,10 @@ Boot.prototype._loadRegistered = function () { Object.defineProperty(Boot.prototype, 'then', { get: thenify }) Boot.prototype._addPlugin = function (plugin, opts, isAfter) { - plugin = assertPlugin(plugin) + if (isBundledOrTypescriptPlugin(plugin)) { + plugin = plugin.default + } + validatePlugin(plugin) opts = opts || {} if (this.booted) { diff --git a/lib/is-bundled-or-typescript-plugin.js b/lib/is-bundled-or-typescript-plugin.js new file mode 100644 index 0000000..f72438e --- /dev/null +++ b/lib/is-bundled-or-typescript-plugin.js @@ -0,0 +1,20 @@ +'use strict' + +/** + * bundled or typescript plugin + * @typedef {object} BundledOrTypescriptPlugin + * @property {function} default + */ + +/** + * @param {unknown} plugin + * @returns {plugin is BundledOrTypescriptPlugin} + */ + +function isBundledOrTypescriptPlugin (plugin) { + return plugin !== null && typeof plugin === 'object' && typeof plugin.default === 'function' +} + +module.exports = { + isBundledOrTypescriptPlugin +} diff --git a/lib/validate-plugin.js b/lib/validate-plugin.js new file mode 100644 index 0000000..4006ca4 --- /dev/null +++ b/lib/validate-plugin.js @@ -0,0 +1,25 @@ +'use strict' + +const { AVV_ERR_PLUGIN_NOT_VALID } = require('./errors') + +/** + * @param {unknown} plugin + * @throws {AVV_ERR_PLUGIN_NOT_VALID} + * @returns {Function} + */ +function validatePlugin (plugin) { + // validate if plugin is a function or Promise + if (!(plugin && (typeof plugin === 'function' || typeof plugin.then === 'function'))) { + if (Array.isArray(plugin)) { + throw new AVV_ERR_PLUGIN_NOT_VALID('array') + } else if (plugin === null) { + throw new AVV_ERR_PLUGIN_NOT_VALID('null') + } else { + throw new AVV_ERR_PLUGIN_NOT_VALID(typeof plugin) + } + } +} + +module.exports = { + validatePlugin +} diff --git a/test/lib/is-bundled-or-typescript-plugin.test.js b/test/lib/is-bundled-or-typescript-plugin.test.js new file mode 100644 index 0000000..b81029b --- /dev/null +++ b/test/lib/is-bundled-or-typescript-plugin.test.js @@ -0,0 +1,20 @@ +'use strict' + +const { test } = require('tap') +const { isBundledOrTypescriptPlugin } = require('../../lib/is-bundled-or-typescript-plugin') + +test('isBundledOrTypescriptPlugin', (t) => { + t.plan(9) + + t.equal(isBundledOrTypescriptPlugin(1), false) + t.equal(isBundledOrTypescriptPlugin('function'), false) + t.equal(isBundledOrTypescriptPlugin({}), false) + t.equal(isBundledOrTypescriptPlugin([]), false) + t.equal(isBundledOrTypescriptPlugin(null), false) + + t.equal(isBundledOrTypescriptPlugin(function () {}), false) + t.equal(isBundledOrTypescriptPlugin(new Promise((resolve) => resolve)), false) + t.equal(isBundledOrTypescriptPlugin(Promise.resolve()), false) + + t.equal(isBundledOrTypescriptPlugin({ default: () => {} }), true) +}) diff --git a/test/lib/validate-plugin.test.js b/test/lib/validate-plugin.test.js new file mode 100644 index 0000000..a3aa956 --- /dev/null +++ b/test/lib/validate-plugin.test.js @@ -0,0 +1,19 @@ +'use strict' + +const { test } = require('tap') +const { validatePlugin } = require('../../lib/validate-plugin') +const { AVV_ERR_PLUGIN_NOT_VALID } = require('../../lib/errors') + +test('validatePlugin', (t) => { + t.plan(8) + + t.throws(() => validatePlugin(1), new AVV_ERR_PLUGIN_NOT_VALID('number')) + t.throws(() => validatePlugin('function'), new AVV_ERR_PLUGIN_NOT_VALID('string')) + t.throws(() => validatePlugin({}), new AVV_ERR_PLUGIN_NOT_VALID('object')) + t.throws(() => validatePlugin([]), new AVV_ERR_PLUGIN_NOT_VALID('array')) + t.throws(() => validatePlugin(null), new AVV_ERR_PLUGIN_NOT_VALID('null')) + + t.doesNotThrow(() => validatePlugin(function () {})) + t.doesNotThrow(() => validatePlugin(new Promise((resolve) => resolve))) + t.doesNotThrow(() => validatePlugin(Promise.resolve())) +})