resolve @extend
issues related to attrbitute equality
This commit is contained in:
parent
6fec0835f8
commit
4610a30024
@ -1,4 +1,7 @@
|
||||
use std::fmt::{self, Display, Write};
|
||||
use std::{
|
||||
fmt::{self, Display, Write},
|
||||
hash::{Hash, Hasher},
|
||||
};
|
||||
|
||||
use codemap::Span;
|
||||
|
||||
@ -6,7 +9,7 @@ use crate::{common::QuoteKind, error::SassResult, parse::Parser, utils::is_ident
|
||||
|
||||
use super::{Namespace, QualifiedName};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct Attribute {
|
||||
attr: QualifiedName,
|
||||
value: String,
|
||||
@ -15,6 +18,26 @@ pub(crate) struct Attribute {
|
||||
span: Span,
|
||||
}
|
||||
|
||||
impl PartialEq for Attribute {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.attr == other.attr
|
||||
&& self.value == other.value
|
||||
&& self.modifier == other.modifier
|
||||
&& self.op == other.op
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Attribute {}
|
||||
|
||||
impl Hash for Attribute {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.attr.hash(state);
|
||||
self.value.hash(state);
|
||||
self.modifier.hash(state);
|
||||
self.op.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
fn attribute_name(parser: &mut Parser<'_>, start: Span) -> SassResult<QualifiedName> {
|
||||
let next = parser.toks.peek().ok_or(("Expected identifier.", start))?;
|
||||
if next.kind == '*' {
|
||||
|
@ -206,25 +206,33 @@ impl Extender {
|
||||
) -> SelectorList {
|
||||
// This could be written more simply using Vec<Vec<T>>, but we want to avoid
|
||||
// any allocations in the common case where no extends apply.
|
||||
let mut extended: Vec<ComplexSelector> = Vec::new();
|
||||
let mut extended: Option<Vec<ComplexSelector>> = None;
|
||||
for i in 0..list.components.len() {
|
||||
let complex = list.components.get(i).unwrap().clone();
|
||||
|
||||
if let Some(result) =
|
||||
self.extend_complex(complex.clone(), extensions, media_query_context)
|
||||
{
|
||||
if extended.is_empty() && i != 0 {
|
||||
extended = list.components[0..i].to_vec();
|
||||
if extended.is_none() {
|
||||
extended = Some(if i == 0 {
|
||||
Vec::new()
|
||||
} else {
|
||||
list.components[0..i].to_vec()
|
||||
});
|
||||
}
|
||||
extended.extend(result.into_iter());
|
||||
} else if !extended.is_empty() {
|
||||
match extended.as_mut() {
|
||||
Some(v) => v.extend(result.into_iter()),
|
||||
None => unreachable!(),
|
||||
}
|
||||
} else if let Some(extended) = extended.as_mut() {
|
||||
extended.push(complex);
|
||||
}
|
||||
}
|
||||
|
||||
if extended.is_empty() {
|
||||
return list;
|
||||
}
|
||||
let extended = match extended {
|
||||
Some(v) => v,
|
||||
None => return list,
|
||||
};
|
||||
|
||||
SelectorList {
|
||||
components: self.trim(extended, |complex| self.originals.contains(complex)),
|
||||
@ -257,7 +265,7 @@ impl Extender {
|
||||
//
|
||||
// This could be written more simply using `Vec::into_iter::map`, but we want to avoid
|
||||
// any allocations in the common case where no extends apply.
|
||||
let mut extended_not_expanded: Vec<Vec<ComplexSelector>> = Vec::new();
|
||||
let mut extended_not_expanded: Option<Vec<Vec<ComplexSelector>>> = None;
|
||||
|
||||
let complex_has_line_break = complex.line_break;
|
||||
|
||||
@ -266,8 +274,9 @@ impl Extender {
|
||||
if let Some(extended) =
|
||||
self.extend_compound(component, extensions, media_query_context)
|
||||
{
|
||||
if extended_not_expanded.is_empty() {
|
||||
extended_not_expanded = complex
|
||||
if extended_not_expanded.is_none() {
|
||||
extended_not_expanded = Some(
|
||||
complex
|
||||
.components
|
||||
.clone()
|
||||
.into_iter()
|
||||
@ -278,28 +287,36 @@ impl Extender {
|
||||
line_break: complex.line_break,
|
||||
}]
|
||||
})
|
||||
.collect();
|
||||
.collect(),
|
||||
);
|
||||
}
|
||||
match extended_not_expanded.as_mut() {
|
||||
Some(v) => v.push(extended),
|
||||
None => unreachable!(),
|
||||
}
|
||||
extended_not_expanded.push(extended);
|
||||
} else {
|
||||
extended_not_expanded.push(vec![ComplexSelector {
|
||||
match extended_not_expanded.as_mut() {
|
||||
Some(v) => v.push(vec![ComplexSelector {
|
||||
components: vec![ComplexSelectorComponent::Compound(component.clone())],
|
||||
line_break: false,
|
||||
}])
|
||||
}]),
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
} else if let Some(component @ ComplexSelectorComponent::Combinator(..)) =
|
||||
complex.components.get(i)
|
||||
{
|
||||
extended_not_expanded.push(vec![ComplexSelector {
|
||||
match extended_not_expanded.as_mut() {
|
||||
Some(v) => v.push(vec![ComplexSelector {
|
||||
components: vec![component.clone()],
|
||||
line_break: false,
|
||||
}])
|
||||
}]),
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if extended_not_expanded.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let extended_not_expanded = extended_not_expanded?;
|
||||
|
||||
let mut first = true;
|
||||
|
||||
@ -354,7 +371,7 @@ impl Extender {
|
||||
// which targets are actually extended.
|
||||
let mut targets_used: HashSet<SimpleSelector> = HashSet::new();
|
||||
|
||||
let mut options: Vec<Vec<Extension>> = Vec::new();
|
||||
let mut options: Option<Vec<Vec<Extension>>> = None;
|
||||
|
||||
for i in 0..compound.components.len() {
|
||||
let simple = compound.components.get(i).cloned().unwrap();
|
||||
@ -365,21 +382,29 @@ impl Extender {
|
||||
media_query_context,
|
||||
&mut targets_used,
|
||||
) {
|
||||
if options.is_empty() && i != 0 {
|
||||
options.push(vec![self.extension_for_compound(
|
||||
if options.is_none() {
|
||||
let mut new_options = Vec::new();
|
||||
if i != 0 {
|
||||
new_options.push(vec![self.extension_for_compound(
|
||||
compound.components.clone().into_iter().take(i).collect(),
|
||||
)]);
|
||||
}
|
||||
options.replace(new_options);
|
||||
}
|
||||
|
||||
options.extend(extended.into_iter());
|
||||
match options.as_mut() {
|
||||
Some(v) => v.extend(extended.into_iter()),
|
||||
None => unreachable!(),
|
||||
}
|
||||
} else {
|
||||
options.push(vec![self.extension_for_simple(simple)]);
|
||||
match options.as_mut() {
|
||||
Some(v) => v.push(vec![self.extension_for_simple(simple)]),
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if options.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let options = options?;
|
||||
|
||||
// If `self.mode` isn't `ExtendMode::Normal` and we didn't use all the targets in
|
||||
// `extensions`, extension fails for `compound`.
|
||||
|
@ -486,7 +486,6 @@ test!(
|
||||
"-a [foo=bar].baz, -a [foo=bar][ns|foo=bar] {\n a: b;\n}\n"
|
||||
);
|
||||
test!(
|
||||
#[ignore = "to investigate (too many selectors)"]
|
||||
attribute_unification_5,
|
||||
"%-a %-a [foo=bar].bar {a: b}
|
||||
[foo=bar] {@extend .bar} -a {@extend %-a}
|
||||
@ -644,7 +643,6 @@ test!(
|
||||
"-a :not(.foo) {\n a: b;\n}\n"
|
||||
);
|
||||
test!(
|
||||
#[ignore = "to investigate (too many selectors)"]
|
||||
negation_unification_3,
|
||||
"%-a :not([a=b]).baz {a: b}
|
||||
:not([a = b]) {@extend .baz} -a {@extend %-a}
|
||||
|
Loading…
x
Reference in New Issue
Block a user