use std::ops::Range;
use roxmltree::Node;
#[derive(Debug, thiserror::Error, miette::Diagnostic)]
pub enum ParseError {
#[error("malformed XML: {message}")]
#[diagnostic(code(ergo_sbe::schema_parse::malformed_xml))]
MalformedXml {
message: String,
#[source_code]
source_code: miette::NamedSource<String>,
#[label("here")]
span: Option<miette::SourceSpan>,
},
#[error("missing {what}")]
#[diagnostic(code(ergo_sbe::schema_parse::missing))]
Missing {
what: String,
#[source_code]
source_code: miette::NamedSource<String>,
#[label("missing here")]
span: Option<miette::SourceSpan>,
},
#[error("invalid {what}: {value}")]
#[diagnostic(code(ergo_sbe::schema_parse::invalid))]
Invalid {
what: String,
value: String,
#[source_code]
source_code: miette::NamedSource<String>,
#[label("invalid here")]
span: Option<miette::SourceSpan>,
},
#[error("resolution error: {error}")]
#[diagnostic(code(ergo_sbe::schema_parse::resolve))]
Resolve {
#[source_code]
source_code: miette::NamedSource<String>,
#[label("here")]
span: Option<miette::SourceSpan>,
#[label("related")]
second_label: Option<miette::SourceSpan>,
#[source]
error: Box<crate::resolve::ResolveError>,
},
#[error("include error: {message}")]
#[diagnostic(code(ergo_sbe::schema_parse::include))]
IncludeError {
message: String,
#[source_code]
source_code: miette::NamedSource<String>,
#[label("include error here")]
span: Option<miette::SourceSpan>,
},
}
impl ParseError {
pub(crate) fn malformed_xml(message: impl Into<String>, xml: &str) -> Self {
Self::MalformedXml {
message: message.into(),
source_code: named_source(xml),
span: None,
}
}
pub(crate) fn from_fault(fault: Fault, input: &str) -> Self {
let source_code = named_source(input);
let span = fault.span.map(miette::SourceSpan::from);
match fault.kind {
FaultKind::Missing { what } => Self::Missing {
what,
source_code,
span,
},
FaultKind::Invalid { what, value } => Self::Invalid {
what,
value,
source_code,
span,
},
FaultKind::IncludeError { message } => Self::IncludeError {
message,
source_code,
span,
},
}
}
}
impl From<crate::resolve::ResolveError> for ParseError {
fn from(mut e: crate::resolve::ResolveError) -> Self {
let source_code = e
.take_source_code()
.unwrap_or_else(|| miette::NamedSource::new("schema.xml", String::new()));
let (span, second_label) = e.take_spans();
Self::Resolve {
source_code,
span,
second_label,
error: Box::new(e),
}
}
}
pub(crate) fn named_source(xml: &str) -> miette::NamedSource<String> {
miette::NamedSource::new("schema.xml", xml.to_owned())
}
#[derive(Debug)]
pub(crate) struct Fault {
pub(crate) kind: FaultKind,
pub(crate) span: Option<Range<usize>>,
}
#[derive(Debug)]
pub(crate) enum FaultKind {
Missing { what: String },
Invalid { what: String, value: String },
IncludeError { message: String },
}
impl Fault {
pub(crate) fn missing(node: Node<'_, '_>, what: impl Into<String>) -> Self {
Self {
kind: FaultKind::Missing { what: what.into() },
span: Some(node.range()),
}
}
pub(crate) fn missing_no_node(what: impl Into<String>) -> Self {
Self {
kind: FaultKind::Missing { what: what.into() },
span: None,
}
}
pub(crate) fn invalid(
node: Node<'_, '_>,
what: impl Into<String>,
value: impl Into<String>,
) -> Self {
Self {
kind: FaultKind::Invalid {
what: what.into(),
value: value.into(),
},
span: Some(node.range()),
}
}
pub(crate) fn include_error(message: impl Into<String>) -> Self {
Self {
kind: FaultKind::IncludeError {
message: message.into(),
},
span: None,
}
}
}