executeHooks method
Future<Map<String, dynamic> >
executeHooks(
- HookStage stage,
- String flagKey,
- Map<
String, dynamic> ? context, { - dynamic result,
- Exception? error,
- EvaluationDetails? evaluationDetails,
- HookHints? hints,
- ClientMetadata? clientMetadata,
- ProviderMetadata? providerMetadata,
- dynamic defaultValue,
- FlagValueType? flagValueType,
- HookData? hookData,
- Iterable<
Hook> additionalHooks = const [], - List<
Hook> ? executionHooks, - void onContextChanged()?,
Execute hooks for a specific stage
Implementation
Future<Map<String, dynamic>> executeHooks(
HookStage stage,
String flagKey,
Map<String, dynamic>? context, {
dynamic result,
Exception? error,
EvaluationDetails? evaluationDetails,
HookHints? hints,
ClientMetadata? clientMetadata,
ProviderMetadata? providerMetadata,
dynamic defaultValue,
FlagValueType? flagValueType,
HookData? hookData,
Iterable<Hook> additionalHooks = const [],
List<Hook>? executionHooks,
void Function(Map<String, dynamic>)? onContextChanged,
}) async {
var currentContext = Map<String, dynamic>.from(context ?? const {});
final evaluationHookData = hookData ?? HookData();
final suppliedHints = hints ?? const HookHints();
final cleanup = stage == HookStage.ERROR || stage == HookStage.FINALLY;
for (final hook in _hooksForStage(stage, additionalHooks, executionHooks)) {
try {
final typed = hook is EvaluationHook;
final scopedData = evaluationHookData._scopeFor(hook);
// Capture before the provider await, including hooks with no before
// callback. Legacy hooks retain their original values and types.
final hookDefault = typed
? scopedData._captureDefault(defaultValue, cleanup: cleanup)
: defaultValue;
if (hook is EvaluationHook && !hook.stages.contains(stage)) continue;
final hookHints = typed ? suppliedHints.snapshot() : suppliedHints;
final hookDetails = typed
? evaluationDetails?._snapshot(cleanup: cleanup)
: evaluationDetails;
final hookContext = HookContext(
flagKey: flagKey,
evaluationContext: typed
? _snapshotHookValue(
currentContext,
cleanup: cleanup,
evaluationContext: true,
)
: currentContext,
result: typed ? _snapshotHookValue(result, cleanup: cleanup) : result,
error: error,
clientMetadata: clientMetadata,
providerMetadata: providerMetadata == null
? null
: ProviderMetadata(
name: providerMetadata.name,
version: providerMetadata.version,
attributes: Map.unmodifiable(providerMetadata.attributes),
),
defaultValue: hookDefault,
flagValueType: flagValueType,
hookData: scopedData,
hints: hookHints,
evaluationDetails: hookDetails,
);
final contextUpdates = await _executeHookWithTimeout(
hook,
stage,
hookContext,
hook.metadata.config.timeout,
hookDetails,
hints == null ? null : hookHints,
);
if (stage == HookStage.BEFORE &&
contextUpdates != null &&
contextUpdates.isNotEmpty) {
currentContext = {...currentContext, ...contextUpdates};
onContextChanged?.call(currentContext);
}
} catch (e) {
if (stage == HookStage.BEFORE || stage == HookStage.AFTER) {
rethrow;
}
// Error/finally failures cannot suppress remaining cleanup hooks.
}
}
return currentContext;
}