Update composer dependencies

This commit is contained in:
Kijin Sung 2017-06-29 23:39:23 +09:00
parent 49cc39e507
commit cbd324c35b
428 changed files with 17862 additions and 5885 deletions

View file

@ -3,6 +3,7 @@
namespace MatthiasMullie\Minify;
use MatthiasMullie\Minify\Exceptions\FileImportException;
use MatthiasMullie\PathConverter\ConverterInterface;
use MatthiasMullie\PathConverter\Converter;
/**
@ -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.');
}
// 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 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;
if (!$this->canImportByPath($match['path']) || !$this->canImportFile($importPath)) {
continue;
}
// 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.');
}
// 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 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);
}
/**
@ -253,18 +236,21 @@ class CSS extends Minify
*/
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
@ -299,12 +285,12 @@ class CSS extends Minify
{
$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,29 +417,46 @@ 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;
}
/*
* Urls with control characters above 0x7e should be quoted.
* According to Mozilla's parser, whitespace is only allowed at the
* end of unquoted urls.
* Urls with `)` (as could happen with data: uris) should also be
* quoted to avoid being confused for the url() closing parentheses.
* And urls with a # have also been reported to cause issues.
*
* @see https://developer.mozilla.org/nl/docs/Web/CSS/url#The_url()_functional_notation
* @see https://hg.mozilla.org/mozilla-central/rev/14abca4e7378
*/
$url = trim($url);
if (preg_match('/[\s\)#\x{7f}-\x{9f}]/u', $url)) {
$url = $match['quotes'] . $url . $match['quotes'];
}
// 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);
}
/**
@ -485,7 +469,7 @@ class CSS extends Minify
*/
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,7 +502,13 @@ 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
);
}
/**
@ -585,18 +575,24 @@ class CSS extends Minify
// looped because there may be multiple 0s inside 1 group of parentheses
do {
$previous = $content;
$content = preg_replace('/\(([^\(\)]+)\s+[\+\-]\s+0(\s+[^\(\)]+)?\)/', '(\\1\\2)', $content);
$content = preg_replace('/\(([^\(\)]+) [\+\-] 0( [^\(\)]+)?\)/', '(\\1\\2)', $content);
} while ($content !== $previous);
// strip all `0 +` occurrences: calc(0 + 10%) -> calc(10%)
$content = preg_replace('/\(\s*0\s+\+\s+([^\(\)]+)\)/', '(\\1)', $content);
$content = preg_replace('/\(0 \+ ([^\(\)]+)\)/', '(\\1)', $content);
// strip all `0 -` occurrences: calc(0 - 10%) -> calc(-10%)
$content = preg_replace('/\(\s*0\s+\-\s+([^\(\)]+)\)/', '(-\\1)', $content);
$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;
}
@ -609,7 +605,7 @@ class CSS extends Minify
*/
protected function stripEmptyTags($content)
{
return preg_replace('/(^|\})[^\{\}]+\{\s*\}/', '\\1', $content);
return preg_replace('/(^|\}|;)[^\{\};]+\{\s*\}/', '\\1', $content);
}
/**
@ -665,4 +661,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);
}
}

View file

@ -222,7 +222,7 @@ class JS extends Minify
return $placeholder;
};
$pattern = '\/.*?(?<!\\\\)(\\\\\\\\)*+\/[gimy]*(?![0-9a-zA-Z\/])';
$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
@ -237,7 +237,7 @@ class JS extends Minify
// (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);
}
/**
@ -323,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
@ -367,8 +368,8 @@ class JS extends Minify
protected function getOperatorsForRegex(array $operators, $delimiter = '/')
{
// escape operators for use in regex
$delimiter = array_fill(0, count($operators), $delimiter);
$escaped = array_map('preg_quote', $operators, $delimiter);
$delimiters = array_fill(0, count($operators), $delimiter);
$escaped = array_map('preg_quote', $operators, $delimiters);
$operators = array_combine($operators, $escaped);
@ -380,7 +381,7 @@ class JS extends Minify
$operators['.'] = '(?<![0-9]\s)\.';
// don't confuse = with other assignment shortcuts (e.g. +=)
$chars = preg_quote('+-*\=<>%&|');
$chars = preg_quote('+-*\=<>%&|', $delimiter);
$operators['='] = '(?<!['.$chars.'])\=';
return $operators;
@ -479,10 +480,23 @@ class JS extends Minify
*/
protected function shortenBools($content)
{
$content = preg_replace('/\btrue\b(?!:)/', '!0', $content);
$content = preg_replace('/\bfalse\b(?!:)/', '!1', $content);
/*
* 'true' or 'false' could be used as property names (which may be
* followed by whitespace) - we must not replace those!
* Since PHP doesn't allow variable-length (to account for the
* whitespace) lookbehind assertions, I need to capture the leading
* character and check if it's a `.`
*/
$callback = function ($match) {
if (trim($match[1]) === '.') {
return $match[0];
}
// for(;;) is exactly the same as while(true)
return $match[1].($match[2] === 'true' ? '!0' : '!1');
};
$content = preg_replace_callback('/(^|.\s*)\b(true|false)\b(?!:)/', $callback, $content);
// for(;;) is exactly the same as while(true), but shorter :)
$content = preg_replace('/\bwhile\(!0\){/', 'for(;;){', $content);
// now make sure we didn't turn any do ... while(true) into do ... for(;;)

View file

@ -54,6 +54,8 @@ abstract class Minify
* Add a file or straight-up code to be minified.
*
* @param string|string[] $data
*
* @return static
*/
public function add($data /* $data = null, ... */)
{
@ -84,6 +86,8 @@ abstract class Minify
// store data
$this->data[$key] = $value;
}
return $this;
}
/**