import type { HookContext, NextFunction } from '@feathersjs/feathers' import type { HookFunction, PredicateFn } from '../../types.js' /** * Wraps a hook so it can be conditionally skipped based on a predicate. * When the predicate returns `true`, the wrapped hook is skipped entirely. * Commonly used with `shouldSkip` and `addSkip` for runtime hook control. * * @example * ```ts * import { skippable, shouldSkip } from 'feathers-utils/predicates' * * const myHook = skippable(someHook(), shouldSkip('someHook')) * ``` * * @see https://utils.feathersjs.com/hooks/skippable.html */ export const skippable = ( innerHook: HookFunction, predicate: PredicateFn, ) => { function hook(context: H): H | void | Promise function hook(context: H, next: NextFunction): Promise function hook(context: H, next?: NextFunction): H | void | Promise { const skip = predicate(context) const skipOrRun = (shouldSkip: boolean): H | void | Promise => { if (shouldSkip) { if (next) return next() return } if (next) return innerHook(context, next) as Promise // before/after mode: return the inner hook's result so an async hook is // awaited and a returned/modified context is propagated to the pipeline. return innerHook(context) } if (!skip || typeof skip === 'boolean') { return skipOrRun(skip) } return skip.then(skipOrRun) as Promise } return hook }