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            // An internal rollback marker for `try_parse`; whoever surfaces a
189            // rolled-back error concretizes it first. Print a generic message
190            // rather than panic in case one ever leaks.
191            Self::TryParseError => write!(f, "syntax error"),
192            Self::CSSWideKeywordDisallowed => {
193                write!(f, "using CSS wide keyword as identifier is disallowed")
194            }
195            Self::MediaTypeKeywordDisallowed(keyword) => {
196                write!(f, "keyword `{keyword}` as media type is disallowed")
197            }
198            Self::UnknownKeyframeSelectorIdent => write!(f, "unknown keyframe selector"),
199            Self::InvalidRatioDenominator => write!(f, "ratio denominator is invalid"),
200            Self::ExpectMediaFeatureName => write!(f, "media feature name is expected"),
201            Self::ExpectDashedIdent => write!(f, "dashed identifier is expected"),
202            Self::InvalidIdSelectorName => write!(f, "invalid ID selector name"),
203            Self::ReturnOutsideFunction => write!(f, "`@return` is disallowed outside function"),
204            Self::MaxCodePointExceeded => {
205                write!(f, "unicode range end value exceeds max allowed code point")
206            }
207            Self::UnicodeRangeStartGreaterThanEnd => {
208                write!(f, "unicode range start value can't greater than end value")
209            }
210            Self::UnexpectedNthMatcher => {
211                write!(f, "elements matcher is allowed in `:nth-child` and `:nth-last-child` only")
212            }
213            Self::InvalidSassFlagName(flag) => write!(f, "invalid Sass flag name `{flag}`"),
214            Self::UnexpectedSassFlag(flag) => write!(f, "Sass flag `!{flag}` is disallowed"),
215            Self::DuplicatedSassFlag(flag) => write!(f, "duplicated Sass flag `!{flag}`"),
216            Self::LessGuardOnMultipleComplexSelectors => {
217                write!(f, "Less guards are only allowed on a single complex selector")
218            }
219            Self::UnexpectedLessMixinCall => write!(f, "Less mixin call is disallowed"),
220            Self::UnexpectedSimpleBlock => write!(f, "simple block is disallowed"),
221            Self::TopLevelDeclaration => write!(f, "declaration at top level is disallowed"),
222
223            Self::EofInBlock => write!(f, "unclosed block before end of file"),
224            Self::BadString => write!(f, "unterminated string before line break"),
225            Self::UnclosedParen => write!(f, "unclosed parenthesis before end of file"),
226        }
227    }
228}
229
230pub type PResult<T> = Result<T, Error>;