|
type Promised<R> = R | PromiseLike<R>; |
|
export type Descriptor<A extends any[], R> = (...args: A) => Promised<R>; |
|
export type Decorator<A extends any[], R> = ( |
|
descriptor: Descriptor<A, R>, |
|
) => Promised<Descriptor<A, R>>; |
|
|
|
export type DescriptorSync<A extends any[], R> = (...args: A) => R; |
|
export type DecoratorSync<A extends any[], R> = ( |
|
descriptor: DescriptorSync<A, R>, |
|
) => DescriptorSync<A, R>; |
|
|
|
/** |
|
* @example |
|
* const decorated = decorate(n => n, increaseBy1, increaseBy2, increaseBy3); |
|
* decorated(1); // => 7 |
|
* @param descriptor |
|
* @param decorators |
|
* @returns a new descriptor wrapped |
|
*/ |
|
export const decorate = <A extends any[], R>( |
|
descriptor: Descriptor<A, R>, |
|
...decorators: Decorator<A, R>[] |
|
) => { |
|
return async function (this: unknown, ...args: A): Promise<R> { |
|
const newDescriptor = decorators.reduce( |
|
( |
|
descriptor: Descriptor<A, R>, |
|
decorator: Decorator<A, R>, |
|
): Descriptor<A, R> => { |
|
return async (...args: A): Promise<R> => { |
|
const nextDescriptor = await Promise.resolve( |
|
decorator.call(this, descriptor), |
|
); |
|
return await Promise.resolve(nextDescriptor.call(this, ...args)); |
|
}; |
|
}, |
|
descriptor.bind(this), |
|
); |
|
return await newDescriptor(...args); |
|
}; |
|
}; |
|
|
|
/** |
|
* @example |
|
* const decorated = decorate(n => n, increaseBy1, increaseBy2, increaseBy3); |
|
* decorated(1); // => 7 |
|
* @param descriptor |
|
* @param decorators |
|
* @returns a new descriptor wrapped |
|
*/ |
|
export const decorateSync = <A extends any[], R>( |
|
descriptor: DescriptorSync<A, R>, |
|
...decorators: DecoratorSync<A, R>[] |
|
) => { |
|
return function (this: unknown, ...args: A): R { |
|
const newDescriptor = decorators.reduce( |
|
( |
|
descriptor: DescriptorSync<A, R>, |
|
decorator: DecoratorSync<A, R>, |
|
): DescriptorSync<A, R> => { |
|
return (...args: A): R => { |
|
const nextDescriptor = decorator.call(this, descriptor); |
|
return nextDescriptor.call(this, ...args); |
|
}; |
|
}, |
|
descriptor.bind(this), |
|
); |
|
return newDescriptor(...args); |
|
}; |
|
}; |