use crate::OrthoResult;
use figment::Figment;
use std::collections::HashSet;
use std::path::{Path, PathBuf};
use super::error::{file_error, invalid_data, invalid_input, not_found};
use super::loader::load_config_file_inner;
use super::path::resolve_base_path;
pub(super) fn get_extends(figment: &Figment, current_path: &Path) -> OrthoResult<Option<PathBuf>> {
match figment.find_value("extends") {
Ok(val) => {
let base = val.as_str().ok_or_else(|| {
let actual_type = match &val {
figment::value::Value::String(..) => "string",
figment::value::Value::Char(..) => "char",
figment::value::Value::Bool(..) => "bool",
figment::value::Value::Num(..) => "number",
figment::value::Value::Empty(..) => "null",
figment::value::Value::Dict(..) => "object",
figment::value::Value::Array(..) => "array",
};
invalid_data(
current_path,
format!("'extends' key must be a string, but found type: {actual_type}"),
)
})?;
if base.is_empty() {
return Err(invalid_data(
current_path,
"'extends' key must be a non-empty string",
));
}
Ok(Some(PathBuf::from(base)))
}
Err(e) if e.missing() => Ok(None),
Err(e) => Err(file_error(current_path, e)),
}
}
pub(super) fn merge_parent(figment: Figment, parent_figment: Figment) -> Figment {
parent_figment.merge(figment)
}
pub(super) fn process_extends(
mut figment: Figment,
current_path: &Path,
visited: &mut HashSet<PathBuf>,
stack: &mut Vec<PathBuf>,
) -> OrthoResult<Figment> {
if let Some(base) = get_extends(&figment, current_path)? {
let canonical = resolve_base_path(current_path, base)?;
if !canonical.is_file() {
return Err(invalid_input(
&canonical,
"extended path is not a regular file",
));
}
let Some(parent_fig) = load_config_file_inner(&canonical, visited, stack)? else {
return Err(not_found(
&canonical,
"extended file disappeared during load",
));
};
figment = merge_parent(figment, parent_fig);
}
Ok(figment)
}