1use miyabi_types::error::{ErrorCode, UnifiedError};
2use std::any::Any;
3use thiserror::Error;
4
5#[derive(Debug, Error)]
6pub enum ModeError {
7 #[error("Mode not found: {0}")]
8 ModeNotFound(String),
9
10 #[error("Duplicate mode slug: {0}")]
11 DuplicateSlug(String),
12
13 #[error("Invalid mode definition: {0}")]
14 InvalidDefinition(String),
15
16 #[error("YAML parsing error: {0}")]
17 YamlError(#[from] serde_yaml::Error),
18
19 #[error("IO error: {0}")]
20 IoError(#[from] std::io::Error),
21
22 #[error("Invalid file regex: {0}")]
23 InvalidRegex(#[from] regex::Error),
24
25 #[error("Mode validation failed: {0}")]
26 ValidationFailed(String),
27
28 #[error("Missing required field: {0}")]
29 MissingField(String),
30}
31
32pub type ModeResult<T> = Result<T, ModeError>;
33
34impl UnifiedError for ModeError {
39 fn code(&self) -> ErrorCode {
40 match self {
41 Self::ModeNotFound(_) => ErrorCode::FILE_NOT_FOUND,
42 Self::DuplicateSlug(_) => ErrorCode::VALIDATION_ERROR,
43 Self::InvalidDefinition(_) => ErrorCode::INVALID_CONFIG,
44 Self::YamlError(_) => ErrorCode::PARSE_ERROR,
45 Self::IoError(e) => match e.kind() {
46 std::io::ErrorKind::NotFound => ErrorCode::FILE_NOT_FOUND,
47 std::io::ErrorKind::PermissionDenied => ErrorCode::PERMISSION_DENIED,
48 _ => ErrorCode::IO_ERROR,
49 },
50 Self::InvalidRegex(_) => ErrorCode::REGEX_ERROR,
51 Self::ValidationFailed(_) => ErrorCode::VALIDATION_ERROR,
52 Self::MissingField(_) => ErrorCode::MISSING_CONFIG,
53 }
54 }
55
56 fn user_message(&self) -> String {
57 match self {
58 Self::ModeNotFound(name) => format!(
59 "Mode '{}' was not found. Please check the mode name and ensure it has been registered.",
60 name
61 ),
62 Self::DuplicateSlug(slug) => format!(
63 "A mode with slug '{}' already exists. Please use a different slug for your mode.",
64 slug
65 ),
66 Self::InvalidDefinition(msg) => format!(
67 "Invalid mode definition: {}. Please check your mode configuration.",
68 msg
69 ),
70 Self::YamlError(e) => format!(
71 "Failed to parse YAML configuration: {}. Please check your YAML syntax.",
72 e
73 ),
74 Self::InvalidRegex(e) => format!(
75 "Invalid file pattern regex: {}. Please check your regex syntax.",
76 e
77 ),
78 Self::ValidationFailed(msg) => format!(
79 "Mode validation failed: {}. Please review your mode configuration.",
80 msg
81 ),
82 Self::MissingField(field) => format!(
83 "Required field '{}' is missing from mode configuration. Please add this field.",
84 field
85 ),
86 _ => self.to_string(),
88 }
89 }
90
91 fn context(&self) -> Option<&dyn Any> {
92 match self {
93 Self::ModeNotFound(name) => Some(name as &dyn Any),
94 Self::DuplicateSlug(slug) => Some(slug as &dyn Any),
95 Self::InvalidDefinition(msg) => Some(msg as &dyn Any),
96 Self::ValidationFailed(msg) => Some(msg as &dyn Any),
97 Self::MissingField(field) => Some(field as &dyn Any),
98 _ => None,
99 }
100 }
101}
102
103#[cfg(test)]
104mod unified_error_tests {
105 use super::*;
106
107 #[test]
108 fn test_mode_error_codes() {
109 let error = ModeError::ModeNotFound("test".to_string());
110 assert_eq!(error.code(), ErrorCode::FILE_NOT_FOUND);
111
112 let error = ModeError::DuplicateSlug("test".to_string());
113 assert_eq!(error.code(), ErrorCode::VALIDATION_ERROR);
114
115 let error = ModeError::InvalidDefinition("test".to_string());
116 assert_eq!(error.code(), ErrorCode::INVALID_CONFIG);
117
118 let error = ModeError::ValidationFailed("test".to_string());
119 assert_eq!(error.code(), ErrorCode::VALIDATION_ERROR);
120
121 let error = ModeError::MissingField("name".to_string());
122 assert_eq!(error.code(), ErrorCode::MISSING_CONFIG);
123 }
124
125 #[test]
126 fn test_user_messages() {
127 let error = ModeError::ModeNotFound("custom-mode".to_string());
128 let msg = error.user_message();
129 assert!(msg.contains("custom-mode"));
130 assert!(msg.contains("not found"));
131
132 let error = ModeError::DuplicateSlug("my-mode".to_string());
133 let msg = error.user_message();
134 assert!(msg.contains("my-mode"));
135 assert!(msg.contains("already exists"));
136
137 let error = ModeError::MissingField("description".to_string());
138 let msg = error.user_message();
139 assert!(msg.contains("description"));
140 assert!(msg.contains("missing"));
141 }
142
143 #[test]
144 fn test_context_extraction() {
145 let error = ModeError::ModeNotFound("test".to_string());
146 assert!(error.context().is_some());
147
148 let error = ModeError::DuplicateSlug("test".to_string());
149 assert!(error.context().is_some());
150
151 let error = ModeError::MissingField("name".to_string());
152 assert!(error.context().is_some());
153
154 let error = ModeError::IoError(std::io::Error::other("test"));
155 assert!(error.context().is_none());
156 }
157}