registerModules static method

Future<void> registerModules(
  1. List<ZenModule> modules,
  2. ZenScope scope
)

Register and load modules atomically with dependency resolution

Implementation

static Future<void> registerModules(
    List<ZenModule> modules, ZenScope scope) async {
  if (modules.isEmpty) return;

  // Store original state for rollback
  final originalScopeState = _captureOriginalScopeState(scope);
  final originalModules = Map<String, ZenModule>.from(_modules);

  try {
    // 1. Collect all dependencies
    final allModules = _collectAllDependencies(modules);

    // 2. Validate no circular dependencies (can throw StateError)
    _validateDependencyGraph(allModules);

    // 3. Calculate load order
    final loadOrder = _calculateLoadOrder(allModules);

    ZenLogger.logInfo(
        'Loading ${loadOrder.length} modules: ${loadOrder.map((m) => m.name).join(' -> ')}');

    // 4. Load modules in dependency order (this can fail)
    for (final module in loadOrder) {
      // Register dependencies (this can throw)
      module.register(scope);

      // Initialize (this can throw)
      await module.onInit(scope);

      // Only add to registry after successful registration and init
      _modules[module.name] = module;

      ZenLogger.logDebug('✅ Loaded: ${module.name}');
    }

    ZenLogger.logInfo(
        '✅ Successfully loaded all ${loadOrder.length} modules');
  } catch (error, stackTrace) {
    // Rollback: restore original module registry
    _modules.clear();
    _modules.addAll(originalModules);

    // Rollback: restore original scope state
    _restoreOriginalScopeState(scope, originalScopeState);

    // Log the failure
    ZenLogger.logError('Module registration failed', error, stackTrace);

    // Re-throw original error without wrapping to preserve type
    rethrow;
  }
}