r93020 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r93019‎ | r93020 | r93021 >
Date:21:46, 24 July 2011
Author:platonides
Status:ok (Comments)
Tags:
Comment:
Update JSMin+ to the newly released 1.4
This upstream release incorporates r92560 and r92563
Modified paths:
  • /trunk/phase3/includes/libs/jsminplus.php (modified) (history)

Diff [purge]

Index: trunk/phase3/includes/libs/jsminplus.php
@@ -1,7 +1,7 @@
22 <?php
33
44 /**
5 - * JSMinPlus version 1.3
 5+ * JSMinPlus version 1.4
66 *
77 * Minifies a javascript file using a javascript parser
88 *
@@ -15,8 +15,10 @@
1616 * Usage: $minified = JSMinPlus::minify($script [, $filename])
1717 *
1818 * Versionlog (see also changelog.txt):
19 - * 19-07-2011 - expanded operator and keyword defines. Fixes the notices when creating several JSTokenizer
20 - * 17-05-2009 - fixed hook:colon precedence, fixed empty body in loop and if-constructs
 19+ * 23-07-2011 - remove dynamic creation of OP_* and KEYWORD_* defines and declare them on top
 20+ * reduce memory footprint by minifying by block-scope
 21+ * some small byte-saving and performance improvements
 22+ * 12-05-2009 - fixed hook:colon precedence, fixed empty body in loop and if-constructs
2123 * 18-04-2009 - fixed crashbug in PHP 5.2.9 and several other bugfixes
2224 * 12-04-2009 - some small bugfixes and performance improvements
2325 * 09-04-2009 - initial open sourced version 1.0
@@ -46,7 +48,7 @@
4749 * the Initial Developer. All Rights Reserved.
4850 *
4951 * Contributor(s): Tino Zijdel <crisp@tweakers.net>
50 - * PHP port, modifications and minifier routine are (C) 2009
 52+ * PHP port, modifications and minifier routine are (C) 2009-2011
5153 *
5254 * Alternatively, the contents of this file may be used under the terms of
5355 * either the GNU General Public License Version 2 or later (the "GPL"), or
@@ -86,6 +88,8 @@
8789 define('JS_GROUP', 112);
8890 define('JS_LIST', 113);
8991
 92+define('JS_MINIFIED', 999);
 93+
9094 define('DECLARED_FORM', 0);
9195 define('EXPRESSED_FORM', 1);
9296 define('STATEMENT_FORM', 2);
@@ -188,7 +192,7 @@
189193
190194 private function __construct()
191195 {
192 - $this->parser = new JSParser();
 196+ $this->parser = new JSParser($this);
193197 }
194198
195199 public static function minify($js, $filename='')
@@ -217,22 +221,18 @@
218222 return false;
219223 }
220224
221 - private function parseTree($n, $noBlockGrouping = false)
 225+ public function parseTree($n, $noBlockGrouping = false)
222226 {
223227 $s = '';
224228
225229 switch ($n->type)
226230 {
227 - case KEYWORD_FUNCTION:
228 - $s .= 'function' . ($n->name ? ' ' . $n->name : '') . '(';
229 - $params = $n->params;
230 - for ($i = 0, $j = count($params); $i < $j; $i++)
231 - $s .= ($i ? ',' : '') . $params[$i];
232 - $s .= '){' . $this->parseTree($n->body, true) . '}';
 231+ case JS_MINIFIED:
 232+ $s = $n->value;
233233 break;
234234
235235 case JS_SCRIPT:
236 - // we do nothing with funDecls or varDecls
 236+ // we do nothing yet with funDecls or varDecls
237237 $noBlockGrouping = true;
238238 // FALL THROUGH
239239
@@ -279,6 +279,14 @@
280280 }
281281 break;
282282
 283+ case KEYWORD_FUNCTION:
 284+ $s .= 'function' . ($n->name ? ' ' . $n->name : '') . '(';
 285+ $params = $n->params;
 286+ for ($i = 0, $j = count($params); $i < $j; $i++)
 287+ $s .= ($i ? ',' : '') . $params[$i];
 288+ $s .= '){' . $this->parseTree($n->body, true) . '}';
 289+ break;
 290+
283291 case KEYWORD_IF:
284292 $s = 'if(' . $this->parseTree($n->condition) . ')';
285293 $thenPart = $this->parseTree($n->thenPart);
@@ -385,19 +393,14 @@
386394 break;
387395
388396 case KEYWORD_THROW:
389 - $s = 'throw ' . $this->parseTree($n->exception);
390 - break;
391 -
392397 case KEYWORD_RETURN:
393 - $s = 'return';
 398+ $s = $n->type;
394399 if ($n->value)
395400 {
396401 $t = $this->parseTree($n->value);
397402 if (strlen($t))
398403 {
399 - if ( $t[0] != '(' && $t[0] != '[' && $t[0] != '{' &&
400 - $t[0] != '"' && $t[0] != "'" && $t[0] != '/'
401 - )
 404+ if ($this->isWordChar($t[0]) || $t[0] == '\\')
402405 $s .= ' ';
403406
404407 $s .= $t;
@@ -423,6 +426,40 @@
424427 }
425428 break;
426429
 430+ case KEYWORD_IN:
 431+ case KEYWORD_INSTANCEOF:
 432+ $left = $this->parseTree($n->treeNodes[0]);
 433+ $right = $this->parseTree($n->treeNodes[1]);
 434+
 435+ $s = $left;
 436+
 437+ if ($this->isWordChar(substr($left, -1)))
 438+ $s .= ' ';
 439+
 440+ $s .= $n->type;
 441+
 442+ if ($this->isWordChar($right[0]) || $right[0] == '\\')
 443+ $s .= ' ';
 444+
 445+ $s .= $right;
 446+ break;
 447+
 448+ case KEYWORD_DELETE:
 449+ case KEYWORD_TYPEOF:
 450+ $right = $this->parseTree($n->treeNodes[0]);
 451+
 452+ $s = $n->type;
 453+
 454+ if ($this->isWordChar($right[0]) || $right[0] == '\\')
 455+ $s .= ' ';
 456+
 457+ $s .= $right;
 458+ break;
 459+
 460+ case KEYWORD_VOID:
 461+ $s = 'void(' . $this->parseTree($n->treeNodes[0]) . ')';
 462+ break;
 463+
427464 case KEYWORD_DEBUGGER:
428465 throw new Exception('NOT IMPLEMENTED: DEBUGGER');
429466 break;
@@ -497,26 +534,6 @@
498535 }
499536 break;
500537
501 - case KEYWORD_IN:
502 - $s = $this->parseTree($n->treeNodes[0]) . ' in ' . $this->parseTree($n->treeNodes[1]);
503 - break;
504 -
505 - case KEYWORD_INSTANCEOF:
506 - $s = $this->parseTree($n->treeNodes[0]) . ' instanceof ' . $this->parseTree($n->treeNodes[1]);
507 - break;
508 -
509 - case KEYWORD_DELETE:
510 - $s = 'delete ' . $this->parseTree($n->treeNodes[0]);
511 - break;
512 -
513 - case KEYWORD_VOID:
514 - $s = 'void(' . $this->parseTree($n->treeNodes[0]) . ')';
515 - break;
516 -
517 - case KEYWORD_TYPEOF:
518 - $s = 'typeof ' . $this->parseTree($n->treeNodes[0]);
519 - break;
520 -
521538 case OP_NOT:
522539 case OP_BITWISE_NOT:
523540 case OP_UNARY_PLUS:
@@ -606,13 +623,33 @@
607624 $s .= '}';
608625 break;
609626
 627+ case TOKEN_NUMBER:
 628+ $s = $n->value;
 629+ if (preg_match('/^([1-9]+)(0{3,})$/', $s, $m))
 630+ $s = $m[1] . 'e' . strlen($m[2]);
 631+ break;
 632+
610633 case KEYWORD_NULL: case KEYWORD_THIS: case KEYWORD_TRUE: case KEYWORD_FALSE:
611 - case TOKEN_IDENTIFIER: case TOKEN_NUMBER: case TOKEN_STRING: case TOKEN_REGEXP:
 634+ case TOKEN_IDENTIFIER: case TOKEN_STRING: case TOKEN_REGEXP:
612635 $s = $n->value;
613636 break;
614637
615638 case JS_GROUP:
616 - $s = '(' . $this->parseTree($n->treeNodes[0]) . ')';
 639+ if (in_array(
 640+ $n->treeNodes[0]->type,
 641+ array(
 642+ JS_ARRAY_INIT, JS_OBJECT_INIT, JS_GROUP,
 643+ TOKEN_NUMBER, TOKEN_STRING, TOKEN_REGEXP, TOKEN_IDENTIFIER,
 644+ KEYWORD_NULL, KEYWORD_THIS, KEYWORD_TRUE, KEYWORD_FALSE
 645+ )
 646+ ))
 647+ {
 648+ $s = $this->parseTree($n->treeNodes[0]);
 649+ }
 650+ else
 651+ {
 652+ $s = '(' . $this->parseTree($n->treeNodes[0]) . ')';
 653+ }
617654 break;
618655
619656 default:
@@ -626,11 +663,17 @@
627664 {
628665 return preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*$/', $string) && !in_array($string, $this->reserved);
629666 }
 667+
 668+ private function isWordChar($char)
 669+ {
 670+ return $char == '_' || $char == '$' || ctype_alnum($char);
 671+ }
630672 }
631673
632674 class JSParser
633675 {
634676 private $t;
 677+ private $minifier;
635678
636679 private $opPrecedence = array(
637680 ';' => 0,
@@ -680,8 +723,9 @@
681724 TOKEN_CONDCOMMENT_START => 1, TOKEN_CONDCOMMENT_END => 1
682725 );
683726
684 - public function __construct()
 727+ public function __construct($minifier=null)
685728 {
 729+ $this->minifier = $minifier;
686730 $this->t = new JSTokenizer();
687731 }
688732
@@ -705,6 +749,19 @@
706750 $n->funDecls = $x->funDecls;
707751 $n->varDecls = $x->varDecls;
708752
 753+ // minify by scope
 754+ if ($this->minifier)
 755+ {
 756+ $n->value = $this->minifier->parseTree($n);
 757+
 758+ // clear tree from node to save memory
 759+ $n->treeNodes = null;
 760+ $n->funDecls = null;
 761+ $n->varDecls = null;
 762+
 763+ $n->type = JS_MINIFIED;
 764+ }
 765+
709766 return $n;
710767 }
711768
@@ -963,7 +1020,7 @@
9641021
9651022 case KEYWORD_THROW:
9661023 $n = new JSNode($this->t);
967 - $n->exception = $this->Expression($x);
 1024+ $n->value = $this->Expression($x);
9681025 break;
9691026
9701027 case KEYWORD_RETURN:
@@ -1678,44 +1735,11 @@
16791736 );
16801737
16811738 private $opTypeNames = array(
1682 - ';' => 'SEMICOLON',
1683 - ',' => 'COMMA',
1684 - '?' => 'HOOK',
1685 - ':' => 'COLON',
1686 - '||' => 'OR',
1687 - '&&' => 'AND',
1688 - '|' => 'BITWISE_OR',
1689 - '^' => 'BITWISE_XOR',
1690 - '&' => 'BITWISE_AND',
1691 - '===' => 'STRICT_EQ',
1692 - '==' => 'EQ',
1693 - '=' => 'ASSIGN',
1694 - '!==' => 'STRICT_NE',
1695 - '!=' => 'NE',
1696 - '<<' => 'LSH',
1697 - '<=' => 'LE',
1698 - '<' => 'LT',
1699 - '>>>' => 'URSH',
1700 - '>>' => 'RSH',
1701 - '>=' => 'GE',
1702 - '>' => 'GT',
1703 - '++' => 'INCREMENT',
1704 - '--' => 'DECREMENT',
1705 - '+' => 'PLUS',
1706 - '-' => 'MINUS',
1707 - '*' => 'MUL',
1708 - '/' => 'DIV',
1709 - '%' => 'MOD',
1710 - '!' => 'NOT',
1711 - '~' => 'BITWISE_NOT',
1712 - '.' => 'DOT',
1713 - '[' => 'LEFT_BRACKET',
1714 - ']' => 'RIGHT_BRACKET',
1715 - '{' => 'LEFT_CURLY',
1716 - '}' => 'RIGHT_CURLY',
1717 - '(' => 'LEFT_PAREN',
1718 - ')' => 'RIGHT_PAREN',
1719 - '@*/' => 'CONDCOMMENT_END'
 1739+ ';', ',', '?', ':', '||', '&&', '|', '^',
 1740+ '&', '===', '==', '=', '!==', '!=', '<<', '<=',
 1741+ '<', '>>>', '>>', '>=', '>', '++', '--', '+',
 1742+ '-', '*', '/', '%', '!', '~', '.', '[',
 1743+ ']', '{', '}', '(', ')', '@*/'
