swc_css_minifier/compressor/
supports.rs

1use std::mem::take;
2
3use swc_common::DUMMY_SP;
4use swc_css_ast::*;
5
6use super::Compressor;
7use crate::util::dedup;
8
9impl Compressor {
10    fn is_first_supports_in_parens(&self, supports_condition: &SupportsCondition) -> bool {
11        if let Some(SupportsConditionType::SupportsInParens(_)) =
12            supports_condition.conditions.first()
13        {
14            true
15        } else {
16            false
17        }
18    }
19
20    fn is_first_or_supports_type(&self, supports_condition: &SupportsCondition) -> bool {
21        matches!(
22            supports_condition.conditions.get(1),
23            Some(SupportsConditionType::Or(_))
24        )
25    }
26
27    fn is_first_and_supports_type(&self, supports_condition: &SupportsCondition) -> bool {
28        matches!(
29            supports_condition.conditions.get(1),
30            Some(SupportsConditionType::And(_))
31        )
32    }
33
34    pub(super) fn compress_supports_condition(&mut self, n: &mut SupportsCondition) {
35        match n.conditions.get(1) {
36            Some(SupportsConditionType::Or(_)) => {
37                let need_compress = n.conditions.iter().any(|item| match item {
38                    SupportsConditionType::SupportsInParens(
39                        SupportsInParens::SupportsCondition(supports_condition),
40                    ) if self.is_first_or_supports_type(supports_condition)
41                        && self.is_first_supports_in_parens(supports_condition) =>
42                    {
43                        true
44                    }
45                    SupportsConditionType::Or(supports_or) => match &*supports_or.condition {
46                        SupportsInParens::SupportsCondition(supports_condition)
47                            if self.is_first_or_supports_type(supports_condition)
48                                && self.is_first_supports_in_parens(supports_condition) =>
49                        {
50                            true
51                        }
52                        _ => false,
53                    },
54                    _ => false,
55                });
56
57                if need_compress {
58                    let mut new_conditions = Vec::with_capacity(n.conditions.len());
59
60                    for item in take(&mut n.conditions) {
61                        match item {
62                            SupportsConditionType::SupportsInParens(
63                                SupportsInParens::SupportsCondition(supports_condition),
64                            ) if self.is_first_or_supports_type(&supports_condition)
65                                && self.is_first_supports_in_parens(&supports_condition) =>
66                            {
67                                let mut iter = supports_condition.conditions.into_iter();
68
69                                if let Some(SupportsConditionType::SupportsInParens(
70                                    supports_in_parens,
71                                )) = iter.next()
72                                {
73                                    new_conditions.push(SupportsConditionType::SupportsInParens(
74                                        supports_in_parens,
75                                    ));
76
77                                    new_conditions.extend(iter);
78                                }
79                            }
80                            SupportsConditionType::Or(supports_or) => {
81                                match *supports_or.condition {
82                                    SupportsInParens::SupportsCondition(supports_condition)
83                                        if self.is_first_or_supports_type(&supports_condition)
84                                            && self.is_first_supports_in_parens(
85                                                &supports_condition,
86                                            ) =>
87                                    {
88                                        let mut iter = supports_condition.conditions.into_iter();
89
90                                        if let Some(SupportsConditionType::SupportsInParens(
91                                            supports_in_parens,
92                                        )) = iter.next()
93                                        {
94                                            new_conditions.push(SupportsConditionType::Or(
95                                                SupportsOr {
96                                                    span: DUMMY_SP,
97                                                    keyword: None,
98                                                    condition: Box::new(supports_in_parens),
99                                                },
100                                            ));
101
102                                            new_conditions.extend(iter);
103                                        }
104                                    }
105                                    _ => {
106                                        new_conditions.push(SupportsConditionType::Or(supports_or));
107                                    }
108                                }
109                            }
110                            _ => {
111                                new_conditions.push(item);
112                            }
113                        }
114                    }
115
116                    n.conditions = new_conditions;
117                }
118            }
119            Some(SupportsConditionType::And(_)) => {
120                let need_compress = n.conditions.iter().any(|item| match item {
121                    SupportsConditionType::SupportsInParens(
122                        SupportsInParens::SupportsCondition(supports_condition),
123                    ) if self.is_first_and_supports_type(supports_condition)
124                        && self.is_first_supports_in_parens(supports_condition) =>
125                    {
126                        true
127                    }
128                    SupportsConditionType::And(supports_and) => match &*supports_and.condition {
129                        SupportsInParens::SupportsCondition(supports_condition)
130                            if self.is_first_and_supports_type(supports_condition)
131                                && self.is_first_supports_in_parens(supports_condition) =>
132                        {
133                            true
134                        }
135                        _ => false,
136                    },
137                    _ => false,
138                });
139
140                if need_compress {
141                    let mut new_conditions = Vec::with_capacity(n.conditions.len());
142
143                    for item in take(&mut n.conditions) {
144                        match item {
145                            SupportsConditionType::SupportsInParens(
146                                SupportsInParens::SupportsCondition(supports_condition),
147                            ) if self.is_first_and_supports_type(&supports_condition)
148                                && self.is_first_supports_in_parens(&supports_condition) =>
149                            {
150                                let mut iter = supports_condition.conditions.into_iter();
151
152                                if let Some(SupportsConditionType::SupportsInParens(
153                                    supports_in_parens,
154                                )) = iter.next()
155                                {
156                                    new_conditions.push(SupportsConditionType::SupportsInParens(
157                                        supports_in_parens,
158                                    ));
159
160                                    new_conditions.extend(iter);
161                                }
162                            }
163                            SupportsConditionType::And(supports_and) => match *supports_and
164                                .condition
165                            {
166                                SupportsInParens::SupportsCondition(supports_condition)
167                                    if self.is_first_and_supports_type(&supports_condition)
168                                        && self
169                                            .is_first_supports_in_parens(&supports_condition) =>
170                                {
171                                    let mut iter = supports_condition.conditions.into_iter();
172
173                                    if let Some(SupportsConditionType::SupportsInParens(
174                                        supports_in_parens,
175                                    )) = iter.next()
176                                    {
177                                        new_conditions.push(SupportsConditionType::And(
178                                            SupportsAnd {
179                                                span: DUMMY_SP,
180                                                keyword: None,
181                                                condition: Box::new(supports_in_parens),
182                                            },
183                                        ));
184
185                                        new_conditions.extend(iter);
186                                    }
187                                }
188                                _ => {
189                                    new_conditions.push(SupportsConditionType::And(supports_and));
190                                }
191                            },
192                            _ => {
193                                new_conditions.push(item);
194                            }
195                        }
196                    }
197
198                    n.conditions = new_conditions;
199                }
200            }
201            _ => {}
202        }
203
204        dedup(&mut n.conditions);
205    }
206
207    pub(super) fn compress_supports_in_parens(&mut self, n: &mut SupportsInParens) {
208        match n {
209            SupportsInParens::SupportsCondition(supports_condition)
210                if supports_condition.conditions.len() == 1 =>
211            {
212                if let Some(SupportsConditionType::SupportsInParens(supports_in_parens)) =
213                    supports_condition.conditions.first()
214                {
215                    *n = supports_in_parens.clone();
216                }
217            }
218            _ => {}
219        }
220    }
221}