Skip to content

Commit d96d6dd

Browse files
fix(css): validate @Property syntax descriptors (#11175)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent 68a2cf8 commit d96d6dd

28 files changed

Lines changed: 695 additions & 83 deletions

File tree

.changeset/yummy-owls-boil.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@biomejs/biome": patch
3+
---
4+
5+
Fixed CSS parsing of registered custom properties: Biome now correctly validates the `syntax` descriptor of `@property` rules.

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/biome_analyze/src/rule.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use biome_analyze_macros::RuleSourceVariantIndex;
88
use biome_console::fmt::{Display, Formatter};
99
use biome_console::{MarkupBuf, markup};
1010
use biome_diagnostics::location::AsSpan;
11+
use biome_diagnostics::serde::Advices as SerializableAdvices;
1112
use biome_diagnostics::{
1213
Advices, Category, Diagnostic, DiagnosticTags, Location, LogCategory, MessageAndDescription,
1314
Visit,
@@ -1611,6 +1612,10 @@ impl Advices for RuleDiagnostic {
16111612
visitor.record_list(&list)?;
16121613
}
16131614

1615+
for advices in &self.rule_advice.parent_advices {
1616+
advices.record(visitor)?;
1617+
}
1618+
16141619
Ok(())
16151620
}
16161621
}
@@ -1621,6 +1626,8 @@ pub struct RuleAdvice {
16211626
pub(crate) details: Vec<Detail>,
16221627
pub(crate) notes: Vec<(LogCategory, MarkupBuf)>,
16231628
pub(crate) suggestion_list: Option<SuggestionList>,
1629+
/// Advices provided by other diagnostics
1630+
pub(crate) parent_advices: Vec<SerializableAdvices>,
16241631
}
16251632

16261633
#[derive(Clone, Debug, Default)]
@@ -1655,6 +1662,9 @@ impl RuleDiagnostic {
16551662

16561663
pub(crate) fn set_advice_offset(&mut self, offset: TextSize) {
16571664
self.advice_offset = Some(offset);
1665+
for advices in &mut self.rule_advice.parent_advices {
1666+
advices.offset_by(offset);
1667+
}
16581668
}
16591669

16601670
/// Marks this diagnostic as deprecated code, which will
@@ -1713,6 +1723,14 @@ impl RuleDiagnostic {
17131723
self.footer(LogCategory::Info, msg)
17141724
}
17151725

1726+
/// Attaches advice emitted by `advices`.
1727+
pub fn with_advices(mut self, advices: impl Advices) -> Self {
1728+
self.rule_advice
1729+
.parent_advices
1730+
.push(SerializableAdvices::new(&advices));
1731+
self
1732+
}
1733+
17161734
/// It creates a new footer note which contains a message and a list of possible suggestions.
17171735
/// Useful when there's need to suggest a list of things inside a diagnostic.
17181736
pub fn footer_list(

crates/biome_cli/tests/commands/lint.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2712,6 +2712,38 @@ fn lint_syntax_rules() {
27122712
));
27132713
}
27142714