17201744 );
17211745
17221746 private $assignOps = array('|', '^', '&', '<<', '>>', '>>>', '+', '-', '*', '/', '%');
@@ -1723,7 +1747,7 @@
17241748
17251749 public function __construct()
17261750 {
1727 - $this->opRegExp = '#^(' . implode('|', array_map('preg_quote', array_keys($this->opTypeNames))) . ')#';
 1751+ $this->opRegExp = '#^(' . implode('|', array_map('preg_quote', $this->opTypeNames)) . ')#';
17281752 }
17291753
17301754 public function init($source, $filename = '', $lineno = 1)
@@ -1874,22 +1898,38 @@
18751899 {
18761900 switch ($input[0])
18771901 {
1878 - case '0': case '1': case '2': case '3': case '4':
1879 - case '5': case '6': case '7': case '8': case '9':
1880 - if (preg_match('/^\d+\.\d*(?:[eE][-+]?\d+)?|^\d+(?:\.\d*)?[eE][-+]?\d+/', $input, $match))
 1902+ case '0':
 1903+ // hexadecimal
 1904+ if (($input[1] == 'x' || $input[1] == 'X') && preg_match('/^0x[0-9a-f]+/i', $input, $match))
18811905 {
18821906 $tt = TOKEN_NUMBER;
 1907+ break;
18831908 }
1884 - else if (preg_match('/^0[xX][\da-fA-F]+|^0[0-7]*|^\d+/', $input, $match))
 1909+ // FALL THROUGH
 1910+
 1911+ case '1': case '2': case '3': case '4': case '5':
 1912+ case '6': case '7': case '8': case '9':
 1913+ // should always match
 1914+ preg_match('/^\d+(?:\.\d*)?(?:[eE][-+]?\d+)?/', $input, $match);
 1915+ $tt = TOKEN_NUMBER;
 1916+ break;
 1917+
 1918+ case "'":
 1919+ if (preg_match('/^\'(?:[^\\\\\'\r\n]++|\\\\(?:.|\r?\n))*\'/', $input, $match))
18851920 {
1886 - // this should always match because of \d+
1887 - $tt = TOKEN_NUMBER;
 1921+ $tt = TOKEN_STRING;
18881922 }
 1923+ else
 1924+ {
 1925+ if ($chunksize)
 1926+ return $this->get(null); // retry with a full chunk fetch
 1927+
 1928+ throw $this->newSyntaxError('Unterminated string literal');
 1929+ }
18891930 break;
18901931
18911932 case '"':
1892 - case "'":
1893 - if (preg_match('/^"(?:\\\\(?:.|\r?\n)|[^\\\\"\r\n]+)*"|^\'(?:\\\\(?:.|\r?\n)|[^\\\\\'\r\n]+)*\'/', $input, $match))
 1933+ if (preg_match('/^"(?:[^\\\\"\r\n]++|\\\\(?:.|\r?\n))*"/', $input, $match))
18941934 {
18951935 $tt = TOKEN_STRING;
18961936 }
@@ -2044,4 +2084,3 @@
20452085 public $lineno;
20462086 public $assignOp;
20472087 }
2048 -

Follow-up revisions

RevisionCommit summaryAuthorDate
r98281* (bug 31187) Fix for user JavaScript validation to allow identifiers with va...brion22:51, 27 September 2011

Past revisions this follows-up on

RevisionCommit summaryAuthorDate
r92560Remove double ; and final ?> from jsminplus (imported in r91591)....platonides19:53, 19 July 2011
r92563Expand the defines from JSTokenizer::__construct() placing them at the top of...platonides20:03, 19 July 2011

Comments

#Comment by Platonides (talk | contribs)   21:53, 24 July 2011

Status & tagging log