diff --git a/crates/biome_cli/tests/snapshots/main_cases_handle_css_files/should_lint_files_by_when_enabled.snap b/crates/biome_cli/tests/snapshots/main_cases_handle_css_files/should_lint_files_by_when_enabled.snap index e28159b183e3..79eac9c30c2e 100644 --- a/crates/biome_cli/tests/snapshots/main_cases_handle_css_files/should_lint_files_by_when_enabled.snap +++ b/crates/biome_cli/tests/snapshots/main_cases_handle_css_files/should_lint_files_by_when_enabled.snap @@ -30,9 +30,9 @@ lint ━━━━━━━━━━━━━━━━━━━━━━━━━ # Emitted Messages ```block -input.css:1:6 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +input.css:1:6 lint/nursery/noEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - × Empty blocks aren't allowed. + × An empty block isn't allowed. > 1 │ html {} │ ^^ diff --git a/crates/biome_configuration/src/linter/rules.rs b/crates/biome_configuration/src/linter/rules.rs index 8879f1c7e19a..dd79ed561fa8 100644 --- a/crates/biome_configuration/src/linter/rules.rs +++ b/crates/biome_configuration/src/linter/rules.rs @@ -3309,9 +3309,6 @@ pub struct Nursery { #[doc = "Disallow the use of Math.min and Math.max to clamp a value where the result itself is constant."] #[serde(skip_serializing_if = "Option::is_none")] pub no_constant_math_min_max_clamp: Option>, - #[doc = "Disallow CSS empty blocks."] - #[serde(skip_serializing_if = "Option::is_none")] - pub no_css_empty_block: Option>, #[doc = "Disallow using a callback in asynchronous tests and hooks."] #[serde(skip_serializing_if = "Option::is_none")] pub no_done_callback: Option>, @@ -3331,6 +3328,9 @@ pub struct Nursery { #[serde(skip_serializing_if = "Option::is_none")] pub no_duplicate_selectors_keyframe_block: Option>, + #[doc = "Disallow CSS empty blocks."] + #[serde(skip_serializing_if = "Option::is_none")] + pub no_empty_block: Option>, #[doc = "Disallow variables from evolving into any type through reassignments."] #[serde(skip_serializing_if = "Option::is_none")] pub no_evolving_any: Option>, @@ -3452,13 +3452,13 @@ impl Nursery { pub(crate) const GROUP_RULES: &'static [&'static str] = &[ "noConsole", "noConstantMathMinMaxClamp", - "noCssEmptyBlock", "noDoneCallback", "noDuplicateAtImportRules", "noDuplicateElseIf", "noDuplicateFontNames", "noDuplicateJsonKeys", "noDuplicateSelectorsKeyframeBlock", + "noEmptyBlock", "noEvolvingAny", "noFlatMapIdentity", "noImportantInKeyframe", @@ -3493,13 +3493,13 @@ impl Nursery { "useTopLevelRegex", ]; const RECOMMENDED_RULES: &'static [&'static str] = &[ - "noCssEmptyBlock", "noDoneCallback", "noDuplicateAtImportRules", "noDuplicateElseIf", "noDuplicateFontNames", "noDuplicateJsonKeys", "noDuplicateSelectorsKeyframeBlock", + "noEmptyBlock", "noEvolvingAny", "noFlatMapIdentity", "noImportantInKeyframe", @@ -3600,37 +3600,37 @@ impl Nursery { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[1])); } } - if let Some(rule) = self.no_css_empty_block.as_ref() { + if let Some(rule) = self.no_done_callback.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[2])); } } - if let Some(rule) = self.no_done_callback.as_ref() { + if let Some(rule) = self.no_duplicate_at_import_rules.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[3])); } } - if let Some(rule) = self.no_duplicate_at_import_rules.as_ref() { + if let Some(rule) = self.no_duplicate_else_if.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[4])); } } - if let Some(rule) = self.no_duplicate_else_if.as_ref() { + if let Some(rule) = self.no_duplicate_font_names.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[5])); } } - if let Some(rule) = self.no_duplicate_font_names.as_ref() { + if let Some(rule) = self.no_duplicate_json_keys.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[6])); } } - if let Some(rule) = self.no_duplicate_json_keys.as_ref() { + if let Some(rule) = self.no_duplicate_selectors_keyframe_block.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[7])); } } - if let Some(rule) = self.no_duplicate_selectors_keyframe_block.as_ref() { + if let Some(rule) = self.no_empty_block.as_ref() { if rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[8])); } @@ -3809,37 +3809,37 @@ impl Nursery { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[1])); } } - if let Some(rule) = self.no_css_empty_block.as_ref() { + if let Some(rule) = self.no_done_callback.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[2])); } } - if let Some(rule) = self.no_done_callback.as_ref() { + if let Some(rule) = self.no_duplicate_at_import_rules.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[3])); } } - if let Some(rule) = self.no_duplicate_at_import_rules.as_ref() { + if let Some(rule) = self.no_duplicate_else_if.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[4])); } } - if let Some(rule) = self.no_duplicate_else_if.as_ref() { + if let Some(rule) = self.no_duplicate_font_names.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[5])); } } - if let Some(rule) = self.no_duplicate_font_names.as_ref() { + if let Some(rule) = self.no_duplicate_json_keys.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[6])); } } - if let Some(rule) = self.no_duplicate_json_keys.as_ref() { + if let Some(rule) = self.no_duplicate_selectors_keyframe_block.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[7])); } } - if let Some(rule) = self.no_duplicate_selectors_keyframe_block.as_ref() { + if let Some(rule) = self.no_empty_block.as_ref() { if rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[8])); } @@ -4048,10 +4048,6 @@ impl Nursery { .no_constant_math_min_max_clamp .as_ref() .map(|conf| (conf.level(), conf.get_options())), - "noCssEmptyBlock" => self - .no_css_empty_block - .as_ref() - .map(|conf| (conf.level(), conf.get_options())), "noDoneCallback" => self .no_done_callback .as_ref() @@ -4076,6 +4072,10 @@ impl Nursery { .no_duplicate_selectors_keyframe_block .as_ref() .map(|conf| (conf.level(), conf.get_options())), + "noEmptyBlock" => self + .no_empty_block + .as_ref() + .map(|conf| (conf.level(), conf.get_options())), "noEvolvingAny" => self .no_evolving_any .as_ref() @@ -4219,11 +4219,6 @@ impl Nursery { rule_conf.set_level(severity); } } - "noCssEmptyBlock" => { - if let Some(rule_conf) = &mut self.no_css_empty_block { - rule_conf.set_level(severity); - } - } "noDoneCallback" => { if let Some(rule_conf) = &mut self.no_done_callback { rule_conf.set_level(severity); @@ -4254,6 +4249,11 @@ impl Nursery { rule_conf.set_level(severity); } } + "noEmptyBlock" => { + if let Some(rule_conf) = &mut self.no_empty_block { + rule_conf.set_level(severity); + } + } "noEvolvingAny" => { if let Some(rule_conf) = &mut self.no_evolving_any { rule_conf.set_level(severity); diff --git a/crates/biome_css_analyze/src/lint/nursery.rs b/crates/biome_css_analyze/src/lint/nursery.rs index 70c0be28246b..177f67240b5e 100644 --- a/crates/biome_css_analyze/src/lint/nursery.rs +++ b/crates/biome_css_analyze/src/lint/nursery.rs @@ -2,10 +2,10 @@ use biome_analyze::declare_group; -pub mod no_css_empty_block; pub mod no_duplicate_at_import_rules; pub mod no_duplicate_font_names; pub mod no_duplicate_selectors_keyframe_block; +pub mod no_empty_block; pub mod no_important_in_keyframe; pub mod no_invalid_position_at_import_rule; pub mod no_unknown_function; @@ -20,10 +20,10 @@ declare_group! { pub Nursery { name : "nursery" , rules : [ - self :: no_css_empty_block :: NoCssEmptyBlock , self :: no_duplicate_at_import_rules :: NoDuplicateAtImportRules , self :: no_duplicate_font_names :: NoDuplicateFontNames , self :: no_duplicate_selectors_keyframe_block :: NoDuplicateSelectorsKeyframeBlock , + self :: no_empty_block :: NoEmptyBlock , self :: no_important_in_keyframe :: NoImportantInKeyframe , self :: no_invalid_position_at_import_rule :: NoInvalidPositionAtImportRule , self :: no_unknown_function :: NoUnknownFunction , diff --git a/crates/biome_css_analyze/src/lint/nursery/no_css_empty_block.rs b/crates/biome_css_analyze/src/lint/nursery/no_empty_block.rs similarity index 53% rename from crates/biome_css_analyze/src/lint/nursery/no_css_empty_block.rs rename to crates/biome_css_analyze/src/lint/nursery/no_empty_block.rs index cd1467a3442f..9efc87978825 100644 --- a/crates/biome_css_analyze/src/lint/nursery/no_css_empty_block.rs +++ b/crates/biome_css_analyze/src/lint/nursery/no_empty_block.rs @@ -1,9 +1,7 @@ use biome_analyze::{context::RuleContext, declare_rule, Ast, Rule, RuleDiagnostic, RuleSource}; use biome_console::markup; use biome_css_syntax::stmt_ext::CssBlockLike; -use biome_deserialize_macros::Deserializable; use biome_rowan::AstNode; -use serde::{Deserialize, Serialize}; declare_rule! { /// Disallow CSS empty blocks. @@ -44,64 +42,24 @@ declare_rule! { /// @media print { a { color: pink; } } /// ``` /// - /// ## Options - /// - /// If false, exclude comments from being treated as content inside of a block. - /// - /// ```json - /// { - /// "noCssEmptyBlock": { - /// "options": { - /// "allowComments": false - /// } - /// } - /// } - /// ``` - /// - pub NoCssEmptyBlock { + pub NoEmptyBlock { version: "next", - name: "noCssEmptyBlock", + name: "noEmptyBlock", language: "css", recommended: true, sources: &[RuleSource::Stylelint("no-empty-block")], } } -#[derive(Debug, Clone, Deserialize, Deserializable, Eq, PartialEq, Serialize)] -#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] -#[serde(rename_all = "camelCase", deny_unknown_fields)] -pub struct NoCssEmptyBlockOptions { - pub allow_comments: bool, -} - -impl Default for NoCssEmptyBlockOptions { - fn default() -> Self { - Self { - allow_comments: true, - } - } -} - -impl Rule for NoCssEmptyBlock { +impl Rule for NoEmptyBlock { type Query = Ast; type State = CssBlockLike; type Signals = Option; - type Options = NoCssEmptyBlockOptions; + type Options = (); fn run(ctx: &RuleContext) -> Option { let node = ctx.query(); - let options = ctx.options(); - let allow_comments_inside_empty_block = options.allow_comments; - if allow_comments_inside_empty_block { - let has_comments_inside_block = node.r_curly_token().ok()?.has_leading_comments() - || node.l_curly_token().ok()?.has_trailing_comments(); - - if !node.is_empty() || has_comments_inside_block { - return None; - } else { - return Some(node.clone()); - } - } else if node.is_empty() { + if node.is_empty() { return Some(node.clone()); } @@ -115,7 +73,7 @@ impl Rule for NoCssEmptyBlock { rule_category!(), span, markup! { - "Empty blocks aren't allowed." + "An empty block isn't allowed." }, ) .note(markup! { diff --git a/crates/biome_css_analyze/src/options.rs b/crates/biome_css_analyze/src/options.rs index a04005c52ce6..544a93840219 100644 --- a/crates/biome_css_analyze/src/options.rs +++ b/crates/biome_css_analyze/src/options.rs @@ -2,12 +2,12 @@ use crate::lint; -pub type NoCssEmptyBlock = - ::Options; pub type NoDuplicateAtImportRules = < lint :: nursery :: no_duplicate_at_import_rules :: NoDuplicateAtImportRules as biome_analyze :: Rule > :: Options ; pub type NoDuplicateFontNames = ::Options; pub type NoDuplicateSelectorsKeyframeBlock = < lint :: nursery :: no_duplicate_selectors_keyframe_block :: NoDuplicateSelectorsKeyframeBlock as biome_analyze :: Rule > :: Options ; +pub type NoEmptyBlock = + ::Options; pub type NoImportantInKeyframe = < lint :: nursery :: no_important_in_keyframe :: NoImportantInKeyframe as biome_analyze :: Rule > :: Options ; pub type NoInvalidPositionAtImportRule = < lint :: nursery :: no_invalid_position_at_import_rule :: NoInvalidPositionAtImportRule as biome_analyze :: Rule > :: Options ; pub type NoUnknownFunction = diff --git a/crates/biome_css_analyze/tests/specs/nursery/noCssEmptyBlock/disallowComment.css b/crates/biome_css_analyze/tests/specs/nursery/noCssEmptyBlock/disallowComment.css deleted file mode 100644 index 5715183c5e0f..000000000000 --- a/crates/biome_css_analyze/tests/specs/nursery/noCssEmptyBlock/disallowComment.css +++ /dev/null @@ -1,19 +0,0 @@ -a { /* foo */ } -a { - /* foo */ -} - -.b { /* foo */ } -.b { - /* foo */ -} - -@media print { /* foo */ } -@media print { - /* foo */ -} -@media print { - a { - /* foo */ - } -} \ No newline at end of file diff --git a/crates/biome_css_analyze/tests/specs/nursery/noCssEmptyBlock/disallowComment.css.snap b/crates/biome_css_analyze/tests/specs/nursery/noCssEmptyBlock/disallowComment.css.snap deleted file mode 100644 index b88b124b400d..000000000000 --- a/crates/biome_css_analyze/tests/specs/nursery/noCssEmptyBlock/disallowComment.css.snap +++ /dev/null @@ -1,152 +0,0 @@ ---- -source: crates/biome_css_analyze/tests/spec_tests.rs -expression: disallowComment.css ---- -# Input -```css -a { /* foo */ } -a { - /* foo */ -} - -.b { /* foo */ } -.b { - /* foo */ -} - -@media print { /* foo */ } -@media print { - /* foo */ -} -@media print { - a { - /* foo */ - } -} -``` - -# Diagnostics -``` -disallowComment.css:1:3 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - ! Empty blocks aren't allowed. - - > 1 │ a { /* foo */ } - │ ^^^^^^^^^^^^^ - 2 │ a { - 3 │ /* foo */ - - i Consider removing the empty block or adding styles inside it. - - -``` - -``` -disallowComment.css:2:3 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - ! Empty blocks aren't allowed. - - 1 │ a { /* foo */ } - > 2 │ a { - │ ^ - > 3 │ /* foo */ - > 4 │ } - │ ^ - 5 │ - 6 │ .b { /* foo */ } - - i Consider removing the empty block or adding styles inside it. - - -``` - -``` -disallowComment.css:6:4 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - ! Empty blocks aren't allowed. - - 4 │ } - 5 │ - > 6 │ .b { /* foo */ } - │ ^^^^^^^^^^^^^ - 7 │ .b { - 8 │ /* foo */ - - i Consider removing the empty block or adding styles inside it. - - -``` - -``` -disallowComment.css:7:4 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - ! Empty blocks aren't allowed. - - 6 │ .b { /* foo */ } - > 7 │ .b { - │ ^ - > 8 │ /* foo */ - > 9 │ } - │ ^ - 10 │ - 11 │ @media print { /* foo */ } - - i Consider removing the empty block or adding styles inside it. - - -``` - -``` -disallowComment.css:11:14 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - ! Empty blocks aren't allowed. - - 9 │ } - 10 │ - > 11 │ @media print { /* foo */ } - │ ^^^^^^^^^^^^^ - 12 │ @media print { - 13 │ /* foo */ - - i Consider removing the empty block or adding styles inside it. - - -``` - -``` -disallowComment.css:12:14 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - ! Empty blocks aren't allowed. - - 11 │ @media print { /* foo */ } - > 12 │ @media print { - │ ^ - > 13 │ /* foo */ - > 14 │ } - │ ^ - 15 │ @media print { - 16 │ a { - - i Consider removing the empty block or adding styles inside it. - - -``` - -``` -disallowComment.css:16:5 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - ! Empty blocks aren't allowed. - - 14 │ } - 15 │ @media print { - > 16 │ a { - │ ^ - > 17 │ /* foo */ - > 18 │ } - │ ^ - 19 │ } - - i Consider removing the empty block or adding styles inside it. - - -``` diff --git a/crates/biome_css_analyze/tests/specs/nursery/noCssEmptyBlock/disallowComment.options.json b/crates/biome_css_analyze/tests/specs/nursery/noCssEmptyBlock/disallowComment.options.json deleted file mode 100644 index 8b7ebcfa0717..000000000000 --- a/crates/biome_css_analyze/tests/specs/nursery/noCssEmptyBlock/disallowComment.options.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "$schema": "../../../../../../packages/@biomejs/biome/configuration_schema.json", - "linter": { - "rules": { - "nursery": { - "noCssEmptyBlock": { - "level": "error", - "options": { - "allowComments": false - } - } - } - } - } -} diff --git a/crates/biome_css_analyze/tests/specs/nursery/noCssEmptyBlock/valid.css.snap b/crates/biome_css_analyze/tests/specs/nursery/noCssEmptyBlock/valid.css.snap deleted file mode 100644 index 8ebfac1bab70..000000000000 --- a/crates/biome_css_analyze/tests/specs/nursery/noCssEmptyBlock/valid.css.snap +++ /dev/null @@ -1,77 +0,0 @@ ---- -source: crates/biome_css_analyze/tests/spec_tests.rs -expression: valid.css ---- -# Input -```css -/* CssDeclarationOrRuleBlock */ -a { color: pink; } -a { /* foo */ } -a { - /* foo */ -} -a { - /* foo */ - /* bar */ -} -a { - /*\nfoo\nbar\n*/ -} - -/* CssRuleBlock */ -@media print { a { color: pink; } } -@media print { a { /* foo */ } } - -/* CssDeclarationBlock */ -@font-palette-values --identifier { - font-family: Bixa; -} - -@font-face { - font-family: "Trickster"; - src: - local("Trickster"), - url("trickster-COLRv1.otf") format("opentype") tech(color-COLRv1), - url("trickster-outline.otf") format("opentype"), - url("trickster-outline.woff") format("woff"); -} - -/* CssKeyframesBlock */ -@keyframes slidein { - from { - transform: translateX(0%); - } - - to { - transform: translateX(100%); - } -} - -/* CssFontFeatureValuesBlock */ -@font-feature-values Font One { - @styleset { - nice-style: 12; - } -} - -/* CssPageAtRuleBlock */ -@page { - size: 8.5in 9in; - margin-top: 4in; -} -@page :right { - size: 11in; - margin-top: 4in; -} - - -/* CssDeclarationOrAtRuleBlock */ -@page { - @top-right { - content: "Page " counter(pageNumber); - } -} - -@import "foo.css"; -@import url(x.css) -``` diff --git a/crates/biome_css_analyze/tests/specs/nursery/noCssEmptyBlock/invalid.css b/crates/biome_css_analyze/tests/specs/nursery/noEmptyBlock/invalid.css similarity index 100% rename from crates/biome_css_analyze/tests/specs/nursery/noCssEmptyBlock/invalid.css rename to crates/biome_css_analyze/tests/specs/nursery/noEmptyBlock/invalid.css diff --git a/crates/biome_css_analyze/tests/specs/nursery/noCssEmptyBlock/invalid.css.snap b/crates/biome_css_analyze/tests/specs/nursery/noEmptyBlock/invalid.css.snap similarity index 76% rename from crates/biome_css_analyze/tests/specs/nursery/noCssEmptyBlock/invalid.css.snap rename to crates/biome_css_analyze/tests/specs/nursery/noEmptyBlock/invalid.css.snap index f65db7d66865..c665a7012b95 100644 --- a/crates/biome_css_analyze/tests/specs/nursery/noCssEmptyBlock/invalid.css.snap +++ b/crates/biome_css_analyze/tests/specs/nursery/noEmptyBlock/invalid.css.snap @@ -63,9 +63,9 @@ a { # Diagnostics ``` -invalid.css:2:3 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.css:2:3 lint/nursery/noEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! Empty blocks aren't allowed. + ! An empty block isn't allowed. 1 │ /* CssDeclarationOrRuleBlock */ > 2 │ a {} @@ -79,9 +79,9 @@ invalid.css:2:3 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━ ``` ``` -invalid.css:3:3 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.css:3:3 lint/nursery/noEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! Empty blocks aren't allowed. + ! An empty block isn't allowed. 1 │ /* CssDeclarationOrRuleBlock */ 2 │ a {} @@ -96,9 +96,9 @@ invalid.css:3:3 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━ ``` ``` -invalid.css:4:3 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.css:4:3 lint/nursery/noEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! Empty blocks aren't allowed. + ! An empty block isn't allowed. 2 │ a {} 3 │ a { } @@ -116,9 +116,9 @@ invalid.css:4:3 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━ ``` ``` -invalid.css:8:4 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.css:8:4 lint/nursery/noEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! Empty blocks aren't allowed. + ! An empty block isn't allowed. 6 │ } 7 │ @@ -133,9 +133,9 @@ invalid.css:8:4 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━ ``` ``` -invalid.css:9:4 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.css:9:4 lint/nursery/noEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! Empty blocks aren't allowed. + ! An empty block isn't allowed. 8 │ .b {} > 9 │ .b { } @@ -149,9 +149,9 @@ invalid.css:9:4 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━ ``` ``` -invalid.css:10:4 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.css:10:4 lint/nursery/noEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! Empty blocks aren't allowed. + ! An empty block isn't allowed. 8 │ .b {} 9 │ .b { } @@ -169,9 +169,9 @@ invalid.css:10:4 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━ ``` ``` -invalid.css:15:14 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.css:15:14 lint/nursery/noEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! Empty blocks aren't allowed. + ! An empty block isn't allowed. 14 │ /* CssRuleBlock */ > 15 │ @media print {} @@ -185,9 +185,9 @@ invalid.css:15:14 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━ ``` ``` -invalid.css:16:14 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.css:16:14 lint/nursery/noEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! Empty blocks aren't allowed. + ! An empty block isn't allowed. 14 │ /* CssRuleBlock */ 15 │ @media print {} @@ -205,9 +205,9 @@ invalid.css:16:14 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━ ``` ``` -invalid.css:19:18 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.css:19:18 lint/nursery/noEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! Empty blocks aren't allowed. + ! An empty block isn't allowed. 18 │ } > 19 │ @media print { a {} } @@ -221,9 +221,9 @@ invalid.css:19:18 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━ ``` ``` -invalid.css:22:30 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.css:22:30 lint/nursery/noEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! Empty blocks aren't allowed. + ! An empty block isn't allowed. 21 │ /* CssDeclarationBlock */ > 22 │ @font-palette-values --ident {} @@ -237,9 +237,9 @@ invalid.css:22:30 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━ ``` ``` -invalid.css:23:12 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.css:23:12 lint/nursery/noEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! Empty blocks aren't allowed. + ! An empty block isn't allowed. 21 │ /* CssDeclarationBlock */ 22 │ @font-palette-values --ident {} @@ -254,9 +254,9 @@ invalid.css:23:12 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━ ``` ``` -invalid.css:26:20 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.css:26:20 lint/nursery/noEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! Empty blocks aren't allowed. + ! An empty block isn't allowed. 25 │ /* CssKeyframesBlock */ > 26 │ @keyframes slidein {} @@ -270,9 +270,9 @@ invalid.css:26:20 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━ ``` ``` -invalid.css:28:10 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.css:28:10 lint/nursery/noEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! Empty blocks aren't allowed. + ! An empty block isn't allowed. 26 │ @keyframes slidein {} 27 │ @keyframes slidein { @@ -289,9 +289,9 @@ invalid.css:28:10 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━ ``` ``` -invalid.css:38:13 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.css:38:13 lint/nursery/noEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! Empty blocks aren't allowed. + ! An empty block isn't allowed. 36 │ /* CssFontFeatureValuesBlock */ 37 │ @font-feature-values Font One { @@ -309,9 +309,9 @@ invalid.css:38:13 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━ ``` ``` -invalid.css:44:7 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.css:44:7 lint/nursery/noEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! Empty blocks aren't allowed. + ! An empty block isn't allowed. 43 │ /* CssPageAtRuleBlock */ > 44 │ @page {} @@ -325,9 +325,9 @@ invalid.css:44:7 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━ ``` ``` -invalid.css:45:14 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.css:45:14 lint/nursery/noEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! Empty blocks aren't allowed. + ! An empty block isn't allowed. 43 │ /* CssPageAtRuleBlock */ 44 │ @page {} @@ -343,9 +343,9 @@ invalid.css:45:14 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━ ``` ``` -invalid.css:50:28 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.css:50:28 lint/nursery/noEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! Empty blocks aren't allowed. + ! An empty block isn't allowed. 49 │ /* CssDeclarationOrAtRuleBlock */ > 50 │ @page :left { @left-middle {} background: red; } @@ -359,9 +359,9 @@ invalid.css:50:28 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━ ``` ``` -invalid.css:52:16 lint/nursery/noCssEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.css:52:16 lint/nursery/noEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ! Empty blocks aren't allowed. + ! An empty block isn't allowed. 50 │ @page :left { @left-middle {} background: red; } 51 │ @page { diff --git a/crates/biome_css_analyze/tests/specs/nursery/noCssEmptyBlock/valid.css b/crates/biome_css_analyze/tests/specs/nursery/noEmptyBlock/valid.css similarity index 100% rename from crates/biome_css_analyze/tests/specs/nursery/noCssEmptyBlock/valid.css rename to crates/biome_css_analyze/tests/specs/nursery/noEmptyBlock/valid.css diff --git a/crates/biome_css_analyze/tests/specs/nursery/noEmptyBlock/valid.css.snap b/crates/biome_css_analyze/tests/specs/nursery/noEmptyBlock/valid.css.snap new file mode 100644 index 000000000000..a029567d6246 --- /dev/null +++ b/crates/biome_css_analyze/tests/specs/nursery/noEmptyBlock/valid.css.snap @@ -0,0 +1,173 @@ +--- +source: crates/biome_css_analyze/tests/spec_tests.rs +expression: valid.css +--- +# Input +```css +/* CssDeclarationOrRuleBlock */ +a { color: pink; } +a { /* foo */ } +a { + /* foo */ +} +a { + /* foo */ + /* bar */ +} +a { + /*\nfoo\nbar\n*/ +} + +/* CssRuleBlock */ +@media print { a { color: pink; } } +@media print { a { /* foo */ } } + +/* CssDeclarationBlock */ +@font-palette-values --identifier { + font-family: Bixa; +} + +@font-face { + font-family: "Trickster"; + src: + local("Trickster"), + url("trickster-COLRv1.otf") format("opentype") tech(color-COLRv1), + url("trickster-outline.otf") format("opentype"), + url("trickster-outline.woff") format("woff"); +} + +/* CssKeyframesBlock */ +@keyframes slidein { + from { + transform: translateX(0%); + } + + to { + transform: translateX(100%); + } +} + +/* CssFontFeatureValuesBlock */ +@font-feature-values Font One { + @styleset { + nice-style: 12; + } +} + +/* CssPageAtRuleBlock */ +@page { + size: 8.5in 9in; + margin-top: 4in; +} +@page :right { + size: 11in; + margin-top: 4in; +} + + +/* CssDeclarationOrAtRuleBlock */ +@page { + @top-right { + content: "Page " counter(pageNumber); + } +} + +@import "foo.css"; +@import url(x.css) +``` + +# Diagnostics +``` +valid.css:3:3 lint/nursery/noEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! An empty block isn't allowed. + + 1 │ /* CssDeclarationOrRuleBlock */ + 2 │ a { color: pink; } + > 3 │ a { /* foo */ } + │ ^^^^^^^^^^^^^ + 4 │ a { + 5 │ /* foo */ + + i Consider removing the empty block or adding styles inside it. + + +``` + +``` +valid.css:4:3 lint/nursery/noEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! An empty block isn't allowed. + + 2 │ a { color: pink; } + 3 │ a { /* foo */ } + > 4 │ a { + │ ^ + > 5 │ /* foo */ + > 6 │ } + │ ^ + 7 │ a { + 8 │ /* foo */ + + i Consider removing the empty block or adding styles inside it. + + +``` + +``` +valid.css:7:3 lint/nursery/noEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! An empty block isn't allowed. + + 5 │ /* foo */ + 6 │ } + > 7 │ a { + │ ^ + > 8 │ /* foo */ + > 9 │ /* bar */ + > 10 │ } + │ ^ + 11 │ a { + 12 │ /*\nfoo\nbar\n*/ + + i Consider removing the empty block or adding styles inside it. + + +``` + +``` +valid.css:11:3 lint/nursery/noEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! An empty block isn't allowed. + + 9 │ /* bar */ + 10 │ } + > 11 │ a { + │ ^ + > 12 │ /*\nfoo\nbar\n*/ + > 13 │ } + │ ^ + 14 │ + 15 │ /* CssRuleBlock */ + + i Consider removing the empty block or adding styles inside it. + + +``` + +``` +valid.css:17:18 lint/nursery/noEmptyBlock ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! An empty block isn't allowed. + + 15 │ /* CssRuleBlock */ + 16 │ @media print { a { color: pink; } } + > 17 │ @media print { a { /* foo */ } } + │ ^^^^^^^^^^^^^ + 18 │ + 19 │ /* CssDeclarationBlock */ + + i Consider removing the empty block or adding styles inside it. + + +``` diff --git a/crates/biome_diagnostics_categories/src/categories.rs b/crates/biome_diagnostics_categories/src/categories.rs index 3f566787414f..e9ad6fc5194a 100644 --- a/crates/biome_diagnostics_categories/src/categories.rs +++ b/crates/biome_diagnostics_categories/src/categories.rs @@ -111,7 +111,7 @@ define_categories! { "lint/correctness/useYield": "https://biomejs.dev/linter/rules/use-yield", "lint/nursery/noConsole": "https://biomejs.dev/linter/rules/no-console", "lint/nursery/noConstantMathMinMaxClamp": "https://biomejs.dev/linter/rules/no-constant-math-min-max-clamp", - "lint/nursery/noCssEmptyBlock": "https://biomejs.dev/linter/rules/no-css-empty-block", + "lint/nursery/noEmptyBlock": "https://biomejs.dev/linter/rules/no-empty-block", "lint/nursery/noDoneCallback": "https://biomejs.dev/linter/rules/no-done-callback", "lint/nursery/noDuplicateAtImportRules": "https://biomejs.dev/linter/rules/no-duplicate-at-import-rules", "lint/nursery/noDuplicateElseIf": "https://biomejs.dev/linter/rules/no-duplicate-else-if", diff --git a/packages/@biomejs/backend-jsonrpc/src/workspace.ts b/packages/@biomejs/backend-jsonrpc/src/workspace.ts index 98b245bd31b3..5bd289d82406 100644 --- a/packages/@biomejs/backend-jsonrpc/src/workspace.ts +++ b/packages/@biomejs/backend-jsonrpc/src/workspace.ts @@ -961,10 +961,6 @@ export interface Nursery { * Disallow the use of Math.min and Math.max to clamp a value where the result itself is constant. */ noConstantMathMinMaxClamp?: RuleFixConfiguration_for_Null; - /** - * Disallow CSS empty blocks. - */ - noCssEmptyBlock?: RuleConfiguration_for_NoCssEmptyBlockOptions; /** * Disallow using a callback in asynchronous tests and hooks. */ @@ -989,6 +985,10 @@ export interface Nursery { * Disallow duplicate selectors within keyframe blocks. */ noDuplicateSelectorsKeyframeBlock?: RuleConfiguration_for_Null; + /** + * Disallow CSS empty blocks. + */ + noEmptyBlock?: RuleConfiguration_for_Null; /** * Disallow variables from evolving into any type through reassignments. */ @@ -1659,9 +1659,6 @@ export type RuleConfiguration_for_HooksOptions = export type RuleConfiguration_for_DeprecatedHooksOptions = | RulePlainConfiguration | RuleWithOptions_for_DeprecatedHooksOptions; -export type RuleConfiguration_for_NoCssEmptyBlockOptions = - | RulePlainConfiguration - | RuleWithOptions_for_NoCssEmptyBlockOptions; export type RuleConfiguration_for_RestrictedImportsOptions = | RulePlainConfiguration | RuleWithOptions_for_RestrictedImportsOptions; @@ -1749,16 +1746,6 @@ export interface RuleWithOptions_for_DeprecatedHooksOptions { */ options: DeprecatedHooksOptions; } -export interface RuleWithOptions_for_NoCssEmptyBlockOptions { - /** - * The severity of the emitted diagnostics by the rule - */ - level: RulePlainConfiguration; - /** - * Rule's options - */ - options: NoCssEmptyBlockOptions; -} export interface RuleWithOptions_for_RestrictedImportsOptions { /** * The severity of the emitted diagnostics by the rule @@ -1861,9 +1848,6 @@ export interface HooksOptions { * Options for the `useHookAtTopLevel` rule have been deprecated, since we now use the React hook naming convention to determine whether a function is a hook. */ export interface DeprecatedHooksOptions {} -export interface NoCssEmptyBlockOptions { - allowComments: boolean; -} /** * Options for the rule `noRestrictedImports`. */ @@ -2283,7 +2267,7 @@ export type Category = | "lint/correctness/useYield" | "lint/nursery/noConsole" | "lint/nursery/noConstantMathMinMaxClamp" - | "lint/nursery/noCssEmptyBlock" + | "lint/nursery/noEmptyBlock" | "lint/nursery/noDoneCallback" | "lint/nursery/noDuplicateAtImportRules" | "lint/nursery/noDuplicateElseIf" diff --git a/packages/@biomejs/biome/configuration_schema.json b/packages/@biomejs/biome/configuration_schema.json index dba7a0d364bb..f82b38f7a69a 100644 --- a/packages/@biomejs/biome/configuration_schema.json +++ b/packages/@biomejs/biome/configuration_schema.json @@ -1599,18 +1599,6 @@ }, "additionalProperties": false }, - "NoCssEmptyBlockConfiguration": { - "anyOf": [ - { "$ref": "#/definitions/RulePlainConfiguration" }, - { "$ref": "#/definitions/RuleWithNoCssEmptyBlockOptions" } - ] - }, - "NoCssEmptyBlockOptions": { - "type": "object", - "required": ["allowComments"], - "properties": { "allowComments": { "type": "boolean" } }, - "additionalProperties": false - }, "Nursery": { "description": "A list of rules that belong to this group", "type": "object", @@ -1633,13 +1621,6 @@ { "type": "null" } ] }, - "noCssEmptyBlock": { - "description": "Disallow CSS empty blocks.", - "anyOf": [ - { "$ref": "#/definitions/NoCssEmptyBlockConfiguration" }, - { "type": "null" } - ] - }, "noDoneCallback": { "description": "Disallow using a callback in asynchronous tests and hooks.", "anyOf": [ @@ -1682,6 +1663,13 @@ { "type": "null" } ] }, + "noEmptyBlock": { + "description": "Disallow CSS empty blocks.", + "anyOf": [ + { "$ref": "#/definitions/RuleConfiguration" }, + { "type": "null" } + ] + }, "noEvolvingAny": { "description": "Disallow variables from evolving into any type through reassignments.", "anyOf": [ @@ -2354,21 +2342,6 @@ }, "additionalProperties": false }, - "RuleWithNoCssEmptyBlockOptions": { - "type": "object", - "required": ["level", "options"], - "properties": { - "level": { - "description": "The severity of the emitted diagnostics by the rule", - "allOf": [{ "$ref": "#/definitions/RulePlainConfiguration" }] - }, - "options": { - "description": "Rule's options", - "allOf": [{ "$ref": "#/definitions/NoCssEmptyBlockOptions" }] - } - }, - "additionalProperties": false - }, "RuleWithNoOptions": { "type": "object", "required": ["level"],