diff --git a/src/output.rs b/src/output.rs index bde2e71..835b2aa 100644 --- a/src/output.rs +++ b/src/output.rs @@ -80,6 +80,17 @@ impl Toplevel { } } +fn set_group_end(group: &mut [Toplevel]) { + match group.last_mut() { + Some(Toplevel::RuleSet { is_group_end, .. }) + | Some(Toplevel::Supports { is_group_end, .. }) + | Some(Toplevel::Media { is_group_end, .. }) => { + *is_group_end = true; + } + _ => {} + } +} + #[derive(Debug, Clone)] enum BlockEntry { Style(Style), @@ -206,7 +217,11 @@ impl Css { Stmt::Return(..) => unreachable!(), Stmt::AtRoot { body } => { body.into_iter().try_for_each(|r| -> SassResult<()> { - vals.append(&mut self.parse_stmt(r)?); + let mut stmts = self.parse_stmt(r)?; + + set_group_end(&mut stmts); + + vals.append(&mut stmts); Ok(()) })?; } @@ -285,14 +300,7 @@ impl Css { for stmt in stmts { let mut v = self.parse_stmt(stmt)?; - match v.last_mut() { - Some(Toplevel::RuleSet { is_group_end, .. }) - | Some(Toplevel::Supports { is_group_end, .. }) - | Some(Toplevel::Media { is_group_end, .. }) => { - *is_group_end = true; - } - _ => {} - } + set_group_end(&mut v); self.blocks.extend(v); } diff --git a/src/parse/mod.rs b/src/parse/mod.rs index 7afc24d..f6d69d8 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -184,9 +184,8 @@ impl<'a> Parser<'a> { if self.at_root { stmts.append(&mut self.parse_at_root()?); } else { - stmts.push(Stmt::AtRoot { - body: self.parse_at_root()?, - }); + let body = self.parse_at_root()?; + stmts.push(Stmt::AtRoot { body }); } } AtRuleKind::Error => { @@ -780,11 +779,27 @@ impl<'a> Parser<'a> { _ => Some(Ok(s)), }) .collect::>>()?; - let mut stmts = vec![Stmt::RuleSet { - selector: at_rule_selector, - body: styles, - }]; - stmts.extend(raw_stmts); + + let stmts = if at_root_has_selector { + let mut body = styles; + body.extend(raw_stmts); + + vec![Stmt::RuleSet { + body, + selector: at_rule_selector, + }] + } else { + if !styles.is_empty() { + return Err(( + "Found style at the toplevel inside @at-root.", + self.span_before, + ) + .into()); + } + + raw_stmts + }; + Ok(stmts) } diff --git a/tests/at-root.rs b/tests/at-root.rs index 4e6ae39..ef3605b 100644 --- a/tests/at-root.rs +++ b/tests/at-root.rs @@ -66,8 +66,53 @@ test!( "a {}\n\n@at-root {\n @-ms-viewport { width: device-width; }\n}\n", "@-ms-viewport {\n width: device-width;\n}\n" ); +test!( + newline_between_style_rules_with_same_parent_but_first_is_in_at_root, + "a { + @at-root { + b { + color: red; + } + } + + b { + color: red; + } + }", + "b {\n color: red;\n}\n\na b {\n color: red;\n}\n" +); +test!( + no_newline_between_style_rules_when_there_exists_a_selector, + "@at-root a { + a { + color: red; + } + + a { + color: red; + } + }", + "a a {\n color: red;\n}\na a {\n color: red;\n}\n" +); +test!( + newline_between_style_rules_when_there_does_not_exist_a_selector, + "@at-root { + a { + color: red; + } + + a { + color: red; + } + }", + "a {\n color: red;\n}\n\na {\n color: red;\n}\n" +); error!( #[ignore = "we do not currently validate missing closing curly braces"] missing_closing_curly_brace, "@at-root {", "Error: expected \"}\"." ); +error!( + style_at_toplevel_without_selector, + "@at-root { color: red; }", "Error: Found style at the toplevel inside @at-root." +);