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
|
||||
/ as a separator in color functions, e.g. rgba(255, 255, 255 / 0)
|
||||
Infinity and -Infinity
|
||||
builtin meta function keywords
|
||||
```
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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);
|
||||
string.push('(');
|
||||
let mut span = self.1;
|
||||
@ -88,7 +88,7 @@ impl CallArgs {
|
||||
.iter()
|
||||
.map(|a| {
|
||||
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>>>>()?
|
||||
.join(", "),
|
||||
|
@ -90,13 +90,17 @@ fn inner_hsl(name: &'static str, mut args: CallArgs, parser: &mut Parser) -> Sas
|
||||
let mut string = format!(
|
||||
"{}({}, {}, {}",
|
||||
name,
|
||||
v.to_css_string(args.span())?,
|
||||
saturation.to_css_string(args.span())?,
|
||||
lightness.to_css_string(args.span())?
|
||||
v.to_css_string(args.span(), parser.options.is_compressed())?,
|
||||
saturation.to_css_string(args.span(), parser.options.is_compressed())?,
|
||||
lightness.to_css_string(args.span(), parser.options.is_compressed())?
|
||||
);
|
||||
if !args.is_empty() {
|
||||
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(')');
|
||||
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!(
|
||||
"{}({}, {}, {}",
|
||||
name,
|
||||
hue,
|
||||
v.to_css_string(args.span())?,
|
||||
lightness.to_css_string(args.span())?
|
||||
hue.to_string(parser.options.is_compressed()),
|
||||
v.to_css_string(args.span(), parser.options.is_compressed())?,
|
||||
lightness.to_css_string(args.span(), parser.options.is_compressed())?
|
||||
);
|
||||
if !args.is_empty() {
|
||||
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(')');
|
||||
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((
|
||||
format!(
|
||||
"$saturation: {} is not a number.",
|
||||
v.to_css_string(args.span())?
|
||||
v.to_css_string(args.span(), parser.options.is_compressed())?
|
||||
),
|
||||
args.span(),
|
||||
)
|
||||
@ -146,13 +154,17 @@ fn inner_hsl(name: &'static str, mut args: CallArgs, parser: &mut Parser) -> Sas
|
||||
let mut string = format!(
|
||||
"{}({}, {}, {}",
|
||||
name,
|
||||
hue,
|
||||
saturation,
|
||||
v.to_css_string(args.span())?
|
||||
hue.to_string(parser.options.is_compressed()),
|
||||
saturation.to_string(parser.options.is_compressed()),
|
||||
v.to_css_string(args.span(), parser.options.is_compressed())?
|
||||
);
|
||||
if !args.is_empty() {
|
||||
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(')');
|
||||
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((
|
||||
format!(
|
||||
"$lightness: {} is not a number.",
|
||||
v.to_css_string(args.span())?
|
||||
v.to_css_string(args.span(), parser.options.is_compressed())?
|
||||
),
|
||||
args.span(),
|
||||
)
|
||||
@ -180,7 +192,7 @@ fn inner_hsl(name: &'static str, mut args: CallArgs, parser: &mut Parser) -> Sas
|
||||
return Err((
|
||||
format!(
|
||||
"$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(),
|
||||
)
|
||||
@ -191,10 +203,10 @@ fn inner_hsl(name: &'static str, mut args: CallArgs, parser: &mut Parser) -> Sas
|
||||
format!(
|
||||
"{}({}, {}, {}, {})",
|
||||
name,
|
||||
hue,
|
||||
saturation,
|
||||
lightness,
|
||||
v.to_css_string(args.span())?
|
||||
hue.to_string(parser.options.is_compressed()),
|
||||
saturation.to_string(parser.options.is_compressed()),
|
||||
lightness.to_string(parser.options.is_compressed()),
|
||||
v.to_css_string(args.span(), parser.options.is_compressed())?
|
||||
),
|
||||
QuoteKind::None,
|
||||
));
|
||||
@ -276,7 +288,7 @@ pub(crate) fn adjust_hue(mut args: CallArgs, parser: &mut Parser) -> SassResult<
|
||||
return Err((
|
||||
format!(
|
||||
"$degrees: {} is not a number.",
|
||||
v.to_css_string(args.span())?
|
||||
v.to_css_string(args.span(), parser.options.is_compressed())?
|
||||
),
|
||||
args.span(),
|
||||
)
|
||||
@ -305,7 +317,7 @@ fn lighten(mut args: CallArgs, parser: &mut Parser) -> SassResult<Value> {
|
||||
return Err((
|
||||
format!(
|
||||
"$amount: {} is not a number.",
|
||||
v.to_css_string(args.span())?
|
||||
v.to_css_string(args.span(), false)?
|
||||
),
|
||||
args.span(),
|
||||
)
|
||||
@ -334,7 +346,7 @@ fn darken(mut args: CallArgs, parser: &mut Parser) -> SassResult<Value> {
|
||||
return Err((
|
||||
format!(
|
||||
"$amount: {} is not a number.",
|
||||
v.to_css_string(args.span())?
|
||||
v.to_css_string(args.span(), false)?
|
||||
),
|
||||
args.span(),
|
||||
)
|
||||
@ -350,7 +362,8 @@ fn saturate(mut args: CallArgs, parser: &mut Parser) -> SassResult<Value> {
|
||||
return Ok(Value::String(
|
||||
format!(
|
||||
"saturate({})",
|
||||
args.get_err(0, "amount")?.to_css_string(args.span())?
|
||||
args.get_err(0, "amount")?
|
||||
.to_css_string(args.span(), false)?
|
||||
),
|
||||
QuoteKind::None,
|
||||
));
|
||||
@ -363,7 +376,7 @@ fn saturate(mut args: CallArgs, parser: &mut Parser) -> SassResult<Value> {
|
||||
return Err((
|
||||
format!(
|
||||
"$amount: {} is not a number.",
|
||||
v.to_css_string(args.span())?
|
||||
v.to_css_string(args.span(), false)?
|
||||
),
|
||||
args.span(),
|
||||
)
|
||||
@ -374,7 +387,7 @@ fn saturate(mut args: CallArgs, parser: &mut Parser) -> SassResult<Value> {
|
||||
Value::Color(c) => c,
|
||||
Value::Dimension(Some(n), u, _) => {
|
||||
return Ok(Value::String(
|
||||
format!("saturate({}{})", n, u),
|
||||
format!("saturate({}{})", n.inspect(), u),
|
||||
QuoteKind::None,
|
||||
))
|
||||
}
|
||||
@ -408,7 +421,7 @@ fn desaturate(mut args: CallArgs, parser: &mut Parser) -> SassResult<Value> {
|
||||
return Err((
|
||||
format!(
|
||||
"$amount: {} is not a number.",
|
||||
v.to_css_string(args.span())?
|
||||
v.to_css_string(args.span(), parser.options.is_compressed())?
|
||||
),
|
||||
args.span(),
|
||||
)
|
||||
@ -424,7 +437,7 @@ pub(crate) fn grayscale(mut args: CallArgs, parser: &mut Parser) -> SassResult<V
|
||||
Value::Color(c) => c,
|
||||
Value::Dimension(Some(n), u, _) => {
|
||||
return Ok(Value::String(
|
||||
format!("grayscale({}{})", n, u),
|
||||
format!("grayscale({}{})", n.inspect(), u),
|
||||
QuoteKind::None,
|
||||
))
|
||||
}
|
||||
@ -471,7 +484,7 @@ pub(crate) fn invert(mut args: CallArgs, parser: &mut Parser) -> SassResult<Valu
|
||||
return Err((
|
||||
format!(
|
||||
"$weight: {} is not a number.",
|
||||
v.to_css_string(args.span())?
|
||||
v.to_css_string(args.span(), parser.options.is_compressed())?
|
||||
),
|
||||
args.span(),
|
||||
)
|
||||
@ -491,7 +504,7 @@ pub(crate) fn invert(mut args: CallArgs, parser: &mut Parser) -> SassResult<Valu
|
||||
.into());
|
||||
}
|
||||
Ok(Value::String(
|
||||
format!("invert({}{})", n, u),
|
||||
format!("invert({}{})", n.inspect(), u),
|
||||
QuoteKind::None,
|
||||
))
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ pub(crate) fn opacity(mut args: CallArgs, parser: &mut Parser) -> SassResult<Val
|
||||
match args.get_err(0, "color")? {
|
||||
Value::Color(c) => Ok(Value::Dimension(Some(c.alpha()), Unit::None, true)),
|
||||
Value::Dimension(Some(num), unit, _) => Ok(Value::String(
|
||||
format!("opacity({}{})", num, unit),
|
||||
format!("opacity({}{})", num.inspect(), unit),
|
||||
QuoteKind::None,
|
||||
)),
|
||||
Value::Dimension(None, ..) => todo!(),
|
||||
|
@ -50,9 +50,9 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser) -> Sas
|
||||
format!(
|
||||
"{}({}, {}, {})",
|
||||
name,
|
||||
red.to_css_string(args.span())?,
|
||||
green.to_css_string(args.span())?,
|
||||
v.to_css_string(args.span())?
|
||||
red.to_css_string(args.span(), parser.options.is_compressed())?,
|
||||
green.to_css_string(args.span(), parser.options.is_compressed())?,
|
||||
v.to_css_string(args.span(), parser.options.is_compressed())?
|
||||
),
|
||||
QuoteKind::None,
|
||||
));
|
||||
@ -78,11 +78,16 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser) -> Sas
|
||||
Some(red) => format!(
|
||||
"{}({}, {}, {})",
|
||||
name,
|
||||
red.to_css_string(args.span())?,
|
||||
v.to_css_string(args.span())?,
|
||||
blue
|
||||
red.to_css_string(args.span(), parser.options.is_compressed())?,
|
||||
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(), 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));
|
||||
}
|
||||
@ -107,9 +112,9 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser) -> Sas
|
||||
format!(
|
||||
"{}({}, {}, {})",
|
||||
name,
|
||||
v.to_css_string(args.span())?,
|
||||
green,
|
||||
blue
|
||||
v.to_css_string(args.span(), parser.options.is_compressed())?,
|
||||
green.to_string(parser.options.is_compressed()),
|
||||
blue.to_string(parser.options.is_compressed())
|
||||
),
|
||||
QuoteKind::None,
|
||||
));
|
||||
@ -136,8 +141,8 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser) -> Sas
|
||||
format!(
|
||||
"{}({}, {})",
|
||||
name,
|
||||
v.to_css_string(args.span())?,
|
||||
alpha.to_css_string(args.span())?
|
||||
v.to_css_string(args.span(), parser.options.is_compressed())?,
|
||||
alpha.to_css_string(args.span(), parser.options.is_compressed())?
|
||||
),
|
||||
QuoteKind::None,
|
||||
));
|
||||
@ -158,7 +163,7 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser) -> Sas
|
||||
return Err((
|
||||
format!(
|
||||
"$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(),
|
||||
)
|
||||
@ -169,10 +174,10 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser) -> Sas
|
||||
format!(
|
||||
"{}({}, {}, {}, {})",
|
||||
name,
|
||||
color.red(),
|
||||
color.green(),
|
||||
color.blue(),
|
||||
v.to_css_string(args.span())?
|
||||
color.red().to_string(parser.options.is_compressed()),
|
||||
color.green().to_string(parser.options.is_compressed()),
|
||||
color.blue().to_string(parser.options.is_compressed()),
|
||||
v.to_css_string(args.span(), parser.options.is_compressed())?
|
||||
),
|
||||
QuoteKind::None,
|
||||
));
|
||||
@ -197,7 +202,7 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser) -> Sas
|
||||
return Err((
|
||||
format!(
|
||||
"$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(),
|
||||
)
|
||||
@ -209,13 +214,17 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser) -> Sas
|
||||
let mut string = format!(
|
||||
"{}({}, {}, {}",
|
||||
name,
|
||||
v.to_css_string(args.span())?,
|
||||
green.to_css_string(args.span())?,
|
||||
blue.to_css_string(args.span())?
|
||||
v.to_css_string(args.span(), parser.options.is_compressed())?,
|
||||
green.to_css_string(args.span(), parser.options.is_compressed())?,
|
||||
blue.to_css_string(args.span(), parser.options.is_compressed())?
|
||||
);
|
||||
if !args.is_empty() {
|
||||
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(')');
|
||||
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((
|
||||
format!(
|
||||
"$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(),
|
||||
)
|
||||
@ -249,13 +258,17 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser) -> Sas
|
||||
let mut string = format!(
|
||||
"{}({}, {}, {}",
|
||||
name,
|
||||
red,
|
||||
v.to_css_string(args.span())?,
|
||||
blue.to_css_string(args.span())?
|
||||
red.to_string(parser.options.is_compressed()),
|
||||
v.to_css_string(args.span(), parser.options.is_compressed())?,
|
||||
blue.to_css_string(args.span(), parser.options.is_compressed())?
|
||||
);
|
||||
if !args.is_empty() {
|
||||
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(')');
|
||||
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((
|
||||
format!(
|
||||
"$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(),
|
||||
)
|
||||
@ -288,13 +301,17 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser) -> Sas
|
||||
let mut string = format!(
|
||||
"{}({}, {}, {}",
|
||||
name,
|
||||
red,
|
||||
green,
|
||||
v.to_css_string(args.span())?
|
||||
red.to_string(parser.options.is_compressed()),
|
||||
green.to_string(parser.options.is_compressed()),
|
||||
v.to_css_string(args.span(), parser.options.is_compressed())?
|
||||
);
|
||||
if !args.is_empty() {
|
||||
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(')');
|
||||
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((
|
||||
format!(
|
||||
"$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(),
|
||||
)
|
||||
@ -329,10 +346,10 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser) -> Sas
|
||||
let string = format!(
|
||||
"{}({}, {}, {}, {})",
|
||||
name,
|
||||
red,
|
||||
green,
|
||||
blue,
|
||||
v.to_css_string(args.span())?
|
||||
red.to_string(parser.options.is_compressed()),
|
||||
green.to_string(parser.options.is_compressed()),
|
||||
blue.to_string(parser.options.is_compressed()),
|
||||
v.to_css_string(args.span(), parser.options.is_compressed())?
|
||||
);
|
||||
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((
|
||||
format!(
|
||||
"$weight: {} is not a number.",
|
||||
v.to_css_string(args.span())?
|
||||
v.to_css_string(args.span(), parser.options.is_compressed())?
|
||||
),
|
||||
args.span(),
|
||||
)
|
||||
|
@ -45,7 +45,7 @@ pub(crate) fn nth(mut args: CallArgs, parser: &mut Parser) -> SassResult<Value>
|
||||
return Err((
|
||||
format!(
|
||||
"$n: Invalid index {}{} for a list with {} elements.",
|
||||
n,
|
||||
n.inspect(),
|
||||
unit,
|
||||
list.len()
|
||||
),
|
||||
@ -55,7 +55,7 @@ pub(crate) fn nth(mut args: CallArgs, parser: &mut Parser) -> SassResult<Value>
|
||||
}
|
||||
|
||||
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() {
|
||||
@ -114,7 +114,9 @@ pub(crate) fn set_nth(mut args: CallArgs, parser: &mut Parser) -> SassResult<Val
|
||||
return Err((
|
||||
format!(
|
||||
"$n: Invalid index {}{} for a list with {} elements.",
|
||||
n, unit, len
|
||||
n.inspect(),
|
||||
unit,
|
||||
len
|
||||
),
|
||||
args.span(),
|
||||
)
|
||||
@ -122,7 +124,7 @@ pub(crate) fn set_nth(mut args: CallArgs, parser: &mut Parser) -> SassResult<Val
|
||||
}
|
||||
|
||||
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")?;
|
||||
|
@ -4,7 +4,13 @@ macro_rules! bound {
|
||||
return Err((
|
||||
format!(
|
||||
"${}: Expected {}{} to be within {}{} and {}{}.",
|
||||
$name, $arg, $unit, $low, $unit, $high, $unit,
|
||||
$name,
|
||||
$arg.inspect(),
|
||||
$unit,
|
||||
$low,
|
||||
$unit,
|
||||
$high,
|
||||
$unit,
|
||||
),
|
||||
$args.span(),
|
||||
)
|
||||
@ -18,7 +24,13 @@ macro_rules! bound {
|
||||
return Err((
|
||||
format!(
|
||||
"${}: Expected {}{} to be within {}{} and {}{}.",
|
||||
$name, $arg, $unit, $low, $unit, $high, $unit,
|
||||
$name,
|
||||
$arg.inspect(),
|
||||
$unit,
|
||||
$low,
|
||||
$unit,
|
||||
$high,
|
||||
$unit,
|
||||
),
|
||||
$args.span(),
|
||||
)
|
||||
|
@ -149,12 +149,16 @@ pub(crate) fn random(mut args: CallArgs, parser: &mut Parser) -> SassResult<Valu
|
||||
}
|
||||
|
||||
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() {
|
||||
return Err((
|
||||
format!("$limit: Must be greater than 0, was {}.", limit),
|
||||
format!("$limit: Must be greater than 0, was {}.", limit.inspect()),
|
||||
args.span(),
|
||||
)
|
||||
.into());
|
||||
@ -164,7 +168,10 @@ pub(crate) fn random(mut args: CallArgs, parser: &mut Parser) -> SassResult<Valu
|
||||
Some(n) => n,
|
||||
None => {
|
||||
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(),
|
||||
)
|
||||
.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 start = match args.get_err(1, "start-at")? {
|
||||
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() => {
|
||||
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)? {
|
||||
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() => {
|
||||
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")? {
|
||||
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(None, Unit::None, ..) => {
|
||||
|
@ -590,7 +590,14 @@ fn repr(red: &Number, green: &Number, blue: &Number, alpha: &Number) -> String {
|
||||
let blue_u8 = into_u8(blue);
|
||||
|
||||
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]) {
|
||||
(*c).to_owned()
|
||||
} 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 {
|
||||
match self {
|
||||
Self::Space => "space",
|
||||
|
@ -260,6 +260,10 @@ impl<'a> Options<'a> {
|
||||
self.unicode_error_messages = unicode_error_messages;
|
||||
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> {
|
||||
|
@ -511,7 +511,7 @@ impl Formatter for CompressedFormatter {
|
||||
write!(buf, "}}")?;
|
||||
}
|
||||
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)?;
|
||||
}
|
||||
}
|
||||
@ -542,7 +542,7 @@ impl CompressedFormatter {
|
||||
for style in &mut styles {
|
||||
match style {
|
||||
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)?;
|
||||
break;
|
||||
}
|
||||
@ -554,7 +554,7 @@ impl CompressedFormatter {
|
||||
for style in styles {
|
||||
match style {
|
||||
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)?;
|
||||
}
|
||||
|
@ -299,8 +299,11 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||
|
||||
let value = format!(
|
||||
"{}={}",
|
||||
left.node.to_css_string(left.span)?,
|
||||
right.node.to_css_string(right.span)?
|
||||
left.node
|
||||
.to_css_string(left.span, self.options.is_compressed())?,
|
||||
right
|
||||
.node
|
||||
.to_css_string(right.span, self.options.is_compressed())?
|
||||
);
|
||||
|
||||
args.insert(
|
||||
|
@ -211,7 +211,7 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||
let from = match from_val.node {
|
||||
Value::Dimension(Some(n), ..) => match n.to_i32() {
|
||||
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,
|
||||
},
|
||||
@ -229,14 +229,17 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||
let to = match to_val.node {
|
||||
Value::Dimension(Some(n), ..) => match n.to_i32() {
|
||||
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,
|
||||
},
|
||||
Value::Dimension(None, ..) => return Err(("NaN is not an int.", from_val.span).into()),
|
||||
v => {
|
||||
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,
|
||||
)
|
||||
.into())
|
||||
|
@ -64,7 +64,11 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||
self.toks.next();
|
||||
// TODO: if ident, interpolate literally
|
||||
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 {
|
||||
self.toks.reset_cursor();
|
||||
break;
|
||||
@ -179,7 +183,10 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||
self.toks.next();
|
||||
match self.parse_interpolation()?.node {
|
||||
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()),
|
||||
@ -268,7 +275,10 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||
let interpolation = self.parse_interpolation()?;
|
||||
match interpolation.node {
|
||||
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;
|
||||
}
|
||||
|
@ -126,7 +126,11 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||
match tok.kind {
|
||||
'#' => {
|
||||
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 {
|
||||
string.push('#');
|
||||
}
|
||||
|
@ -51,7 +51,10 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||
_ => 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> {
|
||||
@ -92,7 +95,11 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||
})?;
|
||||
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();
|
||||
buf.push(')');
|
||||
|
@ -210,7 +210,7 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||
self.consume_char_if_exists(';');
|
||||
|
||||
self.warn(&Spanned {
|
||||
node: message.to_css_string(span)?,
|
||||
node: message.to_css_string(span, false)?,
|
||||
span,
|
||||
});
|
||||
}
|
||||
@ -407,7 +407,11 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||
match kind {
|
||||
'#' => {
|
||||
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 {
|
||||
string.push('#');
|
||||
}
|
||||
@ -513,7 +517,11 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||
}
|
||||
('#', Some(Token { kind: '{', .. })) => {
|
||||
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;
|
||||
}
|
||||
(..) => comment.push(tok.kind),
|
||||
@ -541,7 +549,7 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||
let interpolation = self.parse_interpolation()?;
|
||||
Ok(match interpolation.node {
|
||||
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((
|
||||
format!(
|
||||
"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());
|
||||
}
|
||||
@ -922,7 +930,11 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||
self.toks.next();
|
||||
self.span_before = pos;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -197,7 +197,9 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||
};
|
||||
|
||||
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();
|
||||
|
||||
|
@ -20,7 +20,11 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||
self.span_before = pos;
|
||||
self.toks.next();
|
||||
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 {
|
||||
buf.push('#');
|
||||
}
|
||||
@ -93,7 +97,10 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||
let interpolation = self.parse_interpolation()?;
|
||||
match interpolation.node {
|
||||
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 {
|
||||
buf.push('#');
|
||||
@ -142,7 +149,11 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||
match kind {
|
||||
'+' | '-' | '0'..='9' => {
|
||||
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();
|
||||
@ -316,7 +327,7 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||
q @ ('"' | '\'') => {
|
||||
self.toks.next();
|
||||
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;
|
||||
}
|
||||
'/' => {
|
||||
|
@ -122,14 +122,26 @@ impl<'a, 'b: 'a, 'c> ValueVisitor<'a, 'b, 'c> {
|
||||
Value::Dimension(Some(-n), 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> {
|
||||
Ok(match val {
|
||||
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::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,
|
||||
),
|
||||
_ => Value::String(
|
||||
format!(
|
||||
"{}{}",
|
||||
left.to_css_string(self.span)?,
|
||||
right.to_css_string(self.span)?
|
||||
left.to_css_string(self.span, self.parser.options.is_compressed())?,
|
||||
right.to_css_string(self.span, self.parser.options.is_compressed())?
|
||||
),
|
||||
QuoteKind::None,
|
||||
),
|
||||
},
|
||||
Value::Important => match right {
|
||||
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,
|
||||
),
|
||||
_ => Value::String(
|
||||
format!(
|
||||
"{}{}",
|
||||
left.to_css_string(self.span)?,
|
||||
right.to_css_string(self.span)?
|
||||
left.to_css_string(self.span, self.parser.options.is_compressed())?,
|
||||
right.to_css_string(self.span, self.parser.options.is_compressed())?
|
||||
),
|
||||
QuoteKind::None,
|
||||
),
|
||||
@ -205,7 +225,9 @@ impl<'a, 'b: 'a, 'c> ValueVisitor<'a, 'b, 'c> {
|
||||
Value::Null => match right {
|
||||
Value::Null => Value::Null,
|
||||
_ => 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,
|
||||
),
|
||||
},
|
||||
@ -230,14 +252,34 @@ impl<'a, 'b: 'a, 'c> ValueVisitor<'a, 'b, 'c> {
|
||||
Value::Dimension(Some(num + num2.convert(&unit2, &unit)), unit, true)
|
||||
}
|
||||
}
|
||||
Value::String(s, q) => Value::String(format!("{}{}{}", num, unit, s), q),
|
||||
Value::Null => Value::String(format!("{}{}", num, unit), QuoteKind::None),
|
||||
Value::String(s, q) => Value::String(
|
||||
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::False
|
||||
| Value::List(..)
|
||||
| Value::Important
|
||||
| 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::Map(..) | Value::FunctionRef(..) => {
|
||||
@ -251,7 +293,7 @@ impl<'a, 'b: 'a, 'c> ValueVisitor<'a, 'b, 'c> {
|
||||
return Err((
|
||||
format!(
|
||||
"Undefined operation \"{}{} + {}\".",
|
||||
num,
|
||||
num.inspect(),
|
||||
unit,
|
||||
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::Null => Value::String(c.to_string(), QuoteKind::None),
|
||||
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,
|
||||
),
|
||||
_ => {
|
||||
@ -281,17 +327,25 @@ impl<'a, 'b: 'a, 'c> ValueVisitor<'a, 'b, 'c> {
|
||||
},
|
||||
Value::String(text, quotes) => match right {
|
||||
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::String(s, q) => {
|
||||
Value::String(format!("{}{}", left.to_css_string(self.span)?, s), q)
|
||||
}
|
||||
Value::String(s, q) => Value::String(
|
||||
format!(
|
||||
"{}{}",
|
||||
left.to_css_string(self.span, self.parser.options.is_compressed())?,
|
||||
s
|
||||
),
|
||||
q,
|
||||
),
|
||||
_ => Value::String(
|
||||
format!(
|
||||
"{}{}",
|
||||
left.to_css_string(self.span)?,
|
||||
right.to_css_string(self.span)?
|
||||
left.to_css_string(self.span, self.parser.options.is_compressed())?,
|
||||
right.to_css_string(self.span, self.parser.options.is_compressed())?
|
||||
),
|
||||
QuoteKind::None,
|
||||
),
|
||||
@ -314,7 +368,10 @@ impl<'a, 'b: 'a, 'c> ValueVisitor<'a, 'b, 'c> {
|
||||
};
|
||||
Ok(match left {
|
||||
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,
|
||||
),
|
||||
v @ Value::Dimension(None, ..) => v,
|
||||
@ -344,7 +401,12 @@ impl<'a, 'b: 'a, 'c> ValueVisitor<'a, 'b, 'c> {
|
||||
| Value::True
|
||||
| Value::False
|
||||
| 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::Map(..) | Value::FunctionRef(..) => {
|
||||
@ -358,7 +420,7 @@ impl<'a, 'b: 'a, 'c> ValueVisitor<'a, 'b, 'c> {
|
||||
return Err((
|
||||
format!(
|
||||
"Undefined operation \"{}{} - {}\".",
|
||||
num,
|
||||
num.inspect(),
|
||||
unit,
|
||||
right.inspect(self.span)?
|
||||
),
|
||||
@ -366,7 +428,14 @@ impl<'a, 'b: 'a, 'c> ValueVisitor<'a, 'b, 'c> {
|
||||
)
|
||||
.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::String(s, q) => {
|
||||
@ -385,32 +454,45 @@ impl<'a, 'b: 'a, 'c> ValueVisitor<'a, 'b, 'c> {
|
||||
.into())
|
||||
}
|
||||
_ => 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,
|
||||
),
|
||||
},
|
||||
Value::String(..) => Value::String(
|
||||
format!(
|
||||
"{}-{}",
|
||||
left.to_css_string(self.span)?,
|
||||
right.to_css_string(self.span)?
|
||||
left.to_css_string(self.span, self.parser.options.is_compressed())?,
|
||||
right.to_css_string(self.span, self.parser.options.is_compressed())?
|
||||
),
|
||||
QuoteKind::None,
|
||||
),
|
||||
_ => match right {
|
||||
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,
|
||||
),
|
||||
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,
|
||||
),
|
||||
_ => Value::String(
|
||||
format!(
|
||||
"{}-{}",
|
||||
left.to_css_string(self.span)?,
|
||||
right.to_css_string(self.span)?
|
||||
left.to_css_string(self.span, self.parser.options.is_compressed())?,
|
||||
right.to_css_string(self.span, self.parser.options.is_compressed())?
|
||||
),
|
||||
QuoteKind::None,
|
||||
),
|
||||
@ -448,7 +530,7 @@ impl<'a, 'b: 'a, 'c> ValueVisitor<'a, 'b, 'c> {
|
||||
return Err((
|
||||
format!(
|
||||
"Undefined operation \"{}{} * {}\".",
|
||||
num,
|
||||
num.inspect(),
|
||||
unit,
|
||||
right.inspect(self.span)?
|
||||
),
|
||||
@ -487,7 +569,10 @@ impl<'a, 'b: 'a, 'c> ValueVisitor<'a, 'b, 'c> {
|
||||
};
|
||||
Ok(match left {
|
||||
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,
|
||||
),
|
||||
Value::Dimension(None, ..) => todo!(),
|
||||
@ -537,24 +622,50 @@ impl<'a, 'b: 'a, 'c> ValueVisitor<'a, 'b, 'c> {
|
||||
}
|
||||
} else {
|
||||
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,
|
||||
)
|
||||
}
|
||||
}
|
||||
Value::String(s, q) => {
|
||||
Value::String(format!("{}{}/{}{}{}", num, unit, q, s, q), QuoteKind::None)
|
||||
}
|
||||
Value::String(s, q) => Value::String(
|
||||
format!(
|
||||
"{}{}/{}{}{}",
|
||||
num.to_string(self.parser.options.is_compressed()),
|
||||
unit,
|
||||
q,
|
||||
s,
|
||||
q
|
||||
),
|
||||
QuoteKind::None,
|
||||
),
|
||||
Value::List(..)
|
||||
| Value::True
|
||||
| Value::False
|
||||
| Value::Important
|
||||
| Value::Color(..)
|
||||
| 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,
|
||||
),
|
||||
Value::Null => Value::String(format!("{}{}/", num, unit), QuoteKind::None),
|
||||
Value::Map(..) | Value::FunctionRef(..) => {
|
||||
return Err((
|
||||
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())
|
||||
}
|
||||
_ => 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,
|
||||
),
|
||||
},
|
||||
@ -596,7 +711,13 @@ impl<'a, 'b: 'a, 'c> ValueVisitor<'a, 'b, 'c> {
|
||||
| Value::Color(..)
|
||||
| Value::List(..)
|
||||
| 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,
|
||||
),
|
||||
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 {
|
||||
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,
|
||||
),
|
||||
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,
|
||||
),
|
||||
_ => Value::String(
|
||||
format!(
|
||||
"{}/{}",
|
||||
left.to_css_string(self.span)?,
|
||||
right.to_css_string(self.span)?
|
||||
left.to_css_string(self.span, self.parser.options.is_compressed())?,
|
||||
right.to_css_string(self.span, self.parser.options.is_compressed())?
|
||||
),
|
||||
QuoteKind::None,
|
||||
),
|
||||
|
@ -272,9 +272,17 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||
}
|
||||
"url" => match self.try_parse_url()? {
|
||||
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(
|
||||
@ -1142,7 +1150,10 @@ impl<'a, 'b: 'a, 'c> IntermediateValueIterator<'a, 'b, 'c> {
|
||||
"/{}",
|
||||
ValueVisitor::new(self.parser, right.span)
|
||||
.eval(right.node, false)?
|
||||
.to_css_string(right.span)?
|
||||
.to_css_string(
|
||||
right.span,
|
||||
self.parser.options.is_compressed()
|
||||
)?
|
||||
),
|
||||
QuoteKind::None,
|
||||
)),
|
||||
@ -1348,7 +1359,7 @@ impl<'a, 'b: 'a, 'c> IntermediateValueIterator<'a, 'b, 'c> {
|
||||
"/{}",
|
||||
ValueVisitor::new(self.parser, val.span)
|
||||
.eval(val.node, false)?
|
||||
.to_css_string(val.span)?
|
||||
.to_css_string(val.span, self.parser.options.is_compressed())?
|
||||
),
|
||||
QuoteKind::None,
|
||||
)),
|
||||
|
@ -189,7 +189,7 @@ impl Display for Attribute {
|
||||
// (also avoids the clone because we can consume/modify self)
|
||||
f.write_str(
|
||||
&Value::String(self.value.clone(), QuoteKind::Quoted)
|
||||
.to_css_string(self.span)
|
||||
.to_css_string(self.span, false)
|
||||
.unwrap(),
|
||||
)?;
|
||||
// todo: this space is not emitted when `compressed` output
|
||||
|
@ -14,7 +14,7 @@ impl Style {
|
||||
Ok(format!(
|
||||
"{}: {};",
|
||||
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 {
|
||||
Value::Important => Cow::const_str("!important"),
|
||||
Value::Dimension(num, unit, _) => match unit {
|
||||
Unit::Mul(..) | Unit::Div(..) => {
|
||||
if let Some(num) = num {
|
||||
return Err(
|
||||
(format!("{}{} isn't a valid CSS value.", num, unit), span).into()
|
||||
);
|
||||
return Err((
|
||||
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());
|
||||
}
|
||||
_ => {
|
||||
if let Some(num) = num {
|
||||
Cow::owned(format!("{}{}", num, unit))
|
||||
Cow::owned(format!("{}{}", num.to_string(is_compressed), unit))
|
||||
} else {
|
||||
Cow::owned(format!("NaN{}", unit))
|
||||
}
|
||||
@ -237,17 +243,25 @@ impl Value {
|
||||
Brackets::None => Cow::owned(
|
||||
vals.iter()
|
||||
.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>>>>()?
|
||||
.join(sep.as_str()),
|
||||
.join(if is_compressed {
|
||||
sep.as_compressed_str()
|
||||
} else {
|
||||
sep.as_str()
|
||||
}),
|
||||
),
|
||||
Brackets::Bracketed => Cow::owned(format!(
|
||||
"[{}]",
|
||||
vals.iter()
|
||||
.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>>>>()?
|
||||
.join(sep.as_str()),
|
||||
.join(if is_compressed {
|
||||
sep.as_compressed_str()
|
||||
} else {
|
||||
sep.as_str()
|
||||
}),
|
||||
)),
|
||||
},
|
||||
Value::Color(c) => Cow::owned(c.to_string()),
|
||||
@ -287,9 +301,13 @@ impl Value {
|
||||
Value::ArgList(args) => Cow::owned(
|
||||
args.iter()
|
||||
.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>>>>()?
|
||||
.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>>>()?
|
||||
.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::ArgList(args) if args.is_empty() => Cow::const_str("()"),
|
||||
Value::ArgList(args) if args.len() == 1 => Cow::owned(format!(
|
||||
@ -488,7 +508,7 @@ impl Value {
|
||||
| Value::True
|
||||
| Value::False
|
||||
| Value::Color(..)
|
||||
| Value::String(..) => self.to_css_string(span)?,
|
||||
| Value::String(..) => self.to_css_string(span, false)?,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,7 @@
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
convert::{From, TryFrom},
|
||||
fmt::{self, Display, Write},
|
||||
mem,
|
||||
fmt, mem,
|
||||
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 {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Small(..) => write!(f, "Number::Small( {} )", self),
|
||||
Self::Big(..) => write!(f, "Number::Big( {} )", self),
|
||||
Self::Small(..) => write!(f, "Number::Small( {} )", self.to_string(false)),
|
||||
Self::Big(..) => write!(f, "Number::Big( {} )", self.to_string(false)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -355,16 +354,24 @@ impl ToPrimitive for Number {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Number {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
impl Number {
|
||||
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 has_decimal = self.is_decimal();
|
||||
let mut frac = self.abs().fract();
|
||||
let mut dec = String::with_capacity(if has_decimal { PRECISION } else { 0 });
|
||||
|
||||
let mut buf = String::new();
|
||||
|
||||
if has_decimal {
|
||||
for _ in 0..(PRECISION - 1) {
|
||||
frac *= 10_i64;
|
||||
write!(dec, "{}", frac.to_integer())?;
|
||||
dec.push_str(&frac.to_integer().to_string());
|
||||
|
||||
frac = frac.fract();
|
||||
if frac.is_zero() {
|
||||
break;
|
||||
@ -398,20 +405,25 @@ impl Display for Number {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
write!(dec, "{}", end)?;
|
||||
dec.push_str(&end.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
f.write_char('.')?;
|
||||
write!(f, "{}", dec)?;
|
||||
buf.push('.');
|
||||
buf.push_str(&dec);
|
||||
}
|
||||
Ok(())
|
||||
|
||||
buf
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,13 +13,6 @@ test!(
|
||||
"a{color:red;color:green;color:blue}",
|
||||
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!(
|
||||
compresses_media_rule,
|
||||
"@media foo {\n a {\n color: red;\n }\n}\n",
|
||||
@ -86,3 +79,40 @@ test!(
|
||||
"a{color:red}b{color:green}",
|
||||
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