cratestack_parser/
diagnostics.rs1use std::ops::Range;
2
3use ariadne::{Color, Label, Report, ReportKind, Source};
4use cratestack_core::SourceSpan;
5
6#[derive(Debug, Clone, thiserror::Error)]
7#[error("{message}")]
8pub struct SchemaError {
9 message: String,
10 span: Range<usize>,
11 line: usize,
12}
13
14impl SchemaError {
15 pub(crate) fn new(message: impl Into<String>, span: Range<usize>, line: usize) -> Self {
16 Self {
17 message: message.into(),
18 span,
19 line,
20 }
21 }
22
23 pub fn message(&self) -> &str {
24 &self.message
25 }
26
27 pub fn span(&self) -> Range<usize> {
28 self.span.clone()
29 }
30
31 pub fn line(&self) -> usize {
32 self.line
33 }
34
35 pub fn render(&self, path: &str, source: &str) -> String {
36 let mut output = Vec::new();
37 Report::build(ReportKind::Error, (path.to_owned(), self.span.clone()))
38 .with_message(&self.message)
39 .with_label(
40 Label::new((path.to_owned(), self.span.clone()))
41 .with_message(&self.message)
42 .with_color(Color::Red),
43 )
44 .finish()
45 .write((path.to_owned(), Source::from(source)), &mut output)
46 .expect("diagnostic rendering should succeed");
47
48 String::from_utf8(output).expect("ariadne should emit utf-8")
49 }
50}
51
52pub(crate) fn span_error(message: impl Into<String>, span: SourceSpan) -> SchemaError {
53 SchemaError::new(message, span.start..span.end, span.line)
54}