Skip to main content

oxc_css_parser/
error.rs

1//! Error management.
2
3use crate::pos::Span;
4#[cfg(feature = "serialize")]
5use serde::Serialize;
6use std::fmt::Display;
7
8#[derive(Clone, Debug)]
9#[cfg_attr(feature = "serialize", derive(Serialize))]
10#[cfg_attr(feature = "serialize", serde(rename_all = "camelCase"))]
11pub struct Error {
12    pub kind: ErrorKind,
13    pub span: Span,
14}
15
16#[derive(Clone, Debug)]
17#[cfg_attr(feature = "serialize", derive(Serialize))]
18pub enum ErrorKind {
19    Unexpected(/* expected */ &'static str, /* actual */ &'static str),
20    ExpectOneOf(/* expected */ Vec<&'static str>, /* actual */ &'static str),
21
22    UnknownToken,
23    InvalidNumber,
24    InvalidEscape,
25    InvalidHash,
26    ExpectRightBraceForLessVar,
27    UnexpectedLinebreak,
28    UnexpectedEof,
29    UnterminatedString,
30
31    ExpectRule,
32    UnexpectedWhitespace,
33    UnexpectedWhitespaceOrComments,
34    ExpectSimpleSelector,
35    ExpectTypeSelector,
36    ExpectIdSelector,
37    ExpectWqName,
38    ExpectAttributeSelectorMatcher,
39    ExpectAttributeSelectorValue,
40    ExpectComponentValue,
41    ExpectSassExpression,
42    ExpectDedentOrEof,
43    ExpectString,
44    ExpectUrl,
45    InvalidUrl,
46    UnexpectedTemplateInCss,
47    ExpectMediaFeatureComparison,
48    ExpectMediaAnd,
49    ExpectMediaOr,
50    ExpectMediaNot,
51    ExpectContainerConditionAnd,
52    ExpectContainerConditionOr,
53    ExpectContainerConditionNot,
54    ExpectStyleConditionAnd,
55    ExpectStyleConditionOr,
56    ExpectStyleConditionNot,
57    ExpectStyleQuery,
58    ExpectSassKeyword(&'static str),
59    InvalidAnPlusB,
60    ExpectInteger,
61    ExpectUnsignedInteger,
62    ExpectImportantAnnotation,
63    ExpectSassUseNamespace,
64    InvalidUnicodeRange,
65    UnexpectedSassElseAtRule,
66    ExpectSassAtRootWithOrWithout,
67    ExpectNthOf,
68    ExpectKeyframeBlock,
69    MixedDelimiterKindInLessMixin,
70    ExpectLessKeyword(&'static str),
71    ExpectLessExtendRule,
72    ExpectScopeTo,
73
74    TryParseError,
75    CSSWideKeywordDisallowed,
76    MediaTypeKeywordDisallowed(String),
77    UnknownKeyframeSelectorIdent,
78    InvalidRatioDenominator,
79    ExpectMediaFeatureName,
80    ExpectDashedIdent,
81    InvalidIdSelectorName,
82    ReturnOutsideFunction,
83    MaxCodePointExceeded,
84    UnicodeRangeStartGreaterThanEnd,
85    UnexpectedNthMatcher,
86    InvalidSassFlagName(String),
87    UnexpectedSassFlag(&'static str),
88    DuplicatedSassFlag(&'static str),
89    LessGuardOnMultipleComplexSelectors,
90    UnexpectedLessMixinCall,
91    UnexpectedSimpleBlock,
92    TopLevelDeclaration,
93
94    // Spec parse errors that CSS Syntax recovers from at EOF / newline. The AST
95    // and recovery stay conformant; these are recorded in `recoverable_errors()`
96    // so downstream consumers can tell recovered-from-broken input apart from
97    // valid CSS. See <https://drafts.csswg.org/css-syntax-3/>.
98    /// A `{}`-block left open at end of file (§5.4.4); `UnterminatedString`
99    /// (already defined) covers the EOF-terminated string (§4.3.5).
100    EofInBlock,
101    /// A string terminated by a newline instead of its quote — a
102    /// `<bad-string-token>` (§4.3.5).
103    BadString,
104    /// A `(`/`[` group left open at end of file.
105    UnclosedParen,
106}
107
108impl Display for ErrorKind {
109    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
110        match self {
111            Self::Unexpected(expected, actual) => {
112                write!(f, "expect token `{expected}`, but found `{actual}`")
113            }
114            Self::ExpectOneOf(expected, actual) => {
115                if let [init @ .., last] = &expected[..] {
116                    let joined = init
117                        .iter()
118                        .map(|token| format!("`{token}`"))
119                        .collect::<Vec<_>>()
120                        .join(", ");
121                    write!(f, "expect one of {joined} or `{last}`, but found `{actual}`",)
122                } else {
123                    panic!("the number of expected tokens must be at least 2")
124                }
125            }
126
127            Self::UnknownToken => write!(f, "unknown token"),
128            Self::InvalidNumber => write!(f, "invalid number"),
129            Self::InvalidEscape => write!(f, "invalid escape"),
130            Self::InvalidHash => write!(f, "invalid hash token"),
131            Self::ExpectRightBraceForLessVar => write!(f, "`}}` for Less variable is expected"),
132            Self::UnexpectedLinebreak => write!(f, "unexpected linebreak"),
133            Self::UnexpectedEof => write!(f, "unexpected end of file"),
134            Self::UnterminatedString => write!(f, "unterminated string"),
135
136            Self::ExpectRule => write!(f, "CSS rule is expected"),
137            Self::UnexpectedWhitespace => write!(f, "unexpected whitespace"),
138            Self::UnexpectedWhitespaceOrComments => write!(f, "unexpected whitespace or comments"),
139            Self::ExpectSimpleSelector => write!(f, "simple selector is expected"),
140            Self::ExpectTypeSelector => write!(f, "type selector is expected"),
141            Self::ExpectIdSelector => write!(f, "ID selector is expected"),
142            Self::ExpectWqName => write!(f, "WqName is expected"),
143            Self::ExpectAttributeSelectorMatcher => {
144                write!(f, "attribute selector matcher is expected")
145            }
146            Self::ExpectAttributeSelectorValue => write!(f, "attribute selector value is expected"),
147            Self::ExpectComponentValue => write!(f, "component value is expected"),
148            Self::ExpectSassExpression => write!(f, "Sass expression is expected"),
149            Self::ExpectDedentOrEof => write!(f, "dedentation or end of file is expected"),
150            Self::ExpectString => write!(f, "string is expected"),
151            Self::ExpectUrl => write!(f, "URL is expected"),
152            Self::InvalidUrl => write!(f, "invalid URL"),
153            Self::UnexpectedTemplateInCss => write!(f, "template isn't allowed in CSS"),
154            Self::ExpectMediaFeatureComparison => write!(f, "media feature comparison is expected"),
155            Self::ExpectMediaAnd => write!(f, "media query `and` is expected"),
156            Self::ExpectMediaOr => write!(f, "media query `or` is expected"),
157            Self::ExpectMediaNot => write!(f, "media query `not` is expected"),
158            Self::ExpectContainerConditionAnd => write!(f, "container condition `and` is expected"),
159            Self::ExpectContainerConditionOr => write!(f, "container condition `or` is expected"),
160            Self::ExpectContainerConditionNot => write!(f, "container condition `not` is expected"),
161            Self::ExpectStyleConditionAnd => write!(f, "style condition `and` is expected"),
162            Self::ExpectStyleConditionOr => write!(f, "style condition `or` is expected"),
163            Self::ExpectStyleConditionNot => write!(f, "style condition `not` is expected"),
164            Self::ExpectStyleQuery => write!(f, "style query is expected"),
165            Self::ExpectSassKeyword(keyword) => write!(f, "Sass keyword `{keyword}` is expected"),
166            Self::InvalidAnPlusB => write!(f, "invalid An+B syntax"),
167            Self::ExpectInteger => write!(f, "an integer is expected"),
168            Self::ExpectUnsignedInteger => write!(f, "unsigned integer is expected"),
169            Self::ExpectImportantAnnotation => write!(f, "`!important` is expected"),
170            Self::ExpectSassUseNamespace => {
171                write!(f, "`*` or ident for Sass namespace is expected")
172            }
173            Self::InvalidUnicodeRange => write!(f, "invalid unicode range"),
174            Self::UnexpectedSassElseAtRule => write!(f, "Sass `@else` at-rule is disallowed here"),
175            Self::ExpectSassAtRootWithOrWithout => {
176                write!(f, "Sass identifier `with` or `without` is expected")
177            }
178            Self::ExpectNthOf => write!(f, "`of` is expected"),
179            Self::ExpectKeyframeBlock => write!(f, "keyframe block is expected"),
180            Self::MixedDelimiterKindInLessMixin => write!(
181                f,
182                "using both `;` and `,` as delimiters in the same Less mixin is disallowed"
183            ),
184            Self::ExpectLessKeyword(keyword) => write!(f, "Less keyword `{keyword}` is expected"),
185            Self::ExpectLessExtendRule => write!(f, "Less extend rule is expected"),
186            Self::ExpectScopeTo => write!(f, "keyword `to` of `@scope` at-rule is expected"),
187
188            Self::TryParseError => unreachable!(),
189            Self::CSSWideKeywordDisallowed => {
190                write!(f, "using CSS wide keyword as identifier is disallowed")
191            }
192            Self::MediaTypeKeywordDisallowed(keyword) => {
193                write!(f, "keyword `{keyword}` as media type is disallowed")
194            }
195            Self::UnknownKeyframeSelectorIdent => write!(f, "unknown keyframe selector"),
196            Self::InvalidRatioDenominator => write!(f, "ratio denominator is invalid"),
197            Self::ExpectMediaFeatureName => write!(f, "media feature name is expected"),
198            Self::ExpectDashedIdent => write!(f, "dashed identifier is expected"),
199            Self::InvalidIdSelectorName => write!(f, "invalid ID selector name"),
200            Self::ReturnOutsideFunction => write!(f, "`@return` is disallowed outside function"),
201            Self::MaxCodePointExceeded => {
202                write!(f, "unicode range end value exceeds max allowed code point")
203            }
204            Self::UnicodeRangeStartGreaterThanEnd => {
205                write!(f, "unicode range start value can't greater than end value")
206            }
207            Self::UnexpectedNthMatcher => {
208                write!(f, "elements matcher is allowed in `:nth-child` and `:nth-last-child` only")
209            }
210            Self::InvalidSassFlagName(flag) => write!(f, "invalid Sass flag name `{flag}`"),
211            Self::UnexpectedSassFlag(flag) => write!(f, "Sass flag `!{flag}` is disallowed"),
212            Self::DuplicatedSassFlag(flag) => write!(f, "duplicated Sass flag `!{flag}`"),
213            Self::LessGuardOnMultipleComplexSelectors => {
214                write!(f, "Less guards are only allowed on a single complex selector")
215            }
216            Self::UnexpectedLessMixinCall => write!(f, "Less mixin call is disallowed"),
217            Self::UnexpectedSimpleBlock => write!(f, "simple block is disallowed"),
218            Self::TopLevelDeclaration => write!(f, "declaration at top level is disallowed"),
219
220            Self::EofInBlock => write!(f, "unclosed block before end of file"),
221            Self::BadString => write!(f, "unterminated string before line break"),
222            Self::UnclosedParen => write!(f, "unclosed parenthesis before end of file"),
223        }
224    }
225}
226
227pub type PResult<T> = Result<T, Error>;