turbopack-css: demote recoverable CSS parse warnings to Warning severity (#91524)

### What?

Extends the CSS parse warning severity improvements in
`turbopack/crates/turbopack-css/src/process.rs`.

Canary (#90025, #91513) already:
- Added a `severity` field to `ParsingIssue` and a `fn severity()`
override
- Demoted `UnsupportedPseudoClass` / `UnsupportedPseudoElement` selector
errors from `Error` to `Warning`
- Still **silently dropped** all other unrecognized parser warning kinds
(`_ => { // Ignore }`)

This PR completes the work:

1. **Surfaces all previously-ignored parser warnings as
`IssueSeverity::Warning`** — the `_ => { // Ignore }` arm now emits a
`ParsingIssue` at `Warning` severity instead of discarding it.

2. **Refactors the warning loop** — the nested severity match inside the
existing `match err.kind` arm is replaced with a single top-level `let
severity = match err.kind { … }` followed by an unconditional emit. This
is cleaner and makes the severity logic easier to follow.

Hard parse/transform errors (`Err(e)` from `parse_css_stylesheet`,
minify errors, CSS module pure-selector errors) are unchanged — they
remain `IssueSeverity::Error`.

### Why?

Silently dropping parser warnings hides useful diagnostic information
from developers. Surfacing them as `Warning` gives visibility without
marking the build as broken.

The restructure also avoids a redundant
`UnsupportedPseudoClass`/`UnsupportedPseudoElement` check inside a
nested match — the top-level arm order (specific pseudo variants before
the catch-all `SelectorError(..)`) handles precedence correctly.

### How?

- Removed the now-unused `error::SelectorError` short import
(fully-qualified paths are used in the match).
- Replaced the `match err.kind { <arms that emit> … _ => { // Ignore }
}` pattern with:
1. `let severity = match err.kind { UnsupportedPseudo* => Warning, hard
errors => Error, _ => Warning };`
2. Unconditional `IssueSource` construction and `ParsingIssue {
severity, … }.emit()`.

Co-authored-by: Tobias Koppers <[email protected]>
Co-authored-by: Claude <[email protected]>
This commit is contained in:
Tobias Koppers
2026-03-19 10:43:41 +00:00
committed by GitHub
co-authored by Tobias Koppers Claude
parent 0f089d5f9b
commit 046e0c4a00
+35 -41
View File
@@ -3,7 +3,6 @@ use std::sync::{Arc, RwLock};
use anyhow::{Result, bail};
use lightningcss::{
css_modules::{CssModuleExport, Pattern, Segment},
error::SelectorError,
stylesheet::{MinifyOptions, ParserOptions, PrinterOptions, StyleSheet, ToCssResult},
targets::{BrowserslistConfig, Features, Targets},
traits::ToCss,
@@ -489,49 +488,44 @@ async fn process_content(
) {
Ok(mut ss) => {
for err in warnings.read().unwrap().iter() {
match err.kind {
// Unsupported pseudo-classes/elements are common in real-world CSS
// (vendor prefixes, custom frameworks) and do not prevent the
// stylesheet from being used — treat them as recoverable warnings.
// All other previously-ignored parser warnings are also surfaced.
let severity = match err.kind {
lightningcss::error::ParserError::SelectorError(
lightningcss::error::SelectorError::UnsupportedPseudoClass(_)
| lightningcss::error::SelectorError::UnsupportedPseudoElement(_),
) => IssueSeverity::Warning,
lightningcss::error::ParserError::UnexpectedToken(_)
| lightningcss::error::ParserError::UnexpectedImportRule
| lightningcss::error::ParserError::SelectorError(..)
| lightningcss::error::ParserError::EndOfInput => {
let issue_source = match &err.loc {
Some(loc) => IssueSource::from_single_line_col(
source,
SourcePos {
// lightningcss::ErrorLocation is 1-based for column only
line: loc.line,
column: loc.column - 1,
},
),
None => IssueSource::from_source_only(source),
};
| lightningcss::error::ParserError::EndOfInput => IssueSeverity::Error,
let severity = match &err.kind {
lightningcss::error::ParserError::SelectorError(
SelectorError::UnsupportedPseudoClass(_)
| SelectorError::UnsupportedPseudoElement(_),
) => {
// In most cases, these are new selectors not yet
// implemented in LightningCSS.
IssueSeverity::Warning
}
_ => IssueSeverity::Error,
};
_ => IssueSeverity::Warning,
};
ParsingIssue {
msg: err.kind.to_string().into(),
stage: IssueStage::Parse,
source: issue_source,
severity,
}
.resolved_cell()
.emit();
}
let issue_source = match &err.loc {
Some(loc) => IssueSource::from_single_line_col(
source,
SourcePos {
// lightningcss::ErrorLocation is 1-based for column only
line: loc.line,
column: loc.column - 1,
},
),
None => IssueSource::from_source_only(source),
};
_ => {
// Ignore
}
ParsingIssue {
severity,
msg: err.kind.to_string().into(),
stage: IssueStage::Parse,
source: issue_source,
}
.resolved_cell()
.emit();
}
let targets = *get_lightningcss_browser_targets(
@@ -561,10 +555,10 @@ async fn process_content(
None => IssueSource::from_source_only(source),
};
ParsingIssue {
severity: IssueSeverity::Error,
msg: e.kind.to_string().into(),
stage: IssueStage::Transform,
source: issue_source,
severity: IssueSeverity::Error,
}
.resolved_cell()
.emit();
@@ -601,10 +595,10 @@ async fn process_content(
None => IssueSource::from_source_only(source),
};
ParsingIssue {
severity: IssueSeverity::Error,
msg: e.kind.to_string().into(),
stage: IssueStage::Parse,
source: issue_source,
severity: IssueSeverity::Error,
}
.resolved_cell()
.emit();
@@ -651,6 +645,7 @@ impl CssError {
match self {
CssError::CssSelectorInModuleNotPure { selector } => {
ParsingIssue {
severity: IssueSeverity::Error,
msg: format!(
"Selector \"{selector}\" is not pure. Pure selectors must contain at \
least one local class or id."
@@ -659,7 +654,6 @@ impl CssError {
stage: IssueStage::Transform,
// TODO: This should include the location of the selector in the file.
source: IssueSource::from_source_only(source),
severity: IssueSeverity::Error,
}
.resolved_cell()
.emit();
@@ -756,10 +750,10 @@ fn generate_css_source_map(source_map: &parcel_sourcemap::SourceMap) -> Result<R
#[turbo_tasks::value]
struct ParsingIssue {
severity: IssueSeverity,
msg: RcStr,
stage: IssueStage,
source: IssueSource,
severity: IssueSeverity,
}
#[turbo_tasks::value_impl]