From c534827d539faab885f84d035e2edb912770759f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Berthommier?= Date: Sat, 15 Feb 2020 18:55:20 +0100 Subject: [PATCH] feat: Chainable configuration (#23) --- packages/hooks/src/decorator.ts | 19 +++++++++++++++-- packages/hooks/src/function.ts | 9 ++++++-- packages/hooks/src/index.ts | 5 +++-- packages/hooks/test/function.test.ts | 32 ++++++++++++++++++++++++++++ 4 files changed, 59 insertions(+), 6 deletions(-) diff --git a/packages/hooks/src/decorator.ts b/packages/hooks/src/decorator.ts index fd63d84..5ae7c89 100644 --- a/packages/hooks/src/decorator.ts +++ b/packages/hooks/src/decorator.ts @@ -1,8 +1,13 @@ import { functionHooks } from './function'; -import { HookContext, registerMiddleware, normalizeOptions, HookSettings } from './base'; +import { + HookContext, + registerMiddleware, + normalizeOptions, + HookSettings, withParams +} from './base'; export const hookDecorator = (hooks: HookSettings = []) => { - return (_target: any, method: string, descriptor: TypedPropertyDescriptor): TypedPropertyDescriptor => { + const wrapper: any = (_target: any, method: string, descriptor: TypedPropertyDescriptor): TypedPropertyDescriptor => { const { context, ...options } = normalizeOptions(hooks); if (!descriptor) { @@ -29,4 +34,14 @@ export const hookDecorator = (hooks: HookSettings = []) => { return descriptor; }; + + function params (...args: Array): typeof wrapper { + const { context, ...options } = normalizeOptions(hooks); + return { + ...options, + context: [...context, withParams(...args)] + }; + } + + return Object.assign(wrapper, { params }); }; diff --git a/packages/hooks/src/function.ts b/packages/hooks/src/function.ts index 9056a03..7709f68 100644 --- a/packages/hooks/src/function.ts +++ b/packages/hooks/src/function.ts @@ -5,7 +5,8 @@ import { registerContextUpdater, normalizeOptions, collectContextUpdaters, - HookSettings + HookSettings, + withParams } from './base'; function getOriginal (fn: any): any { @@ -79,5 +80,9 @@ export const functionHooks = (original: F, opts: HookSettings) => } } - return Object.assign(wrapper, { original, collect }); + function params (...args: Array): typeof wrapper { + return registerContextUpdater(wrapper, [withParams(...args)]); + } + + return Object.assign(wrapper, { original, collect, params }); }; diff --git a/packages/hooks/src/index.ts b/packages/hooks/src/index.ts index 6854f5a..4f05632 100644 --- a/packages/hooks/src/index.ts +++ b/packages/hooks/src/index.ts @@ -7,14 +7,15 @@ export * from './function'; export * from './compose'; export * from './base'; -export interface OriginalAddon { +export interface WrapperAddon { original: F; + params: (...params: Array) => F&((...rest: any[]) => Promise); } // hooks(fn, hookSettings) export function hooks ( fn: F, hooks: HookSettings -): F&((...rest: any[]) => Promise)&OriginalAddon; +): F&((...rest: any[]) => Promise)&WrapperAddon; // hooks(object, hookMap) export function hooks (obj: O, hookMap: HookMap): O; // @hooks(hookSettings) diff --git a/packages/hooks/test/function.test.ts b/packages/hooks/test/function.test.ts index 92bd0f4..9767025 100644 --- a/packages/hooks/test/function.test.ts +++ b/packages/hooks/test/function.test.ts @@ -326,6 +326,38 @@ describe('functionHooks', () => { assert.equal(called, 1); }); + it('is chainable with .params on function', async () => { + const hook = async function (this: any, context: HookContext, next: NextFunction) { + await next(); + context.result += '!'; + }; + const exclamation = hooks(hello, [hook]).params(['name', 'Dave']); + + const result = await exclamation(); + + assert.equal(result, 'Hello Dave!'); + }); + + it('is chainable with .params on object', async () => { + const hook = async function (this: any, context: HookContext, next: NextFunction) { + await next(); + context.result += '!'; + }; + const obj = { + sayHi (name: any) { + return `Hi ${name}`; + } + }; + + hooks(obj, { + sayHi: hooks([hook]).params('name') + }); + + const result = await obj.sayHi('Dave'); + + assert.equal(result, 'Hi Dave!'); + }); + it('conserves method properties', async () => { const TEST = Symbol('test'); const hello = (name: any) => `Hi ${name}`;