class TransformationHookManager

Manages a collection of before/after/error hooks and executes them around each transformation in the pipeline.

Usage

import { FilterCompiler, TransformationHookManager } from '@jk-com/adblock-compiler';

const hookManager = new TransformationHookManager();

// Fluent registration
hookManager
  .onBeforeTransform((ctx) => console.log(`▶ ${ctx.name} — ${ctx.ruleCount} rules`))
  .onAfterTransform((ctx) => console.log(`✔ ${ctx.name} — ${ctx.durationMs.toFixed(2)}ms`))
  .onTransformError((ctx) => console.error(`✖ ${ctx.name}`, ctx.error));

const compiler = new FilterCompiler({ hookManager });
await compiler.compile(config);

Hook execution order

Hooks within each category are executed in registration order (FIFO). Each hook is await-ed before the next, so you can safely perform asynchronous work (e.g. writing to a database, emitting a metric) inside a hook without worrying about race conditions.

Error isolation

If a beforeTransform or afterTransform hook throws, the exception propagates up and will abort the pipeline. Wrap hook bodies in try-catch if you want them to be non-fatal.

onError hooks are also awaited sequentially before the pipeline re-throws the original transformation error — they are observers, not catch handlers.

Performance

When no hooks are registered hasHooks() returns false and the pipeline skips all hook-invocation overhead entirely. For zero-hook scenarios use NoOpHookManager (the default) which overrides the execute methods to be empty no-ops, completely eliminating even the hasHooks() check cost.

Constructors

new
TransformationHookManager(config?: TransformationHookConfig)

Creates a new TransformationHookManager.

Pass an initial TransformationHookConfig to bulk-register hooks in one call, or start with an empty manager and use the fluent on* methods:

// Declarative (all hooks at construction time)
const mgr = new TransformationHookManager(createLoggingHook(myLogger));

// Imperative (add hooks later)
const mgr = new TransformationHookManager();
mgr.onAfterTransform(myTimingHook);

Properties

Methods

clear(): void

Remove all registered hooks from this manager.

Useful in tests or when you want to reconfigure a manager without creating a new instance.

executeAfterHooks(context: TransformationHookContext & { inputCount: number; outputCount: number; durationMs: number; }): Promise<void>

Execute all registered afterTransform hooks in order.

Called by the pipeline immediately after a successful transformation.execute() call. Each hook is awaited sequentially. The context includes the wall-clock duration and rule counts for diffing.

Execute all registered beforeTransform hooks in order.

Called by the pipeline immediately before each transformation.execute() call. Each hook is awaited sequentially.

executeErrorHooks(context: TransformationHookContext & { error: Error; }): Promise<void>

Execute all registered onError hooks in order.

Called by the pipeline inside the try-catch that wraps each transformation.execute(). Each hook is awaited sequentially. After all hooks have run the pipeline re-throws the original error.

hasHooks(): boolean

Returns true if at least one hook of any type has been registered.

The TransformationPipeline calls this as a fast-path guard before each hook execution block. When no hooks are registered the pipeline avoids constructing context objects and awaiting async calls entirely, keeping the hot transform loop overhead at zero.

Register a hook to run after each transformation completes.

Multiple hooks can be registered; they fire in registration order.

Register a hook to run before each transformation.

Multiple hooks can be registered; they fire in registration order.

Register a hook to run when a transformation throws an error.

Error hooks are observers — they cannot suppress or replace the thrown error. After all error hooks complete, the pipeline re-throws the original error unchanged.