systemprompt_generator/error/
mod.rs1use std::path::PathBuf;
13
14mod suggestions;
15use suggestions::suggest_fix_for_field;
16
17#[derive(Debug, thiserror::Error)]
18pub enum PublishError {
19 #[error("Missing field '{field}' for content '{slug}'")]
20 MissingField {
21 field: String,
22 slug: String,
23 source_path: Option<PathBuf>,
24 suggestion: Option<String>,
25 },
26
27 #[error("No template for content type '{content_type}'")]
28 TemplateNotFound {
29 content_type: String,
30 slug: String,
31 available_templates: Vec<String>,
32 },
33
34 #[error("Page data provider '{provider_id}' failed: {cause}")]
35 ProviderFailed {
36 provider_id: String,
37 cause: String,
38 suggestion: Option<String>,
39 },
40
41 #[error("Template render failed for '{template_name}'")]
42 RenderFailed {
43 template_name: String,
44 slug: Option<String>,
45 cause: String,
46 },
47
48 #[error("Content fetch failed for source '{source_name}'")]
49 FetchFailed { source_name: String, cause: String },
50
51 #[error("Configuration error: {message}")]
52 Config {
53 message: String,
54 path: Option<String>,
55 },
56
57 #[error("Page prerenderer '{page_type}' failed: {cause}")]
58 PagePrerendererFailed { page_type: String, cause: String },
59
60 #[error("I/O error: {0}")]
61 Io(#[from] std::io::Error),
62
63 #[error("YAML error: {0}")]
64 Yaml(#[from] serde_yaml::Error),
65
66 #[error("JSON error: {0}")]
67 Json(#[from] serde_json::Error),
68
69 #[error("{0}")]
70 Other(String),
71}
72
73pub type GeneratorResult<T> = Result<T, PublishError>;
74
75impl PublishError {
76 pub fn missing_field(field: impl Into<String>, slug: impl Into<String>) -> Self {
77 let field_str = field.into();
78 Self::MissingField {
79 suggestion: suggest_fix_for_field(&field_str),
80 field: field_str,
81 slug: slug.into(),
82 source_path: None,
83 }
84 }
85
86 pub fn missing_field_with_path(
87 field: impl Into<String>,
88 slug: impl Into<String>,
89 path: PathBuf,
90 ) -> Self {
91 let field_str = field.into();
92 Self::MissingField {
93 suggestion: suggest_fix_for_field(&field_str),
94 field: field_str,
95 slug: slug.into(),
96 source_path: Some(path),
97 }
98 }
99
100 pub fn template_not_found(
101 content_type: impl Into<String>,
102 slug: impl Into<String>,
103 available: Vec<String>,
104 ) -> Self {
105 Self::TemplateNotFound {
106 content_type: content_type.into(),
107 slug: slug.into(),
108 available_templates: available,
109 }
110 }
111
112 pub fn provider_failed(provider_id: impl Into<String>, cause: impl Into<String>) -> Self {
113 Self::ProviderFailed {
114 provider_id: provider_id.into(),
115 cause: cause.into(),
116 suggestion: None,
117 }
118 }
119
120 pub fn render_failed(
121 template_name: impl Into<String>,
122 slug: Option<String>,
123 cause: impl Into<String>,
124 ) -> Self {
125 Self::RenderFailed {
126 template_name: template_name.into(),
127 slug,
128 cause: cause.into(),
129 }
130 }
131
132 pub fn fetch_failed(source_name: impl Into<String>, cause: impl Into<String>) -> Self {
133 Self::FetchFailed {
134 source_name: source_name.into(),
135 cause: cause.into(),
136 }
137 }
138
139 pub fn config(message: impl Into<String>) -> Self {
140 Self::Config {
141 message: message.into(),
142 path: None,
143 }
144 }
145
146 pub fn page_prerenderer_failed(page_type: impl Into<String>, cause: impl Into<String>) -> Self {
147 Self::PagePrerendererFailed {
148 page_type: page_type.into(),
149 cause: cause.into(),
150 }
151 }
152
153 pub fn other(cause: impl std::fmt::Display) -> Self {
154 Self::Other(cause.to_string())
155 }
156
157 pub fn location(&self) -> Option<String> {
158 match self {
159 Self::MissingField { source_path, .. } => {
160 source_path.as_ref().map(|p| p.display().to_string())
161 },
162 Self::Config { path, .. } => path.clone(),
163 _ => None,
164 }
165 }
166
167 pub fn suggestion_string(&self) -> Option<String> {
168 match self {
169 Self::MissingField { suggestion, .. } | Self::ProviderFailed { suggestion, .. } => {
170 suggestion.clone()
171 },
172 Self::TemplateNotFound {
173 available_templates,
174 content_type,
175 ..
176 } => {
177 if available_templates.is_empty() {
178 Some("Add templates to the templates directory".to_string())
179 } else {
180 Some(format!(
181 "Change content type from '{}' to one of: {}",
182 content_type,
183 available_templates.join(", ")
184 ))
185 }
186 },
187 _ => None,
188 }
189 }
190
191 pub fn cause_string(&self) -> Option<String> {
192 match self {
193 Self::ProviderFailed { cause, .. }
194 | Self::RenderFailed { cause, .. }
195 | Self::FetchFailed { cause, .. }
196 | Self::PagePrerendererFailed { cause, .. } => Some(cause.clone()),
197 _ => None,
198 }
199 }
200}