mirror of
				https://github.com/NodeBB/NodeBB.git
				synced 2025-10-27 17:16:14 +01:00 
			
		
		
		
	feat: allow filter functions that return promises or the data directly
This commit is contained in:
		| @@ -1,6 +1,5 @@ | |||||||
| 'use strict'; | 'use strict'; | ||||||
|  |  | ||||||
| const async = require('async'); |  | ||||||
| const util = require('util'); | const util = require('util'); | ||||||
| const winston = require('winston'); | const winston = require('winston'); | ||||||
| const plugins = require('.'); | const plugins = require('.'); | ||||||
| @@ -116,37 +115,38 @@ async function fireFilterHook(hook, hookList, params) { | |||||||
| 	if (!Array.isArray(hookList) || !hookList.length) { | 	if (!Array.isArray(hookList) || !hookList.length) { | ||||||
| 		return params; | 		return params; | ||||||
| 	} | 	} | ||||||
| 	return await async.reduce(hookList, params, (params, hookObj, next) => { |  | ||||||
|  | 	async function fireMethod(hookObj, params) { | ||||||
| 		if (typeof hookObj.method !== 'function') { | 		if (typeof hookObj.method !== 'function') { | ||||||
| 			if (global.env === 'development') { | 			if (global.env === 'development') { | ||||||
| 				winston.warn(`[plugins] Expected method for hook '${hook}' in plugin '${hookObj.id}' not found, skipping.`); | 				winston.warn(`[plugins] Expected method for hook '${hook}' in plugin '${hookObj.id}' not found, skipping.`); | ||||||
| 			} | 			} | ||||||
| 			return next(null, params); | 			return params; | ||||||
| 		} | 		} | ||||||
| 		const returned = hookObj.method(params, next); |  | ||||||
| 		if (utils.isPromise(returned)) { | 		if (hookObj.method.constructor && hookObj.method.constructor.name === 'AsyncFunction') { | ||||||
| 			returned.then( | 			return await hookObj.method(params); | ||||||
| 				payload => setImmediate(next, null, payload), |  | ||||||
| 				err => setImmediate(next, err) |  | ||||||
| 			); |  | ||||||
| 		} | 		} | ||||||
| 	}); | 		return new Promise((resolve, reject) => { | ||||||
| 	// breaks plugins that use a non-async function ie emoji-one parse.raw | 			const returned = hookObj.method(params, (err, result) => { | ||||||
| 	// for (const hookObj of hookList) { | 				if (err) reject(err); else resolve(result); | ||||||
| 	// 	if (typeof hookObj.method !== 'function') { | 			}); | ||||||
| 	// 		if (global.env === 'development') { |  | ||||||
| 	// 			winston.warn(`[plugins] Expected method for hook '${hook}' in plugin '${hookObj.id}' not found, skipping.`); | 			if (utils.isPromise(returned)) { | ||||||
| 	// 		} | 				returned.then( | ||||||
| 	// 	} else { | 					payload => resolve(payload), | ||||||
| 	// 		let hookFn = hookObj.method; | 					err => reject(err) | ||||||
| 	// 		if (hookFn.constructor && hookFn.constructor.name !== 'AsyncFunction') { | 				); | ||||||
| 	// 			hookFn = util.promisify(hookFn); | 				return; | ||||||
| 	// 		} | 			} | ||||||
| 	// 		// eslint-disable-next-line | 			resolve(returned); | ||||||
| 	// 		params = await hookFn(params); | 		}); | ||||||
| 	// 	} | 	} | ||||||
| 	// } | 	for (const hookObj of hookList) { | ||||||
| 	// return params; | 		// eslint-disable-next-line | ||||||
|  | 		params = await fireMethod(hookObj, params); | ||||||
|  | 	} | ||||||
|  | 	return params; | ||||||
| } | } | ||||||
|  |  | ||||||
| async function fireActionHook(hook, hookList, params) { | async function fireActionHook(hook, hookList, params) { | ||||||
|   | |||||||
| @@ -47,7 +47,7 @@ describe('Plugins', () => { | |||||||
| 		}); | 		}); | ||||||
| 	}); | 	}); | ||||||
|  |  | ||||||
| 	it('should register and fire a filter hook having 2 methods, one returning a promise and the other calling the callback', (done) => { | 	it('should register and fire a filter hook having 3 methods, one returning a promise, one calling the callback and one just returning', async () => { | ||||||
| 		function method1(data, callback) { | 		function method1(data, callback) { | ||||||
| 			data.foo += 1; | 			data.foo += 1; | ||||||
| 			callback(null, data); | 			callback(null, data); | ||||||
| @@ -58,15 +58,17 @@ describe('Plugins', () => { | |||||||
| 				resolve(data); | 				resolve(data); | ||||||
| 			}); | 			}); | ||||||
| 		} | 		} | ||||||
|  | 		function method3(data) { | ||||||
|  | 			data.foo += 1; | ||||||
|  | 			return data; | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		plugins.hooks.register('test-plugin', { hook: 'filter:test.hook2', method: method1 }); | 		plugins.hooks.register('test-plugin', { hook: 'filter:test.hook2', method: method1 }); | ||||||
| 		plugins.hooks.register('test-plugin', { hook: 'filter:test.hook2', method: method2 }); | 		plugins.hooks.register('test-plugin', { hook: 'filter:test.hook2', method: method2 }); | ||||||
|  | 		plugins.hooks.register('test-plugin', { hook: 'filter:test.hook2', method: method3 }); | ||||||
|  |  | ||||||
| 		plugins.hooks.fire('filter:test.hook2', { foo: 1 }, (err, data) => { | 		const data = await plugins.hooks.fire('filter:test.hook2', { foo: 1 }); | ||||||
| 			assert.ifError(err); | 		assert.strictEqual(data.foo, 8); | ||||||
| 			assert.equal(data.foo, 7); |  | ||||||
| 			done(); |  | ||||||
| 		}); |  | ||||||
| 	}); | 	}); | ||||||
|  |  | ||||||
| 	it('should register and fire a filter hook that returns a promise that gets rejected', (done) => { | 	it('should register and fire a filter hook that returns a promise that gets rejected', (done) => { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user