Skip to content

Commit

Permalink
feat(css/minifier) Remove useless zeroes
Browse files Browse the repository at this point in the history
  • Loading branch information
ghostd authored and kdy1 committed Dec 9, 2022
1 parent 6238abe commit bdc1ca7
Show file tree
Hide file tree
Showing 8 changed files with 183 additions and 6 deletions.
173 changes: 173 additions & 0 deletions crates/swc_css_minifier/src/compressor/calc_sum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ struct CalcSumContext {
impl CalcSumContext {
pub fn fold(&mut self, calc_sum: &mut CalcSum) {
self.nested_fold(None, calc_sum);
self.remove_zeroes();
calc_sum.expressions = self.expressions.to_vec();
remove_unnecessary_nesting_from_calc_sum(calc_sum);
}
Expand Down Expand Up @@ -120,6 +121,163 @@ impl CalcSumContext {
}
}

fn remove_zeroes(&mut self) {
if self.expressions.len() == 1 {
// We do not want to transform "calc(0)" into "calc()", that would be invalid
return;
}

let mut idx = 0;
while idx < self.expressions.len() {
if let Some(CalcProductOrOperator::Product(calc_product)) = self.expressions.get(idx) {
if CalcSumContext::is_calc_product_zero(calc_product)
&& self.try_to_remove_sum_operator_and_term(idx)
{
continue;
}
}
idx += 1;
}
}

fn try_to_remove_sum_operator_and_term(&mut self, term_index: usize) -> bool {
if term_index == 0 {
if self.expressions.len() > 1 {
// If the next operator is minus ("-"), we try to merge it into its following
// term eg: calc(0 - 3% + 10px) => calc(-3% + 10px)
// ... but it's not always possible: calc(0 - pi)
let can_be_removed = match &self.expressions[1] {
CalcProductOrOperator::Operator(CalcOperator {
value: CalcOperatorType::Sub,
..
}) => self.try_to_switch_sum_term_sign(term_index + 2),
_ => true,
};

if can_be_removed {
// Remove the term
self.expressions.remove(term_index);
// Remove the next operator (the sign has been merged into its term)
self.expressions.remove(term_index);
}
return can_be_removed;
}
false
} else {
// Remove the term
self.expressions.remove(term_index);
// Remove the operator
self.expressions.remove(term_index - 1);
true
}
}

fn try_to_switch_sum_term_sign(&mut self, term_index: usize) -> bool {
if let Some(CalcProductOrOperator::Product(ref mut calc_product)) =
self.expressions.get_mut(term_index)
{
let mut idx = 0;
while idx < calc_product.expressions.len() {
match &mut calc_product.expressions[idx] {
CalcValueOrOperator::Value(CalcValue::Number(n)) => {
n.value = -n.value;
return true;
}
CalcValueOrOperator::Value(CalcValue::Dimension(Dimension::Angle(a))) => {
a.value.value = -a.value.value;
return true;
}
CalcValueOrOperator::Value(CalcValue::Dimension(Dimension::Flex(f))) => {
f.value.value = -f.value.value;
return true;
}
CalcValueOrOperator::Value(CalcValue::Dimension(Dimension::Frequency(f))) => {
f.value.value = -f.value.value;
return true;
}
CalcValueOrOperator::Value(CalcValue::Dimension(Dimension::Length(l))) => {
l.value.value = -l.value.value;
return true;
}
CalcValueOrOperator::Value(CalcValue::Dimension(Dimension::Resolution(r))) => {
r.value.value = -r.value.value;
return true;
}
CalcValueOrOperator::Value(CalcValue::Dimension(Dimension::Time(d))) => {
d.value.value = -d.value.value;
return true;
}
CalcValueOrOperator::Value(CalcValue::Dimension(
Dimension::UnknownDimension(u),
)) => {
u.value.value = -u.value.value;
return true;
}
CalcValueOrOperator::Value(CalcValue::Percentage(p)) => {
p.value.value = -p.value.value;
return true;
}
_ => {}
}
idx += 1;
}
}

false
}

fn is_calc_product_zero(calc_product: &CalcProduct) -> bool {
if calc_product.expressions.len() == 1 {
match &calc_product.expressions[0] {
CalcValueOrOperator::Value(calc_value) => {
CalcSumContext::is_calc_value_zero(calc_value)
}
_ => false,
}
} else {
false
}
}

fn is_calc_value_zero(calc_value: &CalcValue) -> bool {
match calc_value {
CalcValue::Number(Number { value, .. })
| CalcValue::Dimension(Dimension::Angle(Angle {
value: Number { value, .. },
..
}))
| CalcValue::Dimension(Dimension::Length(Length {
value: Number { value, .. },
..
}))
| CalcValue::Dimension(Dimension::Flex(Flex {
value: Number { value, .. },
..
}))
| CalcValue::Dimension(Dimension::Frequency(Frequency {
value: Number { value, .. },
..
}))
| CalcValue::Dimension(Dimension::Resolution(Resolution {
value: Number { value, .. },
..
}))
| CalcValue::Dimension(Dimension::Time(Time {
value: Number { value, .. },
..
}))
| CalcValue::Dimension(Dimension::UnknownDimension(UnknownDimension {
value: Number { value, .. },
..
}))
| CalcValue::Percentage(Percentage {
value: Number { value, .. },
..
}) => *value == 0.0,
_ => false,
}
}

fn merge_operators(
surrounding_operator: Option<&CalcOperator>,
nested_operator: Option<&CalcOperator>,
Expand Down Expand Up @@ -799,6 +957,21 @@ fn fold_calc_product(calc_product: &mut CalcProduct) {
prev_operand = cur_operand
}
}
(
Some(operand1),
Some(CalcOperator {
value: CalcOperatorType::Div,
span: op_span,
}),
Some(_),
) => {
folded_expressions.push(CalcValueOrOperator::Value(operand1.clone()));
folded_expressions.push(CalcValueOrOperator::Operator(CalcOperator {
span: *op_span,
value: CalcOperatorType::Div,
}));
prev_operand = cur_operand
}
_ => {
// Something is wrong: we should iterate over some (operand, operator, operand)
// tuples
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,7 @@
.class9 {
width: calc( 0px - (var(--foo, 4px) / 2));
}

.class10 {
width: calc(0 - (pi * 3px) - 0px - 4em);
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1 +1 @@
.class1{width:calc(1/100)}.class2{width:calc(5/1e6)}.class3{width:calc(100%/3*3)}.class4{width:calc(calc(100%/3)*3)}
.class1{width:calc(1/100)}.class2{width:calc(5/1e6)}.class3{width:calc(100%/9)}.class4{width:calc(calc(100%/3)*3)}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1 +1 @@
.class1{width:calc(1px + 1)}.class2{width:calc(100% - 180px)}.class3{width:calc(100% - 30px)}.class4{width:.95s}.class5{width:calc(99.99%*1/1 - 0rem)}.class6{width:calc(55% + 5em)}.class7{width:calc(50px - 0em)}.class8{width:0}
.class1{width:calc(1px + 1)}.class2{width:calc(100% - 180px)}.class3{width:calc(100% - 30px)}.class4{width:.95s}.class5{width:calc(99.99%/1)}.class6{width:calc(55% + 5em)}.class7{width:50px}.class8{width:0}

0 comments on commit bdc1ca7

Please sign in to comment.