]> git.ipfire.org Git - thirdparty/bacula.git/commitdiff
baculum: Add jsmin-php as framework dependency
authorMarcin Haba <marcin.haba@bacula.pl>
Tue, 29 Oct 2019 17:44:02 +0000 (18:44 +0100)
committerMarcin Haba <marcin.haba@bacula.pl>
Sat, 14 Dec 2019 14:57:45 +0000 (15:57 +0100)
39 files changed:
gui/baculum/framework/composer/ClassLoader.php
gui/baculum/framework/composer/autoload_namespaces.php
gui/baculum/framework/composer/autoload_static.php
gui/baculum/framework/composer/installed.json
gui/baculum/framework/mrclay/jsmin-php/.editorconfig [new file with mode: 0644]
gui/baculum/framework/mrclay/jsmin-php/.gitignore [new file with mode: 0644]
gui/baculum/framework/mrclay/jsmin-php/HISTORY.txt [new file with mode: 0644]
gui/baculum/framework/mrclay/jsmin-php/LICENSE.txt [new file with mode: 0644]
gui/baculum/framework/mrclay/jsmin-php/README.devel.txt [new file with mode: 0644]
gui/baculum/framework/mrclay/jsmin-php/composer.json [new file with mode: 0644]
gui/baculum/framework/mrclay/jsmin-php/phpunit.xml.dist [new file with mode: 0644]
gui/baculum/framework/mrclay/jsmin-php/src/JSMin/JSMin.php [new file with mode: 0644]
gui/baculum/framework/mrclay/jsmin-php/src/JSMin/UnterminatedCommentException.php [new file with mode: 0644]
gui/baculum/framework/mrclay/jsmin-php/src/JSMin/UnterminatedRegExpException.php [new file with mode: 0644]
gui/baculum/framework/mrclay/jsmin-php/src/JSMin/UnterminatedStringException.php [new file with mode: 0644]
gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/expected/before.js [new file with mode: 0644]
gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/expected/condcomm.js [new file with mode: 0644]
gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/expected/es6-literal.js [new file with mode: 0644]
gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/expected/issue144.js [new file with mode: 0644]
gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/expected/issue256.js [new file with mode: 0644]
gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/expected/keyword-regex.js [new file with mode: 0644]
gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/expected/not-regexp.js [new file with mode: 0644]
gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/expected/regexes.js [new file with mode: 0644]
gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/expected/starts-regex.js [new file with mode: 0644]
gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/expected/token-regexp.js [new file with mode: 0644]
gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/input/before.js [new file with mode: 0644]
gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/input/condcomm.js [new file with mode: 0644]
gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/input/es6-literal.js [new file with mode: 0644]
gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/input/issue144.js [new file with mode: 0644]
gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/input/issue256.js [new file with mode: 0644]
gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/input/keyword-regex.js [new file with mode: 0644]
gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/input/not-regexp.js [new file with mode: 0644]
gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/input/regexes.js [new file with mode: 0644]
gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/input/starts-regex.js [new file with mode: 0644]
gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/input/token-regexp.js [new file with mode: 0644]
gui/baculum/framework/mrclay/jsmin-php/tests/Tests/JSMin/JSMinTest.php [new file with mode: 0644]
gui/baculum/framework/mrclay/jsmin-php/tests/bootstrap.php [new file with mode: 0644]
gui/baculum/framework/mrclay/jsmin-php/web/README.txt [new file with mode: 0644]
gui/baculum/framework/mrclay/jsmin-php/web/index.php [new file with mode: 0644]

