1use cssparser::{BasicParseErrorKind, ParseError, ParseErrorKind};
2use selectors::parser::SelectorParseErrorKind;
3use std::borrow::Cow;
4use thiserror::Error;
5
6use crate::keyframes::KeyframePreludeParseError;
7
8#[derive(Error, Debug, Clone, PartialEq, Eq)]
10pub enum StyleDeclarationBlockParseError {
11 #[error("failed to parse CSS declaration block `{input}` near `{context}`: {reason}")]
13 InvalidDeclarationBlock {
14 input: String,
16 context: String,
18 reason: String,
20 },
21}
22
23#[derive(Debug, Clone, PartialEq, Eq)]
25pub struct StyleSheetParseError {
26 pub context: Option<String>,
28 pub kind: StyleSheetParseErrorKind,
30}
31
32#[derive(Error, Debug, Clone, PartialEq, Eq)]
34pub enum StyleSheetParseErrorKind {
35 #[error("{0}")]
37 InvalidStyleSheet(String),
38
39 #[error("unsupported media feature")]
41 UnsupportedMediaFeature,
42
43 #[error("@property inherits must be true or false")]
45 PropertyInheritsMustBeBoolean,
46
47 #[error("missing `@property` syntax")]
49 MissingPropertySyntax,
50
51 #[error("missing `@property` inherits")]
53 MissingPropertyInherits,
54
55 #[error("@supports cannot mix `and` and `or` without parentheses")]
57 SupportsMixedAndOrWithoutParentheses,
58
59 #[error("@property name must be a custom property")]
61 PropertyNameMustBeCustomProperty,
62
63 #[error("@layer blocks accept at most one name")]
65 LayerBlockMultipleNames,
66
67 #[error("unsupported nested at-rule")]
69 UnsupportedNestedAtRule,
70}
71
72impl std::fmt::Display for StyleSheetParseError {
73 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
74 if let Some(context) = &self.context {
75 write!(
76 f,
77 "failed to parse stylesheet near `{context}`: {}",
78 self.kind
79 )
80 } else {
81 write!(f, "failed to parse stylesheet: {}", self.kind)
82 }
83 }
84}
85
86impl std::error::Error for StyleSheetParseError {}
87
88impl<'i> From<SelectorParseErrorKind<'i>> for StyleSheetParseError {
89 fn from(err: SelectorParseErrorKind<'i>) -> Self {
90 Self::invalid_reason(format!("{err:?}"))
91 }
92}
93
94impl<'i> From<Cow<'i, str>> for StyleSheetParseError {
95 fn from(err: Cow<'i, str>) -> Self {
96 Self::invalid_reason(err.into_owned())
97 }
98}
99
100impl<'i> From<KeyframePreludeParseError<'i>> for StyleSheetParseError {
101 fn from(_err: KeyframePreludeParseError<'i>) -> Self {
102 Self::invalid_reason(format!("{:?}", BasicParseErrorKind::QualifiedRuleInvalid))
103 }
104}
105
106impl StyleSheetParseError {
107 pub fn invalid_reason(reason: impl Into<String>) -> Self {
108 Self::new(StyleSheetParseErrorKind::InvalidStyleSheet(reason.into()))
109 }
110
111 pub fn unsupported_media_feature() -> Self {
112 Self::new(StyleSheetParseErrorKind::UnsupportedMediaFeature)
113 }
114
115 pub fn property_inherits_must_be_boolean() -> Self {
116 Self::new(StyleSheetParseErrorKind::PropertyInheritsMustBeBoolean)
117 }
118
119 pub fn missing_property_syntax() -> Self {
120 Self::new(StyleSheetParseErrorKind::MissingPropertySyntax)
121 }
122
123 pub fn missing_property_inherits() -> Self {
124 Self::new(StyleSheetParseErrorKind::MissingPropertyInherits)
125 }
126
127 pub fn supports_mixed_and_or_without_parentheses() -> Self {
128 Self::new(StyleSheetParseErrorKind::SupportsMixedAndOrWithoutParentheses)
129 }
130
131 pub fn property_name_must_be_custom_property() -> Self {
132 Self::new(StyleSheetParseErrorKind::PropertyNameMustBeCustomProperty)
133 }
134
135 pub fn layer_block_multiple_names() -> Self {
136 Self::new(StyleSheetParseErrorKind::LayerBlockMultipleNames)
137 }
138
139 pub fn unsupported_nested_at_rule() -> Self {
140 Self::new(StyleSheetParseErrorKind::UnsupportedNestedAtRule)
141 }
142
143 fn new(kind: StyleSheetParseErrorKind) -> Self {
144 Self {
145 context: None,
146 kind,
147 }
148 }
149
150 fn with_context(self, context: &str) -> Self {
151 Self {
152 context: Some(context.to_owned()),
153 kind: self.kind,
154 }
155 }
156
157 pub fn from_parse_error(context: &str, error: ParseError<'_, StyleSheetParseError>) -> Self {
158 match error.kind {
159 ParseErrorKind::Basic(error) => Self::invalid_reason(format!("{error:?}")),
160 ParseErrorKind::Custom(error) => error,
161 }
162 .with_context(context)
163 }
164}