Skip to content

Commit

Permalink
MDL-58550 libraries: Upgrade matthiasmullie libraries
Browse files Browse the repository at this point in the history
  • Loading branch information
ankitagarwal committed Sep 21, 2017
1 parent 91cbdda commit c7f9a59
Show file tree
Hide file tree
Showing 10 changed files with 357 additions and 180 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ typeof
extends
package
private
continue
function
protected
implements
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
&
|
^
~
<<
>>
>>>
Expand Down
254 changes: 140 additions & 114 deletions lib/minify/matthiasmullie-minify/src/CSS.php

Large diffs are not rendered by default.

138 changes: 115 additions & 23 deletions lib/minify/matthiasmullie-minify/src/JS.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
*
* @author Matthias Mullie <[email protected]>
* @author Tijs Verkoyen <[email protected]>
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved.
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
* @license MIT License
*/
class JS extends Minify
Expand Down Expand Up @@ -80,8 +80,7 @@ class JS extends Minify
* them. Some end of lines are not the end of a statement, like with these
* operators.
*
* Note: Most operators are fine, we've only removed !, ++ and --.
* There can't be a newline separating ! and whatever it is negating.
* Note: Most operators are fine, we've only removed ++ and --.
* ++ & -- have to be joined with the value they're in-/decrementing.
*
* Will be loaded from /data/js/operators_before.txt
Expand All @@ -97,7 +96,8 @@ class JS extends Minify
* them. Some end of lines are not the end of a statement, like when
* continued by one of these operators on the newline.
*
* Note: Most operators are fine, we've only removed ), ], ++ and --.
* Note: Most operators are fine, we've only removed ), ], ++, --, ! and ~.
* There can't be a newline separating ! or ~ and whatever it is negating.
* ++ & -- have to be joined with the value they're in-/decrementing.
* ) & ] are "special" in that they have lots or usecases. () for example
* is used for function calls, for grouping, in if () and for (), ...
Expand All @@ -110,6 +110,11 @@ class JS extends Minify
*/
protected $operatorsAfter = array();

/**
* @var array
*/
protected $nestedExtracted = array();

/**
* {@inheritdoc}
*/
Expand All @@ -131,9 +136,9 @@ public function __construct()
* Minify the data.
* Perform JS optimizations.
*
* @param string[optional] $path Path to write the data to.
* @param string[optional] $path Path to write the data to
*
* @return string The minified data.
* @return string The minified data
*/
public function execute($path = null)
{
Expand Down Expand Up @@ -216,28 +221,101 @@ protected function extractRegex()
$minifier = $this;
$callback = function ($match) use ($minifier) {
$count = count($minifier->extracted);
$placeholder = '/'.$count.'/';
$minifier->extracted[$placeholder] = $match[0];
$placeholder = '"'.$count.'"';
$minifier->extracted[$placeholder] = $match['regex'];

// because we're also trying to find regular expressions that follow
// if/when/for statements, we should also make sure that the content
// within these statements is also minified...
// e.g. `if("some string"/* or comment */)` should become
// `if("some string")`
if (isset($match['before'])) {
$other = new static();
$other->extractStrings('\'"`', "$count-");
$other->stripComments();
$match['before'] = $other->replace($match['before']);
$this->nestedExtracted += $other->extracted;
}

return $placeholder;
return (isset($match['before']) ? $match['before'] : '').
$placeholder.
(isset($match['after']) ? $match['after'] : '');
};

$pattern = '\/.*?(?<!\\\\)(\\\\\\\\)*+\/[gimy]*(?![0-9a-zA-Z\/])';
$pattern = '(?P<regex>\/.+?((?<!\\\\)\\\\\\\\)*\/[gimy]*)(?![0-9a-zA-Z\/])';

// a regular expression can only be followed by a few operators or some
// of the RegExp methods (a `\` followed by a variable or value is
// likely part of a division, not a regex)
$after = '[,;\)\}]';
$methods = '\.(exec|test|match|search|replace|split)\(';
$this->registerPattern('/'.$pattern.'(?=\s*('.$after.'|'.$methods.'))/', $callback);
$keywords = array('do', 'in', 'new', 'else', 'throw', 'yield', 'delete', 'return', 'typeof');
$before = '(?P<before>[=:,;\}\(\{&\|!]|^|'.implode('|', $keywords).')';
$propertiesAndMethods = array(
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#Properties
'prototype',
'length',
'lastIndex',
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#Properties_2
'constructor',
'flags',
'global',
'ignoreCase',
'multiline',
'source',
'sticky',
'unicode',
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#Methods_2
'compile(',
'exec(',
'test(',
'match',
'replace(',
'search(',
'split(',
'toSource(',
'toString(',
);
$delimiters = array_fill(0, count($propertiesAndMethods), '/');
$propertiesAndMethods = array_map('preg_quote', $propertiesAndMethods, $delimiters);
$after = '(?P<after>[\.,;\)\}&\|+]|$|\.('.implode('|', $propertiesAndMethods).'))';
$this->registerPattern('/'.$before.'\s*'.$pattern.'\s*'.$after.'/', $callback);

// we didn't check for regular expressions after `)`, because that is
// more often than not not a character where a regex can follow (e.g.
// (1+2)/3/4 -> /3/ could be considered a regex, but it's not)
// however, after single-line if/while/for, there could very well be a
// regex after `)` (e.g. if(true)/regex/)
// there is one problem, though: it's (near) impossible to check for
// when the if/while/for statement is closed (same amount of closing
// brackets as there were opened), so I'll ignore single-line statements
// with nested brackets followed by a regex for now...
$before = '(?P<before>\b(if|while|for)\s*\((?P<code>[^\(]+?)\))';
$this->registerPattern('/'.$before.'\s*'.$pattern.'\s*'.$after.'/', $callback);

// 1 more edge case: a regex can be followed by a lot more operators or
// keywords if there's a newline (ASI) in between, where the operator
// actually starts a new statement
// (https://github.com/matthiasmullie/minify/issues/56)
$operators = $this->getOperatorsForRegex($this->operatorsBefore, '/');
$operators += $this->getOperatorsForRegex($this->keywordsReserved, '/');
$this->registerPattern('/'.$pattern.'\s*\n?(?=\s*('.implode('|', $operators).'))/', $callback);
$after = '(?P<after>\n\s*('.implode('|', $operators).'))';
$this->registerPattern('/'.$pattern.'\s*'.$after.'/', $callback);
}

