grass_compiler/selector/
compound.rs1use 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#[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 !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 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 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 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 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}