1use std::path::PathBuf;
4
5use thiserror::Error;
6
7pub type Result<T> = std::result::Result<T, CoreError>;
9
10#[derive(Error, Debug)]
12pub enum CoreError {
13 #[error("Configuration error: {message}")]
15 Config {
16 message: String,
17 #[source]
18 source: Option<Box<dyn std::error::Error + Send + Sync>>,
19 },
20
21 #[error("Parse error in {path}: {message}")]
23 Parse { path: PathBuf, message: String },
24
25 #[error("Frontmatter error in {path}: {message}")]
27 Frontmatter { path: PathBuf, message: String },
28
29 #[error("Template error: {0}")]
31 Template(String),
32
33 #[error("Search error: {0}")]
35 Search(String),
36
37 #[error("IO error: {0}")]
39 Io(#[from] std::io::Error),
40
41 #[error("TOML parse error: {0}")]
43 Toml(#[from] toml::de::Error),
44
45 #[error("YAML parse error: {0}")]
47 Yaml(#[from] serde_yaml::Error),
48
49 #[error("Config crate error: {0}")]
51 ConfigCrate(#[from] config::ConfigError),
52}
53
54impl CoreError {
55 pub fn config(message: impl Into<String>) -> Self {
57 Self::Config {
58 message: message.into(),
59 source: None,
60 }
61 }
62
63 pub fn config_with_source(
65 message: impl Into<String>,
66 source: impl std::error::Error + Send + Sync + 'static,
67 ) -> Self {
68 Self::Config {
69 message: message.into(),
70 source: Some(Box::new(source)),
71 }
72 }
73
74 pub fn parse(path: impl Into<PathBuf>, message: impl Into<String>) -> Self {
76 Self::Parse {
77 path: path.into(),
78 message: message.into(),
79 }
80 }
81
82 pub fn frontmatter(path: impl Into<PathBuf>, message: impl Into<String>) -> Self {
84 Self::Frontmatter {
85 path: path.into(),
86 message: message.into(),
87 }
88 }
89
90 pub fn template(message: impl Into<String>) -> Self {
92 Self::Template(message.into())
93 }
94
95 pub fn search(message: impl Into<String>) -> Self {
97 Self::Search(message.into())
98 }
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104
105 #[test]
106 fn test_config_error() {
107 let err = CoreError::config("missing field");
108 assert!(err.to_string().contains("Configuration error"));
109 assert!(err.to_string().contains("missing field"));
110 }
111
112 #[test]
113 fn test_parse_error() {
114 let err = CoreError::parse("content/post.md", "invalid syntax");
115 assert!(err.to_string().contains("Parse error"));
116 assert!(err.to_string().contains("content/post.md"));
117 }
118
119 #[test]
120 fn test_frontmatter_error() {
121 let err = CoreError::frontmatter("content/post.md", "missing title");
122 assert!(err.to_string().contains("Frontmatter error"));
123 assert!(err.to_string().contains("missing title"));
124 }
125
126 #[test]
127 fn test_io_error_conversion() {
128 let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
129 let err: CoreError = io_err.into();
130 assert!(err.to_string().contains("IO error"));
131 }
132}