mirror of
https://github.com/mrclay/minify.git
synced 2025-08-19 12:21:20 +02:00
Merge branch 'master' into static
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -9,3 +9,4 @@
|
||||
/vendor
|
||||
/.php_cs.cache
|
||||
/static/[0-9]*
|
||||
/tests/compiler.jar
|
||||
|
3
.php_cs
3
.php_cs
@@ -5,7 +5,7 @@ $finder = Symfony\CS\Finder\DefaultFinder::create()
|
||||
;
|
||||
|
||||
return Symfony\CS\Config\Config::create()
|
||||
->level(Symfony\CS\FixerInterface::NONE_LEVEL)
|
||||
->level(Symfony\CS\FixerInterface::PSR2_LEVEL)
|
||||
->setUsingCache(true)
|
||||
->fixers(array(
|
||||
'linefeed',
|
||||
@@ -21,6 +21,7 @@ return Symfony\CS\Config\Config::create()
|
||||
'controls_spaces',
|
||||
'elseif',
|
||||
'-eof_ending',
|
||||
'-method_argument_space',
|
||||
))
|
||||
->finder($finder)
|
||||
;
|
||||
|
@@ -6,7 +6,6 @@ php:
|
||||
- 5.6
|
||||
- 5.5
|
||||
- 5.4
|
||||
- 5.3
|
||||
- hhvm
|
||||
|
||||
matrix:
|
||||
@@ -25,8 +24,14 @@ cache:
|
||||
install:
|
||||
- composer update --no-interaction --prefer-source
|
||||
|
||||
before_script:
|
||||
- wget -c https://dl.google.com/closure-compiler/compiler-latest.zip -O vendor/compiler-latest.zip
|
||||
- unzip -od vendor/closure-compiler vendor/compiler-latest.zip
|
||||
- ln -sfn ../$(echo vendor/closure-compiler/closure-compiler-*.jar) tests/compiler.jar
|
||||
- java -jar tests/compiler.jar --version
|
||||
|
||||
script:
|
||||
- composer validate
|
||||
- phpunit
|
||||
- phpunit --verbose
|
||||
|
||||
# vim:ts=2:sw=2:et
|
||||
|
@@ -23,21 +23,24 @@
|
||||
"classmap": ["tests/TestCase.php"]
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0",
|
||||
"ext-pcre": "*",
|
||||
"firephp/firephp-core": "~0.4.0",
|
||||
"intervention/httpauth": "~2.0",
|
||||
"monolog/monolog": "~1.1",
|
||||
"mrclay/jsmin-php": "~2",
|
||||
"mrclay/props-dic": "^2.2",
|
||||
"php": "^5.3.0 || ^7.0",
|
||||
"tubalmartin/cssmin": "~2.4.8"
|
||||
},
|
||||
"require-dev": {
|
||||
"firephp/firephp-core": "~0.4.0",
|
||||
"leafo/lessphp": "~0.4.0",
|
||||
"leafo/scssphp": "~0.6.6",
|
||||
"meenie/javascript-packer": "~1.1",
|
||||
"phpunit/phpunit": "4.8.*"
|
||||
"phpunit/phpunit": "4.8.*",
|
||||
"tedivm/jshrink": "~1.1.0"
|
||||
},
|
||||
"suggest": {
|
||||
"firephp/firephp-core": "Use FirePHP for Log messages",
|
||||
"leafo/lessphp": "LESS support",
|
||||
"meenie/javascript-packer": "Keep track of the Packer PHP port using Composer"
|
||||
},
|
||||
|
@@ -10,7 +10,7 @@ In other words, the "f" argument is set to the file path from root without the i
|
||||
|
||||
To combine multiple files, separate the paths given to "f" with commas.
|
||||
|
||||
Let's say you have CSS files at these URLs:
|
||||
Let's say you have JS files at these URLs:
|
||||
|
||||
* http://example.com/scripts/library-1.5.js
|
||||
* http://example.com/scripts/site.js
|
||||
|
@@ -60,7 +60,8 @@
|
||||
* @subpackage HTTP
|
||||
* @author Stephen Clay <steve@mrclay.org>
|
||||
*/
|
||||
class HTTP_ConditionalGet {
|
||||
class HTTP_ConditionalGet
|
||||
{
|
||||
|
||||
/**
|
||||
* Does the client have a valid copy of the requested resource?
|
||||
@@ -340,7 +341,8 @@ class HTTP_ConditionalGet {
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function normalizeEtag($etag) {
|
||||
protected function normalizeEtag($etag)
|
||||
{
|
||||
$etag = trim($etag);
|
||||
|
||||
return $this->_stripEtag
|
||||
|
@@ -43,7 +43,8 @@
|
||||
* @subpackage HTTP
|
||||
* @author Stephen Clay <steve@mrclay.org>
|
||||
*/
|
||||
class HTTP_Encoder {
|
||||
class HTTP_Encoder
|
||||
{
|
||||
|
||||
/**
|
||||
* Should the encoder allow HTTP encoding to IE6?
|
||||
@@ -97,8 +98,7 @@ class HTTP_Encoder {
|
||||
$this->_headers['Content-Type'] = $spec['type'];
|
||||
}
|
||||
if (isset($spec['method'])
|
||||
&& in_array($spec['method'], array('gzip', 'deflate', 'compress', '')))
|
||||
{
|
||||
&& in_array($spec['method'], array('gzip', 'deflate', 'compress', ''))) {
|
||||
$this->_encodeMethod = array($spec['method'], $spec['method']);
|
||||
} else {
|
||||
$this->_encodeMethod = self::getAcceptedEncoding();
|
||||
@@ -192,8 +192,7 @@ class HTTP_Encoder {
|
||||
// @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
|
||||
|
||||
if (! isset($_SERVER['HTTP_ACCEPT_ENCODING'])
|
||||
|| self::isBuggyIe())
|
||||
{
|
||||
|| self::isBuggyIe()) {
|
||||
return array('', '');
|
||||
}
|
||||
$ae = $_SERVER['HTTP_ACCEPT_ENCODING'];
|
||||
@@ -259,8 +258,7 @@ class HTTP_Encoder {
|
||||
}
|
||||
if ('' === $this->_encodeMethod[0]
|
||||
|| ($compressionLevel == 0)
|
||||
|| !extension_loaded('zlib'))
|
||||
{
|
||||
|| !extension_loaded('zlib')) {
|
||||
return false;
|
||||
}
|
||||
if ($this->_encodeMethod[0] === 'deflate') {
|
||||
|
@@ -24,7 +24,8 @@ use Psr\Log\LoggerInterface;
|
||||
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
||||
* @link https://github.com/mrclay/minify
|
||||
*/
|
||||
class Minify {
|
||||
class Minify
|
||||
{
|
||||
|
||||
/**
|
||||
* API version
|
||||
@@ -87,7 +88,8 @@ class Minify {
|
||||
* @param Minify_CacheInterface $cache
|
||||
* @param LoggerInterface $logger
|
||||
*/
|
||||
public function __construct(Minify_CacheInterface $cache, LoggerInterface $logger = null) {
|
||||
public function __construct(Minify_CacheInterface $cache, LoggerInterface $logger = null)
|
||||
{
|
||||
$this->cache = $cache;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
@@ -272,7 +274,8 @@ class Minify {
|
||||
// depending on what the client accepts, $contentEncoding may be
|
||||
// 'x-gzip' while our internal encodeMethod is 'gzip'. Calling
|
||||
// getAcceptedEncoding(false, false) leaves out compress and deflate as options.
|
||||
list($this->options['encodeMethod'], $contentEncoding) = HTTP_Encoder::getAcceptedEncoding(false, false);
|
||||
$list = HTTP_Encoder::getAcceptedEncoding(false, false);
|
||||
list($this->options['encodeMethod'], $contentEncoding) = $list;
|
||||
$sendVary = ! HTTP_Encoder::isBuggyIe();
|
||||
}
|
||||
} else {
|
||||
@@ -492,11 +495,13 @@ class Minify {
|
||||
* @param string $content
|
||||
* @return string
|
||||
*/
|
||||
public static function nullMinifier($content) {
|
||||
public static function nullMinifier($content)
|
||||
{
|
||||
if (isset($content[0]) && $content[0] === "\xef") {
|
||||
$content = substr($content, 3);
|
||||
}
|
||||
$content = str_replace("\r\n", "\n", $content);
|
||||
|
||||
return trim($content);
|
||||
}
|
||||
|
||||
@@ -505,14 +510,14 @@ class Minify {
|
||||
*/
|
||||
protected function setupUriRewrites()
|
||||
{
|
||||
foreach($this->sources as $key => $source) {
|
||||
foreach ($this->sources as $key => $source) {
|
||||
$file = $this->env->normalizePath($source->getFilePath());
|
||||
$minifyOptions = $source->getMinifierOptions();
|
||||
|
||||
if ($file
|
||||
&& !isset($minifyOptions['currentDir'])
|
||||
&& !isset($minifyOptions['prependRelativePath'])
|
||||
) {
|
||||
&& !isset($minifyOptions['prependRelativePath'])) {
|
||||
|
||||
$minifyOptions['currentDir'] = dirname($file);
|
||||
$source->setMinifierOptions($minifyOptions);
|
||||
}
|
||||
@@ -592,9 +597,7 @@ class Minify {
|
||||
! $source // yes, we ran out of sources
|
||||
|| $type === self::TYPE_CSS // yes, to process CSS individually (avoiding PCRE bugs/limits)
|
||||
|| $minifier !== $lastMinifier // yes, minifier changed
|
||||
|| $options !== $lastOptions) // yes, options changed
|
||||
)
|
||||
{
|
||||
|| $options !== $lastOptions)) { // yes, options changed
|
||||
// minify previous sources with last settings
|
||||
$imploded = implode($implodeSeparator, $groupToProcessTogether);
|
||||
$groupToProcessTogether = array();
|
||||
@@ -717,10 +720,10 @@ class Minify {
|
||||
if (!empty($options['contentType'])) {
|
||||
// just verify sources have null content type or match the options
|
||||
if ($sourceType !== null && $sourceType !== $options['contentType']) {
|
||||
|
||||
$this->logger && $this->logger->warning('ContentType mismatch');
|
||||
$this->logger && $this->logger->warning("ContentType mismatch: '{$sourceType}' != '{$options['contentType']}'");
|
||||
|
||||
$this->sources = array();
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
@@ -730,10 +733,10 @@ class Minify {
|
||||
if ($type === null) {
|
||||
$type = $sourceType;
|
||||
} elseif ($sourceType !== $type) {
|
||||
|
||||
$this->logger && $this->logger->warning('ContentType mismatch');
|
||||
$this->logger && $this->logger->warning("ContentType mismatch: '{$sourceType}' != '{$type}'");
|
||||
|
||||
$this->sources = array();
|
||||
|
||||
return $options;
|
||||
}
|
||||
}
|
||||
|
@@ -3,7 +3,6 @@
|
||||
namespace Minify;
|
||||
|
||||
use Props\Container;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* @property \Minify_CacheInterface $cache
|
||||
@@ -22,7 +21,8 @@ use Psr\Log\LoggerInterface;
|
||||
* @property \Minify_Source_Factory $sourceFactory
|
||||
* @property array $sourceFactoryOptions
|
||||
*/
|
||||
class App extends Container {
|
||||
class App extends Container
|
||||
{
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@@ -64,9 +64,10 @@ class App extends Container {
|
||||
|
||||
$propNames = array_keys(get_object_vars($config));
|
||||
|
||||
$varNames = array_map(function ($name) {
|
||||
$prefixer = function ($name) {
|
||||
return "min_$name";
|
||||
}, $propNames);
|
||||
};
|
||||
$varNames = array_map($prefixer, $propNames);
|
||||
|
||||
$vars = compact($varNames);
|
||||
|
||||
@@ -104,12 +105,14 @@ class App extends Container {
|
||||
if (empty($config->documentRoot)) {
|
||||
return $app->env->getDocRoot();
|
||||
}
|
||||
|
||||
return $app->env->normalizePath($config->documentRoot);
|
||||
};
|
||||
|
||||
$this->env = function (App $app) {
|
||||
$config = $app->config;
|
||||
$envArgs = empty($config->envArgs) ? array() : $config->envArgs;
|
||||
|
||||
return new \Minify_Env($envArgs);
|
||||
};
|
||||
|
||||
@@ -117,6 +120,7 @@ class App extends Container {
|
||||
$format = "%channel%.%level_name%: %message% %context% %extra%";
|
||||
$handler = new \Monolog\Handler\ErrorLogHandler();
|
||||
$handler->setFormatter(new \Monolog\Formatter\LineFormatter($format));
|
||||
|
||||
return $handler;
|
||||
};
|
||||
|
||||
@@ -142,11 +146,13 @@ class App extends Container {
|
||||
if ($value === true || $value instanceof \FirePHP) {
|
||||
$logger->pushHandler($app->errorLogHandler);
|
||||
$logger->pushHandler(new \Monolog\Handler\FirePHPHandler());
|
||||
|
||||
return $logger;
|
||||
}
|
||||
|
||||
if ($value instanceof \Monolog\Handler\HandlerInterface) {
|
||||
$logger->pushHandler($value);
|
||||
|
||||
return $logger;
|
||||
}
|
||||
|
||||
@@ -154,6 +160,7 @@ class App extends Container {
|
||||
if (is_object($value) && is_callable(array($value, 'log'))) {
|
||||
$handler = new \Minify\Logger\LegacyHandler($value);
|
||||
$logger->pushHandler($handler);
|
||||
|
||||
return $logger;
|
||||
}
|
||||
|
||||
@@ -232,6 +239,10 @@ class App extends Container {
|
||||
$ret['allowDirs'] = $serveOptions['minApp']['allowDirs'];
|
||||
}
|
||||
|
||||
if (isset($serveOptions['checkAllowDirs'])) {
|
||||
$ret['checkAllowDirs'] = $serveOptions['checkAllowDirs'];
|
||||
}
|
||||
|
||||
if (is_numeric($app->config->uploaderHoursBehind)) {
|
||||
$ret['uploaderHoursBehind'] = $app->config->uploaderHoursBehind;
|
||||
}
|
||||
@@ -240,7 +251,8 @@ class App extends Container {
|
||||
};
|
||||
}
|
||||
|
||||
public function runServer() {
|
||||
public function runServer()
|
||||
{
|
||||
if (!$this->env->get('f') && $this->env->get('g') === null) {
|
||||
// no spec given
|
||||
$msg = '<p>No "f" or "g" parameters were detected.</p>';
|
||||
@@ -256,8 +268,10 @@ class App extends Container {
|
||||
* @param mixed $var
|
||||
* @return string
|
||||
*/
|
||||
private function typeOf($var) {
|
||||
private function typeOf($var)
|
||||
{
|
||||
$type = gettype($var);
|
||||
|
||||
return $type === 'object' ? get_class($var) : $type;
|
||||
}
|
||||
}
|
||||
|
@@ -34,7 +34,8 @@
|
||||
* @package Minify
|
||||
* @author Stephen Clay <steve@mrclay.org>
|
||||
*/
|
||||
class Minify_Build {
|
||||
class Minify_Build
|
||||
{
|
||||
|
||||
/**
|
||||
* Last modification time of all files in the build
|
||||
@@ -67,15 +68,14 @@ class Minify_Build {
|
||||
* append the timestamp to the URI.
|
||||
* @return string
|
||||
*/
|
||||
public function uri($uri, $forceAmpersand = false) {
|
||||
$sep = ($forceAmpersand || strpos($uri, '?') !== false)
|
||||
? self::$ampersand
|
||||
: '?';
|
||||
public function uri($uri, $forceAmpersand = false)
|
||||
{
|
||||
$sep = ($forceAmpersand || strpos($uri, '?') !== false) ? self::$ampersand : '?';
|
||||
|
||||
return "{$uri}{$sep}{$this->lastModified}";
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Create a build object
|
||||
*
|
||||
* @param array $sources array of Minify_Source objects and/or file paths
|
||||
|
@@ -16,7 +16,8 @@
|
||||
*
|
||||
* @deprecated Use Minify_CSSmin
|
||||
*/
|
||||
class Minify_CSS {
|
||||
class Minify_CSS
|
||||
{
|
||||
|
||||
/**
|
||||
* Minify a CSS string
|
||||
@@ -70,32 +71,27 @@ class Minify_CSS {
|
||||
if ($options['removeCharsets']) {
|
||||
$css = preg_replace('/@charset[^;]+;\\s*/', '', $css);
|
||||
}
|
||||
|
||||
if ($options['compress']) {
|
||||
if (! $options['preserveComments']) {
|
||||
$css = Minify_CSS_Compressor::process($css, $options);
|
||||
} else {
|
||||
$css = Minify_CommentPreserver::process(
|
||||
$css
|
||||
,array('Minify_CSS_Compressor', 'process')
|
||||
,array($options)
|
||||
);
|
||||
$processor = array('Minify_CSS_Compressor', 'process');
|
||||
$css = Minify_CommentPreserver::process($css, $processor, array($options));
|
||||
}
|
||||
}
|
||||
|
||||
if (! $options['currentDir'] && ! $options['prependRelativePath']) {
|
||||
return $css;
|
||||
}
|
||||
|
||||
if ($options['currentDir']) {
|
||||
return Minify_CSS_UriRewriter::rewrite(
|
||||
$css
|
||||
,$options['currentDir']
|
||||
,$options['docRoot']
|
||||
,$options['symlinks']
|
||||
);
|
||||
$currentDir = $options['currentDir'];
|
||||
$docRoot = $options['docRoot'];
|
||||
$symlinks = $options['symlinks'];
|
||||
return Minify_CSS_UriRewriter::rewrite($css, $currentDir, $docRoot, $symlinks);
|
||||
} else {
|
||||
return Minify_CSS_UriRewriter::prepend(
|
||||
$css
|
||||
,$options['prependRelativePath']
|
||||
);
|
||||
return Minify_CSS_UriRewriter::prepend($css, $options['prependRelativePath']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -26,7 +26,8 @@
|
||||
*
|
||||
* @deprecated Use CSSmin (tubalmartin/cssmin)
|
||||
*/
|
||||
class Minify_CSS_Compressor {
|
||||
class Minify_CSS_Compressor
|
||||
{
|
||||
|
||||
/**
|
||||
* Minify a CSS string
|
||||
@@ -61,7 +62,8 @@ class Minify_CSS_Compressor {
|
||||
*
|
||||
* @param array $options (currently ignored)
|
||||
*/
|
||||
private function __construct($options) {
|
||||
private function __construct($options)
|
||||
{
|
||||
$this->_options = $options;
|
||||
}
|
||||
|
||||
@@ -86,8 +88,8 @@ class Minify_CSS_Compressor {
|
||||
$css = preg_replace('@:\\s*/\\*\\s*\\*/@', ':/*keep*/', $css);
|
||||
|
||||
// apply callback to all valid comments (and strip out surrounding ws
|
||||
$css = preg_replace_callback('@\\s*/\\*([\\s\\S]*?)\\*/\\s*@'
|
||||
,array($this, '_commentCB'), $css);
|
||||
$pattern = '@\\s*/\\*([\\s\\S]*?)\\*/\\s*@';
|
||||
$css = preg_replace_callback($pattern, array($this, '_commentCB'), $css);
|
||||
|
||||
// remove ws around { } and last semicolon in declaration block
|
||||
$css = preg_replace('/\\s*{\\s*/', '{', $css);
|
||||
@@ -97,16 +99,17 @@ class Minify_CSS_Compressor {
|
||||
$css = preg_replace('/\\s*;\\s*/', ';', $css);
|
||||
|
||||
// remove ws around urls
|
||||
$css = preg_replace('/
|
||||
$pattern = '/
|
||||
url\\( # url(
|
||||
\\s*
|
||||
([^\\)]+?) # 1 = the URL (really just a bunch of non right parenthesis)
|
||||
\\s*
|
||||
\\) # )
|
||||
/x', 'url($1)', $css);
|
||||
/x';
|
||||
$css = preg_replace($pattern, 'url($1)', $css);
|
||||
|
||||
// remove ws between rules and colons
|
||||
$css = preg_replace('/
|
||||
$pattern = '/
|
||||
\\s*
|
||||
([{;]) # 1 = beginning of block or rule separator
|
||||
\\s*
|
||||
@@ -115,10 +118,11 @@ class Minify_CSS_Compressor {
|
||||
:
|
||||
\\s*
|
||||
(\\b|[#\'"-]) # 3 = first character of a value
|
||||
/x', '$1$2:$3', $css);
|
||||
/x';
|
||||
$css = preg_replace($pattern, '$1$2:$3', $css);
|
||||
|
||||
// remove ws in selectors
|
||||
$css = preg_replace_callback('/
|
||||
$pattern = '/
|
||||
(?: # non-capture
|
||||
\\s*
|
||||
[^~>+,\\s]+ # selector part
|
||||
@@ -128,16 +132,16 @@ class Minify_CSS_Compressor {
|
||||
\\s*
|
||||
[^~>+,\\s]+ # selector part
|
||||
{ # open declaration block
|
||||
/x'
|
||||
,array($this, '_selectorsCB'), $css);
|
||||
/x';
|
||||
$css = preg_replace_callback($pattern, array($this, '_selectorsCB'), $css);
|
||||
|
||||
// minimize hex colors
|
||||
$css = preg_replace('/([^=])#([a-f\\d])\\2([a-f\\d])\\3([a-f\\d])\\4([\\s;\\}])/i'
|
||||
, '$1#$2$3$4$5', $css);
|
||||
$pattern = '/([^=])#([a-f\\d])\\2([a-f\\d])\\3([a-f\\d])\\4([\\s;\\}])/i';
|
||||
$css = preg_replace($pattern, '$1#$2$3$4$5', $css);
|
||||
|
||||
// remove spaces between font families
|
||||
$css = preg_replace_callback('/font-family:([^;}]+)([;}])/'
|
||||
,array($this, '_fontFamilyCB'), $css);
|
||||
$pattern = '/font-family:([^;}]+)([;}])/';
|
||||
$css = preg_replace_callback($pattern, array($this, '_fontFamilyCB'), $css);
|
||||
|
||||
$css = preg_replace('/@import\\s+url/', '@import url', $css);
|
||||
|
||||
@@ -145,14 +149,15 @@ class Minify_CSS_Compressor {
|
||||
$css = preg_replace('/[ \\t]*\\n+\\s*/', "\n", $css);
|
||||
|
||||
// separate common descendent selectors w/ newlines (to limit line lengths)
|
||||
$css = preg_replace('/([\\w#\\.\\*]+)\\s+([\\w#\\.\\*]+){/', "$1\n$2{", $css);
|
||||
$pattern = '/([\\w#\\.\\*]+)\\s+([\\w#\\.\\*]+){/';
|
||||
$css = preg_replace($pattern, "$1\n$2{", $css);
|
||||
|
||||
// Use newline after 1st numeric value (to limit line lengths).
|
||||
$css = preg_replace('/
|
||||
$pattern = '/
|
||||
((?:padding|margin|border|outline):\\d+(?:px|em)?) # 1 = prop : 1st numeric value
|
||||
\\s+
|
||||
/x'
|
||||
,"$1\n", $css);
|
||||
/x';
|
||||
$css = preg_replace($pattern, "$1\n", $css);
|
||||
|
||||
// prevent triggering IE6 bug: http://www.crankygeek.com/ie6pebug/
|
||||
$css = preg_replace('/:first-l(etter|ine)\\{/', ':first-l$1 {', $css);
|
||||
@@ -189,52 +194,54 @@ class Minify_CSS_Compressor {
|
||||
if ($m === 'keep') {
|
||||
return '/**/';
|
||||
}
|
||||
|
||||
if ($m === '" "') {
|
||||
// component of http://tantek.com/CSS/Examples/midpass.html
|
||||
return '/*" "*/';
|
||||
}
|
||||
|
||||
if (preg_match('@";\\}\\s*\\}/\\*\\s+@', $m)) {
|
||||
// component of http://tantek.com/CSS/Examples/midpass.html
|
||||
return '/*";}}/* */';
|
||||
}
|
||||
|
||||
if ($this->_inHack) {
|
||||
// inversion: feeding only to one browser
|
||||
if (preg_match('@
|
||||
$pattern = '@
|
||||
^/ # comment started like /*/
|
||||
\\s*
|
||||
(\\S[\\s\\S]+?) # has at least some non-ws content
|
||||
\\s*
|
||||
/\\* # ends like /*/ or /**/
|
||||
@x', $m, $n)) {
|
||||
@x';
|
||||
if (preg_match($pattern, $m, $n)) {
|
||||
// end hack mode after this comment, but preserve the hack and comment content
|
||||
$this->_inHack = false;
|
||||
|
||||
return "/*/{$n[1]}/**/";
|
||||
}
|
||||
}
|
||||
|
||||
if (substr($m, -1) === '\\') { // comment ends like \*/
|
||||
// begin hack mode and preserve hack
|
||||
$this->_inHack = true;
|
||||
|
||||
return '/*\\*/';
|
||||
}
|
||||
|
||||
if ($m !== '' && $m[0] === '/') { // comment looks like /*/ foo */
|
||||
// begin hack mode and preserve hack
|
||||
$this->_inHack = true;
|
||||
|
||||
return '/*/*/';
|
||||
}
|
||||
|
||||
if ($this->_inHack) {
|
||||
// a regular comment ends hack mode but should be preserved
|
||||
$this->_inHack = false;
|
||||
|
||||
return '/**/';
|
||||
}
|
||||
|
||||
// Issue 107: if there's any surrounding whitespace, it may be important, so
|
||||
// replace the comment with a single space
|
||||
return $hasSurroundingWs // remove all other comments
|
||||
? ' '
|
||||
: '';
|
||||
return $hasSurroundingWs ? ' ' : ''; // remove all other comments
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -247,8 +254,10 @@ class Minify_CSS_Compressor {
|
||||
protected function _fontFamilyCB($m)
|
||||
{
|
||||
// Issue 210: must not eliminate WS between words in unquoted families
|
||||
$pieces = preg_split('/(\'[^\']+\'|"[^"]+")/', $m[1], null, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
|
||||
$flags = PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY;
|
||||
$pieces = preg_split('/(\'[^\']+\'|"[^"]+")/', $m[1], null, $flags);
|
||||
$out = 'font-family:';
|
||||
|
||||
while (null !== ($piece = array_shift($pieces))) {
|
||||
if ($piece[0] !== '"' && $piece[0] !== "'") {
|
||||
$piece = preg_replace('/\\s+/', ' ', $piece);
|
||||
|
@@ -10,7 +10,8 @@
|
||||
* @package Minify
|
||||
* @author Stephen Clay <steve@mrclay.org>
|
||||
*/
|
||||
class Minify_CSS_UriRewriter {
|
||||
class Minify_CSS_UriRewriter
|
||||
{
|
||||
|
||||
/**
|
||||
* rewrite() and rewriteRelative() append debugging information here
|
||||
@@ -51,10 +52,10 @@ class Minify_CSS_UriRewriter {
|
||||
|
||||
// normalize symlinks in order to map to link
|
||||
foreach ($symlinks as $link => $target) {
|
||||
$link = ($link === '//')
|
||||
? self::$_docRoot
|
||||
: str_replace('//', self::$_docRoot . '/', $link);
|
||||
|
||||
$link = ($link === '//') ? self::$_docRoot : str_replace('//', self::$_docRoot . '/', $link);
|
||||
$link = strtr($link, '/', DIRECTORY_SEPARATOR);
|
||||
|
||||
self::$_symlinks[$link] = self::_realpath($target);
|
||||
}
|
||||
|
||||
@@ -70,10 +71,11 @@ class Minify_CSS_UriRewriter {
|
||||
$css = self::_owlifySvgPaths($css);
|
||||
|
||||
// rewrite
|
||||
$css = preg_replace_callback('/@import\\s+([\'"])(.*?)[\'"]/'
|
||||
,array(self::$className, '_processUriCB'), $css);
|
||||
$css = preg_replace_callback('/url\\(\\s*([\'"](.*?)[\'"]|[^\\)\\s]+)\\s*\\)/'
|
||||
,array(self::$className, '_processUriCB'), $css);
|
||||
$pattern = '/@import\\s+([\'"])(.*?)[\'"]/';
|
||||
$css = preg_replace_callback($pattern, array(self::$className, '_processUriCB'), $css);
|
||||
|
||||
$pattern = '/url\\(\\s*([\'"](.*?)[\'"]|[^\\)\\s]+)\\s*\\)/';
|
||||
$css = preg_replace_callback($pattern, array(self::$className, '_processUriCB'), $css);
|
||||
|
||||
$css = self::_unOwlify($css);
|
||||
|
||||
@@ -98,10 +100,11 @@ class Minify_CSS_UriRewriter {
|
||||
$css = self::_owlifySvgPaths($css);
|
||||
|
||||
// append
|
||||
$css = preg_replace_callback('/@import\\s+([\'"])(.*?)[\'"]/'
|
||||
,array(self::$className, '_processUriCB'), $css);
|
||||
$css = preg_replace_callback('/url\\(\\s*([\'"](.*?)[\'"]|[^\\)\\s]+)\\s*\\)/'
|
||||
,array(self::$className, '_processUriCB'), $css);
|
||||
$pattern = '/@import\\s+([\'"])(.*?)[\'"]/';
|
||||
$css = preg_replace_callback($pattern, array(self::$className, '_processUriCB'), $css);
|
||||
|
||||
$pattern = '/url\\(\\s*([\'"](.*?)[\'"]|[^\\)\\s]+)\\s*\\)/';
|
||||
$css = preg_replace_callback($pattern, array(self::$className, '_processUriCB'), $css);
|
||||
|
||||
$css = self::_unOwlify($css);
|
||||
|
||||
@@ -151,8 +154,8 @@ class Minify_CSS_UriRewriter {
|
||||
public static function rewriteRelative($uri, $realCurrentDir, $realDocRoot, $symlinks = array())
|
||||
{
|
||||
// prepend path with current dir separator (OS-independent)
|
||||
$path = strtr($realCurrentDir, '/', DIRECTORY_SEPARATOR)
|
||||
. DIRECTORY_SEPARATOR . strtr($uri, '/', DIRECTORY_SEPARATOR);
|
||||
$path = strtr($realCurrentDir, '/', DIRECTORY_SEPARATOR);
|
||||
$path .= DIRECTORY_SEPARATOR . strtr($uri, '/', DIRECTORY_SEPARATOR);
|
||||
|
||||
self::$debugText .= "file-relative URI : {$uri}\n"
|
||||
. "path prepended : {$path}\n";
|
||||
@@ -262,13 +265,14 @@ class Minify_CSS_UriRewriter {
|
||||
*/
|
||||
private static function _trimUrls($css)
|
||||
{
|
||||
return preg_replace('/
|
||||
$pattern = '/
|
||||
url\\( # url(
|
||||
\\s*
|
||||
([^\\)]+?) # 1 = URI (assuming does not contain ")")
|
||||
\\s*
|
||||
\\) # )
|
||||
/x', 'url($1)', $css);
|
||||
/x';
|
||||
return preg_replace($pattern, 'url($1)', $css);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -286,13 +290,15 @@ class Minify_CSS_UriRewriter {
|
||||
$uri = $m[2];
|
||||
} else {
|
||||
// $m[1] is either quoted or not
|
||||
$quoteChar = ($m[1][0] === "'" || $m[1][0] === '"')
|
||||
? $m[1][0]
|
||||
: '';
|
||||
$uri = ($quoteChar === '')
|
||||
? $m[1]
|
||||
: substr($m[1], 1, strlen($m[1]) - 2);
|
||||
$quoteChar = ($m[1][0] === "'" || $m[1][0] === '"') ? $m[1][0] : '';
|
||||
|
||||
$uri = ($quoteChar === '') ? $m[1] : substr($m[1], 1, strlen($m[1]) - 2);
|
||||
}
|
||||
|
||||
if ($uri === '') {
|
||||
return $m[0];
|
||||
}
|
||||
|
||||
// if not root/scheme relative and not starts with scheme
|
||||
if (!preg_match('~^(/|[a-z]+\:)~', $uri)) {
|
||||
// URI is file-relative: rewrite depending on options
|
||||
@@ -312,9 +318,11 @@ class Minify_CSS_UriRewriter {
|
||||
}
|
||||
}
|
||||
|
||||
return $isImport
|
||||
? "@import {$quoteChar}{$uri}{$quoteChar}"
|
||||
: "url({$quoteChar}{$uri}{$quoteChar})";
|
||||
if ($isImport) {
|
||||
return "@import {$quoteChar}{$uri}{$quoteChar}";
|
||||
} else {
|
||||
return "url({$quoteChar}{$uri}{$quoteChar})";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -326,8 +334,10 @@ class Minify_CSS_UriRewriter {
|
||||
* @param string $css
|
||||
* @return string
|
||||
*/
|
||||
private static function _owlifySvgPaths($css) {
|
||||
return preg_replace('~\b((?:clip-path|mask|-webkit-mask)\s*\:\s*)url(\(\s*#\w+\s*\))~', '$1owl$2', $css);
|
||||
private static function _owlifySvgPaths($css)
|
||||
{
|
||||
$pattern = '~\b((?:clip-path|mask|-webkit-mask)\s*\:\s*)url(\(\s*#\w+\s*\))~';
|
||||
return preg_replace($pattern, '$1owl$2', $css);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -338,7 +348,9 @@ class Minify_CSS_UriRewriter {
|
||||
* @param string $css
|
||||
* @return string
|
||||
*/
|
||||
private static function _unOwlify($css) {
|
||||
return preg_replace('~\b((?:clip-path|mask|-webkit-mask)\s*\:\s*)owl~', '$1url', $css);
|
||||
private static function _unOwlify($css)
|
||||
{
|
||||
$pattern = '~\b((?:clip-path|mask|-webkit-mask)\s*\:\s*)owl~';
|
||||
return preg_replace($pattern, '$1url', $css);
|
||||
}
|
||||
}
|
||||
|
@@ -12,7 +12,8 @@
|
||||
* @package Minify
|
||||
* @author Stephen Clay <steve@mrclay.org>
|
||||
*/
|
||||
class Minify_CSSmin {
|
||||
class Minify_CSSmin
|
||||
{
|
||||
|
||||
/**
|
||||
* Minify a CSS string
|
||||
|
@@ -14,7 +14,8 @@
|
||||
* @package Minify
|
||||
* @author Chris Edwards
|
||||
**/
|
||||
class Minify_Cache_APC implements Minify_CacheInterface {
|
||||
class Minify_Cache_APC implements Minify_CacheInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* Create a Minify_Cache_APC object, to be passed to
|
||||
@@ -58,9 +59,11 @@ class Minify_Cache_APC implements Minify_CacheInterface {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2))
|
||||
? mb_strlen($this->_data, '8bit')
|
||||
: strlen($this->_data);
|
||||
if (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) {
|
||||
return mb_strlen($this->_data, '8bit');
|
||||
} else {
|
||||
return strlen($this->_data);;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,9 +87,7 @@ class Minify_Cache_APC implements Minify_CacheInterface {
|
||||
*/
|
||||
public function display($id)
|
||||
{
|
||||
echo $this->_fetch($id)
|
||||
? $this->_data
|
||||
: '';
|
||||
echo $this->_fetch($id) ? $this->_data : '';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -98,9 +99,7 @@ class Minify_Cache_APC implements Minify_CacheInterface {
|
||||
*/
|
||||
public function fetch($id)
|
||||
{
|
||||
return $this->_fetch($id)
|
||||
? $this->_data
|
||||
: '';
|
||||
return $this->_fetch($id) ? $this->_data : '';
|
||||
}
|
||||
|
||||
private $_exp = null;
|
||||
@@ -125,9 +124,9 @@ class Minify_Cache_APC implements Minify_CacheInterface {
|
||||
$ret = apc_fetch($id);
|
||||
if (false === $ret) {
|
||||
$this->_id = null;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
list($this->_lm, $this->_data) = explode('|', $ret, 2);
|
||||
$this->_id = $id;
|
||||
|
||||
|
@@ -6,7 +6,8 @@
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class Minify_Cache_File implements Minify_CacheInterface {
|
||||
class Minify_Cache_File implements Minify_CacheInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @var string
|
||||
@@ -53,17 +54,18 @@ class Minify_Cache_File implements Minify_CacheInterface {
|
||||
*/
|
||||
public function store($id, $data)
|
||||
{
|
||||
$flag = $this->locking
|
||||
? LOCK_EX
|
||||
: null;
|
||||
$flag = $this->locking ? LOCK_EX : null;
|
||||
$file = $this->path . '/' . $id;
|
||||
|
||||
if (! @file_put_contents($file, $data, $flag)) {
|
||||
$this->logger->warning("Minify_Cache_File: Write failed to '$file'");
|
||||
}
|
||||
|
||||
// write control
|
||||
if ($data !== $this->fetch($id)) {
|
||||
@unlink($file);
|
||||
$this->logger->warning("Minify_Cache_File: Post-write read failed for '$file'");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -105,18 +107,19 @@ class Minify_Cache_File implements Minify_CacheInterface {
|
||||
*/
|
||||
public function display($id)
|
||||
{
|
||||
if ($this->locking) {
|
||||
$fp = fopen($this->path . '/' . $id, 'rb');
|
||||
flock($fp, LOCK_SH);
|
||||
fpassthru($fp);
|
||||
flock($fp, LOCK_UN);
|
||||
fclose($fp);
|
||||
} else {
|
||||
if (!$this->locking) {
|
||||
readfile($this->path . '/' . $id);
|
||||
return;
|
||||
}
|
||||
|
||||
$fp = fopen($this->path . '/' . $id, 'rb');
|
||||
flock($fp, LOCK_SH);
|
||||
fpassthru($fp);
|
||||
flock($fp, LOCK_UN);
|
||||
fclose($fp);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Fetch the cached content
|
||||
*
|
||||
* @param string $id cache id (e.g. a filename)
|
||||
@@ -125,20 +128,21 @@ class Minify_Cache_File implements Minify_CacheInterface {
|
||||
*/
|
||||
public function fetch($id)
|
||||
{
|
||||
if ($this->locking) {
|
||||
$fp = fopen($this->path . '/' . $id, 'rb');
|
||||
if (!$fp) {
|
||||
return false;
|
||||
}
|
||||
flock($fp, LOCK_SH);
|
||||
$ret = stream_get_contents($fp);
|
||||
flock($fp, LOCK_UN);
|
||||
fclose($fp);
|
||||
|
||||
return $ret;
|
||||
} else {
|
||||
if (!$this->locking) {
|
||||
return file_get_contents($this->path . '/' . $id);
|
||||
}
|
||||
|
||||
$fp = fopen($this->path . '/' . $id, 'rb');
|
||||
if (!$fp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
flock($fp, LOCK_SH);
|
||||
$ret = stream_get_contents($fp);
|
||||
flock($fp, LOCK_UN);
|
||||
fclose($fp);
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -160,6 +164,7 @@ class Minify_Cache_File implements Minify_CacheInterface {
|
||||
public static function tmp()
|
||||
{
|
||||
trigger_error(__METHOD__ . ' is deprecated in Minfy 3.0', E_USER_DEPRECATED);
|
||||
|
||||
return sys_get_temp_dir();
|
||||
}
|
||||
|
||||
|
@@ -17,7 +17,8 @@
|
||||
* }
|
||||
* </code>
|
||||
**/
|
||||
class Minify_Cache_Memcache implements Minify_CacheInterface {
|
||||
class Minify_Cache_Memcache implements Minify_CacheInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* Create a Minify_Cache_Memcache object, to be passed to
|
||||
@@ -61,9 +62,11 @@ class Minify_Cache_Memcache implements Minify_CacheInterface {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2))
|
||||
? mb_strlen($this->_data, '8bit')
|
||||
: strlen($this->_data);
|
||||
if (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) {
|
||||
return mb_strlen($this->_data, '8bit');
|
||||
} else {
|
||||
return strlen($this->_data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -87,12 +90,10 @@ class Minify_Cache_Memcache implements Minify_CacheInterface {
|
||||
*/
|
||||
public function display($id)
|
||||
{
|
||||
echo $this->_fetch($id)
|
||||
? $this->_data
|
||||
: '';
|
||||
echo $this->_fetch($id) ? $this->_data : '';
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Fetch the cached content
|
||||
*
|
||||
* @param string $id cache id
|
||||
@@ -101,9 +102,7 @@ class Minify_Cache_Memcache implements Minify_CacheInterface {
|
||||
*/
|
||||
public function fetch($id)
|
||||
{
|
||||
return $this->_fetch($id)
|
||||
? $this->_data
|
||||
: '';
|
||||
return $this->_fetch($id) ? $this->_data : '';
|
||||
}
|
||||
|
||||
private $_mc = null;
|
||||
@@ -114,7 +113,7 @@ class Minify_Cache_Memcache implements Minify_CacheInterface {
|
||||
private $_data = null;
|
||||
private $_id = null;
|
||||
|
||||
/**
|
||||
/**
|
||||
* Fetch data and timestamp from memcache, store in instance
|
||||
*
|
||||
* @param string $id
|
||||
@@ -126,12 +125,14 @@ class Minify_Cache_Memcache implements Minify_CacheInterface {
|
||||
if ($this->_id === $id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$ret = $this->_mc->get($id);
|
||||
if (false === $ret) {
|
||||
$this->_id = null;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
list($this->_lm, $this->_data) = explode('|', $ret, 2);
|
||||
$this->_id = $id;
|
||||
|
||||
|
@@ -8,7 +8,8 @@
|
||||
*
|
||||
* @package Minify
|
||||
*/
|
||||
class Minify_Cache_Null implements Minify_CacheInterface {
|
||||
class Minify_Cache_Null implements Minify_CacheInterface
|
||||
{
|
||||
/**
|
||||
* Write data to cache.
|
||||
*
|
||||
|
@@ -60,7 +60,11 @@ class Minify_Cache_WinCache implements Minify_CacheInterface
|
||||
return false;
|
||||
}
|
||||
|
||||
return (function_exists('mb_strlen') && ((int) ini_get('mbstring.func_overload') & 2)) ? mb_strlen($this->_data, '8bit') : strlen($this->_data);
|
||||
if (function_exists('mb_strlen') && ((int) ini_get('mbstring.func_overload') & 2)) {
|
||||
return mb_strlen($this->_data, '8bit');
|
||||
} else {
|
||||
return strlen($this->_data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -99,12 +103,12 @@ class Minify_Cache_WinCache implements Minify_CacheInterface
|
||||
return $this->_fetch($id) ? $this->_data : '';
|
||||
}
|
||||
|
||||
private $_exp = NULL;
|
||||
private $_exp = null;
|
||||
|
||||
// cache of most recently fetched id
|
||||
private $_lm = NULL;
|
||||
private $_data = NULL;
|
||||
private $_id = NULL;
|
||||
private $_lm = null;
|
||||
private $_data = null;
|
||||
private $_id = null;
|
||||
|
||||
/**
|
||||
* Fetch data and timestamp from WinCache, store in instance
|
||||
@@ -118,13 +122,15 @@ class Minify_Cache_WinCache implements Minify_CacheInterface
|
||||
if ($this->_id === $id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$suc = false;
|
||||
$ret = wincache_ucache_get($id, $suc);
|
||||
if (!$suc) {
|
||||
$this->_id = NULL;
|
||||
$this->_id = null;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
list($this->_lm, $this->_data) = explode('|', $ret, 2);
|
||||
$this->_id = $id;
|
||||
|
||||
|
@@ -17,7 +17,8 @@
|
||||
* @package Minify
|
||||
* @author Elan Ruusamäe <glen@delfi.ee>
|
||||
**/
|
||||
class Minify_Cache_XCache implements Minify_CacheInterface {
|
||||
class Minify_Cache_XCache implements Minify_CacheInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* Create a Minify_Cache_XCache object, to be passed to
|
||||
@@ -55,9 +56,11 @@ class Minify_Cache_XCache implements Minify_CacheInterface {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2))
|
||||
? mb_strlen($this->_data, '8bit')
|
||||
: strlen($this->_data);
|
||||
if (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) {
|
||||
return mb_strlen($this->_data, '8bit');
|
||||
} else {
|
||||
return strlen($this->_data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -79,9 +82,7 @@ class Minify_Cache_XCache implements Minify_CacheInterface {
|
||||
*/
|
||||
public function display($id)
|
||||
{
|
||||
echo $this->_fetch($id)
|
||||
? $this->_data
|
||||
: '';
|
||||
echo $this->_fetch($id) ? $this->_data : '';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,9 +93,7 @@ class Minify_Cache_XCache implements Minify_CacheInterface {
|
||||
*/
|
||||
public function fetch($id)
|
||||
{
|
||||
return $this->_fetch($id)
|
||||
? $this->_data
|
||||
: '';
|
||||
return $this->_fetch($id) ? $this->_data : '';
|
||||
}
|
||||
|
||||
private $_exp = null;
|
||||
@@ -115,12 +114,14 @@ class Minify_Cache_XCache implements Minify_CacheInterface {
|
||||
if ($this->_id === $id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$ret = xcache_get($id);
|
||||
if (false === $ret) {
|
||||
$this->_id = null;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
list($this->_lm, $this->_data) = explode('|', $ret, 2);
|
||||
$this->_id = $id;
|
||||
|
||||
|
@@ -16,7 +16,8 @@
|
||||
* @package Minify
|
||||
* @author Patrick van Dissel
|
||||
*/
|
||||
class Minify_Cache_ZendPlatform implements Minify_CacheInterface {
|
||||
class Minify_Cache_ZendPlatform implements Minify_CacheInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* Create a Minify_Cache_ZendPlatform object, to be passed to
|
||||
@@ -54,9 +55,7 @@ class Minify_Cache_ZendPlatform implements Minify_CacheInterface {
|
||||
*/
|
||||
public function getSize($id)
|
||||
{
|
||||
return $this->_fetch($id)
|
||||
? strlen($this->_data)
|
||||
: false;
|
||||
return $this->_fetch($id) ? strlen($this->_data) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -70,9 +69,7 @@ class Minify_Cache_ZendPlatform implements Minify_CacheInterface {
|
||||
*/
|
||||
public function isValid($id, $srcMtime)
|
||||
{
|
||||
$ret = ($this->_fetch($id) && ($this->_lm >= $srcMtime));
|
||||
|
||||
return $ret;
|
||||
return ($this->_fetch($id) && ($this->_lm >= $srcMtime));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,9 +79,7 @@ class Minify_Cache_ZendPlatform implements Minify_CacheInterface {
|
||||
*/
|
||||
public function display($id)
|
||||
{
|
||||
echo $this->_fetch($id)
|
||||
? $this->_data
|
||||
: '';
|
||||
echo $this->_fetch($id) ? $this->_data : '';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,9 +91,7 @@ class Minify_Cache_ZendPlatform implements Minify_CacheInterface {
|
||||
*/
|
||||
public function fetch($id)
|
||||
{
|
||||
return $this->_fetch($id)
|
||||
? $this->_data
|
||||
: '';
|
||||
return $this->_fetch($id) ? $this->_data : '';
|
||||
}
|
||||
|
||||
private $_exp = null;
|
||||
@@ -120,12 +113,14 @@ class Minify_Cache_ZendPlatform implements Minify_CacheInterface {
|
||||
if ($this->_id === $id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$ret = output_cache_get($id, $this->_exp);
|
||||
if (false === $ret) {
|
||||
$this->_id = null;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
list($this->_lm, $this->_data) = explode('|', $ret, 2);
|
||||
$this->_id = $id;
|
||||
|
||||
|
@@ -9,7 +9,8 @@
|
||||
*
|
||||
* @package Minify
|
||||
*/
|
||||
interface Minify_CacheInterface {
|
||||
interface Minify_CacheInterface
|
||||
{
|
||||
/**
|
||||
* Write data to cache.
|
||||
*
|
||||
|
@@ -24,19 +24,12 @@
|
||||
*
|
||||
* </code>
|
||||
*
|
||||
* @todo unit tests, $options docs
|
||||
* @todo more options support (or should just passthru them all?)
|
||||
*
|
||||
* @package Minify
|
||||
* @author Stephen Clay <steve@mrclay.org>
|
||||
* @author Elan Ruusamäe <glen@delfi.ee>
|
||||
*/
|
||||
class Minify_ClosureCompiler
|
||||
{
|
||||
const OPTION_CHARSET = 'charset';
|
||||
const OPTION_COMPILATION_LEVEL = 'compilation_level';
|
||||
const OPTION_WARNING_LEVEL = 'warning_level';
|
||||
|
||||
public static $isDebug = false;
|
||||
|
||||
/**
|
||||
@@ -61,6 +54,17 @@ class Minify_ClosureCompiler
|
||||
*/
|
||||
public static $javaExecutable = 'java';
|
||||
|
||||
/**
|
||||
* Default command line options passed to closure-compiler
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $defaultOptions = array(
|
||||
'charset' => 'utf-8',
|
||||
'compilation_level' => 'SIMPLE_OPTIMIZATIONS',
|
||||
'warning_level' => 'QUIET',
|
||||
);
|
||||
|
||||
/**
|
||||
* Minify a Javascript string
|
||||
*
|
||||
@@ -137,7 +141,8 @@ class Minify_ClosureCompiler
|
||||
$this->checkJar(self::$jarFile);
|
||||
$server = array(
|
||||
self::$javaExecutable,
|
||||
'-jar', escapeshellarg(self::$jarFile)
|
||||
'-jar',
|
||||
escapeshellarg(self::$jarFile)
|
||||
);
|
||||
|
||||
return $server;
|
||||
@@ -151,24 +156,13 @@ class Minify_ClosureCompiler
|
||||
{
|
||||
$args = array();
|
||||
|
||||
$o = array_merge(
|
||||
array(
|
||||
self::OPTION_CHARSET => 'utf-8',
|
||||
self::OPTION_COMPILATION_LEVEL => 'SIMPLE_OPTIMIZATIONS',
|
||||
self::OPTION_WARNING_LEVEL => 'QUIET',
|
||||
),
|
||||
$options = array_merge(
|
||||
static::$defaultOptions,
|
||||
$userOptions
|
||||
);
|
||||
|
||||
$charsetOption = $o[self::OPTION_CHARSET];
|
||||
if (preg_match('/^[\\da-zA-Z0-9\\-]+$/', $charsetOption)) {
|
||||
$args[] = "--charset {$charsetOption}";
|
||||
}
|
||||
|
||||
foreach (array(self::OPTION_COMPILATION_LEVEL, self::OPTION_WARNING_LEVEL) as $opt) {
|
||||
if ($o[$opt]) {
|
||||
$args[] = "--{$opt} " . escapeshellarg($o[$opt]);
|
||||
}
|
||||
foreach ($options as $key => $value) {
|
||||
$args[] = "--{$key} " . escapeshellarg($value);
|
||||
}
|
||||
|
||||
return $args;
|
||||
|
@@ -10,7 +10,8 @@
|
||||
* @package Minify
|
||||
* @author Stephen Clay <steve@mrclay.org>
|
||||
*/
|
||||
class Minify_CommentPreserver {
|
||||
class Minify_CommentPreserver
|
||||
{
|
||||
|
||||
/**
|
||||
* String to be prepended to each preserved comment
|
||||
@@ -71,21 +72,16 @@ class Minify_CommentPreserver {
|
||||
*/
|
||||
private static function _nextComment($in)
|
||||
{
|
||||
if (
|
||||
false === ($start = strpos($in, '/*!'))
|
||||
|| false === ($end = strpos($in, '*/', $start + 3))
|
||||
) {
|
||||
if (false === ($start = strpos($in, '/*!')) || false === ($end = strpos($in, '*/', $start + 3))) {
|
||||
return array($in, false, false);
|
||||
}
|
||||
$ret = array(
|
||||
substr($in, 0, $start)
|
||||
,self::$prepend . '/*!' . substr($in, $start + 3, $end - $start - 1) . self::$append
|
||||
);
|
||||
$endChars = (strlen($in) - $end - 2);
|
||||
$ret[] = (0 === $endChars)
|
||||
? ''
|
||||
: substr($in, -$endChars);
|
||||
|
||||
return $ret;
|
||||
$beforeComment = substr($in, 0, $start);
|
||||
$comment = self::$prepend . '/*!' . substr($in, $start + 3, $end - $start - 1) . self::$append;
|
||||
|
||||
$endChars = (strlen($in) - $end - 2);
|
||||
$afterComment = (0 === $endChars) ? '' : substr($in, -$endChars);
|
||||
|
||||
return array($beforeComment, $comment, $afterComment);
|
||||
}
|
||||
}
|
||||
|
@@ -15,7 +15,8 @@ use Monolog\Logger;
|
||||
* @package Minify
|
||||
* @author Stephen Clay <steve@mrclay.org>
|
||||
*/
|
||||
abstract class Minify_Controller_Base implements Minify_ControllerInterface {
|
||||
abstract class Minify_Controller_Base implements Minify_ControllerInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @var Minify_Env
|
||||
|
@@ -4,7 +4,6 @@
|
||||
* @package Minify
|
||||
*/
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Monolog\Logger;
|
||||
|
||||
/**
|
||||
@@ -29,7 +28,8 @@ use Monolog\Logger;
|
||||
* @package Minify
|
||||
* @author Stephen Clay <steve@mrclay.org>
|
||||
*/
|
||||
class Minify_Controller_Files extends Minify_Controller_Base {
|
||||
class Minify_Controller_Files extends Minify_Controller_Base
|
||||
{
|
||||
|
||||
/**
|
||||
* Set up file sources
|
||||
@@ -41,7 +41,8 @@ class Minify_Controller_Files extends Minify_Controller_Base {
|
||||
*
|
||||
* 'files': (required) array of complete file paths, or a single path
|
||||
*/
|
||||
public function createConfiguration(array $options) {
|
||||
public function createConfiguration(array $options)
|
||||
{
|
||||
// strip controller options
|
||||
|
||||
$files = $options['files'];
|
||||
|
@@ -23,7 +23,8 @@
|
||||
* @package Minify
|
||||
* @author Stephen Clay <steve@mrclay.org>
|
||||
*/
|
||||
class Minify_Controller_Groups extends Minify_Controller_Files {
|
||||
class Minify_Controller_Groups extends Minify_Controller_Files
|
||||
{
|
||||
|
||||
/**
|
||||
* Set up groups of files as sources
|
||||
@@ -35,7 +36,8 @@ class Minify_Controller_Groups extends Minify_Controller_Files {
|
||||
*
|
||||
* @return array Minify options
|
||||
*/
|
||||
public function createConfiguration(array $options) {
|
||||
public function createConfiguration(array $options)
|
||||
{
|
||||
// strip controller options
|
||||
$groups = $options['groups'];
|
||||
unset($options['groups']);
|
||||
@@ -43,12 +45,14 @@ class Minify_Controller_Groups extends Minify_Controller_Files {
|
||||
$server = $this->env->server();
|
||||
|
||||
// mod_fcgid places PATH_INFO in ORIG_PATH_INFO
|
||||
$pathInfo = isset($server['ORIG_PATH_INFO'])
|
||||
? substr($server['ORIG_PATH_INFO'], 1)
|
||||
: (isset($server['PATH_INFO'])
|
||||
? substr($server['PATH_INFO'], 1)
|
||||
: false
|
||||
);
|
||||
if (isset($server['ORIG_PATH_INFO'])) {
|
||||
$pathInfo = substr($server['ORIG_PATH_INFO'], 1);
|
||||
} elseif (isset($server['PATH_INFO'])) {
|
||||
$pathInfo = substr($server['PATH_INFO'], 1)
|
||||
} else {
|
||||
$pathInfo = false;
|
||||
}
|
||||
|
||||
if (false === $pathInfo || ! isset($groups[$pathInfo])) {
|
||||
// no PATH_INFO or not a valid group
|
||||
$this->logger->info("Missing PATH_INFO or no group set for \"$pathInfo\"");
|
||||
|
@@ -10,7 +10,8 @@
|
||||
* @package Minify
|
||||
* @author Stephen Clay <steve@mrclay.org>
|
||||
*/
|
||||
class Minify_Controller_MinApp extends Minify_Controller_Base {
|
||||
class Minify_Controller_MinApp extends Minify_Controller_Base
|
||||
{
|
||||
|
||||
/**
|
||||
* Set up groups of files as sources
|
||||
@@ -19,7 +20,8 @@ class Minify_Controller_MinApp extends Minify_Controller_Base {
|
||||
*
|
||||
* @return array Minify options
|
||||
*/
|
||||
public function createConfiguration(array $options) {
|
||||
public function createConfiguration(array $options)
|
||||
{
|
||||
// PHP insecure by default: realpath() and other FS functions can't handle null bytes.
|
||||
$get = $this->env->get();
|
||||
foreach (array('g', 'b', 'f') as $key) {
|
||||
@@ -29,14 +31,14 @@ class Minify_Controller_MinApp extends Minify_Controller_Base {
|
||||
}
|
||||
|
||||
// filter controller options
|
||||
$localOptions = array_merge(
|
||||
array(
|
||||
'groupsOnly' => false,
|
||||
'groups' => array(),
|
||||
'symlinks' => array(),
|
||||
)
|
||||
,(isset($options['minApp']) ? $options['minApp'] : array())
|
||||
$defaults = array(
|
||||
'groupsOnly' => false,
|
||||
'groups' => array(),
|
||||
'symlinks' => array(),
|
||||
);
|
||||
$minApp = isset($options['minApp']) ? $options['minApp'] : array();
|
||||
$localOptions = array_merge($defaults, $minApp);
|
||||
|
||||
unset($options['minApp']);
|
||||
|
||||
// normalize $symlinks in order to map to target
|
||||
@@ -51,7 +53,7 @@ class Minify_Controller_MinApp extends Minify_Controller_Base {
|
||||
|
||||
$sources = array();
|
||||
$selectionId = '';
|
||||
$firstMissingResource = null;
|
||||
$firstMissing = null;
|
||||
|
||||
if (isset($get['g'])) {
|
||||
// add group(s)
|
||||
@@ -81,12 +83,12 @@ class Minify_Controller_MinApp extends Minify_Controller_Base {
|
||||
$sources[] = $source;
|
||||
} catch (Minify_Source_FactoryException $e) {
|
||||
$this->logger->error($e->getMessage());
|
||||
if (null === $firstMissingResource) {
|
||||
$firstMissingResource = basename($file);
|
||||
if (null === $firstMissing) {
|
||||
$firstMissing = basename($file);
|
||||
continue;
|
||||
} else {
|
||||
$secondMissingResource = basename($file);
|
||||
$this->logger->info("More than one file was missing: '$firstMissingResource', '$secondMissingResource'");
|
||||
$secondMissing = basename($file);
|
||||
$this->logger->info("More than one file was missing: '$firstMissing', '$secondMissing'");
|
||||
|
||||
return new Minify_ServeConfiguration($options);
|
||||
}
|
||||
@@ -98,18 +100,18 @@ class Minify_Controller_MinApp extends Minify_Controller_Base {
|
||||
// try user files
|
||||
// The following restrictions are to limit the URLs that minify will
|
||||
// respond to.
|
||||
if (// verify at least one file, files are single comma separated,
|
||||
// and are all same extension
|
||||
! preg_match('/^[^,]+\\.(css|less|js)(?:,[^,]+\\.\\1)*$/', $get['f'], $m)
|
||||
// no "//"
|
||||
|| strpos($get['f'], '//') !== false
|
||||
// no "\"
|
||||
|| strpos($get['f'], '\\') !== false
|
||||
) {
|
||||
|
||||
// verify at least one file, files are single comma separated, and are all same extension
|
||||
$validPattern = preg_match('/^[^,]+\\.(css|less|scss|js)(?:,[^,]+\\.\\1)*$/', $get['f'], $m);
|
||||
$hasComment = strpos($get['f'], '//') !== false;
|
||||
$hasEscape = strpos($get['f'], '\\') !== false;
|
||||
|
||||
if (!$validPattern || $hasComment || $hasEscape) {
|
||||
$this->logger->info("GET param 'f' was invalid");
|
||||
|
||||
return new Minify_ServeConfiguration($options);
|
||||
}
|
||||
|
||||
$ext = ".{$m[1]}";
|
||||
$files = explode(',', $get['f']);
|
||||
if ($files != array_unique($files)) {
|
||||
@@ -117,11 +119,14 @@ class Minify_Controller_MinApp extends Minify_Controller_Base {
|
||||
|
||||
return new Minify_ServeConfiguration($options);
|
||||
}
|
||||
|
||||
if (isset($get['b'])) {
|
||||
// check for validity
|
||||
if (preg_match('@^[^/]+(?:/[^/]+)*$@', $get['b'])
|
||||
&& false === strpos($get['b'], '..')
|
||||
&& $get['b'] !== '.') {
|
||||
$isValidBase = preg_match('@^[^/]+(?:/[^/]+)*$@', $get['b']);
|
||||
$hasDots = false !== strpos($get['b'], '..');
|
||||
$isDot = $get['b'] === '.';
|
||||
|
||||
if ($isValidBase && !$hasDots && !$isDot) {
|
||||
// valid base
|
||||
$base = "/{$get['b']}/";
|
||||
} else {
|
||||
@@ -152,12 +157,12 @@ class Minify_Controller_MinApp extends Minify_Controller_Base {
|
||||
$basenames[] = basename($path, $ext);
|
||||
} catch (Minify_Source_FactoryException $e) {
|
||||
$this->logger->error($e->getMessage());
|
||||
if (null === $firstMissingResource) {
|
||||
$firstMissingResource = $uri;
|
||||
if (null === $firstMissing) {
|
||||
$firstMissing = $uri;
|
||||
continue;
|
||||
} else {
|
||||
$secondMissingResource = $uri;
|
||||
$this->logger->info("More than one file was missing: '$firstMissingResource', '$secondMissingResource`'");
|
||||
$secondMissing = $uri;
|
||||
$this->logger->info("More than one file was missing: '$firstMissing', '$secondMissing`'");
|
||||
|
||||
return new Minify_ServeConfiguration($options);
|
||||
}
|
||||
@@ -175,14 +180,14 @@ class Minify_Controller_MinApp extends Minify_Controller_Base {
|
||||
return new Minify_ServeConfiguration($options);
|
||||
}
|
||||
|
||||
if (null !== $firstMissingResource) {
|
||||
if (null !== $firstMissing) {
|
||||
array_unshift($sources, new Minify_Source(array(
|
||||
'id' => 'missingFile'
|
||||
'id' => 'missingFile',
|
||||
// should not cause cache invalidation
|
||||
,'lastModified' => 0
|
||||
'lastModified' => 0,
|
||||
// due to caching, filename is unreliable.
|
||||
,'content' => "/* Minify: at least one missing file. See " . Minify::URL_DEBUG . " */\n"
|
||||
,'minifier' => 'Minify::nullMinifier'
|
||||
'content' => "/* Minify: at least one missing file. See " . Minify::URL_DEBUG . " */\n",
|
||||
'minifier' => 'Minify::nullMinifier',
|
||||
)));
|
||||
}
|
||||
|
||||
|
@@ -11,7 +11,8 @@
|
||||
* @package Minify
|
||||
* @author Stephen Clay <steve@mrclay.org>
|
||||
*/
|
||||
class Minify_Controller_Page extends Minify_Controller_Base {
|
||||
class Minify_Controller_Page extends Minify_Controller_Base
|
||||
{
|
||||
|
||||
/**
|
||||
* Set up source of HTML content
|
||||
@@ -31,7 +32,8 @@ class Minify_Controller_Page extends Minify_Controller_Base {
|
||||
* 'minifyAll': should all CSS and Javascript blocks be individually
|
||||
* minified? (default false)
|
||||
*/
|
||||
public function createConfiguration(array $options) {
|
||||
public function createConfiguration(array $options)
|
||||
{
|
||||
if (isset($options['file'])) {
|
||||
$sourceSpec = array(
|
||||
'filepath' => $options['file']
|
||||
@@ -40,8 +42,8 @@ class Minify_Controller_Page extends Minify_Controller_Base {
|
||||
} else {
|
||||
// strip controller options
|
||||
$sourceSpec = array(
|
||||
'content' => $options['content']
|
||||
,'id' => $options['id']
|
||||
'content' => $options['content'],
|
||||
'id' => $options['id'],
|
||||
);
|
||||
$f = $options['id'];
|
||||
unset($options['content'], $options['id']);
|
||||
@@ -52,8 +54,8 @@ class Minify_Controller_Page extends Minify_Controller_Base {
|
||||
if (isset($options['minifyAll'])) {
|
||||
// this will be the 2nd argument passed to Minify_HTML::minify()
|
||||
$sourceSpec['minifyOptions'] = array(
|
||||
'cssMinifier' => array('Minify_CSSmin', 'minify')
|
||||
,'jsMinifier' => array('JSMin\\JSMin', 'minify')
|
||||
'cssMinifier' => array('Minify_CSSmin', 'minify'),
|
||||
'jsMinifier' => array('JSMin\\JSMin', 'minify'),
|
||||
);
|
||||
unset($options['minifyAll']);
|
||||
}
|
||||
|
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
interface Minify_ControllerInterface {
|
||||
interface Minify_ControllerInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* Create controller sources and options for Minify::serve()
|
||||
|
@@ -6,12 +6,14 @@
|
||||
* @package Minify
|
||||
* @author Stephen Clay <steve@mrclay.org>
|
||||
*/
|
||||
class Minify_DebugDetector {
|
||||
class Minify_DebugDetector
|
||||
{
|
||||
public static function shouldDebugRequest(Minify_Env $env)
|
||||
{
|
||||
if ($env->get('debug') !== null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$cookieValue = $env->cookie('minifyDebug');
|
||||
if ($cookieValue) {
|
||||
foreach (preg_split('/\\s+/', $cookieValue) as $debugUri) {
|
||||
|
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
|
||||
class Minify_Env {
|
||||
class Minify_Env
|
||||
{
|
||||
|
||||
/**
|
||||
* @return string
|
||||
@@ -33,6 +34,7 @@ class Minify_Env {
|
||||
} else {
|
||||
$this->server['DOCUMENT_ROOT'] = rtrim($this->server['DOCUMENT_ROOT'], '/\\');
|
||||
}
|
||||
|
||||
$this->server['DOCUMENT_ROOT'] = $this->normalizePath($this->server['DOCUMENT_ROOT']);
|
||||
$this->get = $options['get'];
|
||||
$this->post = $options['post'];
|
||||
@@ -45,9 +47,7 @@ class Minify_Env {
|
||||
return $this->server;
|
||||
}
|
||||
|
||||
return isset($this->server[$key])
|
||||
? $this->server[$key]
|
||||
: null;
|
||||
return isset($this->server[$key]) ? $this->server[$key] : null;
|
||||
}
|
||||
|
||||
public function cookie($key = null, $default = null)
|
||||
@@ -92,11 +92,13 @@ class Minify_Env {
|
||||
if ($realpath) {
|
||||
$path = $realpath;
|
||||
}
|
||||
|
||||
$path = str_replace('\\', '/', $path);
|
||||
$path = rtrim($path, '/');
|
||||
if (substr($path, 1, 1) === ':') {
|
||||
$path = lcfirst($path);
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
@@ -116,11 +118,9 @@ class Minify_Env {
|
||||
if (isset($server['SERVER_SOFTWARE']) && 0 !== strpos($server['SERVER_SOFTWARE'], 'Microsoft-IIS/')) {
|
||||
throw new InvalidArgumentException('DOCUMENT_ROOT is not provided and could not be computed');
|
||||
}
|
||||
$docRoot = substr(
|
||||
$server['SCRIPT_FILENAME']
|
||||
,0
|
||||
,strlen($server['SCRIPT_FILENAME']) - strlen($server['SCRIPT_NAME'])
|
||||
);
|
||||
|
||||
$substrLength = strlen($server['SCRIPT_FILENAME']) - strlen($server['SCRIPT_NAME']);
|
||||
$docRoot = substr($server['SCRIPT_FILENAME'], 0, $substrLength);
|
||||
|
||||
return rtrim($docRoot, '\\');
|
||||
}
|
||||
|
@@ -16,7 +16,8 @@
|
||||
* @package Minify
|
||||
* @author Stephen Clay <steve@mrclay.org>
|
||||
*/
|
||||
class Minify_HTML {
|
||||
class Minify_HTML
|
||||
{
|
||||
/**
|
||||
* @var boolean
|
||||
*/
|
||||
@@ -40,7 +41,8 @@ class Minify_HTML {
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function minify($html, $options = array()) {
|
||||
public static function minify($html, $options = array())
|
||||
{
|
||||
$min = new self($html, $options);
|
||||
|
||||
return $min->process();
|
||||
|
@@ -10,7 +10,8 @@
|
||||
* @package Minify
|
||||
* @author Stephen Clay <steve@mrclay.org>
|
||||
*/
|
||||
class Minify_HTML_Helper {
|
||||
class Minify_HTML_Helper
|
||||
{
|
||||
public $rewriteWorks = true;
|
||||
public $minAppUri = '/min';
|
||||
public $groupsConfigFile = '';
|
||||
@@ -98,8 +99,7 @@ class Minify_HTML_Helper {
|
||||
foreach ($files as $k => $file) {
|
||||
if (0 === strpos($file, '//')) {
|
||||
$file = substr($file, 2);
|
||||
} elseif (0 === strpos($file, '/')
|
||||
|| 1 === strpos($file, ':\\')) {
|
||||
} elseif (0 === strpos($file, '/') || 1 === strpos($file, ':\\')) {
|
||||
$file = substr($file, strlen(self::app()->env->getDocRoot()) + 1);
|
||||
}
|
||||
$file = strtr($file, '\\', '/');
|
||||
@@ -168,11 +168,13 @@ class Minify_HTML_Helper {
|
||||
static $cached;
|
||||
if ($app) {
|
||||
$cached = $app;
|
||||
|
||||
return $app;
|
||||
}
|
||||
if ($cached === null) {
|
||||
$cached = (require __DIR__ . '/../../../bootstrap.php');
|
||||
}
|
||||
|
||||
return $cached;
|
||||
}
|
||||
|
||||
@@ -188,7 +190,8 @@ class Minify_HTML_Helper {
|
||||
* @param int $pos index to check
|
||||
* @return mixed a common char or '' if any do not match
|
||||
*/
|
||||
protected static function _getCommonCharAtPos($arr, $pos) {
|
||||
protected static function _getCommonCharAtPos($arr, $pos)
|
||||
{
|
||||
if (!isset($arr[0][$pos])) {
|
||||
return '';
|
||||
}
|
||||
@@ -213,7 +216,8 @@ class Minify_HTML_Helper {
|
||||
* @param string $minRoot root-relative URI of the "min" application
|
||||
* @return string
|
||||
*/
|
||||
protected static function _getShortestUri($paths, $minRoot = '/min/') {
|
||||
protected static function _getShortestUri($paths, $minRoot = '/min/')
|
||||
{
|
||||
$pos = 0;
|
||||
$base = '';
|
||||
while (true) {
|
||||
@@ -238,9 +242,7 @@ class Minify_HTML_Helper {
|
||||
$base = substr($base, 0, strlen($base) - 1);
|
||||
$bUri = $minRoot . 'b=' . $base . '&f=' . implode(',', $basedPaths);
|
||||
|
||||
$uri = strlen($uri) < strlen($bUri)
|
||||
? $uri
|
||||
: $bUri;
|
||||
$uri = strlen($uri) < strlen($bUri) ? $uri : $bUri;
|
||||
}
|
||||
|
||||
return $uri;
|
||||
|
@@ -18,8 +18,8 @@
|
||||
* @author Stephen Clay <steve@mrclay.org>
|
||||
* @author Simon Schick <simonsimcity@gmail.com>
|
||||
*/
|
||||
class Minify_ImportProcessor {
|
||||
|
||||
class Minify_ImportProcessor
|
||||
{
|
||||
public static $filesIncluded = array();
|
||||
|
||||
public static function process($file)
|
||||
@@ -57,8 +57,7 @@ class Minify_ImportProcessor {
|
||||
$file = realpath($file);
|
||||
if (! $file
|
||||
|| in_array($file, self::$filesIncluded)
|
||||
|| false === ($content = @file_get_contents($file))
|
||||
) {
|
||||
|| false === ($content = @file_get_contents($file))) {
|
||||
// file missing, already included, or failed read
|
||||
return '';
|
||||
}
|
||||
@@ -73,8 +72,7 @@ class Minify_ImportProcessor {
|
||||
$content = str_replace("\r\n", "\n", $content);
|
||||
|
||||
// process @imports
|
||||
$content = preg_replace_callback(
|
||||
'/
|
||||
$pattern = '/
|
||||
@import\\s+
|
||||
(?:url\\(\\s*)? # maybe url(
|
||||
[\'"]? # maybe quote
|
||||
@@ -83,19 +81,14 @@ class Minify_ImportProcessor {
|
||||
(?:\\s*\\))? # maybe )
|
||||
([a-zA-Z,\\s]*)? # 2 = media list
|
||||
; # end token
|
||||
/x'
|
||||
,array($this, '_importCB')
|
||||
,$content
|
||||
);
|
||||
/x';
|
||||
$content = preg_replace_callback($pattern, array($this, '_importCB'), $content);
|
||||
|
||||
// You only need to rework the import-path if the script is imported
|
||||
if (self::$_isCss && $is_imported) {
|
||||
// rewrite remaining relative URIs
|
||||
$content = preg_replace_callback(
|
||||
'/url\\(\\s*([^\\)\\s]+)\\s*\\)/'
|
||||
,array($this, '_urlCB')
|
||||
,$content
|
||||
);
|
||||
$pattern = '/url\\(\\s*([^\\)\\s]+)\\s*\\)/';
|
||||
$content = preg_replace_callback($pattern, array($this, '_urlCB'), $content);
|
||||
}
|
||||
|
||||
return $this->_importedContent . $content;
|
||||
@@ -139,12 +132,10 @@ class Minify_ImportProcessor {
|
||||
private function _urlCB($m)
|
||||
{
|
||||
// $m[1] is either quoted or not
|
||||
$quote = ($m[1][0] === "'" || $m[1][0] === '"')
|
||||
? $m[1][0]
|
||||
: '';
|
||||
$url = ($quote === '')
|
||||
? $m[1]
|
||||
: substr($m[1], 1, strlen($m[1]) - 2);
|
||||
$quote = ($m[1][0] === "'" || $m[1][0] === '"') ? $m[1][0] : '';
|
||||
|
||||
$url = ($quote === '') ? $m[1] : substr($m[1], 1, strlen($m[1]) - 2);
|
||||
|
||||
if ('/' !== $url[0]) {
|
||||
if (strpos($url, '//') > 0) {
|
||||
// probably starts with protocol, do not alter
|
||||
@@ -173,8 +164,7 @@ class Minify_ImportProcessor {
|
||||
|
||||
$arFrom = explode($ps, rtrim($realFrom, $ps));
|
||||
$arTo = explode($ps, rtrim($realTo, $ps));
|
||||
while (count($arFrom) && count($arTo) && ($arFrom[0] == $arTo[0]))
|
||||
{
|
||||
while (count($arFrom) && count($arTo) && ($arFrom[0] == $arTo[0])) {
|
||||
array_shift($arFrom);
|
||||
array_shift($arTo);
|
||||
}
|
||||
@@ -191,28 +181,33 @@ class Minify_ImportProcessor {
|
||||
private function truepath($path)
|
||||
{
|
||||
// whether $path is unix or not
|
||||
$unipath = strlen($path) == 0 || $path{0} != '/';
|
||||
$unipath = (strlen($path) == 0) || ($path{0} != '/');
|
||||
|
||||
// attempts to detect if path is relative in which case, add cwd
|
||||
if (strpos($path, ':') === false && $unipath)
|
||||
if (strpos($path, ':') === false && $unipath) {
|
||||
$path = $this->_currentDir . DIRECTORY_SEPARATOR . $path;
|
||||
}
|
||||
|
||||
// resolve path parts (single dot, double dot and double delimiters)
|
||||
$path = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $path);
|
||||
$parts = array_filter(explode(DIRECTORY_SEPARATOR, $path), 'strlen');
|
||||
$absolutes = array();
|
||||
foreach ($parts as $part) {
|
||||
if ('.' == $part)
|
||||
if ('.' == $part) {
|
||||
continue;
|
||||
}
|
||||
if ('..' == $part) {
|
||||
array_pop($absolutes);
|
||||
} else {
|
||||
$absolutes[] = $part;
|
||||
}
|
||||
}
|
||||
|
||||
$path = implode(DIRECTORY_SEPARATOR, $absolutes);
|
||||
// resolve any symlinks
|
||||
if (file_exists($path) && linkinfo($path) > 0)
|
||||
if (file_exists($path) && linkinfo($path) > 0) {
|
||||
$path = readlink($path);
|
||||
}
|
||||
// put initial separator that could have been lost
|
||||
$path = !$unipath ? '/' . $path : $path;
|
||||
|
||||
|
@@ -13,7 +13,8 @@
|
||||
*
|
||||
* @todo can use a stream wrapper to unit test this?
|
||||
*/
|
||||
class Minify_JS_ClosureCompiler {
|
||||
class Minify_JS_ClosureCompiler
|
||||
{
|
||||
|
||||
/**
|
||||
* @var string The option key for the maximum POST byte size
|
||||
@@ -228,4 +229,6 @@ class Minify_JS_ClosureCompiler {
|
||||
}
|
||||
}
|
||||
|
||||
class Minify_JS_ClosureCompiler_Exception extends Exception {}
|
||||
class Minify_JS_ClosureCompiler_Exception extends Exception
|
||||
{
|
||||
}
|
||||
|
48
lib/Minify/JS/JShrink.php
Normal file
48
lib/Minify/JS/JShrink.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
/**
|
||||
* Class Minify\JS\JShrink
|
||||
*
|
||||
* @package Minify
|
||||
*/
|
||||
|
||||
namespace Minify\JS;
|
||||
|
||||
/**
|
||||
* Wrapper to Javascript Minifier built in PHP http://www.tedivm.com
|
||||
*
|
||||
* @package Minify
|
||||
* @author Elan Ruusamäe <glen@pld-linux.org>
|
||||
* @link https://github.com/tedious/JShrink
|
||||
*
|
||||
*/
|
||||
class JShrink
|
||||
{
|
||||
/**
|
||||
* Contains the default options for minification. This array is merged with
|
||||
* the one passed in by the user to create the request specific set of
|
||||
* options (stored in the $options attribute).
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected static $defaultOptions = array('flaggedComments' => true);
|
||||
|
||||
/**
|
||||
* Takes a string containing javascript and removes unneeded characters in
|
||||
* order to shrink the code without altering it's functionality.
|
||||
*
|
||||
* @param string $js The raw javascript to be minified
|
||||
* @param array $options Various runtime options in an associative array
|
||||
*
|
||||
* @see JShrink\Minifier::minify()
|
||||
* @return string
|
||||
*/
|
||||
public static function minify($js, array $options = array())
|
||||
{
|
||||
$options = array_merge(
|
||||
self::$defaultOptions,
|
||||
$options
|
||||
);
|
||||
|
||||
return \JShrink\Minifier::minify($js, $options);
|
||||
}
|
||||
}
|
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
|
||||
class Minify_LessCssSource extends Minify_Source {
|
||||
class Minify_LessCssSource extends Minify_Source
|
||||
{
|
||||
/**
|
||||
* @var Minify_CacheInterface
|
||||
*/
|
||||
@@ -16,7 +17,8 @@ class Minify_LessCssSource extends Minify_Source {
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function __construct(array $spec, Minify_CacheInterface $cache) {
|
||||
public function __construct(array $spec, Minify_CacheInterface $cache)
|
||||
{
|
||||
parent::__construct($spec);
|
||||
|
||||
$this->cache = $cache;
|
||||
@@ -27,16 +29,11 @@ class Minify_LessCssSource extends Minify_Source {
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getLastModified() {
|
||||
public function getLastModified()
|
||||
{
|
||||
$cache = $this->getCache();
|
||||
|
||||
$lastModified = 0;
|
||||
foreach ($cache['files'] as $mtime) {
|
||||
$lastModified = max($lastModified, $mtime);
|
||||
|
||||
}
|
||||
|
||||
return $lastModified;
|
||||
return $cache['lastModified'];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -44,7 +41,8 @@ class Minify_LessCssSource extends Minify_Source {
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getContent() {
|
||||
public function getContent()
|
||||
{
|
||||
$cache = $this->getCache();
|
||||
|
||||
return $cache['compiled'];
|
||||
@@ -55,7 +53,8 @@ class Minify_LessCssSource extends Minify_Source {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getCache() {
|
||||
private function getCache()
|
||||
{
|
||||
// cache for single run
|
||||
// so that getLastModified and getContent in single request do not add additional cache roundtrips (i.e memcache)
|
||||
if (isset($this->parsed)) {
|
||||
@@ -76,12 +75,29 @@ class Minify_LessCssSource extends Minify_Source {
|
||||
$cache = $less->cachedCompile($input);
|
||||
|
||||
if (!is_array($input) || $cache['updated'] > $input['updated']) {
|
||||
$cache['lastModified'] = $this->getMaxLastModified($cache);
|
||||
$this->cache->store($cacheId, serialize($cache));
|
||||
}
|
||||
|
||||
return $this->parsed = $cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate maximum last modified of all files,
|
||||
* as the 'updated' timestamp in cache is not the same as file last modified timestamp:
|
||||
* @link https://github.com/leafo/lessphp/blob/v0.4.0/lessc.inc.php#L1904
|
||||
* @return int
|
||||
*/
|
||||
private function getMaxLastModified($cache)
|
||||
{
|
||||
$lastModified = 0;
|
||||
foreach ($cache['files'] as $mtime) {
|
||||
$lastModified = max($lastModified, $mtime);
|
||||
}
|
||||
|
||||
return $lastModified;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a unique cache id for for this source.
|
||||
*
|
||||
@@ -89,10 +105,11 @@ class Minify_LessCssSource extends Minify_Source {
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getCacheId($prefix = 'minify') {
|
||||
private function getCacheId($prefix = 'minify')
|
||||
{
|
||||
$md5 = md5($this->filepath);
|
||||
|
||||
return "{$prefix}_less_{$md5}";
|
||||
return "{$prefix}_less2_{$md5}";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -100,7 +117,8 @@ class Minify_LessCssSource extends Minify_Source {
|
||||
*
|
||||
* @return lessc
|
||||
*/
|
||||
private function getCompiler() {
|
||||
private function getCompiler()
|
||||
{
|
||||
$less = new lessc();
|
||||
// do not spend CPU time letting less doing minify
|
||||
$less->setPreserveComments(true);
|
||||
|
@@ -11,7 +11,8 @@
|
||||
* @author Stephen Clay <steve@mrclay.org>
|
||||
* @author Adam Pedersen (Issue 55 fix)
|
||||
*/
|
||||
class Minify_Lines {
|
||||
class Minify_Lines
|
||||
{
|
||||
|
||||
/**
|
||||
* Add line numbers in C-style comments
|
||||
@@ -36,16 +37,9 @@ class Minify_Lines {
|
||||
*/
|
||||
public static function minify($content, $options = array())
|
||||
{
|
||||
$id = (isset($options['id']) && $options['id'])
|
||||
? $options['id']
|
||||
: '';
|
||||
$id = (isset($options['id']) && $options['id']) ? $options['id'] : '';
|
||||
$content = str_replace("\r\n", "\n", $content);
|
||||
|
||||
// Hackily rewrite strings with XPath expressions that are
|
||||
// likely to throw off our dumb parser (for Prototype 1.6.1).
|
||||
$content = str_replace('"/*"', '"/"+"*"', $content);
|
||||
$content = preg_replace('@([\'"])(\\.?//?)\\*@', '$1$2$1+$1*', $content);
|
||||
|
||||
$lines = explode("\n", $content);
|
||||
$numLines = count($lines);
|
||||
// determine left padding
|
||||
@@ -53,6 +47,7 @@ class Minify_Lines {
|
||||
$inComment = false;
|
||||
$i = 0;
|
||||
$newLines = array();
|
||||
|
||||
while (null !== ($line = array_shift($lines))) {
|
||||
if (('' !== $id) && (0 == $i % 50)) {
|
||||
if ($inComment) {
|
||||
@@ -61,24 +56,25 @@ class Minify_Lines {
|
||||
array_push($newLines, '', "/* {$id} */", '');
|
||||
}
|
||||
}
|
||||
|
||||
++$i;
|
||||
$newLines[] = self::_addNote($line, $i, $inComment, $padTo);
|
||||
$inComment = self::_eolInComment($line, $inComment);
|
||||
}
|
||||
|
||||
$content = implode("\n", $newLines) . "\n";
|
||||
|
||||
// check for desired URI rewriting
|
||||
if (isset($options['currentDir'])) {
|
||||
Minify_CSS_UriRewriter::$debugText = '';
|
||||
$content = Minify_CSS_UriRewriter::rewrite(
|
||||
$content
|
||||
,$options['currentDir']
|
||||
,isset($options['docRoot']) ? $options['docRoot'] : $_SERVER['DOCUMENT_ROOT']
|
||||
,isset($options['symlinks']) ? $options['symlinks'] : array()
|
||||
);
|
||||
$docRoot = isset($options['docRoot']) ? $options['docRoot'] : $_SERVER['DOCUMENT_ROOT'];
|
||||
$symlinks = isset($options['symlinks']) ? $options['symlinks'] : array();
|
||||
|
||||
$content = Minify_CSS_UriRewriter::rewrite($content, $options['currentDir'], $docRoot, $symlinks);
|
||||
|
||||
$content = "/* Minify_CSS_UriRewriter::\$debugText\n\n"
|
||||
. Minify_CSS_UriRewriter::$debugText . "*/\n"
|
||||
. $content;
|
||||
. Minify_CSS_UriRewriter::$debugText . "*/\n"
|
||||
. $content;
|
||||
}
|
||||
|
||||
return $content;
|
||||
@@ -89,33 +85,43 @@ class Minify_Lines {
|
||||
*
|
||||
* @param string $line current line of code
|
||||
*
|
||||
* @param bool $inComment was the parser in a comment at the
|
||||
* beginning of the line?
|
||||
* @param bool $inComment was the parser in a C-style comment at the
|
||||
* beginning of the previous line?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private static function _eolInComment($line, $inComment)
|
||||
{
|
||||
// crude way to avoid things like // */
|
||||
$line = preg_replace('~//.*?(\\*/|/\\*).*~', '', $line);
|
||||
|
||||
while (strlen($line)) {
|
||||
$search = $inComment
|
||||
? '*/'
|
||||
: '/*';
|
||||
$pos = strpos($line, $search);
|
||||
if (false === $pos) {
|
||||
return $inComment;
|
||||
} else {
|
||||
if ($pos == 0
|
||||
|| ($inComment
|
||||
? substr($line, $pos, 3)
|
||||
: substr($line, $pos-1, 3)) != '*/*')
|
||||
{
|
||||
$inComment = ! $inComment;
|
||||
if ($inComment) {
|
||||
// only "*/" can end the comment
|
||||
$index = self::_find($line, '*/');
|
||||
if ($index === false) {
|
||||
return true;
|
||||
}
|
||||
$line = substr($line, $pos + 2);
|
||||
|
||||
// stop comment and keep walking line
|
||||
$inComment = false;
|
||||
@$line = (string)substr($line, $index + 2);
|
||||
continue;
|
||||
}
|
||||
|
||||
// look for "//" and "/*"
|
||||
$single = self::_find($line, '//');
|
||||
$multi = self::_find($line, '/*');
|
||||
if ($multi === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($single === false || $multi < $single) {
|
||||
// start comment and keep walking line
|
||||
$inComment = true;
|
||||
@$line = (string)substr($line, $multi + 2);
|
||||
continue;
|
||||
}
|
||||
|
||||
// a single-line comment preceeded it
|
||||
return false;
|
||||
}
|
||||
|
||||
return $inComment;
|
||||
@@ -137,8 +143,67 @@ class Minify_Lines {
|
||||
*/
|
||||
private static function _addNote($line, $note, $inComment, $padTo)
|
||||
{
|
||||
return $inComment
|
||||
? '/* ' . str_pad($note, $padTo, ' ', STR_PAD_RIGHT) . ' *| ' . $line
|
||||
: '/* ' . str_pad($note, $padTo, ' ', STR_PAD_RIGHT) . ' */ ' . $line;
|
||||
if ($inComment) {
|
||||
$line = '/* ' . str_pad($note, $padTo, ' ', STR_PAD_RIGHT) . ' *| ' . $line;
|
||||
} else {
|
||||
$line = '/* ' . str_pad($note, $padTo, ' ', STR_PAD_RIGHT) . ' */ ' . $line;
|
||||
}
|
||||
|
||||
return rtrim($line);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a token trying to avoid false positives
|
||||
*
|
||||
* @param string $str String containing the token
|
||||
* @param string $token Token being checked
|
||||
* @return bool
|
||||
*/
|
||||
private static function _find($str, $token)
|
||||
{
|
||||
switch ($token) {
|
||||
case '//':
|
||||
$fakes = array(
|
||||
'://' => 1,
|
||||
'"//' => 1,
|
||||
'\'//' => 1,
|
||||
'".//' => 2,
|
||||
'\'.//' => 2,
|
||||
);
|
||||
break;
|
||||
case '/*':
|
||||
$fakes = array(
|
||||
'"/*' => 1,
|
||||
'\'/*' => 1,
|
||||
'"//*' => 2,
|
||||
'\'//*' => 2,
|
||||
'".//*' => 3,
|
||||
'\'.//*' => 3,
|
||||
'*/*' => 1,
|
||||
'\\/*' => 1,
|
||||
);
|
||||
break;
|
||||
default:
|
||||
$fakes = array();
|
||||
}
|
||||
|
||||
$index = strpos($str, $token);
|
||||
$offset = 0;
|
||||
|
||||
while ($index !== false) {
|
||||
foreach ($fakes as $fake => $skip) {
|
||||
$check = substr($str, $index - $skip, strlen($fake));
|
||||
if ($check === $fake) {
|
||||
// move offset and scan again
|
||||
$offset += $index + strlen($token);
|
||||
$index = strpos($str, $token, $offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// legitimate find
|
||||
return $index;
|
||||
}
|
||||
|
||||
return $index;
|
||||
}
|
||||
}
|
||||
|
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace Minify\Logger;
|
||||
|
||||
use Monolog\Logger;
|
||||
use Monolog\Handler\AbstractProcessingHandler;
|
||||
|
||||
class LegacyHandler extends AbstractProcessingHandler
|
||||
|
@@ -19,7 +19,8 @@
|
||||
*
|
||||
* @package Minify
|
||||
*/
|
||||
class Minify_Packer {
|
||||
class Minify_Packer
|
||||
{
|
||||
public static function minify($code, $options = array())
|
||||
{
|
||||
// @todo: set encoding options based on $options :)
|
||||
|
176
lib/Minify/ScssCssSource.php
Normal file
176
lib/Minify/ScssCssSource.php
Normal file
@@ -0,0 +1,176 @@
|
||||
<?php
|
||||
use Leafo\ScssPhp\Compiler;
|
||||
use Leafo\ScssPhp\Server;
|
||||
use Leafo\ScssPhp\Version;
|
||||
|
||||
/**
|
||||
* Class for using SCSS files
|
||||
*
|
||||
* @link https://github.com/leafo/scssphp/
|
||||
*/
|
||||
class Minify_ScssCssSource extends Minify_Source
|
||||
{
|
||||
/**
|
||||
* @var Minify_CacheInterface
|
||||
*/
|
||||
private $cache;
|
||||
|
||||
/**
|
||||
* Parsed SCSS cache object
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $parsed;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function __construct(array $spec, Minify_CacheInterface $cache)
|
||||
{
|
||||
parent::__construct($spec);
|
||||
|
||||
$this->cache = $cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get last modified of all parsed files
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getLastModified()
|
||||
{
|
||||
$cache = $this->getCache();
|
||||
|
||||
return $cache['updated'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get content
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getContent()
|
||||
{
|
||||
$cache = $this->getCache();
|
||||
|
||||
return $cache['content'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a unique cache id for for this source.
|
||||
*
|
||||
* @param string $prefix
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getCacheId($prefix = 'minify')
|
||||
{
|
||||
$md5 = md5($this->filepath);
|
||||
|
||||
return "{$prefix}_scss_{$md5}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get SCSS cache object
|
||||
*
|
||||
* Runs the compilation if needed
|
||||
*
|
||||
* Implements Leafo\ScssPhp\Server logic because we need to get parsed files without parsing actual content
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getCache()
|
||||
{
|
||||
// cache for single run
|
||||
// so that getLastModified and getContent in single request do not add additional cache roundtrips (i.e memcache)
|
||||
if (isset($this->parsed)) {
|
||||
return $this->parsed;
|
||||
}
|
||||
|
||||
// check from cache first
|
||||
$cache = null;
|
||||
$cacheId = $this->getCacheId();
|
||||
if ($this->cache->isValid($cacheId, 0)) {
|
||||
if ($cache = $this->cache->fetch($cacheId)) {
|
||||
$cache = unserialize($cache);
|
||||
}
|
||||
}
|
||||
|
||||
$input = $cache ? $cache : $this->filepath;
|
||||
|
||||
if ($this->cacheIsStale($cache)) {
|
||||
$cache = $this->compile($this->filepath);
|
||||
}
|
||||
|
||||
if (!is_array($input) || $cache['updated'] > $input['updated']) {
|
||||
$this->cache->store($cacheId, serialize($cache));
|
||||
}
|
||||
|
||||
return $this->parsed = $cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether .scss file needs to be re-compiled.
|
||||
*
|
||||
* @param array $cache Cache object
|
||||
*
|
||||
* @return boolean True if compile required.
|
||||
*/
|
||||
private function cacheIsStale($cache)
|
||||
{
|
||||
if (!$cache) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$updated = $cache['updated'];
|
||||
foreach ($cache['files'] as $import => $mtime) {
|
||||
$filemtime = filemtime($import);
|
||||
|
||||
if ($filemtime !== $mtime || $filemtime > $updated) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile .scss file
|
||||
*
|
||||
* @param string $filename Input path (.scss)
|
||||
*
|
||||
* @see Server::compile()
|
||||
* @return array meta data result of the compile
|
||||
*/
|
||||
private function compile($filename)
|
||||
{
|
||||
$start = microtime(true);
|
||||
$scss = new Compiler();
|
||||
|
||||
// set import path directory the input filename resides
|
||||
// otherwise @import statements will not find the files
|
||||
// and will treat the @import line as css import
|
||||
$scss->setImportPaths(dirname($filename));
|
||||
|
||||
$css = $scss->compile(file_get_contents($filename), $filename);
|
||||
$elapsed = round((microtime(true) - $start), 4);
|
||||
|
||||
$v = Version::VERSION;
|
||||
$ts = date('r', $start);
|
||||
$css = "/* compiled by scssphp $v on $ts (${elapsed}s) */\n\n" . $css;
|
||||
|
||||
$imports = $scss->getParsedFiles();
|
||||
|
||||
$updated = 0;
|
||||
foreach ($imports as $mtime) {
|
||||
$updated = max($updated, $mtime);
|
||||
}
|
||||
|
||||
return array(
|
||||
'elapsed' => $elapsed, // statistic, can be dropped
|
||||
'updated' => $updated,
|
||||
'content' => $css,
|
||||
'files' => $imports,
|
||||
);
|
||||
}
|
||||
}
|
@@ -9,7 +9,8 @@
|
||||
*
|
||||
* @package Minify
|
||||
*/
|
||||
class Minify_ServeConfiguration {
|
||||
class Minify_ServeConfiguration
|
||||
{
|
||||
|
||||
/**
|
||||
* @var Minify_SourceInterface[]
|
||||
|
@@ -13,7 +13,8 @@
|
||||
* @package Minify
|
||||
* @author Stephen Clay <steve@mrclay.org>
|
||||
*/
|
||||
class Minify_Source implements Minify_SourceInterface {
|
||||
class Minify_Source implements Minify_SourceInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @var int time of last modification
|
||||
@@ -70,14 +71,15 @@ class Minify_Source implements Minify_SourceInterface {
|
||||
if (isset($spec['filepath'])) {
|
||||
$ext = pathinfo($spec['filepath'], PATHINFO_EXTENSION);
|
||||
switch ($ext) {
|
||||
case 'js' : $this->contentType = Minify::TYPE_JS;
|
||||
break;
|
||||
case 'less' : // fallthrough
|
||||
case 'css' : $this->contentType = Minify::TYPE_CSS;
|
||||
break;
|
||||
case 'htm' : // fallthrough
|
||||
case 'html' : $this->contentType = Minify::TYPE_HTML;
|
||||
break;
|
||||
case 'js': $this->contentType = Minify::TYPE_JS;
|
||||
break;
|
||||
case 'less': // fallthrough
|
||||
case 'scss': // fallthrough
|
||||
case 'css': $this->contentType = Minify::TYPE_CSS;
|
||||
break;
|
||||
case 'htm': // fallthrough
|
||||
case 'html': $this->contentType = Minify::TYPE_HTML;
|
||||
break;
|
||||
}
|
||||
$this->filepath = $spec['filepath'];
|
||||
$this->id = $spec['filepath'];
|
||||
@@ -96,9 +98,7 @@ class Minify_Source implements Minify_SourceInterface {
|
||||
} else {
|
||||
$this->getContentFunc = $spec['getContentFunc'];
|
||||
}
|
||||
$this->lastModified = isset($spec['lastModified'])
|
||||
? $spec['lastModified']
|
||||
: time();
|
||||
$this->lastModified = isset($spec['lastModified']) ? $spec['lastModified'] : time();
|
||||
}
|
||||
if (isset($spec['contentType'])) {
|
||||
$this->contentType = $spec['contentType'];
|
||||
@@ -203,11 +203,12 @@ class Minify_Source implements Minify_SourceInterface {
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setupUriRewrites() {
|
||||
public function setupUriRewrites()
|
||||
{
|
||||
if ($this->filepath
|
||||
&& !isset($this->minifyOptions['currentDir'])
|
||||
&& !isset($this->minifyOptions['prependRelativePath'])
|
||||
) {
|
||||
&& !isset($this->minifyOptions['prependRelativePath'])) {
|
||||
|
||||
$this->minifyOptions['currentDir'] = dirname($this->filepath);
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
|
||||
class Minify_Source_Factory {
|
||||
class Minify_Source_Factory
|
||||
{
|
||||
|
||||
/**
|
||||
* @var array
|
||||
@@ -67,9 +68,13 @@ class Minify_Source_Factory {
|
||||
throw new InvalidArgumentException("fileChecker option is not callable");
|
||||
}
|
||||
|
||||
$this->setHandler('~\.less$~i', function ($spec) use ($cache) {
|
||||
return new Minify_LessCssSource($spec, $cache);
|
||||
});
|
||||
$this->setHandler('~\.less$~i', function ($spec) use ($cache) {
|
||||
return new Minify_LessCssSource($spec, $cache);
|
||||
});
|
||||
|
||||
$this->setHandler('~\.scss~i', function ($spec) use ($cache) {
|
||||
return new Minify_ScssCssSource($spec, $cache);
|
||||
});
|
||||
|
||||
$this->setHandler('~\.(js|css)$~i', function ($spec) {
|
||||
return new Minify_Source($spec);
|
||||
|
@@ -1,3 +1,5 @@
|
||||
<?php
|
||||
|
||||
class Minify_Source_FactoryException extends Exception {}
|
||||
class Minify_Source_FactoryException extends Exception
|
||||
{
|
||||
}
|
||||
|
@@ -12,7 +12,8 @@
|
||||
*
|
||||
* @package Minify
|
||||
*/
|
||||
interface Minify_SourceInterface {
|
||||
interface Minify_SourceInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* Get the minifier
|
||||
|
@@ -7,7 +7,8 @@
|
||||
/**
|
||||
* @package Minify
|
||||
*/
|
||||
class Minify_SourceSet {
|
||||
class Minify_SourceSet
|
||||
{
|
||||
|
||||
/**
|
||||
* Get unique string for a set of sources
|
||||
|
@@ -29,7 +29,8 @@
|
||||
* @package Minify
|
||||
* @author Stephen Clay <steve@mrclay.org>
|
||||
*/
|
||||
class Minify_YUICompressor {
|
||||
class Minify_YUICompressor
|
||||
{
|
||||
|
||||
/**
|
||||
* Filepath of the YUI Compressor jar file. This must be set before
|
||||
@@ -92,6 +93,7 @@ class Minify_YUICompressor {
|
||||
if (! ($tmpFile = tempnam(self::$tempDir, 'yuic_'))) {
|
||||
throw new Exception('Minify_YUICompressor : could not create temp file in "'.self::$tempDir.'".');
|
||||
}
|
||||
|
||||
file_put_contents($tmpFile, $content);
|
||||
exec(self::_getCmd($options, $type, $tmpFile), $output, $result_code);
|
||||
unlink($tmpFile);
|
||||
@@ -104,23 +106,20 @@ class Minify_YUICompressor {
|
||||
|
||||
private static function _getCmd($userOptions, $type, $tmpFile)
|
||||
{
|
||||
$o = array_merge(
|
||||
array(
|
||||
'charset' => ''
|
||||
,'line-break' => 5000
|
||||
,'type' => $type
|
||||
,'nomunge' => false
|
||||
,'preserve-semi' => false
|
||||
,'disable-optimizations' => false
|
||||
,'stack-size' => ''
|
||||
)
|
||||
,$userOptions
|
||||
$defaults = array(
|
||||
'charset' => '',
|
||||
'line-break' => 5000,
|
||||
'type' => $type,
|
||||
'nomunge' => false,
|
||||
'preserve-semi' => false,
|
||||
'disable-optimizations' => false,
|
||||
'stack-size' => '',
|
||||
);
|
||||
$o = array_merge($defaults, $userOptions);
|
||||
|
||||
$cmd = self::$javaExecutable
|
||||
. (!empty($o['stack-size'])
|
||||
? ' -Xss' . $o['stack-size']
|
||||
: '')
|
||||
. ' -jar ' . escapeshellarg(self::$jarFile)
|
||||
. (!empty($o['stack-size']) ? ' -Xss' . $o['stack-size'] : '')
|
||||
. ' -jar ' . escapeshellarg(self::$jarFile)
|
||||
. " --type {$type}"
|
||||
. (preg_match('/^[\\da-zA-Z0-9\\-]+$/', $o['charset'])
|
||||
? " --charset {$o['charset']}"
|
||||
|
@@ -18,7 +18,8 @@ use InvalidArgumentException;
|
||||
* @author Steve Clay <steve@mrclay.org>
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
class Cli {
|
||||
class Cli
|
||||
{
|
||||
|
||||
/**
|
||||
* @var array validation errors
|
||||
|
@@ -43,7 +43,8 @@ use BadMethodCallException;
|
||||
* @author Steve Clay <steve@mrclay.org>
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
class Arg {
|
||||
class Arg
|
||||
{
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
|
@@ -55,7 +55,7 @@ if ($env->post('method') === 'Minify and serve') {
|
||||
}
|
||||
|
||||
$tpl = array();
|
||||
$tpl['classes'] = array('Minify_HTML', 'JSMin\\JSMin', 'Minify_CSS');
|
||||
$tpl['classes'] = array('Minify_HTML', 'JSMin\\JSMin', 'Minify_CSS', 'Minify_Lines');
|
||||
|
||||
if (in_array($env->post('method'), $tpl['classes'])) {
|
||||
|
||||
|
@@ -5,7 +5,7 @@
|
||||
*
|
||||
* Change to true to expose this info.
|
||||
*/
|
||||
$enabled = true;
|
||||
$enabled = false;
|
||||
|
||||
///////////////////////
|
||||
|
||||
|
@@ -24,9 +24,7 @@ class LessSourceTest extends TestCase
|
||||
touch($includedLess);
|
||||
|
||||
$mtime1 = filemtime($mainLess);
|
||||
var_dump($mtime1);
|
||||
$mtime2 = filemtime($includedLess);
|
||||
var_dump($mtime2);
|
||||
|
||||
$max = max($mtime1, $mtime2);
|
||||
|
||||
|
@@ -63,7 +63,7 @@ class MinifyClosureCompilerTest extends TestCase
|
||||
$src = "function unused() {};";
|
||||
$minExpected = '';
|
||||
$options = array(
|
||||
Minify_ClosureCompiler::OPTION_COMPILATION_LEVEL => 'ADVANCED_OPTIMIZATIONS'
|
||||
'compilation_level' => 'ADVANCED_OPTIMIZATIONS'
|
||||
);
|
||||
$minOutput = Minify_ClosureCompiler::minify($src, $options);
|
||||
$this->assertSame($minExpected, $minOutput, 'advanced optimizations');
|
||||
@@ -80,12 +80,36 @@ class MinifyClosureCompilerTest extends TestCase
|
||||
{
|
||||
$this->assertHasJar();
|
||||
|
||||
$src = file_get_contents(self::$test_files . '/bug-513.js');
|
||||
$src = $this->getDataFile('bug-513.js');
|
||||
$minExpected = 'var a=4;';
|
||||
$minOutput = Minify_ClosureCompiler::minify($src);
|
||||
$this->assertSame($minExpected, $minOutput, 'advanced optimizations');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that language_in parameter has effect.
|
||||
*/
|
||||
public function testLanguageOptions()
|
||||
{
|
||||
$this->assertHasJar();
|
||||
|
||||
$src = $this->getDataFile('js/jscomp.polyfill.js');
|
||||
$exp = $this->getDataFile('js/jscomp.polyfill.min.js');
|
||||
$options = array(
|
||||
'language_in' => 'ECMASCRIPT3',
|
||||
);
|
||||
|
||||
$res = Minify_ClosureCompiler::minify($src, $options);
|
||||
$this->assertSame($exp, $res);
|
||||
|
||||
$options = array(
|
||||
'language_in' => 'ECMASCRIPT6',
|
||||
);
|
||||
$exp = $this->getDataFile('js/jscomp.polyfilled.min.js');
|
||||
$res = Minify_ClosureCompiler::minify($src, $options);
|
||||
$this->assertSame($exp, $res);
|
||||
}
|
||||
|
||||
protected function assertHasJar()
|
||||
{
|
||||
$this->assertNotEmpty(Minify_ClosureCompiler::$jarFile);
|
||||
|
@@ -4,8 +4,6 @@ class MinifyLinesTest extends TestCase
|
||||
{
|
||||
public function test_lines()
|
||||
{
|
||||
$exp = file_get_contents(self::$test_files . "/minify/lines_output.js");
|
||||
|
||||
$env = new Minify_Env(array(
|
||||
'server' => array(
|
||||
'DOCUMENT_ROOT' => dirname(__DIR__),
|
||||
@@ -15,15 +13,27 @@ class MinifyLinesTest extends TestCase
|
||||
$controller = new Minify_Controller_Files($env, $sourceFactory);
|
||||
$minify = new Minify(new Minify_Cache_Null());
|
||||
|
||||
$ret = $minify->serve($controller, array(
|
||||
'debug' => true
|
||||
,'quiet' => true
|
||||
,'encodeOutput' => false
|
||||
,'files' => array(
|
||||
self::$test_files . "/js/before.js"
|
||||
)
|
||||
));
|
||||
$files = glob(self::$test_files . "/lines/*.in.js");
|
||||
|
||||
$this->assertEquals($exp, $ret['content']);
|
||||
// uncomment to debug one
|
||||
//$files = array(self::$test_files . "/lines/basic.in.js");
|
||||
|
||||
foreach ($files as $file) {
|
||||
$ret = $minify->serve($controller, array(
|
||||
'debug' => true,
|
||||
'quiet' => true,
|
||||
'encodeOutput' => false,
|
||||
'files' => array($file),
|
||||
));
|
||||
|
||||
$outFile = str_replace('.in.js', '.out.js', $file);
|
||||
|
||||
$exp = file_get_contents($outFile);
|
||||
|
||||
// uncomment to set up expected output
|
||||
//file_put_contents($outFile, $ret['content']);
|
||||
|
||||
$this->assertEquals($exp, $ret['content'], "Did not match: " . basename($outFile));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -20,7 +20,7 @@ class MinifyNailgunClosureCompilerTest extends TestCase
|
||||
/**
|
||||
* Test minimisation with the minimum necessary settings
|
||||
*/
|
||||
public function test2()
|
||||
public function test1()
|
||||
{
|
||||
$this->assertHasJar();
|
||||
$src = "
|
||||
@@ -40,8 +40,10 @@ class MinifyNailgunClosureCompilerTest extends TestCase
|
||||
protected function assertHasJar()
|
||||
{
|
||||
$this->assertNotEmpty(Minify_ClosureCompiler::$jarFile);
|
||||
$this->assertNotEmpty(Minify_NailgunClosureCompiler::$ngJarFile);
|
||||
try {
|
||||
$this->assertFileExists(Minify_ClosureCompiler::$jarFile, "Have closure compiler compiler.jar");
|
||||
$this->assertFileExists(Minify_NailgunClosureCompiler::$ngJarFile, "Have nailgun.jar");
|
||||
} catch (Exception $e) {
|
||||
$this->markTestSkipped($e->getMessage());
|
||||
}
|
||||
|
42
tests/ScssSourceTest.php
Normal file
42
tests/ScssSourceTest.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
class ScssSourceTest extends TestCase
|
||||
{
|
||||
public function setUp()
|
||||
{
|
||||
if (version_compare(PHP_VERSION, '5.4.0', '<')) {
|
||||
$this->markTestSkipped('scssphp is not compatible with this PHP version.');
|
||||
}
|
||||
|
||||
$this->realDocRoot = $_SERVER['DOCUMENT_ROOT'];
|
||||
$_SERVER['DOCUMENT_ROOT'] = self::$document_root;
|
||||
}
|
||||
|
||||
/**
|
||||
* @link https://github.com/mrclay/minify/issues/500
|
||||
*/
|
||||
public function testTimestamp()
|
||||
{
|
||||
$baseDir = self::$test_files;
|
||||
|
||||
$mainLess = "$baseDir/main.scss";
|
||||
$includedLess = "$baseDir/_included.scss";
|
||||
|
||||
// touch timestamp with 1s difference
|
||||
touch($mainLess);
|
||||
sleep(1);
|
||||
touch($includedLess);
|
||||
|
||||
$mtime1 = filemtime($mainLess);
|
||||
$mtime2 = filemtime($includedLess);
|
||||
|
||||
$max = max($mtime1, $mtime2);
|
||||
|
||||
$options = array(
|
||||
'groupsConfigFile' => "$baseDir/htmlHelper_groupsConfig.php",
|
||||
);
|
||||
$res = Minify_HTML_Helper::getUri('scss', $options);
|
||||
|
||||
$this->assertEquals("/min/g=scss&{$max}", $res);
|
||||
}
|
||||
}
|
@@ -47,4 +47,23 @@ class TestCase extends PHPUnit_Framework_TestCase
|
||||
$this->assertSame($data, $displayed, "$id display");
|
||||
$this->assertEquals($data, $cache->fetch($id), "$id fetch");
|
||||
}
|
||||
|
||||
/**
|
||||
* Read data file, assert that it exists and is not empty.
|
||||
* As a side effect calls trim() to fight against different Editors that insert or strip final newline.
|
||||
*
|
||||
* @param string $filename
|
||||
* @return string
|
||||
*/
|
||||
protected function getDataFile($filename)
|
||||
{
|
||||
$path = self::$test_files . '/' . $filename;
|
||||
$this->assertFileExists($path);
|
||||
$contents = file_get_contents($path);
|
||||
$this->assertNotEmpty($contents);
|
||||
$contents = trim($contents);
|
||||
$this->assertNotEmpty($contents);
|
||||
|
||||
return $contents;
|
||||
}
|
||||
}
|
8
tests/_test_files/_included.scss
Normal file
8
tests/_test_files/_included.scss
Normal file
@@ -0,0 +1,8 @@
|
||||
/* lesstest2.scss */
|
||||
|
||||
|
||||
a.included {
|
||||
color: $primary-color;
|
||||
font-size: 13px;
|
||||
text-decoration: none;
|
||||
}
|
@@ -8,6 +8,7 @@
|
||||
@import url("/css/foo.css"); /* abs, should not alter */
|
||||
@import url(/css2/foo.css); /* abs, should not alter */
|
||||
@import url(foo:bar); /* scheme, should not alter */
|
||||
@import url(); /* empty, should not alter */
|
||||
foo {clip-path:url(#c1)} /* inline clip path, should not alter */
|
||||
foo {clip-path:url(/_test_files/css_uriRewriter/foo.svg#c1)}
|
||||
foo {mask: url(#c1)} /* should not alter */
|
||||
@@ -17,5 +18,6 @@ foo {background:url('http://foo.com/css/foo.css');} /* scheme, should not alter
|
||||
foo {background:url("//foo.com/css/foo.css");} /* protocol relative, should not alter */
|
||||
foo {background:url(foo:bar);} /* scheme, should not alter */
|
||||
foo {background:url("/_test_files/css_uriRewriter/foo bar.jpg");}
|
||||
foo {background:url("");} /* empty, should not alter */
|
||||
@import url('/_test_files/css_uriRewriter/foo bar.css');
|
||||
@import "/_test_files/css_uriRewriter/foo bar.css";
|
||||
|
@@ -8,6 +8,7 @@
|
||||
@import url("/css/foo.css"); /* abs, should not alter */
|
||||
@import url(/css2/foo.css); /* abs, should not alter */
|
||||
@import url(foo:bar); /* scheme, should not alter */
|
||||
@import url(); /* empty, should not alter */
|
||||
foo {clip-path:url(#c1)} /* inline clip path, should not alter */
|
||||
foo {clip-path:url(http://cnd.com/A/B/foo.svg#c1)}
|
||||
foo {mask: url(#c1)} /* should not alter */
|
||||
@@ -17,5 +18,6 @@ foo {background:url('http://foo.com/css/foo.css');} /* scheme, should not alter
|
||||
foo {background:url("//foo.com/css/foo.css");} /* protocol relative, should not alter */
|
||||
foo {background:url(foo:bar);} /* scheme, should not alter */
|
||||
foo {background:url("http://cnd.com/A/B/foo bar.jpg");}
|
||||
foo {background:url("");} /* empty, should not alter */
|
||||
@import url('http://cnd.com/A/B/foo bar.css');
|
||||
@import "http://cnd.com/A/B/foo bar.css";
|
||||
|
@@ -8,6 +8,7 @@
|
||||
@import url("/css/foo.css"); /* abs, should not alter */
|
||||
@import url(/css2/foo.css); /* abs, should not alter */
|
||||
@import url(foo:bar); /* scheme, should not alter */
|
||||
@import url(); /* empty, should not alter */
|
||||
foo {clip-path:url(#c1)} /* inline clip path, should not alter */
|
||||
foo {clip-path:url(//cnd.com/A/B/foo.svg#c1)}
|
||||
foo {mask: url(#c1)} /* should not alter */
|
||||
@@ -17,5 +18,6 @@ foo {background:url('http://foo.com/css/foo.css');} /* scheme, should not alter
|
||||
foo {background:url("//foo.com/css/foo.css");} /* protocol relative, should not alter */
|
||||
foo {background:url(foo:bar);} /* scheme, should not alter */
|
||||
foo {background:url("//cnd.com/A/B/foo bar.jpg");}
|
||||
foo {background:url("");} /* empty, should not alter */
|
||||
@import url('//cnd.com/A/B/foo bar.css');
|
||||
@import "//cnd.com/A/B/foo bar.css";
|
||||
|
@@ -8,6 +8,7 @@
|
||||
@import url("/css/foo.css"); /* abs, should not alter */
|
||||
@import url(/css2/foo.css); /* abs, should not alter */
|
||||
@import url(foo:bar); /* scheme, should not alter */
|
||||
@import url(); /* empty, should not alter */
|
||||
foo {clip-path:url(#c1)} /* inline clip path, should not alter */
|
||||
foo {clip-path:url(foo.svg#c1)}
|
||||
foo {mask: url( #c1 )} /* should not alter */
|
||||
@@ -17,5 +18,6 @@ foo {background:url('http://foo.com/css/foo.css');} /* scheme, should not alter
|
||||
foo {background:url("//foo.com/css/foo.css");} /* protocol relative, should not alter */
|
||||
foo {background:url(foo:bar);} /* scheme, should not alter */
|
||||
foo {background:url("foo bar.jpg");}
|
||||
foo {background:url("");} /* empty, should not alter */
|
||||
@import url('foo bar.css');
|
||||
@import "foo bar.css";
|
||||
|
@@ -9,4 +9,8 @@ return array(
|
||||
'less' => array(
|
||||
'//_test_files/main.less',
|
||||
),
|
||||
|
||||
'scss' => array(
|
||||
'//_test_files/main.scss',
|
||||
),
|
||||
);
|
||||
|
7
tests/_test_files/js/jscomp.polyfill.js
Normal file
7
tests/_test_files/js/jscomp.polyfill.js
Normal file
@@ -0,0 +1,7 @@
|
||||
(function() {
|
||||
/**
|
||||
* @type {string}
|
||||
*/
|
||||
var $array = jQuery.find('#div');
|
||||
print($array.find('a'));
|
||||
})();
|
1
tests/_test_files/js/jscomp.polyfill.min.js
vendored
Normal file
1
tests/_test_files/js/jscomp.polyfill.min.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
(function(){var a=jQuery.find("#div");print(a.find("a"))})();
|
3
tests/_test_files/js/jscomp.polyfilled.min.js
vendored
Normal file
3
tests/_test_files/js/jscomp.polyfilled.min.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
var $jscomp={scope:{},findInternal:function(a,c,b){a instanceof String&&(a=String(a));for(var d=a.length,e=0;e<d;e++){var f=a[e];if(c.call(b,f,e,a))return{i:e,v:f}}return{i:-1,v:void 0}}};$jscomp.defineProperty="function"==typeof Object.defineProperties?Object.defineProperty:function(a,c,b){if(b.get||b.set)throw new TypeError("ES3 does not support getters and setters.");a!=Array.prototype&&a!=Object.prototype&&(a[c]=b.value)};
|
||||
$jscomp.getGlobal=function(a){return"undefined"!=typeof window&&window===a?a:"undefined"!=typeof global&&null!=global?global:a};$jscomp.global=$jscomp.getGlobal(this);$jscomp.polyfill=function(a,c,b,d){if(c){b=$jscomp.global;a=a.split(".");for(d=0;d<a.length-1;d++){var e=a[d];e in b||(b[e]={});b=b[e]}a=a[a.length-1];d=b[a];c=c(d);c!=d&&null!=c&&$jscomp.defineProperty(b,a,{configurable:!0,writable:!0,value:c})}};
|
||||
$jscomp.polyfill("Array.prototype.find",function(a){return a?a:function(a,b){return $jscomp.findInternal(this,a,b).v}},"es6-impl","es3");(function(){var a=jQuery.find("#div");print(a.find("a"))})();
|
66
tests/_test_files/lines/basic.in.js
Normal file
66
tests/_test_files/lines/basic.in.js
Normal file
@@ -0,0 +1,66 @@
|
||||
/*! is.js
|
||||
|
||||
(c) 2001 Douglas Crockford
|
||||
2001 June 3
|
||||
*/
|
||||
|
||||
// is
|
||||
|
||||
// The -is- object is used to identify the browser. Every browser edition
|
||||
// identifies itself, but there is no standard way of doing it, and some of
|
||||
// the identification is deceptive. This is because the authors of web
|
||||
// browsers are liars. For example, Microsoft's IE browsers claim to be
|
||||
// Mozilla 4. Netscape 6 claims to be version 5.
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*@cc_on
|
||||
/*@if (@_win32)
|
||||
if (is.ie && is.win)
|
||||
document.write("PASS: IE/win honored conditional comment.<br>");
|
||||
@else @*/
|
||||
if (is.ie && is.win)
|
||||
document.write("FAIL: IE/win did not honor multi-line conditional comment.<br>");
|
||||
else
|
||||
document.write("PASS: Non-IE/win browser ignores multi-line conditional comment.<br>");
|
||||
/*@end
|
||||
@*/
|
||||
|
||||
var recognizesCondComm = true;
|
||||
//@cc_on/*
|
||||
recognizesCondComm = false;
|
||||
//@cc_on*/
|
||||
|
||||
if ((is.ie && is.win) == recognizesCondComm)
|
||||
document.write("PASS: IE/win honored single-line conditional comment.<br>");
|
||||
else
|
||||
document.write("FAIL: Non-IE/win browser did not ignore single-line conditional comment.<br>");
|
||||
|
||||
// hello
|
||||
//@cc_on/*
|
||||
// world
|
||||
//@cc_on*/
|
||||
//@cc_on/*
|
||||
'hello';
|
||||
/*!* preserved */
|
||||
/*!* preserved */
|
@@ -1,20 +1,20 @@
|
||||
|
||||
/* before.js */
|
||||
/* basic.in.js */
|
||||
|
||||
/* 1 */ /*! is.js
|
||||
/* 2 *|
|
||||
/* 2 *|
|
||||
/* 3 *| (c) 2001 Douglas Crockford
|
||||
/* 4 *| 2001 June 3
|
||||
/* 5 *| */
|
||||
/* 6 */
|
||||
/* 6 */
|
||||
/* 7 */ // is
|
||||
/* 8 */
|
||||
/* 8 */
|
||||
/* 9 */ // The -is- object is used to identify the browser. Every browser edition
|
||||
/* 10 */ // identifies itself, but there is no standard way of doing it, and some of
|
||||
/* 11 */ // the identification is deceptive. This is because the authors of web
|
||||
/* 12 */ // browsers are liars. For example, Microsoft's IE browsers claim to be
|
||||
/* 13 */ // Mozilla 4. Netscape 6 claims to be version 5.
|
||||
/* 14 */
|
||||
/* 14 */
|
||||
/* 15 */ var is = {
|
||||
/* 16 */ ie: navigator.appName == 'Microsoft Internet Explorer',
|
||||
/* 17 */ java: navigator.javaEnabled(),
|
||||
@@ -36,7 +36,7 @@
|
||||
/* 33 */ is.ie = is.ns = false;
|
||||
/* 34 */ is.gecko = true;
|
||||
/* 35 */ }
|
||||
/* 36 */
|
||||
/* 36 */
|
||||
/* 37 */ /*@cc_on
|
||||
/* 38 *| /*@if (@_win32)
|
||||
/* 39 *| if (is.ie && is.win)
|
||||
@@ -44,24 +44,24 @@
|
||||
/* 41 *| @else @*/
|
||||
/* 42 */ if (is.ie && is.win)
|
||||
/* 43 */ document.write("FAIL: IE/win did not honor multi-line conditional comment.<br>");
|
||||
/* 44 */ else
|
||||
/* 44 */ else
|
||||
/* 45 */ document.write("PASS: Non-IE/win browser ignores multi-line conditional comment.<br>");
|
||||
/* 46 */ /*@end
|
||||
/* 47 *| @*/
|
||||
/* 48 */
|
||||
/* 48 */
|
||||
/* 49 */ var recognizesCondComm = true;
|
||||
/* 50 */ //@cc_on/*
|
||||
|
||||
/* before.js */
|
||||
/* basic.in.js */
|
||||
|
||||
/* 51 */ recognizesCondComm = false;
|
||||
/* 52 */ //@cc_on*/
|
||||
/* 53 */
|
||||
/* 53 */
|
||||
/* 54 */ if ((is.ie && is.win) == recognizesCondComm)
|
||||
/* 55 */ document.write("PASS: IE/win honored single-line conditional comment.<br>");
|
||||
/* 56 */ else
|
||||
/* 56 */ else
|
||||
/* 57 */ document.write("FAIL: Non-IE/win browser did not ignore single-line conditional comment.<br>");
|
||||
/* 58 */
|
||||
/* 58 */
|
||||
/* 59 */ // hello
|
||||
/* 60 */ //@cc_on/*
|
||||
/* 61 */ // world
|
@@ -1,10 +1,14 @@
|
||||
// sections from Prototype 1.6.1
|
||||
var xpath = ".//*[local-name()='ul' or local-name()='UL']" +
|
||||
"//*[local-name()='li' or local-name()='LI']";
|
||||
this.matcher = ['.//*'];
|
||||
xpath = {
|
||||
descendant: "//*",
|
||||
child: "/*",
|
||||
f: 0
|
||||
};
|
||||
document._getElementsByXPath('.//*' + cond, element);
|
||||
// sections from Prototype 1.6.1
|
||||
var xpath = ".//*[local-name()='ul' or local-name()='UL']" +
|
||||
"//*[local-name()='li' or local-name()='LI']";
|
||||
this.matcher = ['.//*'];
|
||||
xpath = {
|
||||
descendant: "//*",
|
||||
child: "/*",
|
||||
f: 0
|
||||
};
|
||||
document._getElementsByXPath('.//*' + cond, element);
|
||||
|
||||
// from angular 1.4.8
|
||||
var URL_REGEXP = /^[a-z][a-z\d.+-]*:\/*(?:[^:@]+(?::[^@]+)?@)?(?:[^\s:/?#]+|\[[a-f\d:]+\])(?::\d+)?(?:\/[^?#]*)?(?:\?[^#]*)?(?:#.*)?$/i;
|
||||
|
18
tests/_test_files/lines/misc.out.js
Normal file
18
tests/_test_files/lines/misc.out.js
Normal file
@@ -0,0 +1,18 @@
|
||||
|
||||
/* misc.in.js */
|
||||
|
||||
/* 1 */ // sections from Prototype 1.6.1
|
||||
/* 2 */ var xpath = ".//*[local-name()='ul' or local-name()='UL']" +
|
||||
/* 3 */ "//*[local-name()='li' or local-name()='LI']";
|
||||
/* 4 */ this.matcher = ['.//*'];
|
||||
/* 5 */ xpath = {
|
||||
/* 6 */ descendant: "//*",
|
||||
/* 7 */ child: "/*",
|
||||
/* 8 */ f: 0
|
||||
/* 9 */ };
|
||||
/* 10 */ document._getElementsByXPath('.//*' + cond, element);
|
||||
/* 11 */
|
||||
/* 12 */ // from angular 1.4.8
|
||||
/* 13 */ var URL_REGEXP = /^[a-z][a-z\d.+-]*:\/*(?:[^:@]+(?::[^@]+)?@)?(?:[^\s:/?#]+|\[[a-f\d:]+\])(?::\d+)?(?:\/[^?#]*)?(?:\?[^#]*)?(?:#.*)?$/i;
|
||||
/* 14 */
|
||||
/* 15 */
|
13
tests/_test_files/lines/url.in.js
Normal file
13
tests/_test_files/lines/url.in.js
Normal file
@@ -0,0 +1,13 @@
|
||||
foo; /* http://example.com */
|
||||
bar;
|
||||
|
||||
foo; /*
|
||||
http://example.com */
|
||||
bar;
|
||||
|
||||
foo = "http://example.com"; /* hello */
|
||||
bar;
|
||||
|
||||
foo = "http://example.com"; /*
|
||||
hello */
|
||||
bar;
|
17
tests/_test_files/lines/url.out.js
Normal file
17
tests/_test_files/lines/url.out.js
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
/* url.in.js */
|
||||
|
||||
/* 1 */ foo; /* http://example.com */
|
||||
/* 2 */ bar;
|
||||
/* 3 */
|
||||
/* 4 */ foo; /*
|
||||
/* 5 *| http://example.com */
|
||||
/* 6 */ bar;
|
||||
/* 7 */
|
||||
/* 8 */ foo = "http://example.com"; /* hello */
|
||||
/* 9 */ bar;
|
||||
/* 10 */
|
||||
/* 11 */ foo = "http://example.com"; /*
|
||||
/* 12 *| hello */
|
||||
/* 13 */ bar;
|
||||
/* 14 */
|
29
tests/_test_files/main.scss
Normal file
29
tests/_test_files/main.scss
Normal file
@@ -0,0 +1,29 @@
|
||||
/*! preserving comment */
|
||||
|
||||
// Variable
|
||||
$primary-color: hotpink;
|
||||
|
||||
// Mixin
|
||||
@mixin border-radius($radius) {
|
||||
-webkit-border-radius: $radius;
|
||||
-moz-border-radius: $radius;
|
||||
border-radius: $radius;
|
||||
}
|
||||
|
||||
.my-element {
|
||||
color: $primary-color;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.my-other-element {
|
||||
@include border-radius(6px);
|
||||
}
|
||||
|
||||
/* import include -> */
|
||||
@import "_included";
|
||||
/* <- import included */
|
||||
|
||||
/*
|
||||
a normal comment.
|
||||
*/
|
Reference in New Issue
Block a user