use quarto_error_reporting::{DiagnosticKind, DiagnosticMessage, DiagnosticMessageBuilder};
use quarto_source_map::{SourceContext, SourceInfo};
struct SimpleCollector {
diagnostics: Vec<DiagnosticMessage>,
}
impl SimpleCollector {
fn new() -> Self {
Self {
diagnostics: Vec::new(),
}
}
fn add(&mut self, diagnostic: DiagnosticMessage) {
self.diagnostics.push(diagnostic);
}
fn error(&mut self, message: impl Into<String>) {
self.add(DiagnosticMessage::error(message.into()));
}
fn warn(&mut self, message: impl Into<String>) {
self.add(DiagnosticMessage::warning(message.into()));
}
fn error_at(&mut self, message: impl Into<String>, location: SourceInfo) {
self.add(
DiagnosticMessageBuilder::error(message.into())
.with_location(location)
.build(),
);
}
fn has_errors(&self) -> bool {
self.diagnostics
.iter()
.any(|d| d.kind == DiagnosticKind::Error)
}
fn diagnostics(&self) -> &[DiagnosticMessage] {
&self.diagnostics
}
fn to_text(&self, ctx: Option<&SourceContext>) -> Vec<String> {
self.diagnostics.iter().map(|d| d.to_text(ctx)).collect()
}
}
fn main() {
println!("=== Example 1: Accumulating multiple errors ===\n");
let mut collector = SimpleCollector::new();
collector.error("Missing required field 'title'");
collector.warn("Field 'description' is deprecated");
collector.error("Invalid value for 'format': expected string, got number");
if collector.has_errors() {
println!(
"Validation failed with {} diagnostics:",
collector.diagnostics().len()
);
for text in collector.to_text(None) {
println!("{}", text);
}
}
println!("\n=== Example 2: Errors with source locations ===\n");
let mut ctx = SourceContext::new();
let file_id = ctx.add_file(
"config.yml".to_string(),
Some("title: 123\nformat: html\nauthor: John\n".to_string()),
);
let mut collector2 = SimpleCollector::new();
let loc1 = SourceInfo::original(file_id, 7, 10);
collector2.error_at("Title must be a string", loc1);
let loc2 = SourceInfo::original(file_id, 33, 37);
let warning = DiagnosticMessageBuilder::warning("Author field should include email")
.with_location(loc2)
.add_hint("Use format: 'Name <email@example.com>'")
.build();
collector2.add(warning);
println!("Collected diagnostics:");
for text in collector2.to_text(Some(&ctx)) {
println!("{}", text);
println!();
}
println!("=== Example 3: JSON output for all diagnostics ===\n");
let json_array: Vec<_> = collector2
.diagnostics()
.iter()
.map(|d| d.to_json())
.collect();
println!("{}", serde_json::to_string_pretty(&json_array).unwrap());
println!("\n=== Example 4: Continuing vs. failing fast ===\n");
let mut collector3 = SimpleCollector::new();
for i in 1..=3 {
collector3.error(format!("Error in item {}", i));
}
if collector3.has_errors() {
eprintln!(
"Processing failed with {} errors",
collector3.diagnostics().len()
);
eprintln!("\nErrors:");
for diag in collector3.diagnostics() {
eprintln!(" - {}", diag.title);
}
}
}