use mycelium_base::utils::errors::{execution_err, MappedErrors};
use serde_json::Value;
pub(crate) fn resolve_refs(
value: &mut Value,
current_depth: usize,
max_depth: usize,
components: &Value,
) -> Result<Value, MappedErrors> {
if current_depth > max_depth {
return Ok(value.clone());
}
match value {
Value::Object(map) => {
for (k, v) in map.iter_mut() {
if k == "$ref"
&& v.is_string()
&& v.as_str().unwrap_or("").starts_with("#/components/")
{
if let Value::String(s) = v {
let resolved_value = resolver_fn(s, components)?;
*v = resolved_value.to_owned();
}
continue;
}
resolve_refs(v, current_depth + 1, max_depth, components)?;
}
}
Value::Array(arr) => {
for item in arr {
resolve_refs(item, current_depth + 1, max_depth, components)?;
}
}
_ => {}
}
Ok(value.clone())
}
fn resolver_fn(
ref_path: &str,
components: &Value,
) -> Result<Value, MappedErrors> {
let splitted_ref_path = ref_path.split('/').collect::<Vec<&str>>();
let default_string = String::new();
let element_definition = if splitted_ref_path.len() > 2 {
splitted_ref_path[splitted_ref_path.len() - 2]
} else {
return execution_err(format!(
"Failed to resolve schema ref. Unable to get the component name from reference: {:?}",
ref_path
)).as_error();
};
let element_name = splitted_ref_path.last().ok_or(execution_err(format!(
"Failed to resolve schema ref. Unable to get the component name from reference: {:?}",
default_string
)))?;
let ref_value = components
.get("components")
.and_then(|schema| schema.get(element_definition))
.and_then(|schema| schema.get(element_name))
.ok_or(
execution_err(format!("Failed to resolve schema ref: {ref_path}"))
.with_exp_true(),
)?;
Ok(ref_value.to_owned())
}