selector unification of pseudo parens
This commit is contained in:
parent
b2451b45c6
commit
b7b58c2ac6
@ -22,6 +22,10 @@ impl Selector {
|
|||||||
pub const fn new() -> Selector {
|
pub const fn new() -> Selector {
|
||||||
Selector(Vec::new())
|
Selector(Vec::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn contains_super_selector(&self) -> bool {
|
||||||
|
self.0.iter().any(|s| s.contains_super_selector)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
@ -29,6 +33,7 @@ struct SelectorPart {
|
|||||||
pub inner: Vec<SelectorKind>,
|
pub inner: Vec<SelectorKind>,
|
||||||
pub is_invisible: bool,
|
pub is_invisible: bool,
|
||||||
pub has_newline: bool,
|
pub has_newline: bool,
|
||||||
|
pub contains_super_selector: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for SelectorPart {
|
impl Display for SelectorPart {
|
||||||
@ -167,7 +172,7 @@ impl Display for SelectorKind {
|
|||||||
SelectorKind::PseudoElement(s) => write!(f, "::{}", s),
|
SelectorKind::PseudoElement(s) => write!(f, "::{}", s),
|
||||||
SelectorKind::PseudoParen(s, val) => write!(f, ":{}({})", s, val),
|
SelectorKind::PseudoParen(s, val) => write!(f, ":{}({})", s, val),
|
||||||
SelectorKind::Placeholder(s) => write!(f, "%{}", s),
|
SelectorKind::Placeholder(s) => write!(f, "%{}", s),
|
||||||
SelectorKind::Super => todo!(),
|
SelectorKind::Super => unreachable!("& selector should not be emitted"),
|
||||||
SelectorKind::Whitespace => f.write_char(' '),
|
SelectorKind::Whitespace => f.write_char(' '),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -240,6 +245,7 @@ impl Selector {
|
|||||||
let mut inner = Vec::new();
|
let mut inner = Vec::new();
|
||||||
let mut is_invisible = false;
|
let mut is_invisible = false;
|
||||||
let mut has_newline = false;
|
let mut has_newline = false;
|
||||||
|
let mut contains_super_selector = false;
|
||||||
let mut parts = Vec::new();
|
let mut parts = Vec::new();
|
||||||
|
|
||||||
// HACK: we re-lex here to get access to generic helper functions that
|
// HACK: we re-lex here to get access to generic helper functions that
|
||||||
@ -255,7 +261,10 @@ impl Selector {
|
|||||||
)?));
|
)?));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
'&' => SelectorKind::Super,
|
'&' => {
|
||||||
|
contains_super_selector = true;
|
||||||
|
SelectorKind::Super
|
||||||
|
}
|
||||||
'.' => {
|
'.' => {
|
||||||
iter.next();
|
iter.next();
|
||||||
inner.push(SelectorKind::Class(eat_ident_no_interpolation(&mut iter)?));
|
inner.push(SelectorKind::Class(eat_ident_no_interpolation(&mut iter)?));
|
||||||
@ -288,11 +297,13 @@ impl Selector {
|
|||||||
inner: inner.clone(),
|
inner: inner.clone(),
|
||||||
is_invisible,
|
is_invisible,
|
||||||
has_newline,
|
has_newline,
|
||||||
|
contains_super_selector,
|
||||||
});
|
});
|
||||||
inner.clear();
|
inner.clear();
|
||||||
}
|
}
|
||||||
is_invisible = false;
|
is_invisible = false;
|
||||||
has_newline = false;
|
has_newline = false;
|
||||||
|
contains_super_selector = false;
|
||||||
devour_whitespace(&mut iter);
|
devour_whitespace(&mut iter);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -303,11 +314,16 @@ impl Selector {
|
|||||||
}
|
}
|
||||||
':' => {
|
':' => {
|
||||||
iter.next();
|
iter.next();
|
||||||
inner.push(Self::consume_pseudo_selector(
|
let sel = Self::consume_pseudo_selector(&mut iter, scope, super_selector)?;
|
||||||
&mut iter,
|
match &sel {
|
||||||
scope,
|
SelectorKind::PseudoParen(_, s) => {
|
||||||
super_selector,
|
if s.contains_super_selector() {
|
||||||
)?);
|
contains_super_selector = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
inner.push(sel);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
c if c.is_whitespace() => {
|
c if c.is_whitespace() => {
|
||||||
@ -326,6 +342,7 @@ impl Selector {
|
|||||||
inner,
|
inner,
|
||||||
is_invisible,
|
is_invisible,
|
||||||
has_newline,
|
has_newline,
|
||||||
|
contains_super_selector,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -367,6 +384,55 @@ impl Selector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn replace(super_selector: Selector, this: Selector) -> Selector {
|
||||||
|
if super_selector.0.is_empty() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
if this.0.is_empty() {
|
||||||
|
return super_selector;
|
||||||
|
}
|
||||||
|
let mut parts = Vec::with_capacity(super_selector.0.len());
|
||||||
|
for (idx, part) in super_selector.clone().0.into_iter().enumerate() {
|
||||||
|
let mut found_inner = false;
|
||||||
|
for part2 in this.clone().0 {
|
||||||
|
if !part2.contains_super_selector {
|
||||||
|
if idx == 0 {
|
||||||
|
parts.push(part2);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let mut kinds = Vec::new();
|
||||||
|
for kind in part2.clone().inner {
|
||||||
|
match kind {
|
||||||
|
SelectorKind::Super => kinds.extend(part.inner.clone()),
|
||||||
|
SelectorKind::PseudoParen(name, inner) => {
|
||||||
|
if inner.contains_super_selector() {
|
||||||
|
found_inner = true;
|
||||||
|
kinds.push(SelectorKind::PseudoParen(
|
||||||
|
name,
|
||||||
|
Selector::replace(super_selector.clone(), inner),
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
kinds.push(SelectorKind::PseudoParen(name, inner));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => kinds.push(kind),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parts.push(SelectorPart {
|
||||||
|
inner: kinds,
|
||||||
|
is_invisible: part2.is_invisible,
|
||||||
|
has_newline: part2.has_newline,
|
||||||
|
contains_super_selector: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if found_inner {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Selector(parts)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn zip(&self, other: &Selector) -> Selector {
|
pub fn zip(&self, other: &Selector) -> Selector {
|
||||||
if self.0.is_empty() {
|
if self.0.is_empty() {
|
||||||
return Selector(other.0.clone());
|
return Selector(other.0.clone());
|
||||||
@ -375,16 +441,30 @@ impl Selector {
|
|||||||
}
|
}
|
||||||
let mut rules = Vec::with_capacity(self.0.len());
|
let mut rules = Vec::with_capacity(self.0.len());
|
||||||
for sel1 in self.clone().0 {
|
for sel1 in self.clone().0 {
|
||||||
|
let mut found_inner = false;
|
||||||
for sel2 in other.clone().0 {
|
for sel2 in other.clone().0 {
|
||||||
let mut this_selector: Vec<SelectorKind> = Vec::with_capacity(other.0.len());
|
let mut this_selector: Vec<SelectorKind> = Vec::with_capacity(other.0.len());
|
||||||
let mut found_super = false;
|
let mut found_super = false;
|
||||||
|
|
||||||
for sel in sel2.inner {
|
for sel in sel2.inner {
|
||||||
if sel == SelectorKind::Super {
|
match sel {
|
||||||
this_selector.extend(sel1.clone().inner);
|
SelectorKind::Super => {
|
||||||
found_super = true;
|
this_selector.extend(sel1.inner.clone());
|
||||||
} else {
|
found_super = true;
|
||||||
this_selector.push(sel.clone());
|
}
|
||||||
|
SelectorKind::PseudoParen(s, inner_selector) => {
|
||||||
|
if inner_selector.contains_super_selector() {
|
||||||
|
found_super = true;
|
||||||
|
found_inner = true;
|
||||||
|
this_selector.push(SelectorKind::PseudoParen(
|
||||||
|
s,
|
||||||
|
Selector::replace(self.clone(), inner_selector),
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
this_selector.push(SelectorKind::PseudoParen(s, inner_selector));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => this_selector.push(sel),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -398,9 +478,13 @@ impl Selector {
|
|||||||
rules.push(SelectorPart {
|
rules.push(SelectorPart {
|
||||||
inner: this_selector,
|
inner: this_selector,
|
||||||
is_invisible: sel1.is_invisible || sel2.is_invisible,
|
is_invisible: sel1.is_invisible || sel2.is_invisible,
|
||||||
has_newline: sel1.has_newline || sel2.has_newline,
|
has_newline: (sel1.has_newline || sel2.has_newline) && !found_inner,
|
||||||
|
contains_super_selector: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if found_inner {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Selector(rules)
|
Selector(rules)
|
||||||
}
|
}
|
||||||
|
@ -333,3 +333,33 @@ error!(
|
|||||||
modifier_on_any_attr,
|
modifier_on_any_attr,
|
||||||
"[attr i] {color: foo;}", "Error: Expected \"]\"."
|
"[attr i] {color: foo;}", "Error: Expected \"]\"."
|
||||||
);
|
);
|
||||||
|
test!(
|
||||||
|
psuedo_paren_child_contains_ampersand,
|
||||||
|
".a, .b {\n :not(&-c) {\n d: e\n }\n}\n",
|
||||||
|
":not(.a-c, .b-c) {\n d: e;\n}\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
psuedo_paren_child_no_ampersand_two_newlines__this_test_confounds_me,
|
||||||
|
".a, .b {\n :not(-c),\n :not(-c) {\n d: e\n }\n}\n",
|
||||||
|
".a :not(-c),\n.a :not(-c), .b :not(-c),\n.b :not(-c) {\n d: e;\n}\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
psuedo_paren_child_ampersand_two_newlines__this_test_confounds_me,
|
||||||
|
".a, .b {\n :not(&-c, &-d),\n :not(&-c) {\n d: e\n }\n}\n",
|
||||||
|
":not(.a-c, .a-d, .b-c, .b-d), :not(.a-c, .b-c) {\n d: e;\n}\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
psuedo_paren_child_ampersand_inner_psuedo_paren,
|
||||||
|
".a, .b {\n :not(:not(&-c)) {\n d: e\n }\n}\n",
|
||||||
|
":not(:not(.a-c, .b-c)) {\n d: e;\n}\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
psuedo_paren_child_psuedo_paren_ampersand_inner_psuedo_paren,
|
||||||
|
".a, .b {\n :not(:not(c), &-d) {\n d: e\n }\n}\n",
|
||||||
|
":not(:not(c), .a-d, .b-d) {\n d: e;\n}\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
psuedo_paren_child_ampersand_psuedo_paren__inner_psuedo_paren,
|
||||||
|
".a, .b {\n :not(&-d, :not(c)) {\n d: e\n }\n}\n",
|
||||||
|
":not(.a-d, :not(c), .b-d) {\n d: e;\n}\n"
|
||||||
|
);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user