Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/no-deprecated-media-type.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@biomejs/biome": patch
---

Added the `noDeprecatedMediaType` CSS rule to flag deprecated media types like `tv` and `handheld`.
4 changes: 4 additions & 0 deletions crates/biome_configuration/src/analyzer/linter/rules.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion crates/biome_css_analyze/src/lint/nursery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
//! Generated file, do not edit by hand, see `xtask/codegen`

use biome_analyze::declare_lint_group;
pub mod no_deprecated_media_type;
pub mod no_empty_source;
pub mod no_excessive_lines_per_file;
pub mod no_hex_colors;
declare_lint_group! { pub Nursery { name : "nursery" , rules : [self :: no_empty_source :: NoEmptySource , self :: no_excessive_lines_per_file :: NoExcessiveLinesPerFile , self :: no_hex_colors :: NoHexColors ,] } }
declare_lint_group! { pub Nursery { name : "nursery" , rules : [self :: no_deprecated_media_type :: NoDeprecatedMediaType , self :: no_empty_source :: NoEmptySource , self :: no_excessive_lines_per_file :: NoExcessiveLinesPerFile , self :: no_hex_colors :: NoHexColors ,] } }
150 changes: 150 additions & 0 deletions crates/biome_css_analyze/src/lint/nursery/no_deprecated_media_type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
use biome_analyze::{
Ast, Rule, RuleDiagnostic, RuleSource, context::RuleContext, declare_lint_rule,
};
use biome_console::markup;
use biome_css_syntax::CssMediaType;
use biome_rowan::AstNode;
use biome_rule_options::no_deprecated_media_type::NoDeprecatedMediaTypeOptions;
use biome_string_case::StrLikeExtension;

declare_lint_rule! {
/// Disallow deprecated media types.
///
/// Several media types defined in earlier specifications have been deprecated and should
/// no longer be used. The deprecated media types are still recognized, but they match nothing.
///
/// For details on media types, see the
/// [Media Queries Level 5 specification](https://drafts.csswg.org/mediaqueries-5/#media-types).
///
/// ## Examples
///
/// ### Invalid
///
/// ```css,expect_diagnostic
/// @media tv {}
/// ```
///
/// ```css,expect_diagnostic
/// @media handheld and (min-width: 480px) {}
/// ```
///
/// ### Valid
///
/// ```css
/// @media screen {}
/// ```
///
/// ```css
/// @media print and (min-resolution: 300dpi) {}
/// ```
///
/// ## Options
///
/// ### `allow`
///
/// Media types to allow (case-insensitive).
///
/// ```json,options
/// {
/// "options": {
/// "allow": ["tv", "speech"]
/// }
/// }
/// ```
///
/// #### Valid
///
/// ```css,use_options
/// @media tv {}
/// @media speech {}
/// ```
///
pub NoDeprecatedMediaType {
version: "next",
name: "noDeprecatedMediaType",
language: "css",
recommended: false,
sources: &[RuleSource::Stylelint("media-type-no-deprecated").same()],
}
}

