{"record":{"id":"c061026a3ae5bbaa","repo":"swc-project/swc","slug":"expected-left-comparison-operator-should-be-equal","errorCode":null,"errorMessage":"Expected left comparison operator should be equal right comparison operator","messagePattern":"Expected left comparison operator should be equal right comparison operator","errorType":"validation","errorClass":"swc_css_parser::error::Error","httpStatus":null,"severity":"error","filePath":"crates/swc_css_parser/src/parser/at_rules/mod.rs","lineNumber":1857,"sourceCode":"\n                let is_valid_operator = match left_comparison {\n                    MediaFeatureRangeComparison::Lt | MediaFeatureRangeComparison::Le\n                        if right_comparison == MediaFeatureRangeComparison::Lt\n                            || right_comparison == MediaFeatureRangeComparison::Le =>\n                    {\n                        true\n                    }\n                    MediaFeatureRangeComparison::Gt | MediaFeatureRangeComparison::Ge\n                        if right_comparison == MediaFeatureRangeComparison::Gt\n                            || right_comparison == MediaFeatureRangeComparison::Ge =>\n                    {\n                        true\n                    }\n                    _ => false,\n                };\n\n                if !is_valid_operator {\n                    return Err(Error::new(\n                        span,\n                        ErrorKind::Expected(\n                            \"left comparison operator should be equal right comparison operator\",\n                        ),\n                    ));\n                }\n\n                Ok(MediaFeature::RangeInterval(MediaFeatureRangeInterval {\n                    span: span!(self, span.lo),\n                    left: Box::new(left),\n                    left_comparison,\n                    name,\n                    right_comparison,\n                    right,\n                }))\n            }\n            _ => Err(Error::new(span, ErrorKind::Expected(\"identifier value\"))),\n        }","sourceCodeStart":1839,"sourceCodeEnd":1875,"githubUrl":"https://github.com/swc-project/swc/blob/5176682b65416c6b5de6b47379ae1588ea3ecb3f/crates/swc_css_parser/src/parser/at_rules/mod.rs#L1839-L1875","documentation":"Validation applied after parsing a range interval '(a OP1 name OP2 c)': both comparisons must point the same way — OP1 and OP2 must both come from {<, <=} or both from {>, >=}. Mixing directions (for example <= with >=) produces ErrorKind::Expected(\"left comparison operator should be equal right comparison operator\"). The span is the whole feature, so the message plus span identifies which interval is inconsistent.","triggerScenarios":"'@media (400px <= width >= 700px)', '@media (400px < width >= 700px)' — any interval whose two operators have opposite directions.","commonSituations":"Hand-typed intervals where the second operator is flipped, and code generation that interpolates 'min' and 'max' operators independently so they can disagree.","solutions":["Make both operators the same direction: @media (400px <= width <= 700px)","Or split the constraint into two conjoined features: @media (min-width: 400px) and (max-width: 700px)","When generating intervals, derive the second operator from the first instead of a separate variable"],"exampleFix":"/* before */\n@media (400px <= width >= 700px) { }\n\n/* after */\n@media (400px <= width <= 700px) { }","handlingStrategy":"validation","validationCode":"fn interval_directions_ok(css: &str) -> bool {\n    for cap in css.split('(').skip(1) {\n        let inner = cap.split(')').next().unwrap_or(\"\");\n        let toks: Vec<&str> = inner.split_whitespace().collect();\n        if toks.len() == 5 {\n            let lt_family = |o: &str| o == \"<\" || o == \"<=\";\n            let (a, b) = (toks[1], toks[3]);\n            if [\"<\", \"<=\", \">\", \">=\"].contains(&a) && [\"<\", \"<=\", \">\", \">=\"].contains(&b) {\n                if lt_family(a) != lt_family(b) {\n                    return false;\n                }\n            }\n        }\n    }\n    true\n}","typeGuard":"fn is_interval_direction_error(e: &swc_css_parser::error::Error) -> bool {\n    matches!(e.kind(), swc_css_parser::error::ErrorKind::Expected(m) if *m == \"left comparison operator should be equal right comparison operator\")\n}","tryCatchPattern":"match parse_file::<Stylesheet>(&fm, None, config, &mut errors) {\n    Ok(sheet) => handle(sheet),\n    Err(err) if is_interval_direction_error(&err) => {\n        let (span, _) = *err.into_inner();\n        hint_at_span(css, span, \"both operators in a range interval must point the same way, e.g. (400px <= width <= 700px)\");\n    }\n    Err(err) => return Err(err.into()),\n}","preventionTips":["Derive the second operator from the first in codegen instead of using two variables","Prefer two conjoined plain features when generating bounds","Add a unit test asserting emitted intervals never mix directions","Review min/max template substitution order"],"tags":["css","swc","parser","at-rules","media-query","media-feature","range-syntax","validation"],"backgroundTag":"css-media-feature-range-syntax","analyzedSha":"5176682b65416c6b5de6b47379ae1588ea3ecb3f","analyzedAt":"2026-08-17T16:16:52.067Z","contentChangedAt":"2026-08-17T16:16:52.067Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}