diff --git a/.changeset/tough-pans-greet.md b/.changeset/tough-pans-greet.md new file mode 100644 index 000000000000..fbd395057a9f --- /dev/null +++ b/.changeset/tough-pans-greet.md @@ -0,0 +1,6 @@ +--- +"@biomejs/biome": patch +--- + +Fixed [#6567](https://github.com/biomejs/biome/issues/6567): +[`noUnknownProperty`](https://biomejs.dev/linter/rules/no-unknown-property/) now ignores unknown properties in at-rules which support descriptors. diff --git a/crates/biome_css_analyze/src/lint/correctness/no_unknown_property.rs b/crates/biome_css_analyze/src/lint/correctness/no_unknown_property.rs index 3324250dc361..b13e6e7fddb6 100644 --- a/crates/biome_css_analyze/src/lint/correctness/no_unknown_property.rs +++ b/crates/biome_css_analyze/src/lint/correctness/no_unknown_property.rs @@ -2,9 +2,12 @@ use biome_analyze::{ Ast, Rule, RuleDiagnostic, RuleSource, context::RuleContext, declare_lint_rule, }; use biome_console::markup; -use biome_css_syntax::{CssGenericProperty, TwPluginAtRule}; +use biome_css_syntax::{ + AnyCssAtRule, CssContainerAtRule, CssGenericProperty, CssLayerAtRule, CssMediaAtRule, + CssScopeAtRule, CssStartingStyleAtRule, CssSupportsAtRule, TwApplyAtRule, +}; use biome_diagnostics::Severity; -use biome_rowan::{AstNode, TextRange}; +use biome_rowan::{AstNode, TextRange, declare_node_union}; use biome_rule_options::no_unknown_property::NoUnknownPropertyOptions; use biome_string_case::StrLikeExtension; @@ -76,12 +79,16 @@ impl Rule for NoUnknownProperty { fn run(ctx: &RuleContext) -> Option { let node = ctx.query(); - let is_inside_plugin_at_rule = node - .syntax() - .ancestors() - .skip(1) - .any(|ancestor| TwPluginAtRule::can_cast(ancestor.kind())); - if is_inside_plugin_at_rule { + let is_at_rule_supporting_descriptors = node.syntax().ancestors().skip(1).any(|ancestor| { + if AnyCssAtRule::can_cast(ancestor.kind()) + && !AnyDescriptorSupportingAtRules::can_cast(ancestor.kind()) + { + return true; + } + + false + }); + if is_at_rule_supporting_descriptors { return None; } let property_name = node.name().ok()?.to_trimmed_text(); @@ -116,3 +123,12 @@ impl Rule for NoUnknownProperty { ) } } + +declare_node_union! { + pub AnyDescriptorSupportingAtRules = TwApplyAtRule | CssContainerAtRule + | CssLayerAtRule + | CssMediaAtRule + | CssScopeAtRule + | CssStartingStyleAtRule + | CssSupportsAtRule +} diff --git a/crates/biome_css_analyze/tests/specs/correctness/noUnknownProperty/invalid.at-rules.css b/crates/biome_css_analyze/tests/specs/correctness/noUnknownProperty/invalid.at-rules.css new file mode 100644 index 000000000000..881b88c37b8e --- /dev/null +++ b/crates/biome_css_analyze/tests/specs/correctness/noUnknownProperty/invalid.at-rules.css @@ -0,0 +1,38 @@ +/* should generate diagnostics */ +@media screen { + a { + foo: 1; + } +} + +@supports (display: grid) { + a { + foo: 1; + } +} + +@layer { + a { + foo: 1; + } +} + +@supports (display:grid) { + @media (min-width: 10px) { + foo: 1; + } +} + +@supports (display:grid) { + @media (min-width: 10px) { + a { + foo: 1; + } + } +} + +@layer { + a { + foo: 1; + } +} diff --git a/crates/biome_css_analyze/tests/specs/correctness/noUnknownProperty/invalid.at-rules.css.snap b/crates/biome_css_analyze/tests/specs/correctness/noUnknownProperty/invalid.at-rules.css.snap new file mode 100644 index 000000000000..8a36f9dc5f38 --- /dev/null +++ b/crates/biome_css_analyze/tests/specs/correctness/noUnknownProperty/invalid.at-rules.css.snap @@ -0,0 +1,161 @@ +--- +source: crates/biome_css_analyze/tests/spec_tests.rs +expression: invalid.at-rules.css +--- +# Input +```css +/* should generate diagnostics */ +@media screen { + a { + foo: 1; + } +} + +@supports (display: grid) { + a { + foo: 1; + } +} + +@layer { + a { + foo: 1; + } +} + +@supports (display:grid) { + @media (min-width: 10px) { + foo: 1; + } +} + +@supports (display:grid) { + @media (min-width: 10px) { + a { + foo: 1; + } + } +} + +@layer { + a { + foo: 1; + } +} + +``` + +# Diagnostics +``` +invalid.at-rules.css:4:3 lint/correctness/noUnknownProperty ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Unknown property is not allowed. + + 2 │ @media screen { + 3 │ a { + > 4 │ foo: 1; + │ ^^^ + 5 │ } + 6 │ } + + i See CSS Specifications and browser specific properties for more details. + + i To resolve this issue, replace the unknown property with a valid CSS property. + + +``` + +``` +invalid.at-rules.css:10:3 lint/correctness/noUnknownProperty ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Unknown property is not allowed. + + 8 │ @supports (display: grid) { + 9 │ a { + > 10 │ foo: 1; + │ ^^^ + 11 │ } + 12 │ } + + i See CSS Specifications and browser specific properties for more details. + + i To resolve this issue, replace the unknown property with a valid CSS property. + + +``` + +``` +invalid.at-rules.css:16:3 lint/correctness/noUnknownProperty ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Unknown property is not allowed. + + 14 │ @layer { + 15 │ a { + > 16 │ foo: 1; + │ ^^^ + 17 │ } + 18 │ } + + i See CSS Specifications and browser specific properties for more details. + + i To resolve this issue, replace the unknown property with a valid CSS property. + + +``` + +``` +invalid.at-rules.css:22:3 lint/correctness/noUnknownProperty ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Unknown property is not allowed. + + 20 │ @supports (display:grid) { + 21 │ @media (min-width: 10px) { + > 22 │ foo: 1; + │ ^^^ + 23 │ } + 24 │ } + + i See CSS Specifications and browser specific properties for more details. + + i To resolve this issue, replace the unknown property with a valid CSS property. + + +``` + +``` +invalid.at-rules.css:29:4 lint/correctness/noUnknownProperty ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Unknown property is not allowed. + + 27 │ @media (min-width: 10px) { + 28 │ a { + > 29 │ foo: 1; + │ ^^^ + 30 │ } + 31 │ } + + i See CSS Specifications and browser specific properties for more details. + + i To resolve this issue, replace the unknown property with a valid CSS property. + + +``` + +``` +invalid.at-rules.css:36:3 lint/correctness/noUnknownProperty ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Unknown property is not allowed. + + 34 │ @layer { + 35 │ a { + > 36 │ foo: 1; + │ ^^^ + 37 │ } + 38 │ } + + i See CSS Specifications and browser specific properties for more details. + + i To resolve this issue, replace the unknown property with a valid CSS property. + + +``` diff --git a/crates/biome_css_analyze/tests/specs/correctness/noUnknownProperty/valid.at-rules.css b/crates/biome_css_analyze/tests/specs/correctness/noUnknownProperty/valid.at-rules.css new file mode 100644 index 000000000000..6029f800ca46 --- /dev/null +++ b/crates/biome_css_analyze/tests/specs/correctness/noUnknownProperty/valid.at-rules.css @@ -0,0 +1,18 @@ +/* should not generate diagnostics */ +@font-feature-values "Test" { + @styleset { + some-feature: 1; + } +} + +@font-face { + foo: 0; +} + +@position-try --foo { + bar: 0 +} + +@foo { + bar: 0; +} diff --git a/crates/biome_css_analyze/tests/specs/correctness/noUnknownProperty/valid.at-rules.css.snap b/crates/biome_css_analyze/tests/specs/correctness/noUnknownProperty/valid.at-rules.css.snap new file mode 100644 index 000000000000..18b8be880b9a --- /dev/null +++ b/crates/biome_css_analyze/tests/specs/correctness/noUnknownProperty/valid.at-rules.css.snap @@ -0,0 +1,26 @@ +--- +source: crates/biome_css_analyze/tests/spec_tests.rs +expression: valid.at-rules.css +--- +# Input +```css +/* should not generate diagnostics */ +@font-feature-values "Test" { + @styleset { + some-feature: 1; + } +} + +@font-face { + foo: 0; +} + +@position-try --foo { + bar: 0 +} + +@foo { + bar: 0; +} + +``` diff --git a/crates/biome_css_analyze/tests/specs/correctness/noUnknownProperty/valid.css b/crates/biome_css_analyze/tests/specs/correctness/noUnknownProperty/valid.css index d1852febfeb1..58e6f0f84055 100644 --- a/crates/biome_css_analyze/tests/specs/correctness/noUnknownProperty/valid.css +++ b/crates/biome_css_analyze/tests/specs/correctness/noUnknownProperty/valid.css @@ -1,74 +1,74 @@ /* should not generate diagnostics */ /* General properties */ a { - color: green; + color: green; } a { - fill: black; + fill: black; } /* Firefox-specific property */ a { - -moz-align-self: center; + -moz-align-self: center; } /* WebKit (Safari, Chrome, etc.) specific property */ a { - -webkit-align-self: center; + -webkit-align-self: center; } /* Standard property */ a { - align-self: center; + align-self: center; } /* Additional examples of browser-specific properties */ /* Internet Explorer specific property */ a { - -ms-flex-align: center; + -ms-flex-align: center; } /* Opera specific property */ a { - -o-link: #FF0000; + -o-link: #FF0000; } /* Microsoft Edge specific property */ a { - -ms-scroll-limit: 5px 5px 0px 0px; + -ms-scroll-limit: 5px 5px 0px 0px; } /* Chrome/Safari specific property */ a { - -webkit-mask-image: url(mask.png); + -webkit-mask-image: url(mask.png); } /* Custom property */ a { - --custom-color: #1234560; + --custom-color: #123456; } a { - --custom-margin: 100px; + --custom-margin: 100px; } a { - --custom-property: 10px; + --custom-property: 10px; } /* Composition */ .classA { - color: green; - background: red; + color: green; + background: red; } .classB { - composes: classA; - color: yellow; + composes: classA; + color: yellow; } /* View Transition navigation property (should not be flagged) */ view-transition { - navigation: auto; + navigation: auto; } diff --git a/crates/biome_css_analyze/tests/specs/correctness/noUnknownProperty/valid.css.snap b/crates/biome_css_analyze/tests/specs/correctness/noUnknownProperty/valid.css.snap index a69a5a6b9ee4..e8d2f88d7b43 100644 --- a/crates/biome_css_analyze/tests/specs/correctness/noUnknownProperty/valid.css.snap +++ b/crates/biome_css_analyze/tests/specs/correctness/noUnknownProperty/valid.css.snap @@ -7,78 +7,76 @@ expression: valid.css /* should not generate diagnostics */ /* General properties */ a { - color: green; + color: green; } a { - fill: black; + fill: black; } /* Firefox-specific property */ a { - -moz-align-self: center; + -moz-align-self: center; } /* WebKit (Safari, Chrome, etc.) specific property */ a { - -webkit-align-self: center; + -webkit-align-self: center; } /* Standard property */ a { - align-self: center; + align-self: center; } /* Additional examples of browser-specific properties */ /* Internet Explorer specific property */ a { - -ms-flex-align: center; + -ms-flex-align: center; } /* Opera specific property */ a { - -o-link: #FF0000; + -o-link: #FF0000; } /* Microsoft Edge specific property */ a { - -ms-scroll-limit: 5px 5px 0px 0px; + -ms-scroll-limit: 5px 5px 0px 0px; } /* Chrome/Safari specific property */ a { - -webkit-mask-image: url(mask.png); + -webkit-mask-image: url(mask.png); } /* Custom property */ a { - --custom-color: #1234560; + --custom-color: #123456; } a { - --custom-margin: 100px; + --custom-margin: 100px; } a { - --custom-property: 10px; + --custom-property: 10px; } /* Composition */ .classA { - color: green; - background: red; + color: green; + background: red; } .classB { - composes: classA; - color: yellow; + composes: classA; + color: yellow; } /* View Transition navigation property (should not be flagged) */ view-transition { - navigation: auto; + navigation: auto; } ``` - -_Note: The parser emitted 2 diagnostics which are not shown here._ diff --git a/crates/biome_css_analyze/tests/specs/correctness/noUnknownProperty/valid.options.json b/crates/biome_css_analyze/tests/specs/correctness/noUnknownProperty/valid.options.json new file mode 100644 index 000000000000..aa3813c03861 --- /dev/null +++ b/crates/biome_css_analyze/tests/specs/correctness/noUnknownProperty/valid.options.json @@ -0,0 +1,7 @@ +{ + "css": { + "parser": { + "cssModules": true + } + } +}