delete lib from index, try to add submodules
This commit is contained in:
parent
1e4a4f181d
commit
0d6d4cf2b9
6
.gitmodules
vendored
6
.gitmodules
vendored
@ -1,3 +1,7 @@
|
|||||||
[submodule "lib"]
|
[submodule "lib"]
|
||||||
path = lib
|
path = lib
|
||||||
url = git@github.com:matthiasmullie/minify.git
|
url = https://github.com/matthiasmullie/minify.git
|
||||||
|
|
||||||
|
[submodule "dep"]
|
||||||
|
path = dep
|
||||||
|
url = https://github.com/matthiasmullie/path-converter.git
|
||||||
|
|||||||
1
dep
Submodule
1
dep
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 0e77b521554de4cec4c222862e899a154b726a85
|
||||||
9
lib/.gitattributes
vendored
9
lib/.gitattributes
vendored
@ -1,9 +0,0 @@
|
|||||||
* text=auto
|
|
||||||
|
|
||||||
/tests export-ignore
|
|
||||||
/.gitattributes export-ignore
|
|
||||||
/.gitignore export-ignore
|
|
||||||
/.travis.yml export-ignore
|
|
||||||
/makefile export-ignore
|
|
||||||
/phpunit.xml.dist export-ignore
|
|
||||||
/README.md export-ignore
|
|
||||||
10
lib/.gitignore
vendored
10
lib/.gitignore
vendored
@ -1,10 +0,0 @@
|
|||||||
/build
|
|
||||||
/docs
|
|
||||||
/vendor
|
|
||||||
/.idea
|
|
||||||
/.project
|
|
||||||
/.cache
|
|
||||||
/.buildpath
|
|
||||||
/.settings
|
|
||||||
.*.swp
|
|
||||||
.DS_Store
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
language: php
|
|
||||||
|
|
||||||
php:
|
|
||||||
- 7
|
|
||||||
- 5.6
|
|
||||||
- 5.5
|
|
||||||
- 5.4
|
|
||||||
- hhvm
|
|
||||||
|
|
||||||
before_script:
|
|
||||||
- pip install --user codecov
|
|
||||||
- composer self-update && composer install --dev
|
|
||||||
|
|
||||||
script:
|
|
||||||
- ./vendor/bin/phpunit
|
|
||||||
|
|
||||||
after_success:
|
|
||||||
- codecov
|
|
||||||
18
lib/LICENSE
18
lib/LICENSE
@ -1,18 +0,0 @@
|
|||||||
Copyright (c) 2012 Matthias Mullie
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
||||||
this software and associated documentation files (the "Software"), to deal in
|
|
||||||
the Software without restriction, including without limitation the rights to
|
|
||||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
||||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
||||||
subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
||||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
||||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
||||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
||||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
140
lib/README.md
140
lib/README.md
@ -1,140 +0,0 @@
|
|||||||
# Minify
|
|
||||||
|
|
||||||
[](https://travis-ci.org/matthiasmullie/minify)
|
|
||||||
[](https://codecov.io/github/matthiasmullie/minify)
|
|
||||||
[](https://scrutinizer-ci.com/g/matthiasmullie/minify)
|
|
||||||
[](https://packagist.org/packages/matthiasmullie/minify)
|
|
||||||
[](https://packagist.org/packages/matthiasmullie/minify)
|
|
||||||
[](https://github.com/matthiasmullie/minify/blob/master/LICENSE)
|
|
||||||
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
### CSS
|
|
||||||
|
|
||||||
```php
|
|
||||||
use MatthiasMullie\Minify;
|
|
||||||
|
|
||||||
$sourcePath = '/path/to/source/css/file.css';
|
|
||||||
$minifier = new Minify\CSS($sourcePath);
|
|
||||||
|
|
||||||
// we can even add another file, they'll then be
|
|
||||||
// joined in 1 output file
|
|
||||||
$sourcePath2 = '/path/to/second/source/css/file.css';
|
|
||||||
$minifier->add($sourcePath2);
|
|
||||||
|
|
||||||
// or we can just add plain CSS
|
|
||||||
$css = 'body { color: #000000; }';
|
|
||||||
$minifier->add($css);
|
|
||||||
|
|
||||||
// save minified file to disk
|
|
||||||
$minifiedPath = '/path/to/minified/css/file.css';
|
|
||||||
$minifier->minify($minifiedPath);
|
|
||||||
|
|
||||||
// or just output the content
|
|
||||||
echo $minifier->minify();
|
|
||||||
```
|
|
||||||
|
|
||||||
### JS
|
|
||||||
|
|
||||||
```php
|
|
||||||
// just look at the CSS example; it's exactly the same, but with the JS class & JS files :)
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Methods
|
|
||||||
|
|
||||||
Available methods, for both CSS & JS minifier, are:
|
|
||||||
|
|
||||||
### __construct(/* overload paths */)
|
|
||||||
|
|
||||||
The object constructor accepts 0, 1 or multiple paths of files, or even complete CSS/JS content, that should be minified.
|
|
||||||
All CSS/JS passed along, will be combined into 1 minified file.
|
|
||||||
|
|
||||||
```php
|
|
||||||
use MatthiasMullie\Minify;
|
|
||||||
$minifier = new Minify\JS($path1, $path2);
|
|
||||||
```
|
|
||||||
|
|
||||||
### add($path, /* overload paths */)
|
|
||||||
|
|
||||||
This is roughly equivalent to the constructor.
|
|
||||||
|
|
||||||
```php
|
|
||||||
$minifier->add($path3);
|
|
||||||
$minifier->add($js);
|
|
||||||
```
|
|
||||||
|
|
||||||
### minify($path)
|
|
||||||
|
|
||||||
This will minify the files' content, save the result to $path and return the resulting content.
|
|
||||||
If the $path parameter is omitted, the result will not be written anywhere.
|
|
||||||
|
|
||||||
*CAUTION: If you have CSS with relative paths (to imports, images, ...), you should always specify a target path! Then those relative paths will be adjusted in accordance with the new path.*
|
|
||||||
|
|
||||||
```php
|
|
||||||
$minifier->minify('/target/path.js');
|
|
||||||
```
|
|
||||||
|
|
||||||
### gzip($path, $level)
|
|
||||||
|
|
||||||
Minifies and optionally saves to a file, just like `minify()`, but it also `gzencode()`s the minified content.
|
|
||||||
|
|
||||||
```php
|
|
||||||
$minifier->gzip('/target/path.js');
|
|
||||||
```
|
|
||||||
|
|
||||||
### setMaxImportSize($size) *(CSS only)*
|
|
||||||
|
|
||||||
The CSS minifier will automatically embed referenced files (like images, fonts, ...) into the minified CSS, so they don't have to be fetched over multiple connections.
|
|
||||||
|
|
||||||
However, for really large files, it's likely better to load them separately (as it would increase the CSS load time if they were included.)
|
|
||||||
|
|
||||||
This method allows the max size of files to import into the minified CSS to be set (in kB). The default size is 5.
|
|
||||||
|
|
||||||
```php
|
|
||||||
$minifier->setMaxImportSize(10);
|
|
||||||
```
|
|
||||||
|
|
||||||
### setImportExtensions($extensions) *(CSS only)*
|
|
||||||
|
|
||||||
The CSS minifier will automatically embed referenced files (like images, fonts, ...) into minified CSS, so they don't have to be fetched over multiple connections.
|
|
||||||
|
|
||||||
This methods allows the type of files to be specified, along with their data:mime type.
|
|
||||||
|
|
||||||
The default embedded file types are gif, png, jpg, jpeg, svg & woff.
|
|
||||||
|
|
||||||
```php
|
|
||||||
$extensions = array(
|
|
||||||
'gif' => 'data:image/gif',
|
|
||||||
'png' => 'data:image/png',
|
|
||||||
);
|
|
||||||
|
|
||||||
$minifier->setImportExtensions($extensions);
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
Simply add a dependency on matthiasmullie/minify to your composer.json file if you use [Composer](https://getcomposer.org/) to manage the dependencies of your project:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
composer require matthiasmullie/minify
|
|
||||||
```
|
|
||||||
|
|
||||||
Although it's recommended to use Composer, you can actually [include these files](https://github.com/matthiasmullie/minify/issues/83) anyway you want.
|
|
||||||
|
|
||||||
|
|
||||||
## Try it
|
|
||||||
|
|
||||||
Simply try it out online at <http://www.minifier.org>.
|
|
||||||
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
Minify is [MIT](http://opensource.org/licenses/MIT) licensed.
|
|
||||||
|
|
||||||
|
|
||||||
## Challenges
|
|
||||||
|
|
||||||
If you're interested in learning some of the harder technical challenges I've encountered building this, you probably want to take a look at [what I wrote about it](http://www.mullie.eu/dont-build-your-own-minifier/) on my blog.
|
|
||||||
@ -1,45 +0,0 @@
|
|||||||
#!/usr/bin/env php
|
|
||||||
<?php
|
|
||||||
use MatthiasMullie\Minify;
|
|
||||||
|
|
||||||
// command line utility to minify CSS
|
|
||||||
if (file_exists(__DIR__ . '/../../../autoload.php')) {
|
|
||||||
// if composer install
|
|
||||||
require_once __DIR__ . '/../../../autoload.php';
|
|
||||||
} else {
|
|
||||||
require_once __DIR__ . '/../src/Minify.php';
|
|
||||||
require_once __DIR__ . '/../src/CSS.php';
|
|
||||||
require_once __DIR__ . '/../src/Exception.php';
|
|
||||||
}
|
|
||||||
|
|
||||||
error_reporting(E_ALL);
|
|
||||||
// check PHP setup for cli arguments
|
|
||||||
if (!isset($_SERVER['argv']) && !isset($argv)) {
|
|
||||||
fwrite(STDERR, 'Please enable the "register_argc_argv" directive in your php.ini' . PHP_EOL);
|
|
||||||
exit(1);
|
|
||||||
} elseif (!isset($argv)) {
|
|
||||||
$argv = $_SERVER['argv'];
|
|
||||||
}
|
|
||||||
// check if path to file given
|
|
||||||
if (!isset($argv[1])) {
|
|
||||||
fwrite(STDERR, 'Argument expected: path to file' . PHP_EOL);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
// check if script run in cli environment
|
|
||||||
if ('cli' !== php_sapi_name()) {
|
|
||||||
fwrite(STDERR, $argv[1] . ' must be run in the command line' . PHP_EOL);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
// check if source file exists
|
|
||||||
if (!file_exists($argv[1])) {
|
|
||||||
fwrite(STDERR, 'Source file "' . $argv[1] . '" not found' . PHP_EOL);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$minifier = new Minify\CSS($argv[1]);
|
|
||||||
echo $minifier->minify();
|
|
||||||
} catch (Exception $e) {
|
|
||||||
fwrite(STDERR, $e->getMessage(), PHP_EOL);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
@ -1,45 +0,0 @@
|
|||||||
#!/usr/bin/env php
|
|
||||||
<?php
|
|
||||||
use MatthiasMullie\Minify;
|
|
||||||
|
|
||||||
// command line utility to minify JS
|
|
||||||
if (file_exists(__DIR__ . '/../../../autoload.php')) {
|
|
||||||
// if composer install
|
|
||||||
require_once __DIR__ . '/../../../autoload.php';
|
|
||||||
} else {
|
|
||||||
require_once __DIR__ . '/../src/Minify.php';
|
|
||||||
require_once __DIR__ . '/../src/JS.php';
|
|
||||||
require_once __DIR__ . '/../src/Exception.php';
|
|
||||||
}
|
|
||||||
|
|
||||||
error_reporting(E_ALL);
|
|
||||||
// check PHP setup for cli arguments
|
|
||||||
if (!isset($_SERVER['argv']) && !isset($argv)) {
|
|
||||||
fwrite(STDERR, 'Please enable the "register_argc_argv" directive in your php.ini' . PHP_EOL);
|
|
||||||
exit(1);
|
|
||||||
} elseif (!isset($argv)) {
|
|
||||||
$argv = $_SERVER['argv'];
|
|
||||||
}
|
|
||||||
// check if path to file given
|
|
||||||
if (!isset($argv[1])) {
|
|
||||||
fwrite(STDERR, 'Argument expected: path to file' . PHP_EOL);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
// check if script run in cli environment
|
|
||||||
if ('cli' !== php_sapi_name()) {
|
|
||||||
fwrite(STDERR, $argv[1] . ' must be run in the command line' . PHP_EOL);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
// check if source file exists
|
|
||||||
if (!file_exists($argv[1])) {
|
|
||||||
fwrite(STDERR, 'Source file "' . $argv[1] . '" not found' . PHP_EOL);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$minifier = new Minify\JS($argv[1]);
|
|
||||||
echo $minifier->minify();
|
|
||||||
} catch (Exception $e) {
|
|
||||||
fwrite(STDERR, $e->getMessage(), PHP_EOL);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
@ -1,34 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "matthiasmullie/minify",
|
|
||||||
"type": "library",
|
|
||||||
"description": "CSS & JS minifier",
|
|
||||||
"keywords": ["minify", "minifier", "css", "js", "javascript"],
|
|
||||||
"homepage": "http://www.minifier.org",
|
|
||||||
"license": "MIT",
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "Matthias Mullie",
|
|
||||||
"homepage": "http://www.mullie.eu",
|
|
||||||
"email": "minify@mullie.eu",
|
|
||||||
"role": "Developer"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"require": {
|
|
||||||
"php": ">=5.3.0",
|
|
||||||
"ext-pcre": "*",
|
|
||||||
"matthiasmullie/path-converter": "~1.0"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"matthiasmullie/scrapbook": "~1.0",
|
|
||||||
"phpunit/phpunit": "~4.8"
|
|
||||||
},
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"MatthiasMullie\\Minify\\": "src/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"bin": [
|
|
||||||
"bin/minifycss",
|
|
||||||
"bin/minifyjs"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
in
|
|
||||||
public
|
|
||||||
extends
|
|
||||||
private
|
|
||||||
protected
|
|
||||||
implements
|
|
||||||
instanceof
|
|
||||||
@ -1,27 +0,0 @@
|
|||||||
do
|
|
||||||
in
|
|
||||||
let
|
|
||||||
new
|
|
||||||
var
|
|
||||||
case
|
|
||||||
else
|
|
||||||
enum
|
|
||||||
void
|
|
||||||
with
|
|
||||||
class
|
|
||||||
const
|
|
||||||
yield
|
|
||||||
delete
|
|
||||||
export
|
|
||||||
import
|
|
||||||
public
|
|
||||||
static
|
|
||||||
typeof
|
|
||||||
extends
|
|
||||||
package
|
|
||||||
private
|
|
||||||
continue
|
|
||||||
function
|
|
||||||
protected
|
|
||||||
implements
|
|
||||||
instanceof
|
|
||||||
@ -1,47 +0,0 @@
|
|||||||
do
|
|
||||||
if
|
|
||||||
in
|
|
||||||
for
|
|
||||||
let
|
|
||||||
new
|
|
||||||
try
|
|
||||||
var
|
|
||||||
case
|
|
||||||
else
|
|
||||||
enum
|
|
||||||
eval
|
|
||||||
null
|
|
||||||
this
|
|
||||||
true
|
|
||||||
void
|
|
||||||
with
|
|
||||||
break
|
|
||||||
catch
|
|
||||||
class
|
|
||||||
const
|
|
||||||
false
|
|
||||||
super
|
|
||||||
throw
|
|
||||||
while
|
|
||||||
yield
|
|
||||||
delete
|
|
||||||
export
|
|
||||||
import
|
|
||||||
public
|
|
||||||
return
|
|
||||||
static
|
|
||||||
switch
|
|
||||||
typeof
|
|
||||||
default
|
|
||||||
extends
|
|
||||||
finally
|
|
||||||
package
|
|
||||||
private
|
|
||||||
continue
|
|
||||||
debugger
|
|
||||||
function
|
|
||||||
arguments
|
|
||||||
interface
|
|
||||||
protected
|
|
||||||
implements
|
|
||||||
instanceof
|
|
||||||
@ -1,45 +0,0 @@
|
|||||||
+
|
|
||||||
-
|
|
||||||
*
|
|
||||||
/
|
|
||||||
%
|
|
||||||
=
|
|
||||||
+=
|
|
||||||
-=
|
|
||||||
*=
|
|
||||||
/=
|
|
||||||
%=
|
|
||||||
<<=
|
|
||||||
>>=
|
|
||||||
>>>=
|
|
||||||
&=
|
|
||||||
^=
|
|
||||||
|=
|
|
||||||
&
|
|
||||||
|
|
|
||||||
^
|
|
||||||
~
|
|
||||||
<<
|
|
||||||
>>
|
|
||||||
>>>
|
|
||||||
==
|
|
||||||
===
|
|
||||||
!=
|
|
||||||
!==
|
|
||||||
>
|
|
||||||
<
|
|
||||||
>=
|
|
||||||
<=
|
|
||||||
&&
|
|
||||||
||
|
|
||||||
.
|
|
||||||
[
|
|
||||||
]
|
|
||||||
?
|
|
||||||
:
|
|
||||||
,
|
|
||||||
;
|
|
||||||
(
|
|
||||||
)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@ -1,43 +0,0 @@
|
|||||||
+
|
|
||||||
-
|
|
||||||
*
|
|
||||||
/
|
|
||||||
%
|
|
||||||
=
|
|
||||||
+=
|
|
||||||
-=
|
|
||||||
*=
|
|
||||||
/=
|
|
||||||
%=
|
|
||||||
<<=
|
|
||||||
>>=
|
|
||||||
>>>=
|
|
||||||
&=
|
|
||||||
^=
|
|
||||||
|=
|
|
||||||
&
|
|
||||||
|
|
|
||||||
^
|
|
||||||
~
|
|
||||||
<<
|
|
||||||
>>
|
|
||||||
>>>
|
|
||||||
==
|
|
||||||
===
|
|
||||||
!=
|
|
||||||
!==
|
|
||||||
>
|
|
||||||
<
|
|
||||||
>=
|
|
||||||
<=
|
|
||||||
&&
|
|
||||||
||
|
|
||||||
!
|
|
||||||
.
|
|
||||||
[
|
|
||||||
?
|
|
||||||
:
|
|
||||||
,
|
|
||||||
;
|
|
||||||
(
|
|
||||||
{
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
docs:
|
|
||||||
wget http://apigen.org/apigen.phar
|
|
||||||
chmod +x apigen.phar
|
|
||||||
php apigen.phar generate --source=src --destination=docs --template-theme=bootstrap
|
|
||||||
rm apigen.phar
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<phpunit colors="true" bootstrap="tests/bootstrap.php">
|
|
||||||
<testsuites>
|
|
||||||
<testsuite name="Minify test suite">
|
|
||||||
<directory suffix="Test.php">tests/css</directory>
|
|
||||||
<directory suffix="Test.php">tests/js</directory>
|
|
||||||
</testsuite>
|
|
||||||
</testsuites>
|
|
||||||
<logging>
|
|
||||||
<log type="coverage-clover" target="build/logs/clover.xml"/>
|
|
||||||
</logging>
|
|
||||||
</phpunit>
|
|
||||||
573
lib/src/CSS.php
573
lib/src/CSS.php
@ -1,573 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace MatthiasMullie\Minify;
|
|
||||||
|
|
||||||
//use MatthiasMullie\PathConverter\Converter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CSS minifier.
|
|
||||||
*
|
|
||||||
* Please report bugs on https://github.com/matthiasmullie/minify/issues
|
|
||||||
*
|
|
||||||
* @author Matthias Mullie <minify@mullie.eu>
|
|
||||||
* @author Tijs Verkoyen <minify@verkoyen.eu>
|
|
||||||
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved.
|
|
||||||
* @license MIT License
|
|
||||||
*/
|
|
||||||
class CSS extends Minify
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var int
|
|
||||||
*/
|
|
||||||
protected $maxImportSize = 5;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string[]
|
|
||||||
*/
|
|
||||||
protected $importExtensions = array(
|
|
||||||
'gif' => 'data:image/gif',
|
|
||||||
'png' => 'data:image/png',
|
|
||||||
'jpe' => 'data:image/jpeg',
|
|
||||||
'jpg' => 'data:image/jpeg',
|
|
||||||
'jpeg' => 'data:image/jpeg',
|
|
||||||
'svg' => 'data:image/svg+xml',
|
|
||||||
'woff' => 'data:application/x-font-woff',
|
|
||||||
'tif' => 'image/tiff',
|
|
||||||
'tiff' => 'image/tiff',
|
|
||||||
'xbm' => 'image/x-xbitmap',
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the maximum size if files to be imported.
|
|
||||||
*
|
|
||||||
* Files larger than this size (in kB) will not be imported into the CSS.
|
|
||||||
* Importing files into the CSS as data-uri will save you some connections,
|
|
||||||
* but we should only import relatively small decorative images so that our
|
|
||||||
* CSS file doesn't get too bulky.
|
|
||||||
*
|
|
||||||
* @param int $size Size in kB
|
|
||||||
*/
|
|
||||||
public function setMaxImportSize($size)
|
|
||||||
{
|
|
||||||
$this->maxImportSize = $size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the type of extensions to be imported into the CSS (to save network
|
|
||||||
* connections).
|
|
||||||
* Keys of the array should be the file extensions & respective values
|
|
||||||
* should be the data type.
|
|
||||||
*
|
|
||||||
* @param string[] $extensions Array of file extensions
|
|
||||||
*/
|
|
||||||
public function setImportExtensions(array $extensions)
|
|
||||||
{
|
|
||||||
$this->importExtensions = $extensions;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Move any import statements to the top.
|
|
||||||
*
|
|
||||||
* @param $content string Nearly finished CSS content
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
protected function moveImportsToTop($content)
|
|
||||||
{
|
|
||||||
if (preg_match_all('/@import[^;]+;/', $content, $matches)) {
|
|
||||||
|
|
||||||
// remove from content
|
|
||||||
foreach ($matches[0] as $import) {
|
|
||||||
$content = str_replace($import, '', $content);
|
|
||||||
}
|
|
||||||
|
|
||||||
// add to top
|
|
||||||
$content = implode('', $matches[0]).$content;
|
|
||||||
};
|
|
||||||
|
|
||||||
return $content;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Combine CSS from import statements.
|
|
||||||
*
|
|
||||||
* @import's will be loaded and their content merged into the original file,
|
|
||||||
* to save HTTP requests.
|
|
||||||
*
|
|
||||||
* @param string $source The file to combine imports for.
|
|
||||||
* @param string $content The CSS content to combine imports for.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
protected function combineImports($source, $content)
|
|
||||||
{
|
|
||||||
$importRegexes = array(
|
|
||||||
// @import url(xxx)
|
|
||||||
'/
|
|
||||||
# import statement
|
|
||||||
@import
|
|
||||||
|
|
||||||
# whitespace
|
|
||||||
\s+
|
|
||||||
|
|
||||||
# open url()
|
|
||||||
url\(
|
|
||||||
|
|
||||||
# (optional) open path enclosure
|
|
||||||
(?P<quotes>["\']?)
|
|
||||||
|
|
||||||
# fetch path
|
|
||||||
(?P<path>
|
|
||||||
|
|
||||||
# do not fetch data uris or external sources
|
|
||||||
(?!(
|
|
||||||
["\']?
|
|
||||||
(data|https?):
|
|
||||||
))
|
|
||||||
|
|
||||||
.+?
|
|
||||||
)
|
|
||||||
|
|
||||||
# (optional) close path enclosure
|
|
||||||
(?P=quotes)
|
|
||||||
|
|
||||||
# close url()
|
|
||||||
\)
|
|
||||||
|
|
||||||
# (optional) trailing whitespace
|
|
||||||
\s*
|
|
||||||
|
|
||||||
# (optional) media statement(s)
|
|
||||||
(?P<media>[^;]*)
|
|
||||||
|
|
||||||
# (optional) trailing whitespace
|
|
||||||
\s*
|
|
||||||
|
|
||||||
# (optional) closing semi-colon
|
|
||||||
;?
|
|
||||||
|
|
||||||
/ix',
|
|
||||||
|
|
||||||
// @import 'xxx'
|
|
||||||
'/
|
|
||||||
|
|
||||||
# import statement
|
|
||||||
@import
|
|
||||||
|
|
||||||
# whitespace
|
|
||||||
\s+
|
|
||||||
|
|
||||||
# open path enclosure
|
|
||||||
(?P<quotes>["\'])
|
|
||||||
|
|
||||||
# fetch path
|
|
||||||
(?P<path>
|
|
||||||
|
|
||||||
# do not fetch data uris or external sources
|
|
||||||
(?!(
|
|
||||||
["\']?
|
|
||||||
(data|https?):
|
|
||||||
))
|
|
||||||
|
|
||||||
.+?
|
|
||||||
)
|
|
||||||
|
|
||||||
# close path enclosure
|
|
||||||
(?P=quotes)
|
|
||||||
|
|
||||||
# (optional) trailing whitespace
|
|
||||||
\s*
|
|
||||||
|
|
||||||
# (optional) media statement(s)
|
|
||||||
(?P<media>[^;]*)
|
|
||||||
|
|
||||||
# (optional) trailing whitespace
|
|
||||||
\s*
|
|
||||||
|
|
||||||
# (optional) closing semi-colon
|
|
||||||
;?
|
|
||||||
|
|
||||||
/ix',
|
|
||||||
);
|
|
||||||
|
|
||||||
// find all relative imports in css
|
|
||||||
$matches = array();
|
|
||||||
foreach ($importRegexes as $importRegex) {
|
|
||||||
if (preg_match_all($importRegex, $content, $regexMatches, PREG_SET_ORDER)) {
|
|
||||||
$matches = array_merge($matches, $regexMatches);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$search = array();
|
|
||||||
$replace = array();
|
|
||||||
|
|
||||||
// loop the matches
|
|
||||||
foreach ($matches as $match) {
|
|
||||||
// get the path for the file that will be imported
|
|
||||||
$importPath = dirname($source).'/'.$match['path'];
|
|
||||||
|
|
||||||
// only replace the import with the content if we can grab the
|
|
||||||
// content of the file
|
|
||||||
if (strlen($importPath) < PHP_MAXPATHLEN && file_exists($importPath) && is_file($importPath)) {
|
|
||||||
// grab referenced file & minify it (which may include importing
|
|
||||||
// yet other @import statements recursively)
|
|
||||||
$minifier = new static($importPath);
|
|
||||||
$importContent = $minifier->execute($source);
|
|
||||||
|
|
||||||
// check if this is only valid for certain media
|
|
||||||
if ($match['media']) {
|
|
||||||
$importContent = '@media '.$match['media'].'{'.$importContent.'}';
|
|
||||||
}
|
|
||||||
|
|
||||||
// add to replacement array
|
|
||||||
$search[] = $match[0];
|
|
||||||
$replace[] = $importContent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// replace the import statements
|
|
||||||
$content = str_replace($search, $replace, $content);
|
|
||||||
|
|
||||||
return $content;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Import files into the CSS, base64-ized.
|
|
||||||
*
|
|
||||||
* @url(image.jpg) images will be loaded and their content merged into the
|
|
||||||
* original file, to save HTTP requests.
|
|
||||||
*
|
|
||||||
* @param string $source The file to import files for.
|
|
||||||
* @param string $content The CSS content to import files for.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
protected function importFiles($source, $content)
|
|
||||||
{
|
|
||||||
$extensions = array_keys($this->importExtensions);
|
|
||||||
$regex = '/url\((["\']?)((?!["\']?data:).*?\.('.implode('|', $extensions).'))\\1\)/i';
|
|
||||||
if ($extensions && preg_match_all($regex, $content, $matches, PREG_SET_ORDER)) {
|
|
||||||
$search = array();
|
|
||||||
$replace = array();
|
|
||||||
|
|
||||||
// loop the matches
|
|
||||||
foreach ($matches as $match) {
|
|
||||||
// get the path for the file that will be imported
|
|
||||||
$path = $match[2];
|
|
||||||
$path = dirname($source).'/'.$path;
|
|
||||||
$extension = $match[3];
|
|
||||||
|
|
||||||
// only replace the import with the content if we're able to get
|
|
||||||
// the content of the file, and it's relatively small
|
|
||||||
$import = strlen($path) < PHP_MAXPATHLEN;
|
|
||||||
$import = $import && file_exists($path);
|
|
||||||
$import = $import && is_file($path);
|
|
||||||
$import = $import && filesize($path) <= $this->maxImportSize * 1024;
|
|
||||||
if (!$import) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// grab content && base64-ize
|
|
||||||
$importContent = $this->load($path);
|
|
||||||
$importContent = base64_encode($importContent);
|
|
||||||
|
|
||||||
// build replacement
|
|
||||||
$search[] = $match[0];
|
|
||||||
$replace[] = 'url('.$this->importExtensions[$extension].';base64,'.$importContent.')';
|
|
||||||
}
|
|
||||||
|
|
||||||
// replace the import statements
|
|
||||||
$content = str_replace($search, $replace, $content);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $content;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Minify the data.
|
|
||||||
* Perform CSS optimizations.
|
|
||||||
*
|
|
||||||
* @param string[optional] $path Path to write the data to.
|
|
||||||
*
|
|
||||||
* @return string The minified data.
|
|
||||||
*/
|
|
||||||
public function execute($path = null)
|
|
||||||
{
|
|
||||||
$content = '';
|
|
||||||
|
|
||||||
// loop files
|
|
||||||
foreach ($this->data as $source => $css) {
|
|
||||||
/*
|
|
||||||
* Let's first take out strings & comments, since we can't just remove
|
|
||||||
* whitespace anywhere. If whitespace occurs inside a string, we should
|
|
||||||
* leave it alone. E.g.:
|
|
||||||
* p { content: "a test" }
|
|
||||||
*/
|
|
||||||
$this->extractStrings();
|
|
||||||
$this->stripComments();
|
|
||||||
$css = $this->replace($css);
|
|
||||||
|
|
||||||
$css = $this->stripWhitespace($css);
|
|
||||||
$css = $this->shortenHex($css);
|
|
||||||
$css = $this->shortenZeroes($css);
|
|
||||||
$css = $this->stripEmptyTags($css);
|
|
||||||
|
|
||||||
// restore the string we've extracted earlier
|
|
||||||
$css = $this->restoreExtractedData($css);
|
|
||||||
|
|
||||||
$source = $source ?: '';
|
|
||||||
$css = $this->combineImports($source, $css);
|
|
||||||
$css = $this->importFiles($source, $css);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If we'll save to a new path, we'll have to fix the relative paths
|
|
||||||
* to be relative no longer to the source file, but to the new path.
|
|
||||||
* If we don't write to a file, fall back to same path so no
|
|
||||||
* conversion happens (because we still want it to go through most
|
|
||||||
* of the move code...)
|
|
||||||
*/
|
|
||||||
//$converter = new Converter($source, $path ?: $source);
|
|
||||||
//$css = $this->move($converter, $css);
|
|
||||||
|
|
||||||
// combine css
|
|
||||||
$content .= $css;
|
|
||||||
}
|
|
||||||
|
|
||||||
$content = $this->moveImportsToTop($content);
|
|
||||||
|
|
||||||
return $content;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Moving a css file should update all relative urls.
|
|
||||||
* Relative references (e.g. ../images/image.gif) in a certain css file,
|
|
||||||
* will have to be updated when a file is being saved at another location
|
|
||||||
* (e.g. ../../images/image.gif, if the new CSS file is 1 folder deeper).
|
|
||||||
*
|
|
||||||
* @param Converter $converter Relative path converter
|
|
||||||
* @param string $content The CSS content to update relative urls for.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
protected function move(Converter $converter, $content)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Relative path references will usually be enclosed by url(). @import
|
|
||||||
* is an exception, where url() is not necessary around the path (but is
|
|
||||||
* allowed).
|
|
||||||
* This *could* be 1 regular expression, where both regular expressions
|
|
||||||
* in this array are on different sides of a |. But we're using named
|
|
||||||
* patterns in both regexes, the same name on both regexes. This is only
|
|
||||||
* possible with a (?J) modifier, but that only works after a fairly
|
|
||||||
* recent PCRE version. That's why I'm doing 2 separate regular
|
|
||||||
* expressions & combining the matches after executing of both.
|
|
||||||
*/
|
|
||||||
$relativeRegexes = array(
|
|
||||||
// url(xxx)
|
|
||||||
'/
|
|
||||||
# open url()
|
|
||||||
url\(
|
|
||||||
|
|
||||||
\s*
|
|
||||||
|
|
||||||
# open path enclosure
|
|
||||||
(?P<quotes>["\'])?
|
|
||||||
|
|
||||||
# fetch path
|
|
||||||
(?P<path>
|
|
||||||
|
|
||||||
# do not fetch data uris or external sources
|
|
||||||
(?!(
|
|
||||||
\s?
|
|
||||||
["\']?
|
|
||||||
(data|https?):
|
|
||||||
))
|
|
||||||
|
|
||||||
.+?
|
|
||||||
)
|
|
||||||
|
|
||||||
# close path enclosure
|
|
||||||
(?(quotes)(?P=quotes))
|
|
||||||
|
|
||||||
\s*
|
|
||||||
|
|
||||||
# close url()
|
|
||||||
\)
|
|
||||||
|
|
||||||
/ix',
|
|
||||||
|
|
||||||
// @import "xxx"
|
|
||||||
'/
|
|
||||||
# import statement
|
|
||||||
@import
|
|
||||||
|
|
||||||
# whitespace
|
|
||||||
\s+
|
|
||||||
|
|
||||||
# we don\'t have to check for @import url(), because the
|
|
||||||
# condition above will already catch these
|
|
||||||
|
|
||||||
# open path enclosure
|
|
||||||
(?P<quotes>["\'])
|
|
||||||
|
|
||||||
# fetch path
|
|
||||||
(?P<path>
|
|
||||||
|
|
||||||
# do not fetch data uris or external sources
|
|
||||||
(?!(
|
|
||||||
["\']?
|
|
||||||
(data|https?):
|
|
||||||
))
|
|
||||||
|
|
||||||
.+?
|
|
||||||
)
|
|
||||||
|
|
||||||
# close path enclosure
|
|
||||||
(?P=quotes)
|
|
||||||
|
|
||||||
/ix',
|
|
||||||
);
|
|
||||||
|
|
||||||
// find all relative urls in css
|
|
||||||
$matches = array();
|
|
||||||
foreach ($relativeRegexes as $relativeRegex) {
|
|
||||||
if (preg_match_all($relativeRegex, $content, $regexMatches, PREG_SET_ORDER)) {
|
|
||||||
$matches = array_merge($matches, $regexMatches);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$search = array();
|
|
||||||
$replace = array();
|
|
||||||
|
|
||||||
// loop all urls
|
|
||||||
foreach ($matches as $match) {
|
|
||||||
// determine if it's a url() or an @import match
|
|
||||||
$type = (strpos($match[0], '@import') === 0 ? 'import' : 'url');
|
|
||||||
|
|
||||||
// fix relative url
|
|
||||||
$url = $converter->convert($match['path']);
|
|
||||||
|
|
||||||
// build replacement
|
|
||||||
$search[] = $match[0];
|
|
||||||
if ($type == 'url') {
|
|
||||||
$replace[] = 'url('.$url.')';
|
|
||||||
} elseif ($type == 'import') {
|
|
||||||
$replace[] = '@import "'.$url.'"';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// replace urls
|
|
||||||
$content = str_replace($search, $replace, $content);
|
|
||||||
|
|
||||||
return $content;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shorthand hex color codes.
|
|
||||||
* #FF0000 -> #F00.
|
|
||||||
*
|
|
||||||
* @param string $content The CSS content to shorten the hex color codes for.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
protected function shortenHex($content)
|
|
||||||
{
|
|
||||||
$content = preg_replace('/(?<![\'"])#([0-9a-z])\\1([0-9a-z])\\2([0-9a-z])\\3(?![\'"])/i', '#$1$2$3', $content);
|
|
||||||
|
|
||||||
return $content;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shorthand 0 values to plain 0, instead of e.g. -0em.
|
|
||||||
*
|
|
||||||
* @param string $content The CSS content to shorten the zero values for.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
protected function shortenZeroes($content)
|
|
||||||
{
|
|
||||||
// reusable bits of code throughout these regexes:
|
|
||||||
// before & after are used to make sure we don't match lose unintended
|
|
||||||
// 0-like values (e.g. in #000, or in http://url/1.0)
|
|
||||||
// units can be stripped from 0 values, or used to recognize non 0
|
|
||||||
// values (where wa may be able to strip a .0 suffix)
|
|
||||||
$before = '(?<=[:(, ])';
|
|
||||||
$after = '(?=[ ,);}])';
|
|
||||||
$units = '(em|ex|%|px|cm|mm|in|pt|pc|ch|rem|vh|vw|vmin|vmax|vm)';
|
|
||||||
|
|
||||||
// strip units after zeroes (0px -> 0)
|
|
||||||
// NOTE: it should be safe to remove all units for a 0 value, but in
|
|
||||||
// practice, Webkit (especially Safari) seems to stumble over at least
|
|
||||||
// 0%, potentially other units as well. Only stripping 'px' for now.
|
|
||||||
// @see https://github.com/matthiasmullie/minify/issues/60
|
|
||||||
$content = preg_replace('/'.$before.'(-?0*(\.0+)?)(?<=0)px'.$after.'/', '\\1', $content);
|
|
||||||
|
|
||||||
// strip 0-digits (.0 -> 0)
|
|
||||||
$content = preg_replace('/'.$before.'\.0+'.$units.'?'.$after.'/', '0\\1', $content);
|
|
||||||
// strip trailing 0: 50.10 -> 50.1, 50.10px -> 50.1px
|
|
||||||
$content = preg_replace('/'.$before.'(-?[0-9]+\.[0-9]+)0+'.$units.'?'.$after.'/', '\\1\\2', $content);
|
|
||||||
// strip trailing 0: 50.00 -> 50, 50.00px -> 50px
|
|
||||||
$content = preg_replace('/'.$before.'(-?[0-9]+)\.0+'.$units.'?'.$after.'/', '\\1\\2', $content);
|
|
||||||
// strip leading 0: 0.1 -> .1, 01.1 -> 1.1
|
|
||||||
$content = preg_replace('/'.$before.'(-?)0+([0-9]*\.[0-9]+)'.$units.'?'.$after.'/', '\\1\\2\\3', $content);
|
|
||||||
|
|
||||||
// strip negative zeroes (-0 -> 0) & truncate zeroes (00 -> 0)
|
|
||||||
$content = preg_replace('/'.$before.'-?0+'.$units.'?'.$after.'/', '0\\1', $content);
|
|
||||||
|
|
||||||
return $content;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Strip comments from source code.
|
|
||||||
*
|
|
||||||
* @param string $content
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
protected function stripEmptyTags($content)
|
|
||||||
{
|
|
||||||
return preg_replace('/(^|\})[^\{\}]+\{\s*\}/', '\\1', $content);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Strip comments from source code.
|
|
||||||
*/
|
|
||||||
protected function stripComments()
|
|
||||||
{
|
|
||||||
$this->registerPattern('/\/\*.*?\*\//s', '');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Strip whitespace.
|
|
||||||
*
|
|
||||||
* @param string $content The CSS content to strip the whitespace for.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
protected function stripWhitespace($content)
|
|
||||||
{
|
|
||||||
// remove leading & trailing whitespace
|
|
||||||
$content = preg_replace('/^\s*/m', '', $content);
|
|
||||||
$content = preg_replace('/\s*$/m', '', $content);
|
|
||||||
|
|
||||||
// replace newlines with a single space
|
|
||||||
$content = preg_replace('/\s+/', ' ', $content);
|
|
||||||
|
|
||||||
// remove whitespace around meta characters
|
|
||||||
// inspired by stackoverflow.com/questions/15195750/minify-compress-css-with-regex
|
|
||||||
$content = preg_replace('/\s*([\*$~^|]?+=|[{};,>~]|!important\b)\s*/', '$1', $content);
|
|
||||||
$content = preg_replace('/([\[(:])\s+/', '$1', $content);
|
|
||||||
$content = preg_replace('/\s+([\]\)])/', '$1', $content);
|
|
||||||
$content = preg_replace('/\s+(:)(?![^\}]*\{)/', '$1', $content);
|
|
||||||
|
|
||||||
// whitespace around + and - can only be stripped in selectors, like
|
|
||||||
// :nth-child(3+2n), not in things like calc(3px + 2px) or shorthands
|
|
||||||
// like 3px -2px
|
|
||||||
$content = preg_replace('/\s*([+-])\s*(?=[^}]*{)/', '$1', $content);
|
|
||||||
|
|
||||||
// remove semicolon/whitespace followed by closing bracket
|
|
||||||
$content = str_replace(';}', '}', $content);
|
|
||||||
|
|
||||||
return trim($content);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace MatthiasMullie\Minify;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Matthias Mullie <minify@mullie.eu>
|
|
||||||
*/
|
|
||||||
class Exception extends \Exception
|
|
||||||
{
|
|
||||||
}
|
|
||||||
490
lib/src/JS.php
490
lib/src/JS.php
File diff suppressed because one or more lines are too long
@ -1,382 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace MatthiasMullie\Minify;
|
|
||||||
|
|
||||||
use Psr\Cache\CacheItemInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abstract minifier class.
|
|
||||||
*
|
|
||||||
* Please report bugs on https://github.com/matthiasmullie/minify/issues
|
|
||||||
*
|
|
||||||
* @author Matthias Mullie <minify@mullie.eu>
|
|
||||||
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved.
|
|
||||||
* @license MIT License
|
|
||||||
*/
|
|
||||||
abstract class Minify
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* The data to be minified.
|
|
||||||
*
|
|
||||||
* @var string[]
|
|
||||||
*/
|
|
||||||
protected $data = array();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Array of patterns to match.
|
|
||||||
*
|
|
||||||
* @var string[]
|
|
||||||
*/
|
|
||||||
protected $patterns = array();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This array will hold content of strings and regular expressions that have
|
|
||||||
* been extracted from the JS source code, so we can reliably match "code",
|
|
||||||
* without having to worry about potential "code-like" characters inside.
|
|
||||||
*
|
|
||||||
* @var string[]
|
|
||||||
*/
|
|
||||||
public $extracted = array();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Init the minify class - optionally, code may be passed along already.
|
|
||||||
*/
|
|
||||||
public function __construct(/* $data = null, ... */)
|
|
||||||
{
|
|
||||||
// it's possible to add the source through the constructor as well ;)
|
|
||||||
if (func_num_args()) {
|
|
||||||
call_user_func_array(array($this, 'add'), func_get_args());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a file or straight-up code to be minified.
|
|
||||||
*
|
|
||||||
* @param string $data
|
|
||||||
*/
|
|
||||||
public function add($data /* $data = null, ... */)
|
|
||||||
{
|
|
||||||
// bogus "usage" of parameter $data: scrutinizer warns this variable is
|
|
||||||
// not used (we're using func_get_args instead to support overloading),
|
|
||||||
// but it still needs to be defined because it makes no sense to have
|
|
||||||
// this function without argument :)
|
|
||||||
$args = array($data) + func_get_args();
|
|
||||||
|
|
||||||
// this method can be overloaded
|
|
||||||
foreach ($args as $data) {
|
|
||||||
// redefine var
|
|
||||||
$data = (string) $data;
|
|
||||||
|
|
||||||
// load data
|
|
||||||
$value = $this->load($data);
|
|
||||||
$key = ($data != $value) ? $data : count($this->data);
|
|
||||||
|
|
||||||
// store data
|
|
||||||
$this->data[$key] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load data.
|
|
||||||
*
|
|
||||||
* @param string $data Either a path to a file or the content itself.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
protected function load($data)
|
|
||||||
{
|
|
||||||
// check if the data is a file
|
|
||||||
if (strlen($data) < PHP_MAXPATHLEN && file_exists($data) && is_file($data)) {
|
|
||||||
$data = file_get_contents($data);
|
|
||||||
|
|
||||||
// strip BOM, if any
|
|
||||||
if (substr($data, 0, 3) == "\xef\xbb\xbf") {
|
|
||||||
$data = substr($data, 3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Save to file.
|
|
||||||
*
|
|
||||||
* @param string $content The minified data.
|
|
||||||
* @param string $path The path to save the minified data to.
|
|
||||||
*
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
protected function save($content, $path)
|
|
||||||
{
|
|
||||||
// create file & open for writing
|
|
||||||
if (($handler = @fopen($path, 'w')) === false) {
|
|
||||||
throw new Exception('The file "'.$path.'" could not be opened. Check if PHP has enough permissions.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// write to file
|
|
||||||
if (@fwrite($handler, $content) === false) {
|
|
||||||
throw new Exception('The file "'.$path.'" could not be written to. Check if PHP has enough permissions.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// close the file
|
|
||||||
@fclose($handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Minify the data & (optionally) saves it to a file.
|
|
||||||
*
|
|
||||||
* @param string[optional] $path Path to write the data to.
|
|
||||||
*
|
|
||||||
* @return string The minified data.
|
|
||||||
*/
|
|
||||||
public function minify($path = null)
|
|
||||||
{
|
|
||||||
$content = $this->execute($path);
|
|
||||||
|
|
||||||
// save to path
|
|
||||||
if ($path !== null) {
|
|
||||||
$this->save($content, $path);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $content;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Minify & gzip the data & (optionally) saves it to a file.
|
|
||||||
*
|
|
||||||
* @param string[optional] $path Path to write the data to.
|
|
||||||
* @param int[optional] $level Compression level, from 0 to 9.
|
|
||||||
*
|
|
||||||
* @return string The minified & gzipped data.
|
|
||||||
*/
|
|
||||||
public function gzip($path = null, $level = 9)
|
|
||||||
{
|
|
||||||
$content = $this->execute($path);
|
|
||||||
$content = gzencode($content, $level, FORCE_GZIP);
|
|
||||||
|
|
||||||
// save to path
|
|
||||||
if ($path !== null) {
|
|
||||||
$this->save($content, $path);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $content;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Minify the data & write it to a CacheItemInterface object.
|
|
||||||
*
|
|
||||||
* @param CacheItemInterface $item Cache item to write the data to.
|
|
||||||
*
|
|
||||||
* @return CacheItemInterface Cache item with the minifier data.
|
|
||||||
*/
|
|
||||||
public function cache(CacheItemInterface $item)
|
|
||||||
{
|
|
||||||
$content = $this->execute();
|
|
||||||
$item->set($content);
|
|
||||||
|
|
||||||
return $item;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Minify the data.
|
|
||||||
*
|
|
||||||
* @param string[optional] $path Path to write the data to.
|
|
||||||
*
|
|
||||||
* @return string The minified data.
|
|
||||||
*/
|
|
||||||
abstract public function execute($path = null);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a pattern to execute against the source content.
|
|
||||||
*
|
|
||||||
* @param string $pattern PCRE pattern.
|
|
||||||
* @param string|callable $replacement Replacement value for matched pattern.
|
|
||||||
*
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
protected function registerPattern($pattern, $replacement = '')
|
|
||||||
{
|
|
||||||
// study the pattern, we'll execute it more than once
|
|
||||||
$pattern .= 'S';
|
|
||||||
|
|
||||||
$this->patterns[] = array($pattern, $replacement);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* We can't "just" run some regular expressions against JavaScript: it's a
|
|
||||||
* complex language. E.g. having an occurrence of // xyz would be a comment,
|
|
||||||
* unless it's used within a string. Of you could have something that looks
|
|
||||||
* like a 'string', but inside a comment.
|
|
||||||
* The only way to accurately replace these pieces is to traverse the JS one
|
|
||||||
* character at a time and try to find whatever starts first.
|
|
||||||
*
|
|
||||||
* @param string $content The content to replace patterns in.
|
|
||||||
*
|
|
||||||
* @return string The (manipulated) content.
|
|
||||||
*/
|
|
||||||
protected function replace($content)
|
|
||||||
{
|
|
||||||
$processed = '';
|
|
||||||
$positions = array_fill(0, count($this->patterns), -1);
|
|
||||||
$matches = array();
|
|
||||||
|
|
||||||
while ($content) {
|
|
||||||
// find first match for all patterns
|
|
||||||
foreach ($this->patterns as $i => $pattern) {
|
|
||||||
list($pattern, $replacement) = $pattern;
|
|
||||||
|
|
||||||
// no need to re-run matches that are still in the part of the
|
|
||||||
// content that hasn't been processed
|
|
||||||
if ($positions[$i] >= 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$match = null;
|
|
||||||
if (preg_match($pattern, $content, $match)) {
|
|
||||||
$matches[$i] = $match;
|
|
||||||
|
|
||||||
// we'll store the match position as well; that way, we
|
|
||||||
// don't have to redo all preg_matches after changing only
|
|
||||||
// the first (we'll still know where those others are)
|
|
||||||
$positions[$i] = strpos($content, $match[0]);
|
|
||||||
} else {
|
|
||||||
// if the pattern couldn't be matched, there's no point in
|
|
||||||
// executing it again in later runs on this same content;
|
|
||||||
// ignore this one until we reach end of content
|
|
||||||
unset($matches[$i]);
|
|
||||||
$positions[$i] = strlen($content);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// no more matches to find: everything's been processed, break out
|
|
||||||
if (!$matches) {
|
|
||||||
$processed .= $content;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// see which of the patterns actually found the first thing (we'll
|
|
||||||
// only want to execute that one, since we're unsure if what the
|
|
||||||
// other found was not inside what the first found)
|
|
||||||
$discardLength = min($positions);
|
|
||||||
$firstPattern = array_search($discardLength, $positions);
|
|
||||||
$match = $matches[$firstPattern][0];
|
|
||||||
|
|
||||||
// execute the pattern that matches earliest in the content string
|
|
||||||
list($pattern, $replacement) = $this->patterns[$firstPattern];
|
|
||||||
$replacement = $this->replacePattern($pattern, $replacement, $content);
|
|
||||||
|
|
||||||
// figure out which part of the string was unmatched; that's the
|
|
||||||
// part we'll execute the patterns on again next
|
|
||||||
$content = substr($content, $discardLength);
|
|
||||||
$unmatched = (string) substr($content, strpos($content, $match) + strlen($match));
|
|
||||||
|
|
||||||
// move the replaced part to $processed and prepare $content to
|
|
||||||
// again match batch of patterns against
|
|
||||||
$processed .= substr($replacement, 0, strlen($replacement) - strlen($unmatched));
|
|
||||||
$content = $unmatched;
|
|
||||||
|
|
||||||
// first match has been replaced & that content is to be left alone,
|
|
||||||
// the next matches will start after this replacement, so we should
|
|
||||||
// fix their offsets
|
|
||||||
foreach ($positions as $i => $position) {
|
|
||||||
$positions[$i] -= $discardLength + strlen($match);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $processed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is where a pattern is matched against $content and the matches
|
|
||||||
* are replaced by their respective value.
|
|
||||||
* This function will be called plenty of times, where $content will always
|
|
||||||
* move up 1 character.
|
|
||||||
*
|
|
||||||
* @param string $pattern Pattern to match.
|
|
||||||
* @param string|callable $replacement Replacement value.
|
|
||||||
* @param string $content Content to match pattern against.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
protected function replacePattern($pattern, $replacement, $content)
|
|
||||||
{
|
|
||||||
if (is_callable($replacement)) {
|
|
||||||
return preg_replace_callback($pattern, $replacement, $content, 1, $count);
|
|
||||||
} else {
|
|
||||||
return preg_replace($pattern, $replacement, $content, 1, $count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Strings are a pattern we need to match, in order to ignore potential
|
|
||||||
* code-like content inside them, but we just want all of the string
|
|
||||||
* content to remain untouched.
|
|
||||||
*
|
|
||||||
* This method will replace all string content with simple STRING#
|
|
||||||
* placeholder text, so we've rid all strings from characters that may be
|
|
||||||
* misinterpreted. Original string content will be saved in $this->extracted
|
|
||||||
* and after doing all other minifying, we can restore the original content
|
|
||||||
* via restoreStrings()
|
|
||||||
*
|
|
||||||
* @param string[optional] $chars
|
|
||||||
*/
|
|
||||||
protected function extractStrings($chars = '\'"')
|
|
||||||
{
|
|
||||||
// PHP only supports $this inside anonymous functions since 5.4
|
|
||||||
$minifier = $this;
|
|
||||||
$callback = function ($match) use ($minifier) {
|
|
||||||
if (!$match[1]) {
|
|
||||||
/*
|
|
||||||
* Empty strings need no placeholder; they can't be confused for
|
|
||||||
* anything else anyway.
|
|
||||||
* But we still needed to match them, for the extraction routine
|
|
||||||
* to skip over this particular string.
|
|
||||||
*/
|
|
||||||
return $match[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
$count = count($minifier->extracted);
|
|
||||||
$placeholder = $match[1].$count.$match[1];
|
|
||||||
$minifier->extracted[$placeholder] = $match[1].$match[2].$match[1];
|
|
||||||
|
|
||||||
return $placeholder;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The \\ messiness explained:
|
|
||||||
* * Don't count ' or " as end-of-string if it's escaped (has backslash
|
|
||||||
* in front of it)
|
|
||||||
* * Unless... that backslash itself is escaped (another leading slash),
|
|
||||||
* in which case it's no longer escaping the ' or "
|
|
||||||
* * So there can be either no backslash, or an even number
|
|
||||||
* * multiply all of that times 4, to account for the escaping that has
|
|
||||||
* to be done to pass the backslash into the PHP string without it being
|
|
||||||
* considered as escape-char (times 2) and to get it in the regex,
|
|
||||||
* escaped (times 2)
|
|
||||||
*/
|
|
||||||
$this->registerPattern('/(['.$chars.'])(.*?(?<!\\\\)(\\\\\\\\)*+)\\1/s', $callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method will restore all extracted data (strings, regexes) that were
|
|
||||||
* replaced with placeholder text in extract*(). The original content was
|
|
||||||
* saved in $this->extracted.
|
|
||||||
*
|
|
||||||
* @param string $content
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
protected function restoreExtractedData($content)
|
|
||||||
{
|
|
||||||
if (!$this->extracted) {
|
|
||||||
// nothing was extracted, nothing to restore
|
|
||||||
return $content;
|
|
||||||
}
|
|
||||||
|
|
||||||
$content = strtr($content, $this->extracted);
|
|
||||||
|
|
||||||
$this->extracted = array();
|
|
||||||
|
|
||||||
return $content;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
require __DIR__.'/../vendor/autoload.php';
|
|
||||||
@ -1,594 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
use MatthiasMullie\Minify;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CSS minifier test case.
|
|
||||||
*/
|
|
||||||
class CSSTest extends PHPUnit_Framework_TestCase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var Minify\CSS
|
|
||||||
*/
|
|
||||||
private $minifier;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prepares the environment before running a test.
|
|
||||||
*/
|
|
||||||
protected function setUp()
|
|
||||||
{
|
|
||||||
parent::setUp();
|
|
||||||
|
|
||||||
// override save method, there's no point in writing the result out here
|
|
||||||
$this->minifier = $this->getMockBuilder('\MatthiasMullie\Minify\CSS')
|
|
||||||
->setMethods(array('save'))
|
|
||||||
->getMock();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cleans up the environment after running a test.
|
|
||||||
*/
|
|
||||||
protected function tearDown()
|
|
||||||
{
|
|
||||||
$this->minifier = null;
|
|
||||||
parent::tearDown();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test CSS minifier rules, provided by dataProvider.
|
|
||||||
*
|
|
||||||
* @test
|
|
||||||
* @dataProvider dataProvider
|
|
||||||
*/
|
|
||||||
public function minify($input, $expected)
|
|
||||||
{
|
|
||||||
$input = (array) $input;
|
|
||||||
foreach ($input as $css) {
|
|
||||||
$this->minifier->add($css);
|
|
||||||
}
|
|
||||||
$result = $this->minifier->minify();
|
|
||||||
|
|
||||||
$this->assertEquals($expected, $result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test conversion of relative paths, provided by dataProviderPaths.
|
|
||||||
*
|
|
||||||
* @test
|
|
||||||
* @dataProvider dataProviderPaths
|
|
||||||
*/
|
|
||||||
public function convertRelativePath($source, $target, $expected)
|
|
||||||
{
|
|
||||||
$source = (array) $source;
|
|
||||||
foreach ($source as $path => $css) {
|
|
||||||
$this->minifier->add($css);
|
|
||||||
|
|
||||||
// $source also accepts an array where the key is a bogus path
|
|
||||||
if (is_string($path)) {
|
|
||||||
$object = new ReflectionObject($this->minifier);
|
|
||||||
$property = $object->getProperty('data');
|
|
||||||
$property->setAccessible(true);
|
|
||||||
$data = $property->getValue($this->minifier);
|
|
||||||
|
|
||||||
// keep content, but make it appear from the given path
|
|
||||||
$data[$path] = array_pop($data);
|
|
||||||
$property->setValue($this->minifier, $data);
|
|
||||||
$property->setAccessible(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$result = $this->minifier->minify($target);
|
|
||||||
|
|
||||||
$this->assertEquals($expected, $result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test minifier import configuration methods.
|
|
||||||
*
|
|
||||||
* @test
|
|
||||||
*/
|
|
||||||
public function setConfig()
|
|
||||||
{
|
|
||||||
$this->minifier->setMaxImportSize(10);
|
|
||||||
$this->minifier->setImportExtensions(array('gif' => 'data:image/gif'));
|
|
||||||
|
|
||||||
$object = new ReflectionObject($this->minifier);
|
|
||||||
|
|
||||||
$property = $object->getProperty('maxImportSize');
|
|
||||||
$property->setAccessible(true);
|
|
||||||
$this->assertEquals($property->getValue($this->minifier), 10);
|
|
||||||
|
|
||||||
$property = $object->getProperty('importExtensions');
|
|
||||||
$property->setAccessible(true);
|
|
||||||
$this->assertEquals($property->getValue($this->minifier), array('gif' => 'data:image/gif'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array [input, expected result]
|
|
||||||
*/
|
|
||||||
public function dataProvider()
|
|
||||||
{
|
|
||||||
$tests = array();
|
|
||||||
|
|
||||||
// try importing, with both @import syntax types & media queries
|
|
||||||
$tests[] = array(
|
|
||||||
__DIR__.'/sample/combine_imports/index.css',
|
|
||||||
'body{color:red}',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
__DIR__.'/sample/combine_imports/index2.css',
|
|
||||||
'body{color:red}',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
__DIR__.'/sample/combine_imports/index3.css',
|
|
||||||
'body{color:red}body{color:red}',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
__DIR__.'/sample/combine_imports/index4.css',
|
|
||||||
'@media only screen{body{color:red}}@media only screen{body{color:red}}',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
__DIR__.'/sample/combine_imports/index5.css',
|
|
||||||
'body{color:red}body{color:red}',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
__DIR__.'/sample/combine_imports/index6a.css',
|
|
||||||
'body{color:red}',
|
|
||||||
);
|
|
||||||
|
|
||||||
// shorthand hex color codes
|
|
||||||
$tests[] = array(
|
|
||||||
'color:#FF00FF;',
|
|
||||||
'color:#F0F;',
|
|
||||||
);
|
|
||||||
|
|
||||||
// import files
|
|
||||||
$tests[] = array(
|
|
||||||
__DIR__.'/sample/import_files/index.css',
|
|
||||||
'body{background:url(data:image/png;base64,'.base64_encode(file_get_contents(__DIR__.'/sample/import_files/file.png')).')}',
|
|
||||||
);
|
|
||||||
|
|
||||||
// strip comments
|
|
||||||
$tests[] = array(
|
|
||||||
'/* This is a CSS comment */',
|
|
||||||
'',
|
|
||||||
);
|
|
||||||
|
|
||||||
// strip whitespace
|
|
||||||
$tests[] = array(
|
|
||||||
'body { color: red; }',
|
|
||||||
'body{color:red}',
|
|
||||||
);
|
|
||||||
|
|
||||||
// whitespace inside strings shouldn't be replaced
|
|
||||||
$tests[] = array(
|
|
||||||
'content:"preserve whitespace"',
|
|
||||||
'content:"preserve whitespace"',
|
|
||||||
);
|
|
||||||
|
|
||||||
$tests[] = array(
|
|
||||||
'html
|
|
||||||
body {
|
|
||||||
color: red;
|
|
||||||
}',
|
|
||||||
'html body{color:red}',
|
|
||||||
);
|
|
||||||
|
|
||||||
$tests[] = array(
|
|
||||||
<<<'JS'
|
|
||||||
p * i , html
|
|
||||||
/* remove spaces */
|
|
||||||
|
|
||||||
/* " comments have no escapes \*/
|
|
||||||
body/* keep */ /* space */p,
|
|
||||||
p [ remove ~= " spaces " ] :nth-child( 3 + 2n ) > b span i , div::after
|
|
||||||
|
|
||||||
{
|
|
||||||
/* comment */
|
|
||||||
content : " escapes \" allowed \\" ;
|
|
||||||
content: " /* string */ " !important ;
|
|
||||||
width: calc( 100% - 3em + 5px ) ;
|
|
||||||
margin-top : 0;
|
|
||||||
margin-bottom : 0;
|
|
||||||
margin-left : 10px;
|
|
||||||
margin-right : 10px;
|
|
||||||
}
|
|
||||||
JS
|
|
||||||
,
|
|
||||||
'p * i,html body p,p [remove~=" spaces "] :nth-child(3+2n)>b span i,div::after{content:" escapes \\" allowed \\\\";content:" /* string */ "!important;width:calc(100% - 3em + 5px);margin-top:0;margin-bottom:0;margin-left:10px;margin-right:10px}',
|
|
||||||
);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* https://github.com/forkcms/forkcms/issues/387
|
|
||||||
*
|
|
||||||
* CSS backslash.
|
|
||||||
* * Backslash escaped by backslash in CSS
|
|
||||||
* * Double CSS backslashed escaped twice for in PHP string
|
|
||||||
*/
|
|
||||||
$tests[] = array(
|
|
||||||
'.iconic.map-pin:before { content: "\\\\"; }',
|
|
||||||
'.iconic.map-pin:before{content:"\\\\"}',
|
|
||||||
);
|
|
||||||
|
|
||||||
// strip BOM
|
|
||||||
$tests[] = array(
|
|
||||||
__DIR__.'/sample/bom/bom.css',
|
|
||||||
'body{color:red}',
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/matthiasmullie/minify/issues/22
|
|
||||||
$tests[] = array(
|
|
||||||
'p { background-position: -0px -64px; }',
|
|
||||||
'p{background-position:0 -64px}',
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/matthiasmullie/minify/issues/23
|
|
||||||
$tests[] = array(
|
|
||||||
'ul.pagination {
|
|
||||||
display: block;
|
|
||||||
min-height: 1.5rem;
|
|
||||||
margin-left: -0.3125rem;
|
|
||||||
}',
|
|
||||||
'ul.pagination{display:block;min-height:1.5rem;margin-left:-.3125rem}',
|
|
||||||
);
|
|
||||||
|
|
||||||
// edge cases for stripping zeroes
|
|
||||||
$tests[] = array(
|
|
||||||
'p { margin: -0.0rem; }',
|
|
||||||
'p{margin:0rem}',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'p { margin: -0.01rem; }',
|
|
||||||
'p{margin:-.01rem}',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'p { margin: .0; }',
|
|
||||||
'p{margin:0}',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'p { margin: .0%; }',
|
|
||||||
'p{margin:0%}',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'p { margin: 1.0; }',
|
|
||||||
'p{margin:1}',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'p { margin: 1.0px; }',
|
|
||||||
'p{margin:1px}',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'p { margin: 1.1; }',
|
|
||||||
'p{margin:1.1}',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'p { margin: 1.1em; }',
|
|
||||||
'p{margin:1.1em}',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'p { margin: 00px; }',
|
|
||||||
'p{margin:0}',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'p { margin: 0.1px; }',
|
|
||||||
'p{margin:.1px}',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'p { margin: 01.1px; }',
|
|
||||||
'p{margin:1.1px}',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'p { margin: 0.060px; }',
|
|
||||||
'p{margin:.06px}',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'p.class00 { background-color: #000000; color: #000; }',
|
|
||||||
'p.class00{background-color:#000;color:#000}',
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/matthiasmullie/minify/issues/24
|
|
||||||
$tests[] = array(
|
|
||||||
'.col-1-1 { width: 100.00%; }',
|
|
||||||
'.col-1-1{width:100%}',
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/matthiasmullie/minify/issues/25
|
|
||||||
$tests[] = array(
|
|
||||||
'p { background-color: #000000; color: #000; }',
|
|
||||||
'p{background-color:#000;color:#000}',
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/matthiasmullie/minify/issues/26
|
|
||||||
$tests[] = array(
|
|
||||||
'.hr > :first-child { width: 0.0001%; }',
|
|
||||||
'.hr>:first-child{width:.0001%}',
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/matthiasmullie/minify/issues/28
|
|
||||||
$tests[] = array(
|
|
||||||
'@font-face { src: url(//netdna.bootstrapcdn.com/font-awesome/4.2.0/fonts/fontawesome-webfont.eot?v=4.2.0); }',
|
|
||||||
'@font-face{src:url(//netdna.bootstrapcdn.com/font-awesome/4.2.0/fonts/fontawesome-webfont.eot?v=4.2.0)}',
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/matthiasmullie/minify/issues/31
|
|
||||||
$tests[] = array(
|
|
||||||
'dfn,em,img{color:red}',
|
|
||||||
'dfn,em,img{color:red}',
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/matthiasmullie/minify/issues/49
|
|
||||||
$tests[] = array(
|
|
||||||
__DIR__.'/sample/import_files/issue49.css',
|
|
||||||
'.social-btn a[href*="facebook"]{background-image:url(data:image/png;base64,'.base64_encode(file_get_contents(__DIR__.'/sample/import_files/facebook.png')).')}'.
|
|
||||||
'.social-btn a[href*="vimeo"]{background-image:url(data:image/png;base64,'.base64_encode(file_get_contents(__DIR__.'/sample/import_files/vimeo.png')).')}'.
|
|
||||||
'.social-btn a[href*="instagram"]{background-image:url(data:image/png;base64,'.base64_encode(file_get_contents(__DIR__.'/sample/import_files/instagram.png')).')}',
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/matthiasmullie/minify/issues/68
|
|
||||||
$tests[] = array(
|
|
||||||
__DIR__.'/sample/external_imports/issue68.css',
|
|
||||||
'@import url(http://localhost/file.css);body{background:green}',
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/matthiasmullie/minify/issues/67
|
|
||||||
$tests[] = array(
|
|
||||||
'body { }
|
|
||||||
p { color: #fff; }',
|
|
||||||
'p{color:#fff}',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'body {}
|
|
||||||
p { color: #fff; }
|
|
||||||
h1 { }
|
|
||||||
strong { color: red; }',
|
|
||||||
'p{color:#fff}strong{color:red}',
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/matthiasmullie/minify/issues/74
|
|
||||||
$tests[] = array(
|
|
||||||
"@media only screen and (-webkit-min-device-pixel-ratio: 1.5),
|
|
||||||
only screen and (min--moz-device-pixel-ratio: 1.5),
|
|
||||||
only screen and (min-device-pixel-ratio: 1.5) {
|
|
||||||
|
|
||||||
#fancybox-loading,.fancybox-close,.fancybox-prev span,.fancybox-next span {
|
|
||||||
background-image: url('/path/to/image.png');
|
|
||||||
background-size: 44px 152px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#fancybox-loading div {
|
|
||||||
background-image: url('/path/to/image.gif');
|
|
||||||
background-size: 24px 24px;
|
|
||||||
}
|
|
||||||
}",
|
|
||||||
'@media only screen and (-webkit-min-device-pixel-ratio:1.5),only screen and (min--moz-device-pixel-ratio:1.5),only screen and (min-device-pixel-ratio:1.5){#fancybox-loading,.fancybox-close,.fancybox-prev span,.fancybox-next span{background-image:url(/path/to/image.png);background-size:44px 152px}#fancybox-loading div{background-image:url(/path/to/image.gif);background-size:24px 24px}}',
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/matthiasmullie/minify/issues/92
|
|
||||||
$tests[] = array(
|
|
||||||
'@media (min-width:320px) {
|
|
||||||
/* smartphones, iPhone, portrait 480x320 phones */
|
|
||||||
p {
|
|
||||||
background-color: red;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media (min-width:1025px) {
|
|
||||||
/* big landscape tablets, laptops, and desktops */
|
|
||||||
/* LEFT EMPTY OF ANY SELECTORS */
|
|
||||||
}
|
|
||||||
@media (min-width:1281px) {
|
|
||||||
/* hi-res laptops and desktops */
|
|
||||||
p {
|
|
||||||
background-color: blue;
|
|
||||||
}
|
|
||||||
}',
|
|
||||||
'@media (min-width:320px){p{background-color:red}}@media (min-width:1281px){p{background-color:blue}}',
|
|
||||||
);
|
|
||||||
|
|
||||||
return $tests;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array [input, expected result]
|
|
||||||
*/
|
|
||||||
public function dataProviderPaths()
|
|
||||||
{
|
|
||||||
$tests = array();
|
|
||||||
|
|
||||||
$source = __DIR__.'/sample/convert_relative_path/source';
|
|
||||||
$target = __DIR__.'/sample/convert_relative_path/target';
|
|
||||||
|
|
||||||
// external link
|
|
||||||
$tests[] = array(
|
|
||||||
$source.'/external.css',
|
|
||||||
$target.'/external.css',
|
|
||||||
file_get_contents($source.'/external.css'),
|
|
||||||
);
|
|
||||||
|
|
||||||
// absolute path
|
|
||||||
$tests[] = array(
|
|
||||||
$source.'/absolute.css',
|
|
||||||
$target.'/absolute.css',
|
|
||||||
file_get_contents($source.'/absolute.css'),
|
|
||||||
);
|
|
||||||
|
|
||||||
// relative paths
|
|
||||||
$tests[] = array(
|
|
||||||
$source.'/relative.css',
|
|
||||||
$target.'/relative.css',
|
|
||||||
'@import url(stylesheet.css);',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
$source.'/../source/relative.css',
|
|
||||||
$target.'/target/relative.css',
|
|
||||||
'@import url(../stylesheet.css);',
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/matthiasmullie/minify/issues/29
|
|
||||||
$tests[] = array(
|
|
||||||
$source.'/issue29.css',
|
|
||||||
$target.'/issue29.css',
|
|
||||||
"@import url('http://myurl.de');",
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/matthiasmullie/minify/issues/38
|
|
||||||
$tests[] = array(
|
|
||||||
$source.'/relative.css',
|
|
||||||
null, // no output file
|
|
||||||
file_get_contents($source.'/relative.css'),
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/matthiasmullie/minify/issues/39
|
|
||||||
$tests[] = array(
|
|
||||||
$source.'/issue39.css',
|
|
||||||
null, // no output file
|
|
||||||
// relative paths should remain untouched
|
|
||||||
"@font-face{font-family:'blackcat';src:url(../webfont/blackcat.eot);src:url(../webfont/blackcat.eot?#iefix) format('embedded-opentype'),url(../webfont/blackcat.svg#blackcat) format('svg'),url(../webfont/blackcat.woff) format('woff'),url(../webfont/blackcat.ttf) format('truetype');font-weight:normal;font-style:normal}",
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
$source.'/issue39.css',
|
|
||||||
$target.'/issue39.css',
|
|
||||||
// relative paths should remain untouched
|
|
||||||
"@font-face{font-family:'blackcat';src:url(../webfont/blackcat.eot);src:url(../webfont/blackcat.eot?#iefix) format('embedded-opentype'),url(../webfont/blackcat.svg#blackcat) format('svg'),url(../webfont/blackcat.woff) format('woff'),url(../webfont/blackcat.ttf) format('truetype');font-weight:normal;font-style:normal}",
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
$source.'/issue39.css',
|
|
||||||
$target.'/target/issue39.css',
|
|
||||||
// relative paths should have changed
|
|
||||||
"@font-face{font-family:'blackcat';src:url(../../webfont/blackcat.eot);src:url(../../webfont/blackcat.eot?#iefix) format('embedded-opentype'),url(../../webfont/blackcat.svg#blackcat) format('svg'),url(../../webfont/blackcat.woff) format('woff'),url(../../webfont/blackcat.ttf) format('truetype');font-weight:normal;font-style:normal}",
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/forkcms/forkcms/issues/1121
|
|
||||||
$tests[] = array(
|
|
||||||
$source.'/nested/nested.css',
|
|
||||||
$target.'/nested.css',
|
|
||||||
'@import url(stylesheet.css);',
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/forkcms/forkcms/issues/1186
|
|
||||||
$tests[] = array(
|
|
||||||
array(
|
|
||||||
// key is a bogus path
|
|
||||||
'/Users/mathias/Documents/— Projecten/PROJECT_NAAM/Web/src/Backend/Core/Layout/Css/screen.css' => '@import url("imports/typography.css");',
|
|
||||||
),
|
|
||||||
'/Users/mathias/Documents/— Projecten/PROJECT_NAAM/Web/src/Backend/Cache/MinifiedCss/some-hash.css',
|
|
||||||
'@import url(../../Core/Layout/Css/imports/typography.css);',
|
|
||||||
);
|
|
||||||
|
|
||||||
$sourceRelative = 'tests/css/sample/convert_relative_path/source';
|
|
||||||
$targetRelative = 'tests/css/sample/convert_relative_path/target';
|
|
||||||
|
|
||||||
// from and/or to are relative links
|
|
||||||
$tests[] = array(
|
|
||||||
$sourceRelative.'/relative.css',
|
|
||||||
$target.'/relative.css',
|
|
||||||
'@import url(stylesheet.css);',
|
|
||||||
);
|
|
||||||
// note: relative target only works if the file already exists: it has
|
|
||||||
// to be able to realpath()
|
|
||||||
$tests[] = array(
|
|
||||||
$source.'/relative.css',
|
|
||||||
$targetRelative.'/relative.css',
|
|
||||||
'@import url(stylesheet.css);',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
$sourceRelative.'/relative.css',
|
|
||||||
$targetRelative.'/relative.css',
|
|
||||||
'@import url(stylesheet.css);',
|
|
||||||
);
|
|
||||||
|
|
||||||
$source = __DIR__.'/sample/symlink';
|
|
||||||
$target = __DIR__.'/sample/symlink/target';
|
|
||||||
$sourceRelative = 'tests/css/sample/symlink';
|
|
||||||
$targetRelative = 'tests/css/sample/symlink/target';
|
|
||||||
|
|
||||||
// import symlinked files: relative, absolute & mix
|
|
||||||
$tests[] = array(
|
|
||||||
$source.'/import_symlinked_file.css',
|
|
||||||
$target.'/import_symlinked_file.css',
|
|
||||||
'',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
$sourceRelative.'/import_symlinked_file.css',
|
|
||||||
$targetRelative.'/import_symlinked_file.css',
|
|
||||||
'',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
$source.'/import_symlinked_file.css',
|
|
||||||
$targetRelative.'/import_symlinked_file.css',
|
|
||||||
'',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
$sourceRelative.'/import_symlinked_file.css',
|
|
||||||
$target.'/import_symlinked_file.css',
|
|
||||||
'',
|
|
||||||
);
|
|
||||||
|
|
||||||
// move symlinked files: relative, absolute & mix
|
|
||||||
$tests[] = array(
|
|
||||||
$source.'/move_symlinked_file.css',
|
|
||||||
$target.'/move_symlinked_file.css',
|
|
||||||
'body{background-url:url(../assets/symlink.bmp)}',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
$sourceRelative.'/move_symlinked_file.css',
|
|
||||||
$targetRelative.'/move_symlinked_file.css',
|
|
||||||
'body{background-url:url(../assets/symlink.bmp)}',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
$source.'/move_symlinked_file.css',
|
|
||||||
$targetRelative.'/move_symlinked_file.css',
|
|
||||||
'body{background-url:url(../assets/symlink.bmp)}',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
$source.'/move_symlinked_file.css',
|
|
||||||
$targetRelative.'/move_symlinked_file.css',
|
|
||||||
'body{background-url:url(../assets/symlink.bmp)}',
|
|
||||||
);
|
|
||||||
|
|
||||||
// import symlinked folders: relative, absolute & mix
|
|
||||||
$tests[] = array(
|
|
||||||
$source.'/import_symlinked_folder.css',
|
|
||||||
$target.'/import_symlinked_folder.css',
|
|
||||||
'',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
$sourceRelative.'/import_symlinked_folder.css',
|
|
||||||
$targetRelative.'/import_symlinked_folder.css',
|
|
||||||
'',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
$source.'/import_symlinked_folder.css',
|
|
||||||
$targetRelative.'/import_symlinked_folder.css',
|
|
||||||
'',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
$sourceRelative.'/import_symlinked_folder.css',
|
|
||||||
$target.'/import_symlinked_folder.css',
|
|
||||||
'',
|
|
||||||
);
|
|
||||||
|
|
||||||
// move symlinked folders: relative, absolute & mix
|
|
||||||
$tests[] = array(
|
|
||||||
$source.'/move_symlinked_folder.css',
|
|
||||||
$target.'/move_symlinked_folder.css',
|
|
||||||
'body{background-url:url(../assets_symlink/asset.bmp)}',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
$sourceRelative.'/move_symlinked_folder.css',
|
|
||||||
$targetRelative.'/move_symlinked_folder.css',
|
|
||||||
'body{background-url:url(../assets_symlink/asset.bmp)}',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
$source.'/move_symlinked_folder.css',
|
|
||||||
$targetRelative.'/move_symlinked_folder.css',
|
|
||||||
'body{background-url:url(../assets_symlink/asset.bmp)}',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
$sourceRelative.'/move_symlinked_folder.css',
|
|
||||||
$target.'/move_symlinked_folder.css',
|
|
||||||
'body{background-url:url(../assets_symlink/asset.bmp)}',
|
|
||||||
);
|
|
||||||
|
|
||||||
return $tests;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
body {
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
body {
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
@ -1 +0,0 @@
|
|||||||
@import url(import.css);
|
|
||||||
@ -1 +0,0 @@
|
|||||||
@import 'import.css';
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
@import url(import.css);
|
|
||||||
@import 'import.css';
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
@import url(import.css) only screen;
|
|
||||||
@import 'import.css' only screen;
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
@import url(import.css);
|
|
||||||
@import 'import.css';
|
|
||||||
@ -1 +0,0 @@
|
|||||||
@import url(index6b.css);
|
|
||||||
@ -1 +0,0 @@
|
|||||||
@import url(import.css);
|
|
||||||
@ -1 +0,0 @@
|
|||||||
@import url(/absolute/path/to/stylesheet.css);
|
|
||||||
@ -1 +0,0 @@
|
|||||||
@import url(http://fonts.googleapis.com/css?family=Lato:100,300,400,700,900|Droid+Sans:400,700);
|
|
||||||
@ -1 +0,0 @@
|
|||||||
@import url( 'http://myurl.de');
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
@font-face {
|
|
||||||
font-family: 'blackcat';
|
|
||||||
src:url('../webfont/blackcat.eot');
|
|
||||||
src:url('../webfont/blackcat.eot?#iefix') format('embedded-opentype'),
|
|
||||||
url('../webfont/blackcat.svg#blackcat') format('svg'),
|
|
||||||
url('../webfont/blackcat.woff') format('woff'),
|
|
||||||
url('../webfont/blackcat.ttf') format('truetype');
|
|
||||||
font-weight: normal;
|
|
||||||
font-style: normal;
|
|
||||||
}
|
|
||||||
@ -1 +0,0 @@
|
|||||||
@import url(../relative.css);
|
|
||||||
@ -1 +0,0 @@
|
|||||||
@import url(../target/stylesheet.css);
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
body {
|
|
||||||
background: green;
|
|
||||||
}
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
@import "file.css";
|
|
||||||
@import url(http://localhost/file.css);
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 178 B |
Binary file not shown.
|
Before Width: | Height: | Size: 178 B |
@ -1 +0,0 @@
|
|||||||
body { background: url(file.png); }
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 178 B |
@ -1,3 +0,0 @@
|
|||||||
.social-btn a[href*="facebook"] { background-image: url(facebook.png) } /* encode skipped */
|
|
||||||
.social-btn a[href*="vimeo"] { background-image: url(vimeo.png) }
|
|
||||||
.social-btn a[href*="instagram"] { background-image: url(instagram.png) }
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 178 B |
@ -1 +0,0 @@
|
|||||||
../other_path/assets/asset.bmp
|
|
||||||
@ -1 +0,0 @@
|
|||||||
other_path/assets
|
|
||||||
@ -1 +0,0 @@
|
|||||||
@import url(imports/symlink.css);
|
|
||||||
@ -1 +0,0 @@
|
|||||||
@import url(imports_symlink/import.css);
|
|
||||||
@ -1 +0,0 @@
|
|||||||
../other_path/imports/import.css
|
|
||||||
@ -1 +0,0 @@
|
|||||||
other_path/imports
|
|
||||||
@ -1 +0,0 @@
|
|||||||
body{background-url:url(assets/symlink.bmp)}
|
|
||||||
@ -1 +0,0 @@
|
|||||||
body{background-url:url(assets_symlink/asset.bmp)}
|
|
||||||
@ -1,149 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
use MatthiasMullie\Minify;
|
|
||||||
use MatthiasMullie\Scrapbook\Adapters\MemoryStore;
|
|
||||||
use MatthiasMullie\Scrapbook\Psr6\Pool;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests common functions of abstract Minify class by using JS implementation.
|
|
||||||
*/
|
|
||||||
class CommonTest extends PHPUnit_Framework_TestCase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @test
|
|
||||||
*/
|
|
||||||
public function construct()
|
|
||||||
{
|
|
||||||
$path1 = __DIR__.'/sample/source/script1.js';
|
|
||||||
$path2 = __DIR__.'/sample/source/script2.js';
|
|
||||||
$content1 = file_get_contents($path1);
|
|
||||||
$content2 = file_get_contents($path2);
|
|
||||||
|
|
||||||
// 1 source in constructor
|
|
||||||
$minifier = new Minify\JS($content1);
|
|
||||||
$result = $minifier->minify();
|
|
||||||
|
|
||||||
$this->assertEquals($content1, $result);
|
|
||||||
|
|
||||||
// multiple sources in constructor
|
|
||||||
$minifier = new Minify\JS($content1, $content2);
|
|
||||||
$result = $minifier->minify();
|
|
||||||
|
|
||||||
$this->assertEquals($content1.';'.$content2, $result);
|
|
||||||
|
|
||||||
// file in constructor
|
|
||||||
$minifier = new Minify\JS($path1);
|
|
||||||
$result = $minifier->minify();
|
|
||||||
|
|
||||||
$this->assertEquals($content1, $result);
|
|
||||||
|
|
||||||
// multiple files in constructor
|
|
||||||
$minifier = new Minify\JS($path1, $path2);
|
|
||||||
$result = $minifier->minify();
|
|
||||||
|
|
||||||
$this->assertEquals($content1.';'.$content2, $result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @test
|
|
||||||
*/
|
|
||||||
public function add()
|
|
||||||
{
|
|
||||||
$path1 = __DIR__.'/sample/source/script1.js';
|
|
||||||
$path2 = __DIR__.'/sample/source/script2.js';
|
|
||||||
$content1 = file_get_contents($path1);
|
|
||||||
$content2 = file_get_contents($path2);
|
|
||||||
|
|
||||||
// 1 source in add
|
|
||||||
$minifier = new Minify\JS();
|
|
||||||
$minifier->add($content1);
|
|
||||||
$result = $minifier->minify();
|
|
||||||
|
|
||||||
$this->assertEquals($content1, $result);
|
|
||||||
|
|
||||||
// multiple sources in add
|
|
||||||
$minifier = new Minify\JS();
|
|
||||||
$minifier->add($content1);
|
|
||||||
$minifier->add($content2);
|
|
||||||
$result = $minifier->minify();
|
|
||||||
|
|
||||||
$this->assertEquals($content1.';'.$content2, $result);
|
|
||||||
|
|
||||||
// file in add
|
|
||||||
$minifier = new Minify\JS();
|
|
||||||
$minifier->add($path1);
|
|
||||||
$result = $minifier->minify();
|
|
||||||
|
|
||||||
$this->assertEquals($content1, $result);
|
|
||||||
|
|
||||||
// multiple files in add
|
|
||||||
$minifier = new Minify\JS();
|
|
||||||
$minifier->add($path1);
|
|
||||||
$minifier->add($path2);
|
|
||||||
$result = $minifier->minify();
|
|
||||||
|
|
||||||
$this->assertEquals($content1.';'.$content2, $result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @test
|
|
||||||
*/
|
|
||||||
public function load()
|
|
||||||
{
|
|
||||||
// content greater than PHP_MAXPATHLEN
|
|
||||||
// https://github.com/matthiasmullie/minify/issues/90
|
|
||||||
$content = rtrim(str_repeat('var a="b";', 500), ';');
|
|
||||||
|
|
||||||
$minifier = new Minify\JS($content);
|
|
||||||
|
|
||||||
$this->assertEquals($minifier->minify(), $content);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @test
|
|
||||||
*/
|
|
||||||
public function save()
|
|
||||||
{
|
|
||||||
$path = __DIR__.'/sample/source/script1.js';
|
|
||||||
$content = file_get_contents($path);
|
|
||||||
$savePath = __DIR__.'/sample/target/script1.js';
|
|
||||||
|
|
||||||
$minifier = new Minify\JS($path);
|
|
||||||
$minifier->minify($savePath);
|
|
||||||
|
|
||||||
$this->assertEquals(file_get_contents($savePath), $content);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @test
|
|
||||||
*/
|
|
||||||
public function gzip()
|
|
||||||
{
|
|
||||||
$path = __DIR__.'/sample/source/script1.js';
|
|
||||||
$content = file_get_contents($path);
|
|
||||||
$savePath = __DIR__.'/sample/target/script1.js.gz';
|
|
||||||
|
|
||||||
$minifier = new Minify\JS($path);
|
|
||||||
$minifier->gzip($savePath, 9);
|
|
||||||
|
|
||||||
$this->assertEquals(file_get_contents($savePath), gzencode($content, 9, FORCE_GZIP));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @test
|
|
||||||
*/
|
|
||||||
public function cache()
|
|
||||||
{
|
|
||||||
$path = __DIR__.'/sample/source/script1.js';
|
|
||||||
$content = file_get_contents($path);
|
|
||||||
|
|
||||||
$cache = new MemoryStore();
|
|
||||||
$pool = new Pool($cache);
|
|
||||||
$item = $pool->getItem('cache-script1');
|
|
||||||
|
|
||||||
$minifier = new Minify\JS($path);
|
|
||||||
$item = $minifier->cache($item);
|
|
||||||
|
|
||||||
$this->assertEquals($item->get(), $content);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,670 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
use MatthiasMullie\Minify;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JS minifier test case.
|
|
||||||
*/
|
|
||||||
class JSTest extends PHPUnit_Framework_TestCase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var Minify\JS
|
|
||||||
*/
|
|
||||||
private $minifier;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prepares the environment before running a test.
|
|
||||||
*/
|
|
||||||
protected function setUp()
|
|
||||||
{
|
|
||||||
parent::setUp();
|
|
||||||
|
|
||||||
// override save method, there's no point in writing the result out here
|
|
||||||
$this->minifier = $this->getMockBuilder('\MatthiasMullie\Minify\JS')
|
|
||||||
->setMethods(array('save'))
|
|
||||||
->getMock();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cleans up the environment after running a test.
|
|
||||||
*/
|
|
||||||
protected function tearDown()
|
|
||||||
{
|
|
||||||
$this->minifier = null;
|
|
||||||
parent::tearDown();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test JS minifier rules, provided by dataProvider.
|
|
||||||
*
|
|
||||||
* @test
|
|
||||||
* @dataProvider dataProvider
|
|
||||||
*/
|
|
||||||
public function minify($input, $expected)
|
|
||||||
{
|
|
||||||
$input = (array) $input;
|
|
||||||
foreach ($input as $js) {
|
|
||||||
$this->minifier->add($js);
|
|
||||||
}
|
|
||||||
$result = $this->minifier->minify();
|
|
||||||
|
|
||||||
$this->assertEquals($expected, $result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array [input, expected result]
|
|
||||||
*/
|
|
||||||
public function dataProvider()
|
|
||||||
{
|
|
||||||
$tests = array();
|
|
||||||
|
|
||||||
// escaped quotes should not terminate string
|
|
||||||
$tests[] = array(
|
|
||||||
'alert("Escaped quote which is same as string quotes: \"; should not match")',
|
|
||||||
'alert("Escaped quote which is same as string quotes: \"; should not match")',
|
|
||||||
);
|
|
||||||
|
|
||||||
// backtick string (allow string interpolation)
|
|
||||||
$tests[] = array(
|
|
||||||
'var str=`Hi, ${name}`',
|
|
||||||
'var str=`Hi, ${name}`',
|
|
||||||
);
|
|
||||||
|
|
||||||
// regex delimiters need to be treated as strings
|
|
||||||
// (two forward slashes could look like a comment)
|
|
||||||
$tests[] = array(
|
|
||||||
'/abc\/def\//.test("abc")',
|
|
||||||
'/abc\/def\//.test("abc")',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'var a = /abc\/def\//.test("abc")',
|
|
||||||
'var a=/abc\/def\//.test("abc")',
|
|
||||||
);
|
|
||||||
|
|
||||||
// don't confuse multiple slashes for regexes
|
|
||||||
$tests[] = array(
|
|
||||||
'a = b / c; d = e / f',
|
|
||||||
'a=b/c;d=e/f',
|
|
||||||
);
|
|
||||||
|
|
||||||
// mixture of quotes starting in comment/regex, to make sure strings are
|
|
||||||
// matched correctly, not inside comment/regex.
|
|
||||||
$tests[] = array(
|
|
||||||
'/abc"def/.test("abc")',
|
|
||||||
'/abc"def/.test("abc")',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'/* Bogus " */var test="test";',
|
|
||||||
'var test="test"',
|
|
||||||
);
|
|
||||||
|
|
||||||
// replace comments
|
|
||||||
$tests[] = array(
|
|
||||||
'/* This is a JS comment */',
|
|
||||||
'',
|
|
||||||
);
|
|
||||||
|
|
||||||
// make sure no ; is added in places it shouldn't
|
|
||||||
$tests[] = array(
|
|
||||||
'if(true){}else{}',
|
|
||||||
'if(!0){}else{}',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'do{i++}while(i<1)',
|
|
||||||
'do{i++}while(i<1)',
|
|
||||||
);
|
|
||||||
|
|
||||||
$tests[] = array(
|
|
||||||
'if(true)statement;else statement',
|
|
||||||
'if(!0)statement;else statement',
|
|
||||||
);
|
|
||||||
|
|
||||||
$tests[] = array(
|
|
||||||
'for ( i = 0; ; i++ ) statement',
|
|
||||||
'for(i=0;;i++)statement',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'for (i = 0; (i < 10); i++) statement',
|
|
||||||
'for(i=0;(i<10);i++)statement',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'alert("test");;alert("test2")',
|
|
||||||
'alert("test");alert("test2")',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'-1
|
|
||||||
+2',
|
|
||||||
'-1+2',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'-1+
|
|
||||||
2',
|
|
||||||
'-1+2',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'alert("this is a test");',
|
|
||||||
'alert("this is a test")',
|
|
||||||
);
|
|
||||||
|
|
||||||
// test where newline should be preserved (for ASI) or semicolon added
|
|
||||||
$tests[] = array(
|
|
||||||
'function(){console.log("this is a test");}',
|
|
||||||
'function(){console.log("this is a test")}',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'alert("this is a test")
|
|
||||||
alert("this is another test")',
|
|
||||||
'alert("this is a test")
|
|
||||||
alert("this is another test")',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'a=b+c
|
|
||||||
d=e+f',
|
|
||||||
'a=b+c
|
|
||||||
d=e+f',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'a++
|
|
||||||
|
|
||||||
++b',
|
|
||||||
'a++
|
|
||||||
++b',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'!a
|
|
||||||
!b',
|
|
||||||
'!a
|
|
||||||
!b',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
// don't confuse with 'if'
|
|
||||||
'digestif
|
|
||||||
(true)
|
|
||||||
statement',
|
|
||||||
'digestif(!0)
|
|
||||||
statement',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'if
|
|
||||||
(
|
|
||||||
(
|
|
||||||
true
|
|
||||||
)
|
|
||||||
&&
|
|
||||||
(
|
|
||||||
true
|
|
||||||
)
|
|
||||||
)
|
|
||||||
statement',
|
|
||||||
'if((!0)&&(!0))
|
|
||||||
statement',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'if
|
|
||||||
(
|
|
||||||
true
|
|
||||||
)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
}',
|
|
||||||
'if(!0){}
|
|
||||||
else{}',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'do
|
|
||||||
{
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
while
|
|
||||||
(
|
|
||||||
i<1
|
|
||||||
)',
|
|
||||||
'do{i++}
|
|
||||||
while(i<1)',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'if ( true )
|
|
||||||
statement
|
|
||||||
else
|
|
||||||
statement',
|
|
||||||
'if(!0)
|
|
||||||
statement
|
|
||||||
else statement',
|
|
||||||
);
|
|
||||||
|
|
||||||
// test if whitespace around keywords is properly collapsed
|
|
||||||
$tests[] = array(
|
|
||||||
'var
|
|
||||||
variable
|
|
||||||
=
|
|
||||||
"value";',
|
|
||||||
'var variable="value"',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'var variable = {
|
|
||||||
test:
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}',
|
|
||||||
'var variable={test:{}}',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'if ( true ) {
|
|
||||||
} else {
|
|
||||||
}',
|
|
||||||
'if(!0){}else{}',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'53 instanceof String',
|
|
||||||
'53 instanceof String',
|
|
||||||
);
|
|
||||||
|
|
||||||
// remove whitespace around operators
|
|
||||||
$tests[] = array(
|
|
||||||
'a = 1 + 2',
|
|
||||||
'a=1+2',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'object . property',
|
|
||||||
'object.property',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'object
|
|
||||||
.property',
|
|
||||||
'object.property',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'alert ( "this is a test" );',
|
|
||||||
'alert("this is a test")',
|
|
||||||
);
|
|
||||||
|
|
||||||
// mix of ++ and +: three consecutive +es will be interpreted as ++ +
|
|
||||||
$tests[] = array(
|
|
||||||
'a++ +b',
|
|
||||||
'a++ +b',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'a+ ++b',
|
|
||||||
'a+ ++b', // +++ would actually be allowed as well
|
|
||||||
);
|
|
||||||
|
|
||||||
// SyntaxError: identifier starts immediately after numeric literal
|
|
||||||
$tests[] = array(
|
|
||||||
'42 .toString()',
|
|
||||||
'42 .toString()',
|
|
||||||
);
|
|
||||||
|
|
||||||
// add comment in between whitespace that needs to be stripped
|
|
||||||
$tests[] = array(
|
|
||||||
'object
|
|
||||||
// haha, some comment, just to make things harder!
|
|
||||||
.property',
|
|
||||||
'object.property',
|
|
||||||
);
|
|
||||||
|
|
||||||
// add comment in between whitespace that needs to be stripped
|
|
||||||
$tests[] = array(
|
|
||||||
'var test=true,test2=false',
|
|
||||||
'var test=!0,test2=!1',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'var testtrue="testing if true as part of varname is ignored as it should"',
|
|
||||||
'var testtrue="testing if true as part of varname is ignored as it should"',
|
|
||||||
);
|
|
||||||
|
|
||||||
// random bits of code that tripped errors during development
|
|
||||||
$tests[] = array(
|
|
||||||
'
|
|
||||||
// check if it isn\'t a text-element
|
|
||||||
if(currentElement.attr(\'type\') != \'text\')
|
|
||||||
{
|
|
||||||
// remove the current one
|
|
||||||
currentElement.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
// already a text element
|
|
||||||
else newElement = currentElement;
|
|
||||||
',
|
|
||||||
'if(currentElement.attr(\'type\')!=\'text\'){currentElement.remove()}
|
|
||||||
else newElement=currentElement',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'var jsBackend =
|
|
||||||
{
|
|
||||||
debug: false,
|
|
||||||
current: {}
|
|
||||||
}',
|
|
||||||
'var jsBackend={debug:!1,current:{}}',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'var utils =
|
|
||||||
{
|
|
||||||
debug: false
|
|
||||||
}
|
|
||||||
utils.array =
|
|
||||||
{
|
|
||||||
}',
|
|
||||||
'var utils={debug:!1}
|
|
||||||
utils.array={}',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'rescape = /\'|\\\\/g,
|
|
||||||
|
|
||||||
// blablabla here was some more code but the point was that somewhere
|
|
||||||
// down below, there would be a closing quote which would cause the
|
|
||||||
// regex (confused for escaped closing tag) not to be recognized,
|
|
||||||
// taking the opening single quote & looking for a string.
|
|
||||||
// So here\'s <-- the closing quote
|
|
||||||
runescape = \'blabla\'',
|
|
||||||
'rescape=/\'|\\\\/g,runescape=\'blabla\'',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'var rsingleTag = (/^<(\w+)\s*\/?>(?:<\/\1>|)$/)',
|
|
||||||
'var rsingleTag=(/^<(\w+)\s*\/?>(?:<\/\1>|)$/)',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'if (this.sliding) return this.$element.one(\'slid.bs.carousel\', function () { that.to(pos) }) // yes, "slid"
|
|
||||||
if (activeIndex == pos) return this.pause().cycle()',
|
|
||||||
'if(this.sliding)return this.$element.one(\'slid.bs.carousel\',function(){that.to(pos)})
|
|
||||||
if(activeIndex==pos)return this.pause().cycle()',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'if (e.which == 38 && index > 0) index-- // up
|
|
||||||
if (e.which == 40 && index < $items.length - 1) index++ // down',
|
|
||||||
'if(e.which==38&&index>0)index--
|
|
||||||
if(e.which==40&&index<$items.length-1)index++',
|
|
||||||
);
|
|
||||||
|
|
||||||
// replace associative array key references by property notation
|
|
||||||
$tests[] = array(
|
|
||||||
'array["key"][\'key2\']',
|
|
||||||
'array.key.key2',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'array[ "key" ][ \'key2\' ]',
|
|
||||||
'array.key.key2',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'array["a","b","c"]',
|
|
||||||
'array["a","b","c"]',
|
|
||||||
);
|
|
||||||
//
|
|
||||||
$tests[] = array(
|
|
||||||
"['loader']",
|
|
||||||
"['loader']",
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'array["dont-replace"][\'key2\']',
|
|
||||||
'array["dont-replace"].key2',
|
|
||||||
);
|
|
||||||
|
|
||||||
// shorten bools
|
|
||||||
$tests[] = array(
|
|
||||||
'while(true){break}',
|
|
||||||
'for(;;){break}',
|
|
||||||
);
|
|
||||||
// make sure we don't get "missing while after do-loop body"
|
|
||||||
$tests[] = array(
|
|
||||||
'do{break}while(true)',
|
|
||||||
'do{break}while(!0)',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
"do break\nwhile(true)",
|
|
||||||
"do break\nwhile(!0)",
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
"do{break}while(true){alert('test')}",
|
|
||||||
"do{break}while(!0){alert('test')}",
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
"do break\nwhile(true){alert('test')}",
|
|
||||||
"do break\nwhile(!0){alert('test')}",
|
|
||||||
);
|
|
||||||
// nested do-while & while
|
|
||||||
$tests[] = array(
|
|
||||||
"do{while(true){break}break}while(true){alert('test')}",
|
|
||||||
"do{for(;;){break}break}while(!0){alert('test')}",
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
"do{while(true){break}break}while(true){alert('test')}while(true){break}",
|
|
||||||
"do{for(;;){break}break}while(!0){alert('test')}for(;;){break}",
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
"do{while(true){break}break}while(true){alert('test')}while(true){break}do{while(true){break}break}while(true){alert('test')}while(true){break}",
|
|
||||||
"do{for(;;){break}break}while(!0){alert('test')}for(;;){break}do{for(;;){break}break}while(!0){alert('test')}for(;;){break}",
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/matthiasmullie/minify/issues/10
|
|
||||||
$tests[] = array(
|
|
||||||
'// first mutation patch
|
|
||||||
// second mutation patch
|
|
||||||
// third mutation patch
|
|
||||||
// fourth mutation patch',
|
|
||||||
'',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'/////////////////////////
|
|
||||||
// first mutation patch
|
|
||||||
// second mutation patch
|
|
||||||
// third mutation patch
|
|
||||||
// fourth mutation patch
|
|
||||||
/////////////////////////',
|
|
||||||
'',
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/matthiasmullie/minify/issues/14
|
|
||||||
$tests[] = array(
|
|
||||||
'function foo (a, b)
|
|
||||||
{
|
|
||||||
return a / b;
|
|
||||||
}
|
|
||||||
function foo (a, b)
|
|
||||||
{
|
|
||||||
return a / b;
|
|
||||||
}',
|
|
||||||
'function foo(a,b){return a/b}
|
|
||||||
function foo(a,b){return a/b}',
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/matthiasmullie/minify/issues/15
|
|
||||||
$tests[] = array(
|
|
||||||
'if ( !data.success )
|
|
||||||
deferred.reject(); else
|
|
||||||
deferred.resolve(data);',
|
|
||||||
'if(!data.success)
|
|
||||||
deferred.reject();else deferred.resolve(data)',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
"if ( typeof jQuery === 'undefined' )
|
|
||||||
throw new Error('.editManager.js: jQuery is required and must be loaded first');",
|
|
||||||
"if(typeof jQuery==='undefined')
|
|
||||||
throw new Error('.editManager.js: jQuery is required and must be loaded first')",
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/matthiasmullie/minify/issues/27
|
|
||||||
$tests[] = array(
|
|
||||||
'$.expr[":"]',
|
|
||||||
'$.expr[":"]',
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/matthiasmullie/minify/issues/31
|
|
||||||
$tests[] = array(
|
|
||||||
"$(_this).attr('src',this.src).trigger('adapt',['loader'])",
|
|
||||||
"$(_this).attr('src',this.src).trigger('adapt',['loader'])",
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/matthiasmullie/minify/issues/33
|
|
||||||
$tests[] = array(
|
|
||||||
'$.fn.alert = Plugin
|
|
||||||
$.fn.alert.Constructor = Alert',
|
|
||||||
'$.fn.alert=Plugin
|
|
||||||
$.fn.alert.Constructor=Alert',
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/matthiasmullie/minify/issues/34
|
|
||||||
$tests[] = array(
|
|
||||||
'a.replace("\\\\","");hi="This is a string"',
|
|
||||||
'a.replace("\\\\","");hi="This is a string"',
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/matthiasmullie/minify/issues/35
|
|
||||||
$tests[] = array(
|
|
||||||
array(
|
|
||||||
'// script that ends with comment',
|
|
||||||
'var test=1',
|
|
||||||
),
|
|
||||||
'var test=1',
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/matthiasmullie/minify/issues/37
|
|
||||||
$tests[] = array(
|
|
||||||
'function () { ;;;;;;;; }',
|
|
||||||
'function(){}',
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/matthiasmullie/minify/issues/40
|
|
||||||
$tests[] = array(
|
|
||||||
'for(v=1,_=b;;){}',
|
|
||||||
'for(v=1,_=b;;){}',
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/matthiasmullie/minify/issues/41
|
|
||||||
$tests[] = array(
|
|
||||||
"conf.zoomHoverIcons['default']",
|
|
||||||
"conf.zoomHoverIcons['default']",
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/matthiasmullie/minify/issues/42
|
|
||||||
$tests[] = array(
|
|
||||||
'for(i=1;i<2;i++);',
|
|
||||||
'for(i=1;i<2;i++);',
|
|
||||||
);
|
|
||||||
$tests[] = array(
|
|
||||||
'if(1){for(i=1;i<2;i++);}',
|
|
||||||
'if(1){for(i=1;i<2;i++);}',
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/matthiasmullie/minify/issues/43
|
|
||||||
$tests[] = array(
|
|
||||||
'{"key":"3","key2":"value","key3":"3"}',
|
|
||||||
'{"key":"3","key2":"value","key3":"3"}',
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/matthiasmullie/minify/issues/44
|
|
||||||
$tests[] = array(
|
|
||||||
'return ["x"]',
|
|
||||||
'return["x"]',
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/matthiasmullie/minify/issues/50
|
|
||||||
$tests[] = array(
|
|
||||||
'do{var dim=this._getDaysInMonth(year,month-1);if(day<=dim){break}month++;day-=dim}while(true)}',
|
|
||||||
'do{var dim=this._getDaysInMonth(year,month-1);if(day<=dim){break}month++;day-=dim}while(!0)}',
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/matthiasmullie/minify/issues/53
|
|
||||||
$tests[] = array(
|
|
||||||
'a.validator.addMethod("accept", function (b, c, d) {
|
|
||||||
var e, f, g = "string" == typeof d ?
|
|
||||||
d.replace(/\s/g, "").replace(/,/g, "|") :
|
|
||||||
"image/*", h = this.optional(c);
|
|
||||||
if (h)return h;
|
|
||||||
if ("file" === a(c).attr("type") && (g = g.replace(/\*/g, ".*"), c.files && c.files.length))
|
|
||||||
for (e = 0; e < c.files.length; e++)
|
|
||||||
if (f = c.files[e], !f.type.match(new RegExp(".?(" + g + ")$", "i")))
|
|
||||||
return !1;
|
|
||||||
return !0
|
|
||||||
}',
|
|
||||||
'a.validator.addMethod("accept",function(b,c,d){var e,f,g="string"==typeof d?d.replace(/\s/g,"").replace(/,/g,"|"):"image/*",h=this.optional(c);if(h)return h;if("file"===a(c).attr("type")&&(g=g.replace(/\*/g,".*"),c.files&&c.files.length))
|
|
||||||
for(e=0;e<c.files.length;e++)
|
|
||||||
if(f=c.files[e],!f.type.match(new RegExp(".?("+g+")$","i")))
|
|
||||||
return !1;return !0}',
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/matthiasmullie/minify/issues/54
|
|
||||||
$tests[] = array(
|
|
||||||
'function a() {
|
|
||||||
if (true)
|
|
||||||
return
|
|
||||||
if (false)
|
|
||||||
return
|
|
||||||
}',
|
|
||||||
'function a(){if(!0)
|
|
||||||
return
|
|
||||||
if(!1)
|
|
||||||
return}',
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/matthiasmullie/minify/issues/56
|
|
||||||
$tests[] = array(
|
|
||||||
'var timeRegex = /^([2][0-3]|[01]?[0-9])(:[0-5][0-9])?$/
|
|
||||||
if (start_time.match(timeRegex) == null) {}',
|
|
||||||
'var timeRegex=/^([2][0-3]|[01]?[0-9])(:[0-5][0-9])?$/
|
|
||||||
if(start_time.match(timeRegex)==null){}',
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/matthiasmullie/minify/issues/58
|
|
||||||
// stripped of redundant code to expose problem case
|
|
||||||
$tests[] = array(
|
|
||||||
<<<'BUG'
|
|
||||||
function inspect() {
|
|
||||||
escapedString.replace(/abc/g, '\\\'');
|
|
||||||
}
|
|
||||||
function isJSON() {
|
|
||||||
str.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']');
|
|
||||||
}
|
|
||||||
BUG
|
|
||||||
,
|
|
||||||
<<<'BUG'
|
|
||||||
function inspect(){escapedString.replace(/abc/g,'\\\'')}
|
|
||||||
function isJSON(){str.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']')}
|
|
||||||
BUG
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/matthiasmullie/minify/issues/59
|
|
||||||
$tests[] = array(
|
|
||||||
'isPath:function(e) {
|
|
||||||
return /\//.test(e);
|
|
||||||
}',
|
|
||||||
'isPath:function(e){return/\//.test(e)}',
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/matthiasmullie/minify/issues/64
|
|
||||||
$tests[] = array(
|
|
||||||
' var d3_nsPrefix = {
|
|
||||||
svg: "http://www.w3.org/2000/svg",
|
|
||||||
xhtml: "http://www.w3.org/1999/xhtml",
|
|
||||||
xlink: "http://www.w3.org/1999/xlink",
|
|
||||||
xml: "http://www.w3.org/XML/1998/namespace",
|
|
||||||
xmlns: "http://www.w3.org/2000/xmlns/"
|
|
||||||
};',
|
|
||||||
'var d3_nsPrefix={svg:"http://www.w3.org/2000/svg",xhtml:"http://www.w3.org/1999/xhtml",xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"}',
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/matthiasmullie/minify/issues/66
|
|
||||||
$tests[] = array(
|
|
||||||
"$(coming.wrap).bind('onReset', function () {
|
|
||||||
try {
|
|
||||||
$(this).find('iframe').hide().attr('src', '//about:blank').end().empty();
|
|
||||||
} catch (e) {}
|
|
||||||
});",
|
|
||||||
"$(coming.wrap).bind('onReset',function(){try{\$(this).find('iframe').hide().attr('src','//about:blank').end().empty()}catch(e){}})",
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/matthiasmullie/minify/issues/89
|
|
||||||
$tests[] = array(
|
|
||||||
'for(;;ja||(ja=true)){}',
|
|
||||||
'for(;;ja||(ja=!0)){}',
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://github.com/matthiasmullie/minify/issues/91
|
|
||||||
$tests[] = array(
|
|
||||||
'if(true){if(true)console.log("test")else;}',
|
|
||||||
'if(!0){if(!0)console.log("test")}',
|
|
||||||
);
|
|
||||||
|
|
||||||
return $tests;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1 +0,0 @@
|
|||||||
var test=1
|
|
||||||
@ -1 +0,0 @@
|
|||||||
var test=2
|
|
||||||
Loading…
x
Reference in New Issue
Block a user