properly handle chained @content

This commit is contained in:
Connor Skees 2020-07-02 15:22:15 -04:00
parent 5dd14794c5
commit 1b033c3643
7 changed files with 100 additions and 28 deletions

View File

@ -24,6 +24,7 @@ impl Mixin {
}
}
#[derive(Debug, Clone)]
pub(crate) struct Content {
pub content: Option<Vec<Token>>,
pub content_args: Option<FuncArgs>,

View File

@ -245,7 +245,13 @@ fn content_exists(args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value>
)
.into());
}
Ok(Value::bool(parser.content.content.is_some()))
Ok(Value::bool(
parser
.content
.last()
.map(|c| c.content.is_some())
.unwrap_or(false),
))
}
pub(crate) fn declare(f: &mut GlobalFunctionMap) {

View File

@ -160,7 +160,7 @@ pub fn from_path(p: &str) -> Result<String> {
global_scope: &mut Scope::new(),
super_selectors: &mut NeverEmptyVec::new(Selector::new(empty_span)),
span_before: empty_span,
content: &Content::new(),
content: &mut vec![Content::new()],
in_mixin: false,
in_function: false,
in_control_flow: false,
@ -206,7 +206,7 @@ pub fn from_string(p: String) -> Result<String> {
global_scope: &mut Scope::new(),
super_selectors: &mut NeverEmptyVec::new(Selector::new(empty_span)),
span_before: empty_span,
content: &Content::new(),
content: &mut vec![Content::new()],
in_mixin: false,
in_function: false,
in_control_flow: false,
@ -242,7 +242,7 @@ pub fn from_string(p: String) -> std::result::Result<String, JsValue> {
global_scope: &mut Scope::new(),
super_selectors: &mut NeverEmptyVec::new(Selector::new(empty_span)),
span_before: empty_span,
content: &Content::new(),
content: &mut vec![Content::new()],
in_mixin: false,
in_function: false,
in_control_flow: false,

View File

@ -113,6 +113,11 @@ impl<'a> Parser<'a> {
} = self.scopes.last().get_mixin(name, self.global_scope)?;
self.eval_args(fn_args, args, &mut scope)?;
self.content.push(Content {
content,
content_args,
});
let body = Parser {
toks: &mut body.into_iter().peekmore(),
map: self.map,
@ -124,16 +129,15 @@ impl<'a> Parser<'a> {
in_mixin: true,
in_function: self.in_function,
in_control_flow: self.in_control_flow,
content: &Content {
content,
content_args,
},
content: self.content,
at_root: false,
at_root_has_selector: self.at_root_has_selector,
extender: self.extender,
}
.parse()?;
self.content.pop();
Ok(body)
}
@ -143,7 +147,9 @@ impl<'a> Parser<'a> {
if let Some(Token { kind: '(', .. }) = self.toks.peek() {
self.toks.next();
let args = self.parse_call_args()?;
if let Some(content_args) = self.content.content_args.clone() {
if let Some(Some(content_args)) =
self.content.last().map(|v| v.content_args.clone())
{
args.max_args(content_args.len())?;
self.eval_args(content_args, args, &mut scope)?;
@ -152,24 +158,30 @@ impl<'a> Parser<'a> {
}
}
Ok(if let Some(content) = &self.content.content {
Parser {
toks: &mut content.to_vec().into_iter().peekmore(),
map: self.map,
path: self.path,
scopes: &mut NeverEmptyVec::new(scope),
global_scope: self.global_scope,
super_selectors: self.super_selectors,
span_before: self.span_before,
in_mixin: false,
in_function: self.in_function,
in_control_flow: self.in_control_flow,
content: self.content,
at_root: false,
at_root_has_selector: self.at_root_has_selector,
extender: self.extender,
}
.parse()?
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: &mut NeverEmptyVec::new(scope),
global_scope: self.global_scope,
super_selectors: self.super_selectors,
span_before: self.span_before,
in_mixin: self.in_mixin,
in_function: self.in_function,
in_control_flow: self.in_control_flow,
content: self.content,
at_root: self.at_root,
at_root_has_selector: self.at_root_has_selector,
extender: self.extender,
}
.parse()?
} else {
Vec::new()
};
self.content.push(content.clone());
stmts
} else {
Vec::new()
})

View File

@ -70,7 +70,7 @@ pub(crate) struct Parser<'a> {
pub scopes: &'a mut NeverEmptyVec<Scope>,
pub super_selectors: &'a mut NeverEmptyVec<Selector>,
pub span_before: Span,
pub content: &'a Content,
pub content: &'a mut Vec<Content>,
pub in_mixin: bool,
pub in_function: bool,
pub in_control_flow: bool,

View File

@ -33,6 +33,22 @@ test!(
"@mixin foo {\n color: content-exists();\n @content;\n}\n\na {\n @include foo{color: red};\n}\n",
"a {\n color: true;\n color: red;\n}\n"
);
test!(
chained_mixin_second_doesnt_have_content,
"@mixin foo {
color: content-exists();
}
@mixin bar {
@include foo;
@content;
}
a {
@include bar {}
}",
"a {\n color: false;\n}\n"
);
error!(
#[ignore = "haven't yet figured out a good way to check for whether an @content block exists"]
include_empty_braces_no_args_no_at_content,

View File

@ -286,6 +286,43 @@ test!(
}",
"a {\n color: red;\n}\n"
);
test!(
multiple_content_using_different_args,
"@mixin foo {
@content(1);
@content(2);
}
@mixin bar {
@include foo using ($a) {
color: $a
}
}
a {
@include bar;
}",
"a {\n color: 1;\n color: 2;\n}\n"
);
test!(
chained_content,
"@mixin foo {
@content;
}
@mixin bar {
@include foo {
@content;
}
}
a {
@include bar {
color: red;
}
}",
"a {\n color: red;\n}\n"
);
error!(
content_using_too_many_args,
"@mixin foo {