impl Rule for NoDeprecatedMediaType {
type Query = Ast<CssMediaType>;
type State = ();
type Signals = Option<Self::State>;
type Options = NoDeprecatedMediaTypeOptions;

fn run(ctx: &RuleContext<Self>) -> Self::Signals {
let node = ctx.query();
let media_type = node.value().ok().and_then(|v| v.value_token().ok())?;
let media_type = media_type.text_trimmed();

// Check allow list from options
if let Some(allow_list) = &ctx.options().allow {
for allowed in allow_list {
if media_type.eq_ignore_ascii_case(allowed) {
return None;
}
}
}

// FIXME: Optimize to avoid allocation
let media_type = media_type.to_ascii_lowercase_cow();
if DEPRECATED_MEDIA_TYPES
.binary_search(&media_type.as_ref())
.is_ok()
{
return Some(());
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

None
}

fn diagnostic(ctx: &RuleContext<Self>, _state: &Self::State) -> Option<RuleDiagnostic> {
let media_type = ctx
.query()
.value()
.ok()
.and_then(|v| v.value_token().ok())?;
let media_type = media_type.text_trimmed();
Some(
RuleDiagnostic::new(
rule_category!(),
ctx.query().range(),
markup! {
"Unexpected deprecated media type: "<Emphasis>{ media_type }</Emphasis>
},
)
.note(markup! {
"Deprecated media types are recognized but match nothing; prefer using media features or recommended media types."
})
.footer_list(
markup! {
"Recommended media types include:"
},
["all", "print", "screen"],
),
)
}
}

const DEPRECATED_MEDIA_TYPES: [&str; 8] = [
"aural",
"braille",
"embossed",
"handheld",
"projection",
"speech",
"tty",
"tv",
];

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn builtin_list_is_sorted() {
assert!(DEPRECATED_MEDIA_TYPES.is_sorted());
Comment thread
dyc3 marked this conversation as resolved.
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/* should generate diagnostics */
@media tv {}
@media handheld and (min-width: 480px) {}
@media speech {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
---
source: crates/biome_css_analyze/tests/spec_tests.rs
expression: invalid.css
---
# Input
```css
/* should generate diagnostics */
@media tv {}
@media handheld and (min-width: 480px) {}
@media speech {}

```

# Diagnostics
```
invalid.css:2:8 lint/nursery/noDeprecatedMediaType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

i Unexpected deprecated media type: tv

1 │ /* should generate diagnostics */
> 2 │ @media tv {}
│ ^^
3 │ @media handheld and (min-width: 480px) {}
4 │ @media speech {}

i Deprecated media types are recognized but match nothing; prefer using media features or recommended media types.

i This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.

i Recommended media types include:

- all
- print
- screen


```

```
invalid.css:3:8 lint/nursery/noDeprecatedMediaType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

i Unexpected deprecated media type: handheld

1 │ /* should generate diagnostics */
2 │ @media tv {}
> 3 │ @media handheld and (min-width: 480px) {}
│ ^^^^^^^^
4 │ @media speech {}
5 │

i Deprecated media types are recognized but match nothing; prefer using media features or recommended media types.

i This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.

i Recommended media types include:

- all
- print
- screen


```

```
invalid.css:4:8 lint/nursery/noDeprecatedMediaType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

i Unexpected deprecated media type: speech

2 │ @media tv {}
3 │ @media handheld and (min-width: 480px) {}
> 4 │ @media speech {}
│ ^^^^^^
5 │

i Deprecated media types are recognized but match nothing; prefer using media features or recommended media types.

i This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.

i Recommended media types include:

- all
- print
- screen


```
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/* should not generate diagnostics */
@media speech {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
source: crates/biome_css_analyze/tests/spec_tests.rs
expression: valid-allowed.css
---
# Input
```css
/* should not generate diagnostics */
@media speech {}

```
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"$schema": "../../../../../../packages/@biomejs/biome/configuration_schema.json",
"linter": {
"rules": {
"nursery": {
"noDeprecatedMediaType": {
"level": "error",
"options": {
"allow": ["speech"]
}
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/* should not generate diagnostics */
@media screen {}
@media print and (min-resolution: 300dpi) {}
@media (max-width: 600px) {}
@media (min-width: 900px) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
source: crates/biome_css_analyze/tests/spec_tests.rs
expression: valid.css
---
# Input
```css
/* should not generate diagnostics */
@media screen {}
@media print and (min-resolution: 300dpi) {}
@media (max-width: 600px) {}
@media (min-width: 900px) {}

```
1 change: 1 addition & 0 deletions crates/biome_diagnostics_categories/src/categories.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/biome_rule_options/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ pub mod no_debugger;
pub mod no_default_export;
pub mod no_delete;
pub mod no_deprecated_imports;
pub mod no_deprecated_media_type;
pub mod no_descending_specificity;
pub mod no_distracting_elements;
pub mod no_div_regex;
Expand Down
11 changes: 11 additions & 0 deletions crates/biome_rule_options/src/no_deprecated_media_type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use biome_deserialize_macros::{Deserializable, Merge};
use serde::{Deserialize, Serialize};

#[derive(Default, Clone, Debug, Deserialize, Deserializable, Merge, Eq, PartialEq, Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(rename_all = "camelCase", deny_unknown_fields, default)]
pub struct NoDeprecatedMediaTypeOptions {
/// Media types to allow (case-insensitive).
#[serde(skip_serializing_if = "Option::is_none")]
pub allow: Option<Box<[String]>>,
}
Loading
Loading