Skip to content

Commit 022cd72

Browse files
More robust calc() detection
Fixes #312
1 parent 21678a3 commit 022cd72

File tree

2 files changed

+28
-13
lines changed

2 files changed

+28
-13
lines changed

src/CSS.php

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -684,14 +684,22 @@ protected function stripWhitespace($content)
684684
*/
685685
protected function extractMath()
686686
{
687+
$functions = array('calc', 'clamp', 'min', 'max');
688+
$pattern = '/('. implode($functions, '|') .')(\(.+?)(?=$|;|})/m';
689+
687690
// PHP only supports $this inside anonymous functions since 5.4
688691
$minifier = $this;
689-
$callback = function ($match) use ($minifier) {
692+
$callback = function ($match) use ($minifier, $pattern, &$callback) {
690693
$function = $match[1];
691694
$length = strlen($match[2]);
692695
$expr = '';
693696
$opened = 0;
694697

698+
// the regular expression for extracting math has 1 significant problem:
699+
// it can't determine the correct closing parenthesis...
700+
// instead, it'll match a larger portion of code to where it's certain that
701+
// the calc() musts have ended, and we'll figure out which is the correct
702+
// closing parenthesis here, by counting how many have opened
695703
for ($i = 0; $i < $length; $i++) {
696704
$char = $match[2][$i];
697705
$expr .= $char;
@@ -701,25 +709,22 @@ protected function extractMath()
701709
break;
702710
}
703711
}
704-
$rest = str_replace($expr, '', $match[2]);
705-
$expr = trim(substr($expr, 1, -1));
706712

713+
// now that we've figured out where the calc() starts and ends, extract it
707714
$count = count($minifier->extracted);
708715
$placeholder = 'math('.$count.')';
709-
$minifier->extracted[$placeholder] = $function.'('.$expr.')';
716+
$minifier->extracted[$placeholder] = $function.'('.trim(substr($expr, 1, -1)).')';
717+
718+
// and since we've captured more code than required, we may have some leftover
719+
// calc() in here too - go recursive on the remaining but of code to go figure
720+
// that out and extract what is needed
721+
$rest = str_replace($function.$expr, '', $match[0]);
722+
$rest = preg_replace_callback($pattern, $callback, $rest);
710723

711724
return $placeholder.$rest;
712725
};
713726

714-
$functions = array('calc', 'clamp', 'min', 'max');
715-
$this->registerPattern(
716-
'/('. implode($functions, '|') .')(\(.+?)(?=$|;|}|('. implode($functions, '|') .')\()/',
717-
$callback
718-
);
719-
$this->registerPattern(
720-
'/('. implode($functions, '|') .')(\(.+?)(?=$|;|}|('. implode($functions, '|') .')\()/m',
721-
$callback
722-
);
727+
$this->registerPattern($pattern, $callback);
723728
}
724729

725730
/**

tests/css/CSSTest.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -813,6 +813,16 @@ public function dataProvider()
813813
'--headlineFontSize:16px + var(--multiplicator);font-size:calc(var(--headlineFontSize));',
814814
);
815815

816+
// https://github.com/matthiasmullie/minify/issues/312
817+
$tests[] = array(
818+
'.alignfull { width: calc(100% + calc(2 * var(--central-padding))); }',
819+
'.alignfull{width:calc(100% + calc(2 * var(--central-padding)))}',
820+
);
821+
$tests[] = array(
822+
'*{margin-left: calc(0.5rem * calc(1 - var(--space-x-reverse)));}',
823+
'*{margin-left:calc(0.5rem * calc(1 - var(--space-x-reverse)))}',
824+
);
825+
816826
return $tests;
817827
}
818828

0 commit comments

Comments
 (0)