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(crate) struct Content {
|
||||||
pub content: Option<Vec<Token>>,
|
pub content: Option<Vec<Token>>,
|
||||||
pub content_args: Option<FuncArgs>,
|
pub content_args: Option<FuncArgs>,
|
||||||
|
@ -245,7 +245,13 @@ fn content_exists(args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value>
|
|||||||
)
|
)
|
||||||
.into());
|
.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) {
|
pub(crate) fn declare(f: &mut GlobalFunctionMap) {
|
||||||
|
@ -160,7 +160,7 @@ pub fn from_path(p: &str) -> Result<String> {
|
|||||||
global_scope: &mut Scope::new(),
|
global_scope: &mut Scope::new(),
|
||||||
super_selectors: &mut NeverEmptyVec::new(Selector::new(empty_span)),
|
super_selectors: &mut NeverEmptyVec::new(Selector::new(empty_span)),
|
||||||
span_before: empty_span,
|
span_before: empty_span,
|
||||||
content: &Content::new(),
|
content: &mut vec![Content::new()],
|
||||||
in_mixin: false,
|
in_mixin: false,
|
||||||
in_function: false,
|
in_function: false,
|
||||||
in_control_flow: false,
|
in_control_flow: false,
|
||||||
@ -206,7 +206,7 @@ pub fn from_string(p: String) -> Result<String> {
|
|||||||
global_scope: &mut Scope::new(),
|
global_scope: &mut Scope::new(),
|
||||||
super_selectors: &mut NeverEmptyVec::new(Selector::new(empty_span)),
|
super_selectors: &mut NeverEmptyVec::new(Selector::new(empty_span)),
|
||||||
span_before: empty_span,
|
span_before: empty_span,
|
||||||
content: &Content::new(),
|
content: &mut vec![Content::new()],
|
||||||
in_mixin: false,
|
in_mixin: false,
|
||||||
in_function: false,
|
in_function: false,
|
||||||
in_control_flow: 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(),
|
global_scope: &mut Scope::new(),
|
||||||
super_selectors: &mut NeverEmptyVec::new(Selector::new(empty_span)),
|
super_selectors: &mut NeverEmptyVec::new(Selector::new(empty_span)),
|
||||||
span_before: empty_span,
|
span_before: empty_span,
|
||||||
content: &Content::new(),
|
content: &mut vec![Content::new()],
|
||||||
in_mixin: false,
|
in_mixin: false,
|
||||||
in_function: false,
|
in_function: false,
|
||||||
in_control_flow: false,
|
in_control_flow: false,
|
||||||
|
@ -113,6 +113,11 @@ impl<'a> Parser<'a> {
|
|||||||
} = self.scopes.last().get_mixin(name, self.global_scope)?;
|
} = self.scopes.last().get_mixin(name, self.global_scope)?;
|
||||||
self.eval_args(fn_args, args, &mut scope)?;
|
self.eval_args(fn_args, args, &mut scope)?;
|
||||||
|
|
||||||
|
self.content.push(Content {
|
||||||
|
content,
|
||||||
|
content_args,
|
||||||
|
});
|
||||||
|
|
||||||
let body = Parser {
|
let body = Parser {
|
||||||
toks: &mut body.into_iter().peekmore(),
|
toks: &mut body.into_iter().peekmore(),
|
||||||
map: self.map,
|
map: self.map,
|
||||||
@ -124,16 +129,15 @@ impl<'a> Parser<'a> {
|
|||||||
in_mixin: true,
|
in_mixin: true,
|
||||||
in_function: self.in_function,
|
in_function: self.in_function,
|
||||||
in_control_flow: self.in_control_flow,
|
in_control_flow: self.in_control_flow,
|
||||||
content: &Content {
|
content: self.content,
|
||||||
content,
|
|
||||||
content_args,
|
|
||||||
},
|
|
||||||
at_root: false,
|
at_root: false,
|
||||||
at_root_has_selector: self.at_root_has_selector,
|
at_root_has_selector: self.at_root_has_selector,
|
||||||
extender: self.extender,
|
extender: self.extender,
|
||||||
}
|
}
|
||||||
.parse()?;
|
.parse()?;
|
||||||
|
|
||||||
|
self.content.pop();
|
||||||
|
|
||||||
Ok(body)
|
Ok(body)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,7 +147,9 @@ impl<'a> Parser<'a> {
|
|||||||
if let Some(Token { kind: '(', .. }) = self.toks.peek() {
|
if let Some(Token { kind: '(', .. }) = self.toks.peek() {
|
||||||
self.toks.next();
|
self.toks.next();
|
||||||
let args = self.parse_call_args()?;
|
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())?;
|
args.max_args(content_args.len())?;
|
||||||
|
|
||||||
self.eval_args(content_args, args, &mut scope)?;
|
self.eval_args(content_args, args, &mut scope)?;
|
||||||
@ -152,24 +158,30 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(if let Some(content) = &self.content.content {
|
Ok(if let Some(content) = &self.content.pop() {
|
||||||
Parser {
|
let stmts = if let Some(body) = content.content.clone() {
|
||||||
toks: &mut content.to_vec().into_iter().peekmore(),
|
Parser {
|
||||||
map: self.map,
|
toks: &mut body.into_iter().peekmore(),
|
||||||
path: self.path,
|
map: self.map,
|
||||||
scopes: &mut NeverEmptyVec::new(scope),
|
path: self.path,
|
||||||
global_scope: self.global_scope,
|
scopes: &mut NeverEmptyVec::new(scope),
|
||||||
super_selectors: self.super_selectors,
|
global_scope: self.global_scope,
|
||||||
span_before: self.span_before,
|
super_selectors: self.super_selectors,
|
||||||
in_mixin: false,
|
span_before: self.span_before,
|
||||||
in_function: self.in_function,
|
in_mixin: self.in_mixin,
|
||||||
in_control_flow: self.in_control_flow,
|
in_function: self.in_function,
|
||||||
content: self.content,
|
in_control_flow: self.in_control_flow,
|
||||||
at_root: false,
|
content: self.content,
|
||||||
at_root_has_selector: self.at_root_has_selector,
|
at_root: self.at_root,
|
||||||
extender: self.extender,
|
at_root_has_selector: self.at_root_has_selector,
|
||||||
}
|
extender: self.extender,
|
||||||
.parse()?
|
}
|
||||||
|
.parse()?
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
};
|
||||||
|
self.content.push(content.clone());
|
||||||
|
stmts
|
||||||
} else {
|
} else {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
})
|
})
|
||||||
|
@ -70,7 +70,7 @@ pub(crate) struct Parser<'a> {
|
|||||||
pub scopes: &'a mut NeverEmptyVec<Scope>,
|
pub scopes: &'a mut NeverEmptyVec<Scope>,
|
||||||
pub super_selectors: &'a mut NeverEmptyVec<Selector>,
|
pub super_selectors: &'a mut NeverEmptyVec<Selector>,
|
||||||
pub span_before: Span,
|
pub span_before: Span,
|
||||||
pub content: &'a Content,
|
pub content: &'a mut Vec<Content>,
|
||||||
pub in_mixin: bool,
|
pub in_mixin: bool,
|
||||||
pub in_function: bool,
|
pub in_function: bool,
|
||||||
pub in_control_flow: 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",
|
"@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"
|
"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!(
|
error!(
|
||||||
#[ignore = "haven't yet figured out a good way to check for whether an @content block exists"]
|
#[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,
|
include_empty_braces_no_args_no_at_content,
|
||||||
|
@ -286,6 +286,43 @@ test!(
|
|||||||
}",
|
}",
|
||||||
"a {\n color: red;\n}\n"
|
"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!(
|
error!(
|
||||||
content_using_too_many_args,
|
content_using_too_many_args,
|
||||||
"@mixin foo {
|
"@mixin foo {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user