UNPKG

fastify

Version:

Fast and low overhead web framework, for Node.js

168 lines (139 loc) 4.59 kB
'use strict' const semver = require('semver') const assert = require('node:assert') const kRegisteredPlugins = Symbol.for('registered-plugin') const { kTestInternals } = require('./symbols.js') const { exist, existReply, existRequest } = require('./decorate') const { FST_ERR_PLUGIN_VERSION_MISMATCH, FST_ERR_PLUGIN_NOT_PRESENT_IN_INSTANCE } = require('./errors') const { FSTWRN002 } = require('./warnings.js') function getMeta (fn) { return fn[Symbol.for('plugin-meta')] } function getPluginName (func) { const display = getDisplayName(func) if (display) { return display } // let's see if this is a file, and in that case use that // this is common for plugins const cache = require.cache // cache is undefined inside SEA if (cache) { const keys = Object.keys(cache) for (let i = 0; i < keys.length; i++) { const key = keys[i] if (cache[key].exports === func) { return key } } } // if not maybe it's a named function, so use that if (func.name) { return func.name } return null } function getFuncPreview (func) { // takes the first two lines of the function if nothing else works return func.toString().split('\n').slice(0, 2).map(s => s.trim()).join(' -- ') } function getDisplayName (fn) { return fn[Symbol.for('fastify.display-name')] } function shouldSkipOverride (fn) { return !!fn[Symbol.for('skip-override')] } function checkDependencies (fn) { const meta = getMeta(fn) if (!meta) return const dependencies = meta.dependencies if (!dependencies) return assert(Array.isArray(dependencies), 'The dependencies should be an array of strings') dependencies.forEach(dependency => { assert( this[kRegisteredPlugins].indexOf(dependency) > -1, `The dependency '${dependency}' of plugin '${meta.name}' is not registered` ) }) } function checkDecorators (fn) { const meta = getMeta(fn) if (!meta) return const { decorators, name } = meta if (!decorators) return if (decorators.fastify) _checkDecorators(this, 'Fastify', decorators.fastify, name) if (decorators.reply) _checkDecorators(this, 'Reply', decorators.reply, name) if (decorators.request) _checkDecorators(this, 'Request', decorators.request, name) } const checks = { Fastify: exist, Request: existRequest, Reply: existReply } function _checkDecorators (that, instance, decorators, name) { assert(Array.isArray(decorators), 'The decorators should be an array of strings') decorators.forEach(decorator => { const withPluginName = typeof name === 'string' ? ` required by '${name}'` : '' if (!checks[instance].call(that, decorator)) { throw new FST_ERR_PLUGIN_NOT_PRESENT_IN_INSTANCE(decorator, withPluginName, instance) } }) } function checkVersion (fn) { const meta = getMeta(fn) if (!meta) return const requiredVersion = meta.fastify const fastifyRc = /-rc.+$/.test(this.version) if (fastifyRc === true && semver.gt(this.version, semver.coerce(requiredVersion)) === true) { // A Fastify release candidate phase is taking place. In order to reduce // the effort needed to test plugins with the RC, we allow plugins targeting // the prior Fastify release to be loaded. return } if (requiredVersion && semver.satisfies(this.version, requiredVersion, { includePrerelease: fastifyRc }) === false) { // We are not in a release candidate phase. Thus, we must honor the semver // ranges defined by the plugin's metadata. Which is to say, if the plugin // expects an older version of Fastify than the _current_ version, we will // throw an error. throw new FST_ERR_PLUGIN_VERSION_MISMATCH(meta.name, requiredVersion, this.version) } } function registerPluginName (fn) { const meta = getMeta(fn) if (!meta) return const name = meta.name if (!name) return this[kRegisteredPlugins].push(name) return name } function checkPluginHealthiness (fn, pluginName) { if (fn.constructor.name === 'AsyncFunction' && fn.length === 3) { FSTWRN002(pluginName || 'anonymous') } } function registerPlugin (fn) { const pluginName = registerPluginName.call(this, fn) || getPluginName(fn) checkPluginHealthiness.call(this, fn, pluginName) checkVersion.call(this, fn) checkDecorators.call(this, fn) checkDependencies.call(this, fn) return shouldSkipOverride(fn) } module.exports = { getPluginName, getFuncPreview, kRegisteredPlugins, getDisplayName, registerPlugin } module.exports[kTestInternals] = { shouldSkipOverride, getMeta, checkDecorators, checkDependencies }