diff --git a/packages/hooks/src/base.ts b/packages/hooks/src/base.ts index 09d2881..57cd3c2 100644 --- a/packages/hooks/src/base.ts +++ b/packages/hooks/src/base.ts @@ -3,20 +3,38 @@ import { Middleware } from './compose'; export const HOOKS: string = Symbol('@feathersjs/hooks') as any; export const CONTEXT: string = Symbol('@feathersjs/hooks/context') as any; +function walkOriginal (fn: any, method: any, res: any[] = []): any { + return typeof fn.original === 'function' + ? walkOriginal(fn.original, method, [...res, ...method(fn)]) + : [...res, ...method(fn)]; +} + +export function getMiddleware (target: any): Array> { + return (target && target[HOOKS]) || []; +} + +export type MiddlewareSetter = (currentMiddleware: Middleware[]) => Middleware[]; + /** * @param target The target object or function - * @param middleware + * @param middleware or function */ -export function registerMiddleware (target: T, middleware: Middleware[]) { - const current: Middleware[] = (target as any)[HOOKS] || []; - - (target as any)[HOOKS] = current.concat(middleware); +export function setMiddleware (target: T, middleware: Middleware[] | MiddlewareSetter) { + (target as any)[HOOKS] = typeof middleware === 'function' ? middleware(getMiddleware(target)) : middleware; return target; } -export function getMiddleware (target: any): Array> { - return (target && target[HOOKS]) || []; +/** + * @param target The target object + * @param middleware or a function that takes current middleware as first argument + */ +export function registerMiddleware (target: T, middleware: Middleware[]) { + return setMiddleware(target, (current: Middleware[]) => current.concat(middleware)); +} + +export function getContextUpdater (target: any): Array> { + return (target && target[CONTEXT]) || []; } /** @@ -24,17 +42,13 @@ export function getMiddleware (target: any): Array> { * @param updaters */ export function registerContextUpdater (target: T, updaters: ContextUpdater[]) { - const current: ContextUpdater[] = (target as any)[CONTEXT] || []; + const current = getContextUpdater(target); (target as any)[CONTEXT] = current.concat(updaters); return target; } -export function getContextUpdater (target: any): Array> { - return (target && target[CONTEXT]) || []; -} - /** * The base hook context. */ diff --git a/packages/hooks/test/function.test.ts b/packages/hooks/test/function.test.ts index 7996c42..2e50c64 100644 --- a/packages/hooks/test/function.test.ts +++ b/packages/hooks/test/function.test.ts @@ -1,8 +1,8 @@ import { strict as assert } from 'assert'; import { hooks, HookContext, functionHooks, - NextFunction, getMiddleware, registerMiddleware, - withParams, withProps + NextFunction, getMiddleware, setMiddleware, registerMiddleware, + withParams, withProps, Middleware } from '../src/'; describe('functionHooks', () => { @@ -26,6 +26,24 @@ describe('functionHooks', () => { assert.deepEqual(getMiddleware(fn), []); }); + it('can manually set an array of middleware', () => { + const fn = hooks(hello, []) as any; + const mw = [(_ctx: any, next: any) => next()]; + + setMiddleware(fn, mw); + + assert.deepEqual(getMiddleware(fn), mw); + }); + + it('can manually set middleware with a function', () => { + const noop = (_ctx: any, next: any) => next(); + const fn = hooks(hello, [noop]) as any; + + setMiddleware(fn, (current: Middleware[]) => [...current, noop]); + + assert.deepEqual(getMiddleware(fn), [noop, noop]); + }); + it('can override arguments, has context', async () => { const addYou = async (ctx: HookContext, next: NextFunction) => { assert.ok(ctx instanceof HookContext);