Kaynağa Gözat

#542 Matthias Mullie: Minify from 1.3.28 to 1.3.43, Path Converter from 1.0.5 to 1.1.0

Alex Trofimov 9 yıl önce
ebeveyn
işleme
ec5118a99c

+ 1 - 0
inc/classes/BxDolMinify.php

@@ -9,6 +9,7 @@
 
 use MatthiasMullie\Minify;
 
+require_once(BX_DIRECTORY_PATH_PLUGINS . 'matthiasmullie/path-converter/ConverterInterface.php');
 require_once(BX_DIRECTORY_PATH_PLUGINS . 'matthiasmullie/path-converter/Converter.php');
 require_once(BX_DIRECTORY_PATH_PLUGINS . 'matthiasmullie/minify/Minify.php');
 require_once(BX_DIRECTORY_PATH_PLUGINS . 'matthiasmullie/minify/CSS.php');

+ 129 - 105
plugins/matthiasmullie/minify/CSS.php

@@ -3,6 +3,7 @@
 namespace MatthiasMullie\Minify;
 
 use MatthiasMullie\Minify\Exceptions\FileImportException;
+use MatthiasMullie\PathConverter\ConverterInterface;
 use MatthiasMullie\PathConverter\Converter;
 
 /**
@@ -12,7 +13,7 @@ use MatthiasMullie\PathConverter\Converter;
  *
  * @author Matthias Mullie <minify@mullie.eu>
  * @author Tijs Verkoyen <minify@verkoyen.eu>
- * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved.
+ * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
  * @license MIT License
  */
 class CSS extends Minify
@@ -83,7 +84,7 @@ class CSS extends Minify
 
             // add to top
             $content = implode('', $matches[0]).$content;
-        };
+        }
 
         return $content;
     }
@@ -94,9 +95,9 @@ class CSS extends Minify
      * @import's will be loaded and their content merged into the original file,
      * to save HTTP requests.
      *
-     * @param string   $source  The file to combine imports for.
-     * @param string   $content The CSS content to combine imports for.
-     * @param string[] $parents Parent paths, for circular reference checks.
+     * @param string   $source  The file to combine imports for
+     * @param string   $content The CSS content to combine imports for
+     * @param string[] $parents Parent paths, for circular reference checks
      *
      * @return string
      *
