diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 11:31:45 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 11:31:45 +0000 |
commit | 4e393913a4b1f06509da4341f0f58a41adac9117 (patch) | |
tree | 9c27e3eb77d109dff5fd031502311c5616adab04 /vendor/tedivm | |
parent | Initial commit. (diff) | |
download | icinga-php-thirdparty-4e393913a4b1f06509da4341f0f58a41adac9117.tar.xz icinga-php-thirdparty-4e393913a4b1f06509da4341f0f58a41adac9117.zip |
Adding upstream version 0.12.1+ds.upstream/0.12.1+dsupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/tedivm')
-rw-r--r-- | vendor/tedivm/jshrink/CONTRIBUTING.md | 54 | ||||
-rw-r--r-- | vendor/tedivm/jshrink/LICENSE | 29 | ||||
-rw-r--r-- | vendor/tedivm/jshrink/README.md | 72 | ||||
-rw-r--r-- | vendor/tedivm/jshrink/composer.json | 30 | ||||
-rw-r--r-- | vendor/tedivm/jshrink/src/JShrink/Minifier.php | 721 |
5 files changed, 906 insertions, 0 deletions
diff --git a/vendor/tedivm/jshrink/CONTRIBUTING.md b/vendor/tedivm/jshrink/CONTRIBUTING.md new file mode 100644 index 0000000..8fe815a --- /dev/null +++ b/vendor/tedivm/jshrink/CONTRIBUTING.md @@ -0,0 +1,54 @@ +# Contributions Welcome! + +Pull Requests and Community Contributions are the bread and butter of open source software. Every contribution- from bug +reports to feature requests, typos to full new features- are greatly appreciated. + + +## Important Guidelines + +* One Item Per Pull Request or Issue. This makes it much easier to review code and merge it back in, and prevents issues + with one request from blocking another. + +* Code Coverage is extremely important, and pull requests are much more likely to be accepted if testing is also improved. + New code should be properly tested, and all tests must pass. + +* Read the LICENSE document and make sure you understand it, because your code is going to be released under it. + +* Be prepared to make revisions. Don't be discouraged if you're asked to make changes, as that is just another step + towards refining the code and getting it merged back in. + +* Remember to add the relevant documentation, particular the docblock comments. + + +## Code Styling + +This project follows the PSR standards set forth by the [PHP Framework Interop Group](http://www.php-fig.org/). + +* [PSR-0: Class and file naming conventions](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md) +* [PSR-1: Basic coding standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md) +* [PSR-2: Coding style guide](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md) + +All code most follow these standards to be accepted. The easiest way to accomplish this is to run php-cs-fixer once the +new changes are finished. The php-cs-fixer package is installed as a development dependency of this project. + + composer install --dev + vendor/bin/php-cs-fixer fix ./ --level="all" -vv + + +## Running the test suite + +First install dependencies using Composer. It's important to include the dev packages: + + composer install --dev + +The "runTests.sh" script runs the full test suite- phpunit, php-cs-fixer, as well as any environmental setup: + + tests/runTests.sh + +To call phpunit directly: + + vendor/bin/phpunit + +To call php-cs-fixer directly: + + vendor/bin/php-cs-fixer fix ./ --level="all" -vv --dry-run diff --git a/vendor/tedivm/jshrink/LICENSE b/vendor/tedivm/jshrink/LICENSE new file mode 100644 index 0000000..c6597d8 --- /dev/null +++ b/vendor/tedivm/jshrink/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +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: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder 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 HOLDER 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/vendor/tedivm/jshrink/README.md b/vendor/tedivm/jshrink/README.md new file mode 100644 index 0000000..11c84cb --- /dev/null +++ b/vendor/tedivm/jshrink/README.md @@ -0,0 +1,72 @@ +# JShrink [![Build Status](https://img.shields.io/github/actions/workflow/status/tedious/jshrink/pr_tests.yml?branch=master)](https://github.com/tedious/JShrink/actions/workflows/pr_tests.yml) + +[![License](http://img.shields.io/packagist/l/tedivm/JShrink.svg)](https://github.com/tedivm/JShrink/blob/master/LICENSE) +[![Latest Stable Version](http://img.shields.io/github/release/tedious/JShrink.svg)](https://packagist.org/packages/tedivm/JShrink) +[![Coverage Status](https://coveralls.io/repos/tedious/JShrink/badge.png?branch=master)](https://coveralls.io/r/tedivm/JShrink?branch=master) +[![Total Downloads](http://img.shields.io/packagist/dt/tedivm/jshrink.svg)](https://packagist.org/packages/tedivm/JShrink) + +JShrink is a php class that minifies javascript so that it can be delivered to the client quicker. This code can be used +by any product looking to minify their javascript on the fly (although caching the results is suggested for performance +reasons). Unlike many other products this is not a port into php but a native application, resulting in better +performance. + + +## Usage + +Minifying your code is simple call to a static function- + +```php +<?php +include('vendor/autoload.php'); + +// Basic (default) usage. +$minifiedCode = \JShrink\Minifier::minify($js); + +// Disable YUI style comment preservation. +$minifiedCode = \JShrink\Minifier::minify($js, array('flaggedComments' => false)); +``` + + +## Results + +* Raw - 586,990 +* Gzip - 151,301 +* JShrink - 371,982 +* JShrink and Gzip - 93,507 + + +## Installing + +### Composer + +Installing JShrink can be done through a variety of methods, although Composer is +recommended. + +```yaml +"require": { + "tedivm/jshrink": "~1.0" +} +``` + +### Github + +Releases of JShrink are available on [Github](https://github.com/tedious/JShrink/releases). + + +## License + +JShrink is licensed under the BSD License. See the LICENSE file for details. + +In the spirit of open source, use of this library for evil is discouraged but not prohibited. + + +## Reporting Security and Vulnerability Issues + +This project utilizes the [Tidelift Security Reporting System](https://tidelift.com/security) for security and vulnerability reporting. + + +## Support + +Issues can be opened directly in Github for issues that aren't related to security. + +[Professionally supported JShrink is now available with Tidelift.](https://tidelift.com/subscription/pkg/packagist-tedivm-jshrink?utm_source=packagist-tedivm-jshrink&utm_medium=referral&utm_campaign=readme) diff --git a/vendor/tedivm/jshrink/composer.json b/vendor/tedivm/jshrink/composer.json new file mode 100644 index 0000000..6b77e1b --- /dev/null +++ b/vendor/tedivm/jshrink/composer.json @@ -0,0 +1,30 @@ +{ + "name": "tedivm/jshrink", + "description": "Javascript Minifier built in PHP", + "keywords": [ + "minifier", + "javascript" + ], + "homepage": "http://github.com/tedious/JShrink", + "type": "library", + "license": "BSD-3-Clause", + "authors": [ + { + "name": "Robert Hafner", + "email": "tedivm@tedivm.com" + } + ], + "require": { + "php": "^7.0|^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9|^10", + "friendsofphp/php-cs-fixer": "^3.14", + "php-coveralls/php-coveralls": "^2.5.0" + }, + "autoload": { + "psr-0": { + "JShrink": "src/" + } + } +} diff --git a/vendor/tedivm/jshrink/src/JShrink/Minifier.php b/vendor/tedivm/jshrink/src/JShrink/Minifier.php new file mode 100644 index 0000000..f0a078d --- /dev/null +++ b/vendor/tedivm/jshrink/src/JShrink/Minifier.php @@ -0,0 +1,721 @@ +<?php +/* + * This file is part of the JShrink package. + * + * (c) Robert Hafner <tedivm@tedivm.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * JShrink + * + * + * @package JShrink + * @author Robert Hafner <tedivm@tedivm.com> + */ + +namespace JShrink; + +/** + * Minifier + * + * Usage - Minifier::minify($js); + * Usage - Minifier::minify($js, $options); + * Usage - Minifier::minify($js, array('flaggedComments' => false)); + * + * @package JShrink + * @author Robert Hafner <tedivm@tedivm.com> + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + */ +class Minifier +{ + /** + * The input javascript to be minified. + * + * @var string + */ + protected $input; + + /** + * Length of input javascript. + * + * @var int + */ + protected $len = 0; + + /** + * The location of the character (in the input string) that is next to be + * processed. + * + * @var int + */ + protected $index = 0; + + /** + * The first of the characters currently being looked at. + * + * @var string + */ + protected $a = ''; + + /** + * The next character being looked at (after a); + * + * @var string + */ + protected $b = ''; + + /** + * This character is only active when certain look ahead actions take place. + * + * @var string + */ + protected $c; + + /** + * This character is only active when certain look ahead actions take place. + * + * @var string + */ + protected $last_char; + + /** + * This character is only active when certain look ahead actions take place. + * + * @var string + */ + protected $output; + + /** + * Contains the options for the current minification process. + * + * @var array + */ + protected $options; + + /** + * These characters are used to define strings. + */ + protected $stringDelimiters = ['\'' => true, '"' => true, '`' => true]; + + /** + * Contains the default options for minification. This array is merged with + * the one passed in by the user to create the request specific set of + * options (stored in the $options attribute). + * + * @var array + */ + protected static $defaultOptions = ['flaggedComments' => true]; + + + protected static $keywords = ["delete", "do", "for", "in", "instanceof", "return", "typeof", "yield"]; + + protected $max_keyword_len; + + /** + * Contains lock ids which are used to replace certain code patterns and + * prevent them from being minified + * + * @var array + */ + protected $locks = []; + + /** + * Takes a string containing javascript and removes unneeded characters in + * order to shrink the code without altering it's functionality. + * + * @param string $js The raw javascript to be minified + * @param array $options Various runtime options in an associative array + * @throws \Exception + * @return bool|string + */ + public static function minify($js, $options = []) + { + try { + $jshrink = new Minifier(); + $js = $jshrink->lock($js); + $js = ltrim($jshrink->minifyToString($js, $options)); + $js = $jshrink->unlock($js); + unset($jshrink); + return $js; + } catch (\Exception $e) { + if (isset($jshrink)) { + // Since the breakdownScript function probably wasn't finished + // we clean it out before discarding it. + $jshrink->clean(); + unset($jshrink); + } + throw $e; + } + } + + /** + * Processes a javascript string and outputs only the required characters, + * stripping out all unneeded characters. + * + * @param string $js The raw javascript to be minified + * @param array $options Various runtime options in an associative array + */ + protected function minifyToString($js, $options) + { + $this->initialize($js, $options); + $this->loop(); + $this->clean(); + return $this->output; + } + + /** + * Initializes internal variables, normalizes new lines, + * + * @param string $js The raw javascript to be minified + * @param array $options Various runtime options in an associative array + */ + protected function initialize($js, $options) + { + $this->options = array_merge(static::$defaultOptions, $options); + $this->input = $js; + + // We add a newline to the end of the script to make it easier to deal + // with comments at the bottom of the script- this prevents the unclosed + // comment error that can otherwise occur. + $this->input .= PHP_EOL; + + // save input length to skip calculation every time + $this->len = strlen($this->input); + + // Populate "a" with a new line, "b" with the first character, before + // entering the loop + $this->a = "\n"; + $this->b = "\n"; + $this->last_char = "\n"; + $this->output = ""; + + $this->max_keyword_len = max(array_map('strlen', static::$keywords)); + } + + /** + * Characters that can't stand alone preserve the newline. + * + * @var array + */ + protected $noNewLineCharacters = [ + '(' => true, + '-' => true, + '+' => true, + '[' => true, + '#' => true, + '@' => true]; + + + protected function echo($char) { + $this->output .= $char; + $this->last_char = $char[-1]; + } + + + /** + * The primary action occurs here. This function loops through the input string, + * outputting anything that's relevant and discarding anything that is not. + */ + protected function loop() + { + while ($this->a !== false && !is_null($this->a) && $this->a !== '') { + switch ($this->a) { + // new lines + case "\r": + case "\n": + // if the next line is something that can't stand alone preserve the newline + if ($this->b !== false && isset($this->noNewLineCharacters[$this->b])) { + $this->echo($this->a); + $this->saveString(); + break; + } + + // if B is a space we skip the rest of the switch block and go down to the + // string/regex check below, resetting $this->b with getReal + if ($this->b === ' ') { + break; + } + + // otherwise we treat the newline like a space + + // no break + case ' ': + if (static::isAlphaNumeric($this->b)) { + $this->echo($this->a); + } + + $this->saveString(); + break; + + default: + switch ($this->b) { + case "\r": + case "\n": + if (strpos('}])+-"\'', $this->a) !== false) { + $this->echo($this->a); + $this->saveString(); + break; + } else { + if (static::isAlphaNumeric($this->a)) { + $this->echo($this->a); + $this->saveString(); + } + } + break; + + case ' ': + if (!static::isAlphaNumeric($this->a)) { + break; + } + + // no break + default: + // check for some regex that breaks stuff + if ($this->a === '/' && ($this->b === '\'' || $this->b === '"')) { + $this->saveRegex(); + continue 3; + } + + $this->echo($this->a); + $this->saveString(); + break; + } + } + + // do reg check of doom + $this->b = $this->getReal(); + + if ($this->b == '/') { + $valid_tokens = "(,=:[!&|?\n"; + + # Find last "real" token, excluding spaces. + $last_token = $this->a; + if ($last_token == " ") { + $last_token = $this->last_char; + } + + if (strpos($valid_tokens, $last_token) !== false) { + // Regex can appear unquoted after these symbols + $this->saveRegex(); + } else if ($this->endsInKeyword()) { + // This block checks for the "return" token before the slash. + $this->saveRegex(); + } + } + + // if (($this->b == '/' && strpos('(,=:[!&|?', $this->a) !== false)) { + // $this->saveRegex(); + // } + } + } + + /** + * Resets attributes that do not need to be stored between requests so that + * the next request is ready to go. Another reason for this is to make sure + * the variables are cleared and are not taking up memory. + */ + protected function clean() + { + unset($this->input); + $this->len = 0; + $this->index = 0; + $this->a = $this->b = ''; + unset($this->c); + unset($this->options); + } + + /** + * Returns the next string for processing based off of the current index. + * + * @return string + */ + protected function getChar() + { + // Check to see if we had anything in the look ahead buffer and use that. + if (isset($this->c)) { + $char = $this->c; + unset($this->c); + } else { + // Otherwise we start pulling from the input. + $char = $this->index < $this->len ? $this->input[$this->index] : false; + + // If the next character doesn't exist return false. + if (isset($char) && $char === false) { + return false; + } + + // Otherwise increment the pointer and use this char. + $this->index++; + } + + # Convert all line endings to unix standard. + # `\r\n` converts to `\n\n` and is minified. + if ($char == "\r") { + $char = "\n"; + } + + // Normalize all whitespace except for the newline character into a + // standard space. + if ($char !== "\n" && $char < "\x20") { + return ' '; + } + + return $char; + } + + /** + * This function returns the next character without moving the index forward. + * + * + * @return string The next character + * @throws \RuntimeException + */ + protected function peek() + { + if ($this->index >= $this->len) { + return false; + } + + $char = $this->input[$this->index]; + # Convert all line endings to unix standard. + # `\r\n` converts to `\n\n` and is minified. + if ($char == "\r") { + $char = "\n"; + } + + // Normalize all whitespace except for the newline character into a + // standard space. + if ($char !== "\n" && $char < "\x20") { + return ' '; + } + + # Return the next character but don't push the index. + return $char; + } + + /** + * This function gets the next "real" character. It is essentially a wrapper + * around the getChar function that skips comments. This has significant + * performance benefits as the skipping is done using native functions (ie, + * c code) rather than in script php. + * + * + * @return string Next 'real' character to be processed. + * @throws \RuntimeException + */ + protected function getReal() + { + $startIndex = $this->index; + $char = $this->getChar(); + + // Check to see if we're potentially in a comment + if ($char !== '/') { + return $char; + } + + $this->c = $this->getChar(); + + if ($this->c === '/') { + $this->processOneLineComments($startIndex); + + return $this->getReal(); + } elseif ($this->c === '*') { + $this->processMultiLineComments($startIndex); + + return $this->getReal(); + } + + return $char; + } + + /** + * Removed one line comments, with the exception of some very specific types of + * conditional comments. + * + * @param int $startIndex The index point where "getReal" function started + * @return void + */ + protected function processOneLineComments($startIndex) + { + $thirdCommentString = $this->index < $this->len ? $this->input[$this->index] : false; + + // kill rest of line + $this->getNext("\n"); + + unset($this->c); + + if ($thirdCommentString == '@') { + $endPoint = $this->index - $startIndex; + $this->c = "\n" . substr($this->input, $startIndex, $endPoint); + } + } + + /** + * Skips multiline comments where appropriate, and includes them where needed. + * Conditional comments and "license" style blocks are preserved. + * + * @param int $startIndex The index point where "getReal" function started + * @return void + * @throws \RuntimeException Unclosed comments will throw an error + */ + protected function processMultiLineComments($startIndex) + { + $this->getChar(); // current C + $thirdCommentString = $this->getChar(); + + // Detect a completely empty comment, ie `/**/` + if ($thirdCommentString == "*") { + $peekChar = $this->peek(); + if ($peekChar == "/") { + $this->index++; + return; + } + } + + // kill everything up to the next */ if it's there + if ($this->getNext('*/')) { + $this->getChar(); // get * + $this->getChar(); // get / + $char = $this->getChar(); // get next real character + + // Now we reinsert conditional comments and YUI-style licensing comments + if (($this->options['flaggedComments'] && $thirdCommentString === '!') + || ($thirdCommentString === '@')) { + + // If conditional comments or flagged comments are not the first thing in the script + // we need to echo a and fill it with a space before moving on. + if ($startIndex > 0) { + $this->echo($this->a); + $this->a = " "; + + // If the comment started on a new line we let it stay on the new line + if ($this->input[($startIndex - 1)] === "\n") { + $this->echo("\n"); + } + } + + $endPoint = ($this->index - 1) - $startIndex; + $this->echo(substr($this->input, $startIndex, $endPoint)); + + $this->c = $char; + + return; + } + } else { + $char = false; + } + + if ($char === false) { + throw new \RuntimeException('Unclosed multiline comment at position: ' . ($this->index - 2)); + } + + // if we're here c is part of the comment and therefore tossed + $this->c = $char; + } + + /** + * Pushes the index ahead to the next instance of the supplied string. If it + * is found the first character of the string is returned and the index is set + * to it's position. + * + * @param string $string + * @return string|false Returns the first character of the string or false. + */ + protected function getNext($string) + { + // Find the next occurrence of "string" after the current position. + $pos = strpos($this->input, $string, $this->index); + + // If it's not there return false. + if ($pos === false) { + return false; + } + + // Adjust position of index to jump ahead to the asked for string + $this->index = $pos; + + // Return the first character of that string. + return $this->index < $this->len ? $this->input[$this->index] : false; + } + + /** + * When a javascript string is detected this function crawls for the end of + * it and saves the whole string. + * + * @throws \RuntimeException Unclosed strings will throw an error + */ + protected function saveString() + { + $startpos = $this->index; + + // saveString is always called after a gets cleared, so we push b into + // that spot. + $this->a = $this->b; + + // If this isn't a string we don't need to do anything. + if (!isset($this->stringDelimiters[$this->a])) { + return; + } + + // String type is the quote used, " or ' + $stringType = $this->a; + + // Echo out that starting quote + $this->echo($this->a); + + // Loop until the string is done + // Grab the very next character and load it into a + while (($this->a = $this->getChar()) !== false) { + switch ($this->a) { + + // If the string opener (single or double quote) is used + // output it and break out of the while loop- + // The string is finished! + case $stringType: + break 2; + + // New lines in strings without line delimiters are bad- actual + // new lines will be represented by the string \n and not the actual + // character, so those will be treated just fine using the switch + // block below. + case "\n": + if ($stringType === '`') { + $this->echo($this->a); + } else { + throw new \RuntimeException('Unclosed string at position: ' . $startpos); + } + break; + + // Escaped characters get picked up here. If it's an escaped new line it's not really needed + case '\\': + + // a is a slash. We want to keep it, and the next character, + // unless it's a new line. New lines as actual strings will be + // preserved, but escaped new lines should be reduced. + $this->b = $this->getChar(); + + // If b is a new line we discard a and b and restart the loop. + if ($this->b === "\n") { + break; + } + + // echo out the escaped character and restart the loop. + $this->echo($this->a . $this->b); + break; + + + // Since we're not dealing with any special cases we simply + // output the character and continue our loop. + default: + $this->echo($this->a); + } + } + } + + /** + * When a regular expression is detected this function crawls for the end of + * it and saves the whole regex. + * + * @throws \RuntimeException Unclosed regex will throw an error + */ + protected function saveRegex() + { + if ($this->a != " ") { + $this->echo($this->a); + } + + $this->echo($this->b); + + while (($this->a = $this->getChar()) !== false) { + if ($this->a === '/') { + break; + } + + if ($this->a === '\\') { + $this->echo($this->a); + $this->a = $this->getChar(); + } + + if ($this->a === "\n") { + throw new \RuntimeException('Unclosed regex pattern at position: ' . $this->index); + } + + $this->echo($this->a); + } + $this->b = $this->getReal(); + } + + /** + * Checks to see if a character is alphanumeric. + * + * @param string $char Just one character + * @return bool + */ + protected static function isAlphaNumeric($char) + { + return preg_match('/^[\w\$\pL]$/', $char) === 1 || $char == '/'; + } + + protected function endsInKeyword() { + + # When this function is called A is not yet assigned to output. + # Regular expression only needs to check final part of output for keyword. + $testOutput = substr($this->output . $this->a, -1 * ($this->max_keyword_len + 10)); + + foreach(static::$keywords as $keyword) { + if (preg_match('/[^\w]'.$keyword.'[ ]?$/i', $testOutput) === 1) { + return true; + } + } + return false; + } + + + + /** + * Replace patterns in the given string and store the replacement + * + * @param string $js The string to lock + * @return bool + */ + protected function lock($js) + { + /* lock things like <code>"asd" + ++x;</code> */ + $lock = '"LOCK---' . crc32(time()) . '"'; + + $matches = []; + preg_match('/([+-])(\s+)([+-])/S', $js, $matches); + if (empty($matches)) { + return $js; + } + + $this->locks[$lock] = $matches[2]; + + $js = preg_replace('/([+-])\s+([+-])/S', "$1{$lock}$2", $js); + /* -- */ + + return $js; + } + + /** + * Replace "locks" with the original characters + * + * @param string $js The string to unlock + * @return bool + */ + protected function unlock($js) + { + if (empty($this->locks)) { + return $js; + } + + foreach ($this->locks as $lock => $replacement) { + $js = str_replace($lock, $replacement, $js); + } + + return $js; + } +} |