use serde_json::{Value, json};
use crate::error::CliError;
pub(crate) fn merge_hooks(existing: Value, generated: Value) -> Result<Value, CliError> {
let mut root = hook_config_root(existing)?;
let hooks = hooks_object_mut(&mut root)?;
let generated_hooks = generated_hooks_object(&generated)?;
for (event, groups) in generated_hooks {
merge_event_hook_groups(hooks, event, groups)?;
}
Ok(root)
}
pub(super) fn hook_config_root(existing: Value) -> Result<Value, CliError> {
match existing {
Value::Null => Ok(json!({})),
Value::Object(object) => Ok(Value::Object(object)),
_ => Err(CliError::Install(
"hook config must be a JSON object".into(),
)),
}
}
pub(super) fn hooks_object_mut(
root: &mut Value,
) -> Result<&mut serde_json::Map<String, Value>, CliError> {
root.as_object_mut()
.expect("root checked as object")
.entry("hooks")
.or_insert_with(|| json!({}))
.as_object_mut()
.ok_or_else(|| CliError::Install("hooks must be a JSON object".into()))
}
pub(super) fn generated_hooks_object(
generated: &Value,
) -> Result<&serde_json::Map<String, Value>, CliError> {
generated
.get("hooks")
.and_then(Value::as_object)
.ok_or_else(|| CliError::Install("generated hooks were malformed".into()))
}
pub(super) fn merge_event_hook_groups(
hooks: &mut serde_json::Map<String, Value>,
event: &str,
groups: &Value,
) -> Result<(), CliError> {
let groups = groups
.as_array()
.ok_or_else(|| CliError::Install("generated hook groups were malformed".into()))?;
let event_groups = hooks.entry(event.to_string()).or_insert_with(|| json!([]));
let event_groups = event_groups
.as_array_mut()
.ok_or_else(|| CliError::Install(format!("{event} hooks must be an array")))?;
for group in groups {
if !event_groups.iter().any(|existing| existing == group) {
event_groups.push(group.clone());
}
}
Ok(())
}