2715+
#[test]
2716+
fn lint_invalid_property_syntax() {
2717+
let fs = MemoryFileSystem::default();
2718+
let mut console = BufferConsole::default();
2719+
2720+
let file_path = Utf8Path::new("check.css");
2721+
fs.insert(
2722+
file_path.into(),
2723+
r#"@property --value {
2724+
syntax: "<unknown>";
2725+
inherits: false;
2726+
}"#
2727+
.as_bytes(),
2728+
);
2729+
2730+
let (fs, result) = run_cli(
2731+
fs,
2732+
&mut console,
2733+
Args::from(["lint", file_path.as_str()].as_slice()),
2734+
);
2735+
2736+
assert!(result.is_err(), "run_cli returned {result:?}");
2737+
2738+
assert_cli_snapshot(SnapshotPayload::new(
2739+
module_path!(),
2740+
"lint_invalid_property_syntax",
2741+
fs,
2742+
console,
2743+
result,
2744+
));
2745+
}
2746+
27152747
#[test]
27162748
fn should_lint_error_without_file_paths() {
27172749
let fs = MemoryFileSystem::default();
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
---
2+
source: crates/biome_cli/tests/snap_test.rs
3+
expression: redactor(content)
4+
---
5+
## `check.css`
6+
7+
```css
8+
@property --value {
9+
syntax: "<unknown>";
10+
inherits: false;
11+
}
12+
```
13+
14+
# Termination Message
15+
16+
```block
17+
lint ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
18+
19+
× Some errors were emitted while running checks.
20+
21+
22+
23+
```
24+
25+
# Emitted Messages
26+
27+
```block
28+
check.css:2:14 syntax/correctness/noInvalidPropertySyntax ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
29+
30+
× Use a supported property syntax type.
31+
32+
1 │ @property --value {
33+
> 2syntax: "<unknown>";
34+
^^^^^^^^^
35+
3inherits: false;
36+
4}
37+
38+
i Supported types:
39+
40+
- <angle>
41+
- <color>
42+
- <custom-ident>
43+
- <image>
44+
- <integer>
45+
- <length>
46+
- <length-percentage>
47+
- <number>
48+
- <percentage>
49+
- <resolution>
50+
- <string>
51+
- <time>
52+
- <transform-function>
53+
- <transform-list>
54+
- <url>
55+
56+
57+
```
58+
59+
```block
60+
Checked 1 file in <TIME>. No fixes applied.
61+
Found 1 error.
62+
```

crates/biome_css_analyze/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ biome_diagnostics = { workspace = true }
3131
biome_languages = { workspace = true, features = ["lang_css"] }
3232
biome_module_graph = { workspace = true }
3333
biome_project_layout = { workspace = true }
34+
biome_property_codec = { workspace = true }
3435
biome_rowan = { workspace = true }
3536
biome_rule_options = { workspace = true }
3637
biome_string_case = { workspace = true }

crates/biome_css_analyze/build.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ fn main() -> io::Result<()> {
2020
watch_group("lint", "nursery")?;
2121
watch_group("lint", "style")?;
2222
watch_group("lint", "suspicious")?;
23+
watch_group("syntax", "correctness")?;
2324
Ok(())
2425
}
2526
#[doc = r" Watch a specific group directory and touch its group file when changes occur"]

crates/biome_css_analyze/src/lib.rs

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ mod order;
99
mod registry;
1010
mod services;
1111
mod suppression_action;
12+
mod syntax;
1213
mod utils;
1314

1415
pub use crate::registry::visit_registry;
@@ -175,10 +176,7 @@ where
175176

176177
services.insert_service(css_services.file_source);
177178
if let Some(semantic_model) = css_services.semantic_model {
178-
services.insert_service(Arc::new(semantic_model.clone()));
179-
} else {
180-
let semantic_model = biome_css_semantic::semantic_model(root);
181-
services.insert_service(Arc::new(semantic_model));
179+
services.insert_service(semantic_model.clone());
182180
}
183181
if let Some(module_db) = css_services.module_db {
184182
services.insert_service(module_db);
@@ -314,7 +312,7 @@ mod tests {
314312
fn top_level_suppression_simple() {
315313
const SOURCE: &str = "
316314
/**
317-
* biome-ignore lint/suspicious/noEmptyBlock: reason
315+
* biome-ignore-all lint/suspicious/noEmptyBlock: reason
318316
*/
319317
320318
#foo {}
@@ -324,7 +322,8 @@ mod tests {
324322
let parsed = parse_css(SOURCE, CssFileSource::css(), CssParserOptions::default());
325323

326324
let filter = AnalysisFilter {
327-
categories: RuleCategoriesBuilder::default().with_syntax().build(),
325+
categories: RuleCategoriesBuilder::default().with_lint().build(),
326+
enabled_rules: Some(&[RuleFilter::Rule("suspicious", "noEmptyBlock")]),
328327
..AnalysisFilter::default()
329328
};
330329

@@ -359,11 +358,11 @@ mod tests {
359358
fn top_level_suppression_multiple() {
360359
const SOURCE: &str = "
361360
/**
362-
* biome-ignore lint/suspicious/noEmptyBlock: reason
361+
* biome-ignore-all lint/suspicious/noEmptyBlock: reason
363362
*/
364363
365364
/**
366-
* biome-ignore lint/correctness/noUnknownProperty: reason2
365+
* biome-ignore-all lint/correctness/noUnknownProperty: reason2
367366
*/
368367
369368
@@ -376,7 +375,11 @@ a {
376375
let parsed = parse_css(SOURCE, CssFileSource::css(), CssParserOptions::default());
377376

378377
let filter = AnalysisFilter {
379-
categories: RuleCategoriesBuilder::default().with_syntax().build(),
378+
categories: RuleCategoriesBuilder::default().with_lint().build(),
379+
enabled_rules: Some(&[
380+
RuleFilter::Rule("suspicious", "noEmptyBlock"),
381+
RuleFilter::Rule("correctness", "noUnknownProperty"),
382+
]),
380383
..AnalysisFilter::default()
381384
};
382385

@@ -411,8 +414,8 @@ a {
411414
fn top_level_suppression_multiple2() {
412415
const SOURCE: &str = "
413416
/**
414-
* biome-ignore lint/suspicious/noEmptyBlock: reason
415-
* biome-ignore lint/correctness/noUnknownProperty: reason2
417+
* biome-ignore-all lint/suspicious/noEmptyBlock: reason
418+
* biome-ignore-all lint/correctness/noUnknownProperty: reason2
416419
*/
417420
418421
#foo {}
@@ -424,7 +427,11 @@ a {
424427
let parsed = parse_css(SOURCE, CssFileSource::css(), CssParserOptions::default());
425428

426429
let filter = AnalysisFilter {
427-
categories: RuleCategoriesBuilder::default().with_syntax().build(),
430+
categories: RuleCategoriesBuilder::default().with_lint().build(),
431+
enabled_rules: Some(&[
432+
RuleFilter::Rule("suspicious", "noEmptyBlock"),
433+
RuleFilter::Rule("correctness", "noUnknownProperty"),
434+
]),
428435
..AnalysisFilter::default()
429436
};
430437

@@ -458,18 +465,16 @@ a {
458465
#[test]
459466
fn top_level_suppression_with_unused() {
460467
const SOURCE: &str = "
461-
/**
462-
*/
463-
464-
#foo {}
468+
#foo { color: red; }
465469
// biome-ignore lint/suspicious/noEmptyBlock: reason
466-
#bar {}
470+
#bar { color: blue; }
467471
";
468472

469473
let parsed = parse_css(SOURCE, CssFileSource::css(), CssParserOptions::default());
470474

471475
let filter = AnalysisFilter {
472-
categories: RuleCategoriesBuilder::default().with_syntax().build(),
476+
categories: RuleCategoriesBuilder::default().with_lint().build(),
477+
enabled_rules: Some(&[RuleFilter::Rule("suspicious", "noEmptyBlock")]),
473478
..AnalysisFilter::default()
474479
};
475480

crates/biome_css_analyze/src/registry.rs

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)