interpolated ampersand in at-root

This commit is contained in:
ConnorSkees 2020-04-06 14:30:36 -04:00
parent 8802a92f9b
commit 26fdcfdf17
3 changed files with 93 additions and 26 deletions

View File

@ -15,7 +15,7 @@ pub(crate) use function::Function;
pub(crate) use if_rule::If; pub(crate) use if_rule::If;
pub(crate) use kind::AtRuleKind; pub(crate) use kind::AtRuleKind;
pub(crate) use mixin::{eat_include, Mixin}; pub(crate) use mixin::{eat_include, Mixin};
use parse::eat_stmts; use parse::{eat_stmts, eat_stmts_at_root};
use unknown::UnknownAtRule; use unknown::UnknownAtRule;
mod for_rule; mod for_rule;
@ -105,7 +105,7 @@ impl AtRule {
AtRuleKind::Use => todo!("@use not yet implemented"), AtRuleKind::Use => todo!("@use not yet implemented"),
AtRuleKind::Annotation => todo!("@annotation not yet implemented"), AtRuleKind::Annotation => todo!("@annotation not yet implemented"),
AtRuleKind::AtRoot => { AtRuleKind::AtRoot => {
let selector = &Selector::replace( let mut selector = &Selector::replace(
super_selector.clone(), super_selector.clone(),
Selector::from_tokens( Selector::from_tokens(
&mut read_until_open_curly_brace(toks).into_iter().peekable(), &mut read_until_open_curly_brace(toks).into_iter().peekable(),
@ -113,36 +113,33 @@ impl AtRule {
super_selector, super_selector,
)?, )?,
); );
let mut is_some = true;
if selector.is_empty() {
is_some = false;
selector = super_selector;
}
toks.next(); toks.next();
devour_whitespace(toks); devour_whitespace(toks);
let mut body = read_until_closing_curly_brace(toks); let mut body = read_until_closing_curly_brace(toks);
body.push(toks.next().unwrap()); body.push(toks.next().unwrap());
devour_whitespace(toks); devour_whitespace(toks);
let mut styles = Vec::new(); let mut styles = Vec::new();
let raw_stmts = eat_stmts(&mut body.into_iter().peekable(), scope, &selector)? let raw_stmts = eat_stmts_at_root(
.into_iter() &mut body.into_iter().peekable(),
.filter_map(|s| match s { scope,
Stmt::Style(..) => { &selector,
styles.push(s); 0,
None is_some,
} )?
Stmt::RuleSet(RuleSet { .into_iter()
selector: mut selector2, .filter_map(|s| match s {
rules, Stmt::Style(..) => {
super_selector: super_selector2, styles.push(s);
}) => { None
if selector.is_empty() { }
selector2 = Selector::replace(super_selector.clone(), selector2); _ => Some(s),
} })
Some(Stmt::RuleSet(RuleSet { .collect::<Vec<Stmt>>();
selector: selector2,
rules,
super_selector: super_selector2,
}))
}
_ => Some(s),
})
.collect::<Vec<Stmt>>();
let mut stmts = vec![Stmt::RuleSet(RuleSet { let mut stmts = vec![Stmt::RuleSet(RuleSet {
selector: selector.clone(), selector: selector.clone(),
rules: styles, rules: styles,

View File

@ -36,3 +36,48 @@ pub(crate) fn eat_stmts<I: Iterator<Item = Token>>(
} }
Ok(stmts) Ok(stmts)
} }
pub(crate) fn eat_stmts_at_root<I: Iterator<Item = Token>>(
toks: &mut Peekable<I>,
scope: &mut Scope,
super_selector: &Selector,
mut nesting: usize,
is_some: bool,
) -> SassResult<Vec<Stmt>> {
let mut stmts = Vec::new();
while let Some(expr) = eat_expr(toks, scope, super_selector)? {
match expr {
Expr::AtRule(a) => stmts.push(Stmt::AtRule(a)),
Expr::Style(s) => stmts.push(Stmt::Style(s)),
Expr::Styles(s) => stmts.extend(s.into_iter().map(Box::new).map(Stmt::Style)),
Expr::Include(s) => stmts.extend(s),
Expr::MixinDecl(..) | Expr::FunctionDecl(..) | Expr::Debug(..) | Expr::Warn(..) => {
todo!()
}
Expr::Selector(mut selector) => {
if nesting > 1 || is_some {
selector = super_selector.zip(&selector);
} else {
selector = Selector::replace(super_selector.clone(), selector);
}
nesting += 1;
let rules = eat_stmts_at_root(toks, scope, &selector, nesting, true)?;
nesting -= 1;
stmts.push(Stmt::RuleSet(RuleSet {
super_selector: if nesting > 1 {
super_selector.clone()
} else {
Selector::new()
},
selector,
rules,
}));
}
Expr::VariableDecl(name, val) => {
scope.insert_var(&name, *val)?;
}
Expr::MultilineComment(s) => stmts.push(Stmt::MultilineComment(s)),
}
}
Ok(stmts)
}

View File

@ -38,3 +38,28 @@ test!(
"foo {\n @at-root {\n & {\n color: bar;\n }\n }\n}\n", "foo {\n @at-root {\n & {\n color: bar;\n }\n }\n}\n",
"foo {\n color: bar;\n}\n" "foo {\n color: bar;\n}\n"
); );
test!(
interpolated_super_selector_with_nothing,
"test {\n @at-root {\n #{&}post {\n foo {\n bar: baz;\n }\n }\n }\n}\n",
"testpost foo {\n bar: baz;\n}\n"
);
test!(
with_ampersand_single,
"test {\n @at-root {\n #{&}post {\n foo {\n bar: baz;\n }\n }\n }\n}\n",
"testpost foo {\n bar: baz;\n}\n"
);
test!(
root_interpolated_ampersand,
"@at-root {\n #{&}post {\n foo {\n bar: baz;\n }\n }\n}\n",
"post foo {\n bar: baz;\n}\n"
);
test!(
nested_prefix_interpolated_ampersand,
"test {\n @at-root {\n pre#{&} {\n foo {\n bar: baz;\n }\n }\n }\n}\n",
"pretest foo {\n bar: baz;\n}\n"
);
test!(
nested_alone_interpolated_ampersand,
"test {\n @at-root {\n #{&} {\n foo {\n bar: baz;\n }\n }\n }\n}\n",
"test foo {\n bar: baz;\n}\n"
);