From 2cbf5c9b3957e7141ccd3ce688936f19db3e6856 Mon Sep 17 00:00:00 2001 From: Steve Clay Date: Wed, 7 May 2008 20:11:55 +0000 Subject: [PATCH] + preserveComments option to Minify_Javascript (default true), test case, and doc comments --- lib/Minify/Javascript.php | 56 ++++++++++++++++++- web/test/_test_files/js/before.js | 11 ++-- web/test/_test_files/js/before.min.js | 9 +++ .../_test_files/js/before_noComments.min.js | 3 + web/test/test_Javascript.php | 18 +++++- 5 files changed, 90 insertions(+), 7 deletions(-) create mode 100644 web/test/_test_files/js/before_noComments.min.js diff --git a/lib/Minify/Javascript.php b/lib/Minify/Javascript.php index 1f19b9d..ab785a9 100644 --- a/lib/Minify/Javascript.php +++ b/lib/Minify/Javascript.php @@ -13,8 +13,62 @@ require dirname(__FILE__) . '/3rd_party/jsmin.php'; * @author Stephen Clay */ class Minify_Javascript { + + /** + * Minify a Javascript string + * + * @param string $js input javascript + * + * @param array $options available options: + * + * 'preserveComments': (default true) multi-line comments that begin + * with "/*!" will be preserved with newlines before and after to + * preserve readability. + * + * @return string + */ public static function minify($js, $options = array()) { - return trim(JSMin::minify($js)); + if (isset($options['preserveComments']) + && !$options['preserveComments']) { + return trim(JSMin::minify($js)); + } + $ret = ''; + while (1) { + list($beforeComment, $comment, $afterComment) + = self::_nextYuiComment($js); + $ret .= trim(JSMin::minify($beforeComment)); + if (false === $comment) { + break; + } + $ret .= $comment; + $js = $afterComment; + } + return $ret; + } + + /** + * Extract comments that YUI Compressor preserves. + * + * @param string $js input + * + * @return array 3 elements are returned. If a YUI comment is found, the + * 2nd element is the comment and the 1st and 2nd are the surrounding + * strings. If no comment is found, the entire string is returned as the 1st + * element and the other two are false. + */ + private static function _nextYuiComment($js) + { + return ( + (false !== ($start = strpos($js, '/*!'))) + && (false !== ($end = strpos($js, '*/'))) + && ($start < $end) + ) + ? array( + substr($js, 0, $start) + ,"\n/*" . substr($js, $start + 3, $end - $start - 1) . "\n" + ,substr($js, -(strlen($js) - $end - 2)) + ) + : array($js, false, false); } } diff --git a/web/test/_test_files/js/before.js b/web/test/_test_files/js/before.js index 4c0b090..37f34c7 100644 --- a/web/test/_test_files/js/before.js +++ b/web/test/_test_files/js/before.js @@ -1,8 +1,8 @@ -// is.js - -// (c) 2001 Douglas Crockford -// 2001 June 3 +/*! is.js + (c) 2001 Douglas Crockford + 2001 June 3 +*/ // is @@ -21,6 +21,9 @@ var is = { parseFloat(navigator.appVersion), win: navigator.platform == 'Win32' } +/*!* + * preserve this comment, too + */ is.mac = is.ua.indexOf('mac') >= 0; if (is.ua.indexOf('opera') >= 0) { is.ie = is.ns = false; diff --git a/web/test/_test_files/js/before.min.js b/web/test/_test_files/js/before.min.js index 1b4c3d9..3bb55b2 100644 --- a/web/test/_test_files/js/before.min.js +++ b/web/test/_test_files/js/before.min.js @@ -1,3 +1,12 @@ + +/* is.js + + (c) 2001 Douglas Crockford + 2001 June 3 +*/ var is={ie:navigator.appName=='Microsoft Internet Explorer',java:navigator.javaEnabled(),ns:navigator.appName=='Netscape',ua:navigator.userAgent.toLowerCase(),version:parseFloat(navigator.appVersion.substr(21))||parseFloat(navigator.appVersion),win:navigator.platform=='Win32'} +/** + * preserve this comment, too + */ is.mac=is.ua.indexOf('mac')>=0;if(is.ua.indexOf('opera')>=0){is.ie=is.ns=false;is.opera=true;} if(is.ua.indexOf('gecko')>=0){is.ie=is.ns=false;is.gecko=true;} \ No newline at end of file diff --git a/web/test/_test_files/js/before_noComments.min.js b/web/test/_test_files/js/before_noComments.min.js new file mode 100644 index 0000000..1b4c3d9 --- /dev/null +++ b/web/test/_test_files/js/before_noComments.min.js @@ -0,0 +1,3 @@ +var is={ie:navigator.appName=='Microsoft Internet Explorer',java:navigator.javaEnabled(),ns:navigator.appName=='Netscape',ua:navigator.userAgent.toLowerCase(),version:parseFloat(navigator.appVersion.substr(21))||parseFloat(navigator.appVersion),win:navigator.platform=='Win32'} +is.mac=is.ua.indexOf('mac')>=0;if(is.ua.indexOf('opera')>=0){is.ie=is.ns=false;is.opera=true;} +if(is.ua.indexOf('gecko')>=0){is.ie=is.ns=false;is.gecko=true;} \ No newline at end of file diff --git a/web/test/test_Javascript.php b/web/test/test_Javascript.php index d94354a..d046c78 100644 --- a/web/test/test_Javascript.php +++ b/web/test/test_Javascript.php @@ -8,7 +8,7 @@ function test_Javascript() global $thisDir; $src = file_get_contents($thisDir . '/_test_files/js/before.js'); - $minExpected = file_get_contents($thisDir . '/_test_files/js/before.min.js');; + $minExpected = file_get_contents($thisDir . '/_test_files/js/before.min.js'); $minOutput = Minify_Javascript::minify($src); $passed = assertTrue($minExpected == $minOutput, 'Minify_Javascript'); @@ -17,7 +17,21 @@ function test_Javascript() echo "\n---Output: " .strlen($minOutput). " bytes\n\n{$minOutput}\n\n"; echo "---Expected: " .strlen($minExpected). " bytes\n\n{$minExpected}\n\n"; echo "---Source: " .strlen($src). " bytes\n\n{$src}\n\n\n"; - } + } + + //$src = file_get_contents($thisDir . '/_test_files/js/before.js'); + $minExpected = file_get_contents($thisDir . '/_test_files/js/before_noComments.min.js'); + $minOutput = Minify_Javascript::minify($src, array( + 'preserveComments' => false + )); + + $passed = assertTrue($minExpected == $minOutput, 'Minify_Javascript'); + + if (__FILE__ === $_SERVER['SCRIPT_FILENAME']) { + echo "\n---Output: " .strlen($minOutput). " bytes\n\n{$minOutput}\n\n"; + echo "---Expected: " .strlen($minExpected). " bytes\n\n{$minExpected}\n\n"; + echo "---Source: " .strlen($src). " bytes\n\n{$src}\n\n\n"; + } } test_Javascript();