use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
pub struct RegionSchema {
pub format: ContentFormat,
#[serde(skip_serializing_if = "Option::is_none")]
pub custom_script: Option<String>,
}
impl Clone for RegionSchema {
fn clone(&self) -> Self {
Self {
format: self.format.clone(),
custom_script: self.custom_script.clone(),
}
}
}
impl RegionSchema {
pub fn new(format: ContentFormat) -> Self {
Self {
format,
custom_script: None,
}
}
pub fn with_custom_script(mut self, script: String) -> Self {
self.custom_script = Some(script);
self
}
pub fn validate(&self, content: &str) -> crate::error::Result<()> {
match &self.format {
ContentFormat::Json => {
serde_json::from_str::<serde_json::Value>(content).map_err(|e| {
crate::error::Error::ValidationFailed(format!("Invalid JSON: {}", e))
})?;
}
ContentFormat::Mermaid => {
if !content.contains("graph")
&& !content.contains("sequenceDiagram")
&& !content.contains("classDiagram")
&& !content.contains("stateDiagram")
&& !content.contains("erDiagram")
&& !content.contains("journey")
&& !content.contains("gantt")
&& !content.contains("pie")
&& !content.contains("flowchart")
{
return Err(crate::error::Error::ValidationFailed(
"Mermaid diagrams must contain a valid diagram type (graph, sequenceDiagram, etc.)".to_string()
));
}
}
ContentFormat::Code { .. } => {
if content.trim().is_empty() {
return Err(crate::error::Error::ValidationFailed(
"Code cannot be empty".to_string(),
));
}
}
ContentFormat::Markdown => {
if content.trim().is_empty() {
return Err(crate::error::Error::ValidationFailed(
"Markdown content cannot be empty".to_string(),
));
}
}
ContentFormat::Text | ContentFormat::Custom { .. } => {
}
}
Ok(())
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum ContentFormat {
Text,
Json,
Mermaid,
Code {
language: String,
},
Markdown,
Custom {
format_name: String,
},
}
pub trait Validator: Send + Sync {
fn validate(&self, content: &str) -> std::result::Result<(), crate::error::ValidationError>;
fn description(&self) -> &str;
}