import { assertMethodDecorator } from "../common/decorators.js"; import type { Method } from "../common/types.js"; import { isPromise, resolveCallable, } from "../common/utils.js"; export interface BeforeConfig { func: ((...args: any[]) => unknown) | keyof This; wait?: boolean; } export function createBeforeMethod( originalMethod: Method, config: BeforeConfig, ): Method { const resolvedConfig = { wait: false, ...config, }; return function(this: This, ...args: Args): Return { const beforeFunc = resolveCallable(this, resolvedConfig.func); if (!resolvedConfig.wait) { beforeFunc(); return originalMethod.apply(this, args); } const beforeResult = beforeFunc(); if (isPromise(beforeResult)) { return Promise.resolve(beforeResult).then(() => { return originalMethod.apply(this, args); }) as Return; } return originalMethod.apply(this, args); } as Method; } export function before(config: BeforeConfig) { return function( value: Method, context: ClassMethodDecoratorContext>, ): Method { assertMethodDecorator("before", value, context); return createBeforeMethod(value, config); }; }