swc_css_compat/compiler/
nesting.rs1use std::iter::once;
2
3use swc_common::{util::take::Take, DUMMY_SP};
4use swc_css_ast::*;
5
6use crate::compiler::Compiler;
7
8impl Compiler {
9 fn process_subclass_selectors(
10 &mut self,
11 prelude: &SelectorList,
12 subclass: &mut Vec<SubclassSelector>,
13 ) {
14 for sel in subclass {
15 if let SubclassSelector::PseudoClass(PseudoClassSelector {
16 children: Some(children),
17 ..
18 }) = sel
19 {
20 for c in children {
21 if let PseudoClassSelectorChildren::ForgivingSelectorList(c) = c {
22 let mut selectors = Vec::new();
23
24 for sel in &mut c.children {
25 match sel {
26 ForgivingComplexSelector::ComplexSelector(sel) => {
27 selectors.push(sel.clone());
28 }
29 ForgivingComplexSelector::ListOfComponentValues(_) => {
30 return;
32 }
33 }
34 }
35
36 self.process_complex_selectors(prelude, &mut selectors);
37
38 *c = ForgivingSelectorList {
39 children: selectors
40 .into_iter()
41 .map(ForgivingComplexSelector::ComplexSelector)
42 .collect(),
43 ..*c
44 };
45 }
46 }
47 }
48 }
49 }
50
51 fn process_complex_selectors(
52 &mut self,
53 prelude: &SelectorList,
54 selectors: &mut Vec<ComplexSelector>,
55 ) {
56 let mut new_selectors = Vec::new();
57
58 'complex: for complex in selectors.take() {
59 for compound in &complex.children {
60 match compound {
61 ComplexSelectorChildren::CompoundSelector(compound) => {
62 if compound.nesting_selector.is_some() {
63 for prelude_children in &prelude.children {
64 let mut new = ComplexSelector {
65 span: Default::default(),
66 children: Default::default(),
67 };
68 for compound in &complex.children {
69 match compound {
70 ComplexSelectorChildren::CompoundSelector(compound) => {
71 self.append_compound(
72 prelude,
73 &mut new,
74 prelude_children,
75 compound,
76 );
77 }
78 ComplexSelectorChildren::Combinator(_) => {
79 new.children.push(compound.clone());
80 }
81 }
82 }
83 new_selectors.push(new);
84 }
85 continue 'complex;
86 }
87 }
88 ComplexSelectorChildren::Combinator(_) => {}
89 }
90 }
91
92 new_selectors.push(complex);
93 }
94
95 *selectors = new_selectors;
96 }
97
98 fn append_compound(
99 &mut self,
100 prelude: &SelectorList,
101 to: &mut ComplexSelector,
102 base: &ComplexSelector,
103 c: &CompoundSelector,
104 ) {
105 if c.nesting_selector.is_some() {
106 let len = base.children.len();
107
108 to.children
109 .extend(
110 base.children
111 .iter()
112 .cloned()
113 .enumerate()
114 .map(|(idx, mut children)| {
115 if idx == len - 1 {
116 if let ComplexSelectorChildren::CompoundSelector(compound) =
117 &mut children
118 {
119 if c.type_selector.is_some() {
120 compound.type_selector.clone_from(&c.type_selector);
121 }
122
123 let mut subclass = c.subclass_selectors.clone();
124
125 self.process_subclass_selectors(prelude, &mut subclass);
126
127 compound.subclass_selectors.extend(subclass);
128 }
129 }
130
131 children
132 }),
133 );
134 } else {
135 to.children
136 .push(ComplexSelectorChildren::CompoundSelector(c.clone()));
137 }
138 }
139
140 fn relative_selector_list_to_selector_list(
141 &mut self,
142 base: &SelectorList,
143 relative_selector_list: &RelativeSelectorList,
144 ) -> SelectorList {
145 let mut children = Vec::new();
146
147 for base_complex in &base.children {
148 for relative_selector in &relative_selector_list.children {
149 let mut complex_selector = ComplexSelector {
150 span: relative_selector.span,
151 children: Default::default(),
152 };
153
154 let is_non_relative = relative_selector.combinator.is_none()
155 && relative_selector.selector.children.iter().any(|s| match s {
156 ComplexSelectorChildren::CompoundSelector(s) => {
157 s.nesting_selector.is_some()
158 }
159 _ => false,
160 });
161
162 if let Some(combinator) = &relative_selector.combinator {
163 complex_selector
164 .children
165 .extend(base_complex.children.clone());
166 complex_selector
167 .children
168 .push(ComplexSelectorChildren::Combinator(combinator.clone()))
169 } else if !is_non_relative {
170 complex_selector
171 .children
172 .extend(base_complex.children.clone());
173 complex_selector
174 .children
175 .push(ComplexSelectorChildren::Combinator(Combinator {
176 span: DUMMY_SP,
177 value: CombinatorValue::Descendant,
178 }))
179 }
180
181 for relative_complex_selector_children in &relative_selector.selector.children {
182 match relative_complex_selector_children {
183 ComplexSelectorChildren::CompoundSelector(compound) => {
184 self.append_compound(
185 base,
186 &mut complex_selector,
187 base_complex,
188 compound,
189 );
190 }
191 ComplexSelectorChildren::Combinator(combinator) => {
192 complex_selector
193 .children
194 .push(ComplexSelectorChildren::Combinator(combinator.clone()));
195 }
196 }
197 }
198
199 children.push(complex_selector);
200 }
201 }
202
203 SelectorList {
204 span: relative_selector_list.span,
205 children,
206 }
207 }
208
209 fn process_prelude(&mut self, base: &QualifiedRulePrelude, to: &mut QualifiedRulePrelude) {
211 if let (
212 QualifiedRulePrelude::SelectorList(base),
213 QualifiedRulePrelude::RelativeSelectorList(relative_selector_list),
214 ) = (base, &to)
215 {
216 let selector_list =
217 self.relative_selector_list_to_selector_list(base, relative_selector_list);
218
219 *to = QualifiedRulePrelude::SelectorList(selector_list);
220 }
221 }
222
223 pub(crate) fn extract_nested_rules(&mut self, rule: &mut QualifiedRule) -> Vec<Rule> {
224 let mut nested_rules = Vec::new();
225 let mut block_values = Vec::new();
226
227 for value in rule.block.value.take() {
228 match value {
229 ComponentValue::QualifiedRule(mut nested) => {
230 self.process_prelude(&rule.prelude, &mut nested.prelude);
231
232 nested_rules.push(Rule::QualifiedRule(nested));
233
234 continue;
235 }
236 ComponentValue::AtRule(ref at_rule) => {
237 if let Some(
238 AtRulePrelude::MediaPrelude(..)
239 | AtRulePrelude::SupportsPrelude(..)
240 | AtRulePrelude::ContainerPrelude(..)
241 | AtRulePrelude::DocumentPrelude(..),
242 ) = at_rule.prelude.as_deref()
243 {
244 if let Some(block) = &at_rule.block {
245 let mut decls_of_media = Vec::new();
246 let mut nested_of_media = Vec::new();
247
248 for n in &block.value {
249 match n {
250 ComponentValue::QualifiedRule(n) => {
251 let mut q = n.clone();
252
253 self.process_prelude(&rule.prelude, &mut q.prelude);
254
255 let rules = self.extract_nested_rules(&mut q);
256
257 nested_of_media.extend(
258 once(Rule::QualifiedRule(q))
259 .chain(rules)
260 .map(From::from),
261 );
262 }
263
264 _ => {
265 decls_of_media.push(n.clone());
266 }
267 }
268 }
269
270 if !decls_of_media.is_empty() {
271 let rule = Box::new(QualifiedRule {
272 span: DUMMY_SP,
273 prelude: rule.prelude.clone(),
274 block: SimpleBlock {
275 value: decls_of_media,
276 ..block.clone()
277 },
278 });
279
280 nested_of_media.insert(0, ComponentValue::QualifiedRule(rule));
281 }
282
283 nested_rules.push(Rule::AtRule(Box::new(AtRule {
284 block: Some(SimpleBlock {
285 value: nested_of_media,
286 ..block.clone()
287 }),
288 ..*at_rule.clone()
289 })));
290
291 continue;
292 }
293 }
294 }
295 _ => {}
296 }
297
298 block_values.push(value);
299 }
300
301 rule.block.value = block_values;
302
303 nested_rules
304 }
305}