Skip to content

Commit 31fc453

Browse files
committed
Fix downleveling selectors
Fixes parcel-bundler#413
1 parent 59cbc02 commit 31fc453

File tree

3 files changed

+98
-8
lines changed

3 files changed

+98
-8
lines changed

src/lib.rs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5627,6 +5627,84 @@ mod tests {
56275627
},
56285628
);
56295629

5630+
prefix_test(
5631+
"a:is(:dir(rtl)) {color:red}",
5632+
indoc! {r#"
5633+
a:lang(ae, ar, arc, bcc, bqi, ckb, dv, fa, glk, he, ku, mzn, nqo, pnb, ps, sd, ug, ur, yi) {
5634+
color: red;
5635+
}
5636+
"#},
5637+
Browsers {
5638+
safari: Some(14 << 16),
5639+
..Browsers::default()
5640+
},
5641+
);
5642+
5643+
prefix_test(
5644+
"a:where(:dir(rtl)) {color:red}",
5645+
indoc! {r#"
5646+
a:where(:lang(ae, ar, arc, bcc, bqi, ckb, dv, fa, glk, he, ku, mzn, nqo, pnb, ps, sd, ug, ur, yi)) {
5647+
color: red;
5648+
}
5649+
"#},
5650+
Browsers {
5651+
safari: Some(14 << 16),
5652+
..Browsers::default()
5653+
},
5654+
);
5655+
5656+
prefix_test(
5657+
"a:has(:dir(rtl)) {color:red}",
5658+
indoc! {r#"
5659+
a:has(:lang(ae, ar, arc, bcc, bqi, ckb, dv, fa, glk, he, ku, mzn, nqo, pnb, ps, sd, ug, ur, yi)) {
5660+
color: red;
5661+
}
5662+
"#},
5663+
Browsers {
5664+
safari: Some(14 << 16),
5665+
..Browsers::default()
5666+
},
5667+
);
5668+
5669+
prefix_test(
5670+
"a:not(:dir(rtl)) {color:red}",
5671+
indoc! {r#"
5672+
a:not(:lang(ae, ar, arc, bcc, bqi, ckb, dv, fa, glk, he, ku, mzn, nqo, pnb, ps, sd, ug, ur, yi)) {
5673+
color: red;
5674+
}
5675+
"#},
5676+
Browsers {
5677+
safari: Some(14 << 16),
5678+
..Browsers::default()
5679+
},
5680+
);
5681+
5682+
prefix_test(
5683+
"a:dir(rtl)::after {color:red}",
5684+
indoc! {r#"
5685+
a:lang(ae, ar, arc, bcc, bqi, ckb, dv, fa, glk, he, ku, mzn, nqo, pnb, ps, sd, ug, ur, yi):after {
5686+
color: red;
5687+
}
5688+
"#},
5689+
Browsers {
5690+
safari: Some(14 << 16),
5691+
..Browsers::default()
5692+
},
5693+
);
5694+
5695+
prefix_test(
5696+
"a:dir(rtl) div {color:red}",
5697+
indoc! {r#"
5698+
a:lang(ae, ar, arc, bcc, bqi, ckb, dv, fa, glk, he, ku, mzn, nqo, pnb, ps, sd, ug, ur, yi) div {
5699+
color: red;
5700+
}
5701+
"#},
5702+
Browsers {
5703+
safari: Some(14 << 16),
5704+
..Browsers::default()
5705+
},
5706+
);
5707+
56305708
minify_test(".foo::cue {color: red}", ".foo::cue{color:red}");
56315709
minify_test(".foo::cue-region {color: red}", ".foo::cue-region{color:red}");
56325710
minify_test(".foo::cue(b) {color: red}", ".foo::cue(b){color:red}");

src/rules/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -593,7 +593,7 @@ impl<'i, T> CssRuleList<'i, T> {
593593
if let Some(targets) = context.targets {
594594
style.vendor_prefix = get_prefix(&style.selectors);
595595
if style.vendor_prefix.contains(VendorPrefix::None) {
596-
style.vendor_prefix = downlevel_selectors(&mut style.selectors, *targets);
596+
style.vendor_prefix = downlevel_selectors(style.selectors.0.as_mut_slice(), *targets);
597597
}
598598
}
599599

src/selector.rs

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1655,12 +1655,16 @@ pub(crate) fn is_equivalent<'i>(selectors: &SelectorList<'i>, other: &SelectorLi
16551655
pub(crate) fn get_prefix(selectors: &SelectorList) -> VendorPrefix {
16561656
let mut prefix = VendorPrefix::empty();
16571657
for selector in &selectors.0 {
1658-
for component in selector.iter() {
1658+
for component in selector.iter_raw_match_order() {
16591659
let p = match component {
16601660
// Return none rather than empty for these so that we call downlevel_selectors.
16611661
Component::NonTSPseudoClass(PseudoClass::Lang { .. })
16621662
| Component::NonTSPseudoClass(PseudoClass::Dir { .. })
1663-
| Component::Is(..) => VendorPrefix::None,
1663+
| Component::Is(..)
1664+
| Component::Where(..)
1665+
| Component::Has(..)
1666+
| Component::Negation(..) => VendorPrefix::None,
1667+
Component::Any(prefix, _) => *prefix,
16641668
Component::NonTSPseudoClass(pc) => pc.get_prefix(),
16651669
Component::PseudoElement(pe) => pe.get_prefix(),
16661670
_ => VendorPrefix::empty(),
@@ -1686,9 +1690,9 @@ const RTL_LANGS: &[&str] = &[
16861690

16871691
/// Downlevels the given selectors to be compatible with the given browser targets.
16881692
/// Returns the necessary vendor prefixes.
1689-
pub(crate) fn downlevel_selectors(selectors: &mut SelectorList, targets: Browsers) -> VendorPrefix {
1693+
pub(crate) fn downlevel_selectors(selectors: &mut [Selector], targets: Browsers) -> VendorPrefix {
16901694
let mut necessary_prefixes = VendorPrefix::empty();
1691-
for selector in &mut selectors.0 {
1695+
for selector in selectors {
16921696
for component in selector.iter_mut_raw_match_order() {
16931697
necessary_prefixes |= downlevel_component(component, targets);
16941698
}
@@ -1723,17 +1727,25 @@ fn downlevel_component<'i>(component: &mut Component<'i>, targets: Browsers) ->
17231727
}
17241728
}
17251729
Component::PseudoElement(pe) => pe.get_necessary_prefixes(targets),
1726-
Component::Is(ref selectors) => {
1730+
Component::Is(selectors) => {
1731+
let mut necessary_prefixes = downlevel_selectors(&mut **selectors, targets);
1732+
17271733
// Convert :is to :-webkit-any/:-moz-any if needed.
17281734
// All selectors must be simple, no combinators are supported.
17291735
if !Feature::CssMatchesPseudo.is_compatible(targets)
17301736
&& selectors.iter().all(|selector| !selector.has_combinator())
17311737
{
1732-
crate::prefixes::Feature::AnyPseudo.prefixes_for(targets)
1738+
necessary_prefixes |= crate::prefixes::Feature::AnyPseudo.prefixes_for(targets)
17331739
} else {
1734-
VendorPrefix::empty()
1740+
necessary_prefixes |= VendorPrefix::empty()
17351741
}
1742+
1743+
necessary_prefixes
17361744
}
1745+
Component::Where(selectors)
1746+
| Component::Any(_, selectors)
1747+
| Component::Negation(selectors)
1748+
| Component::Has(selectors) => downlevel_selectors(&mut **selectors, targets),
17371749
_ => VendorPrefix::empty(),
17381750
}
17391751
}

0 commit comments

Comments
 (0)