grass_compiler/selector/
compound.rs

1use std::fmt::{self, Write};
2
3use codemap::Span;
4
5use crate::error::SassResult;
6
7use super::{
8    ComplexSelector, ComplexSelectorComponent, Namespace, Pseudo, SelectorList, SimpleSelector,
9    Specificity,
10};
11
12/// A compound selector is composed of several
13/// simple selectors
14#[derive(Clone, Debug, Eq, PartialEq, Hash)]
15pub(crate) struct CompoundSelector {
16    pub components: Vec<SimpleSelector>,
17}
18
19impl fmt::Display for CompoundSelector {
20    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21        let mut did_write = false;
22        for simple in &self.components {
23            if did_write {
24                write!(f, "{}", simple)?;
25            } else {
26                let s = simple.to_string();
27                if !s.is_empty() {
28                    did_write = true;
29                }
30                write!(f, "{}", s)?;
31            }
32        }
33
34        // If we emit an empty compound, it's because all of the components got
35        // optimized out because they match all selectors, so we just emit the
36        // universal selector.
37        if !did_write {
38            f.write_char('*')?;
39        }
40
41        Ok(())
42    }
43}
44
45impl CompoundSelector {
46    pub fn max_specificity(&self) -> i32 {
47        self.specificity().max
48    }
49
50    pub fn min_specificity(&self) -> i32 {
51        self.specificity().min
52    }
53
54    /// Returns tuple of (min, max) specificity
55    pub fn specificity(&self) -> Specificity {
56        let mut min = 0;
57        let mut max = 0;
58        for simple in &self.components {
59            min += simple.min_specificity();
60            max += simple.max_specificity();
61        }
62        Specificity::new(min, max)
63    }
64
65    pub fn is_invisible(&self) -> bool {
66        self.components.iter().any(SimpleSelector::is_invisible)
67    }
68
69    pub fn is_super_selector(
70        &self,
71        other: &Self,
72        parents: &Option<Vec<ComplexSelectorComponent>>,
73    ) -> bool {
74        for simple1 in &self.components {
75            if let SimpleSelector::Pseudo(
76                pseudo @ Pseudo {
77                    selector: Some(..), ..
78                },
79            ) = simple1
80            {
81                if !pseudo.is_super_selector(other, parents.clone()) {
82                    return false;
83                }
84            } else if !simple1.is_super_selector_of_compound(other) {
85                return false;
86            }
87        }
88
89        for simple2 in &other.components {
90            if let SimpleSelector::Pseudo(Pseudo {
91                is_class: false,
92                selector: None,
93                ..
94            }) = simple2
95            {
96                if !simple2.is_super_selector_of_compound(self) {
97                    return false;
98                }
99            }
100        }
101
102        true
103    }
104
105    /// Returns a new `CompoundSelector` based on `compound` with all
106    /// `SimpleSelector::Parent`s replaced with `parent`.
107    ///
108    /// Returns `None` if `compound` doesn't contain any `SimpleSelector::Parent`s.
109    pub fn resolve_parent_selectors(
110        self,
111        span: Span,
112        parent: SelectorList,
113    ) -> SassResult<Option<Vec<ComplexSelector>>> {
114        let contains_selector_pseudo = self.components.iter().any(|simple| {
115            if let SimpleSelector::Pseudo(Pseudo {
116                selector: Some(sel),
117                ..
118            }) = simple
119            {
120                sel.contains_parent_selector()
121            } else {
122                false
123            }
124        });
125
126        if !contains_selector_pseudo && !self.components[0].is_parent() {
127            return Ok(None);
128        }
129
130        let resolved_members: Vec<SimpleSelector> = if contains_selector_pseudo {
131            self.components
132                .clone()
133                .into_iter()
134                .map(|simple| {
135                    if let SimpleSelector::Pseudo(mut pseudo) = simple {
136                        if let Some(sel) = pseudo.selector.clone() {
137                            if !sel.contains_parent_selector() {
138                                return Ok(SimpleSelector::Pseudo(pseudo));
139                            }
140
141                            pseudo.selector = Some(Box::new(
142                                sel.resolve_parent_selectors(Some(parent.clone()), false)?,
143                            ));
144                        }
145
146                        Ok(SimpleSelector::Pseudo(pseudo))
147                    } else {
148                        Ok(simple)
149                    }
150                })
151                .collect::<SassResult<Vec<SimpleSelector>>>()?
152        } else {
153            self.components.clone()
154        };
155
156        if let Some(SimpleSelector::Parent(suffix)) = self.components.first() {
157            if self.components.len() == 1 && suffix.is_none() {
158                return Ok(Some(parent.components));
159            }
160        } else {
161            return Ok(Some(vec![ComplexSelector::new(
162                vec![ComplexSelectorComponent::Compound(CompoundSelector {
163                    components: resolved_members,
164                })],
165                false,
166            )]));
167        }
168
169        let parent_span = parent.span;
170
171        Ok(Some(
172            parent
173                .components
174                .into_iter()
175                .map(move |mut complex| {
176                    let last_component = complex.components.last();
177                    let last = if let Some(ComplexSelectorComponent::Compound(c)) = last_component {
178                        c.clone()
179                    } else {
180                        return Err((
181                            format!("Parent \"{}\" is incompatible with this selector.", complex),
182                            span,
183                        )
184                            .into());
185                    };
186
187                    let mut components = last.components;
188
189                    if let Some(SimpleSelector::Parent(Some(suffix))) = self.components.first() {
190                        let mut end = components.pop().unwrap();
191                        end.add_suffix(suffix, parent_span)?;
192                        components.push(end);
193                    }
194
195                    components.extend(resolved_members.clone().into_iter().skip(1));
196
197                    let last = CompoundSelector { components };
198
199                    complex.components.pop();
200
201                    let mut components = complex.components;
202                    components.push(ComplexSelectorComponent::Compound(last));
203
204                    Ok(ComplexSelector::new(components, complex.line_break))
205                })
206                .collect::<SassResult<Vec<ComplexSelector>>>()?,
207        ))
208    }
209
210    /// Returns a `CompoundSelector` that matches only elements that are matched by
211    /// both `compound1` and `compound2`.
212    ///
213    /// If no such selector can be produced, returns `None`.
214    pub fn unify(self, other: Self) -> Option<Self> {
215        let mut components = other.components;
216        for simple in self.components {
217            components = simple.unify(std::mem::take(&mut components))?;
218        }
219
220        Some(Self { components })
221    }
222
223    /// Adds a `SimpleSelector::Parent` to the beginning of `compound`, or returns `None` if
224    /// that wouldn't produce a valid selector.
225    pub fn prepend_parent(mut self) -> Option<Self> {
226        Some(match self.components.first()? {
227            SimpleSelector::Universal(..) => return None,
228            SimpleSelector::Type(name) => {
229                if name.namespace != Namespace::None {
230                    return None;
231                }
232                let mut components = vec![SimpleSelector::Parent(Some(name.ident.clone()))];
233                components.extend(self.components.into_iter().skip(1));
234
235                Self { components }
236            }
237            _ => {
238                let mut components = vec![SimpleSelector::Parent(None)];
239                components.append(&mut self.components);
240                Self { components }
241            }
242        })
243    }
244}