diff --git a/src/selector/mod.rs b/src/selector/mod.rs index 4167064..0b0d2e7 100644 --- a/src/selector/mod.rs +++ b/src/selector/mod.rs @@ -2,12 +2,14 @@ use std::fmt::{self, Display, Write}; use peekmore::{PeekMore, PeekMoreIterator}; +use crate::common::{Brackets, ListSeparator, QuoteKind}; use crate::error::SassResult; use crate::scope::Scope; use crate::utils::{ devour_whitespace, eat_comment, eat_ident_no_interpolation, parse_interpolation, read_until_closing_paren, read_until_newline, IsWhitespace, }; +use crate::value::Value; use crate::Token; use attribute::Attribute; @@ -25,6 +27,44 @@ struct SelectorPart { pub contains_super_selector: bool, } +impl SelectorPart { + pub fn into_value(&self) -> Value { + let mut kinds = Vec::new(); + let mut this_kind = Vec::new(); + for kind in &self.inner { + match kind { + SelectorKind::Whitespace => { + if !this_kind.is_empty() { + kinds.push(SelectorPart { + inner: std::mem::take(&mut this_kind), + is_invisible: false, + has_newline: false, + contains_super_selector: false, + }); + } + } + v => this_kind.push(v.clone()), + } + } + if !this_kind.is_empty() { + kinds.push(SelectorPart { + inner: std::mem::take(&mut this_kind), + is_invisible: false, + has_newline: false, + contains_super_selector: false, + }); + } + Value::List( + kinds + .iter() + .map(|s| Value::Ident(s.to_string(), QuoteKind::None)) + .collect(), + ListSeparator::Space, + Brackets::None, + ) + } +} + impl Display for SelectorPart { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut iter = self.inner.iter().peekmore(); @@ -562,4 +602,12 @@ impl Selector { pub fn contains_super_selector(&self) -> bool { self.0.iter().any(|s| s.contains_super_selector) } + + pub fn into_value(&self) -> Value { + Value::List( + self.0.iter().map(SelectorPart::into_value).collect(), + ListSeparator::Comma, + Brackets::None, + ) + } } diff --git a/src/value/parse.rs b/src/value/parse.rs index ea66c58..a7fceff 100644 --- a/src/value/parse.rs +++ b/src/value/parse.rs @@ -670,7 +670,7 @@ impl Value { '&' => { let span = toks.next().unwrap().pos(); Ok(IntermediateValue::Value(Spanned { - node: Value::Ident(super_selector.to_string(), QuoteKind::None), + node: super_selector.into_value(), span, })) } diff --git a/tests/selectors.rs b/tests/selectors.rs index 2ee48eb..c6cd536 100644 --- a/tests/selectors.rs +++ b/tests/selectors.rs @@ -427,3 +427,83 @@ test!( ":not(%b) {x: y}", "* {\n x: y;\n}\n" ); +test!( + interpolated_super_selector_in_style, + "a {\n color: #{&};\n}\n", + "a {\n color: a;\n}\n" +); +test!( + interpolated_super_selector_in_style_symbols, + "* .a #b:foo() {\n color: #{&};\n}\n", + "* .a #b:foo() {\n color: * .a #b:foo();\n}\n" +); +test!( + uninterpolated_super_selector, + "* .a #b:foo() {\n color: &;\n}\n", + "* .a #b:foo() {\n color: * .a #b:foo();\n}\n" +); +test!( + interpolated_super_selector_in_selector_and_style, + "a {\n b #{&} {\n color: &;\n }\n}\n", + "a b a {\n color: a b a;\n}\n" +); +test!( + super_selector_treated_as_list, + "a, b {\n color: type-of(&);\n}\n", + "a, b {\n color: list;\n}\n" +); +test!( + length_of_comma_separated_super_selector, + "a, b {\n color: length(&);\n}\n", + "a, b {\n color: 2;\n}\n" +); +test!( + nth_1_of_comma_separated_super_selector, + "a, b {\n color: nth(&, 1);\n}\n", + "a, b {\n color: a;\n}\n" +); +test!( + nth_2_of_comma_separated_super_selector, + "a, b {\n color: nth(&, 2);\n}\n", + "a, b {\n color: b;\n}\n" +); +test!( + length_of_space_separated_super_selector, + "a b {\n color: length(&);\n}\n", + "a b {\n color: 1;\n}\n" +); +test!( + nth_1_of_space_separated_super_selector, + "a b {\n color: nth(&, 1);\n}\n", + "a b {\n color: a b;\n}\n" +); +test!( + length_of_comma_separated_super_selector_has_compound, + "a:foo, b {\n color: length(&);\n}\n", + "a:foo, b {\n color: 2;\n}\n" +); +test!( + nth_1_of_comma_separated_super_selector_has_compound, + "a:foo, b {\n color: nth(&, 1);\n}\n", + "a:foo, b {\n color: a:foo;\n}\n" +); +test!( + length_of_space_separated_super_selector_has_compound, + "a:foo b {\n color: length(&);\n}\n", + "a:foo b {\n color: 1;\n}\n" +); +test!( + nth_1_of_space_separated_super_selector_has_compound, + "a:foo b {\n color: nth(&, 1);\n}\n", + "a:foo b {\n color: a:foo b;\n}\n" +); +test!( + length_super_selector_placeholder, + "a, %b {\n color: length(&);\n}\n", + "a {\n color: 2;\n}\n" +); +test!( + nth_2_super_selector_placeholder, + "a, %b {\n color: nth(&, 2);\n}\n", + "a {\n color: %b;\n}\n" +); diff --git a/tests/styles.rs b/tests/styles.rs index 2bbb9c7..ee5100b 100644 --- a/tests/styles.rs +++ b/tests/styles.rs @@ -155,26 +155,6 @@ test!( styles_after_quoted, "a {\n color: \"red\";\n color: blue;\n}\n" ); -test!( - interpolated_super_selector_in_style, - "a {\n color: #{&};\n}\n", - "a {\n color: a;\n}\n" -); -test!( - interpolated_super_selector_in_style_symbols, - "* .a #b:foo() {\n color: #{&};\n}\n", - "* .a #b:foo() {\n color: * .a #b:foo();\n}\n" -); -test!( - uninterpolated_super_selector, - "* .a #b:foo() {\n color: &;\n}\n", - "* .a #b:foo() {\n color: * .a #b:foo();\n}\n" -); -test!( - interpolated_super_selector_in_selector_and_style, - "a {\n b #{&} {\n color: &;\n }\n}\n", - "a b a {\n color: a b a;\n}\n" -); test!( emits_leading_whitespace, "a {\n color: unquote(\" foo\");\n}\n",