/**
* In addition to the regular restore routine, we also need to restore a few
* more things that have been extracted as part of the regex extraction...
*
* {@inheritdoc}
*/
protected function restoreExtractedData($content)
{
// restore regular extracted stuff
$content = parent::restoreExtractedData($content);

// restore nested stuff from within regex extraction
$content = strtr($content, $this->nestedExtracted);

return $content;
}

/**
Expand All @@ -252,7 +330,7 @@ protected function extractRegex()
* Because it's sometimes hard to tell if a newline is part of a statement
* that should be terminated or not, we'll just leave some of them alone.
*
* @param string $content The content to strip the whitespace for.
* @param string $content The content to strip the whitespace for
*
* @return string
*/
Expand Down Expand Up @@ -323,14 +401,15 @@ protected function stripWhitespace($content)
/*
* Next, we'll be removing all semicolons where ASI kicks in.
* for-loops however, can have an empty body (ending in only a
* semicolon), like: `for(i=1;i<3;i++);`
* semicolon), like: `for(i=1;i<3;i++);`, of `for(i in list);`
* Here, nothing happens during the loop; it's just used to keep
* increasing `i`. With that ; omitted, the next line would be expected
* to be the for-loop's body...
* I'm going to double that semicolon (if any) so after the next line,
* which strips semicolons here & there, we're still left with this one.
*/
$content = preg_replace('/(for\([^;]*;[^;]*;[^;\{]*\));(\}|$)/s', '\\1;;\\2', $content);
$content = preg_replace('/(for\([^;\{]*;[^;\{]*;[^;\{]*\));(\}|$)/s', '\\1;;\\2', $content);
$content = preg_replace('/(for\([^;\{]+\s+in\s+[^;\{]+\));(\}|$)/s', '\\1;;\\2', $content);

/*
* We also can't strip empty else-statements. Even though they're
Expand Down Expand Up @@ -367,8 +446,8 @@ protected function stripWhitespace($content)
protected function getOperatorsForRegex(array $operators, $delimiter = '/')
{
// escape operators for use in regex
$delimiter = array_fill(0, count($operators), $delimiter);
$escaped = array_map('preg_quote', $operators, $delimiter);
$delimiters = array_fill(0, count($operators), $delimiter);
$escaped = array_map('preg_quote', $operators, $delimiters);

$operators = array_combine($operators, $escaped);

Expand All @@ -380,7 +459,7 @@ protected function getOperatorsForRegex(array $operators, $delimiter = '/')
$operators['.'] = '(?<![0-9]\s)\.';

// don't confuse = with other assignment shortcuts (e.g. +=)
$chars = preg_quote('+-*\=<>%&|');
$chars = preg_quote('+-*\=<>%&|', $delimiter);
$operators['='] = '(?<!['.$chars.'])\=';

return $operators;
Expand Down Expand Up @@ -479,10 +558,23 @@ protected function propertyNotation($content)
*/
protected function shortenBools($content)
{
$content = preg_replace('/\btrue\b(?!:)/', '!0', $content);
$content = preg_replace('/\bfalse\b(?!:)/', '!1', $content);
/*
* 'true' or 'false' could be used as property names (which may be
* followed by whitespace) - we must not replace those!
* Since PHP doesn't allow variable-length (to account for the
* whitespace) lookbehind assertions, I need to capture the leading
* character and check if it's a `.`
*/
$callback = function ($match) {
if (trim($match[1]) === '.') {
return $match[0];
}

return $match[1].($match[2] === 'true' ? '!0' : '!1');
};
$content = preg_replace_callback('/(^|.\s*)\b(true|false)\b(?!:)/', $callback, $content);

// for(;;) is exactly the same as while(true)
// for(;;) is exactly the same as while(true), but shorter :)
$content = preg_replace('/\bwhile\(!0\){/', 'for(;;){', $content);

// now make sure we didn't turn any do ... while(true) into do ... for(;;)
Expand Down
Loading

0 comments on commit c7f9a59

Please sign in to comment.