resolve merge conflicts with master

This commit is contained in:
Connor Skees 2020-07-31 17:37:00 -04:00
commit 123ed80e9a
4 changed files with 148 additions and 25 deletions

View File

@ -26,6 +26,19 @@ impl Mixin {
#[derive(Debug, Clone)]
pub(crate) struct Content {
/// The literal block, serialized as a list of tokens
pub content: Option<Vec<Token>>,
/// Optional args, e.g. `@content(a, b, c);`
pub content_args: Option<FuncArgs>,
/// The number of scopes at the use of `@include`
///
/// This is used to "reset" back to the state of the `@include`
/// without actually cloning the scope or putting it in an `Rc`
pub scope_len: usize,
/// Whether or not the mixin this `@content` block is inside of was
/// declared in the global scope
pub declared_at_root: bool,
}

View File

@ -8,6 +8,7 @@ use crate::{
args::{CallArgs, FuncArgs},
atrule::{Content, Mixin},
error::SassResult,
scope::Scopes,
utils::read_until_closing_curly_brace,
Token,
};
@ -129,6 +130,8 @@ impl<'a> Parser<'a> {
let scope = self.eval_args(fn_args, args)?;
let scope_len = self.scopes.len();
if declared_at_root {
mem::swap(self.scopes, self.content_scopes);
}
@ -138,6 +141,8 @@ impl<'a> Parser<'a> {
self.content.push(Content {
content,
content_args,
scope_len,
declared_at_root,
});
let body = Parser {
@ -178,26 +183,35 @@ impl<'a> Parser<'a> {
.into());
}
Ok(if let Some(content) = self.content.pop() {
let (mut scope_at_decl, mixin_scope) = if content.declared_at_root {
(mem::take(self.content_scopes), Scopes::new())
} else {
mem::take(self.scopes).split_off(content.scope_len)
};
let mut entered_scope = false;
if let Some(Token { kind: '(', .. }) = self.toks.peek() {
self.toks.next();
let args = self.parse_call_args()?;
if let Some(Some(content_args)) = self.content.last().map(|v| v.content_args.clone()) {
if let Some(ref content_args) = content.content_args {
args.max_args(content_args.len())?;
let scope = self.eval_args(content_args, args)?;
self.content_scopes.merge(scope);
let scope = self.eval_args(content_args.clone(), args)?;
scope_at_decl.enter_scope(scope);
entered_scope = true;
} else {
args.max_args(0)?;
}
}
Ok(if let Some(content) = &self.content.pop() {
let stmts = if let Some(body) = content.content.clone() {
Parser {
toks: &mut body.into_iter().peekmore(),
map: self.map,
path: self.path,
scopes: self.content_scopes,
scopes: &mut scope_at_decl,
global_scope: self.global_scope,
super_selectors: self.super_selectors,
span_before: self.span_before,
@ -214,8 +228,21 @@ impl<'a> Parser<'a> {
} else {
Vec::new()
};
self.content.push(content.clone());
self.scopes.exit_scope();
if entered_scope {
scope_at_decl.exit_scope();
}
scope_at_decl.merge(mixin_scope);
if content.declared_at_root {
*self.content_scopes = scope_at_decl;
} else {
*self.scopes = scope_at_decl;
}
self.content.push(content);
stmts
} else {
Vec::new()

View File

@ -93,6 +93,15 @@ impl Scopes {
Self(Vec::new())
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn split_off(mut self, len: usize) -> (Scopes, Scopes) {
let split = self.0.split_off(len);
(self, Scopes(split))
}
pub fn enter_new_scope(&mut self) {
self.0.push(Scope::new());
}
@ -105,12 +114,8 @@ impl Scopes {
self.0.pop();
}
pub fn merge(&mut self, other: Scope) {
if let Some(scope) = self.0.last_mut() {
scope.merge(other)
} else {
panic!()
}
pub fn merge(&mut self, mut other: Self) {
self.0.append(&mut other.0);
}
}

View File

@ -449,6 +449,84 @@ test!(
}",
"a {\n color: foo;\n color: foo;\n}\n"
);
test!(
can_access_variables_declared_before_content,
"@mixin foo {
$a: red;
@content;
color: $a;
}
a {
@include foo;
}",
"a {\n color: red;\n}\n"
);
test!(
content_contains_variable_declared_in_outer_scope_not_declared_at_root,
"a {
$a: red;
@mixin foo {
@content;
}
@include foo {
color: $a;
}
}",
"a {\n color: red;\n}\n"
);
test!(
content_contains_variable_declared_in_outer_scope_declared_at_root,
"@mixin foo {
@content;
}
a {
$a: red;
@include foo {
color: $a;
}
}",
"a {\n color: red;\n}\n"
);
test!(
content_contains_variable_declared_in_outer_scope_not_declared_at_root_and_modified,
"a {
$a: red;
@mixin foo {
$a: green;
@content;
}
@include foo {
color: $a;
}
}",
"a {\n color: green;\n}\n"
);
test!(
content_contains_variable_declared_in_outer_scope_declared_at_root_and_modified,
"@mixin foo {
$a: green;
@content;
}
a {
$a: red;
@include foo {
color: $a;
}
}",
"a {\n color: red;\n}\n"
);
error!(
mixin_in_function,
"@function foo() {