UNPKG

3.12 kBJavaScriptView Raw
1'use strict'
2
3const semver = require('semver')
4const console = require('console')
5const extractPluginName = require('./stackParser')
6const { join, dirname } = require('path')
7
8let count = 0
9
10function plugin (fn, options = {}) {
11 let autoName = false
12
13 if (typeof fn.default !== 'undefined') { // Support for 'export default' behaviour in transpiled ECMAScript module
14 fn = fn.default
15 }
16
17 if (typeof fn !== 'function') {
18 throw new TypeError(`fastify-plugin expects a function, instead got a '${typeof fn}'`)
19 }
20
21 fn[Symbol.for('skip-override')] = true
22
23 const pluginName = (options && options.name) || checkName(fn)
24
25 if (typeof options === 'string') {
26 checkVersion(options, pluginName)
27 options = {}
28 }
29
30 if (typeof options !== 'object' || Array.isArray(options) || options === null) {
31 throw new TypeError('The options object should be an object')
32 }
33
34 if (!options.name) {
35 autoName = true
36 options.name = pluginName + '-auto-' + count++
37 }
38
39 fn[Symbol.for('fastify.display-name')] = options.name
40
41 if (options.fastify) {
42 checkVersion(options.fastify, pluginName)
43 }
44
45 fn[Symbol.for('plugin-meta')] = options
46
47 // Faux modules support
48 if (!fn.default) {
49 fn.default = fn
50 }
51
52 // TypeScript support for named imports
53 // See https://github.com/fastify/fastify/issues/2404 for more details
54 // The type definitions would have to be update to match this.
55 const camelCase = toCamelCase(options.name)
56 if (!autoName && !fn[camelCase]) {
57 fn[camelCase] = fn
58 }
59
60 return fn
61}
62
63function checkName (fn) {
64 if (fn.name.length > 0) return fn.name
65
66 try {
67 throw new Error('anonymous function')
68 } catch (e) {
69 return extractPluginName(e.stack)
70 }
71}
72
73function toCamelCase (name) {
74 const newName = name.replace(/-(.)/g, function (match, g1) {
75 return g1.toUpperCase()
76 })
77 return newName
78}
79
80function resolvePkgPath (mainFilename) {
81 return join(dirname(require.resolve('fastify', { paths: [mainFilename] })), 'package.json')
82}
83
84function checkVersion (version, pluginName) {
85 if (typeof version !== 'string') {
86 throw new TypeError(`fastify-plugin expects a version string, instead got '${typeof version}'`)
87 }
88
89 // TODO refactor this check and move it inside Fastify itself.
90 var fastifyVersion
91 try {
92 var pkgPath
93 if (require.main && require.main.filename) {
94 // We need to dynamically compute this to support yarn pnp
95 pkgPath = resolvePkgPath(require.main.filename)
96 } else if (process.argv[1]) {
97 // We need this to support native ESM context
98 pkgPath = resolvePkgPath(process.argv[1])
99 } else {
100 // In bundlers, there is no require.main.filename so we go ahead and require directly
101 pkgPath = 'fastify/package.json'
102 }
103
104 fastifyVersion = semver.coerce(require(pkgPath).version)
105 } catch (_) {
106 console.info('fastify not found, proceeding anyway')
107 }
108
109 if (fastifyVersion && !semver.satisfies(fastifyVersion, version)) {
110 throw new Error(`fastify-plugin: ${pluginName} - expected '${version}' fastify version, '${fastifyVersion}' is installed`)
111 }
112}
113
114module.exports = plugin