Skip to content

Commit

Permalink
fix(css_parser): fix constant crashes when editing css files #3256 (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
denbezrukov committed Jun 22, 2024
1 parent 6ad7fbf commit 86d4e7c
Show file tree
Hide file tree
Showing 7 changed files with 226 additions and 18 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@ our [guidelines for writing a good changelog entry](https://github.com/biomejs/b
#### New features

- Implement [CSS unicode range](https://github.com/biomejs/biome/pull/3251). Contributed by @denbezrukov
-

### Formatter

#### Bug fixes

- Fix [#3184](https://github.com/biomejs/biome/issues/3184) CSS formatter converts custom identifiers to lowercase. Contributed by @denbezrukov
- Fix [#3256](https://github.com/biomejs/biome/issues/3256) constant crashes when editing css files #3256. Contributed by @denbezrukov

## v1.8.2 (2024-06-20)

Expand Down
16 changes: 1 addition & 15 deletions crates/biome_css_parser/src/syntax/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use crate::parser::CssParser;
use crate::syntax::at_rule::{is_at_at_rule, parse_at_rule};
use crate::syntax::block::parse_declaration_or_rule_list_block;
use crate::syntax::parse_error::{expected_any_rule, expected_non_css_wide_keyword_identifier};
use crate::syntax::property::color::{is_at_color, parse_color};
use crate::syntax::property::unicode_range::{is_at_unicode_range, parse_unicode_range};
use crate::syntax::property::{is_at_any_property, parse_any_property};
use crate::syntax::selector::is_nth_at_selector;
Expand Down Expand Up @@ -287,21 +288,6 @@ pub(crate) fn parse_any_value(p: &mut CssParser) -> ParsedSyntax {
}
}

#[inline]
pub(crate) fn is_at_color(p: &mut CssParser) -> bool {
p.at(T![#])
}
#[inline]
pub(crate) fn parse_color(p: &mut CssParser) -> ParsedSyntax {
if !is_at_color(p) {
return Absent;
}
let m = p.start();
p.bump_with_context(T![#], CssLexContext::Color);
p.expect(CSS_COLOR_LITERAL);
Present(m.complete(p, CSS_COLOR))
}

struct CssComponentValueList;
impl ParseNodeList for CssComponentValueList {
type Kind = CssSyntaxKind;
Expand Down
35 changes: 35 additions & 0 deletions crates/biome_css_parser/src/syntax/property/color.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use crate::lexer::CssLexContext;
use crate::parser::CssParser;
use biome_css_syntax::CssSyntaxKind::{CSS_COLOR, CSS_COLOR_LITERAL};
use biome_css_syntax::{TextRange, T};
use biome_parser::diagnostic::{expected_node, ParseDiagnostic};
use biome_parser::parsed_syntax::ParsedSyntax;
use biome_parser::parsed_syntax::ParsedSyntax::{Absent, Present};
use biome_parser::Parser;

#[inline]
pub(crate) fn is_at_color(p: &mut CssParser) -> bool {
p.at(T![#])
}
#[inline]
pub(crate) fn parse_color(p: &mut CssParser) -> ParsedSyntax {
if !is_at_color(p) {
return Absent;
}

let m = p.start();
let hash_range = p.cur_range();
p.bump_with_context(T![#], CssLexContext::Color);

if !p.eat(CSS_COLOR_LITERAL) {
p.error(expected_color(p, hash_range));
}

Present(m.complete(p, CSS_COLOR))
}

/// Generates a parse diagnostic for an expected "color" error message at the given range.
pub(crate) fn expected_color(p: &CssParser, range: TextRange) -> ParseDiagnostic {
expected_node("color", range, p)
.with_hint("Ensure the color is specified in a valid hexadecimal format. Examples: #000, #000f, #ffffff, #ffffffff")
}
1 change: 1 addition & 0 deletions crates/biome_css_parser/src/syntax/property/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub(crate) mod color;
pub(crate) mod unicode_range;

use crate::lexer::CssLexContext;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.formTable tbody td {
border-left: 1px # solid;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
---
source: crates/biome_css_parser/tests/spec_test.rs
expression: snapshot
---
## Input

```css
.formTable tbody td {
border-left: 1px # solid;
}
```


## AST

```
CssRoot {
bom_token: missing (optional),
rules: CssRuleList [
CssQualifiedRule {
prelude: CssSelectorList [
CssComplexSelector {
left: CssComplexSelector {
left: CssCompoundSelector {
nesting_selector_token: missing (optional),
simple_selector: missing (optional),
sub_selectors: CssSubSelectorList [
CssClassSelector {
dot_token: DOT@0..1 "." [] [],
name: CssCustomIdentifier {
value_token: IDENT@1..10 "formTable" [] [],
},
},
],
},
combinator: CSS_SPACE_LITERAL@10..11 " " [] [],
right: CssCompoundSelector {
nesting_selector_token: missing (optional),
simple_selector: CssTypeSelector {
namespace: missing (optional),
ident: CssIdentifier {
value_token: IDENT@11..16 "tbody" [] [],
},
},
sub_selectors: CssSubSelectorList [],
},
},
combinator: CSS_SPACE_LITERAL@16..17 " " [] [],
right: CssCompoundSelector {
nesting_selector_token: missing (optional),
simple_selector: CssTypeSelector {
namespace: missing (optional),
ident: CssIdentifier {
value_token: IDENT@17..20 "td" [] [Whitespace(" ")],
},
},
sub_selectors: CssSubSelectorList [],
},
},
],
block: CssDeclarationOrRuleBlock {
l_curly_token: L_CURLY@20..21 "{" [] [],
items: CssDeclarationOrRuleList [
CssDeclarationWithSemicolon {
declaration: CssDeclaration {
property: CssGenericProperty {
name: CssIdentifier {
value_token: IDENT@21..34 "border-left" [Newline("\n"), Whitespace("\t")] [],
},
colon_token: COLON@34..36 ":" [] [Whitespace(" ")],
value: CssGenericComponentValueList [
CssRegularDimension {
value_token: CSS_NUMBER_LITERAL@36..37 "1" [] [],
unit_token: IDENT@37..40 "px" [] [Whitespace(" ")],
},
CssColor {
hash_token: HASH@40..42 "#" [] [Whitespace(" ")],
value_token: missing (required),
},
CssIdentifier {
value_token: IDENT@42..47 "solid" [] [],
},
],
},
important: missing (optional),
},
semicolon_token: SEMICOLON@47..48 ";" [] [],
},
],
r_curly_token: R_CURLY@48..50 "}" [Newline("\n")] [],
},
},
],
eof_token: EOF@50..51 "" [Newline("\n")] [],
}
```

## CST

```
0: [email protected]
0: (empty)
1: [email protected]
0: [email protected]
0: [email protected]
0: [email protected]
0: [email protected]
0: [email protected]
0: (empty)
1: (empty)
2: [email protected]
0: [email protected]
0: [email protected] "." [] []
1: [email protected]
0: [email protected] "formTable" [] []
1: [email protected] " " [] []
2: [email protected]
0: (empty)
1: [email protected]
0: (empty)
1: [email protected]
0: [email protected] "tbody" [] []
2: [email protected]
1: [email protected] " " [] []
2: [email protected]
0: (empty)
1: [email protected]
0: (empty)
1: [email protected]
0: [email protected] "td" [] [Whitespace(" ")]
2: [email protected]
1: [email protected]
0: [email protected] "{" [] []
1: CSS_DECLARATION_OR_RULE_LIST@21..48
0: CSS_DECLARATION_WITH_SEMICOLON@21..48
0: CSS_DECLARATION@21..47
0: CSS_GENERIC_PROPERTY@21..47
0: CSS_IDENTIFIER@21..34
0: IDENT@21..34 "border-left" [Newline("\n"), Whitespace("\t")] []
1: COLON@34..36 ":" [] [Whitespace(" ")]
2: CSS_GENERIC_COMPONENT_VALUE_LIST@36..47
0: CSS_REGULAR_DIMENSION@36..40
0: CSS_NUMBER_LITERAL@36..37 "1" [] []
1: IDENT@37..40 "px" [] [Whitespace(" ")]
1: CSS_COLOR@40..42
0: HASH@40..42 "#" [] [Whitespace(" ")]
1: (empty)
2: CSS_IDENTIFIER@42..47
0: IDENT@42..47 "solid" [] []
1: (empty)
1: SEMICOLON@47..48 ";" [] []
2: R_CURLY@48..50 "}" [Newline("\n")] []
2: EOF@50..51 "" [Newline("\n")] []
```
## Diagnostics
```
color_error.css:2:19 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
× Expected a color but instead found '#'.
1 │ .formTable tbody td {
> 2 │ border-left: 1px # solid;
^
3 │ }
4
i Expected a color here.
1 │ .formTable tbody td {
> 2 │ border-left: 1px # solid;
^
3 │ }
4
i Ensure the color is specified in a valid hexadecimal format. Examples: #000, #000f, #ffffff, #ffffffff
```
5 changes: 3 additions & 2 deletions crates/biome_css_parser/tests/spec_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,9 @@ pub fn run(test_case: &str, _snapshot_name: &str, test_directory: &str, outcome_
#[test]
pub fn quick_test() {
let code = r#"
@font-face { color: U+0100-024F; }
.formTable tbody td {
border-left: 1px # solid;
}
"#;

let root = parse_css(
Expand Down

0 comments on commit 86d4e7c

Please sign in to comment.