emit method

  1. @override
Future emit(
  1. String eventName, {
  2. Future action(
    1. HHCtxI ctx
    )?,
  3. bool handleCtrlException = false,
})
override

Emits an event, executing all registered hooks for that event.

Implementation

@override
Future<dynamic> emit(
  String eventName, {
  Future Function(HHCtxI ctx)? action,
  bool handleCtrlException = false,
}) async {
  dynamic result;
  bool skipNextBatch = false;

  try {
    // Execute pre-action hooks
    if (!skipNextBatch) {
      final preHooks = ctx.config.preActionHooks[eventName] ?? [];
      // print(
      //   'DEBUG: Executing $eventName - preHooks count: ${preHooks.length}',
      // );
      for (var hook in preHooks) {
        try {
          await invoke(hook.action, handleCtrlException);
        } on HHCtrlException catch (e) {
          if (e.nextPhase == NextPhase.f_skip) {
            // Skip the next batch (main action)
            skipNextBatch = true;
            break;
          }
          rethrow;
        }
      }
    }

    // Execute the main action if provided
    if (action != null && !skipNextBatch) {
      try {
        result = await invoke(action, handleCtrlException);
      } on HHCtrlException catch (e) {
        if (e.nextPhase == NextPhase.f_skip) {
          // Skip the next batch (post hooks)
          skipNextBatch = true;
        } else {
          rethrow;
        }
      }
    }

    // Execute post-action hooks
    if (!skipNextBatch) {
      final postHooks = ctx.config.postActionHooks[eventName] ?? [];
      for (var hook in postHooks) {
        try {
          await invoke(hook.action, handleCtrlException);
        } on HHCtrlException catch (e) {
          if (e.nextPhase == NextPhase.f_skip) {
            // No more batches after post hooks
            break;
          }
          rethrow;
        }
      }
    }
  } on HHCtrlException catch (e) {
    // Handle phase control that affects the entire emit
    switch (e.nextPhase) {
      case NextPhase.f_break:
        // Break out of hook execution - return value
        return e.returnValue;

      case NextPhase.f_delete:
        // Delete the key
        if (ctx.payload.key != null) {
          await ctx.access.storeDelete(ctx.payload.key!);
          if (ctx.config.usesMeta) {
            await ctx.access.metaDelete(ctx.payload.key!);
          }
        }
        return e.returnValue;

      case NextPhase.f_pop:
        // Pop the key and return its value
        if (ctx.payload.key != null) {
          final value = await ctx.access.storePop(ctx.payload.key!);
          return value ?? e.returnValue;
        }
        return e.returnValue;

      case NextPhase.f_skip:
      case NextPhase.f_continue:
      case NextPhase.f_panic:
        // These shouldn't reach here, but rethrow if they do
        rethrow;
    }
  }

  return result;
}