All files after-if.ts

100% Statements 83/83
86.66% Branches 13/15
100% Functions 10/10
100% Lines 83/83

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 841x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 4x 4x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 4x 4x 4x 3x 4x 4x 3x 2x 2x 4x 4x 1x 1x 1x 1x 1x 1x 1x 1x 2x 2x 1x  
import { Rowan, Next, Processor } from "./rowan.js";
 
/**
 * A middleware container that executes its child middleware only if a predicate returns true,
 * and only after the next middleware in the chain has completed.
 * 
 * This is useful for conditional post-processing based on the results of upstream middleware.
 * The predicate is evaluated after next() has been called, allowing you to conditionally
 * execute middleware based on what happened during the main processing chain.
 * 
 * @template Ctx - The type of the context object
 * 
 * @example
 * ```typescript
 * const afterIf = new AfterIf(
 *   async (ctx) => ctx.success === true,
 *   [
 *     async (ctx) => console.log('Success handler'),
 *     async (ctx) => ctx.logSuccess = true
 *   ]
 * );
 * 
 * // Will only run success handlers if ctx.success is true after main processing
 * await afterIf.process(context, async () => {
 *   // Main processing logic
 *   context.success = true;
 * });
 * ```
 */
export class AfterIf<Ctx = any> extends Rowan<Ctx>{
  /**
   * Creates a new AfterIf middleware container.
   * 
   * @param predicate - Async function that determines whether to execute the middleware.
   *                   Called after next() has completed with the processed context.
   * @param middleware - Array of processors to execute if the predicate returns true
   * 
   * @example
   * ```typescript
   * const afterIf = new AfterIf(
   *   async (ctx) => ctx.statusCode === 200,
   *   [
   *     async (ctx) => ctx.cached = true,
   *     async (ctx) => console.log('Request successful')
   *   ]
   * );
   * ```
   */
  constructor(private predicate: (ctx: Ctx) => Promise<boolean>, middleware: Processor<Ctx>[]) {
    super(middleware);
  }
  
  /**
   * Processes the context by first calling next(), then evaluating the predicate,
   * and finally executing the child middleware if the predicate returns true.
   * 
   * @param ctx - The context object to process
   * @param next - Function to call the next middleware in the chain
   * @returns A Promise that resolves when processing is complete
   */
  process(ctx: Ctx, next: Next): Promise<void> {
    const self = this;
    return next()
      .then(function() { 
        return self.predicate(ctx); 
      })
      .then(function(r) {
        if (r) {
          return self.processInternal(ctx);
        }
      });
  }
 
  /**
   * Internal method to process child middleware without calling next.
   * 
   * @param ctx - The context object to process
   * @returns A Promise that resolves when child middleware processing is complete
   */
  private processInternal(ctx: Ctx): Promise<void> {
    return super.process(ctx);
  }
}