use std::path::Path; use serde_json::Value; use crate::error::{ConfigError, Result}; use crate::format::{self, ConfigLoader}; /// Extensiones adicionales para ConfigLoader pub trait ConfigLoaderExt: ConfigLoader { /// Carga la configuración como JSON genérico (sin deserializar a tipo /// específico) fn load_as_json() -> Result { let service = Self::service_name(); // Intenta cargar desde la jerarquía if let Some(path) = crate::hierarchy::resolve_config_path(service) { return format::load_config(&path); } // Fallback a defaults tracing::debug!("No config file found for {} - using empty object", service); Ok(Value::Object(serde_json::Map::new())) } /// Valida si la configuración está disponible fn is_available() -> bool { crate::hierarchy::resolve_config_path(Self::service_name()).is_some() } /// Obtiene el archivo de configuración que se usaría fn config_path() -> Option { crate::hierarchy::resolve_config_path(Self::service_name()) } } /// Implementa ConfigLoaderExt automáticamente para todos los ConfigLoader impl ConfigLoaderExt for T {} /// Utilidad para cargar y validar configuraciones genéricamente pub struct ConfigValidator; impl ConfigValidator { /// Valida que un archivo de configuración sea válido pub fn validate_file>(path: P) -> Result<()> { let _ = format::load_config(path)?; Ok(()) } /// Valida que el servicio tenga una configuración disponible pub fn validate_service() -> Result<()> { T::load().map(|_| ()).map_err(|e| { ConfigError::validation_failed(format!( "Service {} validation failed: {}", T::service_name(), e )) }) } /// Valida múltiples servicios en paralelo pub fn validate_services( services: Vec<(&'static str, fn() -> Result<()>)>, ) -> Result)>> { let mut results = Vec::new(); for (service_name, validator) in services { let result = validator(); results.push((service_name.to_string(), result)); } Ok(results) } } #[cfg(test)] mod tests { use super::*; #[test] fn test_config_validator_creates() { let _ = ConfigValidator; } }