2020-05-31 04:51:41 -04:00
|
|
|
use std::{
|
2020-06-16 20:00:11 -04:00
|
|
|
collections::VecDeque,
|
2020-05-31 04:51:41 -04:00
|
|
|
fmt::{self, Write},
|
2020-06-23 01:23:12 -04:00
|
|
|
hash::{Hash, Hasher},
|
2020-05-31 04:51:41 -04:00
|
|
|
mem,
|
|
|
|
};
|
|
|
|
|
2020-06-22 12:39:09 -04:00
|
|
|
use codemap::Span;
|
|
|
|
|
2020-05-31 04:51:41 -04:00
|
|
|
use super::{unify_complex, ComplexSelector, ComplexSelectorComponent};
|
|
|
|
|
2020-06-16 20:00:11 -04:00
|
|
|
use crate::{
|
|
|
|
common::{Brackets, ListSeparator, QuoteKind},
|
2020-06-22 12:39:09 -04:00
|
|
|
error::SassResult,
|
2020-06-16 20:00:11 -04:00
|
|
|
value::Value,
|
|
|
|
};
|
2020-05-31 04:51:41 -04:00
|
|
|
|
|
|
|
/// A selector list.
|
|
|
|
///
|
|
|
|
/// A selector list is composed of `ComplexSelector`s. It matches an element
|
|
|
|
/// that matches any of the component selectors.
|
2020-06-23 01:23:12 -04:00
|
|
|
#[derive(Clone, Debug)]
|
2020-05-31 04:51:41 -04:00
|
|
|
pub(crate) struct SelectorList {
|
|
|
|
/// The components of this selector.
|
|
|
|
///
|
|
|
|
/// This is never empty.
|
|
|
|
pub components: Vec<ComplexSelector>,
|
2020-06-22 12:39:09 -04:00
|
|
|
pub span: Span,
|
2020-05-31 04:51:41 -04:00
|
|
|
}
|
|
|
|
|
2020-06-23 01:23:12 -04:00
|
|
|
impl PartialEq for SelectorList {
|
|
|
|
fn eq(&self, other: &SelectorList) -> bool {
|
|
|
|
self.components == other.components
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Eq for SelectorList {}
|
|
|
|
|
|
|
|
impl Hash for SelectorList {
|
|
|
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
|
|
self.components.hash(state);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-31 04:51:41 -04:00
|
|
|
impl fmt::Display for SelectorList {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
let complexes = self.components.iter().filter(|c| !c.is_invisible());
|
|
|
|
|
|
|
|
let mut first = true;
|
|
|
|
|
|
|
|
for complex in complexes {
|
|
|
|
if first {
|
|
|
|
first = false;
|
|
|
|
} else {
|
|
|
|
f.write_char(',')?;
|
|
|
|
if complex.line_break {
|
|
|
|
f.write_char('\n')?;
|
|
|
|
} else {
|
|
|
|
// todo: not emitted in compressed
|
|
|
|
f.write_char(' ')?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
write!(f, "{}", complex)?;
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SelectorList {
|
|
|
|
pub fn is_invisible(&self) -> bool {
|
2020-05-31 15:48:11 -04:00
|
|
|
self.components.iter().all(ComplexSelector::is_invisible)
|
2020-05-31 04:51:41 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn contains_parent_selector(&self) -> bool {
|
2020-05-31 15:48:11 -04:00
|
|
|
self.components
|
|
|
|
.iter()
|
|
|
|
.any(ComplexSelector::contains_parent_selector)
|
2020-05-31 04:51:41 -04:00
|
|
|
}
|
|
|
|
|
2020-06-22 12:39:09 -04:00
|
|
|
pub const fn new(span: Span) -> Self {
|
2020-05-31 04:51:41 -04:00
|
|
|
Self {
|
|
|
|
components: Vec::new(),
|
2020-06-22 12:39:09 -04:00
|
|
|
span,
|
2020-05-31 04:51:41 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn is_empty(&self) -> bool {
|
|
|
|
self.components.is_empty()
|
|
|
|
}
|
|
|
|
|
2020-05-31 15:48:11 -04:00
|
|
|
/// Returns a `SassScript` list that represents this selector.
|
2020-05-31 04:51:41 -04:00
|
|
|
///
|
|
|
|
/// This has the same format as a list returned by `selector-parse()`.
|
|
|
|
pub fn to_sass_list(self) -> Value {
|
|
|
|
Value::List(
|
|
|
|
self.components
|
|
|
|
.into_iter()
|
|
|
|
.map(|complex| {
|
|
|
|
Value::List(
|
|
|
|
complex
|
|
|
|
.components
|
|
|
|
.into_iter()
|
|
|
|
.map(|complex_component| {
|
|
|
|
Value::String(complex_component.to_string(), QuoteKind::None)
|
|
|
|
})
|
|
|
|
.collect(),
|
|
|
|
ListSeparator::Space,
|
|
|
|
Brackets::None,
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.collect(),
|
|
|
|
ListSeparator::Comma,
|
|
|
|
Brackets::None,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns a `SelectorList` that matches only elements that are matched by
|
|
|
|
/// both this and `other`.
|
|
|
|
///
|
|
|
|
/// If no such list can be produced, returns `None`.
|
2020-05-31 15:48:11 -04:00
|
|
|
pub fn unify(self, other: &Self) -> Option<Self> {
|
2020-05-31 04:51:41 -04:00
|
|
|
let contents: Vec<ComplexSelector> = self
|
|
|
|
.components
|
|
|
|
.into_iter()
|
|
|
|
.flat_map(|c1| {
|
|
|
|
other.clone().components.into_iter().flat_map(move |c2| {
|
|
|
|
let unified: Option<Vec<Vec<ComplexSelectorComponent>>> =
|
|
|
|
unify_complex(vec![c1.components.clone(), c2.components]);
|
|
|
|
if let Some(u) = unified {
|
|
|
|
u.into_iter()
|
|
|
|
.map(|c| ComplexSelector {
|
|
|
|
components: c,
|
|
|
|
line_break: false,
|
|
|
|
})
|
|
|
|
.collect()
|
|
|
|
} else {
|
|
|
|
Vec::new()
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
if contents.is_empty() {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
|
|
|
Some(Self {
|
|
|
|
components: contents,
|
2020-06-22 12:39:09 -04:00
|
|
|
span: self.span.merge(other.span),
|
2020-05-31 04:51:41 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns a new list with all `SimpleSelector::Parent`s replaced with `parent`.
|
|
|
|
///
|
|
|
|
/// If `implicit_parent` is true, this treats `ComplexSelector`s that don't
|
|
|
|
/// contain an explicit `SimpleSelector::Parent` as though they began with one.
|
|
|
|
///
|
|
|
|
/// The given `parent` may be `None`, indicating that this has no parents. If
|
|
|
|
/// so, this list is returned as-is if it doesn't contain any explicit
|
|
|
|
/// `SimpleSelector::Parent`s. If it does, this returns a `SassError`.
|
2020-06-22 12:39:09 -04:00
|
|
|
pub fn resolve_parent_selectors(
|
|
|
|
self,
|
|
|
|
parent: Option<Self>,
|
|
|
|
implicit_parent: bool,
|
|
|
|
) -> SassResult<Self> {
|
2020-05-31 04:51:41 -04:00
|
|
|
let parent = match parent {
|
|
|
|
Some(p) => p,
|
|
|
|
None => {
|
|
|
|
if !self.contains_parent_selector() {
|
2020-06-22 12:39:09 -04:00
|
|
|
return Ok(self);
|
2020-05-31 04:51:41 -04:00
|
|
|
}
|
2020-06-22 12:39:09 -04:00
|
|
|
return Err((
|
|
|
|
"Top-level selectors may not contain the parent selector \"&\".",
|
|
|
|
self.span,
|
|
|
|
)
|
|
|
|
.into());
|
2020-05-31 04:51:41 -04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-06-22 12:39:09 -04:00
|
|
|
Ok(Self {
|
2020-05-31 04:51:41 -04:00
|
|
|
components: flatten_vertically(
|
|
|
|
self.components
|
|
|
|
.into_iter()
|
|
|
|
.map(|complex| {
|
|
|
|
if !complex.contains_parent_selector() {
|
|
|
|
if !implicit_parent {
|
2020-06-22 12:39:09 -04:00
|
|
|
return Ok(vec![complex]);
|
2020-05-31 04:51:41 -04:00
|
|
|
}
|
2020-06-22 12:39:09 -04:00
|
|
|
return Ok(parent
|
2020-05-31 04:51:41 -04:00
|
|
|
.clone()
|
|
|
|
.components
|
|
|
|
.into_iter()
|
|
|
|
.map(move |parent_complex| {
|
|
|
|
let mut components = parent_complex.components;
|
|
|
|
components.append(&mut complex.components.clone());
|
|
|
|
ComplexSelector {
|
|
|
|
components,
|
|
|
|
line_break: complex.line_break || parent_complex.line_break,
|
|
|
|
}
|
|
|
|
})
|
2020-06-22 12:39:09 -04:00
|
|
|
.collect());
|
2020-05-31 04:51:41 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
let mut new_complexes: Vec<Vec<ComplexSelectorComponent>> =
|
|
|
|
vec![Vec::new()];
|
|
|
|
let mut line_breaks = vec![false];
|
|
|
|
|
|
|
|
for component in complex.components {
|
|
|
|
if component.is_compound() {
|
|
|
|
let resolved = match component
|
|
|
|
.clone()
|
2020-06-22 12:39:09 -04:00
|
|
|
.resolve_parent_selectors(parent.clone())?
|
2020-05-31 04:51:41 -04:00
|
|
|
{
|
|
|
|
Some(r) => r,
|
|
|
|
None => {
|
2020-05-31 15:48:11 -04:00
|
|
|
for new_complex in &mut new_complexes {
|
2020-05-31 04:51:41 -04:00
|
|
|
new_complex.push(component.clone());
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let previous_complexes = mem::take(&mut new_complexes);
|
|
|
|
let previous_line_breaks = mem::take(&mut line_breaks);
|
|
|
|
|
2020-05-31 15:48:11 -04:00
|
|
|
for (i, new_complex) in previous_complexes.into_iter().enumerate() {
|
|
|
|
// todo: use .get(i)
|
2020-05-31 04:51:41 -04:00
|
|
|
let line_break = previous_line_breaks[i];
|
|
|
|
for mut resolved_complex in resolved.clone() {
|
|
|
|
let mut new_this_complex = new_complex.clone();
|
|
|
|
new_this_complex.append(&mut resolved_complex.components);
|
|
|
|
new_complexes.push(mem::take(&mut new_this_complex));
|
|
|
|
line_breaks.push(line_break || resolved_complex.line_break);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2020-05-31 15:48:11 -04:00
|
|
|
for new_complex in &mut new_complexes {
|
2020-05-31 04:51:41 -04:00
|
|
|
new_complex.push(component.clone());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut i = 0;
|
2020-06-22 12:39:09 -04:00
|
|
|
Ok(new_complexes
|
2020-05-31 04:51:41 -04:00
|
|
|
.into_iter()
|
|
|
|
.map(|new_complex| {
|
|
|
|
i += 1;
|
|
|
|
ComplexSelector {
|
|
|
|
components: new_complex,
|
|
|
|
line_break: line_breaks[i - 1],
|
|
|
|
}
|
|
|
|
})
|
2020-06-22 12:39:09 -04:00
|
|
|
.collect())
|
2020-05-31 04:51:41 -04:00
|
|
|
})
|
2020-06-22 12:39:09 -04:00
|
|
|
.collect::<SassResult<Vec<Vec<ComplexSelector>>>>()?,
|
2020-05-31 04:51:41 -04:00
|
|
|
),
|
2020-06-22 12:39:09 -04:00
|
|
|
span: self.span,
|
|
|
|
})
|
2020-05-31 04:51:41 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn is_superselector(&self, other: &Self) -> bool {
|
|
|
|
other.components.iter().all(|complex1| {
|
|
|
|
self.components
|
|
|
|
.iter()
|
|
|
|
.any(|complex2| complex2.is_super_selector(complex1))
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn flatten_vertically<A: std::fmt::Debug>(iterable: Vec<Vec<A>>) -> Vec<A> {
|
2020-05-31 15:48:11 -04:00
|
|
|
let mut queues: Vec<VecDeque<A>> = iterable.into_iter().map(VecDeque::from).collect();
|
2020-05-31 04:51:41 -04:00
|
|
|
|
|
|
|
let mut result = Vec::new();
|
|
|
|
|
|
|
|
while !queues.is_empty() {
|
2020-05-31 15:48:11 -04:00
|
|
|
for queue in &mut queues {
|
2020-05-31 04:51:41 -04:00
|
|
|
if queue.is_empty() {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
result.push(queue.pop_front().unwrap());
|
|
|
|
}
|
|
|
|
|
|
|
|
queues = queues
|
|
|
|
.into_iter()
|
|
|
|
.filter(|queue| !queue.is_empty())
|
|
|
|
.collect();
|
|
|
|
}
|
|
|
|
|
|
|
|
result
|
|
|
|
}
|