diff --git a/src/output.rs b/src/output.rs index bbf16b4..793eb9e 100644 --- a/src/output.rs +++ b/src/output.rs @@ -248,7 +248,7 @@ impl Css { let out = unsafe { String::from_utf8_unchecked(buf) }; Ok(if show_charset { match style { - OutputStyle::Compressed => format!("@charset \"UTF-8\";{}", out), + OutputStyle::Compressed => format!("\u{FEFF}{}", out), OutputStyle::Expanded => format!("@charset \"UTF-8\";\n{}", out), } } else { @@ -311,9 +311,7 @@ impl Formatter for CompressedFormatter { self.write_block_entry(buf, &styles)?; write!(buf, "}}")?; } - Toplevel::MultilineComment(s) => { - write!(buf, "/*{}*/", s)?; - } + Toplevel::MultilineComment(..) => continue, Toplevel::Import(s) => { write!(buf, "@import {};", s)?; } @@ -411,22 +409,26 @@ impl CompressedFormatter { fn write_block_entry(&self, buf: &mut Vec, styles: &[BlockEntry]) -> SassResult<()> { let mut styles = styles.iter(); - if let Some(style) = styles.next() { + + while let Some(style) = styles.next() { match style { BlockEntry::Style(s) => { let value = s.value.node.to_css_string(s.value.span)?; write!(buf, "{}:{}", s.property, value)?; + break; } - BlockEntry::MultilineComment(s) => write!(buf, "/*{}*/", s)?, + BlockEntry::MultilineComment(..) => continue, } } + for style in styles { match style { BlockEntry::Style(s) => { let value = s.value.node.to_css_string(s.value.span)?; + write!(buf, ";{}:{}", s.property, value)?; } - BlockEntry::MultilineComment(s) => write!(buf, "/*{}*/", s)?, + BlockEntry::MultilineComment(..) => continue, } } Ok(()) diff --git a/tests/compressed.rs b/tests/compressed.rs new file mode 100644 index 0000000..c87f1c1 --- /dev/null +++ b/tests/compressed.rs @@ -0,0 +1,88 @@ +#[macro_use] +mod macros; + +test!( + compresses_simple_rule, + "a {\n color: red;\n}\n", + "a{color:red}", + grass::Options::default().style(grass::OutputStyle::Compressed) +); +test!( + compresses_rule_with_many_styles, + "a {\n color: red;\n color: green;\n color: blue;\n}\n", + "a{color:red;color:green;color:blue}", + grass::Options::default().style(grass::OutputStyle::Compressed) +); +test!( + #[ignore = "we don't support compressed values"] + strips_the_leading_zero, + "a {\n color: 0.5;\n}\n", + "a{color:.5}", + grass::Options::default().style(grass::OutputStyle::Compressed) +); +test!( + compresses_media_rule, + "@media foo {\n a {\n color: red;\n }\n}\n", + "@media foo{a{color:red}}", + grass::Options::default().style(grass::OutputStyle::Compressed) +); +test!( + compresses_selector_with_space_after_comma, + "a, b {\n color: red;\n}\n", + "a,b{color:red}", + grass::Options::default().style(grass::OutputStyle::Compressed) +); +test!( + compresses_selector_with_newline_after_comma, + "a,\nb {\n color: red;\n}\n", + "a,b{color:red}", + grass::Options::default().style(grass::OutputStyle::Compressed) +); +test!( + emits_bom_when_compressed, + "a {\n color: 👭;\n}\n", + "\u{FEFF}a{color:👭}", + grass::Options::default().style(grass::OutputStyle::Compressed) +); +test!( + removes_space_between_selector_combinator, + "a > b {\n color: red;\n}\n", + "a>b{color:red}", + grass::Options::default().style(grass::OutputStyle::Compressed) +); +test!( + removes_multiline_comment_before_style, + "a {\n /* abc */\n color: red;\n}\n", + "a{color:red}", + grass::Options::default().style(grass::OutputStyle::Compressed) +); +test!( + removes_multiline_comment_after_style, + "a {\n color: red;\n /* abc */\n}\n", + "a{color:red}", + grass::Options::default().style(grass::OutputStyle::Compressed) +); +test!( + removes_multiline_comment_between_styles, + "a {\n color: red;\n /* abc */\n color: green;\n}\n", + "a{color:red;color:green}", + grass::Options::default().style(grass::OutputStyle::Compressed) +); +test!( + removes_multiline_comment_before_ruleset, + "/* abc */a {\n color: red;\n}\n", + "a{color:red}", + grass::Options::default().style(grass::OutputStyle::Compressed) +); +test!( + removes_multiline_comment_after_ruleset, + "a {\n color: red;\n}\n/* abc */", + "a{color:red}", + grass::Options::default().style(grass::OutputStyle::Compressed) +); +test!( + removes_multiline_comment_between_rulesets, + "a {\n color: red;\n}\n/* abc */b {\n color: green;\n}\n", + "a{color:red}b{color:green}", + grass::Options::default().style(grass::OutputStyle::Compressed) +); diff --git a/tests/macros.rs b/tests/macros.rs index c4c2ccf..8d8eaa5 100644 --- a/tests/macros.rs +++ b/tests/macros.rs @@ -1,11 +1,11 @@ #[macro_export] macro_rules! test { - ($( #[$attr:meta] ),*$func:ident, $input:expr, $output:expr) => { + (@base $( #[$attr:meta] ),*$func:ident, $input:expr, $output:expr, $options:expr) => { $(#[$attr])* #[test] #[allow(non_snake_case)] fn $func() { - let sass = grass::from_string($input.to_string(), &grass::Options::default()) + let sass = grass::from_string($input.to_string(), &$options) .expect(concat!("failed to parse on ", $input)); assert_eq!( String::from($output), @@ -13,6 +13,12 @@ macro_rules! test { ); } }; + ($( #[$attr:meta] ),*$func:ident, $input:expr, $output:expr, $options:expr) => { + test!(@base $(#[$attr])* $func, $input, $output, $options); + }; + ($( #[$attr:meta] ),*$func:ident, $input:expr, $output:expr) => { + test!(@base $(#[$attr])* $func, $input, $output, grass::Options::default()); + }; } /// Verify the error *message*