@@ -120,16 +121,7 @@ class CSS extends Minify
                     (?P<quotes>["\']?)
 
                         # fetch path
-                        (?P<path>
-
-                            # do not fetch data uris or external sources
-                            (?!(
-                                ["\']?
-                                (data|https?):
-                            ))
-
-                            .+?
-                        )
+                        (?P<path>.+?)
 
                     # (optional) close path enclosure
                     (?P=quotes)
@@ -164,16 +156,7 @@ class CSS extends Minify
                 (?P<quotes>["\'])
 
                     # fetch path
-                    (?P<path>
-
-                        # do not fetch data uris or external sources
-                        (?!(
-                            ["\']?
-                            (data|https?):
-                        ))
-
-                        .+?
-                    )
+                    (?P<path>.+?)
 
                 # close path enclosure
                 (?P=quotes)
@@ -211,33 +194,33 @@ class CSS extends Minify
 
             // only replace the import with the content if we can grab the
             // content of the file
-            if ($this->canImportFile($importPath)) {
-                // check if current file was not imported previously in the same
-                // import chain.
-                if (in_array($importPath, $parents)) {
-                    throw new FileImportException('Failed to import file "'.$importPath.'": circular reference detected.');
-                }
+            if (!$this->canImportByPath($match['path']) || !$this->canImportFile($importPath)) {
+                continue;
+            }
 
-                // grab referenced file & minify it (which may include importing
-                // yet other @import statements recursively)
-                $minifier = new static($importPath);
-                $importContent = $minifier->execute($source, $parents);
+            // check if current file was not imported previously in the same
+            // import chain.
+            if (in_array($importPath, $parents)) {
+                throw new FileImportException('Failed to import file "'.$importPath.'": circular reference detected.');
+            }
 
-                // check if this is only valid for certain media
-                if (!empty($match['media'])) {
-                    $importContent = '@media '.$match['media'].'{'.$importContent.'}';
-                }
+            // grab referenced file & minify it (which may include importing
+            // yet other @import statements recursively)
+            $minifier = new static($importPath);
+            $importContent = $minifier->execute($source, $parents);
 
-                // add to replacement array
-                $search[] = $match[0];
-                $replace[] = $importContent;
+            // check if this is only valid for certain media
+            if (!empty($match['media'])) {
+                $importContent = '@media '.$match['media'].'{'.$importContent.'}';
             }
+
+            // add to replacement array
+            $search[] = $match[0];
+            $replace[] = $importContent;
         }
 
         // replace the import statements
-        $content = str_replace($search, $replace, $content);
-
-        return $content;
+        return str_replace($search, $replace, $content);
     }
 
     /**
@@ -246,25 +229,28 @@ class CSS extends Minify
      * @url(image.jpg) images will be loaded and their content merged into the
      * original file, to save HTTP requests.
      *
-     * @param string $source  The file to import files for.
-     * @param string $content The CSS content to import files for.
+     * @param string $source  The file to import files for
+     * @param string $content The CSS content to import files for
      *
      * @return string
      */
     protected function importFiles($source, $content)
     {
-        $extensions = array_keys($this->importExtensions);
-        $regex = '/url\((["\']?)((?!["\']?data:).*?\.('.implode('|', $extensions).'))\\1\)/i';
-        if ($extensions && preg_match_all($regex, $content, $matches, PREG_SET_ORDER)) {
+        $regex = '/url\((["\']?)(.+?)\\1\)/i';
+        if ($this->importExtensions && preg_match_all($regex, $content, $matches, PREG_SET_ORDER)) {
             $search = array();
             $replace = array();
 
             // loop the matches
             foreach ($matches as $match) {
+                $extension = substr(strrchr($match[2], '.'), 1);
+                if ($extension && !array_key_exists($extension, $this->importExtensions)) {
+                    continue;
+                }
+
                 // get the path for the file that will be imported
                 $path = $match[2];
                 $path = dirname($source).'/'.$path;
-                $extension = $match[3];
 
                 // only replace the import with the content if we're able to get
                 // the content of the file, and it's relatively small
@@ -290,21 +276,21 @@ class CSS extends Minify
      * Minify the data.
      * Perform CSS optimizations.
      *
-     * @param string[optional] $path    Path to write the data to.
-     * @param string[]         $parents Parent paths, for circular reference checks.
+     * @param string[optional] $path    Path to write the data to
+     * @param string[]         $parents Parent paths, for circular reference checks
      *
-     * @return string The minified data.
+     * @return string The minified data
      */
     public function execute($path = null, $parents = array())
     {
         $content = '';
 
-        // loop css data (raw data and files)
+        // loop CSS data (raw data and files)
         foreach ($this->data as $source => $css) {
             /*
-             * Let's first take out strings & comments, since we can't just remove
-             * whitespace anywhere. If whitespace occurs inside a string, we should
-             * leave it alone. E.g.:
+             * Let's first take out strings & comments, since we can't just
+             * remove whitespace anywhere. If whitespace occurs inside a string,
+             * we should leave it alone. E.g.:
              * p { content: "a   test" }
              */
             $this->extractStrings();
@@ -330,9 +316,9 @@ class CSS extends Minify
              * to be relative no longer to the source file, but to the new path.
              * If we don't write to a file, fall back to same path so no
              * conversion happens (because we still want it to go through most
-             * of the move code...)
+             * of the move code, which also addresses url() & @import syntax...)
              */
-            $converter = new Converter($source, $path ?: $source);
+            $converter = $this->getPathConverter($source, $path ?: $source);
             $css = $this->move($converter, $css);
 
             // combine css
@@ -350,12 +336,12 @@ class CSS extends Minify
      * will have to be updated when a file is being saved at another location
      * (e.g. ../../images/image.gif, if the new CSS file is 1 folder deeper).
      *
-     * @param Converter $converter Relative path converter
-     * @param string    $content   The CSS content to update relative urls for.
+     * @param ConverterInterface $converter Relative path converter
+     * @param string             $content   The CSS content to update relative urls for
      *
      * @return string
      */
-    protected function move(Converter $converter, $content)
+    protected function move(ConverterInterface $converter, $content)
     {
         /*
          * Relative path references will usually be enclosed by url(). @import
@@ -380,17 +366,7 @@ class CSS extends Minify
                 (?P<quotes>["\'])?
 
                     # fetch path
-                    (?P<path>
-
-                        # do not fetch data uris or external sources
-                        (?!(
-                            \s?
-                            ["\']?
-                            (data|https?):
-                        ))
-
-                        .+?
-                    )
+                    (?P<path>.+?)
 
                 # close path enclosure
                 (?(quotes)(?P=quotes))
@@ -417,16 +393,7 @@ class CSS extends Minify
                 (?P<quotes>["\'])
 
                     # fetch path
-                    (?P<path>
-
-                        # do not fetch data uris or external sources
-                        (?!(
-                            ["\']?
-                            (data|https?):
-                        ))
-
-                        .+?
-                    )
+                    (?P<path>.+?)
 
                 # close path enclosure
                 (?P=quotes)
@@ -450,42 +417,43 @@ class CSS extends Minify
             // determine if it's a url() or an @import match
             $type = (strpos($match[0], '@import') === 0 ? 'import' : 'url');
 
-            // attempting to interpret GET-params makes no sense, so let's discard them for awhile
-            $params = strrchr($match['path'], '?');
-            $url = $params ? substr($match['path'], 0, -strlen($params)) : $match['path'];
+            $url = $match['path'];
+            if ($this->canImportByPath($url)) {
+                // attempting to interpret GET-params makes no sense, so let's discard them for awhile
+                $params = strrchr($url, '?');
+                $url = $params ? substr($url, 0, -strlen($params)) : $url;
 
-            // fix relative url
-            $url = $converter->convert($url);
+                // fix relative url
+                $url = $converter->convert($url);
 
-            // now that the path has been converted, re-apply GET-params
-            $url .= $params;
+                // now that the path has been converted, re-apply GET-params
+                $url .= $params;
+            }
 
             // build replacement
             $search[] = $match[0];
-            if ($type == 'url') {
+            if ($type === 'url') {
                 $replace[] = 'url('.$url.')';
-            } elseif ($type == 'import') {
+            } elseif ($type === 'import') {
                 $replace[] = '@import "'.$url.'"';
             }
         }
 
         // replace urls
-        $content = str_replace($search, $replace, $content);
-
-        return $content;
+        return str_replace($search, $replace, $content);
     }
 
     /**
      * Shorthand hex color codes.
      * #FF0000 -> #F00.
      *
-     * @param string $content The CSS content to shorten the hex color codes for.
+     * @param string $content The CSS content to shorten the hex color codes for
      *
      * @return string
      */
     protected function shortenHex($content)
     {
-        $content = preg_replace('/(?<![\'"])#([0-9a-z])\\1([0-9a-z])\\2([0-9a-z])\\3(?![\'"])/i', '#$1$2$3', $content);
+        $content = preg_replace('/(?<=[: ])#([0-9a-z])\\1([0-9a-z])\\2([0-9a-z])\\3(?=[; }])/i', '#$1$2$3', $content);
 
         // we can shorten some even more by replacing them with their color name
         $colors = array(
@@ -518,13 +486,19 @@ class CSS extends Minify
             '#F5DEB3' => 'wheat',
         );
 
-        return str_ireplace(array_keys($colors), $colors, $content);
+        return preg_replace_callback(
+            '/(?<=[: ])('.implode(array_keys($colors), '|').')(?=[; }])/i',
+            function ($match) use ($colors) {
+                return $colors[strtoupper($match[0])];
+            },
+            $content
+        );
     }
 
     /**
      * Shorten CSS font weights.
      *
-     * @param string $content The CSS content to shorten the font weights for.
+     * @param string $content The CSS content to shorten the font weights for
      *
      * @return string
      */
@@ -536,7 +510,7 @@ class CSS extends Minify
         );
 
         $callback = function ($match) use ($weights) {
-            return $match[1] . $weights[$match[2]];
+            return $match[1].$weights[$match[2]];
         };
 
         return preg_replace_callback('/(font-weight\s*:\s*)('.implode('|', array_keys($weights)).')(?=[;}])/', $callback, $content);
@@ -545,7 +519,7 @@ class CSS extends Minify
     /**
      * Shorthand 0 values to plain 0, instead of e.g. -0em.
      *
-     * @param string $content The CSS content to shorten the zero values for.
+     * @param string $content The CSS content to shorten the zero values for
      *
      * @return string
      */
@@ -579,6 +553,30 @@ class CSS extends Minify
         // strip negative zeroes (-0 -> 0) & truncate zeroes (00 -> 0)
         $content = preg_replace('/'.$before.'-?0+'.$units.'?'.$after.'/', '0\\1', $content);
 
+        // remove zeroes where they make no sense in calc: e.g. calc(100px - 0)
+        // the 0 doesn't have any effect, and this isn't even valid without unit
+        // strip all `+ 0` or `- 0` occurrences: calc(10% + 0) -> calc(10%)
+        // looped because there may be multiple 0s inside 1 group of parentheses
+        do {
+            $previous = $content;
+            $content = preg_replace('/\(([^\(\)]+) [\+\-] 0( [^\(\)]+)?\)/', '(\\1\\2)', $content);
+        } while ($content !== $previous);
+        // strip all `0 +` occurrences: calc(0 + 10%) -> calc(10%)
+        $content = preg_replace('/\(0 \+ ([^\(\)]+)\)/', '(\\1)', $content);
+        // strip all `0 -` occurrences: calc(0 - 10%) -> calc(-10%)
+        $content = preg_replace('/\(0 \- ([^\(\)]+)\)/', '(-\\1)', $content);
+        // I'm not going to attempt to optimize away `x * 0` instances:
+        // it's dumb enough code already that it likely won't occur, and it's
+        // too complex to do right (order of operations would have to be
+        // respected etc)
+        // what I cared about most here was fixing incorrectly truncated units
+
+        // IE doesn't seem to understand a unitless flex-basis value, so let's
+        // add it in again (make it `%`, which is only 1 char: 0%, 0px, 0
+        // anything, it's all just the same)
+        $content = preg_replace('/flex:([^ ]+ [^ ]+ )0([;\}])/', 'flex:${1}0%${2}', $content);
+        $content = preg_replace('/flex-basis:0([;\}])/', 'flex-basis:0%${1}', $content);
+
         return $content;
     }
 
@@ -591,7 +589,7 @@ class CSS extends Minify
      */
     protected function stripEmptyTags($content)
     {
-        return preg_replace('/(^|\})[^\{\}]+\{\s*\}/', '\\1', $content);
+        return preg_replace('/(^|\}|;)[^\{\};]+\{\s*\}/', '\\1', $content);
     }
 
     /**
@@ -605,7 +603,7 @@ class CSS extends Minify
     /**
      * Strip whitespace.
      *
-     * @param string $content The CSS content to strip the whitespace for.
+     * @param string $content The CSS content to strip the whitespace for
      *
      * @return string
      */
@@ -639,7 +637,7 @@ class CSS extends Minify
     /**
      * Check if file is small enough to be imported.
      *
-     * @param string $path The path to the file.
+     * @param string $path The path to the file
      *
      * @return bool
      */
@@ -647,4 +645,30 @@ class CSS extends Minify
     {
         return ($size = @filesize($path)) && $size <= $this->maxImportSize * 1024;
     }
+
+    /**
+     * Check if file a file can be imported, going by the path.
+     *
+     * @param string $path
+     *
+     * @return bool
+     */
+    protected function canImportByPath($path)
+    {
+        return preg_match('/^(data:|https?:|\\/)/', $path) === 0;
+    }
+
+    /**
+     * Return a converter to update relative paths to be relative to the new
+     * destination.
+     *
+     * @param string $source
+     * @param string $target
+     *
+     * @return ConverterInterface
+     */
+    protected function getPathConverter($source, $target)
+    {
+        return new Converter($source, $target);
+    }
 }

+ 44 - 28
plugins/matthiasmullie/minify/JS.php

@@ -9,7 +9,7 @@ namespace MatthiasMullie\Minify;
  *
  * @author Matthias Mullie <minify@mullie.eu>
  * @author Tijs Verkoyen <minify@verkoyen.eu>
- * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved.
+ * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
  * @license MIT License
  */
 class JS extends Minify
@@ -64,6 +64,17 @@ class JS extends Minify
      */
     protected $keywordsAfter = array();
 
+    /**
+     * List of all JavaScript operators.
+     *
+     * Will be loaded from /data/js/operators.txt
+     *
+     * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators
+     *
+     * @var string[]
+     */
+    protected $operators = array();
+
     /**
      * List of JavaScript operators that accept a <variable, value, ...> after
      * them. Some end of lines are not the end of a statement, like with these
@@ -111,6 +122,7 @@ class JS extends Minify
         $this->keywordsReserved = file($dataDir.'keywords_reserved.txt', $options);
         $this->keywordsBefore = file($dataDir.'keywords_before.txt', $options);
         $this->keywordsAfter = file($dataDir.'keywords_after.txt', $options);
+        $this->operators = file($dataDir.'operators.txt', $options);
         $this->operatorsBefore = file($dataDir.'operators_before.txt', $options);
         $this->operatorsAfter = file($dataDir.'operators_after.txt', $options);
     }
@@ -119,9 +131,9 @@ class JS extends Minify
      * Minify the data.
      * Perform JS optimizations.
      *
-     * @param string[optional] $path Path to write the data to.
+     * @param string[optional] $path Path to write the data to
      *
-     * @return string The minified data.
+     * @return string The minified data
      */
     public function execute($path = null)
     {
@@ -156,9 +168,9 @@ class JS extends Minify
         $this->extractRegex();
         $content = $this->replace($content);
 
-        $content = $this->stripWhitespace($content);
         $content = $this->propertyNotation($content);
         $content = $this->shortenBools($content);
+        $content = $this->stripWhitespace($content);
 
         /*
          * Earlier, we extracted strings & regular expressions and replaced them
@@ -210,22 +222,22 @@ class JS extends Minify
             return $placeholder;
         };
 
-        $pattern = '\/.*?(?<!\\\\)(\\\\\\\\)*+\/[gimy]*';
+        $pattern = '\/.+?(?<!\\\\)(\\\\\\\\)*\/[gimy]*(?![0-9a-zA-Z\/])';
 
         // a regular expression can only be followed by a few operators or some
         // of the RegExp methods (a `\` followed by a variable or value is
         // likely part of a division, not a regex)
-        $after = '[,;\)]';
+        $after = '[\.,;\)\}]';
         $methods = '\.(exec|test|match|search|replace|split)\(';
-        $this->registerPattern('/'.$pattern.'\s*(?=('.$after.'|'.$methods.'))/', $callback);
+        $this->registerPattern('/'.$pattern.'(?=\s*('.$after.'|'.$methods.'))/', $callback);
 
-        // 1 more edgecase: a regex can be followed by a lot more operators or
+        // 1 more edge case: a regex can be followed by a lot more operators or
         // keywords if there's a newline (ASI) in between, where the operator
         // actually starts a new statement
         // (https://github.com/matthiasmullie/minify/issues/56)
         $operators = $this->getOperatorsForRegex($this->operatorsBefore, '/');
         $operators += $this->getOperatorsForRegex($this->keywordsReserved, '/');
-        $this->registerPattern('/'.$pattern.'\s*\n?(?=\s*('.implode('|', $operators).'))/', $callback);
+        $this->registerPattern('/'.$pattern.'\s*\n(?=\s*('.implode('|', $operators).'))/', $callback);
     }
 
     /**
@@ -240,7 +252,7 @@ class JS extends Minify
      * Because it's sometimes hard to tell if a newline is part of a statement
      * that should be terminated or not, we'll just leave some of them alone.
      *
-     * @param string $content The content to strip the whitespace for.
+     * @param string $content The content to strip the whitespace for
      *
      * @return string
      */
@@ -258,17 +270,19 @@ class JS extends Minify
         // collapse consecutive line feeds into just 1
         $content = preg_replace('/\n+/', "\n", $content);
 
-        $before = $this->getOperatorsForRegex($this->operatorsBefore, '/');
-        $after = $this->getOperatorsForRegex($this->operatorsAfter, '/');
-        $operators = $before + $after;
+        $operatorsBefore = $this->getOperatorsForRegex($this->operatorsBefore, '/');
+        $operatorsAfter = $this->getOperatorsForRegex($this->operatorsAfter, '/');
+        $operators = $this->getOperatorsForRegex($this->operators, '/');
+        $keywordsBefore = $this->getKeywordsForRegex($this->keywordsBefore, '/');
+        $keywordsAfter = $this->getKeywordsForRegex($this->keywordsAfter, '/');
 
         // strip whitespace that ends in (or next line begin with) an operator
         // that allows statements to be broken up over multiple lines
-        unset($before['+'], $before['-'], $after['+'], $after['-']);
+        unset($operatorsBefore['+'], $operatorsBefore['-'], $operatorsAfter['+'], $operatorsAfter['-']);
         $content = preg_replace(
             array(
-                '/('.implode('|', $before).')\s+/',
-                '/\s+('.implode('|', $after).')/',
+                '/('.implode('|', $operatorsBefore).')\s+/',
+                '/\s+('.implode('|', $operatorsAfter).')/',
             ), '\\1', $content
         );
 
@@ -280,19 +294,20 @@ class JS extends Minify
             ), '\\1', $content
         );
 
+        // collapse whitespace around reserved words into single space
+        $content = preg_replace('/(^|[;\}\s])\K('.implode('|', $keywordsBefore).')\s+/', '\\2 ', $content);
+        $content = preg_replace('/\s+('.implode('|', $keywordsAfter).')(?=([;\{\s]|$))/', ' \\1', $content);
+
         /*
          * We didn't strip whitespace after a couple of operators because they
          * could be used in different contexts and we can't be sure it's ok to
          * strip the newlines. However, we can safely strip any non-line feed
          * whitespace that follows them.
          */
-        $content = preg_replace('/([\}\)\]])[^\S\n]+(?!'.implode('|', $operators).')/', '\\1', $content);
-
-        // collapse whitespace around reserved words into single space
-        $before = $this->getKeywordsForRegex($this->keywordsBefore, '/');
-        $after = $this->getKeywordsForRegex($this->keywordsAfter, '/');
-        $content = preg_replace('/(^|[;\}\s])\K('.implode('|', $before).')\s+/', '\\2 ', $content);
-        $content = preg_replace('/\s+('.implode('|', $after).')(?=([;\{\s]|$))/', ' \\1', $content);
+        $operatorsDiffBefore = array_diff($operators, $operatorsBefore);
+        $operatorsDiffAfter = array_diff($operators, $operatorsAfter);
+        $content = preg_replace('/('.implode('|', $operatorsDiffBefore).')[^\S\n]+/', '\\1', $content);
+        $content = preg_replace('/[^\S\n]+('.implode('|', $operatorsDiffAfter).')/', '\\1', $content);
 
         /*
          * Get rid of double semicolons, except where they can be used like:
@@ -308,14 +323,15 @@ class JS extends Minify
         /*
          * Next, we'll be removing all semicolons where ASI kicks in.
          * for-loops however, can have an empty body (ending in only a
-         * semicolon), like: `for(i=1;i<3;i++);`
+         * semicolon), like: `for(i=1;i<3;i++);`, of `for(i in list);`
          * Here, nothing happens during the loop; it's just used to keep
          * increasing `i`. With that ; omitted, the next line would be expected
          * to be the for-loop's body...
          * I'm going to double that semicolon (if any) so after the next line,
          * which strips semicolons here & there, we're still left with this one.
          */
-        $content = preg_replace('/(for\([^;]*;[^;]*;[^;\{]*\));(\}|$)/s', '\\1;;\\2', $content);
+        $content = preg_replace('/(for\([^;\{]*;[^;\{]*;[^;\{]*\));(\}|$)/s', '\\1;;\\2', $content);
+        $content = preg_replace('/(for\([^;\{]+\s+in\s+[^;\{]+\));(\}|$)/s', '\\1;;\\2', $content);
 
         /*
          * We also can't strip empty else-statements. Even though they're
@@ -452,7 +468,7 @@ class JS extends Minify
         $keywords = $this->getKeywordsForRegex($keywords);
         $keywords = '(?<!'.implode(')(?<!', $keywords).')';
 
-        return preg_replace_callback('/(?<='.$previousChar.'|\])'.$keywords.'\[(([\'"])[0-9]+\\2)\]/u', $callback, $content);
+        return preg_replace_callback('/(?<='.$previousChar.'|\])'.$keywords.'\[\s*(([\'"])[0-9]+\\2)\s*\]/u', $callback, $content);
     }
 
     /**
@@ -464,8 +480,8 @@ class JS extends Minify
      */
     protected function shortenBools($content)
     {
-        $content = preg_replace('/\btrue\b/', '!0', $content);
-        $content = preg_replace('/\bfalse\b/', '!1', $content);
+        $content = preg_replace('/\btrue\b(?!:)/', '!0', $content);
+        $content = preg_replace('/\bfalse\b(?!:)/', '!1', $content);
 
         // for(;;) is exactly the same as while(true)
         $content = preg_replace('/\bwhile\(!0\){/', 'for(;;){', $content);

+ 39 - 26
plugins/matthiasmullie/minify/Minify.php

@@ -11,7 +11,7 @@ use Psr\Cache\CacheItemInterface;
  * Please report bugs on https://github.com/matthiasmullie/minify/issues
  *
  * @author Matthias Mullie <minify@mullie.eu>
- * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved.
+ * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
  * @license MIT License
  */
 abstract class Minify
@@ -53,7 +53,9 @@ abstract class Minify
     /**
      * Add a file or straight-up code to be minified.
      *
-     * @param string $data
+     * @param string|string[] $data
+     *
+     * @return static
      */
     public function add($data /* $data = null, ... */)
     {
@@ -65,6 +67,11 @@ abstract class Minify
 
         // this method can be overloaded
         foreach ($args as $data) {
+            if (is_array($data)) {
+                call_user_func_array(array($this, 'add'), $data);
+                continue;
+            }
+
             // redefine var
             $data = (string) $data;
 
@@ -72,17 +79,23 @@ abstract class Minify
             $value = $this->load($data);
             $key = ($data != $value) ? $data : count($this->data);
 
+            // replace CR linefeeds etc.
+            // @see https://github.com/matthiasmullie/minify/pull/139
+            $value = str_replace(array("\r\n", "\r"), "\n", $value);
+
             // store data
             $this->data[$key] = $value;
         }
+
+        return $this;
     }
 
     /**
      * Minify the data & (optionally) saves it to a file.
      *
-     * @param string[optional] $path Path to write the data to.
+     * @param string[optional] $path Path to write the data to
      *
-     * @return string The minified data.
+     * @return string The minified data
      */
     public function minify($path = null)
     {
@@ -99,10 +112,10 @@ abstract class Minify
     /**
      * Minify & gzip the data & (optionally) saves it to a file.
      *
-     * @param string[optional] $path  Path to write the data to.
-     * @param int[optional]    $level Compression level, from 0 to 9.
+     * @param string[optional] $path  Path to write the data to
+     * @param int[optional]    $level Compression level, from 0 to 9
      *
-     * @return string The minified & gzipped data.
+     * @return string The minified & gzipped data
      */
     public function gzip($path = null, $level = 9)
     {
@@ -120,9 +133,9 @@ abstract class Minify
     /**
      * Minify the data & write it to a CacheItemInterface object.
      *
-     * @param CacheItemInterface $item Cache item to write the data to.
+     * @param CacheItemInterface $item Cache item to write the data to
      *
-     * @return CacheItemInterface Cache item with the minifier data.
+     * @return CacheItemInterface Cache item with the minifier data
      */
     public function cache(CacheItemInterface $item)
     {
@@ -135,16 +148,16 @@ abstract class Minify
     /**
      * Minify the data.
      *
-     * @param string[optional] $path Path to write the data to.
+     * @param string[optional] $path Path to write the data to
      *
-     * @return string The minified data.
+     * @return string The minified data
      */
     abstract public function execute($path = null);
 
     /**
      * Load data.
      *
-     * @param string $data Either a path to a file or the content itself.
+     * @param string $data Either a path to a file or the content itself
      *
      * @return string
      */
@@ -166,8 +179,8 @@ abstract class Minify
     /**
      * Save to file.
      *
-     * @param string $content The minified data.
-     * @param string $path    The path to save the minified data to.
+     * @param string $content The minified data
+     * @param string $path    The path to save the minified data to
      *
      * @throws IOException
      */
@@ -183,8 +196,8 @@ abstract class Minify
     /**
      * Register a pattern to execute against the source content.
      *
-     * @param string          $pattern     PCRE pattern.
-     * @param string|callable $replacement Replacement value for matched pattern.
+     * @param string          $pattern     PCRE pattern
+     * @param string|callable $replacement Replacement value for matched pattern
      */
     protected function registerPattern($pattern, $replacement = '')
     {
@@ -202,9 +215,9 @@ abstract class Minify
      * The only way to accurately replace these pieces is to traverse the JS one
      * character at a time and try to find whatever starts first.
      *
-     * @param string $content The content to replace patterns in.
+     * @param string $content The content to replace patterns in
      *
-     * @return string The (manipulated) content.
+     * @return string The (manipulated) content
      */
     protected function replace($content)
     {
@@ -284,9 +297,9 @@ abstract class Minify
      * This function will be called plenty of times, where $content will always
      * move up 1 character.
      *
-     * @param string          $pattern     Pattern to match.
-     * @param string|callable $replacement Replacement value.
-     * @param string          $content     Content to match pattern against.
+     * @param string          $pattern     Pattern to match
+     * @param string|callable $replacement Replacement value
+     * @param string          $content     Content to match pattern against
      *
      * @return string
      */
@@ -388,9 +401,9 @@ abstract class Minify
     /**
      * Attempts to open file specified by $path for writing.
      *
-     * @param string $path The path to the file.
+     * @param string $path The path to the file
      *
-     * @return resource Specifier for the target file.
+     * @return resource Specifier for the target file
      *
      * @throws IOException
      */
@@ -406,9 +419,9 @@ abstract class Minify
     /**
      * Attempts to write $content to the file specified by $handler. $path is used for printing exceptions.
      *
-     * @param resource $handler The resource to write to.
-     * @param string   $content The content to write.
-     * @param string   $path    The path to the file (for exception printing only).
+     * @param resource $handler The resource to write to
+     * @param string   $content The content to write
+     * @param string   $path    The path to the file (for exception printing only)
      *
      * @throws IOException
      */

+ 5 - 5
plugins/matthiasmullie/path-converter/Converter.php

@@ -13,10 +13,10 @@ namespace MatthiasMullie\PathConverter;
  * Please report bugs on https://github.com/matthiasmullie/path-converter/issues
  *
  * @author Matthias Mullie <pathconverter@mullie.eu>
- * @copyright Copyright (c) 2015, Matthias Mullie. All rights reserved.
+ * @copyright Copyright (c) 2015, Matthias Mullie. All rights reserved
  * @license MIT License
  */
-class Converter
+class Converter implements ConverterInterface
 {
     /**
      * @var string
@@ -129,9 +129,9 @@ class Converter
      *     ../../core/layout/images/img.gif relative to
      *     /home/forkcms/frontend/cache/minified_css
      *
-     * @param string $path The relative path that needs to be converted.
+     * @param string $path The relative path that needs to be converted
      *
-     * @return string The new relative path.
+     * @return string The new relative path
      */
     public function convert($path)
     {
@@ -167,7 +167,7 @@ class Converter
      *
      * @return string
      */
-    public function dirname($path)
+    protected function dirname($path)
     {
         if (is_file($path)) {
             return dirname($path);

+ 24 - 0
plugins/matthiasmullie/path-converter/ConverterInterface.php

@@ -0,0 +1,24 @@
+<?php
+
+namespace MatthiasMullie\PathConverter;
+
+/**
+ * Convert file paths.
+ *
+ * Please report bugs on https://github.com/matthiasmullie/path-converter/issues
+ *
+ * @author Matthias Mullie <pathconverter@mullie.eu>
+ * @copyright Copyright (c) 2015, Matthias Mullie. All rights reserved
+ * @license MIT License
+ */
+interface ConverterInterface
+{
+    /**
+     * Convert file paths.
+     *
+     * @param string $path The path to be converted
+     *
+     * @return string The new path
+     */
+    public function convert($path);
+}

+ 23 - 0
plugins/matthiasmullie/path-converter/NoConverter.php

@@ -0,0 +1,23 @@
+<?php
+
+namespace MatthiasMullie\PathConverter;
+
+/**
+ * Don't convert paths.
+ *
+ * Please report bugs on https://github.com/matthiasmullie/path-converter/issues
+ *
+ * @author Matthias Mullie <pathconverter@mullie.eu>
+ * @copyright Copyright (c) 2015, Matthias Mullie. All rights reserved
+ * @license MIT License
+ */
+class NoConverter implements ConverterInterface
+{
+    /**
+     * {@inheritdoc}
+     */
+    public function convert($path)
+    {
+        return $path;
+    }
+}