Repository: vercel/next.js
Pull request: turbopack-css: demote recoverable CSS parse warnings to Warning severity

### 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()`.


Changed files:
filename: turbopack/crates/turbopack-css/src/process.rs
patch: @@ -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),
-                            };
-
-                            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,
-                            };
-
-                            ParsingIssue {
-                                msg: err.kind.to_string().into(),
-                                stage: IssueStage::Parse,
-                                source: issue_source,
-                                severity,
-                            }
-                            .resolved_cell()
-                            .emit();
-                        }
+                        | lightningcss::error::ParserError::EndOfInput => IssueSeverity::Error,
 
-                        _ => {
-                            // Ignore
-                        }
+                        _ => IssueSeverity::Warning,
+                    };
+
+                    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),
+                    };
+
+                    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]