use crate::css;
use crate::sass::SassString;
use crate::{Error, ParseError, ScopeRef};
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd)]
pub struct Selectors {
s: Vec<Selector>,
}
impl Selectors {
pub fn root() -> Self {
Selectors::new(vec![Selector::root()])
}
pub fn is_root(&self) -> bool {
self.s == [Selector::root()]
}
pub fn new(s: Vec<Selector>) -> Self {
Selectors { s }
}
pub fn eval(&self, scope: ScopeRef) -> Result<css::Selectors, Error> {
let s = css::Selectors::new(
self.s
.iter()
.map(|s| s.eval(scope.clone()))
.collect::<Result<Vec<_>, Error>>()?,
);
use crate::parser::css::selectors;
use crate::parser::input_span;
Ok(ParseError::check(selectors(input_span(
format!("{} ", s).as_bytes(),
)))?)
}
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd)]
pub struct Selector(Vec<SelectorPart>);
impl Selector {
pub fn root() -> Self {
Selector(vec![])
}
pub fn new(s: Vec<SelectorPart>) -> Self {
Selector(s)
}
fn eval(&self, scope: ScopeRef) -> Result<css::Selector, Error> {
self.0
.iter()
.map(|sp| sp.eval(scope.clone()))
.collect::<Result<_, _>>()
.map(css::Selector)
}
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd)]
pub enum SelectorPart {
Simple(SassString),
Descendant,
RelOp(u8),
Attribute {
name: SassString,
op: String,
val: SassString,
modifier: Option<char>,
},
PseudoElement {
name: SassString,
arg: Option<Selectors>,
},
Pseudo {
name: SassString,
arg: Option<Selectors>,
},
BackRef,
}
impl SelectorPart {
fn eval(&self, scope: ScopeRef) -> Result<css::SelectorPart, Error> {
match *self {
SelectorPart::Attribute {
ref name,
ref op,
ref val,
ref modifier,
} => Ok(css::SelectorPart::Attribute {
name: name.evaluate(scope.clone())?,
op: op.clone(),
val: val.evaluate(scope)?.opt_unquote(),
modifier: *modifier,
}),
SelectorPart::Simple(ref v) => {
Ok(css::SelectorPart::Simple(v.evaluate(scope)?.to_string()))
}
SelectorPart::Pseudo { ref name, ref arg } => {
let arg = match &arg {
Some(ref a) => Some(a.eval(scope.clone())?),
None => None,
};
Ok(css::SelectorPart::Pseudo {
name: name.evaluate(scope)?,
arg,
})
}
SelectorPart::PseudoElement { ref name, ref arg } => {
let arg = match &arg {
Some(ref a) => Some(a.eval(scope.clone())?),
None => None,
};
Ok(css::SelectorPart::PseudoElement {
name: name.evaluate(scope)?,
arg,
})
}
SelectorPart::Descendant => Ok(css::SelectorPart::Descendant),
SelectorPart::RelOp(op) => Ok(css::SelectorPart::RelOp(op)),
SelectorPart::BackRef => Ok(css::SelectorPart::BackRef),
}
}
}