swc_css_compat/compiler/
media_query_ranges.rs

1use swc_common::DUMMY_SP;
2use swc_css_ast::{
3    Dimension, Ident, MediaFeature, MediaFeatureName, MediaFeaturePlain, MediaFeatureRange,
4    MediaFeatureRangeComparison, MediaFeatureRangeInterval, MediaFeatureValue,
5};
6
7use crate::compiler::Compiler;
8
9impl Compiler {
10    pub(crate) fn get_legacy_media_feature(
11        &mut self,
12        n: &mut MediaFeature,
13    ) -> Option<(MediaFeature, Option<MediaFeature>)> {
14        match n {
15            MediaFeature::Range(MediaFeatureRange {
16                span,
17                left,
18                comparison,
19                right,
20                ..
21            }) => {
22                if let MediaFeatureValue::Ident(name) = &**left {
23                    let name = match comparison {
24                        MediaFeatureRangeComparison::Lt | MediaFeatureRangeComparison::Le => {
25                            self.get_right_media_feature_name(name)
26                        }
27                        MediaFeatureRangeComparison::Eq => {
28                            Some(MediaFeatureName::Ident(name.clone()))
29                        }
30                        _ => self.get_left_media_feature_name(name),
31                    }?;
32
33                    let original_value = (**right).clone();
34                    let value = match comparison {
35                        MediaFeatureRangeComparison::Lt => self.get_lt_value(original_value),
36                        MediaFeatureRangeComparison::Gt => self.get_gt_value(original_value),
37                        _ => Some(original_value),
38                    }?;
39
40                    return Some((
41                        MediaFeature::Plain(MediaFeaturePlain {
42                            span: *span,
43                            name,
44                            value: Box::new(value),
45                        }),
46                        None,
47                    ));
48                } else if let MediaFeatureValue::Ident(name) = &**right {
49                    let name = match comparison {
50                        MediaFeatureRangeComparison::Lt | MediaFeatureRangeComparison::Le => {
51                            self.get_left_media_feature_name(name)
52                        }
53                        MediaFeatureRangeComparison::Eq => {
54                            Some(MediaFeatureName::Ident(name.clone()))
55                        }
56                        _ => self.get_right_media_feature_name(name),
57                    }?;
58
59                    let original_value = (**left).clone();
60                    let value = match comparison {
61                        MediaFeatureRangeComparison::Lt => self.get_gt_value(original_value),
62                        MediaFeatureRangeComparison::Gt => self.get_lt_value(original_value),
63                        _ => Some(original_value),
64                    }?;
65
66                    return Some((
67                        MediaFeature::Plain(MediaFeaturePlain {
68                            span: *span,
69                            name,
70                            value: Box::new(value),
71                        }),
72                        None,
73                    ));
74                }
75            }
76            MediaFeature::RangeInterval(MediaFeatureRangeInterval {
77                span,
78                left,
79                left_comparison,
80                name: MediaFeatureName::Ident(name),
81                right,
82                right_comparison,
83                ..
84            }) => {
85                let left_name = match left_comparison {
86                    MediaFeatureRangeComparison::Gt | MediaFeatureRangeComparison::Ge => {
87                        self.get_right_media_feature_name(name)
88                    }
89                    _ => self.get_left_media_feature_name(name),
90                }?;
91
92                let left_value = match left_comparison {
93                    MediaFeatureRangeComparison::Lt => self.get_gt_value((**left).clone()),
94                    MediaFeatureRangeComparison::Gt => self.get_lt_value((**left).clone()),
95                    _ => Some((**left).clone()),
96                }?;
97
98                let left = MediaFeature::Plain(MediaFeaturePlain {
99                    span: *span,
100                    name: left_name,
101                    value: Box::new(left_value),
102                });
103
104                let right_name = match right_comparison {
105                    MediaFeatureRangeComparison::Gt | MediaFeatureRangeComparison::Ge => {
106                        self.get_left_media_feature_name(name)
107                    }
108                    _ => self.get_right_media_feature_name(name),
109                }?;
110
111                let right_value = match right_comparison {
112                    MediaFeatureRangeComparison::Lt => self.get_lt_value((**right).clone()),
113                    MediaFeatureRangeComparison::Gt => self.get_gt_value((**right).clone()),
114                    _ => Some((**right).clone()),
115                }?;
116
117                let right = MediaFeature::Plain(MediaFeaturePlain {
118                    span: *span,
119                    name: right_name,
120                    value: Box::new(right_value),
121                });
122
123                return Some((left, Some(right)));
124            }
125            _ => {}
126        }
127
128        None
129    }
130
131    fn get_left_media_feature_name(&self, name: &Ident) -> Option<MediaFeatureName> {
132        let value = match &*name.value {
133            "width" => "min-width",
134            "height" => "min-height",
135            "device-width" => "min-device-width",
136            "device-height" => "min-device-height",
137            "aspect-ratio" => "min-aspect-ratio",
138            "device-aspect-ratio" => "min-device-aspect-ratio",
139            "color" => "min-color",
140            "color-index" => "min-color-index",
141            "monochrome" => "min-monochrome",
142            "resolution" => "min-resolution",
143            _ => return None,
144        };
145
146        Some(MediaFeatureName::Ident(Ident {
147            span: DUMMY_SP,
148            value: value.into(),
149            raw: None,
150        }))
151    }
152
153    fn get_right_media_feature_name(&self, name: &Ident) -> Option<MediaFeatureName> {
154        let value = match &*name.value {
155            "width" => "max-width",
156            "height" => "max-height",
157            "device-width" => "max-device-width",
158            "device-height" => "max-device-height",
159            "aspect-ratio" => "max-aspect-ratio",
160            "device-aspect-ratio" => "max-device-aspect-ratio",
161            "color" => "max-color",
162            "color-index" => "max-color-index",
163            "monochrome" => "max-monochrome",
164            "resolution" => "max-resolution",
165            _ => return None,
166        };
167
168        Some(MediaFeatureName::Ident(Ident {
169            span: DUMMY_SP,
170            value: value.into(),
171            raw: None,
172        }))
173    }
174
175    fn get_lt_value(&self, mut value: MediaFeatureValue) -> Option<MediaFeatureValue> {
176        match &mut value {
177            MediaFeatureValue::Number(number) => {
178                number.value -= 1.0;
179                number.raw = None;
180
181                Some(value)
182            }
183            MediaFeatureValue::Dimension(dimension) => {
184                match dimension {
185                    Dimension::Length(length) => {
186                        length.value.value -= 0.001;
187                        length.value.raw = None;
188                    }
189                    _ => {
190                        return None;
191                    }
192                }
193
194                Some(value)
195            }
196            MediaFeatureValue::Ratio(ration) => {
197                ration.left.value -= 0.001;
198                ration.left.raw = None;
199
200                Some(value)
201            }
202            _ => None,
203        }
204    }
205
206    fn get_gt_value(&self, mut value: MediaFeatureValue) -> Option<MediaFeatureValue> {
207        match &mut value {
208            MediaFeatureValue::Number(number) => {
209                number.value += 1.0;
210                number.raw = None;
211
212                Some(value)
213            }
214            MediaFeatureValue::Dimension(dimension) => {
215                match dimension {
216                    Dimension::Length(length) => {
217                        length.value.value += 0.001;
218                        length.value.raw = None;
219                    }
220                    _ => {
221                        return None;
222                    }
223                }
224
225                Some(value)
226            }
227            MediaFeatureValue::Ratio(ration) => {
228                ration.left.value += 0.001;
229                ration.left.raw = None;
230
231                Some(value)
232            }
233            _ => None,
234        }
235    }
236}