elif_core/errors/
core.rs

1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3use thiserror::Error;
4
5/// Core error type for the elif framework
6#[derive(Debug, Error)]
7pub enum CoreError {
8    #[error("IO error: {0}")]
9    Io(#[from] std::io::Error),
10    
11    #[error("YAML parsing error: {0}")]
12    Yaml(#[from] serde_yaml::Error),
13    
14    #[error("JSON parsing error: {0}")]
15    Json(#[from] serde_json::Error),
16    
17    #[error("Validation error: {message}")]
18    Validation { message: String },
19    
20    #[error("Configuration error: {message}")]
21    Configuration { message: String },
22    
23    #[error("Service not found: {service_type}")]
24    ServiceNotFound { service_type: String },
25    
26    #[error("Invalid service scope: {scope}")]
27    InvalidServiceScope { scope: String },
28    
29    #[error("Lock error on resource: {resource}")]
30    LockError { resource: String },
31    
32    #[error("Lifecycle error in component '{component}' during '{operation}': {source}")]
33    LifecycleError {
34        component: String,
35        operation: String,
36        source: Box<dyn std::error::Error + Send + Sync>,
37    },
38    
39    #[error("System error: {message}")]
40    SystemError {
41        message: String,
42        source: Option<Box<dyn std::error::Error + Send + Sync>>,
43    },
44    
45    #[error("Module error: {message}")]
46    Module { message: String },
47    
48    #[error("Provider error: {message}")]
49    Provider { message: String },
50    
51    #[error("Codegen error: {message}")]
52    Codegen { message: String },
53    
54    #[error("Template error: {message}")]
55    Template { message: String },
56    
57    #[error("Database error: {message}")]
58    Database { message: String },
59    
60    #[error("API error: {code} - {message}")]
61    Api {
62        code: String,
63        message: String,
64        hint: Option<String>,
65    },
66}
67
68impl CoreError {
69    /// Create a new validation error
70    pub fn validation(message: impl Into<String>) -> Self {
71        Self::Validation {
72            message: message.into(),
73        }
74    }
75    
76    /// Create a new configuration error
77    pub fn configuration(message: impl Into<String>) -> Self {
78        Self::Configuration {
79            message: message.into(),
80        }
81    }
82    
83    /// Create a new service not found error
84    pub fn service_not_found(service_type: impl Into<String>) -> Self {
85        Self::ServiceNotFound {
86            service_type: service_type.into(),
87        }
88    }
89    
90    /// Create a new system error
91    pub fn system_error(message: impl Into<String>) -> Self {
92        Self::SystemError {
93            message: message.into(),
94            source: None,
95        }
96    }
97    
98    /// Create a new system error with source
99    pub fn system_error_with_source(
100        message: impl Into<String>,
101        source: Box<dyn std::error::Error + Send + Sync>,
102    ) -> Self {
103        Self::SystemError {
104            message: message.into(),
105            source: Some(source),
106        }
107    }
108    
109    /// Create a new API error
110    pub fn api_error(code: impl Into<String>, message: impl Into<String>) -> Self {
111        Self::Api {
112            code: code.into(),
113            message: message.into(),
114            hint: None,
115        }
116    }
117    
118    /// Add a hint to an API error
119    pub fn with_hint(mut self, hint: impl Into<String>) -> Self {
120        if let Self::Api { hint: ref mut h, .. } = self {
121            *h = Some(hint.into());
122        }
123        self
124    }
125    
126    /// Check if the error is a validation error
127    pub fn is_validation(&self) -> bool {
128        matches!(self, Self::Validation { .. })
129    }
130    
131    /// Check if the error is a configuration error
132    pub fn is_configuration(&self) -> bool {
133        matches!(self, Self::Configuration { .. })
134    }
135    
136    /// Check if the error is a service error
137    pub fn is_service(&self) -> bool {
138        matches!(self, Self::ServiceNotFound { .. })
139    }
140}
141
142/// Error definition for the error catalog
143#[derive(Debug, Clone, Serialize, Deserialize)]
144pub struct ErrorDefinition {
145    pub code: String,
146    pub http: u16,
147    pub message: String,
148    pub hint: String,
149}
150
151/// API error response structure
152#[derive(Debug, Clone, Serialize, Deserialize)]
153pub struct ApiErrorResponse {
154    pub error: ApiError,
155}
156
157/// API error structure
158#[derive(Debug, Clone, Serialize, Deserialize)]
159pub struct ApiError {
160    pub code: String,
161    pub message: String,
162    pub hint: Option<String>,
163}
164
165impl ApiError {
166    /// Create a new API error
167    pub fn new(code: impl Into<String>, message: impl Into<String>) -> Self {
168        Self {
169            code: code.into(),
170            message: message.into(),
171            hint: None,
172        }
173    }
174    
175    /// Add a hint to the API error
176    pub fn with_hint(mut self, hint: impl Into<String>) -> Self {
177        self.hint = Some(hint.into());
178        self
179    }
180}
181
182impl From<CoreError> for ApiError {
183    fn from(error: CoreError) -> Self {
184        match error {
185            CoreError::Api { code, message, hint } => Self { code, message, hint },
186            CoreError::Validation { message } => Self::new("VALIDATION_ERROR", message),
187            CoreError::Configuration { message } => Self::new("CONFIG_ERROR", message),
188            CoreError::ServiceNotFound { service_type } => {
189                Self::new("SERVICE_NOT_FOUND", format!("Service not found: {}", service_type))
190            }
191            _ => Self::new("INTERNAL_ERROR", error.to_string()),
192        }
193    }
194}
195
196impl From<ApiError> for ApiErrorResponse {
197    fn from(error: ApiError) -> Self {
198        Self { error }
199    }
200}
201
202/// Type alias for error catalog
203pub type ErrorCatalog = HashMap<String, ErrorDefinition>;
204
205/// Legacy alias for backward compatibility
206pub type ElifError = CoreError;