Skip to content

Commit

Permalink
Mixin improvements
Browse files Browse the repository at this point in the history
Better handling of mixin call bodies, the `@content` item, and the
`content_exists` function.

Fixes #112.
  • Loading branch information
kaj committed Jun 2, 2021
1 parent e732f60 commit 6c2a718
Show file tree
Hide file tree
Showing 10 changed files with 54 additions and 44 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,19 @@ The format is based on
project adheres to
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased

### Breaking changes

* The `sass::Item::MixinCall` enum alternative was modified.

### Improvements

* Better handling of mixin call bodies, the `@content` item, and the
`content_exists` function.
* Removed some debug printouts that was accidentally left in 0.21.0.


## Release 0.21.0 - 2021-06-01

Progress: 3727 of 6171 tests passed in dart-sass compatibility mode.
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rsass"
version = "0.21.0"
version = "0.21.1-PRE"
authors = ["Rasmus Kaj <[email protected]>"]
categories = ["command-line-utilities", "web-programming"]
keywords = ["scss", "sass", "css"]
Expand Down
32 changes: 13 additions & 19 deletions src/output/transform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ fn handle_item(
Mixin {
args: FormalArgs::none(),
scope,
body: body.clone(),
body: body.clone().unwrap_or_else(Mixin::no_body),
},
);
handle_body(
Expand All @@ -332,24 +332,18 @@ fn handle_item(
}
}
Item::Content => {
if let Some(rule) = rule {
if let Some(content) =
scope.get_mixin(&Name::from_static("%%BODY%%"))
{
let sel = scope.get_selectors().clone();
handle_body(
&content.body,
head,
Some(rule),
buf,
ScopeRef::sub_selectors(content.scope, sel),
file_context,
)?;
}
} else {
return Err(Error::S(
"@content not allowed in global context".into(),
));
if let Some(content) =
scope.get_mixin(&Name::from_static("%%BODY%%"))
{
let sel = scope.get_selectors().clone();
handle_body(
&content.body,
head,
rule,
buf,
ScopeRef::sub_selectors(content.scope, sel),
file_context,
)?;
}
}

Expand Down
15 changes: 4 additions & 11 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,14 +236,7 @@ fn mixin_call2(input: Span) -> PResult<Item> {
opt(body_block),
terminated(opt_spacelike, opt(tag(";"))),
)(input)?;
Ok((
input,
Item::MixinCall(
name,
args.unwrap_or_default(),
body.unwrap_or_default(),
),
))
Ok((input, Item::MixinCall(name, args.unwrap_or_default(), body)))
}

/// What follows an `@` sign
Expand Down Expand Up @@ -619,7 +612,7 @@ fn if_with_no_else() {
fn test_mixin_call_noargs() {
assert_eq!(
check_parse!(mixin_call, b"@include foo;"),
Item::MixinCall("foo".to_string(), CallArgs::default(), vec![]),
Item::MixinCall("foo".to_string(), CallArgs::default(), None),
)
}

Expand All @@ -630,7 +623,7 @@ fn test_mixin_call_pos_args() {
Item::MixinCall(
"foo".to_string(),
CallArgs::new(vec![(None, string("bar")), (None, string("baz"))]),
vec![],
None,
),
)
}
Expand All @@ -645,7 +638,7 @@ fn test_mixin_call_named_args() {
(Some("x".into()), string("bar")),
(Some("y".into()), string("baz")),
]),
vec![],
None,
),
)
}
Expand Down
12 changes: 9 additions & 3 deletions src/sass/functions/meta.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::{check, get_opt_check, get_string, Error, FunctionMap};
use crate::css::{CallArgs, Value};
use crate::sass::Name;
use crate::sass::{Mixin, Name};
use crate::{Format, Scope, ScopeRef};

pub fn create_module() -> Scope {
Expand Down Expand Up @@ -37,8 +37,14 @@ pub fn create_module() -> Scope {
}
});
def!(f, content_exists(), |s| {
let content = s.get_mixin(&Name::from_static("%%BODY%%"));
Ok(content.map(|m| !m.body.is_empty()).unwrap_or(false).into())
let content = call_scope(s).get_mixin(&Name::from_static("%%BODY%%"));
if let Some(content) = content {
Ok((!Mixin::is_no_body(&content.body)).into())
} else {
Err(Error::error(
"content-exists() may only be called within a mixin",
))
}
});
def!(f, feature_exists(feature), |s| {
let (feature, _q) = get_string(s, "feature")?;
Expand Down
2 changes: 1 addition & 1 deletion src/sass/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ pub enum Item {
/// A `@mixin` directive, declaring a mixin.
MixinDeclaration(String, FormalArgs, Vec<Item>),
/// An `@include` directive, calling a mixin.
MixinCall(String, CallArgs, Vec<Item>),
MixinCall(String, CallArgs, Option<Vec<Item>>),
/// An `@content` directive (in a mixin declaration).
Content,

Expand Down
12 changes: 11 additions & 1 deletion src/sass/mixin.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::sass::{FormalArgs, Item};
use crate::sass::{FormalArgs, Item, Value};
use crate::ScopeRef;

/// A mixin is a callable body of items.
Expand All @@ -11,3 +11,13 @@ pub struct Mixin {
/// The body of this mixin.
pub body: Vec<Item>,
}

impl Mixin {
/// An illegal mixin body, used for `@content` on mixin calls sans body.
pub(crate) fn no_body() -> Vec<Item> {
vec![Item::Property("%%NO-BODY%%".into(), Value::Null)]
}
pub(crate) fn is_no_body(body: &[Item]) -> bool {
body == [Item::Property("%%NO-BODY%%".into(), Value::Null)]
}
}
7 changes: 1 addition & 6 deletions tests/spec/core_functions/meta/content_exists.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ mod controls {
);
}
#[test]
#[ignore] // wrong result
fn test_true() {
assert_eq!(
runner().ok("// Regression test for sass/libsass#2842\
Expand Down Expand Up @@ -80,7 +79,7 @@ mod error {
);
}
#[test]
#[ignore] // missing error
#[ignore] // wrong error
fn in_function_called_by_mixin() {
assert_eq!(
runner().err(
Expand All @@ -103,7 +102,6 @@ mod error {
);
}
#[test]
#[ignore] // missing error
fn outside_mixin() {
assert_eq!(
runner().err("a {b: content-exists()}\n"),
Expand Down Expand Up @@ -144,7 +142,6 @@ mod test_false {
use super::runner;

#[test]
#[ignore] // unexepected error
fn through_content() {
assert_eq!(
runner().ok("@mixin call-content {\
Expand Down Expand Up @@ -179,7 +176,6 @@ mod test_true {
use super::runner;

#[test]
#[ignore] // unexepected error
fn empty() {
assert_eq!(
runner().ok("@mixin a {\
Expand All @@ -193,7 +189,6 @@ mod test_true {
);
}
#[test]
#[ignore] // unexepected error
fn non_empty() {
assert_eq!(
runner().ok("@mixin a {\
Expand Down
1 change: 0 additions & 1 deletion tests/spec/libsass_closed_issues/issue_1640.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ fn runner() -> crate::TestRunner {
}

#[test]
#[ignore] // unexepected error
fn test() {
assert_eq!(
runner().ok("@mixin foo() {\
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ fn runner() -> crate::TestRunner {
}

#[test]
#[ignore] // wrong error
#[ignore] // missing error
fn test() {
assert_eq!(
runner().err(
Expand Down

0 comments on commit 6c2a718

Please sign in to comment.