1use cssparser::{BasicParseErrorKind, ParseError, ParseErrorKind, SourceLocation};
3use std::{
4 borrow::Cow,
5 error::Error,
6 fmt,
7 fmt::{Display, Formatter},
8 io,
9};
10
11#[derive(Debug)]
13pub enum InlineError {
14 MissingStyleSheet {
16 path: String,
18 },
19 IO(io::Error),
22 #[cfg(feature = "http")]
24 Network {
25 error: reqwest::Error,
27 location: String,
29 },
30 ParseError(Cow<'static, str>),
32}
33
34impl From<io::Error> for InlineError {
35 fn from(error: io::Error) -> Self {
36 Self::IO(error)
37 }
38}
39
40impl Error for InlineError {
41 fn source(&self) -> Option<&(dyn Error + 'static)> {
42 match self {
43 InlineError::IO(error) => Some(error),
44 #[cfg(feature = "http")]
45 InlineError::Network { error, .. } => Some(error),
46 InlineError::MissingStyleSheet { .. } | InlineError::ParseError(_) => None,
47 }
48 }
49}
50
51impl Display for InlineError {
52 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
53 match self {
54 Self::IO(error) => error.fmt(f),
55 #[cfg(feature = "http")]
56 Self::Network { error, location } => f.write_fmt(format_args!("{error}: {location}")),
57 Self::ParseError(error) => f.write_str(error),
58 Self::MissingStyleSheet { path } => {
59 f.write_fmt(format_args!("Missing stylesheet file: {path}"))
60 }
61 }
62 }
63}
64
65impl From<(ParseError<()>, &str, SourceLocation)> for InlineError {
66 fn from(error: (ParseError<()>, &str, SourceLocation)) -> Self {
67 let source = error.1;
69 match error.0.kind {
70 ParseErrorKind::Basic(kind) => match kind {
71 BasicParseErrorKind::UnexpectedToken => {
72 let mut parser = cssparser::Parser::new(source);
73 let mut last = None;
74 while let Ok(token) = parser.next() {
75 last = Some(format!("{token:?}"));
76 }
77 match last {
78 Some(token) => {
79 Self::ParseError(Cow::Owned(format!("Unexpected token: {token}")))
80 }
81 None => Self::ParseError(Cow::Borrowed("Unexpected token")),
82 }
83 }
84 BasicParseErrorKind::EndOfInput => Self::ParseError(Cow::Borrowed("End of input")),
85 BasicParseErrorKind::AtRuleInvalid => {
86 let name = source
87 .trim_start()
88 .trim_start_matches('@')
89 .split(|c: char| c.is_whitespace() || matches!(c, '{' | ';'))
90 .next()
91 .unwrap_or_default();
92 Self::ParseError(Cow::Owned(format!("Invalid @ rule: {name}")))
93 }
94 BasicParseErrorKind::TooManyNestedBlocks => {
95 Self::ParseError(Cow::Borrowed("Too many nested blocks"))
96 }
97 BasicParseErrorKind::AtRuleBodyInvalid => {
98 Self::ParseError(Cow::Borrowed("Invalid @ rule body"))
99 }
100 BasicParseErrorKind::QualifiedRuleInvalid => {
101 Self::ParseError(Cow::Borrowed("Invalid qualified rule"))
102 }
103 },
104 ParseErrorKind::Custom(()) => Self::ParseError(Cow::Borrowed("Unknown error")),
105 }
106 }
107}