index dc02dfb114fb6af2eacf89407a529c37ab8e7eb8..fce8549f0781bafdc7da2301b84d048286757445 100644 (file)
@@ -279,7 +279,7 @@ class ClassLoader
      */
     public function setApcuPrefix($apcuPrefix)
     {
-        $this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null;
+        $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
     }
 
     /**
@@ -377,7 +377,7 @@ class ClassLoader
             $subPath = $class;
             while (false !== $lastPos = strrpos($subPath, '\\')) {
                 $subPath = substr($subPath, 0, $lastPos);
-                $search = $subPath.'\\';
+                $search = $subPath . '\\';
                 if (isset($this->prefixDirsPsr4[$search])) {
                     $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
                     foreach ($this->prefixDirsPsr4[$search] as $dir) {
index b7fc0125dbca56fd7565ad62097672a59473e64e..89764e0cc9568d25cbf73ab97b2a3ab041b9f294 100644 (file)
@@ -6,4 +6,5 @@ $vendorDir = dirname(dirname(__FILE__));
 $baseDir = dirname($vendorDir);
 
 return array(
+    'JSMin\\' => array($vendorDir . '/mrclay/jsmin-php/src'),
 );
index 53ee5181394ea53646676f7cb6e73a943824c6a7..44baaad54756815841c709e250d55c927e457078 100644 (file)
@@ -20,11 +20,22 @@ class ComposerStaticInitce99a96f11b07d74c065123825cb4155
         ),
     );
 
+    public static $prefixesPsr0 = array (
+        'J' => 
+        array (
+            'JSMin\\' => 
+            array (
+                0 => __DIR__ . '/..' . '/mrclay/jsmin-php/src',
+            ),
+        ),
+    );
+
     public static function getInitializer(ClassLoader $loader)
     {
         return \Closure::bind(function () use ($loader) {
             $loader->prefixLengthsPsr4 = ComposerStaticInitce99a96f11b07d74c065123825cb4155::$prefixLengthsPsr4;
             $loader->prefixDirsPsr4 = ComposerStaticInitce99a96f11b07d74c065123825cb4155::$prefixDirsPsr4;
+            $loader->prefixesPsr0 = ComposerStaticInitce99a96f11b07d74c065123825cb4155::$prefixesPsr0;
 
         }, null, ClassLoader::class);
     }
index 76d2be61478f5fcf0d33fc4f1966bc122eea5e2b..024dd97efd9467fd94df3a0daaff392d699dd0d4 100644 (file)
@@ -11,8 +11,7 @@
         "dist": {
             "type": "zip",
             "url": "https://api.github.com/repos/jquery/jquery-dist/zipball/9e8ec3d10fad04748176144f108d7355662ae75e",
-            "reference": "9e8ec3d10fad04748176144f108d7355662ae75e",
-            "shasum": null
+            "reference": "9e8ec3d10fad04748176144f108d7355662ae75e"
         },
         "type": "bower-asset",
         "installation-source": "dist",
         "version_normalized": "1.12.1.0",
         "source": {
             "type": "git",
-            "url": "https://github.com/components/jqueryui.git",
+            "url": "git@github.com:components/jqueryui.git",
             "reference": "44ecf3794cc56b65954cc19737234a3119d036cc"
         },
         "dist": {
             "type": "zip",
             "url": "https://api.github.com/repos/components/jqueryui/zipball/44ecf3794cc56b65954cc19737234a3119d036cc",
-            "reference": "44ecf3794cc56b65954cc19737234a3119d036cc",
-            "shasum": null
+            "reference": "44ecf3794cc56b65954cc19737234a3119d036cc"
         },
         "require": {
             "bower-asset/jquery": ">=1.6"
             "MIT"
         ]
     },
+    {
+        "name": "mrclay/jsmin-php",
+        "version": "2.4.0",
+        "version_normalized": "2.4.0.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/mrclay/jsmin-php.git",
+            "reference": "bb05febc9440852d39899255afd5569b7f21a72c"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/mrclay/jsmin-php/zipball/bb05febc9440852d39899255afd5569b7f21a72c",
+            "reference": "bb05febc9440852d39899255afd5569b7f21a72c",
+            "shasum": ""
+        },
+        "require": {
+            "ext-pcre": "*",
+            "php": ">=5.3.0"
+        },
+        "require-dev": {
+            "phpunit/phpunit": "4.2"
+        },
+        "time": "2018-12-06T15:03:38+00:00",
+        "type": "library",
+        "installation-source": "dist",
+        "autoload": {
+            "psr-0": {
+                "JSMin\\": "src/"
+            }
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "MIT"
+        ],
+        "authors": [
+            {
+                "name": "Stephen Clay",
+                "email": "steve@mrclay.org",
+                "role": "Developer"
+            },
+            {
+                "name": "Ryan Grove",
+                "email": "ryan@wonko.com",
+                "role": "Developer"
+            }
+        ],
+        "description": "Provides a modified port of Douglas Crockford's jsmin.c, which removes unnecessary whitespace from JavaScript files.",
+        "homepage": "https://github.com/mrclay/jsmin-php/",
+        "keywords": [
+            "compress",
+            "jsmin",
+            "minify"
+        ]
+    },
     {
         "name": "pradosoft/prado",
         "version": "4.0.1",
diff --git a/gui/baculum/framework/mrclay/jsmin-php/.editorconfig b/gui/baculum/framework/mrclay/jsmin-php/.editorconfig
new file mode 100644 (file)
index 0000000..09c6107
--- /dev/null
@@ -0,0 +1,19 @@
+# top-most EditorConfig file
+root = true
+
+[*]
+charset = utf-8
+end_of_line = lf
+
+; temporary
+trim_trailing_whitespace = false
+
+[*.php]
+indent_style = space
+indent_size = 4
+insert_final_newline = true
+
+[vendor/**]
+; Use editor default (possible autodetection).
+indent_style =
+indent_size =
diff --git a/gui/baculum/framework/mrclay/jsmin-php/.gitignore b/gui/baculum/framework/mrclay/jsmin-php/.gitignore
new file mode 100644 (file)
index 0000000..04e2064
--- /dev/null
@@ -0,0 +1,6 @@
+.idea/
+.DS_Store
+/vendor
+/composer.lock
+/tests/Resources/*/actual/*
+composer.phar
diff --git a/gui/baculum/framework/mrclay/jsmin-php/HISTORY.txt b/gui/baculum/framework/mrclay/jsmin-php/HISTORY.txt
new file mode 100644 (file)
index 0000000..ca682d4
--- /dev/null
@@ -0,0 +1,30 @@
+JSMin fixes
+
+Version 2.3.2
+    * Correctly identifies regexes following keywords with no space. E.g. return/regex/;
+
+Version 2.3.1
+    * Exception classes are PSR-0 loadable
+
+Version 2.3.0
+    * Removes leading UTF-8 BOM
+
+Version 2.2.0
+    * Fix handling of RegEx in certain situations in JSMin
+    * Fix bug in JSMin exceptions
+
+Version 2.1.6
+    * JSMin fixes
+
+Version 2.1.4
+    * JSMin won't choke on common Closure compiler syntaxes (i+ ++j)
+    * mbstring.func_overload usage is safer
+
+Version 2.1.2
+    * quote characters inside RegExp literals no longer cause exception
+
+Version 2.1.0
+    * JS: preserves IE conditional comments
+
+Version 1.0.1 (2007-05-05)
+    * Replaced old JSMin library with a much faster custom implementation.
diff --git a/gui/baculum/framework/mrclay/jsmin-php/LICENSE.txt b/gui/baculum/framework/mrclay/jsmin-php/LICENSE.txt
new file mode 100644 (file)
index 0000000..8f008ad
--- /dev/null
@@ -0,0 +1,26 @@
+Copyright (c) 2008 Ryan Grove <ryan@wonko.com>
+Copyright (c) 2008 Steve Clay <steve@mrclay.org>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of this project nor the names of its contributors may be
+    used to endorse or promote products derived from this software without
+    specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/gui/baculum/framework/mrclay/jsmin-php/README.devel.txt b/gui/baculum/framework/mrclay/jsmin-php/README.devel.txt
new file mode 100644 (file)
index 0000000..1d7ffb2
--- /dev/null
@@ -0,0 +1,10 @@
+The following steps can be performed to setup a development environment.
+
+Download composer.phar as described at https://getcomposer.org/download/
+
+Execute composer:
+  php composer.phar update
+
+Execute phpunit tests:
+  ./vendor/bin/phpunit
+
diff --git a/gui/baculum/framework/mrclay/jsmin-php/composer.json b/gui/baculum/framework/mrclay/jsmin-php/composer.json
new file mode 100644 (file)
index 0000000..fb00b97
--- /dev/null
@@ -0,0 +1,34 @@
+{
+       "name": "mrclay/jsmin-php",
+       "type": "library",
+       "description": "Provides a modified port of Douglas Crockford's jsmin.c, which removes unnecessary whitespace from JavaScript files.",
+    "keywords": ["jsmin", "minify", "compress"],
+       "homepage": "https://github.com/mrclay/jsmin-php/",
+       "license": "MIT",
+       "authors": [
+               {
+                       "name": "Stephen Clay",
+                       "email": "steve@mrclay.org",
+                       "role": "Developer"
+               },
+        {
+            "name": "Ryan Grove",
+            "email": "ryan@wonko.com",
+            "role": "Developer"
+        }
+       ],
+       "support": {
+               "email": "minify@googlegroups.com",
+               "issues": "https://github.com/mrclay/jsmin-php/issues"
+       },
+       "require": {
+               "php": ">=5.3.0",
+               "ext-pcre": "*"
+       },
+    "require-dev": {
+        "phpunit/phpunit": "4.2"
+    },
+       "autoload": {
+        "psr-0": {"JSMin\\": "src/"}
+       }
+}
diff --git a/gui/baculum/framework/mrclay/jsmin-php/phpunit.xml.dist b/gui/baculum/framework/mrclay/jsmin-php/phpunit.xml.dist
new file mode 100644 (file)
index 0000000..37f3bad
--- /dev/null
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<phpunit backupGlobals="false"
+         backupStaticAttributes="false"
+         colors="true"
+         convertErrorsToExceptions="true"
+         convertNoticesToExceptions="true"
+         convertWarningsToExceptions="true"
+         processIsolation="false"
+         bootstrap="tests/bootstrap.php"
+        >
+    <testsuites>
+        <testsuite name="JSMin Test Suite">
+            <directory>./tests/</directory>
+        </testsuite>
+    </testsuites>
+
+    <filter>
+        <whitelist>
+            <directory>./</directory>
+            <exclude>
+                <directory>./tests</directory>
+                <directory>./vendor</directory>
+            </exclude>
+        </whitelist>
+    </filter>
+</phpunit>
\ No newline at end of file
diff --git a/gui/baculum/framework/mrclay/jsmin-php/src/JSMin/JSMin.php b/gui/baculum/framework/mrclay/jsmin-php/src/JSMin/JSMin.php
new file mode 100644 (file)
index 0000000..bbf7c50
--- /dev/null
@@ -0,0 +1,457 @@
+<?php
+
+namespace JSMin;
+
+/**
+ * JSMin.php - modified PHP implementation of Douglas Crockford's JSMin.
+ *
+ * <code>
+ * $minifiedJs = JSMin::minify($js);
+ * </code>
+ *
+ * This is a modified port of jsmin.c. Improvements:
+ *
+ * Does not choke on some regexp literals containing quote characters. E.g. /'/
+ *
+ * Spaces are preserved after some add/sub operators, so they are not mistakenly
+ * converted to post-inc/dec. E.g. a + ++b -> a+ ++b
+ *
+ * Preserves multi-line comments that begin with /*!
+ *
+ * PHP 5 or higher is required.
+ *
+ * Permission is hereby granted to use this version of the library under the
+ * same terms as jsmin.c, which has the following license:
+ *
+ * --
+ * Copyright (c) 2002 Douglas Crockford  (www.crockford.com)
+ *
+ * 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 shall be used for Good, not Evil.
+ *
+ * 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.
+ * --
+ *
+ * @package JSMin
+ * @author Ryan Grove <ryan@wonko.com> (PHP port)
+ * @author Steve Clay <steve@mrclay.org> (modifications + cleanup)
+ * @author Andrea Giammarchi <http://www.3site.eu> (spaceBeforeRegExp)
+ * @copyright 2002 Douglas Crockford <douglas@crockford.com> (jsmin.c)
+ * @copyright 2008 Ryan Grove <ryan@wonko.com> (PHP port)
+ * @license http://opensource.org/licenses/mit-license.php MIT License
+ * @link http://code.google.com/p/jsmin-php/
+ */
+class JSMin {
+    const ORD_LF            = 10;
+    const ORD_SPACE         = 32;
+    const ACTION_KEEP_A     = 1;
+    const ACTION_DELETE_A   = 2;
+    const ACTION_DELETE_A_B = 3;
+
+    protected $a           = "\n";
+    protected $b           = '';
+    protected $input       = '';
+    protected $inputIndex  = 0;
+    protected $inputLength = 0;
+    protected $lookAhead   = null;
+    protected $output      = '';
+    protected $lastByteOut  = '';
+    protected $keptComment = '';
+
+    /**
+     * Minify Javascript.
+     *
+     * @param string $js Javascript to be minified
+     *
+     * @return string
+     */
+    public static function minify($js)
+    {
+        $jsmin = new JSMin($js);
+        return $jsmin->min();
+    }
+
+    /**
+     * @param string $input
+     */
+    public function __construct($input)
+    {
+        $this->input = $input;
+    }
+
+    /**
+     * Perform minification, return result
+     *
+     * @return string
+     */
+    public function min()
+    {
+        if ($this->output !== '') { // min already run
+            return $this->output;
+        }
+
+        $mbIntEnc = null;
+        if (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) {
+            $mbIntEnc = mb_internal_encoding();
+            mb_internal_encoding('8bit');
+        }
+
+        if (isset($this->input[0]) && $this->input[0] === "\xef") {
+            $this->input = substr($this->input, 3);
+        }
+
+        $this->input = str_replace("\r\n", "\n", $this->input);
+        $this->inputLength = strlen($this->input);
+
+        $this->action(self::ACTION_DELETE_A_B);
+
+        while ($this->a !== null) {
+            // determine next command
+            $command = self::ACTION_KEEP_A; // default
+            if ($this->a === ' ') {
+                if (($this->lastByteOut === '+' || $this->lastByteOut === '-')
+                        && ($this->b === $this->lastByteOut)) {
+                    // Don't delete this space. If we do, the addition/subtraction
+                    // could be parsed as a post-increment
+                } elseif (! $this->isAlphaNum($this->b)) {
+                    $command = self::ACTION_DELETE_A;
+                }
+            } elseif ($this->a === "\n") {
+                if ($this->b === ' ') {
+                    $command = self::ACTION_DELETE_A_B;
+
+                    // in case of mbstring.func_overload & 2, must check for null b,
+                    // otherwise mb_strpos will give WARNING
+                } elseif ($this->b === null
+                          || (false === strpos('{[(+-!~', $this->b)
+                              && ! $this->isAlphaNum($this->b))) {
+                    $command = self::ACTION_DELETE_A;
+                }
+            } elseif (! $this->isAlphaNum($this->a)) {
+                if ($this->b === ' '
+                    || ($this->b === "\n"
+                        && (false === strpos('}])+-"\'', $this->a)))) {
+                    $command = self::ACTION_DELETE_A_B;
+                }
+            }
+            $this->action($command);
+        }
+        $this->output = trim($this->output);
+
+        if ($mbIntEnc !== null) {
+            mb_internal_encoding($mbIntEnc);
+        }
+        return $this->output;
+    }
+
+    /**
+     * ACTION_KEEP_A = Output A. Copy B to A. Get the next B.
+     * ACTION_DELETE_A = Copy B to A. Get the next B.
+     * ACTION_DELETE_A_B = Get the next B.
+     *
+     * @param int $command
+     * @throws UnterminatedRegExpException|UnterminatedStringException
+     */
+    protected function action($command)
+    {
+        // make sure we don't compress "a + ++b" to "a+++b", etc.
+        if ($command === self::ACTION_DELETE_A_B
+            && $this->b === ' '
+            && ($this->a === '+' || $this->a === '-')) {
+            // Note: we're at an addition/substraction operator; the inputIndex
+            // will certainly be a valid index
+            if ($this->input[$this->inputIndex] === $this->a) {
+                // This is "+ +" or "- -". Don't delete the space.
+                $command = self::ACTION_KEEP_A;
+            }
+        }
+
+        switch ($command) {
+            case self::ACTION_KEEP_A: // 1
+                $this->output .= $this->a;
+
+                if ($this->keptComment) {
+                    $this->output = rtrim($this->output, "\n");
+                    $this->output .= $this->keptComment;
+                    $this->keptComment = '';
+                }
+
+                $this->lastByteOut = $this->a;
+
+                // fallthrough intentional
+            case self::ACTION_DELETE_A: // 2
+                $this->a = $this->b;
+                if ($this->a === "'" || $this->a === '"' || $this->a === '`') { // string/template literal
+                    $delimiter = $this->a;
+                    $str = $this->a; // in case needed for exception
+                    for(;;) {
+                        $this->output .= $this->a;
+                        $this->lastByteOut = $this->a;
+
+                        $this->a = $this->get();
+                        if ($this->a === $this->b) { // end quote
+                            break;
+                        }
+                        if ($delimiter === '`' && $this->a === "\n") {
+                            // leave the newline
+                        } elseif ($this->isEOF($this->a)) {
+                            $byte = $this->inputIndex - 1;
+                            throw new UnterminatedStringException(
+                                "JSMin: Unterminated String at byte {$byte}: {$str}");
+                        }
+                        $str .= $this->a;
+                        if ($this->a === '\\') {
+                            $this->output .= $this->a;
+                            $this->lastByteOut = $this->a;
+
+                            $this->a = $this->get();
+                            $str .= $this->a;
+                        }
+                    }
+                }
+
+                // fallthrough intentional
+            case self::ACTION_DELETE_A_B: // 3
+                $this->b = $this->next();
+                if ($this->b === '/' && $this->isRegexpLiteral()) {
+                    $this->output .= $this->a . $this->b;
+                    $pattern = '/'; // keep entire pattern in case we need to report it in the exception
+                    for(;;) {
+                        $this->a = $this->get();
+                        $pattern .= $this->a;
+                        if ($this->a === '[') {
+                            for(;;) {
+                                $this->output .= $this->a;
+                                $this->a = $this->get();
+                                $pattern .= $this->a;
+                                if ($this->a === ']') {
+                                    break;
+                                }
+                                if ($this->a === '\\') {
+                                    $this->output .= $this->a;
+                                    $this->a = $this->get();
+                                    $pattern .= $this->a;
+                                }
+                                if ($this->isEOF($this->a)) {
+                                    throw new UnterminatedRegExpException(
+                                        "JSMin: Unterminated set in RegExp at byte "
+                                            . $this->inputIndex .": {$pattern}");
+                                }
+                            }
+                        }
+
+                        if ($this->a === '/') { // end pattern
+                            break; // while (true)
+                        } elseif ($this->a === '\\') {
+                            $this->output .= $this->a;
+                            $this->a = $this->get();
+                            $pattern .= $this->a;
+                        } elseif ($this->isEOF($this->a)) {
+                            $byte = $this->inputIndex - 1;
+                            throw new UnterminatedRegExpException(
+                                "JSMin: Unterminated RegExp at byte {$byte}: {$pattern}");
+                        }
+                        $this->output .= $this->a;
+                        $this->lastByteOut = $this->a;
+                    }
+                    $this->b = $this->next();
+                }
+            // end case ACTION_DELETE_A_B
+        }
+    }
+
+    /**
+     * @return bool
+     */
+    protected function isRegexpLiteral()
+    {
+        if (false !== strpos("(,=:[!&|?+-~*{;", $this->a)) {
+            // we can't divide after these tokens
+            return true;
+        }
+
+        // check if first non-ws token is "/" (see starts-regex.js)
+        $length = strlen($this->output);
+        if ($this->a === ' ' || $this->a === "\n") {
+            if ($length < 2) { // weird edge case
+                return true;
+            }
+        }
+
+        // if the "/" follows a keyword, it must be a regexp, otherwise it's best to assume division
+
+        $subject = $this->output . trim($this->a);
+        if (!preg_match('/(?:case|else|in|return|typeof)$/', $subject, $m)) {
+            // not a keyword
+            return false;
+        }
+
+        // can't be sure it's a keyword yet (see not-regexp.js)
+        $charBeforeKeyword = substr($subject, 0 - strlen($m[0]) - 1, 1);
+        if ($this->isAlphaNum($charBeforeKeyword)) {
+            // this is really an identifier ending in a keyword, e.g. "xreturn"
+            return false;
+        }
+
+        // it's a regexp. Remove unneeded whitespace after keyword
+        if ($this->a === ' ' || $this->a === "\n") {
+            $this->a = '';
+        }
+
+        return true;
+    }
+
+    /**
+     * Return the next character from stdin. Watch out for lookahead. If the character is a control character,
+     * translate it to a space or linefeed.
+     *
+     * @return string
+     */
+    protected function get()
+    {
+        $c = $this->lookAhead;
+        $this->lookAhead = null;
+        if ($c === null) {
+            // getc(stdin)
+            if ($this->inputIndex < $this->inputLength) {
+                $c = $this->input[$this->inputIndex];
+                $this->inputIndex += 1;
+            } else {
+                $c = null;
+            }
+        }
+        if (ord($c) >= self::ORD_SPACE || $c === "\n" || $c === null) {
+            return $c;
+        }
+        if ($c === "\r") {
+            return "\n";
+        }
+        return ' ';
+    }
+
+    /**
+     * Does $a indicate end of input?
+     *
+     * @param string $a
+     * @return bool
+     */
+    protected function isEOF($a)
+    {
+        return ord($a) <= self::ORD_LF;
+    }
+
+    /**
+     * Get next char (without getting it). If is ctrl character, translate to a space or newline.
+     *
+     * @return string
+     */
+    protected function peek()
+    {
+        $this->lookAhead = $this->get();
+        return $this->lookAhead;
+    }
+
+    /**
+     * Return true if the character is a letter, digit, underscore, dollar sign, or non-ASCII character.
+     *
+     * @param string $c
+     *
+     * @return bool
+     */
+    protected function isAlphaNum($c)
+    {
+        return (preg_match('/^[a-z0-9A-Z_\\$\\\\]$/', $c) || ord($c) > 126);
+    }
+
+    /**
+     * Consume a single line comment from input (possibly retaining it)
+     */
+    protected function consumeSingleLineComment()
+    {
+        $comment = '';
+        while (true) {
+            $get = $this->get();
+            $comment .= $get;
+            if (ord($get) <= self::ORD_LF) { // end of line reached
+                // if IE conditional comment
+                if (preg_match('/^\\/@(?:cc_on|if|elif|else|end)\\b/', $comment)) {
+                    $this->keptComment .= "/{$comment}";
+                }
+                return;
+            }
+        }
+    }
+
+    /**
+     * Consume a multiple line comment from input (possibly retaining it)
+     *
+     * @throws UnterminatedCommentException
+     */
+    protected function consumeMultipleLineComment()
+    {
+        $this->get();
+        $comment = '';
+        for(;;) {
+            $get = $this->get();
+            if ($get === '*') {
+                if ($this->peek() === '/') { // end of comment reached
+                    $this->get();
+                    if (0 === strpos($comment, '!')) {
+                        // preserved by YUI Compressor
+                        if (!$this->keptComment) {
+                            // don't prepend a newline if two comments right after one another
+                            $this->keptComment = "\n";
+                        }
+                        $this->keptComment .= "/*!" . substr($comment, 1) . "*/\n";
+                    } else if (preg_match('/^@(?:cc_on|if|elif|else|end)\\b/', $comment)) {
+                        // IE conditional
+                        $this->keptComment .= "/*{$comment}*/";
+                    }
+                    return;
+                }
+            } elseif ($get === null) {
+                throw new UnterminatedCommentException(
+                    "JSMin: Unterminated comment at byte {$this->inputIndex}: /*{$comment}");
+            }
+            $comment .= $get;
+        }
+    }
+
+    /**
+     * Get the next character, skipping over comments. Some comments may be preserved.
+     *
+     * @return string
+     */
+    protected function next()
+    {
+        $get = $this->get();
+        if ($get === '/') {
+            switch ($this->peek()) {
+                case '/':
+                    $this->consumeSingleLineComment();
+                    $get = "\n";
+                    break;
+                case '*':
+                    $this->consumeMultipleLineComment();
+                    $get = ' ';
+                    break;
+            }
+        }
+        return $get;
+    }
+}
diff --git a/gui/baculum/framework/mrclay/jsmin-php/src/JSMin/UnterminatedCommentException.php b/gui/baculum/framework/mrclay/jsmin-php/src/JSMin/UnterminatedCommentException.php
new file mode 100644 (file)
index 0000000..c0bd2f7
--- /dev/null
@@ -0,0 +1,6 @@
+<?php
+
+namespace JSMin;
+
+class UnterminatedCommentException extends \Exception {
+}
diff --git a/gui/baculum/framework/mrclay/jsmin-php/src/JSMin/UnterminatedRegExpException.php b/gui/baculum/framework/mrclay/jsmin-php/src/JSMin/UnterminatedRegExpException.php
new file mode 100644 (file)
index 0000000..aa3aae8
--- /dev/null
@@ -0,0 +1,6 @@
+<?php
+
+namespace JSMin;
+
+class UnterminatedRegExpException extends \Exception {
+}
diff --git a/gui/baculum/framework/mrclay/jsmin-php/src/JSMin/UnterminatedStringException.php b/gui/baculum/framework/mrclay/jsmin-php/src/JSMin/UnterminatedStringException.php
new file mode 100644 (file)
index 0000000..a31a3ce
--- /dev/null
@@ -0,0 +1,6 @@
+<?php
+
+namespace JSMin;
+
+class UnterminatedStringException extends \Exception {
+}
diff --git a/gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/expected/before.js b/gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/expected/before.js
new file mode 100644 (file)
index 0000000..bccd725
--- /dev/null
@@ -0,0 +1,27 @@
+/*! is.js
+
+ (c) 2001 Douglas Crockford
+ 2001 June 3
+*/
+var is={ie:navigator.appName=='Microsoft Internet Explorer',java:navigator.javaEnabled(),ns:navigator.appName=='Netscape',ua:navigator.userAgent.toLowerCase(),version:parseFloat(navigator.appVersion.substr(21))||parseFloat(navigator.appVersion),win:navigator.platform=='Win32'}
+/*!*
+ * preserve this comment, too
+ */
+is.mac=is.ua.indexOf('mac')>=0;if(is.ua.indexOf('opera')>=0){is.ie=is.ns=false;is.opera=true;}
+if(is.ua.indexOf('gecko')>=0){is.ie=is.ns=false;is.gecko=true;}/*@cc_on
+   /*@if (@_win32)
+    if (is.ie && is.win)
+        document.write("PASS: IE/win honored conditional comment.<br>");
+   @else @*/if(is.ie&&is.win)
+document.write("FAIL: IE/win did not honor multi-line conditional comment.<br>");else
+document.write("PASS: Non-IE/win browser ignores multi-line conditional comment.<br>");/*@end
+@*/var recognizesCondComm=true;//@cc_on/*
+recognizesCondComm=false;//@cc_on*/
+if((is.ie&&is.win)==recognizesCondComm)
+document.write("PASS: IE/win honored single-line conditional comment.<br>");else
+document.write("FAIL: Non-IE/win browser did not ignore single-line conditional comment.<br>");//@cc_on/*
+//@cc_on*/
+//@cc_on/*
+'hello';
+/*!* preserved */
+/*!* preserved */
\ No newline at end of file
diff --git a/gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/expected/condcomm.js b/gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/expected/condcomm.js
new file mode 100644 (file)
index 0000000..5c79831
--- /dev/null
@@ -0,0 +1,6 @@
+var isWin;/*@cc_on
+    @if (@_win32)
+        isWin = true;
+    @else @*/isWin=false;/*@end
+@*/isWin=/*@cc_on!*/!1;var recognizesCondComm=true;//@cc_on/*
+recognizesCondComm=false;//@cc_on*/
\ No newline at end of file
diff --git a/gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/expected/es6-literal.js b/gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/expected/es6-literal.js
new file mode 100644 (file)
index 0000000..79d0a1f
--- /dev/null
@@ -0,0 +1,2 @@
+`line
+break`+`he  llo`;foo`hel( '');lo`;`he\nl\`lo`;(`he${one + two}`)
\ No newline at end of file
diff --git a/gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/expected/issue144.js b/gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/expected/issue144.js
new file mode 100644 (file)
index 0000000..e339d0a
--- /dev/null
@@ -0,0 +1 @@
+a/++b;a*--b;a++-b;a+--b;a-++b;a+-b;a+ ++b;a+--b;a- --b;
\ No newline at end of file
diff --git a/gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/expected/issue256.js b/gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/expected/issue256.js
new file mode 100644 (file)
index 0000000..eb1b0d6
--- /dev/null
@@ -0,0 +1,2 @@
+!function(){}(window)
+!function(){}(window)
\ No newline at end of file
diff --git a/gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/expected/keyword-regex.js b/gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/expected/keyword-regex.js
new file mode 100644 (file)
index 0000000..02ec79e
--- /dev/null
@@ -0,0 +1 @@
+return/return/;
\ No newline at end of file
diff --git a/gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/expected/not-regexp.js b/gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/expected/not-regexp.js
new file mode 100644 (file)
index 0000000..a7516fb
--- /dev/null
@@ -0,0 +1 @@
+!function(){return xreturn/foo}();!function(){return xtypeof/foo}();
\ No newline at end of file
diff --git a/gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/expected/regexes.js b/gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/expected/regexes.js
new file mode 100644 (file)
index 0000000..d7d5b4e
--- /dev/null
@@ -0,0 +1,2 @@
+function testIssue74(){return/'/;}
+!function(s){return/^[£$€?.]/.test(s);}();typeof/ ' /;x=/ [/] /;1/foo;(2)/foo;function(){return/foo/};function(){return typeof/foo/};
\ No newline at end of file
diff --git a/gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/expected/starts-regex.js b/gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/expected/starts-regex.js
new file mode 100644 (file)
index 0000000..2623624
--- /dev/null
@@ -0,0 +1 @@
+/return/.test(bar);
\ No newline at end of file
diff --git a/gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/expected/token-regexp.js b/gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/expected/token-regexp.js
new file mode 100644 (file)
index 0000000..13f263c
--- /dev/null
@@ -0,0 +1 @@
+typeof[/return/];
\ No newline at end of file
diff --git a/gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/input/before.js b/gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/input/before.js
new file mode 100644 (file)
index 0000000..ae96568
--- /dev/null
@@ -0,0 +1,66 @@
+/*! is.js
+
+ (c) 2001 Douglas Crockford
+ 2001 June 3
+*/
+
+// is
+
+// The -is- object is used to identify the browser.  Every browser edition
+// identifies itself, but there is no standard way of doing it, and some of
+// the identification is deceptive. This is because the authors of web
+// browsers are liars. For example, Microsoft's IE browsers claim to be
+// Mozilla 4. Netscape 6 claims to be version 5.
+
+var is = {
+    ie:      navigator.appName == 'Microsoft Internet Explorer',
+    java:    navigator.javaEnabled(),
+    ns:      navigator.appName == 'Netscape',
+    ua:      navigator.userAgent.toLowerCase(),
+    version: parseFloat(navigator.appVersion.substr(21)) ||
+             parseFloat(navigator.appVersion),
+    win:     navigator.platform == 'Win32'
+}
+/*!*
+ * preserve this comment, too
+ */
+is.mac = is.ua.indexOf('mac') >= 0;
+if (is.ua.indexOf('opera') >= 0) {
+    is.ie = is.ns = false;
+    is.opera = true;
+}
+if (is.ua.indexOf('gecko') >= 0) {
+    is.ie = is.ns = false;
+    is.gecko = true;
+}
+
+/*@cc_on
+   /*@if (@_win32)
+    if (is.ie && is.win)
+        document.write("PASS: IE/win honored conditional comment.<br>");
+   @else @*/
+    if (is.ie && is.win)
+        document.write("FAIL: IE/win did not honor multi-line conditional comment.<br>");
+    else 
+        document.write("PASS: Non-IE/win browser ignores multi-line conditional comment.<br>");
+   /*@end
+@*/
+
+var recognizesCondComm = true;
+//@cc_on/*
+recognizesCondComm = false;
+//@cc_on*/
+
+if ((is.ie && is.win) == recognizesCondComm)
+    document.write("PASS: IE/win honored single-line conditional comment.<br>");
+else 
+    document.write("FAIL: Non-IE/win browser did not ignore single-line conditional comment.<br>");
+
+// hello
+//@cc_on/*
+// world
+//@cc_on*/
+//@cc_on/*
+'hello';
+/*!* preserved */
+/*!* preserved */
\ No newline at end of file
diff --git a/gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/input/condcomm.js b/gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/input/condcomm.js
new file mode 100644 (file)
index 0000000..28aa126
--- /dev/null
@@ -0,0 +1,14 @@
+var isWin;
+/*@cc_on
+    @if (@_win32)
+        isWin = true;
+    @else @*/ isWin = false;
+   /*@end
+@*/
+
+isWin = /*@cc_on!*/!1;
+
+var recognizesCondComm = true;
+//@cc_on/*
+recognizesCondComm = false;
+//@cc_on*/
diff --git a/gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/input/es6-literal.js b/gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/input/es6-literal.js
new file mode 100644 (file)
index 0000000..57aea26
--- /dev/null
@@ -0,0 +1,2 @@
+`line
+break` + `he  llo`; foo`hel( '');lo`; `he\nl\`lo`; (`he${one + two}`)
diff --git a/gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/input/issue144.js b/gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/input/issue144.js
new file mode 100644 (file)
index 0000000..204911d
--- /dev/null
@@ -0,0 +1,9 @@
+a    /  ++b;
+a    *  --b;
+a++  -  b;
+a    +  --b;
+a    -  ++b;
+a    +  -b;
+a    +  ++b;
+a    +  --b;
+a    -  --b;
\ No newline at end of file
diff --git a/gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/input/issue256.js b/gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/input/issue256.js
new file mode 100644 (file)
index 0000000..519a52f
--- /dev/null
@@ -0,0 +1,3 @@
+!function(){}(window)
+
+!function(){}(window)
\ No newline at end of file
diff --git a/gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/input/keyword-regex.js b/gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/input/keyword-regex.js
new file mode 100644 (file)
index 0000000..36e2fce
--- /dev/null
@@ -0,0 +1,3 @@
+// this is specifically designed so that, if the first "/" is misinterpreted as division,
+// then "/;" will be interpreted as an incomplete regexp, causing a failing test.
+return /return/;
\ No newline at end of file
diff --git a/gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/input/not-regexp.js b/gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/input/not-regexp.js
new file mode 100644 (file)
index 0000000..9da5082
--- /dev/null
@@ -0,0 +1,3 @@
+!function(){return xreturn/foo}();
+
+!function(){return xtypeof/foo}();
diff --git a/gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/input/regexes.js b/gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/input/regexes.js
new file mode 100644 (file)
index 0000000..57e083e
--- /dev/null
@@ -0,0 +1,24 @@
+function testIssue74() {
+    return /'/;
+}
+
+!function(s) {
+    return /^[£$€?.]/.test(s);
+}();
+
+typeof  
+    / ' /;
+
+x = / [/] /;
+
+1
+
+/ foo;
+
+(2)
+
+/ foo;
+
+function(){return/foo/};
+
+function(){return typeof/foo/};
diff --git a/gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/input/starts-regex.js b/gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/input/starts-regex.js
new file mode 100644 (file)
index 0000000..997b905
--- /dev/null
@@ -0,0 +1,3 @@
+// this is specifically designed so that, if the first "/" is misinterpreted as division,
+// then "/.test(bar);" will be interpreted as an incomplete regexp, causing a failing test.
+/return/.test(bar);
\ No newline at end of file
diff --git a/gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/input/token-regexp.js b/gui/baculum/framework/mrclay/jsmin-php/tests/Resources/minify/input/token-regexp.js
new file mode 100644 (file)
index 0000000..917bd20
--- /dev/null
@@ -0,0 +1,3 @@
+// this is specifically designed so that, if the first "/" is misinterpreted as division,
+// then "/[;" will be interpreted as an incomplete regexp, causing a failing test.
+typeof [/return/];
\ No newline at end of file
diff --git a/gui/baculum/framework/mrclay/jsmin-php/tests/Tests/JSMin/JSMinTest.php b/gui/baculum/framework/mrclay/jsmin-php/tests/Tests/JSMin/JSMinTest.php
new file mode 100644 (file)
index 0000000..90b8aac
--- /dev/null
@@ -0,0 +1,168 @@
+<?php
+
+namespace Tests\JSMin;
+
+use JSMin\JSMin;
+
+/**
+ * Copyright (c) 2009, Robert Hafner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the Stash Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Robert Hafner BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+class JSMinTest extends \PHPUnit_Framework_TestCase {
+
+       /**
+        * @group minify
+        * @dataProvider minifyProvider
+        */
+       public function testMinify($testName, $input, $expected, $actualFile)
+       {
+               $actual = JSMin::minify($input);
+               if ($actual !== $expected && is_writable(dirname($actualFile))) {
+                       file_put_contents($actualFile, $actual);
+               }
+               $this->assertEquals($expected, $actual, 'Running Minify Test: ' . $testName);
+       }
+
+       public function testWhitespace() {
+               $this->assertEquals("hello;", JSMin::minify("\r\n\r\nhello;\r\n"));
+       }
+
+       public function testBomRemoval() {
+        $this->assertEquals("hello;", JSMin::minify("\xEF\xBB\xBFhello;"));
+       }
+
+    public function testFuncOverload() {
+        if (!function_exists('mb_strlen') || !((int)ini_get('mbstring.func_overload') & 2)) {
+            $this->markTestIncomplete('Cannot be tested unless mbstring.func_overload is used');
+            return;
+        }
+
+        $input = 'function(s) {  return /^[£$€?.]/.test(s); }';
+        $expected = 'function(s){return/^[£$€?.]/.test(s);}';
+        $this->assertEquals($expected, JSMin::minify($input));
+    }
+
+    /**
+     * @dataProvider exceptionProvider
+     */
+    public function testExpections($input, $label, $expClass, $expMessage) {
+        $eClass = $eMsg = '';
+        try {
+            JSMin::minify($input);
+        } catch (\Exception $e) {
+            $eClass = get_class($e);
+            $eMsg = $e->getMessage();
+        }
+        $this->assertTrue(
+            $eClass === $expClass && $eMsg === $expMessage,
+            'JSMin : throw on ' . $label
+        );
+    }
+
+    public function exceptionProvider() {
+        return array(
+            array(
+                '"Hello'
+                ,'Unterminated String'
+                ,'JSMin\\UnterminatedStringException'
+                ,"JSMin: Unterminated String at byte 5: \"Hello"),
+            array(
+                "return /regexp\n}"
+                ,'Unterminated RegExp'
+                ,'JSMin\\UnterminatedRegExpException'
+                ,"JSMin: Unterminated RegExp at byte 14: /regexp\n"),
+            array(
+                "return/regexp\n}"
+                ,'Unterminated RegExp'
+                ,'JSMin\\UnterminatedRegExpException'
+                ,"JSMin: Unterminated RegExp at byte 13: /regexp\n"),
+            array(
+                ";return/regexp\n}"
+                ,'Unterminated RegExp'
+                ,'JSMin\\UnterminatedRegExpException'
+                ,"JSMin: Unterminated RegExp at byte 14: /regexp\n"),
+            array(
+                ";return /regexp\n}"
+                ,'Unterminated RegExp'
+                ,'JSMin\\UnterminatedRegExpException'
+                ,"JSMin: Unterminated RegExp at byte 15: /regexp\n"),
+            array(
+                "typeof/regexp\n}"
+                ,'Unterminated RegExp'
+                ,'JSMin\\UnterminatedRegExpException'
+                ,"JSMin: Unterminated RegExp at byte 13: /regexp\n"),
+            array(
+                "/* Comment "
+                ,'Unterminated Comment'
+                ,'JSMin\\UnterminatedCommentException'
+                ,"JSMin: Unterminated comment at byte 11: /* Comment "),
+        );
+    }
+
+       /**
+        * This function loads all of the test cases from the specified group.
+        * Groups are created simply by populating the appropriate directories:
+        *
+        *    /tests/Resources/GROUPNAME/input/
+        *    /tests/Resources/GROUPNAME/output/
+        *
+        * Each test case should have two identically named files, with the raw
+        * javascript going in the test folder and the expected results to be in
+        * the output folder.
+        *
+        * @param $group string
+        * @return array
+        */
+       public function getTestFiles($group)
+       {
+               $baseDir = __DIR__ . '/../../Resources/' . $group . '/';
+               $testDir = $baseDir . 'input/';
+               $expectDir = $baseDir . 'expected/';
+               $actualDir = $baseDir . 'actual/';
+
+               $returnData = array();
+
+               $testFiles = scandir($testDir);
+               foreach ($testFiles as $testFile) {
+                       if (substr($testFile, -3) !== '.js' || !file_exists(($expectDir . $testFile))) {
+                               continue;
+                       }
+
+                       $testInput = file_get_contents($testDir . $testFile);
+                       $expectedOutput = file_get_contents($expectDir . $testFile);
+                       $actualFile = $actualDir . $testFile;
+
+                       $returnData[] = array($testFile, $testInput, $expectedOutput, $actualFile);
+               }
+
+               return $returnData;
+       }
+
+       public function minifyProvider()
+       {
+               return $this->getTestFiles('minify');
+       }
+}
diff --git a/gui/baculum/framework/mrclay/jsmin-php/tests/bootstrap.php b/gui/baculum/framework/mrclay/jsmin-php/tests/bootstrap.php
new file mode 100644 (file)
index 0000000..b3d9bbc
--- /dev/null
@@ -0,0 +1 @@
+<?php
diff --git a/gui/baculum/framework/mrclay/jsmin-php/web/README.txt b/gui/baculum/framework/mrclay/jsmin-php/web/README.txt
new file mode 100644 (file)
index 0000000..e5e6e3a
--- /dev/null
@@ -0,0 +1,2 @@
+This can be placed in webroot to allow easy direct testing of JSMin.
+
diff --git a/gui/baculum/framework/mrclay/jsmin-php/web/index.php b/gui/baculum/framework/mrclay/jsmin-php/web/index.php
new file mode 100644 (file)
index 0000000..a829ad2
--- /dev/null
@@ -0,0 +1,92 @@
+<?php
+
+require __DIR__ . '/../vendor/autoload.php';
+
+function h($txt) {
+    return htmlspecialchars($txt, ENT_QUOTES, 'UTF-8');
+}
+
+$tpl = array();
+
+if (isset($_POST['textIn'])) {
+    $textIn = str_replace("\r\n", "\n", $_POST['textIn']);
+
+    $tpl['inBytes'] = strlen($textIn);
+    $startTime = microtime(true);
+    try {
+        $tpl['output'] = \JSMin\JSMin::minify($textIn);
+    } catch (Exception $e) {
+        $tpl['exceptionMsg'] = getExceptionMsg($e, $textIn);
+        $tpl['output'] = $textIn;
+        sendPage($tpl);
+    }
+    $tpl['time'] = microtime(true) - $startTime;
+    $tpl['outBytes'] = strlen($tpl['output']);
+}
+
+sendPage($tpl);
+
+
+/**
+ * @param Exception $e
+ * @param string $input
+ * @return string HTML
+ */
+function getExceptionMsg(Exception $e, $input) {
+    $msg = "<p>" . h($e->getMessage()) . "</p>";
+
+    if (0 !== strpos(get_class($e), 'JSMin\\Unterminated')
+        || !preg_match('~byte (\d+)~', $e->getMessage(), $m)) {
+        return $msg;
+    }
+
+    $msg .= "<pre>";
+    if ($m[1] > 200) {
+        $msg .= h(substr($input, ($m[1] - 200), 200));
+    } else {
+        $msg .= h(substr($input, 0, $m[1]));
+    }
+    $highlighted = isset($input[$m[1]]) ? h($input[$m[1]]) : '&#9220;';
+    if ($highlighted === "\n") {
+        $highlighted = "&#9166;\n";
+    }
+    $msg .= "<span style='background:#c00;color:#fff'>$highlighted</span>";
+    $msg .= h(substr($input, $m[1] + 1, 200)) . "</span></pre>";
+
+    return $msg;
+}
+
+/**
+ * Draw page
+ *
+ * @param array $vars
+ */
+function sendPage($vars) {
+    header('Content-Type: text/html; charset=utf-8');
+
+    ?>
+    <!DOCTYPE html><head><title>JSMin</title></head>
+    <?php
+    if (isset($vars['exceptionMsg'])) {
+        echo $vars['exceptionMsg'];
+    }
+    if (isset($vars['time'])) {
+        echo "
+<table>
+    <tr><th>Bytes in</th><td>{$vars['inBytes']} (after line endings normalized to <code>\\n</code>)</td></tr>
+    <tr><th>Bytes out</th><td>{$vars['outBytes']} (reduced " . round(100 - (100 * $vars['outBytes'] / $vars['inBytes'])) . "%)</td></tr>
+    <tr><th>Time (s)</th><td>" . round($vars['time'], 5) . "</td></tr>
+</table>
+    ";
+    }
+    ?>
+    <form action="?2" method="post">
+    <p><label>Content<br><textarea name="textIn" cols="80" rows="35" style="width:99%"><?php
+                if (isset($vars['output'])) {
+                    echo h($vars['output']);
+                }
+                ?></textarea></label></p>
+    <p><input type="submit" name="method" value="JSMin::minify()"></p>
+    </form><?php
+    exit;
+}