properly handle chained @content
This commit is contained in:
parent
5dd14794c5
commit
1b033c3643
@ -24,6 +24,7 @@ impl Mixin {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct Content {
|
||||
pub content: Option<Vec<Token>>,
|
||||
pub content_args: Option<FuncArgs>,
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
|
@ -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,26 +158,32 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
Ok(if let Some(content) = &self.content.content {
|
||||
Ok(if let Some(content) = &self.content.pop() {
|
||||
let stmts = if let Some(body) = content.content.clone() {
|
||||
Parser {
|
||||
toks: &mut content.to_vec().into_iter().peekmore(),
|
||||
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: false,
|
||||
in_mixin: self.in_mixin,
|
||||
in_function: self.in_function,
|
||||
in_control_flow: self.in_control_flow,
|
||||
content: self.content,
|
||||
at_root: false,
|
||||
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()
|
||||
})
|
||||
} else {
|
||||
Err((
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user