csskit_transform/
css_minifier.rs1use crate::{ReduceColors, ReduceLengths, ReduceTimeUnits, transformer};
2use bitmask_enum::bitmask;
3use css_ast::{CssMetadata, Visitable};
4
5transformer!(
6 pub enum CssMinifierFeature[CssMetadata, Visitable] {
8 ReduceColors,
10 ReduceLengths,
12 ReduceTimeUnits,
14 }
15);
16
17impl Default for CssMinifierFeature {
18 fn default() -> Self {
19 Self::none()
20 }
21}
22
23#[cfg(test)]
24mod tests {
25 use super::*;
26 use crate::Transformer;
27 use bumpalo::Bump;
28 use css_ast::{CssAtomSet, StyleSheet};
29 use css_lexer::Lexer;
30 use css_parse::{CursorCompactWriteSink, CursorOverlaySink, Parser, ToCursors};
31
32 fn minify(source_text: &str, features: CssMinifierFeature) -> (String, bool) {
33 let bump = Bump::default();
34 let mut transformer = Transformer::new_in(&bump, features, &CssAtomSet::ATOMS, source_text);
35 let lexer = Lexer::new(&CssAtomSet::ATOMS, source_text);
36 let mut parser = Parser::new(&bump, source_text, lexer);
37 let mut result = parser.parse_entirely::<StyleSheet>();
38 let mut output = String::new();
39 if let Some(ref mut node) = result.output {
40 transformer.transform(node);
41 let overlays = transformer.overlays();
42 let changed = transformer.has_changed();
43 let mut overlay_stream =
44 CursorOverlaySink::new(source_text, &*overlays, CursorCompactWriteSink::new(source_text, &mut output));
45 result.output.to_cursors(&mut overlay_stream);
46 (output.clone(), changed)
47 } else {
48 panic!("Could not transform output");
49 }
50 }
51
52 #[test]
53 fn test_reduce_lengths_feature() {
54 let input = "body { width: 0px; }";
55 let (output, changed) = minify(input, CssMinifierFeature::ReduceLengths);
56 assert!(changed);
57 assert!(output.contains("width:0"), "Should apply length reduction, got: {}", output);
58 assert!(!output.contains("0px"), "Should not contain 0px, got: {}", output);
59 }
60
61 #[test]
62 fn test_no_features() {
63 let input = "body { width: 0px; }";
64 let (output, changed) = minify(input, CssMinifierFeature::none());
65 assert!(!changed, "Should not make changes with no features enabled");
66 assert!(output.contains("width:0px"));
67 }
68
69 #[test]
70 fn test_changed_flag_accuracy() {
71 let input = "body { width: 10px; }";
72 let (_, changed) = minify(input, CssMinifierFeature::all_bits());
73 assert!(!changed, "Should report no changes when no optimizations apply");
74 }
75}