swc_css_minifier/compressor/
declaration.rs

1use swc_atoms::atom;
2use swc_common::{util::take::Take, Span, DUMMY_SP};
3use swc_css_ast::*;
4
5use super::Compressor;
6
7impl Compressor {
8    pub(super) fn compress_declaration(&self, declaration: &mut Declaration) {
9        if let DeclarationName::Ident(Ident { value: name, .. }) = &mut declaration.name {
10            *name = name.to_ascii_lowercase();
11
12            match &**name {
13                "display" if declaration.value.len() > 1 => {
14                    let mut outside = None;
15                    let mut inside = None;
16                    let mut list_item = None;
17
18                    for value in declaration.value.iter() {
19                        match value {
20                            outside_node @ ComponentValue::Ident(ident)
21                                if matches_eq_ignore_ascii_case!(
22                                    ident.value,
23                                    "block",
24                                    "inline",
25                                    "run-in"
26                                ) =>
27                            {
28                                outside = Some(outside_node);
29                            }
30                            inside_node @ ComponentValue::Ident(ident)
31                                if matches_eq_ignore_ascii_case!(
32                                    ident.value,
33                                    "flow",
34                                    "flow-root",
35                                    "table",
36                                    "flex",
37                                    "grid",
38                                    "ruby"
39                                ) =>
40                            {
41                                inside = Some(inside_node);
42                            }
43                            list_item_node @ ComponentValue::Ident(ident)
44                                if ident.value.eq_ignore_ascii_case("list-item") =>
45                            {
46                                if let Some(ComponentValue::Ident(ident)) = inside {
47                                    if !matches_eq_ignore_ascii_case!(
48                                        ident.value,
49                                        "flow",
50                                        "flow-root"
51                                    ) {
52                                        continue;
53                                    }
54                                }
55
56                                list_item = Some(list_item_node)
57                            }
58                            _ => {}
59                        }
60                    }
61
62                    match (outside, inside, list_item) {
63                        // `block flow` -> `block`
64                        // `inline flow` -> `inline`
65                        // `run-in flow` -> `run-in`
66                        (Some(outside), Some(ComponentValue::Ident(inside_ident)), None)
67                            if inside_ident.value.eq_ignore_ascii_case("flow") =>
68                        {
69                            declaration.value = vec![outside.clone()];
70                        }
71                        // `block flow-root` -> `flow-root`
72                        (
73                            Some(ComponentValue::Ident(outside_ident)),
74                            Some(inside @ ComponentValue::Ident(inside_ident)),
75                            None,
76                        ) if outside_ident.value.eq_ignore_ascii_case("block")
77                            && inside_ident.value.eq_ignore_ascii_case("flow-root") =>
78                        {
79                            declaration.value = vec![inside.clone()];
80                        }
81                        // `inline flow-root` -> `inline-block`
82                        (
83                            Some(ComponentValue::Ident(outside_ident)),
84                            Some(ComponentValue::Ident(inside_ident)),
85                            None,
86                        ) if outside_ident.value.eq_ignore_ascii_case("inline")
87                            && inside_ident.value.eq_ignore_ascii_case("flow-root") =>
88                        {
89                            declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
90                                span: outside_ident.span,
91                                value: atom!("inline-block"),
92                                raw: None,
93                            }))];
94                        }
95                        // `block flow list-item` -> `list-item`
96                        (
97                            Some(ComponentValue::Ident(outside_ident)),
98                            Some(ComponentValue::Ident(inside_ident)),
99                            Some(list_item),
100                        ) if outside_ident.value.eq_ignore_ascii_case("block")
101                            && inside_ident.value.eq_ignore_ascii_case("flow") =>
102                        {
103                            declaration.value = vec![list_item.clone()];
104                        }
105                        // `block list-item` -> `list-item`
106                        (Some(ComponentValue::Ident(outside_ident)), None, Some(list_item))
107                            if outside_ident.value.eq_ignore_ascii_case("block") =>
108                        {
109                            declaration.value = vec![list_item.clone()];
110                        }
111                        // `flow list-item` -> `list-item`
112                        (None, Some(ComponentValue::Ident(inside_ident)), Some(list_item))
113                            if inside_ident.value.eq_ignore_ascii_case("flow") =>
114                        {
115                            declaration.value = vec![list_item.clone()];
116                        }
117                        // `inline flow list-item` -> `inline list-item`
118                        (
119                            Some(outside @ ComponentValue::Ident(outside_ident)),
120                            Some(ComponentValue::Ident(inside_ident)),
121                            Some(list_item),
122                        ) if outside_ident.value.eq_ignore_ascii_case("inline")
123                            && inside_ident.value.eq_ignore_ascii_case("flow") =>
124                        {
125                            declaration.value = vec![outside.clone(), list_item.clone()];
126                        }
127                        // `block flex` -> `flex`
128                        // `block grid` -> `grid`
129                        // `block table` -> `table`
130                        (
131                            Some(ComponentValue::Ident(outside_ident)),
132                            Some(inside @ ComponentValue::Ident(inside_ident)),
133                            None,
134                        ) if outside_ident.value.eq_ignore_ascii_case("block")
135                            && matches_eq_ignore_ascii_case!(
136                                inside_ident.value,
137                                "flex",
138                                "grid",
139                                "table"
140                            ) =>
141                        {
142                            declaration.value = vec![inside.clone()];
143                        }
144                        // `inline ruby` -> `ruby`
145                        (
146                            Some(ComponentValue::Ident(outside_ident)),
147                            Some(inside @ ComponentValue::Ident(inside_ident)),
148                            None,
149                        ) if outside_ident.value.eq_ignore_ascii_case("inline")
150                            && inside_ident.value.eq_ignore_ascii_case("ruby") =>
151                        {
152                            declaration.value = vec![inside.clone()];
153                        }
154                        _ => {}
155                    }
156                }
157                // TODO handle `auto`
158                // TODO compress numbers too
159                "padding"
160                | "margin"
161                | "border-width"
162                | "inset"
163                | "scroll-margin"
164                | "scroll-padding"
165                | "mask-border-outset"
166                | "border-image-width"
167                | "border-image-outset"
168                | "border-image-slice"
169                    if declaration.value.len() > 1 =>
170                {
171                    let top = declaration.value.first();
172                    let right = declaration
173                        .value
174                        .get(1)
175                        .or_else(|| declaration.value.first());
176                    let bottom = declaration
177                        .value
178                        .get(2)
179                        .or_else(|| declaration.value.first());
180                    let left = declaration
181                        .value
182                        .get(3)
183                        .or_else(|| declaration.value.get(1))
184                        .or_else(|| declaration.value.first());
185
186                    if self.is_same_length_percentage_nodes(left, right) {
187                        if self.is_same_length_percentage_nodes(bottom, top) {
188                            if self.is_same_length_percentage_nodes(right, top) {
189                                declaration.value = vec![top.unwrap().clone()];
190                            } else {
191                                declaration.value =
192                                    vec![top.unwrap().clone(), right.unwrap().clone()];
193                            }
194                        } else {
195                            declaration.value = vec![
196                                top.unwrap().clone(),
197                                right.unwrap().clone(),
198                                bottom.unwrap().clone(),
199                            ];
200                        }
201                    }
202                }
203                "padding-inline"
204                | "padding-block"
205                | "margin-inline"
206                | "margin-block"
207                | "margin-inline"
208                | "inset-inline"
209                | "inset-block"
210                | "border-inline-width"
211                | "border-block-width"
212                | "scroll-padding-inline"
213                | "scroll-padding-block"
214                | "scroll-margin-inline"
215                | "scroll-margin-block"
216                | "border-top-left-radius"
217                | "border-top-right-radius"
218                | "border-bottom-right-radius"
219                | "border-bottom-left-radius"
220                | "border-start-start-radius"
221                | "border-start-end-radius"
222                | "border-end-start-radius"
223                | "border-end-end-radius"
224                    if declaration.value.len() == 2 =>
225                {
226                    let first = declaration.value.first();
227                    let second = declaration.value.get(1);
228
229                    if self.is_same_length_percentage_nodes(first, second)
230                        || self.is_same_ident(first, second)
231                    {
232                        declaration.value.remove(1);
233                    }
234                }
235                "border-style" if declaration.value.len() > 1 => {
236                    let top = declaration.value.first();
237                    let right = declaration
238                        .value
239                        .get(1)
240                        .or_else(|| declaration.value.first());
241                    let bottom = declaration
242                        .value
243                        .get(2)
244                        .or_else(|| declaration.value.first());
245                    let left = declaration
246                        .value
247                        .get(3)
248                        .or_else(|| declaration.value.get(1))
249                        .or_else(|| declaration.value.first());
250
251                    if self.is_same_ident(left, right) {
252                        if self.is_same_ident(bottom, top) {
253                            if self.is_same_ident(right, top) {
254                                declaration.value = vec![top.unwrap().clone()];
255                            } else {
256                                declaration.value =
257                                    vec![top.unwrap().clone(), right.unwrap().clone()];
258                            }
259                        } else {
260                            declaration.value = vec![
261                                top.unwrap().clone(),
262                                right.unwrap().clone(),
263                                bottom.unwrap().clone(),
264                            ];
265                        }
266                    }
267                }
268                "border-spacing" | "border-image-repeat" if declaration.value.len() == 2 => {
269                    let first = declaration.value.first();
270                    let second = declaration.value.get(1);
271
272                    if self.is_same_length_nodes(first, second) {
273                        declaration.value.remove(1);
274                    }
275                }
276                "font-weight" => {
277                    declaration.value = declaration
278                        .value
279                        .take()
280                        .into_iter()
281                        .map(|node| match node {
282                            ComponentValue::Ident(ident)
283                                if ident.value.eq_ignore_ascii_case("normal") =>
284                            {
285                                ComponentValue::Integer(Box::new(Integer {
286                                    span: ident.span,
287                                    value: 400,
288                                    raw: None,
289                                }))
290                            }
291                            ComponentValue::Ident(ident)
292                                if ident.value.eq_ignore_ascii_case("bold") =>
293                            {
294                                ComponentValue::Integer(Box::new(Integer {
295                                    span: ident.span,
296                                    value: 700,
297                                    raw: None,
298                                }))
299                            }
300                            _ => node,
301                        })
302                        .collect();
303                }
304                "background-repeat" | "mask-repeat" | "-webkit-mask-repeat"
305                    if declaration.value.len() == 2 =>
306                {
307                    let first = declaration.value.first();
308                    let second = declaration.value.get(1);
309
310                    if let (
311                        Some(ComponentValue::Ident(first_ident)),
312                        Some(ComponentValue::Ident(second_ident)),
313                    ) = (first, second)
314                    {
315                        match (
316                            &*first_ident.value.to_ascii_lowercase(),
317                            &*second_ident.value.to_ascii_lowercase(),
318                        ) {
319                            ("repeat", "no-repeat") => {
320                                declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
321                                    span: first_ident.span,
322                                    value: atom!("repeat-x"),
323                                    raw: None,
324                                }))];
325                            }
326                            ("no-repeat", "repeat") => {
327                                declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
328                                    span: first_ident.span,
329                                    value: atom!("repeat-y"),
330                                    raw: None,
331                                }))];
332                            }
333                            ("repeat", "repeat")
334                            | ("space", "space")
335                            | ("round", "round")
336                            | ("no-repeat", "no-repeat") => {
337                                declaration.value.remove(1);
338                            }
339                            _ => {}
340                        }
341                    }
342                }
343                "border-image-repeat"
344                | "mask-border-repeat"
345                | "-webkit-mask-box-image-repeat"
346                | "overscroll-behavior"
347                | "scroll-snap-align"
348                | "overflow"
349                | "place-self"
350                | "place-items"
351                | "place-content"
352                    if declaration.value.len() == 2 =>
353                {
354                    let first = declaration.value.first();
355                    let second = declaration.value.get(1);
356
357                    if self.is_same_ident(first, second) {
358                        declaration.value.remove(1);
359                    }
360                }
361                "animation" if !declaration.value.is_empty() => {
362                    let first = declaration.value.first().cloned();
363                    if let Some(ComponentValue::Str(ident)) = first {
364                        declaration.value.remove(0);
365                        match &*ident.value.to_ascii_lowercase() {
366                            _ if crate::is_css_wide_keyword(&ident.value)
367                                || ident.value.eq_ignore_ascii_case("none") =>
368                            {
369                                declaration.value.insert(0, ComponentValue::Str(ident));
370                            }
371                            to_be_identify => {
372                                declaration.value.insert(
373                                    0,
374                                    if self.is_ident_shorter_than_str(to_be_identify) {
375                                        ComponentValue::Ident(Box::new(Ident {
376                                            span: ident.span,
377                                            value: to_be_identify.into(),
378                                            raw: None,
379                                        }))
380                                    } else {
381                                        ComponentValue::Str(Box::new(Str {
382                                            span: ident.span,
383                                            value: to_be_identify.into(),
384                                            raw: None,
385                                        }))
386                                    },
387                                );
388                            }
389                        }
390                    }
391                }
392                "animation-name" => {
393                    declaration.value = declaration
394                        .value
395                        .take()
396                        .into_iter()
397                        .map(|node| match node {
398                            ComponentValue::Str(ref ident) => {
399                                let value = ident.value.to_ascii_lowercase();
400                                match &*value {
401                                    _ if crate::is_css_wide_keyword(&ident.value)
402                                        || ident.value.eq_ignore_ascii_case("none") =>
403                                    {
404                                        node
405                                    }
406                                    to_be_identify => {
407                                        if self.is_ident_shorter_than_str(to_be_identify) {
408                                            ComponentValue::Ident(Box::new(Ident {
409                                                span: ident.span,
410                                                value: to_be_identify.into(),
411                                                raw: None,
412                                            }))
413                                        } else {
414                                            ComponentValue::Str(Box::new(Str {
415                                                span: ident.span,
416                                                value: to_be_identify.into(),
417                                                raw: None,
418                                            }))
419                                        }
420                                    }
421                                }
422                            }
423                            _ => node,
424                        })
425                        .collect();
426                }
427                _ => {}
428            }
429
430            let is_initial = if let Some(ComponentValue::Ident(ident)) = declaration.value.first() {
431                if ident.value.eq_ignore_ascii_case("initial") {
432                    Some(ident.span)
433                } else {
434                    None
435                }
436            } else {
437                None
438            };
439
440            if let Some(span) = is_initial {
441                self.compress_from_initial(declaration, span);
442            }
443            // TODO `browserslist` support
444            // else {
445            // self.compress_to_initial(declaration);
446            // }
447        }
448    }
449
450    fn is_same_length_nodes(
451        &self,
452        node_1: Option<&ComponentValue>,
453        node_2: Option<&ComponentValue>,
454    ) -> bool {
455        let Some(node_1) = node_1 else { return false };
456        let Some(node_2) = node_2 else { return false };
457
458        match (node_1, node_2) {
459            (ComponentValue::Dimension(dimension_1), ComponentValue::Dimension(dimension_2)) => {
460                let result_1 = dimension_1
461                    .as_length()
462                    .map(|length| (&length.value.value, &length.unit.value));
463
464                let result_2 = dimension_2
465                    .as_length()
466                    .map(|length| (&length.value.value, &length.unit.value));
467
468                result_1.is_some() && result_1 == result_2
469            }
470            (ComponentValue::Integer(integer_1), ComponentValue::Integer(integer_2)) => {
471                integer_1.value == 0 && integer_2.value == 0
472            }
473            (ComponentValue::Number(number_1), ComponentValue::Number(number_2)) => {
474                number_1.value == number_2.value
475            }
476            _ => false,
477        }
478    }
479
480    fn is_same_length_percentage_nodes(
481        &self,
482        node_1: Option<&ComponentValue>,
483        node_2: Option<&ComponentValue>,
484    ) -> bool {
485        let Some(node_1) = node_1 else { return false };
486        let Some(node_2) = node_2 else { return false };
487
488        match (node_1, node_2) {
489            (ComponentValue::Dimension(dimension_1), ComponentValue::Dimension(dimension_2)) => {
490                let Some(result_1) = dimension_1.as_length() else {
491                    return false;
492                };
493
494                let Some(result_2) = dimension_2.as_length() else {
495                    return false;
496                };
497
498                result_1.value.value == result_2.value.value
499                    && result_1
500                        .unit
501                        .value
502                        .eq_ignore_ascii_case(&result_2.unit.value)
503            }
504            (
505                ComponentValue::Percentage(percentage_1),
506                ComponentValue::Percentage(percentage_2),
507            ) => percentage_1.value.value == percentage_2.value.value,
508            (ComponentValue::Integer(integer_1), ComponentValue::Integer(integer_2)) => {
509                integer_1.value == 0 && integer_2.value == 0
510            }
511            (ComponentValue::Number(number_1), ComponentValue::Number(number_2)) => {
512                number_1.value == number_2.value
513            }
514            _ => false,
515        }
516    }
517
518    fn is_same_ident(
519        &self,
520        node_1: Option<&ComponentValue>,
521        node_2: Option<&ComponentValue>,
522    ) -> bool {
523        let Some(node_1) = node_1 else { return false };
524        let Some(node_2) = node_2 else { return false };
525
526        let Some(value_1) = node_1.as_ident().map(|ident| &ident.value) else {
527            return false;
528        };
529        let Some(value_2) = node_2.as_ident().map(|ident| &ident.value) else {
530            return false;
531        };
532
533        value_1.eq_ignore_ascii_case(value_2)
534    }
535
536    fn compress_from_initial(&self, declaration: &mut Declaration, span: Span) {
537        let name = if let DeclarationName::Ident(Ident { value, .. }) = &declaration.name {
538            value
539        } else {
540            return;
541        };
542
543        match &**name {
544            "accent-color"
545            | "align-self"
546            | "animation-timeline"
547            | "aspect-ratio"
548            | "block-size"
549            | "bottom"
550            | "break-after"
551            | "break-before"
552            | "break-inside"
553            | "caret-color"
554            | "caret-shape"
555            | "clip"
556            | "column-count"
557            | "column-width"
558            | "cursor"
559            | "flex-basis"
560            | "font-kerning"
561            | "font-optical-sizing"
562            | "forced-color-adjust"
563            | "grid-auto-columns"
564            | "grid-auto-rows"
565            | "grid-column-end"
566            | "grid-column-start"
567            | "grid-row-end"
568            | "grid-row-start"
569            | "height"
570            | "hyphenate-character"
571            | "image-rendering"
572            | "ime-mode"
573            | "initial-letter-align"
574            | "inline-size"
575            | "input-security"
576            | "inset"
577            | "inset-block"
578            | "inset-block-end"
579            | "inset-block-start"
580            | "inset-inline"
581            | "inset-inline-end"
582            | "inset-inline-start"
583            | "isolation"
584            | "justify-self"
585            | "left"
586            | "line-break"
587            | "mask-border-width"
588            | "mask-size"
589            | "min-height"
590            | "min-width"
591            | "offset-anchor"
592            | "offset-position"
593            | "offset-rotate"
594            | "overflow-anchor"
595            | "overflow-block"
596            | "overflow-inline"
597            | "overscroll-behavior"
598            | "overscroll-behavior-block"
599            | "overscroll-behavior-inline"
600            | "overscroll-behavior-x"
601            | "overscroll-behavior-y"
602            | "page-break-after"
603            | "page-break-before"
604            | "page-break-inside"
605            | "pointer-events"
606            | "right"
607            | "scrollbar-color"
608            | "scrollbar-gutter"
609            | "scrollbar-width"
610            | "scroll-behavior"
611            | "scroll-padding"
612            | "scroll-padding-block"
613            | "scroll-padding-block-start"
614            | "scroll-padding-block-end"
615            | "scroll-padding-bottom"
616            | "scroll-padding-inline"
617            | "scroll-padding-inline-start"
618            | "scroll-padding-inline-end"
619            | "scroll-padding-left"
620            | "scroll-padding-right"
621            | "scroll-padding-top"
622            | "table-layout"
623            | "text-align-last"
624            | "text-decoration-skip-ink"
625            | "text-decoration-thickness"
626            | "text-justify"
627            | "text-rendering"
628            | "text-underline-offset"
629            | "text-underline-position"
630            | "top"
631            | "touch-action"
632            | "user-select"
633            | "width"
634            | "will-change"
635            | "z-index" => {
636                declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
637                    span,
638                    value: atom!("auto"),
639                    raw: None,
640                }))];
641            }
642            "-webkit-line-clamp"
643            | "animation-fill-mode"
644            | "animation-name"
645            | "appearance"
646            | "backdrop-filter"
647            | "background-image"
648            | "border-block-style"
649            | "border-block-end-style"
650            | "border-block-start-style"
651            | "border-bottom-style"
652            | "border-image-source"
653            | "border-inline-style"
654            | "border-inline-end-style"
655            | "border-inline-start-style"
656            | "border-left-style"
657            | "border-right-style"
658            | "border-top-style"
659            | "box-shadow"
660            | "clear"
661            | "clip-path"
662            | "column-rule-style"
663            | "column-span"
664            | "contain"
665            | "contain-intrinsic-block-size"
666            | "contain-intrinsic-height"
667            | "contain-intrinsic-inline-size"
668            | "contain-intrinsic-width"
669            | "counter-increment"
670            | "counter-reset"
671            | "counter-set"
672            | "filter"
673            | "float"
674            | "font-size-adjust"
675            | "grid-template-areas"
676            | "grid-template-columns"
677            | "grid-template-rows"
678            | "hanging-punctuation"
679            | "line-clamp"
680            | "list-style-image"
681            | "margin-trim"
682            | "mask-border-source"
683            | "mask-image"
684            | "max-block-size"
685            | "max-height"
686            | "max-inline-size"
687            | "max-lines"
688            | "max-width"
689            | "offset-path"
690            | "outline-style"
691            | "perspective"
692            | "resize"
693            | "rotate"
694            | "scale"
695            | "scroll-snap-align"
696            | "scroll-snap-coordinate"
697            | "scroll-snap-points-x"
698            | "scroll-snap-points-y"
699            | "scroll-snap-type"
700            | "scroll-snap-type-x"
701            | "scroll-snap-type-y"
702            | "scroll-timeline-name"
703            | "shape-outside"
704            | "text-combine-upright"
705            | "text-decoration-line"
706            | "text-emphasis-style"
707            | "text-shadow"
708            | "text-transform"
709            | "transform"
710            | "translate" => {
711                declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
712                    span,
713                    value: atom!("none"),
714                    raw: None,
715                }))];
716            }
717            "align-content"
718            | "align-items"
719            | "align-tracks"
720            | "animation-direction"
721            | "background-blend-mode"
722            | "color-scheme"
723            | "column-gap"
724            | "content"
725            | "font-feature-settings"
726            | "font-language-override"
727            | "font-variation-settings"
728            | "font-stretch"
729            | "font-style"
730            | "font-variant"
731            | "font-variant-alternates"
732            | "font-variant-caps"
733            | "font-variant-east-asian"
734            | "font-variant-ligatures"
735            | "font-variant-numeric"
736            | "font-variant-position"
737            | "font-weight"
738            | "initial-letter"
739            | "justify-content"
740            | "justify-tracks"
741            | "letter-spacing"
742            | "line-height"
743            | "math-shift"
744            | "math-style"
745            | "mix-blend-mode"
746            | "overflow-wrap"
747            | "paint-order"
748            | "place-content"
749            | "row-gap"
750            | "scroll-snap-stop"
751            | "unicode-bidi"
752            | "white-space"
753            | "word-break"
754            | "word-spacing"
755            | "word-wrap"
756            | "grid-row-gap"
757            | "grid-column-gap" => {
758                declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
759                    span,
760                    value: atom!("normal"),
761                    raw: None,
762                }))];
763            }
764            "animation-delay"
765            | "animation-duration"
766            | "transition-delay"
767            | "transition-duration" => {
768                declaration.value =
769                    vec![ComponentValue::Dimension(Box::new(Dimension::Time(Time {
770                        span,
771                        value: Number {
772                            span: DUMMY_SP,
773                            value: 0.0,
774                            raw: None,
775                        },
776                        unit: Ident {
777                            span: DUMMY_SP,
778                            value: atom!("s"),
779                            raw: None,
780                        },
781                    })))];
782            }
783            "shape-image-threshold" | "opacity" => {
784                declaration.value = vec![ComponentValue::AlphaValue(Box::new(AlphaValue::Number(
785                    Number {
786                        span,
787                        value: 0.0,
788                        raw: None,
789                    },
790                )))];
791            }
792            "animation-iteration-count" => {
793                declaration.value = vec![ComponentValue::Number(Box::new(Number {
794                    span,
795                    value: 1.0,
796                    raw: None,
797                }))];
798            }
799            "animation-timing-function" | "transition-timing-function" => {
800                declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
801                    span,
802                    value: atom!("ease"),
803                    raw: None,
804                }))];
805            }
806            "azimuth" | "mask-position" => {
807                declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
808                    span,
809                    value: atom!("center"),
810                    raw: None,
811                }))];
812            }
813            "background-attachment" => {
814                declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
815                    span,
816                    value: atom!("scroll"),
817                    raw: None,
818                }))];
819            }
820            "background-position" => {
821                declaration.value = vec![
822                    ComponentValue::Percentage(Box::new(Percentage {
823                        span,
824                        value: Number {
825                            span: DUMMY_SP,
826                            value: 0.0,
827                            raw: None,
828                        },
829                    })),
830                    ComponentValue::Percentage(Box::new(Percentage {
831                        span,
832                        value: Number {
833                            span: DUMMY_SP,
834                            value: 0.0,
835                            raw: None,
836                        },
837                    })),
838                ];
839            }
840            "background-position-x" | "background-position-y" => {
841                declaration.value = vec![ComponentValue::Percentage(Box::new(Percentage {
842                    span,
843                    value: Number {
844                        span: DUMMY_SP,
845                        value: 0.0,
846                        raw: None,
847                    },
848                }))];
849            }
850            "background-repeat" | "mask-repeat" => {
851                declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
852                    span,
853                    value: atom!("repeat"),
854                    raw: None,
855                }))];
856            }
857            "block-overflow" => {
858                declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
859                    span,
860                    value: atom!("clip"),
861                    raw: None,
862                }))];
863            }
864            "border-block-width"
865            | "border-block-end-width"
866            | "border-block-start-width"
867            | "border-bottom-width"
868            | "border-inline-width"
869            | "border-inline-end-width"
870            | "border-inline-start-width"
871            | "border-left-width"
872            | "border-right-width"
873            | "border-top-width"
874            | "column-rule-width"
875            | "font-size"
876            | "outline-width" => {
877                declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
878                    span,
879                    value: atom!("medium"),
880                    raw: None,
881                }))];
882            }
883            "border-top-left-radius"
884            | "border-top-right-radius"
885            | "border-start-end-radius"
886            | "border-start-start-radius"
887            | "border-bottom-left-radius"
888            | "border-bottom-right-radius"
889            | "border-end-end-radius"
890            | "border-end-start-radius"
891            | "shape-margin"
892            | "offset-distance" => {
893                declaration.value = vec![ComponentValue::LengthPercentage(Box::new(
894                    LengthPercentage::Length(Length {
895                        span,
896                        value: Number {
897                            span: DUMMY_SP,
898                            value: 0.0,
899                            raw: None,
900                        },
901                        unit: Ident {
902                            span: DUMMY_SP,
903                            value: atom!("px"),
904                            raw: None,
905                        },
906                    }),
907                ))];
908            }
909            "padding-block"
910            | "padding-block-end"
911            | "padding-block-start"
912            | "padding-bottom"
913            | "padding-inline"
914            | "padding-inline-end"
915            | "padding-inline-start"
916            | "padding-left"
917            | "padding-right"
918            | "padding-top"
919            | "padding"
920            | "margin-block"
921            | "margin-block-end"
922            | "margin-block-start"
923            | "margin-bottom"
924            | "margin-inline"
925            | "margin-inline-end"
926            | "margin-inline-start"
927            | "margin-left"
928            | "margin-right"
929            | "margin-top"
930            | "margin"
931            | "scroll-margin"
932            | "scroll-margin-block"
933            | "scroll-margin-block-start"
934            | "scroll-margin-block-end"
935            | "scroll-margin-bottom"
936            | "scroll-margin-inline"
937            | "scroll-margin-inline-start"
938            | "scroll-margin-inline-end"
939            | "scroll-margin-left"
940            | "scroll-margin-right"
941            | "scroll-margin-top"
942            | "min-inline-size"
943            | "min-block-size"
944            | "border-image-outset"
945            | "text-indent"
946            | "outline-offset"
947            | "line-height-step"
948            | "border-spacing" => {
949                declaration.value = vec![ComponentValue::Dimension(Box::new(Dimension::Length(
950                    Length {
951                        span,
952                        value: Number {
953                            span: DUMMY_SP,
954                            value: 0.0,
955                            raw: None,
956                        },
957                        unit: Ident {
958                            span: DUMMY_SP,
959                            value: atom!("px"),
960                            raw: None,
961                        },
962                    },
963                )))];
964            }
965            "flex-direction" | "grid-auto-flow" => {
966                declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
967                    span,
968                    value: atom!("row"),
969                    raw: None,
970                }))];
971            }
972            "mask-border-slice" | "mask-border-outset" => {
973                declaration.value = vec![ComponentValue::Number(Box::new(Number {
974                    span,
975                    value: 0.0,
976                    raw: None,
977                }))];
978            }
979            "border-image-slice" => {
980                declaration.value = vec![ComponentValue::Percentage(Box::new(Percentage {
981                    span,
982                    value: Number {
983                        span: DUMMY_SP,
984                        value: 100.0,
985                        raw: None,
986                    },
987                }))];
988            }
989            "border-image-width" => {
990                declaration.value = vec![ComponentValue::Number(Box::new(Number {
991                    span,
992                    value: 1.0,
993                    raw: None,
994                }))];
995            }
996            "box-decoration-break" => {
997                declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
998                    span,
999                    value: atom!("slice"),
1000                    raw: None,
1001                }))];
1002            }
1003            "caption-side" => {
1004                declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
1005                    span,
1006                    value: atom!("top"),
1007                    raw: None,
1008                }))];
1009            }
1010            "direction" => {
1011                declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
1012                    span,
1013                    value: atom!("ltr"),
1014                    raw: None,
1015                }))];
1016            }
1017            "empty-cells" => {
1018                declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
1019                    span,
1020                    value: atom!("show"),
1021                    raw: None,
1022                }))];
1023            }
1024            "flex-grow" => {
1025                declaration.value = vec![ComponentValue::Number(Box::new(Number {
1026                    span,
1027                    value: 0.0,
1028                    raw: None,
1029                }))];
1030            }
1031            "flex-shrink" => {
1032                declaration.value = vec![ComponentValue::Number(Box::new(Number {
1033                    span,
1034                    value: 1.0,
1035                    raw: None,
1036                }))];
1037            }
1038            "flex-wrap" => {
1039                declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
1040                    span,
1041                    value: atom!("nowrap"),
1042                    raw: None,
1043                }))];
1044            }
1045            "hyphens" => {
1046                declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
1047                    span,
1048                    value: atom!("manual"),
1049                    raw: None,
1050                }))];
1051            }
1052            "image-resolution" => {
1053                declaration.value = vec![ComponentValue::Dimension(Box::new(
1054                    Dimension::Resolution(Resolution {
1055                        span,
1056                        value: Number {
1057                            span: DUMMY_SP,
1058                            value: 1.0,
1059                            raw: None,
1060                        },
1061                        unit: Ident {
1062                            span: DUMMY_SP,
1063                            value: atom!("dppx"),
1064                            raw: None,
1065                        },
1066                    }),
1067                ))];
1068            }
1069            "justify-items" => {
1070                declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
1071                    span,
1072                    value: atom!("legacy"),
1073                    raw: None,
1074                }))];
1075            }
1076            "list-style-type" => {
1077                declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
1078                    span,
1079                    value: atom!("disk"),
1080                    raw: None,
1081                }))];
1082            }
1083            "mask-border-mode" => {
1084                declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
1085                    span,
1086                    value: atom!("alpha"),
1087                    raw: None,
1088                }))];
1089            }
1090            "mask-composite" => {
1091                declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
1092                    span,
1093                    value: atom!("add"),
1094                    raw: None,
1095                }))];
1096            }
1097            "masonry-auto-flow" => {
1098                declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
1099                    span,
1100                    value: atom!("pack"),
1101                    raw: None,
1102                }))];
1103            }
1104            "math-depth" | "order" => {
1105                declaration.value = vec![ComponentValue::Integer(Box::new(Integer {
1106                    span,
1107                    value: 0,
1108                    raw: None,
1109                }))];
1110            }
1111            "object-fit" => {
1112                declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
1113                    span,
1114                    value: atom!("fill"),
1115                    raw: None,
1116                }))];
1117            }
1118            "overflow-clip-margin" => {
1119                declaration.value = vec![ComponentValue::Dimension(Box::new(Dimension::Length(
1120                    Length {
1121                        span,
1122                        value: Number {
1123                            span: DUMMY_SP,
1124                            value: 0.0,
1125                            raw: None,
1126                        },
1127                        unit: Ident {
1128                            span: DUMMY_SP,
1129                            value: atom!("px"),
1130                            raw: None,
1131                        },
1132                    },
1133                )))];
1134            }
1135            "position" => {
1136                declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
1137                    span,
1138                    value: atom!("static"),
1139                    raw: None,
1140                }))];
1141            }
1142            "scroll-timeline-axis" => {
1143                declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
1144                    span,
1145                    value: atom!("block"),
1146                    raw: None,
1147                }))];
1148            }
1149            "tab-size" => {
1150                declaration.value = vec![ComponentValue::Number(Box::new(Number {
1151                    span: DUMMY_SP,
1152                    value: 8.0,
1153                    raw: None,
1154                }))];
1155            }
1156            "text-decoration-style" => {
1157                declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
1158                    span,
1159                    value: atom!("solid"),
1160                    raw: None,
1161                }))];
1162            }
1163            "text-orientation" => {
1164                declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
1165                    span,
1166                    value: atom!("mixed"),
1167                    raw: None,
1168                }))];
1169            }
1170            "text-overflow" => {
1171                declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
1172                    span,
1173                    value: atom!("clip"),
1174                    raw: None,
1175                }))];
1176            }
1177            "transform-style" => {
1178                declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
1179                    span,
1180                    value: atom!("flat"),
1181                    raw: None,
1182                }))];
1183            }
1184            "transition-property" => {
1185                declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
1186                    span,
1187                    value: atom!("all"),
1188                    raw: None,
1189                }))];
1190            }
1191            "orphans" | "widows" => {
1192                declaration.value = vec![ComponentValue::Integer(Box::new(Integer {
1193                    span,
1194                    value: 2,
1195                    raw: None,
1196                }))];
1197            }
1198            _ => {}
1199        }
1200    }
1201
1202    fn _compress_to_initial(&self, declaration: &mut Declaration) {
1203        let name = if let DeclarationName::Ident(Ident { value, .. }) = &declaration.name {
1204            value
1205        } else {
1206            return;
1207        };
1208
1209        match &**name {
1210            "background-clip" | "mask-clip" | "mask-origin" => {
1211                if let Some(ComponentValue::Ident(ident)) = declaration.value.first() {
1212                    if ident.value.eq_ignore_ascii_case("border-box") {
1213                        declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
1214                            span: ident.span,
1215                            value: atom!("initial"),
1216                            raw: None,
1217                        }))];
1218                    }
1219                }
1220            }
1221            "background-color" => {
1222                if let Some(ComponentValue::Ident(ident)) = declaration.value.first() {
1223                    if ident.value.eq_ignore_ascii_case("transparent") {
1224                        declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
1225                            span: ident.span,
1226                            value: atom!("initial"),
1227                            raw: None,
1228                        }))];
1229                    }
1230                }
1231            }
1232            "background-origin" => {
1233                if let Some(ComponentValue::Ident(ident)) = declaration.value.first() {
1234                    if ident.value.eq_ignore_ascii_case("padding-box") {
1235                        declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
1236                            span: ident.span,
1237                            value: atom!("initial"),
1238                            raw: None,
1239                        }))];
1240                    }
1241                }
1242            }
1243            "background-size" => {
1244                if let (Some(ComponentValue::Ident(first)), Some(ComponentValue::Ident(second))) =
1245                    (declaration.value.first(), declaration.value.get(1))
1246                {
1247                    if first.value.eq_ignore_ascii_case("auto")
1248                        && second.value.eq_ignore_ascii_case("auto")
1249                        && declaration.value.len() == 2
1250                    {
1251                        declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
1252                            span: first.span,
1253                            value: atom!("initial"),
1254                            raw: None,
1255                        }))];
1256                    }
1257                }
1258            }
1259            "border-block-color"
1260            | "border-block-start-color"
1261            | "border-block-end-color"
1262            | "border-inline-color"
1263            | "border-inline-start-color"
1264            | "border-inline-end-color"
1265            | "border-bottom-color"
1266            | "border-left-color"
1267            | "border-right-color"
1268            | "border-top-color"
1269            | "column-rule-color"
1270            | "text-emphasis-color"
1271            | "text-decoration-color" => {
1272                if let Some(ComponentValue::Ident(ident)) = declaration.value.first() {
1273                    if ident.value.eq_ignore_ascii_case("currentcolor") {
1274                        declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
1275                            span: ident.span,
1276                            value: atom!("initial"),
1277                            raw: None,
1278                        }))];
1279                    }
1280                }
1281            }
1282            "border-collapse" => {
1283                if let Some(ComponentValue::Ident(ident)) = declaration.value.first() {
1284                    if ident.value.eq_ignore_ascii_case("separate") {
1285                        declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
1286                            span: ident.span,
1287                            value: atom!("initial"),
1288                            raw: None,
1289                        }))];
1290                    }
1291                }
1292            }
1293            "box-sizing" => {
1294                if let Some(ComponentValue::Ident(ident)) = declaration.value.first() {
1295                    if ident.value.eq_ignore_ascii_case("content-box") {
1296                        declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
1297                            span: ident.span,
1298                            value: atom!("initial"),
1299                            raw: None,
1300                        }))];
1301                    }
1302                }
1303            }
1304            "color" => {
1305                if let Some(ComponentValue::Ident(ident)) = declaration.value.first() {
1306                    if ident.value.eq_ignore_ascii_case("canvastext") {
1307                        declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
1308                            span: ident.span,
1309                            value: atom!("initial"),
1310                            raw: None,
1311                        }))];
1312                    }
1313                }
1314            }
1315            "font-synthesis" => {
1316                if let (Some(ComponentValue::Ident(first)), Some(ComponentValue::Ident(second))) =
1317                    (declaration.value.first(), declaration.value.get(1))
1318                {
1319                    if first.value.eq_ignore_ascii_case("weight")
1320                        && second.value.eq_ignore_ascii_case("style")
1321                        && declaration.value.len() == 2
1322                    {
1323                        declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
1324                            span: first.span,
1325                            value: atom!("initial"),
1326                            raw: None,
1327                        }))];
1328                    }
1329                }
1330            }
1331            "image-orientation" => {
1332                if let Some(ComponentValue::Ident(ident)) = declaration.value.first() {
1333                    if ident.value.eq_ignore_ascii_case("from-image") {
1334                        declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
1335                            span: ident.span,
1336                            value: atom!("initial"),
1337                            raw: None,
1338                        }))];
1339                    }
1340                }
1341            }
1342            "mask-mode" => {
1343                if let Some(ComponentValue::Ident(ident)) = declaration.value.first() {
1344                    if ident.value.eq_ignore_ascii_case("match-source")
1345                        && declaration.value.len() == 1
1346                    {
1347                        declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
1348                            span: ident.span,
1349                            value: atom!("initial"),
1350                            raw: None,
1351                        }))];
1352                    }
1353                }
1354            }
1355            "mask-type" => {
1356                if let Some(ComponentValue::Ident(ident)) = declaration.value.first() {
1357                    if ident.value.eq_ignore_ascii_case("luminance") {
1358                        declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
1359                            span: ident.span,
1360                            value: atom!("initial"),
1361                            raw: None,
1362                        }))];
1363                    }
1364                }
1365            }
1366            "ruby-align" => {
1367                if let Some(ComponentValue::Ident(ident)) = declaration.value.first() {
1368                    if ident.value.eq_ignore_ascii_case("space-around") {
1369                        declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
1370                            span: ident.span,
1371                            value: atom!("initial"),
1372                            raw: None,
1373                        }))];
1374                    }
1375                }
1376            }
1377            "ruby-merge" => {
1378                if let Some(ComponentValue::Ident(ident)) = declaration.value.first() {
1379                    if ident.value.eq_ignore_ascii_case("separate") {
1380                        declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
1381                            span: ident.span,
1382                            value: atom!("initial"),
1383                            raw: None,
1384                        }))];
1385                    }
1386                }
1387            }
1388            "ruby-position" => {
1389                if let Some(ComponentValue::Ident(ident)) = declaration.value.first() {
1390                    if ident.value.eq_ignore_ascii_case("alternate") {
1391                        declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
1392                            span: ident.span,
1393                            value: atom!("initial"),
1394                            raw: None,
1395                        }))];
1396                    }
1397                }
1398            }
1399            "text-emphasis-position" => {
1400                if let (Some(ComponentValue::Ident(first)), Some(ComponentValue::Ident(second))) =
1401                    (declaration.value.first(), declaration.value.get(1))
1402                {
1403                    if first.value.eq_ignore_ascii_case("over")
1404                        && second.value.eq_ignore_ascii_case("right")
1405                    {
1406                        declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
1407                            span: first.span,
1408                            value: atom!("initial"),
1409                            raw: None,
1410                        }))];
1411                    }
1412                }
1413            }
1414            "transform-box" => {
1415                if let Some(ComponentValue::Ident(ident)) = declaration.value.first() {
1416                    if ident.value.eq_ignore_ascii_case("view-box") {
1417                        declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
1418                            span: ident.span,
1419                            value: atom!("initial"),
1420                            raw: None,
1421                        }))];
1422                    }
1423                }
1424            }
1425            "transform-origin" => {
1426                if let (
1427                    Some(Percentage {
1428                        value: Number { value: first, .. },
1429                        span,
1430                        ..
1431                    }),
1432                    Some(Percentage {
1433                        value: Number { value: second, .. },
1434                        ..
1435                    }),
1436                    Some(Integer { value: third, .. }),
1437                ) = (
1438                    declaration
1439                        .value
1440                        .first()
1441                        .and_then(|x| x.as_percentage())
1442                        .map(|x| x.as_ref()),
1443                    declaration
1444                        .value
1445                        .get(1)
1446                        .and_then(|x| x.as_percentage())
1447                        .map(|x| x.as_ref()),
1448                    declaration
1449                        .value
1450                        .get(2)
1451                        .and_then(|x| x.as_integer())
1452                        .map(|x| x.as_ref()),
1453                ) {
1454                    if *first == 50.0
1455                        && *second == 50.0
1456                        && *third == 0
1457                        && declaration.value.len() == 3
1458                    {
1459                        declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
1460                            span: *span,
1461                            value: atom!("initial"),
1462                            raw: None,
1463                        }))];
1464                    }
1465                }
1466            }
1467            "vertical-align" => {
1468                if let Some(ComponentValue::Ident(ident)) = declaration.value.first() {
1469                    if ident.value.eq_ignore_ascii_case("baseline") {
1470                        declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
1471                            span: ident.span,
1472                            value: atom!("initial"),
1473                            raw: None,
1474                        }))];
1475                    }
1476                }
1477            }
1478            "writing-mode" => {
1479                if let Some(ComponentValue::Ident(ident)) = declaration.value.first() {
1480                    if ident.value.eq_ignore_ascii_case("horizontal-tb") {
1481                        declaration.value = vec![ComponentValue::Ident(Box::new(Ident {
1482                            span: ident.span,
1483                            value: atom!("initial"),
1484                            raw: None,
1485                        }))];
1486                    }
1487                }
1488            }
1489            _ => {}
1490        }
1491    }
1492}