<?php namespace HashOver;

// Copyright (C) 2015-2021 Jacob Barkdull
// This file is part of HashOver.
//
// HashOver is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// HashOver is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with HashOver. If not, see <http://www.gnu.org/licenses/>.


class JavaScriptMinifier
{
// Array for locking minification
protected $lock = array (
'status' => false,
'char' => ''
);

// JavaScript minification function
public function minify ($js, $level = 4)
{
if ($level <= 0) {
return $js;
}

if ($level >= 1) {
// Remove single-line code comments
$js = preg_replace ('/^[\t ]*?\/\/.*\s?/m', '', $js);

// Remove end-of-line code comments
$js = preg_replace ('/([\s;})]+)\/\/.*/m', '\\1', $js);

// Remove multi-line code comments
$js = preg_replace ('/\/\*[\s\S]*?\*\//', '', $js);
}

if ($level >= 2) {
// Remove leading whitespace
$js = preg_replace ('/^\s*/m', '', $js);

// Replace multiple tabs with a single space
$js = preg_replace ('/\t+/m', ' ', $js);
}

if ($level >= 3) {
// Remove newlines
$js = preg_replace ('/[\r\n]+/', '', $js);
}

if ($level >= 4) {
// Split input JavaScript by single and double quotes
$js_substrings = preg_split ('/([\'"])/', $js, -1, PREG_SPLIT_DELIM_CAPTURE);

// Empty variable for minified JavaScript
$js = '';

foreach ($js_substrings as $substring) {
// Check if substring is split delimiter
if ($substring === '\'' or $substring === '"') {
// If so, check whether minification is unlocked
if ($this->lock['status'] === false) {
// If so, lock it and set lock character
$this->lock['status'] = true;
$this->lock['char'] = $substring;
} else {
// If not, check if substring is lock character
if ($substring === $this->lock['char']) {
// If so, unlock minification
$this->lock['status'] = false;
$this->lock['char'] = '';
}
}

// Add substring to minified output
$js .= $substring;

continue;
}

// Minify current substring if minification is unlocked
if ($this->lock['status'] === false) {
// Remove unnecessary semicolons
$substring = str_replace (';}', '}', $substring);

// Remove spaces round operators
$substring = preg_replace ('/ *([<>=+\-!\|{(},;&:?]+) */', '\\1', $substring);
}

// Add substring to minified output
$js .= $substring;
}
}

// Create URL to unminified version
$unminified_url = 'http' . (isset ($_SERVER['HTTPS']) ? 's' : '') . '://';
$unminified_url .= $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
$unminified_url .= '?unminified';

// Copyright notice
$copyright = implode (PHP_EOL, array (
'// Copyright (C) 2010-2021 Jacob Barkdull',
'// Under the terms of the GNU Affero General Public License.',
'// This program source code has been minified.',
'//',
'// Unminified version:',
'// ' . $unminified_url . PHP_EOL . PHP_EOL
));

// Return final minified JavaScript
return $copyright . trim ($js);
}
}