HHImmutableConfig constructor
HHImmutableConfig({
- required String env,
- List<
HActionHook> actionHooks = const [], - bool usesMeta = true,
- List<
SerializationHook> serializationHooksParam = const [], - List<
TerminalSerializationHook> terminalSerializationHooksParam = const [],
Creates or retrieves an immutable configuration. Returns existing instance if one exists for the environment.
Implementation
factory HHImmutableConfig({
required String env,
List<HActionHook> actionHooks = const [],
bool usesMeta = true,
List<SerializationHook> serializationHooksParam = const [],
List<TerminalSerializationHook> terminalSerializationHooksParam = const [],
}) {
// env validation
if (env.startsWith('_')) {
throw ArgumentError(
'Environment name cannot start with an underscore (_).',
);
}
// If usesMeta is false, no action hooks are allowed
if (!usesMeta && actionHooks.isNotEmpty) {
throw ArgumentError(
'Action hooks are not allowed when usesMeta is false.',
);
}
if (_instances.containsKey(env)) {
final existingInstance = _instances[env]!;
// Check if settings are identical
final isIdentical =
existingInstance.actionHooks.length == actionHooks.length;
if (!isIdentical) {
throw ArgumentError(
'Config with env "$env" already exists with different settings.',
);
}
return existingInstance;
}
// Group hooks by event name and pre/post status
final Map<String, Set<HActionHook>> preHooks = {};
final Map<String, Set<HActionHook>> postHooks = {};
for (var hook in actionHooks) {
for (var latch in hook.latches) {
final eventName = latch.customEvent ?? latch.triggerType.name;
if (latch.isPost) {
postHooks.putIfAbsent(eventName, () => {}).add(hook);
} else {
preHooks.putIfAbsent(eventName, () => {}).add(hook);
}
}
}
// Sort each event's hooks by priority (higher priority first) and convert to lists
final Map<String, List<HActionHook>> sortedPreHooks = {};
preHooks.forEach((event, hooksSet) {
final hooksList = hooksSet.toList();
hooksList.sort((a, b) {
final aPriority = a.latches
.where(
(l) =>
(l.customEvent ?? l.triggerType.name) == event && !l.isPost,
)
.map((l) => l.priority)
.fold(0, (max, p) => p > max ? p : max);
final bPriority = b.latches
.where(
(l) =>
(l.customEvent ?? l.triggerType.name) == event && !l.isPost,
)
.map((l) => l.priority)
.fold(0, (max, p) => p > max ? p : max);
return bPriority.compareTo(aPriority);
});
sortedPreHooks[event] = hooksList;
});
final Map<String, List<HActionHook>> sortedPostHooks = {};
postHooks.forEach((event, hooksSet) {
final hooksList = hooksSet.toList();
hooksList.sort((a, b) {
final aPriority = a.latches
.where(
(l) => (l.customEvent ?? l.triggerType.name) == event && l.isPost,
)
.map((l) => l.priority)
.fold(0, (max, p) => p > max ? p : max);
final bPriority = b.latches
.where(
(l) => (l.customEvent ?? l.triggerType.name) == event && l.isPost,
)
.map((l) => l.priority)
.fold(0, (max, p) => p > max ? p : max);
return bPriority.compareTo(aPriority);
});
sortedPostHooks[event] = hooksList;
});
// Only store serialization hooks are used (metadata is always Map<String, dynamic>)
final storeSerializationHooks = serializationHooksParam
.where((hook) => hook.forStore)
.toList();
// Terminal serialization hooks - separate by context
final metaTerminalSerializationHooks = <TerminalSerializationHook>[];
final storeTerminalSerializationHooks = <TerminalSerializationHook>[];
// For now, all terminal hooks go to store (can be enhanced later)
storeTerminalSerializationHooks.addAll(terminalSerializationHooksParam);
final newInstance = HHImmutableConfig._internal(
sortedPreHooks,
sortedPostHooks,
storeSerializationHooks,
metaTerminalSerializationHooks,
storeTerminalSerializationHooks,
env: env,
usesMeta: usesMeta,
actionHooks: actionHooks,
serializationHooks: serializationHooksParam,
terminalSerializationHooks: terminalSerializationHooksParam,
);
_instances[env] = newInstance;
return newInstance;
}