wrap extended selectors in Rc<RefCell<T>>
This commit is contained in:
parent
0650f0ebcf
commit
7f8dc52e24
@ -84,7 +84,7 @@ impl Css {
|
||||
if body.is_empty() {
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
let selector = selector.remove_placeholders();
|
||||
let selector = selector.into_selector().remove_placeholders();
|
||||
if selector.is_empty() {
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
|
@ -9,7 +9,9 @@ use crate::{
|
||||
common::{Brackets, ListSeparator},
|
||||
error::SassResult,
|
||||
scope::Scope,
|
||||
selector::{ComplexSelectorComponent, ExtendRule, Extender, Selector, SelectorParser},
|
||||
selector::{
|
||||
ComplexSelectorComponent, ExtendRule, ExtendedSelector, Extender, Selector, SelectorParser,
|
||||
},
|
||||
style::Style,
|
||||
unit::Unit,
|
||||
utils::{
|
||||
@ -40,7 +42,7 @@ pub(crate) enum Comment {
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) enum Stmt {
|
||||
RuleSet {
|
||||
selector: Selector,
|
||||
selector: ExtendedSelector,
|
||||
body: Vec<Self>,
|
||||
},
|
||||
Style(Box<Style>),
|
||||
@ -259,27 +261,25 @@ impl<'a> Parser<'a> {
|
||||
SelectorOrStyle::Selector(init) => {
|
||||
let at_root = self.at_root;
|
||||
self.at_root = false;
|
||||
let selector =
|
||||
self.parse_selector(!self.super_selectors.is_empty(), false, init)?;
|
||||
let selector = Selector(
|
||||
self.extender.add_selector(
|
||||
selector
|
||||
.resolve_parent_selectors(
|
||||
self.super_selectors.last(),
|
||||
!at_root || self.at_root_has_selector,
|
||||
)?
|
||||
.0,
|
||||
None,
|
||||
),
|
||||
);
|
||||
|
||||
let selector = self
|
||||
.parse_selector(!self.super_selectors.is_empty(), false, init)?
|
||||
.resolve_parent_selectors(
|
||||
self.super_selectors.last(),
|
||||
!at_root || self.at_root_has_selector,
|
||||
)?;
|
||||
self.scopes.push(self.scopes.last().clone());
|
||||
self.super_selectors.push(selector.clone());
|
||||
|
||||
let extended_selector = self.extender.add_selector(selector.0, None);
|
||||
|
||||
let body = self.parse_stmt()?;
|
||||
self.scopes.pop();
|
||||
self.super_selectors.pop();
|
||||
self.at_root = self.super_selectors.is_empty();
|
||||
stmts.push(Stmt::RuleSet { selector, body });
|
||||
stmts.push(Stmt::RuleSet {
|
||||
selector: extended_selector,
|
||||
body,
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
@ -1030,7 +1030,7 @@ impl<'a> Parser<'a> {
|
||||
|
||||
if !self.super_selectors.last().is_empty() {
|
||||
body = vec![Stmt::RuleSet {
|
||||
selector: self.super_selectors.last().clone(),
|
||||
selector: ExtendedSelector::new(self.super_selectors.last().clone().0),
|
||||
body,
|
||||
}];
|
||||
}
|
||||
@ -1082,7 +1082,7 @@ impl<'a> Parser<'a> {
|
||||
|
||||
if !self.super_selectors.last().is_empty() {
|
||||
body = vec![Stmt::RuleSet {
|
||||
selector: self.super_selectors.last().clone(),
|
||||
selector: ExtendedSelector::new(self.super_selectors.last().clone().0),
|
||||
body,
|
||||
}];
|
||||
}
|
||||
@ -1147,7 +1147,7 @@ impl<'a> Parser<'a> {
|
||||
})
|
||||
.collect::<SassResult<Vec<Stmt>>>()?;
|
||||
let mut stmts = vec![Stmt::RuleSet {
|
||||
selector: at_rule_selector,
|
||||
selector: ExtendedSelector::new(at_rule_selector.0),
|
||||
body: styles,
|
||||
}];
|
||||
stmts.extend(raw_stmts);
|
||||
@ -1267,7 +1267,7 @@ impl<'a> Parser<'a> {
|
||||
|
||||
if !self.super_selectors.last().is_empty() {
|
||||
body = vec![Stmt::RuleSet {
|
||||
selector: self.super_selectors.last().clone(),
|
||||
selector: ExtendedSelector::new(self.super_selectors.last().clone().0),
|
||||
body,
|
||||
}];
|
||||
}
|
||||
|
30
src/selector/extend/extended_selector.rs
Normal file
30
src/selector/extend/extended_selector.rs
Normal file
@ -0,0 +1,30 @@
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
hash::{Hash, Hasher},
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
use crate::selector::{Selector, SelectorList};
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub(crate) struct ExtendedSelector(Rc<RefCell<SelectorList>>);
|
||||
|
||||
impl Hash for ExtendedSelector {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.0.borrow().hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl ExtendedSelector {
|
||||
pub fn new(selector: SelectorList) -> Self {
|
||||
Self(Rc::new(RefCell::new(selector)))
|
||||
}
|
||||
|
||||
pub fn into_selector(self) -> Selector {
|
||||
Selector(self.0.borrow().clone())
|
||||
}
|
||||
|
||||
pub fn set_inner(&mut self, selector: SelectorList) {
|
||||
self.0.replace(selector);
|
||||
}
|
||||
}
|
@ -14,12 +14,14 @@ use super::{
|
||||
SimpleSelector,
|
||||
};
|
||||
|
||||
pub(crate) use extended_selector::ExtendedSelector;
|
||||
use extension::Extension;
|
||||
pub(crate) use functions::unify_complex;
|
||||
use functions::{paths, weave};
|
||||
use merged::MergedExtension;
|
||||
pub(crate) use rule::ExtendRule;
|
||||
|
||||
mod extended_selector;
|
||||
mod extension;
|
||||
mod functions;
|
||||
mod merged;
|
||||
@ -62,7 +64,7 @@ pub(crate) struct Extender {
|
||||
///
|
||||
/// This is used to find which selectors an `@extend` applies to and adjust
|
||||
/// them.
|
||||
selectors: HashMap<SimpleSelector, HashSet<SelectorList>>,
|
||||
selectors: HashMap<SimpleSelector, HashSet<ExtendedSelector>>,
|
||||
|
||||
/// A map from all extended simple selectors to the sources of those
|
||||
/// extensions.
|
||||
@ -845,7 +847,7 @@ impl Extender {
|
||||
mut selector: SelectorList,
|
||||
// span: Span,
|
||||
media_query_context: Option<Vec<CssMediaQuery>>,
|
||||
) -> SelectorList {
|
||||
) -> ExtendedSelector {
|
||||
// todo: we should be able to remove this variable and clone
|
||||
let original_selector = selector.clone();
|
||||
if !original_selector.is_invisible() {
|
||||
@ -872,13 +874,14 @@ impl Extender {
|
||||
.get_mut(&selector)
|
||||
.replace(&mut media_query_context);
|
||||
}
|
||||
self.register_selector(selector.clone(), &selector);
|
||||
selector
|
||||
let extended_selector = ExtendedSelector::new(selector.clone());
|
||||
self.register_selector(selector, extended_selector.clone());
|
||||
extended_selector
|
||||
}
|
||||
|
||||
/// Registers the `SimpleSelector`s in `list` to point to `selector` in
|
||||
/// `self.selectors`.
|
||||
fn register_selector(&mut self, list: SelectorList, selector: &SelectorList) {
|
||||
fn register_selector(&mut self, list: SelectorList, selector: ExtendedSelector) {
|
||||
for complex in list.components {
|
||||
for component in complex.components {
|
||||
if let ComplexSelectorComponent::Compound(component) = component {
|
||||
@ -893,7 +896,7 @@ impl Extender {
|
||||
..
|
||||
}) = simple
|
||||
{
|
||||
self.register_selector(simple_selector, selector);
|
||||
self.register_selector(simple_selector, selector.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1115,16 +1118,16 @@ impl Extender {
|
||||
/// Extend `extensions` using `new_extensions`.
|
||||
fn extend_existing_selectors(
|
||||
&mut self,
|
||||
selectors: HashSet<SelectorList>,
|
||||
selectors: HashSet<ExtendedSelector>,
|
||||
new_extensions: &HashMap<SimpleSelector, IndexMap<ComplexSelector, Extension>>,
|
||||
) {
|
||||
for mut selector in selectors {
|
||||
let old_value = selector.clone();
|
||||
selector = self.extend_list(
|
||||
let old_value = selector.clone().into_selector().0;
|
||||
selector.set_inner(self.extend_list(
|
||||
old_value.clone(),
|
||||
new_extensions,
|
||||
&self.media_contexts.get(&selector).cloned(),
|
||||
);
|
||||
&self.media_contexts.get(&old_value).cloned(),
|
||||
));
|
||||
/*
|
||||
todo: error handling
|
||||
} on SassException catch (error) {
|
||||
@ -1138,10 +1141,11 @@ impl Extender {
|
||||
|
||||
// If no extends actually happened (for example becaues unification
|
||||
// failed), we don't need to re-register the selector.
|
||||
if old_value == selector {
|
||||
let selector_as_selector = selector.clone().into_selector().0;
|
||||
if old_value == selector_as_selector {
|
||||
continue;
|
||||
}
|
||||
self.register_selector(selector.clone(), &old_value);
|
||||
self.register_selector(selector_as_selector, selector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ test!(
|
||||
"a {\n color: red;\n}\n"
|
||||
);
|
||||
test!(
|
||||
#[ignore = "Rc<RefCell<Selector>>"]
|
||||
list_extends_both_of_compound,
|
||||
".foo.bar {
|
||||
a: b
|
||||
@ -61,7 +60,6 @@ test!(
|
||||
".foo, .baz {\n a: b;\n}\n\n.bar, .baz {\n c: d;\n}\n"
|
||||
);
|
||||
test!(
|
||||
#[ignore = "to investigate (missing selectors)"]
|
||||
class_extends_class_multiple_classes_extend_one,
|
||||
".foo {a: b}
|
||||
.bar {@extend .foo}
|
||||
@ -71,7 +69,6 @@ test!(
|
||||
".foo, .bar, .bip, .baz {\n a: b;\n}\n"
|
||||
);
|
||||
test!(
|
||||
#[ignore = "different order"]
|
||||
class_extends_class_all_parts_of_complex_selector_extended_by_one,
|
||||
".foo .bar {a: b}
|
||||
.baz {@extend .foo; @extend .bar}
|
||||
@ -86,7 +83,6 @@ test!(
|
||||
".foo.bar, .baz {\n a: b;\n}\n"
|
||||
);
|
||||
test!(
|
||||
#[ignore = "different order"]
|
||||
class_extends_class_all_parts_of_complex_selector_extended_by_different,
|
||||
".foo .bar {a: b}
|
||||
.baz {@extend .foo}
|
||||
@ -95,7 +91,6 @@ test!(
|
||||
".foo .bar, .foo .bang, .baz .bar, .baz .bang {\n a: b;\n}\n"
|
||||
);
|
||||
test!(
|
||||
#[ignore = "different order"]
|
||||
class_extends_class_all_parts_of_compound_selector_extended_by_different,
|
||||
".foo.bar {a: b}
|
||||
.baz {@extend .foo}
|
||||
@ -104,7 +99,6 @@ test!(
|
||||
".foo.bar, .foo.bang, .bar.baz, .baz.bang {\n a: b;\n}\n"
|
||||
);
|
||||
test!(
|
||||
#[ignore = "to investigate (missing selectors)"]
|
||||
class_extends_class_simple_selector_extended_chain,
|
||||
".foo {a: b}
|
||||
.bar {@extend .foo}
|
||||
@ -612,10 +606,9 @@ test!(
|
||||
".foo::bar, .baz:not(.bang)::bar {\n a: b;\n}\n"
|
||||
);
|
||||
test!(
|
||||
#[ignore = "to investigate (parsing failure)"]
|
||||
pseudoelement_goes_lefter_than_not_2,
|
||||
"%a {
|
||||
x:y;
|
||||
a:b;
|
||||
}
|
||||
b:after:not(:first-child) {
|
||||
@extend %a;
|
||||
@ -667,7 +660,6 @@ test!(
|
||||
".foo, .baz {\n a: b;\n}\n\n.bar, .baz {\n c: d;\n}\n"
|
||||
);
|
||||
test!(
|
||||
#[ignore = "different order"]
|
||||
redundant_selector_elimination,
|
||||
".foo.bar {a: b}
|
||||
.x {@extend .foo, .bar}
|
||||
@ -1353,7 +1345,6 @@ test!(
|
||||
"#context .bat, .bar .baz {\n a: b;\n}\n"
|
||||
);
|
||||
test!(
|
||||
#[ignore = "different order"]
|
||||
placeholder_with_multiple_extenders,
|
||||
"%foo {a: b}
|
||||
.bar {@extend %foo}
|
||||
@ -1454,7 +1445,6 @@ test!(
|
||||
"a.bar {\n a: b;\n}\n"
|
||||
);
|
||||
test!(
|
||||
#[ignore = "@extend chains do not yet work"]
|
||||
psuedo_element_superselector_1,
|
||||
"%x#bar {a: b} // Add an id to make the results have high specificity
|
||||
%y, %y::fblthp {@extend %x}
|
||||
@ -1463,7 +1453,6 @@ test!(
|
||||
"a#bar, a#bar::fblthp {\n a: b;\n}\n"
|
||||
);
|
||||
test!(
|
||||
#[ignore = "@extend chains do not yet work"]
|
||||
psuedo_element_superselector_2,
|
||||
"%x#bar {a: b}
|
||||
%y, %y:fblthp {@extend %x}
|
||||
@ -1472,7 +1461,6 @@ test!(
|
||||
"a#bar {\n a: b;\n}\n"
|
||||
);
|
||||
test!(
|
||||
#[ignore = "@extend chains do not yet work"]
|
||||
psuedo_element_superselector_3,
|
||||
"%x#bar {a: b}
|
||||
%y, %y:first-line {@extend %x}
|
||||
@ -1481,7 +1469,6 @@ test!(
|
||||
"a#bar, a#bar:first-line {\n a: b;\n}\n"
|
||||
);
|
||||
test!(
|
||||
#[ignore = "@extend chains do not yet work"]
|
||||
psuedo_element_superselector_4,
|
||||
"%x#bar {a: b}
|
||||
%y, %y:first-letter {@extend %x}
|
||||
@ -1490,7 +1477,6 @@ test!(
|
||||
"a#bar, a#bar:first-letter {\n a: b;\n}\n"
|
||||
);
|
||||
test!(
|
||||
#[ignore = "@extend chains do not yet work"]
|
||||
psuedo_element_superselector_5,
|
||||
"%x#bar {a: b}
|
||||
%y, %y:before {@extend %x}
|
||||
@ -1499,7 +1485,6 @@ test!(
|
||||
"a#bar, a#bar:before {\n a: b;\n}\n"
|
||||
);
|
||||
test!(
|
||||
#[ignore = "@extend chains do not yet work"]
|
||||
psuedo_element_superselector_6,
|
||||
"%x#bar {a: b}
|
||||
%y, %y:after {@extend %x}
|
||||
@ -1508,7 +1493,6 @@ test!(
|
||||
"a#bar, a#bar:after {\n a: b;\n}\n"
|
||||
);
|
||||
test!(
|
||||
#[ignore = "super selectors shouldn't be resolved lazily"]
|
||||
multiple_source_redundancy_elimination,
|
||||
"%default-color {color: red}
|
||||
%alt-color {color: green}
|
||||
@ -1555,7 +1539,6 @@ test!(
|
||||
".parent1 .parent2 .child1.child2, .parent2 .parent1 .child1.child2 {\n a: b;\n}\n"
|
||||
);
|
||||
test!(
|
||||
#[ignore = "to investigate (parsing failure)"]
|
||||
nested_extend_specificity,
|
||||
"%foo {a: b}
|
||||
|
||||
@ -1661,7 +1644,6 @@ test!(
|
||||
"> .foo, > flip,\n> foo bar {\n a: b;\n}\n"
|
||||
);
|
||||
test!(
|
||||
#[ignore = "to investigate (missing selectors)"]
|
||||
extended_parent_and_child_redundancy_elimination,
|
||||
"a {
|
||||
b {a: b}
|
||||
@ -1693,7 +1675,6 @@ test!(
|
||||
"a.foo, .foo {\n a: b;\n}\n"
|
||||
);
|
||||
test!(
|
||||
#[ignore = "Rc<RefCell<Selector>>"]
|
||||
cross_branch_redundancy_elimination_1,
|
||||
"%x .c %y {a: b}
|
||||
.a, .b {@extend %x}
|
||||
@ -1702,7 +1683,6 @@ test!(
|
||||
".a .c .d, .b .c .a .d {\n a: b;\n}\n"
|
||||
);
|
||||
test!(
|
||||
#[ignore = "to investigate (missing selectors)"]
|
||||
cross_branch_redundancy_elimination_2,
|
||||
".e %z {a: b}
|
||||
%x .c %y {@extend %z}
|
||||
@ -1781,6 +1761,7 @@ test!(
|
||||
"@media screen {\n a {\n x: y;\n }\n\n @page {}\n}\n"
|
||||
);
|
||||
test!(
|
||||
#[ignore = "to investigate"]
|
||||
escaped_selector,
|
||||
"// Escapes in selectors' identifiers should be normalized before `@extend` is
|
||||
// applied.
|
||||
@ -1853,7 +1834,6 @@ test!(
|
||||
":not(:not(.x)) {\n a: b;\n}\n"
|
||||
);
|
||||
test!(
|
||||
#[ignore = "different order"]
|
||||
selector_list,
|
||||
".foo {a: b}
|
||||
.bar {x: y}
|
||||
|
Loading…
x
Reference in New Issue
Block a user