From 333b17ee4eeda6e786beaec9d1982d024039f203 Mon Sep 17 00:00:00 2001 From: LeoniePhiline <22329650+LeoniePhiline@users.noreply.github.com> Date: Sun, 6 Nov 2022 19:39:11 +0100 Subject: [PATCH 1/2] feat: Add failing test --- src/media_query.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/media_query.rs b/src/media_query.rs index 1d471e75..a388cb05 100644 --- a/src/media_query.rs +++ b/src/media_query.rs @@ -991,7 +991,7 @@ fn process_condition<'i>( #[cfg(test)] mod tests { use super::*; - use crate::stylesheet::PrinterOptions; + use crate::{stylesheet::PrinterOptions, targets::Browsers}; fn parse(s: &str) -> MediaQuery { let mut input = ParserInput::new(&s); @@ -1038,4 +1038,14 @@ mod tests { assert_eq!(and("only screen", "all"), "only screen"); assert_eq!(and("print", "print"), "print"); } + + #[test] + fn test_negated_interval_parens() { + let media_query = parse("screen and not (200px <= width < 500px)"); + let printer_options = PrinterOptions { + targets: Browsers::from_browserslist(["chrome 95"]).unwrap(), + ..Default::default() + }; + assert_eq!(media_query.to_css_string(printer_options).unwrap(), "screen and not ((min-width: 200px) and (max-width: 499.999px))"); + } } From ae5f4b501a507cd51e3cf75b61503f3a61257753 Mon Sep 17 00:00:00 2001 From: LeoniePhiline <22329650+LeoniePhiline@users.noreply.github.com> Date: Mon, 7 Nov 2022 01:12:23 +0100 Subject: [PATCH 2/2] fix: Correctly enclose negated downleveled interval media queries in parens (Alternative A) --- src/media_query.rs | 38 ++++++++++++++++++++++++++++++-------- src/printer.rs | 2 ++ 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/media_query.rs b/src/media_query.rs index a388cb05..be0be683 100644 --- a/src/media_query.rs +++ b/src/media_query.rs @@ -449,10 +449,19 @@ impl<'i> ToCss for MediaCondition<'i> { { match *self { MediaCondition::Feature(ref f) => f.to_css(dest), - MediaCondition::Not(ref c) => { - dest.write_str("not ")?; - c.to_css(dest) - } + MediaCondition::Not(ref c) => match **c { + MediaCondition::Feature(ref f) => { + dest.write_str("not ")?; + dest.in_negated_media_feature = true; + f.to_css(dest)?; + dest.in_negated_media_feature = false; + Ok(()) + } + _ => { + dest.write_str("not ")?; + c.to_css(dest) + } + }, MediaCondition::InParens(ref c) => { dest.write_char('(')?; c.to_css(dest)?; @@ -672,9 +681,16 @@ impl<'i> ToCss for MediaFeature<'i> { } => { if let Some(targets) = dest.targets { if !Feature::MediaIntervalSyntax.is_compatible(targets) { + if dest.in_negated_media_feature { + dest.write_char('(')?; + } write_min_max(&start_operator.opposite(), name, start, dest)?; dest.write_str(" and (")?; - return write_min_max(end_operator, name, end, dest); + write_min_max(end_operator, name, end, dest)?; + if dest.in_negated_media_feature { + dest.write_char(')')?; + } + return Ok(()); } } @@ -1043,9 +1059,15 @@ mod tests { fn test_negated_interval_parens() { let media_query = parse("screen and not (200px <= width < 500px)"); let printer_options = PrinterOptions { - targets: Browsers::from_browserslist(["chrome 95"]).unwrap(), - ..Default::default() + targets: Some(Browsers { + firefox: Some(62 << 16), + ..Browsers::default() + }), + ..PrinterOptions::default() }; - assert_eq!(media_query.to_css_string(printer_options).unwrap(), "screen and not ((min-width: 200px) and (max-width: 499.999px))"); + assert_eq!( + media_query.to_css_string(printer_options).unwrap(), + "screen and not ((min-width: 200px) and (max-width: 499.999px))" + ); } } diff --git a/src/printer.rs b/src/printer.rs index 58ce88a9..a3dd5009 100644 --- a/src/printer.rs +++ b/src/printer.rs @@ -72,6 +72,7 @@ pub struct Printer<'a, 'b, 'c, W> { /// the vendor prefix of whatever is being printed. pub(crate) vendor_prefix: VendorPrefix, pub(crate) in_calc: bool, + pub(crate) in_negated_media_feature: bool, pub(crate) css_module: Option>, pub(crate) dependencies: Option>, pub(crate) remove_imports: bool, @@ -98,6 +99,7 @@ impl<'a, 'b, 'c, W: std::fmt::Write + Sized> Printer<'a, 'b, 'c, W> { targets: options.targets, vendor_prefix: VendorPrefix::empty(), in_calc: false, + in_negated_media_feature: false, css_module: None, dependencies: if options.analyze_dependencies.is_some() { Some(Vec::new())