support compressed lists and number values
This commit is contained in:
parent
3ced8feed5
commit
94fe52a81d
@ -34,6 +34,7 @@ complex uses of @at-root
|
|||||||
media queries with @import
|
media queries with @import
|
||||||
/ as a separator in color functions, e.g. rgba(255, 255, 255 / 0)
|
/ as a separator in color functions, e.g. rgba(255, 255, 255 / 0)
|
||||||
Infinity and -Infinity
|
Infinity and -Infinity
|
||||||
|
builtin meta function keywords
|
||||||
```
|
```
|
||||||
|
|
||||||
All known missing features and bugs are tracked in [#19](https://github.com/connorskees/grass/issues/19).
|
All known missing features and bugs are tracked in [#19](https://github.com/connorskees/grass/issues/19).
|
||||||
|
@ -64,7 +64,7 @@ impl CallArgs {
|
|||||||
CallArgs(HashMap::new(), span)
|
CallArgs(HashMap::new(), span)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_css_string(self) -> SassResult<Spanned<String>> {
|
pub fn to_css_string(self, is_compressed: bool) -> SassResult<Spanned<String>> {
|
||||||
let mut string = String::with_capacity(2 + self.len() * 10);
|
let mut string = String::with_capacity(2 + self.len() * 10);
|
||||||
string.push('(');
|
string.push('(');
|
||||||
let mut span = self.1;
|
let mut span = self.1;
|
||||||
@ -88,7 +88,7 @@ impl CallArgs {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|a| {
|
.map(|a| {
|
||||||
span = span.merge(a.span);
|
span = span.merge(a.span);
|
||||||
a.node.to_css_string(a.span)
|
a.node.to_css_string(a.span, is_compressed)
|
||||||
})
|
})
|
||||||
.collect::<SassResult<Vec<Cow<'static, str>>>>()?
|
.collect::<SassResult<Vec<Cow<'static, str>>>>()?
|
||||||
.join(", "),
|
.join(", "),
|
||||||
|
@ -90,13 +90,17 @@ fn inner_hsl(name: &'static str, mut args: CallArgs, parser: &mut Parser) -> Sas
|
|||||||
let mut string = format!(
|
let mut string = format!(
|
||||||
"{}({}, {}, {}",
|
"{}({}, {}, {}",
|
||||||
name,
|
name,
|
||||||
v.to_css_string(args.span())?,
|
v.to_css_string(args.span(), parser.options.is_compressed())?,
|
||||||
saturation.to_css_string(args.span())?,
|
saturation.to_css_string(args.span(), parser.options.is_compressed())?,
|
||||||
lightness.to_css_string(args.span())?
|
lightness.to_css_string(args.span(), parser.options.is_compressed())?
|
||||||
);
|
);
|
||||||
if !args.is_empty() {
|
if !args.is_empty() {
|
||||||
string.push_str(", ");
|
string.push_str(", ");
|
||||||
string.push_str(&args.get_err(3, "alpha")?.to_css_string(args.span())?);
|
string.push_str(
|
||||||
|
&args
|
||||||
|
.get_err(3, "alpha")?
|
||||||
|
.to_css_string(args.span(), parser.options.is_compressed())?,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
string.push(')');
|
string.push(')');
|
||||||
return Ok(Value::String(string, QuoteKind::None));
|
return Ok(Value::String(string, QuoteKind::None));
|
||||||
@ -117,13 +121,17 @@ fn inner_hsl(name: &'static str, mut args: CallArgs, parser: &mut Parser) -> Sas
|
|||||||
let mut string = format!(
|
let mut string = format!(
|
||||||
"{}({}, {}, {}",
|
"{}({}, {}, {}",
|
||||||
name,
|
name,
|
||||||
hue,
|
hue.to_string(parser.options.is_compressed()),
|
||||||
v.to_css_string(args.span())?,
|
v.to_css_string(args.span(), parser.options.is_compressed())?,
|
||||||
lightness.to_css_string(args.span())?
|
lightness.to_css_string(args.span(), parser.options.is_compressed())?
|
||||||
);
|
);
|
||||||
if !args.is_empty() {
|
if !args.is_empty() {
|
||||||
string.push_str(", ");
|
string.push_str(", ");
|
||||||
string.push_str(&args.get_err(3, "alpha")?.to_css_string(args.span())?);
|
string.push_str(
|
||||||
|
&args
|
||||||
|
.get_err(3, "alpha")?
|
||||||
|
.to_css_string(args.span(), parser.options.is_compressed())?,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
string.push(')');
|
string.push(')');
|
||||||
return Ok(Value::String(string, QuoteKind::None));
|
return Ok(Value::String(string, QuoteKind::None));
|
||||||
@ -132,7 +140,7 @@ fn inner_hsl(name: &'static str, mut args: CallArgs, parser: &mut Parser) -> Sas
|
|||||||
return Err((
|
return Err((
|
||||||
format!(
|
format!(
|
||||||
"$saturation: {} is not a number.",
|
"$saturation: {} is not a number.",
|
||||||
v.to_css_string(args.span())?
|
v.to_css_string(args.span(), parser.options.is_compressed())?
|
||||||
),
|
),
|
||||||
args.span(),
|
args.span(),
|
||||||
)
|
)
|
||||||
@ -146,13 +154,17 @@ fn inner_hsl(name: &'static str, mut args: CallArgs, parser: &mut Parser) -> Sas
|
|||||||
let mut string = format!(
|
let mut string = format!(
|
||||||
"{}({}, {}, {}",
|
"{}({}, {}, {}",
|
||||||
name,
|
name,
|
||||||
hue,
|
hue.to_string(parser.options.is_compressed()),
|
||||||
saturation,
|
saturation.to_string(parser.options.is_compressed()),
|
||||||
v.to_css_string(args.span())?
|
v.to_css_string(args.span(), parser.options.is_compressed())?
|
||||||
);
|
);
|
||||||
if !args.is_empty() {
|
if !args.is_empty() {
|
||||||
string.push_str(", ");
|
string.push_str(", ");
|
||||||
string.push_str(&args.get_err(3, "alpha")?.to_css_string(args.span())?);
|
string.push_str(
|
||||||
|
&args
|
||||||
|
.get_err(3, "alpha")?
|
||||||
|
.to_css_string(args.span(), parser.options.is_compressed())?,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
string.push(')');
|
string.push(')');
|
||||||
return Ok(Value::String(string, QuoteKind::None));
|
return Ok(Value::String(string, QuoteKind::None));
|
||||||
@ -161,7 +173,7 @@ fn inner_hsl(name: &'static str, mut args: CallArgs, parser: &mut Parser) -> Sas
|
|||||||
return Err((
|
return Err((
|
||||||
format!(
|
format!(
|
||||||
"$lightness: {} is not a number.",
|
"$lightness: {} is not a number.",
|
||||||
v.to_css_string(args.span())?
|
v.to_css_string(args.span(), parser.options.is_compressed())?
|
||||||
),
|
),
|
||||||
args.span(),
|
args.span(),
|
||||||
)
|
)
|
||||||
@ -180,7 +192,7 @@ fn inner_hsl(name: &'static str, mut args: CallArgs, parser: &mut Parser) -> Sas
|
|||||||
return Err((
|
return Err((
|
||||||
format!(
|
format!(
|
||||||
"$alpha: Expected {} to have no units or \"%\".",
|
"$alpha: Expected {} to have no units or \"%\".",
|
||||||
v.to_css_string(args.span())?
|
v.to_css_string(args.span(), parser.options.is_compressed())?
|
||||||
),
|
),
|
||||||
args.span(),
|
args.span(),
|
||||||
)
|
)
|
||||||
@ -191,10 +203,10 @@ fn inner_hsl(name: &'static str, mut args: CallArgs, parser: &mut Parser) -> Sas
|
|||||||
format!(
|
format!(
|
||||||
"{}({}, {}, {}, {})",
|
"{}({}, {}, {}, {})",
|
||||||
name,
|
name,
|
||||||
hue,
|
hue.to_string(parser.options.is_compressed()),
|
||||||
saturation,
|
saturation.to_string(parser.options.is_compressed()),
|
||||||
lightness,
|
lightness.to_string(parser.options.is_compressed()),
|
||||||
v.to_css_string(args.span())?
|
v.to_css_string(args.span(), parser.options.is_compressed())?
|
||||||
),
|
),
|
||||||
QuoteKind::None,
|
QuoteKind::None,
|
||||||
));
|
));
|
||||||
@ -276,7 +288,7 @@ pub(crate) fn adjust_hue(mut args: CallArgs, parser: &mut Parser) -> SassResult<
|
|||||||
return Err((
|
return Err((
|
||||||
format!(
|
format!(
|
||||||
"$degrees: {} is not a number.",
|
"$degrees: {} is not a number.",
|
||||||
v.to_css_string(args.span())?
|
v.to_css_string(args.span(), parser.options.is_compressed())?
|
||||||
),
|
),
|
||||||
args.span(),
|
args.span(),
|
||||||
)
|
)
|
||||||
@ -305,7 +317,7 @@ fn lighten(mut args: CallArgs, parser: &mut Parser) -> SassResult<Value> {
|
|||||||
return Err((
|
return Err((
|
||||||
format!(
|
format!(
|
||||||
"$amount: {} is not a number.",
|
"$amount: {} is not a number.",
|
||||||
v.to_css_string(args.span())?
|
v.to_css_string(args.span(), false)?
|
||||||
),
|
),
|
||||||
args.span(),
|
args.span(),
|
||||||
)
|
)
|
||||||
@ -334,7 +346,7 @@ fn darken(mut args: CallArgs, parser: &mut Parser) -> SassResult<Value> {
|
|||||||
return Err((
|
return Err((
|
||||||
format!(
|
format!(
|
||||||
"$amount: {} is not a number.",
|
"$amount: {} is not a number.",
|
||||||
v.to_css_string(args.span())?
|
v.to_css_string(args.span(), false)?
|
||||||
),
|
),
|
||||||
args.span(),
|
args.span(),
|
||||||
)
|
)
|
||||||
@ -350,7 +362,8 @@ fn saturate(mut args: CallArgs, parser: &mut Parser) -> SassResult<Value> {
|
|||||||
return Ok(Value::String(
|
return Ok(Value::String(
|
||||||
format!(
|
format!(
|
||||||
"saturate({})",
|
"saturate({})",
|
||||||
args.get_err(0, "amount")?.to_css_string(args.span())?
|
args.get_err(0, "amount")?
|
||||||
|
.to_css_string(args.span(), false)?
|
||||||
),
|
),
|
||||||
QuoteKind::None,
|
QuoteKind::None,
|
||||||
));
|
));
|
||||||
@ -363,7 +376,7 @@ fn saturate(mut args: CallArgs, parser: &mut Parser) -> SassResult<Value> {
|
|||||||
return Err((
|
return Err((
|
||||||
format!(
|
format!(
|
||||||
"$amount: {} is not a number.",
|
"$amount: {} is not a number.",
|
||||||
v.to_css_string(args.span())?
|
v.to_css_string(args.span(), false)?
|
||||||
),
|
),
|
||||||
args.span(),
|
args.span(),
|
||||||
)
|
)
|
||||||
@ -374,7 +387,7 @@ fn saturate(mut args: CallArgs, parser: &mut Parser) -> SassResult<Value> {
|
|||||||
Value::Color(c) => c,
|
Value::Color(c) => c,
|
||||||
Value::Dimension(Some(n), u, _) => {
|
Value::Dimension(Some(n), u, _) => {
|
||||||
return Ok(Value::String(
|
return Ok(Value::String(
|
||||||
format!("saturate({}{})", n, u),
|
format!("saturate({}{})", n.inspect(), u),
|
||||||
QuoteKind::None,
|
QuoteKind::None,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@ -408,7 +421,7 @@ fn desaturate(mut args: CallArgs, parser: &mut Parser) -> SassResult<Value> {
|
|||||||
return Err((
|
return Err((
|
||||||
format!(
|
format!(
|
||||||
"$amount: {} is not a number.",
|
"$amount: {} is not a number.",
|
||||||
v.to_css_string(args.span())?
|
v.to_css_string(args.span(), parser.options.is_compressed())?
|
||||||
),
|
),
|
||||||
args.span(),
|
args.span(),
|
||||||
)
|
)
|
||||||
@ -424,7 +437,7 @@ pub(crate) fn grayscale(mut args: CallArgs, parser: &mut Parser) -> SassResult<V
|
|||||||
Value::Color(c) => c,
|
Value::Color(c) => c,
|
||||||
Value::Dimension(Some(n), u, _) => {
|
Value::Dimension(Some(n), u, _) => {
|
||||||
return Ok(Value::String(
|
return Ok(Value::String(
|
||||||
format!("grayscale({}{})", n, u),
|
format!("grayscale({}{})", n.inspect(), u),
|
||||||
QuoteKind::None,
|
QuoteKind::None,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@ -471,7 +484,7 @@ pub(crate) fn invert(mut args: CallArgs, parser: &mut Parser) -> SassResult<Valu
|
|||||||
return Err((
|
return Err((
|
||||||
format!(
|
format!(
|
||||||
"$weight: {} is not a number.",
|
"$weight: {} is not a number.",
|
||||||
v.to_css_string(args.span())?
|
v.to_css_string(args.span(), parser.options.is_compressed())?
|
||||||
),
|
),
|
||||||
args.span(),
|
args.span(),
|
||||||
)
|
)
|
||||||
@ -491,7 +504,7 @@ pub(crate) fn invert(mut args: CallArgs, parser: &mut Parser) -> SassResult<Valu
|
|||||||
.into());
|
.into());
|
||||||
}
|
}
|
||||||
Ok(Value::String(
|
Ok(Value::String(
|
||||||
format!("invert({}{})", n, u),
|
format!("invert({}{})", n.inspect(), u),
|
||||||
QuoteKind::None,
|
QuoteKind::None,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -74,7 +74,7 @@ pub(crate) fn opacity(mut args: CallArgs, parser: &mut Parser) -> SassResult<Val
|
|||||||
match args.get_err(0, "color")? {
|
match args.get_err(0, "color")? {
|
||||||
Value::Color(c) => Ok(Value::Dimension(Some(c.alpha()), Unit::None, true)),
|
Value::Color(c) => Ok(Value::Dimension(Some(c.alpha()), Unit::None, true)),
|
||||||
Value::Dimension(Some(num), unit, _) => Ok(Value::String(
|
Value::Dimension(Some(num), unit, _) => Ok(Value::String(
|
||||||
format!("opacity({}{})", num, unit),
|
format!("opacity({}{})", num.inspect(), unit),
|
||||||
QuoteKind::None,
|
QuoteKind::None,
|
||||||
)),
|
)),
|
||||||
Value::Dimension(None, ..) => todo!(),
|
Value::Dimension(None, ..) => todo!(),
|
||||||
|
@ -50,9 +50,9 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser) -> Sas
|
|||||||
format!(
|
format!(
|
||||||
"{}({}, {}, {})",
|
"{}({}, {}, {})",
|
||||||
name,
|
name,
|
||||||
red.to_css_string(args.span())?,
|
red.to_css_string(args.span(), parser.options.is_compressed())?,
|
||||||
green.to_css_string(args.span())?,
|
green.to_css_string(args.span(), parser.options.is_compressed())?,
|
||||||
v.to_css_string(args.span())?
|
v.to_css_string(args.span(), parser.options.is_compressed())?
|
||||||
),
|
),
|
||||||
QuoteKind::None,
|
QuoteKind::None,
|
||||||
));
|
));
|
||||||
@ -78,11 +78,16 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser) -> Sas
|
|||||||
Some(red) => format!(
|
Some(red) => format!(
|
||||||
"{}({}, {}, {})",
|
"{}({}, {}, {})",
|
||||||
name,
|
name,
|
||||||
red.to_css_string(args.span())?,
|
red.to_css_string(args.span(), parser.options.is_compressed())?,
|
||||||
v.to_css_string(args.span())?,
|
v.to_css_string(args.span(), parser.options.is_compressed())?,
|
||||||
blue
|
blue.to_string(parser.options.is_compressed())
|
||||||
|
),
|
||||||
|
None => format!(
|
||||||
|
"{}({} {})",
|
||||||
|
name,
|
||||||
|
v.to_css_string(args.span(), parser.options.is_compressed())?,
|
||||||
|
blue.to_string(parser.options.is_compressed())
|
||||||
),
|
),
|
||||||
None => format!("{}({} {})", name, v.to_css_string(args.span())?, blue),
|
|
||||||
};
|
};
|
||||||
return Ok(Value::String(string, QuoteKind::None));
|
return Ok(Value::String(string, QuoteKind::None));
|
||||||
}
|
}
|
||||||
@ -107,9 +112,9 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser) -> Sas
|
|||||||
format!(
|
format!(
|
||||||
"{}({}, {}, {})",
|
"{}({}, {}, {})",
|
||||||
name,
|
name,
|
||||||
v.to_css_string(args.span())?,
|
v.to_css_string(args.span(), parser.options.is_compressed())?,
|
||||||
green,
|
green.to_string(parser.options.is_compressed()),
|
||||||
blue
|
blue.to_string(parser.options.is_compressed())
|
||||||
),
|
),
|
||||||
QuoteKind::None,
|
QuoteKind::None,
|
||||||
));
|
));
|
||||||
@ -136,8 +141,8 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser) -> Sas
|
|||||||
format!(
|
format!(
|
||||||
"{}({}, {})",
|
"{}({}, {})",
|
||||||
name,
|
name,
|
||||||
v.to_css_string(args.span())?,
|
v.to_css_string(args.span(), parser.options.is_compressed())?,
|
||||||
alpha.to_css_string(args.span())?
|
alpha.to_css_string(args.span(), parser.options.is_compressed())?
|
||||||
),
|
),
|
||||||
QuoteKind::None,
|
QuoteKind::None,
|
||||||
));
|
));
|
||||||
@ -158,7 +163,7 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser) -> Sas
|
|||||||
return Err((
|
return Err((
|
||||||
format!(
|
format!(
|
||||||
"$alpha: Expected {} to have no units or \"%\".",
|
"$alpha: Expected {} to have no units or \"%\".",
|
||||||
v.to_css_string(args.span())?
|
v.to_css_string(args.span(), parser.options.is_compressed())?
|
||||||
),
|
),
|
||||||
args.span(),
|
args.span(),
|
||||||
)
|
)
|
||||||
@ -169,10 +174,10 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser) -> Sas
|
|||||||
format!(
|
format!(
|
||||||
"{}({}, {}, {}, {})",
|
"{}({}, {}, {}, {})",
|
||||||
name,
|
name,
|
||||||
color.red(),
|
color.red().to_string(parser.options.is_compressed()),
|
||||||
color.green(),
|
color.green().to_string(parser.options.is_compressed()),
|
||||||
color.blue(),
|
color.blue().to_string(parser.options.is_compressed()),
|
||||||
v.to_css_string(args.span())?
|
v.to_css_string(args.span(), parser.options.is_compressed())?
|
||||||
),
|
),
|
||||||
QuoteKind::None,
|
QuoteKind::None,
|
||||||
));
|
));
|
||||||
@ -197,7 +202,7 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser) -> Sas
|
|||||||
return Err((
|
return Err((
|
||||||
format!(
|
format!(
|
||||||
"$red: Expected {} to have no units or \"%\".",
|
"$red: Expected {} to have no units or \"%\".",
|
||||||
v.to_css_string(args.span())?
|
v.to_css_string(args.span(), parser.options.is_compressed())?
|
||||||
),
|
),
|
||||||
args.span(),
|
args.span(),
|
||||||
)
|
)
|
||||||
@ -209,13 +214,17 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser) -> Sas
|
|||||||
let mut string = format!(
|
let mut string = format!(
|
||||||
"{}({}, {}, {}",
|
"{}({}, {}, {}",
|
||||||
name,
|
name,
|
||||||
v.to_css_string(args.span())?,
|
v.to_css_string(args.span(), parser.options.is_compressed())?,
|
||||||
green.to_css_string(args.span())?,
|
green.to_css_string(args.span(), parser.options.is_compressed())?,
|
||||||
blue.to_css_string(args.span())?
|
blue.to_css_string(args.span(), parser.options.is_compressed())?
|
||||||
);
|
);
|
||||||
if !args.is_empty() {
|
if !args.is_empty() {
|
||||||
string.push_str(", ");
|
string.push_str(", ");
|
||||||
string.push_str(&args.get_err(3, "alpha")?.to_css_string(args.span())?);
|
string.push_str(
|
||||||
|
&args
|
||||||
|
.get_err(3, "alpha")?
|
||||||
|
.to_css_string(args.span(), parser.options.is_compressed())?,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
string.push(')');
|
string.push(')');
|
||||||
return Ok(Value::String(string, QuoteKind::None));
|
return Ok(Value::String(string, QuoteKind::None));
|
||||||
@ -238,7 +247,7 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser) -> Sas
|
|||||||
return Err((
|
return Err((
|
||||||
format!(
|
format!(
|
||||||
"$green: Expected {} to have no units or \"%\".",
|
"$green: Expected {} to have no units or \"%\".",
|
||||||
v.to_css_string(args.span())?
|
v.to_css_string(args.span(), parser.options.is_compressed())?
|
||||||
),
|
),
|
||||||
args.span(),
|
args.span(),
|
||||||
)
|
)
|
||||||
@ -249,13 +258,17 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser) -> Sas
|
|||||||
let mut string = format!(
|
let mut string = format!(
|
||||||
"{}({}, {}, {}",
|
"{}({}, {}, {}",
|
||||||
name,
|
name,
|
||||||
red,
|
red.to_string(parser.options.is_compressed()),
|
||||||
v.to_css_string(args.span())?,
|
v.to_css_string(args.span(), parser.options.is_compressed())?,
|
||||||
blue.to_css_string(args.span())?
|
blue.to_css_string(args.span(), parser.options.is_compressed())?
|
||||||
);
|
);
|
||||||
if !args.is_empty() {
|
if !args.is_empty() {
|
||||||
string.push_str(", ");
|
string.push_str(", ");
|
||||||
string.push_str(&args.get_err(3, "alpha")?.to_css_string(args.span())?);
|
string.push_str(
|
||||||
|
&args
|
||||||
|
.get_err(3, "alpha")?
|
||||||
|
.to_css_string(args.span(), parser.options.is_compressed())?,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
string.push(')');
|
string.push(')');
|
||||||
return Ok(Value::String(string, QuoteKind::None));
|
return Ok(Value::String(string, QuoteKind::None));
|
||||||
@ -278,7 +291,7 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser) -> Sas
|
|||||||
return Err((
|
return Err((
|
||||||
format!(
|
format!(
|
||||||
"$blue: Expected {} to have no units or \"%\".",
|
"$blue: Expected {} to have no units or \"%\".",
|
||||||
v.to_css_string(args.span())?
|
v.to_css_string(args.span(), parser.options.is_compressed())?
|
||||||
),
|
),
|
||||||
args.span(),
|
args.span(),
|
||||||
)
|
)
|
||||||
@ -288,13 +301,17 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser) -> Sas
|
|||||||
let mut string = format!(
|
let mut string = format!(
|
||||||
"{}({}, {}, {}",
|
"{}({}, {}, {}",
|
||||||
name,
|
name,
|
||||||
red,
|
red.to_string(parser.options.is_compressed()),
|
||||||
green,
|
green.to_string(parser.options.is_compressed()),
|
||||||
v.to_css_string(args.span())?
|
v.to_css_string(args.span(), parser.options.is_compressed())?
|
||||||
);
|
);
|
||||||
if !args.is_empty() {
|
if !args.is_empty() {
|
||||||
string.push_str(", ");
|
string.push_str(", ");
|
||||||
string.push_str(&args.get_err(3, "alpha")?.to_css_string(args.span())?);
|
string.push_str(
|
||||||
|
&args
|
||||||
|
.get_err(3, "alpha")?
|
||||||
|
.to_css_string(args.span(), parser.options.is_compressed())?,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
string.push(')');
|
string.push(')');
|
||||||
return Ok(Value::String(string, QuoteKind::None));
|
return Ok(Value::String(string, QuoteKind::None));
|
||||||
@ -319,7 +336,7 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser) -> Sas
|
|||||||
return Err((
|
return Err((
|
||||||
format!(
|
format!(
|
||||||
"$alpha: Expected {} to have no units or \"%\".",
|
"$alpha: Expected {} to have no units or \"%\".",
|
||||||
v.to_css_string(args.span())?
|
v.to_css_string(args.span(), parser.options.is_compressed())?
|
||||||
),
|
),
|
||||||
args.span(),
|
args.span(),
|
||||||
)
|
)
|
||||||
@ -329,10 +346,10 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser) -> Sas
|
|||||||
let string = format!(
|
let string = format!(
|
||||||
"{}({}, {}, {}, {})",
|
"{}({}, {}, {}, {})",
|
||||||
name,
|
name,
|
||||||
red,
|
red.to_string(parser.options.is_compressed()),
|
||||||
green,
|
green.to_string(parser.options.is_compressed()),
|
||||||
blue,
|
blue.to_string(parser.options.is_compressed()),
|
||||||
v.to_css_string(args.span())?
|
v.to_css_string(args.span(), parser.options.is_compressed())?
|
||||||
);
|
);
|
||||||
return Ok(Value::String(string, QuoteKind::None));
|
return Ok(Value::String(string, QuoteKind::None));
|
||||||
}
|
}
|
||||||
@ -429,7 +446,7 @@ pub(crate) fn mix(mut args: CallArgs, parser: &mut Parser) -> SassResult<Value>
|
|||||||
return Err((
|
return Err((
|
||||||
format!(
|
format!(
|
||||||
"$weight: {} is not a number.",
|
"$weight: {} is not a number.",
|
||||||
v.to_css_string(args.span())?
|
v.to_css_string(args.span(), parser.options.is_compressed())?
|
||||||
),
|
),
|
||||||
args.span(),
|
args.span(),
|
||||||
)
|
)
|
||||||
|
@ -45,7 +45,7 @@ pub(crate) fn nth(mut args: CallArgs, parser: &mut Parser) -> SassResult<Value>
|
|||||||
return Err((
|
return Err((
|
||||||
format!(
|
format!(
|
||||||
"$n: Invalid index {}{} for a list with {} elements.",
|
"$n: Invalid index {}{} for a list with {} elements.",
|
||||||
n,
|
n.inspect(),
|
||||||
unit,
|
unit,
|
||||||
list.len()
|
list.len()
|
||||||
),
|
),
|
||||||
@ -55,7 +55,7 @@ pub(crate) fn nth(mut args: CallArgs, parser: &mut Parser) -> SassResult<Value>
|
|||||||
}
|
}
|
||||||
|
|
||||||
if n.is_decimal() {
|
if n.is_decimal() {
|
||||||
return Err((format!("$n: {} is not an int.", n), args.span()).into());
|
return Err((format!("$n: {} is not an int.", n.inspect()), args.span()).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(list.remove(if n.is_positive() {
|
Ok(list.remove(if n.is_positive() {
|
||||||
@ -114,7 +114,9 @@ pub(crate) fn set_nth(mut args: CallArgs, parser: &mut Parser) -> SassResult<Val
|
|||||||
return Err((
|
return Err((
|
||||||
format!(
|
format!(
|
||||||
"$n: Invalid index {}{} for a list with {} elements.",
|
"$n: Invalid index {}{} for a list with {} elements.",
|
||||||
n, unit, len
|
n.inspect(),
|
||||||
|
unit,
|
||||||
|
len
|
||||||
),
|
),
|
||||||
args.span(),
|
args.span(),
|
||||||
)
|
)
|
||||||
@ -122,7 +124,7 @@ pub(crate) fn set_nth(mut args: CallArgs, parser: &mut Parser) -> SassResult<Val
|
|||||||
}
|
}
|
||||||
|
|
||||||
if n.is_decimal() {
|
if n.is_decimal() {
|
||||||
return Err((format!("$n: {} is not an int.", n), args.span()).into());
|
return Err((format!("$n: {} is not an int.", n.inspect()), args.span()).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let val = args.get_err(2, "value")?;
|
let val = args.get_err(2, "value")?;
|
||||||
|
@ -4,7 +4,13 @@ macro_rules! bound {
|
|||||||
return Err((
|
return Err((
|
||||||
format!(
|
format!(
|
||||||
"${}: Expected {}{} to be within {}{} and {}{}.",
|
"${}: Expected {}{} to be within {}{} and {}{}.",
|
||||||
$name, $arg, $unit, $low, $unit, $high, $unit,
|
$name,
|
||||||
|
$arg.inspect(),
|
||||||
|
$unit,
|
||||||
|
$low,
|
||||||
|
$unit,
|
||||||
|
$high,
|
||||||
|
$unit,
|
||||||
),
|
),
|
||||||
$args.span(),
|
$args.span(),
|
||||||
)
|
)
|
||||||
@ -18,7 +24,13 @@ macro_rules! bound {
|
|||||||
return Err((
|
return Err((
|
||||||
format!(
|
format!(
|
||||||
"${}: Expected {}{} to be within {}{} and {}{}.",
|
"${}: Expected {}{} to be within {}{} and {}{}.",
|
||||||
$name, $arg, $unit, $low, $unit, $high, $unit,
|
$name,
|
||||||
|
$arg.inspect(),
|
||||||
|
$unit,
|
||||||
|
$low,
|
||||||
|
$unit,
|
||||||
|
$high,
|
||||||
|
$unit,
|
||||||
),
|
),
|
||||||
$args.span(),
|
$args.span(),
|
||||||
)
|
)
|
||||||
|
@ -149,12 +149,16 @@ pub(crate) fn random(mut args: CallArgs, parser: &mut Parser) -> SassResult<Valu
|
|||||||
}
|
}
|
||||||
|
|
||||||
if limit.is_decimal() {
|
if limit.is_decimal() {
|
||||||
return Err((format!("$limit: {} is not an int.", limit), args.span()).into());
|
return Err((
|
||||||
|
format!("$limit: {} is not an int.", limit.inspect()),
|
||||||
|
args.span(),
|
||||||
|
)
|
||||||
|
.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
if limit.is_zero() || limit.is_negative() {
|
if limit.is_zero() || limit.is_negative() {
|
||||||
return Err((
|
return Err((
|
||||||
format!("$limit: Must be greater than 0, was {}.", limit),
|
format!("$limit: Must be greater than 0, was {}.", limit.inspect()),
|
||||||
args.span(),
|
args.span(),
|
||||||
)
|
)
|
||||||
.into());
|
.into());
|
||||||
@ -164,7 +168,10 @@ pub(crate) fn random(mut args: CallArgs, parser: &mut Parser) -> SassResult<Valu
|
|||||||
Some(n) => n,
|
Some(n) => n,
|
||||||
None => {
|
None => {
|
||||||
return Err((
|
return Err((
|
||||||
format!("max must be in range 0 < max \u{2264} 2^32, was {}", limit),
|
format!(
|
||||||
|
"max must be in range 0 < max \u{2264} 2^32, was {}",
|
||||||
|
limit.inspect()
|
||||||
|
),
|
||||||
args.span(),
|
args.span(),
|
||||||
)
|
)
|
||||||
.into())
|
.into())
|
||||||
|
@ -100,7 +100,7 @@ pub(crate) fn str_slice(mut args: CallArgs, parser: &mut Parser) -> SassResult<V
|
|||||||
let str_len = string.chars().count();
|
let str_len = string.chars().count();
|
||||||
let start = match args.get_err(1, "start-at")? {
|
let start = match args.get_err(1, "start-at")? {
|
||||||
Value::Dimension(Some(n), Unit::None, _) if n.is_decimal() => {
|
Value::Dimension(Some(n), Unit::None, _) if n.is_decimal() => {
|
||||||
return Err((format!("{} is not an int.", n), args.span()).into())
|
return Err((format!("{} is not an int.", n.inspect()), args.span()).into())
|
||||||
}
|
}
|
||||||
Value::Dimension(Some(n), Unit::None, _) if n.is_positive() => {
|
Value::Dimension(Some(n), Unit::None, _) if n.is_positive() => {
|
||||||
n.to_integer().to_usize().unwrap_or(str_len + 1)
|
n.to_integer().to_usize().unwrap_or(str_len + 1)
|
||||||
@ -133,7 +133,7 @@ pub(crate) fn str_slice(mut args: CallArgs, parser: &mut Parser) -> SassResult<V
|
|||||||
};
|
};
|
||||||
let mut end = match args.default_arg(2, "end-at", Value::Null)? {
|
let mut end = match args.default_arg(2, "end-at", Value::Null)? {
|
||||||
Value::Dimension(Some(n), Unit::None, _) if n.is_decimal() => {
|
Value::Dimension(Some(n), Unit::None, _) if n.is_decimal() => {
|
||||||
return Err((format!("{} is not an int.", n), args.span()).into())
|
return Err((format!("{} is not an int.", n.inspect()), args.span()).into())
|
||||||
}
|
}
|
||||||
Value::Dimension(Some(n), Unit::None, _) if n.is_positive() => {
|
Value::Dimension(Some(n), Unit::None, _) if n.is_positive() => {
|
||||||
n.to_integer().to_usize().unwrap_or(str_len + 1)
|
n.to_integer().to_usize().unwrap_or(str_len + 1)
|
||||||
@ -240,7 +240,11 @@ pub(crate) fn str_insert(mut args: CallArgs, parser: &mut Parser) -> SassResult<
|
|||||||
|
|
||||||
let index = match args.get_err(2, "index")? {
|
let index = match args.get_err(2, "index")? {
|
||||||
Value::Dimension(Some(n), Unit::None, _) if n.is_decimal() => {
|
Value::Dimension(Some(n), Unit::None, _) if n.is_decimal() => {
|
||||||
return Err((format!("$index: {} is not an int.", n), args.span()).into())
|
return Err((
|
||||||
|
format!("$index: {} is not an int.", n.inspect()),
|
||||||
|
args.span(),
|
||||||
|
)
|
||||||
|
.into())
|
||||||
}
|
}
|
||||||
Value::Dimension(Some(n), Unit::None, _) => n,
|
Value::Dimension(Some(n), Unit::None, _) => n,
|
||||||
Value::Dimension(None, Unit::None, ..) => {
|
Value::Dimension(None, Unit::None, ..) => {
|
||||||
|
@ -590,7 +590,14 @@ fn repr(red: &Number, green: &Number, blue: &Number, alpha: &Number) -> String {
|
|||||||
let blue_u8 = into_u8(blue);
|
let blue_u8 = into_u8(blue);
|
||||||
|
|
||||||
if alpha < &Number::one() {
|
if alpha < &Number::one() {
|
||||||
format!("rgba({}, {}, {}, {})", red_u8, green_u8, blue_u8, alpha)
|
format!(
|
||||||
|
"rgba({}, {}, {}, {})",
|
||||||
|
red_u8,
|
||||||
|
green_u8,
|
||||||
|
blue_u8,
|
||||||
|
// todo: is_compressed
|
||||||
|
alpha.inspect()
|
||||||
|
)
|
||||||
} else if let Some(c) = NAMED_COLORS.get_by_rgba([red_u8, green_u8, blue_u8]) {
|
} else if let Some(c) = NAMED_COLORS.get_by_rgba([red_u8, green_u8, blue_u8]) {
|
||||||
(*c).to_owned()
|
(*c).to_owned()
|
||||||
} else {
|
} else {
|
||||||
|
@ -99,6 +99,13 @@ impl ListSeparator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn as_compressed_str(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::Space => " ",
|
||||||
|
Self::Comma => ",",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn name(self) -> &'static str {
|
pub fn name(self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
Self::Space => "space",
|
Self::Space => "space",
|
||||||
|
@ -260,6 +260,10 @@ impl<'a> Options<'a> {
|
|||||||
self.unicode_error_messages = unicode_error_messages;
|
self.unicode_error_messages = unicode_error_messages;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn is_compressed(&self) -> bool {
|
||||||
|
matches!(self.style, OutputStyle::Compressed)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn raw_to_parse_error(map: &CodeMap, err: Error, unicode: bool) -> Box<Error> {
|
fn raw_to_parse_error(map: &CodeMap, err: Error, unicode: bool) -> Box<Error> {
|
||||||
|
@ -511,7 +511,7 @@ impl Formatter for CompressedFormatter {
|
|||||||
write!(buf, "}}")?;
|
write!(buf, "}}")?;
|
||||||
}
|
}
|
||||||
Toplevel::Style(style) => {
|
Toplevel::Style(style) => {
|
||||||
let value = style.value.node.to_css_string(style.value.span)?;
|
let value = style.value.node.to_css_string(style.value.span, true)?;
|
||||||
write!(buf, "{}:{};", style.property, value)?;
|
write!(buf, "{}:{};", style.property, value)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -542,7 +542,7 @@ impl CompressedFormatter {
|
|||||||
for style in &mut styles {
|
for style in &mut styles {
|
||||||
match style {
|
match style {
|
||||||
BlockEntry::Style(s) => {
|
BlockEntry::Style(s) => {
|
||||||
let value = s.value.node.to_css_string(s.value.span)?;
|
let value = s.value.node.to_css_string(s.value.span, true)?;
|
||||||
write!(buf, "{}:{}", s.property, value)?;
|
write!(buf, "{}:{}", s.property, value)?;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -554,7 +554,7 @@ impl CompressedFormatter {
|
|||||||
for style in styles {
|
for style in styles {
|
||||||
match style {
|
match style {
|
||||||
BlockEntry::Style(s) => {
|
BlockEntry::Style(s) => {
|
||||||
let value = s.value.node.to_css_string(s.value.span)?;
|
let value = s.value.node.to_css_string(s.value.span, true)?;
|
||||||
|
|
||||||
write!(buf, ";{}:{}", s.property, value)?;
|
write!(buf, ";{}:{}", s.property, value)?;
|
||||||
}
|
}
|
||||||
|
@ -299,8 +299,11 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||||||
|
|
||||||
let value = format!(
|
let value = format!(
|
||||||
"{}={}",
|
"{}={}",
|
||||||
left.node.to_css_string(left.span)?,
|
left.node
|
||||||
right.node.to_css_string(right.span)?
|
.to_css_string(left.span, self.options.is_compressed())?,
|
||||||
|
right
|
||||||
|
.node
|
||||||
|
.to_css_string(right.span, self.options.is_compressed())?
|
||||||
);
|
);
|
||||||
|
|
||||||
args.insert(
|
args.insert(
|
||||||
|
@ -211,7 +211,7 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||||||
let from = match from_val.node {
|
let from = match from_val.node {
|
||||||
Value::Dimension(Some(n), ..) => match n.to_i32() {
|
Value::Dimension(Some(n), ..) => match n.to_i32() {
|
||||||
Some(std::i32::MAX) | Some(std::i32::MIN) | None => {
|
Some(std::i32::MAX) | Some(std::i32::MIN) | None => {
|
||||||
return Err((format!("{} is not an int.", n), from_val.span).into())
|
return Err((format!("{} is not an int.", n.inspect()), from_val.span).into())
|
||||||
}
|
}
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
},
|
},
|
||||||
@ -229,14 +229,17 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||||||
let to = match to_val.node {
|
let to = match to_val.node {
|
||||||
Value::Dimension(Some(n), ..) => match n.to_i32() {
|
Value::Dimension(Some(n), ..) => match n.to_i32() {
|
||||||
Some(std::i32::MAX) | Some(std::i32::MIN) | None => {
|
Some(std::i32::MAX) | Some(std::i32::MIN) | None => {
|
||||||
return Err((format!("{} is not an int.", n), to_val.span).into())
|
return Err((format!("{} is not an int.", n.inspect()), to_val.span).into())
|
||||||
}
|
}
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
},
|
},
|
||||||
Value::Dimension(None, ..) => return Err(("NaN is not an int.", from_val.span).into()),
|
Value::Dimension(None, ..) => return Err(("NaN is not an int.", from_val.span).into()),
|
||||||
v => {
|
v => {
|
||||||
return Err((
|
return Err((
|
||||||
format!("{} is not a number.", v.to_css_string(to_val.span)?),
|
format!(
|
||||||
|
"{} is not a number.",
|
||||||
|
v.to_css_string(to_val.span, self.options.is_compressed())?
|
||||||
|
),
|
||||||
to_val.span,
|
to_val.span,
|
||||||
)
|
)
|
||||||
.into())
|
.into())
|
||||||
|
@ -64,7 +64,11 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||||||
self.toks.next();
|
self.toks.next();
|
||||||
// TODO: if ident, interpolate literally
|
// TODO: if ident, interpolate literally
|
||||||
let interpolation = self.parse_interpolation()?;
|
let interpolation = self.parse_interpolation()?;
|
||||||
buf.push_str(&interpolation.node.to_css_string(interpolation.span)?);
|
buf.push_str(
|
||||||
|
&interpolation
|
||||||
|
.node
|
||||||
|
.to_css_string(interpolation.span, self.options.is_compressed())?,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
self.toks.reset_cursor();
|
self.toks.reset_cursor();
|
||||||
break;
|
break;
|
||||||
@ -179,7 +183,10 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||||||
self.toks.next();
|
self.toks.next();
|
||||||
match self.parse_interpolation()?.node {
|
match self.parse_interpolation()?.node {
|
||||||
Value::String(ref s, ..) => text.push_str(s),
|
Value::String(ref s, ..) => text.push_str(s),
|
||||||
v => text.push_str(v.to_css_string(self.span_before)?.borrow()),
|
v => text.push_str(
|
||||||
|
v.to_css_string(self.span_before, self.options.is_compressed())?
|
||||||
|
.borrow(),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => return Err(("Expected identifier.", pos).into()),
|
_ => return Err(("Expected identifier.", pos).into()),
|
||||||
@ -268,7 +275,10 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||||||
let interpolation = self.parse_interpolation()?;
|
let interpolation = self.parse_interpolation()?;
|
||||||
match interpolation.node {
|
match interpolation.node {
|
||||||
Value::String(ref v, ..) => s.push_str(v),
|
Value::String(ref v, ..) => s.push_str(v),
|
||||||
v => s.push_str(v.to_css_string(interpolation.span)?.borrow()),
|
v => s.push_str(
|
||||||
|
v.to_css_string(interpolation.span, self.options.is_compressed())?
|
||||||
|
.borrow(),
|
||||||
|
),
|
||||||
};
|
};
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -126,7 +126,11 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||||||
match tok.kind {
|
match tok.kind {
|
||||||
'#' => {
|
'#' => {
|
||||||
if self.consume_char_if_exists('{') {
|
if self.consume_char_if_exists('{') {
|
||||||
string.push_str(&self.parse_interpolation()?.to_css_string(span)?);
|
string.push_str(
|
||||||
|
&self
|
||||||
|
.parse_interpolation()?
|
||||||
|
.to_css_string(span, self.options.is_compressed())?,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
string.push('#');
|
string.push('#');
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,10 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||||||
_ => false,
|
_ => false,
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
value.node.unquote().to_css_string(value.span)
|
value
|
||||||
|
.node
|
||||||
|
.unquote()
|
||||||
|
.to_css_string(value.span, self.options.is_compressed())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn parse_media_query_list(&mut self) -> SassResult<String> {
|
pub(super) fn parse_media_query_list(&mut self) -> SassResult<String> {
|
||||||
@ -92,7 +95,11 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||||||
})?;
|
})?;
|
||||||
self.expect_char(')')?;
|
self.expect_char(')')?;
|
||||||
|
|
||||||
buf.push_str(&value.node.to_css_string(value.span)?);
|
buf.push_str(
|
||||||
|
&value
|
||||||
|
.node
|
||||||
|
.to_css_string(value.span, self.options.is_compressed())?,
|
||||||
|
);
|
||||||
|
|
||||||
self.whitespace_or_comment();
|
self.whitespace_or_comment();
|
||||||
buf.push(')');
|
buf.push(')');
|
||||||
|
@ -210,7 +210,7 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||||||
self.consume_char_if_exists(';');
|
self.consume_char_if_exists(';');
|
||||||
|
|
||||||
self.warn(&Spanned {
|
self.warn(&Spanned {
|
||||||
node: message.to_css_string(span)?,
|
node: message.to_css_string(span, false)?,
|
||||||
span,
|
span,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -407,7 +407,11 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||||||
match kind {
|
match kind {
|
||||||
'#' => {
|
'#' => {
|
||||||
if self.consume_char_if_exists('{') {
|
if self.consume_char_if_exists('{') {
|
||||||
string.push_str(&self.parse_interpolation()?.to_css_string(span)?);
|
string.push_str(
|
||||||
|
&self
|
||||||
|
.parse_interpolation()?
|
||||||
|
.to_css_string(span, self.options.is_compressed())?,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
string.push('#');
|
string.push('#');
|
||||||
}
|
}
|
||||||
@ -513,7 +517,11 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||||||
}
|
}
|
||||||
('#', Some(Token { kind: '{', .. })) => {
|
('#', Some(Token { kind: '{', .. })) => {
|
||||||
self.toks.next();
|
self.toks.next();
|
||||||
comment.push_str(&self.parse_interpolation()?.to_css_string(span)?);
|
comment.push_str(
|
||||||
|
&self
|
||||||
|
.parse_interpolation()?
|
||||||
|
.to_css_string(span, self.options.is_compressed())?,
|
||||||
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
(..) => comment.push(tok.kind),
|
(..) => comment.push(tok.kind),
|
||||||
@ -541,7 +549,7 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||||||
let interpolation = self.parse_interpolation()?;
|
let interpolation = self.parse_interpolation()?;
|
||||||
Ok(match interpolation.node {
|
Ok(match interpolation.node {
|
||||||
Value::String(v, ..) => Cow::owned(v),
|
Value::String(v, ..) => Cow::owned(v),
|
||||||
v => v.to_css_string(interpolation.span)?,
|
v => v.to_css_string(interpolation.span, self.options.is_compressed())?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -855,7 +863,7 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||||||
return Err((
|
return Err((
|
||||||
format!(
|
format!(
|
||||||
"compound selectors may no longer be extended.\nConsider `@extend {}` instead.\nSee http://bit.ly/ExtendCompound for details.\n",
|
"compound selectors may no longer be extended.\nConsider `@extend {}` instead.\nSee http://bit.ly/ExtendCompound for details.\n",
|
||||||
compound.components.iter().map(|x| x.to_string()).collect::<Vec<String>>().join(", ")
|
compound.components.iter().map(ToString::to_string).collect::<Vec<String>>().join(", ")
|
||||||
)
|
)
|
||||||
, self.span_before).into());
|
, self.span_before).into());
|
||||||
}
|
}
|
||||||
@ -922,7 +930,11 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||||||
self.toks.next();
|
self.toks.next();
|
||||||
self.span_before = pos;
|
self.span_before = pos;
|
||||||
let interpolation = self.parse_interpolation()?;
|
let interpolation = self.parse_interpolation()?;
|
||||||
params.push_str(&interpolation.node.to_css_string(interpolation.span)?);
|
params.push_str(
|
||||||
|
&interpolation
|
||||||
|
.node
|
||||||
|
.to_css_string(interpolation.span, self.options.is_compressed())?,
|
||||||
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,7 +197,9 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let Spanned { node: module, span } = self.parse_quoted_string(quote)?;
|
let Spanned { node: module, span } = self.parse_quoted_string(quote)?;
|
||||||
let module_name = module.unquote().to_css_string(span)?;
|
let module_name = module
|
||||||
|
.unquote()
|
||||||
|
.to_css_string(span, self.options.is_compressed())?;
|
||||||
|
|
||||||
self.whitespace_or_comment();
|
self.whitespace_or_comment();
|
||||||
|
|
||||||
|
@ -20,7 +20,11 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||||||
self.span_before = pos;
|
self.span_before = pos;
|
||||||
self.toks.next();
|
self.toks.next();
|
||||||
let interpolation = self.parse_interpolation()?;
|
let interpolation = self.parse_interpolation()?;
|
||||||
buf.push_str(&interpolation.node.to_css_string(interpolation.span)?);
|
buf.push_str(
|
||||||
|
&interpolation
|
||||||
|
.node
|
||||||
|
.to_css_string(interpolation.span, self.options.is_compressed())?,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
buf.push('#');
|
buf.push('#');
|
||||||
}
|
}
|
||||||
@ -93,7 +97,10 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||||||
let interpolation = self.parse_interpolation()?;
|
let interpolation = self.parse_interpolation()?;
|
||||||
match interpolation.node {
|
match interpolation.node {
|
||||||
Value::String(ref s, ..) => buf.push_str(s),
|
Value::String(ref s, ..) => buf.push_str(s),
|
||||||
v => buf.push_str(v.to_css_string(interpolation.span)?.borrow()),
|
v => buf.push_str(
|
||||||
|
v.to_css_string(interpolation.span, self.options.is_compressed())?
|
||||||
|
.borrow(),
|
||||||
|
),
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
buf.push('#');
|
buf.push('#');
|
||||||
@ -142,7 +149,11 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||||||
match kind {
|
match kind {
|
||||||
'+' | '-' | '0'..='9' => {
|
'+' | '-' | '0'..='9' => {
|
||||||
let number = self.parse_dimension(&|_| false)?;
|
let number = self.parse_dimension(&|_| false)?;
|
||||||
buf.push_str(&number.node.to_css_string(number.span)?);
|
buf.push_str(
|
||||||
|
&number
|
||||||
|
.node
|
||||||
|
.to_css_string(number.span, self.options.is_compressed())?,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
'#' => {
|
'#' => {
|
||||||
self.toks.next();
|
self.toks.next();
|
||||||
@ -316,7 +327,7 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||||||
q @ ('"' | '\'') => {
|
q @ ('"' | '\'') => {
|
||||||
self.toks.next();
|
self.toks.next();
|
||||||
let s = self.parse_quoted_string(q)?;
|
let s = self.parse_quoted_string(q)?;
|
||||||
buffer.push_str(&s.node.to_css_string(s.span)?);
|
buffer.push_str(&s.node.to_css_string(s.span, self.options.is_compressed())?);
|
||||||
wrote_newline = false;
|
wrote_newline = false;
|
||||||
}
|
}
|
||||||
'/' => {
|
'/' => {
|
||||||
|
@ -122,14 +122,26 @@ impl<'a, 'b: 'a, 'c> ValueVisitor<'a, 'b, 'c> {
|
|||||||
Value::Dimension(Some(-n), u, should_divide)
|
Value::Dimension(Some(-n), u, should_divide)
|
||||||
}
|
}
|
||||||
Value::Dimension(None, u, should_divide) => Value::Dimension(None, u, should_divide),
|
Value::Dimension(None, u, should_divide) => Value::Dimension(None, u, should_divide),
|
||||||
v => Value::String(format!("-{}", v.to_css_string(self.span)?), QuoteKind::None),
|
v => Value::String(
|
||||||
|
format!(
|
||||||
|
"-{}",
|
||||||
|
v.to_css_string(self.span, self.parser.options.is_compressed())?
|
||||||
|
),
|
||||||
|
QuoteKind::None,
|
||||||
|
),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unary_plus(&self, val: Value) -> SassResult<Value> {
|
fn unary_plus(&self, val: Value) -> SassResult<Value> {
|
||||||
Ok(match val {
|
Ok(match val {
|
||||||
v @ Value::Dimension(..) => v,
|
v @ Value::Dimension(..) => v,
|
||||||
v => Value::String(format!("+{}", v.to_css_string(self.span)?), QuoteKind::None),
|
v => Value::String(
|
||||||
|
format!(
|
||||||
|
"+{}",
|
||||||
|
v.to_css_string(self.span, self.parser.options.is_compressed())?
|
||||||
|
),
|
||||||
|
QuoteKind::None,
|
||||||
|
),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,28 +188,36 @@ impl<'a, 'b: 'a, 'c> ValueVisitor<'a, 'b, 'c> {
|
|||||||
}
|
}
|
||||||
Value::True | Value::False => match right {
|
Value::True | Value::False => match right {
|
||||||
Value::String(s, QuoteKind::Quoted) => Value::String(
|
Value::String(s, QuoteKind::Quoted) => Value::String(
|
||||||
format!("{}{}", left.to_css_string(self.span)?, s),
|
format!(
|
||||||
|
"{}{}",
|
||||||
|
left.to_css_string(self.span, self.parser.options.is_compressed())?,
|
||||||
|
s
|
||||||
|
),
|
||||||
QuoteKind::Quoted,
|
QuoteKind::Quoted,
|
||||||
),
|
),
|
||||||
_ => Value::String(
|
_ => Value::String(
|
||||||
format!(
|
format!(
|
||||||
"{}{}",
|
"{}{}",
|
||||||
left.to_css_string(self.span)?,
|
left.to_css_string(self.span, self.parser.options.is_compressed())?,
|
||||||
right.to_css_string(self.span)?
|
right.to_css_string(self.span, self.parser.options.is_compressed())?
|
||||||
),
|
),
|
||||||
QuoteKind::None,
|
QuoteKind::None,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
Value::Important => match right {
|
Value::Important => match right {
|
||||||
Value::String(s, ..) => Value::String(
|
Value::String(s, ..) => Value::String(
|
||||||
format!("{}{}", left.to_css_string(self.span)?, s),
|
format!(
|
||||||
|
"{}{}",
|
||||||
|
left.to_css_string(self.span, self.parser.options.is_compressed())?,
|
||||||
|
s
|
||||||
|
),
|
||||||
QuoteKind::None,
|
QuoteKind::None,
|
||||||
),
|
),
|
||||||
_ => Value::String(
|
_ => Value::String(
|
||||||
format!(
|
format!(
|
||||||
"{}{}",
|
"{}{}",
|
||||||
left.to_css_string(self.span)?,
|
left.to_css_string(self.span, self.parser.options.is_compressed())?,
|
||||||
right.to_css_string(self.span)?
|
right.to_css_string(self.span, self.parser.options.is_compressed())?
|
||||||
),
|
),
|
||||||
QuoteKind::None,
|
QuoteKind::None,
|
||||||
),
|
),
|
||||||
@ -205,7 +225,9 @@ impl<'a, 'b: 'a, 'c> ValueVisitor<'a, 'b, 'c> {
|
|||||||
Value::Null => match right {
|
Value::Null => match right {
|
||||||
Value::Null => Value::Null,
|
Value::Null => Value::Null,
|
||||||
_ => Value::String(
|
_ => Value::String(
|
||||||
right.to_css_string(self.span)?.into_owned(),
|
right
|
||||||
|
.to_css_string(self.span, self.parser.options.is_compressed())?
|
||||||
|
.into_owned(),
|
||||||
QuoteKind::None,
|
QuoteKind::None,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@ -230,14 +252,34 @@ impl<'a, 'b: 'a, 'c> ValueVisitor<'a, 'b, 'c> {
|
|||||||
Value::Dimension(Some(num + num2.convert(&unit2, &unit)), unit, true)
|
Value::Dimension(Some(num + num2.convert(&unit2, &unit)), unit, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Value::String(s, q) => Value::String(format!("{}{}{}", num, unit, s), q),
|
Value::String(s, q) => Value::String(
|
||||||
Value::Null => Value::String(format!("{}{}", num, unit), QuoteKind::None),
|
format!(
|
||||||
|
"{}{}{}",
|
||||||
|
num.to_string(self.parser.options.is_compressed()),
|
||||||
|
unit,
|
||||||
|
s
|
||||||
|
),
|
||||||
|
q,
|
||||||
|
),
|
||||||
|
Value::Null => Value::String(
|
||||||
|
format!(
|
||||||
|
"{}{}",
|
||||||
|
num.to_string(self.parser.options.is_compressed()),
|
||||||
|
unit
|
||||||
|
),
|
||||||
|
QuoteKind::None,
|
||||||
|
),
|
||||||
Value::True
|
Value::True
|
||||||
| Value::False
|
| Value::False
|
||||||
| Value::List(..)
|
| Value::List(..)
|
||||||
| Value::Important
|
| Value::Important
|
||||||
| Value::ArgList(..) => Value::String(
|
| Value::ArgList(..) => Value::String(
|
||||||
format!("{}{}{}", num, unit, right.to_css_string(self.span)?),
|
format!(
|
||||||
|
"{}{}{}",
|
||||||
|
num.to_string(self.parser.options.is_compressed()),
|
||||||
|
unit,
|
||||||
|
right.to_css_string(self.span, self.parser.options.is_compressed())?
|
||||||
|
),
|
||||||
QuoteKind::None,
|
QuoteKind::None,
|
||||||
),
|
),
|
||||||
Value::Map(..) | Value::FunctionRef(..) => {
|
Value::Map(..) | Value::FunctionRef(..) => {
|
||||||
@ -251,7 +293,7 @@ impl<'a, 'b: 'a, 'c> ValueVisitor<'a, 'b, 'c> {
|
|||||||
return Err((
|
return Err((
|
||||||
format!(
|
format!(
|
||||||
"Undefined operation \"{}{} + {}\".",
|
"Undefined operation \"{}{} + {}\".",
|
||||||
num,
|
num.inspect(),
|
||||||
unit,
|
unit,
|
||||||
right.inspect(self.span)?
|
right.inspect(self.span)?
|
||||||
),
|
),
|
||||||
@ -264,7 +306,11 @@ impl<'a, 'b: 'a, 'c> ValueVisitor<'a, 'b, 'c> {
|
|||||||
Value::String(s, q) => Value::String(format!("{}{}", c, s), q),
|
Value::String(s, q) => Value::String(format!("{}{}", c, s), q),
|
||||||
Value::Null => Value::String(c.to_string(), QuoteKind::None),
|
Value::Null => Value::String(c.to_string(), QuoteKind::None),
|
||||||
Value::List(..) => Value::String(
|
Value::List(..) => Value::String(
|
||||||
format!("{}{}", c, right.to_css_string(self.span)?),
|
format!(
|
||||||
|
"{}{}",
|
||||||
|
c,
|
||||||
|
right.to_css_string(self.span, self.parser.options.is_compressed())?
|
||||||
|
),
|
||||||
QuoteKind::None,
|
QuoteKind::None,
|
||||||
),
|
),
|
||||||
_ => {
|
_ => {
|
||||||
@ -281,17 +327,25 @@ impl<'a, 'b: 'a, 'c> ValueVisitor<'a, 'b, 'c> {
|
|||||||
},
|
},
|
||||||
Value::String(text, quotes) => match right {
|
Value::String(text, quotes) => match right {
|
||||||
Value::String(text2, ..) => Value::String(text + &text2, quotes),
|
Value::String(text2, ..) => Value::String(text + &text2, quotes),
|
||||||
_ => Value::String(text + &right.to_css_string(self.span)?, quotes),
|
_ => Value::String(
|
||||||
|
text + &right.to_css_string(self.span, self.parser.options.is_compressed())?,
|
||||||
|
quotes,
|
||||||
|
),
|
||||||
},
|
},
|
||||||
Value::List(..) | Value::ArgList(..) => match right {
|
Value::List(..) | Value::ArgList(..) => match right {
|
||||||
Value::String(s, q) => {
|
Value::String(s, q) => Value::String(
|
||||||
Value::String(format!("{}{}", left.to_css_string(self.span)?, s), q)
|
format!(
|
||||||
}
|
"{}{}",
|
||||||
|
left.to_css_string(self.span, self.parser.options.is_compressed())?,
|
||||||
|
s
|
||||||
|
),
|
||||||
|
q,
|
||||||
|
),
|
||||||
_ => Value::String(
|
_ => Value::String(
|
||||||
format!(
|
format!(
|
||||||
"{}{}",
|
"{}{}",
|
||||||
left.to_css_string(self.span)?,
|
left.to_css_string(self.span, self.parser.options.is_compressed())?,
|
||||||
right.to_css_string(self.span)?
|
right.to_css_string(self.span, self.parser.options.is_compressed())?
|
||||||
),
|
),
|
||||||
QuoteKind::None,
|
QuoteKind::None,
|
||||||
),
|
),
|
||||||
@ -314,7 +368,10 @@ impl<'a, 'b: 'a, 'c> ValueVisitor<'a, 'b, 'c> {
|
|||||||
};
|
};
|
||||||
Ok(match left {
|
Ok(match left {
|
||||||
Value::Null => Value::String(
|
Value::Null => Value::String(
|
||||||
format!("-{}", right.to_css_string(self.span)?),
|
format!(
|
||||||
|
"-{}",
|
||||||
|
right.to_css_string(self.span, self.parser.options.is_compressed())?
|
||||||
|
),
|
||||||
QuoteKind::None,
|
QuoteKind::None,
|
||||||
),
|
),
|
||||||
v @ Value::Dimension(None, ..) => v,
|
v @ Value::Dimension(None, ..) => v,
|
||||||
@ -344,7 +401,12 @@ impl<'a, 'b: 'a, 'c> ValueVisitor<'a, 'b, 'c> {
|
|||||||
| Value::True
|
| Value::True
|
||||||
| Value::False
|
| Value::False
|
||||||
| Value::ArgList(..) => Value::String(
|
| Value::ArgList(..) => Value::String(
|
||||||
format!("{}{}-{}", num, unit, right.to_css_string(self.span)?),
|
format!(
|
||||||
|
"{}{}-{}",
|
||||||
|
num.to_string(self.parser.options.is_compressed()),
|
||||||
|
unit,
|
||||||
|
right.to_css_string(self.span, self.parser.options.is_compressed())?
|
||||||
|
),
|
||||||
QuoteKind::None,
|
QuoteKind::None,
|
||||||
),
|
),
|
||||||
Value::Map(..) | Value::FunctionRef(..) => {
|
Value::Map(..) | Value::FunctionRef(..) => {
|
||||||
@ -358,7 +420,7 @@ impl<'a, 'b: 'a, 'c> ValueVisitor<'a, 'b, 'c> {
|
|||||||
return Err((
|
return Err((
|
||||||
format!(
|
format!(
|
||||||
"Undefined operation \"{}{} - {}\".",
|
"Undefined operation \"{}{} - {}\".",
|
||||||
num,
|
num.inspect(),
|
||||||
unit,
|
unit,
|
||||||
right.inspect(self.span)?
|
right.inspect(self.span)?
|
||||||
),
|
),
|
||||||
@ -366,7 +428,14 @@ impl<'a, 'b: 'a, 'c> ValueVisitor<'a, 'b, 'c> {
|
|||||||
)
|
)
|
||||||
.into())
|
.into())
|
||||||
}
|
}
|
||||||
Value::Null => Value::String(format!("{}{}-", num, unit), QuoteKind::None),
|
Value::Null => Value::String(
|
||||||
|
format!(
|
||||||
|
"{}{}-",
|
||||||
|
num.to_string(self.parser.options.is_compressed()),
|
||||||
|
unit
|
||||||
|
),
|
||||||
|
QuoteKind::None,
|
||||||
|
),
|
||||||
},
|
},
|
||||||
Value::Color(c) => match right {
|
Value::Color(c) => match right {
|
||||||
Value::String(s, q) => {
|
Value::String(s, q) => {
|
||||||
@ -385,32 +454,45 @@ impl<'a, 'b: 'a, 'c> ValueVisitor<'a, 'b, 'c> {
|
|||||||
.into())
|
.into())
|
||||||
}
|
}
|
||||||
_ => Value::String(
|
_ => Value::String(
|
||||||
format!("{}-{}", c, right.to_css_string(self.span)?),
|
format!(
|
||||||
|
"{}-{}",
|
||||||
|
c,
|
||||||
|
right.to_css_string(self.span, self.parser.options.is_compressed())?
|
||||||
|
),
|
||||||
QuoteKind::None,
|
QuoteKind::None,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
Value::String(..) => Value::String(
|
Value::String(..) => Value::String(
|
||||||
format!(
|
format!(
|
||||||
"{}-{}",
|
"{}-{}",
|
||||||
left.to_css_string(self.span)?,
|
left.to_css_string(self.span, self.parser.options.is_compressed())?,
|
||||||
right.to_css_string(self.span)?
|
right.to_css_string(self.span, self.parser.options.is_compressed())?
|
||||||
),
|
),
|
||||||
QuoteKind::None,
|
QuoteKind::None,
|
||||||
),
|
),
|
||||||
_ => match right {
|
_ => match right {
|
||||||
Value::String(s, q) => Value::String(
|
Value::String(s, q) => Value::String(
|
||||||
format!("{}-{}{}{}", left.to_css_string(self.span)?, q, s, q),
|
format!(
|
||||||
|
"{}-{}{}{}",
|
||||||
|
left.to_css_string(self.span, self.parser.options.is_compressed())?,
|
||||||
|
q,
|
||||||
|
s,
|
||||||
|
q
|
||||||
|
),
|
||||||
QuoteKind::None,
|
QuoteKind::None,
|
||||||
),
|
),
|
||||||
Value::Null => Value::String(
|
Value::Null => Value::String(
|
||||||
format!("{}-", left.to_css_string(self.span)?),
|
format!(
|
||||||
|
"{}-",
|
||||||
|
left.to_css_string(self.span, self.parser.options.is_compressed())?
|
||||||
|
),
|
||||||
QuoteKind::None,
|
QuoteKind::None,
|
||||||
),
|
),
|
||||||
_ => Value::String(
|
_ => Value::String(
|
||||||
format!(
|
format!(
|
||||||
"{}-{}",
|
"{}-{}",
|
||||||
left.to_css_string(self.span)?,
|
left.to_css_string(self.span, self.parser.options.is_compressed())?,
|
||||||
right.to_css_string(self.span)?
|
right.to_css_string(self.span, self.parser.options.is_compressed())?
|
||||||
),
|
),
|
||||||
QuoteKind::None,
|
QuoteKind::None,
|
||||||
),
|
),
|
||||||
@ -448,7 +530,7 @@ impl<'a, 'b: 'a, 'c> ValueVisitor<'a, 'b, 'c> {
|
|||||||
return Err((
|
return Err((
|
||||||
format!(
|
format!(
|
||||||
"Undefined operation \"{}{} * {}\".",
|
"Undefined operation \"{}{} * {}\".",
|
||||||
num,
|
num.inspect(),
|
||||||
unit,
|
unit,
|
||||||
right.inspect(self.span)?
|
right.inspect(self.span)?
|
||||||
),
|
),
|
||||||
@ -487,7 +569,10 @@ impl<'a, 'b: 'a, 'c> ValueVisitor<'a, 'b, 'c> {
|
|||||||
};
|
};
|
||||||
Ok(match left {
|
Ok(match left {
|
||||||
Value::Null => Value::String(
|
Value::Null => Value::String(
|
||||||
format!("/{}", right.to_css_string(self.span)?),
|
format!(
|
||||||
|
"/{}",
|
||||||
|
right.to_css_string(self.span, self.parser.options.is_compressed())?
|
||||||
|
),
|
||||||
QuoteKind::None,
|
QuoteKind::None,
|
||||||
),
|
),
|
||||||
Value::Dimension(None, ..) => todo!(),
|
Value::Dimension(None, ..) => todo!(),
|
||||||
@ -537,24 +622,50 @@ impl<'a, 'b: 'a, 'c> ValueVisitor<'a, 'b, 'c> {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Value::String(
|
Value::String(
|
||||||
format!("{}{}/{}{}", num, unit, num2, unit2),
|
format!(
|
||||||
|
"{}{}/{}{}",
|
||||||
|
num.to_string(self.parser.options.is_compressed()),
|
||||||
|
unit,
|
||||||
|
num2.to_string(self.parser.options.is_compressed()),
|
||||||
|
unit2
|
||||||
|
),
|
||||||
QuoteKind::None,
|
QuoteKind::None,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Value::String(s, q) => {
|
Value::String(s, q) => Value::String(
|
||||||
Value::String(format!("{}{}/{}{}{}", num, unit, q, s, q), QuoteKind::None)
|
format!(
|
||||||
}
|
"{}{}/{}{}{}",
|
||||||
|
num.to_string(self.parser.options.is_compressed()),
|
||||||
|
unit,
|
||||||
|
q,
|
||||||
|
s,
|
||||||
|
q
|
||||||
|
),
|
||||||
|
QuoteKind::None,
|
||||||
|
),
|
||||||
Value::List(..)
|
Value::List(..)
|
||||||
| Value::True
|
| Value::True
|
||||||
| Value::False
|
| Value::False
|
||||||
| Value::Important
|
| Value::Important
|
||||||
| Value::Color(..)
|
| Value::Color(..)
|
||||||
| Value::ArgList(..) => Value::String(
|
| Value::ArgList(..) => Value::String(
|
||||||
format!("{}{}/{}", num, unit, right.to_css_string(self.span)?),
|
format!(
|
||||||
|
"{}{}/{}",
|
||||||
|
num.to_string(self.parser.options.is_compressed()),
|
||||||
|
unit,
|
||||||
|
right.to_css_string(self.span, self.parser.options.is_compressed())?
|
||||||
|
),
|
||||||
|
QuoteKind::None,
|
||||||
|
),
|
||||||
|
Value::Null => Value::String(
|
||||||
|
format!(
|
||||||
|
"{}{}/",
|
||||||
|
num.to_string(self.parser.options.is_compressed()),
|
||||||
|
unit
|
||||||
|
),
|
||||||
QuoteKind::None,
|
QuoteKind::None,
|
||||||
),
|
),
|
||||||
Value::Null => Value::String(format!("{}{}/", num, unit), QuoteKind::None),
|
|
||||||
Value::Map(..) | Value::FunctionRef(..) => {
|
Value::Map(..) | Value::FunctionRef(..) => {
|
||||||
return Err((
|
return Err((
|
||||||
format!("{} isn't a valid CSS value.", right.inspect(self.span)?),
|
format!("{} isn't a valid CSS value.", right.inspect(self.span)?),
|
||||||
@ -580,7 +691,11 @@ impl<'a, 'b: 'a, 'c> ValueVisitor<'a, 'b, 'c> {
|
|||||||
.into())
|
.into())
|
||||||
}
|
}
|
||||||
_ => Value::String(
|
_ => Value::String(
|
||||||
format!("{}/{}", c, right.to_css_string(self.span)?),
|
format!(
|
||||||
|
"{}/{}",
|
||||||
|
c,
|
||||||
|
right.to_css_string(self.span, self.parser.options.is_compressed())?
|
||||||
|
),
|
||||||
QuoteKind::None,
|
QuoteKind::None,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@ -596,7 +711,13 @@ impl<'a, 'b: 'a, 'c> ValueVisitor<'a, 'b, 'c> {
|
|||||||
| Value::Color(..)
|
| Value::Color(..)
|
||||||
| Value::List(..)
|
| Value::List(..)
|
||||||
| Value::ArgList(..) => Value::String(
|
| Value::ArgList(..) => Value::String(
|
||||||
format!("{}{}{}/{}", q1, s1, q1, right.to_css_string(self.span)?),
|
format!(
|
||||||
|
"{}{}{}/{}",
|
||||||
|
q1,
|
||||||
|
s1,
|
||||||
|
q1,
|
||||||
|
right.to_css_string(self.span, self.parser.options.is_compressed())?
|
||||||
|
),
|
||||||
QuoteKind::None,
|
QuoteKind::None,
|
||||||
),
|
),
|
||||||
Value::Null => Value::String(format!("{}{}{}/", q1, s1, q1), QuoteKind::None),
|
Value::Null => Value::String(format!("{}{}{}/", q1, s1, q1), QuoteKind::None),
|
||||||
@ -610,18 +731,27 @@ impl<'a, 'b: 'a, 'c> ValueVisitor<'a, 'b, 'c> {
|
|||||||
},
|
},
|
||||||
_ => match right {
|
_ => match right {
|
||||||
Value::String(s, q) => Value::String(
|
Value::String(s, q) => Value::String(
|
||||||
format!("{}/{}{}{}", left.to_css_string(self.span)?, q, s, q),
|
format!(
|
||||||
|
"{}/{}{}{}",
|
||||||
|
left.to_css_string(self.span, self.parser.options.is_compressed())?,
|
||||||
|
q,
|
||||||
|
s,
|
||||||
|
q
|
||||||
|
),
|
||||||
QuoteKind::None,
|
QuoteKind::None,
|
||||||
),
|
),
|
||||||
Value::Null => Value::String(
|
Value::Null => Value::String(
|
||||||
format!("{}/", left.to_css_string(self.span)?),
|
format!(
|
||||||
|
"{}/",
|
||||||
|
left.to_css_string(self.span, self.parser.options.is_compressed())?
|
||||||
|
),
|
||||||
QuoteKind::None,
|
QuoteKind::None,
|
||||||
),
|
),
|
||||||
_ => Value::String(
|
_ => Value::String(
|
||||||
format!(
|
format!(
|
||||||
"{}/{}",
|
"{}/{}",
|
||||||
left.to_css_string(self.span)?,
|
left.to_css_string(self.span, self.parser.options.is_compressed())?,
|
||||||
right.to_css_string(self.span)?
|
right.to_css_string(self.span, self.parser.options.is_compressed())?
|
||||||
),
|
),
|
||||||
QuoteKind::None,
|
QuoteKind::None,
|
||||||
),
|
),
|
||||||
|
@ -272,9 +272,17 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||||||
}
|
}
|
||||||
"url" => match self.try_parse_url()? {
|
"url" => match self.try_parse_url()? {
|
||||||
Some(val) => s = val,
|
Some(val) => s = val,
|
||||||
None => s.push_str(&self.parse_call_args()?.to_css_string()?),
|
None => s.push_str(
|
||||||
|
&self
|
||||||
|
.parse_call_args()?
|
||||||
|
.to_css_string(self.options.is_compressed())?,
|
||||||
|
),
|
||||||
},
|
},
|
||||||
_ => s.push_str(&self.parse_call_args()?.to_css_string()?),
|
_ => s.push_str(
|
||||||
|
&self
|
||||||
|
.parse_call_args()?
|
||||||
|
.to_css_string(self.options.is_compressed())?,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(IntermediateValue::Value(HigherIntermediateValue::Literal(
|
return Ok(IntermediateValue::Value(HigherIntermediateValue::Literal(
|
||||||
@ -1142,7 +1150,10 @@ impl<'a, 'b: 'a, 'c> IntermediateValueIterator<'a, 'b, 'c> {
|
|||||||
"/{}",
|
"/{}",
|
||||||
ValueVisitor::new(self.parser, right.span)
|
ValueVisitor::new(self.parser, right.span)
|
||||||
.eval(right.node, false)?
|
.eval(right.node, false)?
|
||||||
.to_css_string(right.span)?
|
.to_css_string(
|
||||||
|
right.span,
|
||||||
|
self.parser.options.is_compressed()
|
||||||
|
)?
|
||||||
),
|
),
|
||||||
QuoteKind::None,
|
QuoteKind::None,
|
||||||
)),
|
)),
|
||||||
@ -1348,7 +1359,7 @@ impl<'a, 'b: 'a, 'c> IntermediateValueIterator<'a, 'b, 'c> {
|
|||||||
"/{}",
|
"/{}",
|
||||||
ValueVisitor::new(self.parser, val.span)
|
ValueVisitor::new(self.parser, val.span)
|
||||||
.eval(val.node, false)?
|
.eval(val.node, false)?
|
||||||
.to_css_string(val.span)?
|
.to_css_string(val.span, self.parser.options.is_compressed())?
|
||||||
),
|
),
|
||||||
QuoteKind::None,
|
QuoteKind::None,
|
||||||
)),
|
)),
|
||||||
|
@ -189,7 +189,7 @@ impl Display for Attribute {
|
|||||||
// (also avoids the clone because we can consume/modify self)
|
// (also avoids the clone because we can consume/modify self)
|
||||||
f.write_str(
|
f.write_str(
|
||||||
&Value::String(self.value.clone(), QuoteKind::Quoted)
|
&Value::String(self.value.clone(), QuoteKind::Quoted)
|
||||||
.to_css_string(self.span)
|
.to_css_string(self.span, false)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
)?;
|
)?;
|
||||||
// todo: this space is not emitted when `compressed` output
|
// todo: this space is not emitted when `compressed` output
|
||||||
|
@ -14,7 +14,7 @@ impl Style {
|
|||||||
Ok(format!(
|
Ok(format!(
|
||||||
"{}: {};",
|
"{}: {};",
|
||||||
self.property,
|
self.property,
|
||||||
self.value.node.to_css_string(self.value.span)?
|
self.value.node.to_css_string(self.value.span, false)?
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -205,22 +205,28 @@ impl Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_css_string(&self, span: Span) -> SassResult<Cow<'static, str>> {
|
pub fn to_css_string(&self, span: Span, is_compressed: bool) -> SassResult<Cow<'static, str>> {
|
||||||
Ok(match self {
|
Ok(match self {
|
||||||
Value::Important => Cow::const_str("!important"),
|
Value::Important => Cow::const_str("!important"),
|
||||||
Value::Dimension(num, unit, _) => match unit {
|
Value::Dimension(num, unit, _) => match unit {
|
||||||
Unit::Mul(..) | Unit::Div(..) => {
|
Unit::Mul(..) | Unit::Div(..) => {
|
||||||
if let Some(num) = num {
|
if let Some(num) = num {
|
||||||
return Err(
|
return Err((
|
||||||
(format!("{}{} isn't a valid CSS value.", num, unit), span).into()
|
format!(
|
||||||
);
|
"{}{} isn't a valid CSS value.",
|
||||||
|
num.to_string(is_compressed),
|
||||||
|
unit
|
||||||
|
),
|
||||||
|
span,
|
||||||
|
)
|
||||||
|
.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
return Err((format!("NaN{} isn't a valid CSS value.", unit), span).into());
|
return Err((format!("NaN{} isn't a valid CSS value.", unit), span).into());
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
if let Some(num) = num {
|
if let Some(num) = num {
|
||||||
Cow::owned(format!("{}{}", num, unit))
|
Cow::owned(format!("{}{}", num.to_string(is_compressed), unit))
|
||||||
} else {
|
} else {
|
||||||
Cow::owned(format!("NaN{}", unit))
|
Cow::owned(format!("NaN{}", unit))
|
||||||
}
|
}
|
||||||
@ -237,17 +243,25 @@ impl Value {
|
|||||||
Brackets::None => Cow::owned(
|
Brackets::None => Cow::owned(
|
||||||
vals.iter()
|
vals.iter()
|
||||||
.filter(|x| !x.is_null())
|
.filter(|x| !x.is_null())
|
||||||
.map(|x| x.to_css_string(span))
|
.map(|x| x.to_css_string(span, is_compressed))
|
||||||
.collect::<SassResult<Vec<Cow<'static, str>>>>()?
|
.collect::<SassResult<Vec<Cow<'static, str>>>>()?
|
||||||
.join(sep.as_str()),
|
.join(if is_compressed {
|
||||||
|
sep.as_compressed_str()
|
||||||
|
} else {
|
||||||
|
sep.as_str()
|
||||||
|
}),
|
||||||
),
|
),
|
||||||
Brackets::Bracketed => Cow::owned(format!(
|
Brackets::Bracketed => Cow::owned(format!(
|
||||||
"[{}]",
|
"[{}]",
|
||||||
vals.iter()
|
vals.iter()
|
||||||
.filter(|x| !x.is_null())
|
.filter(|x| !x.is_null())
|
||||||
.map(|x| x.to_css_string(span))
|
.map(|x| x.to_css_string(span, is_compressed))
|
||||||
.collect::<SassResult<Vec<Cow<'static, str>>>>()?
|
.collect::<SassResult<Vec<Cow<'static, str>>>>()?
|
||||||
.join(sep.as_str()),
|
.join(if is_compressed {
|
||||||
|
sep.as_compressed_str()
|
||||||
|
} else {
|
||||||
|
sep.as_str()
|
||||||
|
}),
|
||||||
)),
|
)),
|
||||||
},
|
},
|
||||||
Value::Color(c) => Cow::owned(c.to_string()),
|
Value::Color(c) => Cow::owned(c.to_string()),
|
||||||
@ -287,9 +301,13 @@ impl Value {
|
|||||||
Value::ArgList(args) => Cow::owned(
|
Value::ArgList(args) => Cow::owned(
|
||||||
args.iter()
|
args.iter()
|
||||||
.filter(|x| !x.is_null())
|
.filter(|x| !x.is_null())
|
||||||
.map(|a| a.node.to_css_string(span))
|
.map(|a| a.node.to_css_string(span, is_compressed))
|
||||||
.collect::<SassResult<Vec<Cow<'static, str>>>>()?
|
.collect::<SassResult<Vec<Cow<'static, str>>>>()?
|
||||||
.join(", "),
|
.join(if is_compressed {
|
||||||
|
ListSeparator::Comma.as_compressed_str()
|
||||||
|
} else {
|
||||||
|
ListSeparator::Comma.as_str()
|
||||||
|
}),
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -466,7 +484,9 @@ impl Value {
|
|||||||
.collect::<SassResult<Vec<String>>>()?
|
.collect::<SassResult<Vec<String>>>()?
|
||||||
.join(", ")
|
.join(", ")
|
||||||
)),
|
)),
|
||||||
Value::Dimension(Some(num), unit, _) => Cow::owned(format!("{}{}", num, unit)),
|
Value::Dimension(Some(num), unit, _) => {
|
||||||
|
Cow::owned(format!("{}{}", num.inspect(), unit))
|
||||||
|
}
|
||||||
Value::Dimension(None, unit, ..) => Cow::owned(format!("NaN{}", unit)),
|
Value::Dimension(None, unit, ..) => Cow::owned(format!("NaN{}", unit)),
|
||||||
Value::ArgList(args) if args.is_empty() => Cow::const_str("()"),
|
Value::ArgList(args) if args.is_empty() => Cow::const_str("()"),
|
||||||
Value::ArgList(args) if args.len() == 1 => Cow::owned(format!(
|
Value::ArgList(args) if args.len() == 1 => Cow::owned(format!(
|
||||||
@ -488,7 +508,7 @@ impl Value {
|
|||||||
| Value::True
|
| Value::True
|
||||||
| Value::False
|
| Value::False
|
||||||
| Value::Color(..)
|
| Value::Color(..)
|
||||||
| Value::String(..) => self.to_css_string(span)?,
|
| Value::String(..) => self.to_css_string(span, false)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
use std::{
|
use std::{
|
||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
convert::{From, TryFrom},
|
convert::{From, TryFrom},
|
||||||
fmt::{self, Display, Write},
|
fmt, mem,
|
||||||
mem,
|
|
||||||
ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign},
|
ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -313,8 +312,8 @@ from_smaller_integer!(u8);
|
|||||||
impl fmt::Debug for Number {
|
impl fmt::Debug for Number {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::Small(..) => write!(f, "Number::Small( {} )", self),
|
Self::Small(..) => write!(f, "Number::Small( {} )", self.to_string(false)),
|
||||||
Self::Big(..) => write!(f, "Number::Big( {} )", self),
|
Self::Big(..) => write!(f, "Number::Big( {} )", self.to_string(false)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -355,16 +354,24 @@ impl ToPrimitive for Number {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Number {
|
impl Number {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
pub(crate) fn inspect(&self) -> String {
|
||||||
|
self.to_string(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn to_string(&self, is_compressed: bool) -> String {
|
||||||
let mut whole = self.to_integer().abs();
|
let mut whole = self.to_integer().abs();
|
||||||
let has_decimal = self.is_decimal();
|
let has_decimal = self.is_decimal();
|
||||||
let mut frac = self.abs().fract();
|
let mut frac = self.abs().fract();
|
||||||
let mut dec = String::with_capacity(if has_decimal { PRECISION } else { 0 });
|
let mut dec = String::with_capacity(if has_decimal { PRECISION } else { 0 });
|
||||||
|
|
||||||
|
let mut buf = String::new();
|
||||||
|
|
||||||
if has_decimal {
|
if has_decimal {
|
||||||
for _ in 0..(PRECISION - 1) {
|
for _ in 0..(PRECISION - 1) {
|
||||||
frac *= 10_i64;
|
frac *= 10_i64;
|
||||||
write!(dec, "{}", frac.to_integer())?;
|
dec.push_str(&frac.to_integer().to_string());
|
||||||
|
|
||||||
frac = frac.fract();
|
frac = frac.fract();
|
||||||
if frac.is_zero() {
|
if frac.is_zero() {
|
||||||
break;
|
break;
|
||||||
@ -398,20 +405,25 @@ impl Display for Number {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
write!(dec, "{}", end)?;
|
dec.push_str(&end.to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.is_negative() && (!whole.is_zero() || !dec.is_empty()) {
|
if self.is_negative() && (!whole.is_zero() || !dec.is_empty()) {
|
||||||
f.write_char('-')?;
|
buf.push('-');
|
||||||
}
|
}
|
||||||
write!(f, "{}", whole)?;
|
|
||||||
|
if !(whole.is_zero() && is_compressed) {
|
||||||
|
buf.push_str(&whole.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
if !dec.is_empty() {
|
if !dec.is_empty() {
|
||||||
f.write_char('.')?;
|
buf.push('.');
|
||||||
write!(f, "{}", dec)?;
|
buf.push_str(&dec);
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
|
buf
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,13 +13,6 @@ test!(
|
|||||||
"a{color:red;color:green;color:blue}",
|
"a{color:red;color:green;color:blue}",
|
||||||
grass::Options::default().style(grass::OutputStyle::Compressed)
|
grass::Options::default().style(grass::OutputStyle::Compressed)
|
||||||
);
|
);
|
||||||
test!(
|
|
||||||
#[ignore = "we don't support compressed values"]
|
|
||||||
strips_the_leading_zero,
|
|
||||||
"a {\n color: 0.5;\n}\n",
|
|
||||||
"a{color:.5}",
|
|
||||||
grass::Options::default().style(grass::OutputStyle::Compressed)
|
|
||||||
);
|
|
||||||
test!(
|
test!(
|
||||||
compresses_media_rule,
|
compresses_media_rule,
|
||||||
"@media foo {\n a {\n color: red;\n }\n}\n",
|
"@media foo {\n a {\n color: red;\n }\n}\n",
|
||||||
@ -86,3 +79,40 @@ test!(
|
|||||||
"a{color:red}b{color:green}",
|
"a{color:red}b{color:green}",
|
||||||
grass::Options::default().style(grass::OutputStyle::Compressed)
|
grass::Options::default().style(grass::OutputStyle::Compressed)
|
||||||
);
|
);
|
||||||
|
test!(
|
||||||
|
removes_spaces_in_comma_separated_list,
|
||||||
|
"a {\n color: a, b, c;\n}\n",
|
||||||
|
"a{color:a,b,c}",
|
||||||
|
grass::Options::default().style(grass::OutputStyle::Compressed)
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
removes_leading_zero_in_number_under_1,
|
||||||
|
"a {\n color: 0.5;\n}\n",
|
||||||
|
"a{color:.5}",
|
||||||
|
grass::Options::default().style(grass::OutputStyle::Compressed)
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
#[ignore = "we do not support compressed colors"]
|
||||||
|
removes_leading_zero_in_number_under_1_in_rgba_alpha_channel,
|
||||||
|
"a {\n color: rgba(1, 1, 1, 0.5);\n}\n",
|
||||||
|
"a{color:rgba(1,1,1,.5)}",
|
||||||
|
grass::Options::default().style(grass::OutputStyle::Compressed)
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
retains_leading_zero_in_opacity,
|
||||||
|
"a {\n color: opacity(0.5);\n}\n",
|
||||||
|
"a{color:opacity(0.5)}",
|
||||||
|
grass::Options::default().style(grass::OutputStyle::Compressed)
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
retains_leading_zero_in_saturate,
|
||||||
|
"a {\n color: saturate(0.5);\n}\n",
|
||||||
|
"a{color:saturate(0.5)}",
|
||||||
|
grass::Options::default().style(grass::OutputStyle::Compressed)
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
retains_leading_zero_in_grayscale,
|
||||||
|
"a {\n color: grayscale(0.5);\n}\n",
|
||||||
|
"a{color:grayscale(0.5)}",
|
||||||
|
grass::Options::default().style(grass::OutputStyle::Compressed)
|
||||||
|
);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user