Skip to content

Commit 930c858

Browse files
authored
fix(css): improve unicode wildcard range recovery (#9354)
1 parent 104c684 commit 930c858

4 files changed

Lines changed: 272 additions & 89 deletions

File tree

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
---
2+
"@biomejs/biome": patch
3+
---
4+
5+
Improved CSS parser recovery for invalid `unicode-range` values that mix wildcard ranges with range intervals. For example, Biome now reports clearer diagnostics for invalid syntax like:
6+
7+
```css
8+
unicode-range: U+11???-2??;
9+
unicode-range: U+11???-;
10+
```
11+
12+
with diagnostics such as:
13+
14+
```text
15+
× Wildcard ranges cannot be combined with a range interval.
16+
> unicode-range: U+11???-2??;
17+
^
18+
19+
× Expected a codepoint but instead found ';'.
20+
> unicode-range: U+11???-;
21+
^
22+
```

crates/biome_css_parser/src/syntax/property/unicode_range.rs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,24 @@ pub(crate) fn parse_unicode_range(p: &mut CssParser) -> ParsedSyntax {
6464
p.bump_with_context(T!["U+"], CssLexContext::UnicodeRange);
6565

6666
// Checks if the parser is positioned to parse a Unicode range wildcard.
67-
// A wildcard cannot be combined with a range interval. For example, `U+????-U+????` is invalid.
67+
// A wildcard cannot be combined with a range interval. For example, `U+????-2222` is invalid.
6868
if is_at_unicode_range_wildcard(p) {
6969
parse_unicode_range_wildcard(p).ok();
7070

71+
if p.at(T![-]) {
72+
// Wildcards cannot start a range interval (e.g. `U+????-2222`); consume the tail to recover.
73+
let range = p.cur_range();
74+
p.error(wildcard_range_interval_not_allowed(p, range));
75+
p.bump_with_context(T![-], CssLexContext::UnicodeRange);
76+
77+
if parse_unicode_codepoint(p).is_absent() && parse_unicode_range_wildcard(p).is_absent()
78+
{
79+
p.error(expected_codepoint(p, p.cur_range()));
80+
}
81+
82+
return Present(m.complete(p, CSS_BOGUS_UNICODE_RANGE_VALUE));
83+
}
84+
7185
return Present(m.complete(p, CSS_UNICODE_RANGE));
7286
}
7387

@@ -173,6 +187,22 @@ pub(crate) fn wildcard_not_allowed(p: &CssParser, range: TextRange) -> ParseDiag
173187
)
174188
}
175189

190+
/// Provides a diagnostic for invalid use of a wildcard range with an explicit interval.
191+
///
192+
/// Example: `U+11???-2222`
193+
pub(crate) fn wildcard_range_interval_not_allowed(
194+
p: &CssParser,
195+
range: TextRange,
196+
) -> ParseDiagnostic {
197+
p.err_builder(
198+
"Wildcard ranges cannot be combined with a range interval.",
199+
range,
200+
)
201+
.with_hint(
202+
"Use either a wildcard range (e.g. `U+11???`) or an explicit interval (e.g. `U+1100-2222`).",
203+
)
204+
}
205+
176206
/// Generates a parse diagnostic for an expected "codepoint" error message at the given range.
177207
pub(crate) fn expected_codepoint(p: &CssParser, range: TextRange) -> ParseDiagnostic {
178208
expected_node("codepoint", range, p)

crates/biome_css_parser/tests/css_test_suite/error/property/unicode_range_error.css

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
unicode-range: U+;
33
unicode-range: U+1111111111;
44
unicode-range: U+11???-2222;
5+
unicode-range: U+11???-2??;
6+
unicode-range: U+11???-;
57
unicode-range: U+11-2??;
68
unicode-range: U+11-;
79
}

0 commit comments

Comments
 (0)