Completed
Push — release-2.1 ( 121660...f19596 )
by Mathias
09:09
created

JS::stripComments()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 0
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace MatthiasMullie\Minify;
4
5
/**
6
 * JavaScript minifier.
7
 *
8
 * Please report bugs on https://github.com/matthiasmullie/minify/issues
9
 *
10
 * @author Matthias Mullie <[email protected]>
11
 * @author Tijs Verkoyen <[email protected]>
12
 * @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
13
 * @license MIT License
14
 */
15
class JS extends Minify
16
{
17
    /**
18
     * Var-matching regex based on https://stackoverflow.com/a/9337047/802993.
19
     *
20
     * Note that regular expressions using that bit must have the PCRE_UTF8
21
     * pattern modifier (/u) set.
22
     *
23
     * @var string
24
     */
25
    const REGEX_VARIABLE = '\b[$A-Z\_a-z\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\x{02c1}\x{02c6}-\x{02d1}\x{02e0}-\x{02e4}\x{02ec}\x{02ee}\x{0370}-\x{0374}\x{0376}\x{0377}\x{037a}-\x{037d}\x{0386}\x{0388}-\x{038a}\x{038c}\x{038e}-\x{03a1}\x{03a3}-\x{03f5}\x{03f7}-\x{0481}\x{048a}-\x{0527}\x{0531}-\x{0556}\x{0559}\x{0561}-\x{0587}\x{05d0}-\x{05ea}\x{05f0}-\x{05f2}\x{0620}-\x{064a}\x{066e}\x{066f}\x{0671}-\x{06d3}\x{06d5}\x{06e5}\x{06e6}\x{06ee}\x{06ef}\x{06fa}-\x{06fc}\x{06ff}\x{0710}\x{0712}-\x{072f}\x{074d}-\x{07a5}\x{07b1}\x{07ca}-\x{07ea}\x{07f4}\x{07f5}\x{07fa}\x{0800}-\x{0815}\x{081a}\x{0824}\x{0828}\x{0840}-\x{0858}\x{08a0}\x{08a2}-\x{08ac}\x{0904}-\x{0939}\x{093d}\x{0950}\x{0958}-\x{0961}\x{0971}-\x{0977}\x{0979}-\x{097f}\x{0985}-\x{098c}\x{098f}\x{0990}\x{0993}-\x{09a8}\x{09aa}-\x{09b0}\x{09b2}\x{09b6}-\x{09b9}\x{09bd}\x{09ce}\x{09dc}\x{09dd}\x{09df}-\x{09e1}\x{09f0}\x{09f1}\x{0a05}-\x{0a0a}\x{0a0f}\x{0a10}\x{0a13}-\x{0a28}\x{0a2a}-\x{0a30}\x{0a32}\x{0a33}\x{0a35}\x{0a36}\x{0a38}\x{0a39}\x{0a59}-\x{0a5c}\x{0a5e}\x{0a72}-\x{0a74}\x{0a85}-\x{0a8d}\x{0a8f}-\x{0a91}\x{0a93}-\x{0aa8}\x{0aaa}-\x{0ab0}\x{0ab2}\x{0ab3}\x{0ab5}-\x{0ab9}\x{0abd}\x{0ad0}\x{0ae0}\x{0ae1}\x{0b05}-\x{0b0c}\x{0b0f}\x{0b10}\x{0b13}-\x{0b28}\x{0b2a}-\x{0b30}\x{0b32}\x{0b33}\x{0b35}-\x{0b39}\x{0b3d}\x{0b5c}\x{0b5d}\x{0b5f}-\x{0b61}\x{0b71}\x{0b83}\x{0b85}-\x{0b8a}\x{0b8e}-\x{0b90}\x{0b92}-\x{0b95}\x{0b99}\x{0b9a}\x{0b9c}\x{0b9e}\x{0b9f}\x{0ba3}\x{0ba4}\x{0ba8}-\x{0baa}\x{0bae}-\x{0bb9}\x{0bd0}\x{0c05}-\x{0c0c}\x{0c0e}-\x{0c10}\x{0c12}-\x{0c28}\x{0c2a}-\x{0c33}\x{0c35}-\x{0c39}\x{0c3d}\x{0c58}\x{0c59}\x{0c60}\x{0c61}\x{0c85}-\x{0c8c}\x{0c8e}-\x{0c90}\x{0c92}-\x{0ca8}\x{0caa}-\x{0cb3}\x{0cb5}-\x{0cb9}\x{0cbd}\x{0cde}\x{0ce0}\x{0ce1}\x{0cf1}\x{0cf2}\x{0d05}-\x{0d0c}\x{0d0e}-\x{0d10}\x{0d12}-\x{0d3a}\x{0d3d}\x{0d4e}\x{0d60}\x{0d61}\x{0d7a}-\x{0d7f}\x{0d85}-\x{0d96}\x{0d9a}-\x{0db1}\x{0db3}-\x{0dbb}\x{0dbd}\x{0dc0}-\x{0dc6}\x{0e01}-\x{0e30}\x{0e32}\x{0e33}\x{0e40}-\x{0e46}\x{0e81}\x{0e82}\x{0e84}\x{0e87}\x{0e88}\x{0e8a}\x{0e8d}\x{0e94}-\x{0e97}\x{0e99}-\x{0e9f}\x{0ea1}-\x{0ea3}\x{0ea5}\x{0ea7}\x{0eaa}\x{0eab}\x{0ead}-\x{0eb0}\x{0eb2}\x{0eb3}\x{0ebd}\x{0ec0}-\x{0ec4}\x{0ec6}\x{0edc}-\x{0edf}\x{0f00}\x{0f40}-\x{0f47}\x{0f49}-\x{0f6c}\x{0f88}-\x{0f8c}\x{1000}-\x{102a}\x{103f}\x{1050}-\x{1055}\x{105a}-\x{105d}\x{1061}\x{1065}\x{1066}\x{106e}-\x{1070}\x{1075}-\x{1081}\x{108e}\x{10a0}-\x{10c5}\x{10c7}\x{10cd}\x{10d0}-\x{10fa}\x{10fc}-\x{1248}\x{124a}-\x{124d}\x{1250}-\x{1256}\x{1258}\x{125a}-\x{125d}\x{1260}-\x{1288}\x{128a}-\x{128d}\x{1290}-\x{12b0}\x{12b2}-\x{12b5}\x{12b8}-\x{12be}\x{12c0}\x{12c2}-\x{12c5}\x{12c8}-\x{12d6}\x{12d8}-\x{1310}\x{1312}-\x{1315}\x{1318}-\x{135a}\x{1380}-\x{138f}\x{13a0}-\x{13f4}\x{1401}-\x{166c}\x{166f}-\x{167f}\x{1681}-\x{169a}\x{16a0}-\x{16ea}\x{16ee}-\x{16f0}\x{1700}-\x{170c}\x{170e}-\x{1711}\x{1720}-\x{1731}\x{1740}-\x{1751}\x{1760}-\x{176c}\x{176e}-\x{1770}\x{1780}-\x{17b3}\x{17d7}\x{17dc}\x{1820}-\x{1877}\x{1880}-\x{18a8}\x{18aa}\x{18b0}-\x{18f5}\x{1900}-\x{191c}\x{1950}-\x{196d}\x{1970}-\x{1974}\x{1980}-\x{19ab}\x{19c1}-\x{19c7}\x{1a00}-\x{1a16}\x{1a20}-\x{1a54}\x{1aa7}\x{1b05}-\x{1b33}\x{1b45}-\x{1b4b}\x{1b83}-\x{1ba0}\x{1bae}\x{1baf}\x{1bba}-\x{1be5}\x{1c00}-\x{1c23}\x{1c4d}-\x{1c4f}\x{1c5a}-\x{1c7d}\x{1ce9}-\x{1cec}\x{1cee}-\x{1cf1}\x{1cf5}\x{1cf6}\x{1d00}-\x{1dbf}\x{1e00}-\x{1f15}\x{1f18}-\x{1f1d}\x{1f20}-\x{1f45}\x{1f48}-\x{1f4d}\x{1f50}-\x{1f57}\x{1f59}\x{1f5b}\x{1f5d}\x{1f5f}-\x{1f7d}\x{1f80}-\x{1fb4}\x{1fb6}-\x{1fbc}\x{1fbe}\x{1fc2}-\x{1fc4}\x{1fc6}-\x{1fcc}\x{1fd0}-\x{1fd3}\x{1fd6}-\x{1fdb}\x{1fe0}-\x{1fec}\x{1ff2}-\x{1ff4}\x{1ff6}-\x{1ffc}\x{2071}\x{207f}\x{2090}-\x{209c}\x{2102}\x{2107}\x{210a}-\x{2113}\x{2115}\x{2119}-\x{211d}\x{2124}\x{2126}\x{2128}\x{212a}-\x{212d}\x{212f}-\x{2139}\x{213c}-\x{213f}\x{2145}-\x{2149}\x{214e}\x{2160}-\x{2188}\x{2c00}-\x{2c2e}\x{2c30}-\x{2c5e}\x{2c60}-\x{2ce4}\x{2ceb}-\x{2cee}\x{2cf2}\x{2cf3}\x{2d00}-\x{2d25}\x{2d27}\x{2d2d}\x{2d30}-\x{2d67}\x{2d6f}\x{2d80}-\x{2d96}\x{2da0}-\x{2da6}\x{2da8}-\x{2dae}\x{2db0}-\x{2db6}\x{2db8}-\x{2dbe}\x{2dc0}-\x{2dc6}\x{2dc8}-\x{2dce}\x{2dd0}-\x{2dd6}\x{2dd8}-\x{2dde}\x{2e2f}\x{3005}-\x{3007}\x{3021}-\x{3029}\x{3031}-\x{3035}\x{3038}-\x{303c}\x{3041}-\x{3096}\x{309d}-\x{309f}\x{30a1}-\x{30fa}\x{30fc}-\x{30ff}\x{3105}-\x{312d}\x{3131}-\x{318e}\x{31a0}-\x{31ba}\x{31f0}-\x{31ff}\x{3400}-\x{4db5}\x{4e00}-\x{9fcc}\x{a000}-\x{a48c}\x{a4d0}-\x{a4fd}\x{a500}-\x{a60c}\x{a610}-\x{a61f}\x{a62a}\x{a62b}\x{a640}-\x{a66e}\x{a67f}-\x{a697}\x{a6a0}-\x{a6ef}\x{a717}-\x{a71f}\x{a722}-\x{a788}\x{a78b}-\x{a78e}\x{a790}-\x{a793}\x{a7a0}-\x{a7aa}\x{a7f8}-\x{a801}\x{a803}-\x{a805}\x{a807}-\x{a80a}\x{a80c}-\x{a822}\x{a840}-\x{a873}\x{a882}-\x{a8b3}\x{a8f2}-\x{a8f7}\x{a8fb}\x{a90a}-\x{a925}\x{a930}-\x{a946}\x{a960}-\x{a97c}\x{a984}-\x{a9b2}\x{a9cf}\x{aa00}-\x{aa28}\x{aa40}-\x{aa42}\x{aa44}-\x{aa4b}\x{aa60}-\x{aa76}\x{aa7a}\x{aa80}-\x{aaaf}\x{aab1}\x{aab5}\x{aab6}\x{aab9}-\x{aabd}\x{aac0}\x{aac2}\x{aadb}-\x{aadd}\x{aae0}-\x{aaea}\x{aaf2}-\x{aaf4}\x{ab01}-\x{ab06}\x{ab09}-\x{ab0e}\x{ab11}-\x{ab16}\x{ab20}-\x{ab26}\x{ab28}-\x{ab2e}\x{abc0}-\x{abe2}\x{ac00}-\x{d7a3}\x{d7b0}-\x{d7c6}\x{d7cb}-\x{d7fb}\x{f900}-\x{fa6d}\x{fa70}-\x{fad9}\x{fb00}-\x{fb06}\x{fb13}-\x{fb17}\x{fb1d}\x{fb1f}-\x{fb28}\x{fb2a}-\x{fb36}\x{fb38}-\x{fb3c}\x{fb3e}\x{fb40}\x{fb41}\x{fb43}\x{fb44}\x{fb46}-\x{fbb1}\x{fbd3}-\x{fd3d}\x{fd50}-\x{fd8f}\x{fd92}-\x{fdc7}\x{fdf0}-\x{fdfb}\x{fe70}-\x{fe74}\x{fe76}-\x{fefc}\x{ff21}-\x{ff3a}\x{ff41}-\x{ff5a}\x{ff66}-\x{ffbe}\x{ffc2}-\x{ffc7}\x{ffca}-\x{ffcf}\x{ffd2}-\x{ffd7}\x{ffda}-\x{ffdc}][$A-Z\_a-z\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\x{02c1}\x{02c6}-\x{02d1}\x{02e0}-\x{02e4}\x{02ec}\x{02ee}\x{0370}-\x{0374}\x{0376}\x{0377}\x{037a}-\x{037d}\x{0386}\x{0388}-\x{038a}\x{038c}\x{038e}-\x{03a1}\x{03a3}-\x{03f5}\x{03f7}-\x{0481}\x{048a}-\x{0527}\x{0531}-\x{0556}\x{0559}\x{0561}-\x{0587}\x{05d0}-\x{05ea}\x{05f0}-\x{05f2}\x{0620}-\x{064a}\x{066e}\x{066f}\x{0671}-\x{06d3}\x{06d5}\x{06e5}\x{06e6}\x{06ee}\x{06ef}\x{06fa}-\x{06fc}\x{06ff}\x{0710}\x{0712}-\x{072f}\x{074d}-\x{07a5}\x{07b1}\x{07ca}-\x{07ea}\x{07f4}\x{07f5}\x{07fa}\x{0800}-\x{0815}\x{081a}\x{0824}\x{0828}\x{0840}-\x{0858}\x{08a0}\x{08a2}-\x{08ac}\x{0904}-\x{0939}\x{093d}\x{0950}\x{0958}-\x{0961}\x{0971}-\x{0977}\x{0979}-\x{097f}\x{0985}-\x{098c}\x{098f}\x{0990}\x{0993}-\x{09a8}\x{09aa}-\x{09b0}\x{09b2}\x{09b6}-\x{09b9}\x{09bd}\x{09ce}\x{09dc}\x{09dd}\x{09df}-\x{09e1}\x{09f0}\x{09f1}\x{0a05}-\x{0a0a}\x{0a0f}\x{0a10}\x{0a13}-\x{0a28}\x{0a2a}-\x{0a30}\x{0a32}\x{0a33}\x{0a35}\x{0a36}\x{0a38}\x{0a39}\x{0a59}-\x{0a5c}\x{0a5e}\x{0a72}-\x{0a74}\x{0a85}-\x{0a8d}\x{0a8f}-\x{0a91}\x{0a93}-\x{0aa8}\x{0aaa}-\x{0ab0}\x{0ab2}\x{0ab3}\x{0ab5}-\x{0ab9}\x{0abd}\x{0ad0}\x{0ae0}\x{0ae1}\x{0b05}-\x{0b0c}\x{0b0f}\x{0b10}\x{0b13}-\x{0b28}\x{0b2a}-\x{0b30}\x{0b32}\x{0b33}\x{0b35}-\x{0b39}\x{0b3d}\x{0b5c}\x{0b5d}\x{0b5f}-\x{0b61}\x{0b71}\x{0b83}\x{0b85}-\x{0b8a}\x{0b8e}-\x{0b90}\x{0b92}-\x{0b95}\x{0b99}\x{0b9a}\x{0b9c}\x{0b9e}\x{0b9f}\x{0ba3}\x{0ba4}\x{0ba8}-\x{0baa}\x{0bae}-\x{0bb9}\x{0bd0}\x{0c05}-\x{0c0c}\x{0c0e}-\x{0c10}\x{0c12}-\x{0c28}\x{0c2a}-\x{0c33}\x{0c35}-\x{0c39}\x{0c3d}\x{0c58}\x{0c59}\x{0c60}\x{0c61}\x{0c85}-\x{0c8c}\x{0c8e}-\x{0c90}\x{0c92}-\x{0ca8}\x{0caa}-\x{0cb3}\x{0cb5}-\x{0cb9}\x{0cbd}\x{0cde}\x{0ce0}\x{0ce1}\x{0cf1}\x{0cf2}\x{0d05}-\x{0d0c}\x{0d0e}-\x{0d10}\x{0d12}-\x{0d3a}\x{0d3d}\x{0d4e}\x{0d60}\x{0d61}\x{0d7a}-\x{0d7f}\x{0d85}-\x{0d96}\x{0d9a}-\x{0db1}\x{0db3}-\x{0dbb}\x{0dbd}\x{0dc0}-\x{0dc6}\x{0e01}-\x{0e30}\x{0e32}\x{0e33}\x{0e40}-\x{0e46}\x{0e81}\x{0e82}\x{0e84}\x{0e87}\x{0e88}\x{0e8a}\x{0e8d}\x{0e94}-\x{0e97}\x{0e99}-\x{0e9f}\x{0ea1}-\x{0ea3}\x{0ea5}\x{0ea7}\x{0eaa}\x{0eab}\x{0ead}-\x{0eb0}\x{0eb2}\x{0eb3}\x{0ebd}\x{0ec0}-\x{0ec4}\x{0ec6}\x{0edc}-\x{0edf}\x{0f00}\x{0f40}-\x{0f47}\x{0f49}-\x{0f6c}\x{0f88}-\x{0f8c}\x{1000}-\x{102a}\x{103f}\x{1050}-\x{1055}\x{105a}-\x{105d}\x{1061}\x{1065}\x{1066}\x{106e}-\x{1070}\x{1075}-\x{1081}\x{108e}\x{10a0}-\x{10c5}\x{10c7}\x{10cd}\x{10d0}-\x{10fa}\x{10fc}-\x{1248}\x{124a}-\x{124d}\x{1250}-\x{1256}\x{1258}\x{125a}-\x{125d}\x{1260}-\x{1288}\x{128a}-\x{128d}\x{1290}-\x{12b0}\x{12b2}-\x{12b5}\x{12b8}-\x{12be}\x{12c0}\x{12c2}-\x{12c5}\x{12c8}-\x{12d6}\x{12d8}-\x{1310}\x{1312}-\x{1315}\x{1318}-\x{135a}\x{1380}-\x{138f}\x{13a0}-\x{13f4}\x{1401}-\x{166c}\x{166f}-\x{167f}\x{1681}-\x{169a}\x{16a0}-\x{16ea}\x{16ee}-\x{16f0}\x{1700}-\x{170c}\x{170e}-\x{1711}\x{1720}-\x{1731}\x{1740}-\x{1751}\x{1760}-\x{176c}\x{176e}-\x{1770}\x{1780}-\x{17b3}\x{17d7}\x{17dc}\x{1820}-\x{1877}\x{1880}-\x{18a8}\x{18aa}\x{18b0}-\x{18f5}\x{1900}-\x{191c}\x{1950}-\x{196d}\x{1970}-\x{1974}\x{1980}-\x{19ab}\x{19c1}-\x{19c7}\x{1a00}-\x{1a16}\x{1a20}-\x{1a54}\x{1aa7}\x{1b05}-\x{1b33}\x{1b45}-\x{1b4b}\x{1b83}-\x{1ba0}\x{1bae}\x{1baf}\x{1bba}-\x{1be5}\x{1c00}-\x{1c23}\x{1c4d}-\x{1c4f}\x{1c5a}-\x{1c7d}\x{1ce9}-\x{1cec}\x{1cee}-\x{1cf1}\x{1cf5}\x{1cf6}\x{1d00}-\x{1dbf}\x{1e00}-\x{1f15}\x{1f18}-\x{1f1d}\x{1f20}-\x{1f45}\x{1f48}-\x{1f4d}\x{1f50}-\x{1f57}\x{1f59}\x{1f5b}\x{1f5d}\x{1f5f}-\x{1f7d}\x{1f80}-\x{1fb4}\x{1fb6}-\x{1fbc}\x{1fbe}\x{1fc2}-\x{1fc4}\x{1fc6}-\x{1fcc}\x{1fd0}-\x{1fd3}\x{1fd6}-\x{1fdb}\x{1fe0}-\x{1fec}\x{1ff2}-\x{1ff4}\x{1ff6}-\x{1ffc}\x{2071}\x{207f}\x{2090}-\x{209c}\x{2102}\x{2107}\x{210a}-\x{2113}\x{2115}\x{2119}-\x{211d}\x{2124}\x{2126}\x{2128}\x{212a}-\x{212d}\x{212f}-\x{2139}\x{213c}-\x{213f}\x{2145}-\x{2149}\x{214e}\x{2160}-\x{2188}\x{2c00}-\x{2c2e}\x{2c30}-\x{2c5e}\x{2c60}-\x{2ce4}\x{2ceb}-\x{2cee}\x{2cf2}\x{2cf3}\x{2d00}-\x{2d25}\x{2d27}\x{2d2d}\x{2d30}-\x{2d67}\x{2d6f}\x{2d80}-\x{2d96}\x{2da0}-\x{2da6}\x{2da8}-\x{2dae}\x{2db0}-\x{2db6}\x{2db8}-\x{2dbe}\x{2dc0}-\x{2dc6}\x{2dc8}-\x{2dce}\x{2dd0}-\x{2dd6}\x{2dd8}-\x{2dde}\x{2e2f}\x{3005}-\x{3007}\x{3021}-\x{3029}\x{3031}-\x{3035}\x{3038}-\x{303c}\x{3041}-\x{3096}\x{309d}-\x{309f}\x{30a1}-\x{30fa}\x{30fc}-\x{30ff}\x{3105}-\x{312d}\x{3131}-\x{318e}\x{31a0}-\x{31ba}\x{31f0}-\x{31ff}\x{3400}-\x{4db5}\x{4e00}-\x{9fcc}\x{a000}-\x{a48c}\x{a4d0}-\x{a4fd}\x{a500}-\x{a60c}\x{a610}-\x{a61f}\x{a62a}\x{a62b}\x{a640}-\x{a66e}\x{a67f}-\x{a697}\x{a6a0}-\x{a6ef}\x{a717}-\x{a71f}\x{a722}-\x{a788}\x{a78b}-\x{a78e}\x{a790}-\x{a793}\x{a7a0}-\x{a7aa}\x{a7f8}-\x{a801}\x{a803}-\x{a805}\x{a807}-\x{a80a}\x{a80c}-\x{a822}\x{a840}-\x{a873}\x{a882}-\x{a8b3}\x{a8f2}-\x{a8f7}\x{a8fb}\x{a90a}-\x{a925}\x{a930}-\x{a946}\x{a960}-\x{a97c}\x{a984}-\x{a9b2}\x{a9cf}\x{aa00}-\x{aa28}\x{aa40}-\x{aa42}\x{aa44}-\x{aa4b}\x{aa60}-\x{aa76}\x{aa7a}\x{aa80}-\x{aaaf}\x{aab1}\x{aab5}\x{aab6}\x{aab9}-\x{aabd}\x{aac0}\x{aac2}\x{aadb}-\x{aadd}\x{aae0}-\x{aaea}\x{aaf2}-\x{aaf4}\x{ab01}-\x{ab06}\x{ab09}-\x{ab0e}\x{ab11}-\x{ab16}\x{ab20}-\x{ab26}\x{ab28}-\x{ab2e}\x{abc0}-\x{abe2}\x{ac00}-\x{d7a3}\x{d7b0}-\x{d7c6}\x{d7cb}-\x{d7fb}\x{f900}-\x{fa6d}\x{fa70}-\x{fad9}\x{fb00}-\x{fb06}\x{fb13}-\x{fb17}\x{fb1d}\x{fb1f}-\x{fb28}\x{fb2a}-\x{fb36}\x{fb38}-\x{fb3c}\x{fb3e}\x{fb40}\x{fb41}\x{fb43}\x{fb44}\x{fb46}-\x{fbb1}\x{fbd3}-\x{fd3d}\x{fd50}-\x{fd8f}\x{fd92}-\x{fdc7}\x{fdf0}-\x{fdfb}\x{fe70}-\x{fe74}\x{fe76}-\x{fefc}\x{ff21}-\x{ff3a}\x{ff41}-\x{ff5a}\x{ff66}-\x{ffbe}\x{ffc2}-\x{ffc7}\x{ffca}-\x{ffcf}\x{ffd2}-\x{ffd7}\x{ffda}-\x{ffdc}0-9\x{0300}-\x{036f}\x{0483}-\x{0487}\x{0591}-\x{05bd}\x{05bf}\x{05c1}\x{05c2}\x{05c4}\x{05c5}\x{05c7}\x{0610}-\x{061a}\x{064b}-\x{0669}\x{0670}\x{06d6}-\x{06dc}\x{06df}-\x{06e4}\x{06e7}\x{06e8}\x{06ea}-\x{06ed}\x{06f0}-\x{06f9}\x{0711}\x{0730}-\x{074a}\x{07a6}-\x{07b0}\x{07c0}-\x{07c9}\x{07eb}-\x{07f3}\x{0816}-\x{0819}\x{081b}-\x{0823}\x{0825}-\x{0827}\x{0829}-\x{082d}\x{0859}-\x{085b}\x{08e4}-\x{08fe}\x{0900}-\x{0903}\x{093a}-\x{093c}\x{093e}-\x{094f}\x{0951}-\x{0957}\x{0962}\x{0963}\x{0966}-\x{096f}\x{0981}-\x{0983}\x{09bc}\x{09be}-\x{09c4}\x{09c7}\x{09c8}\x{09cb}-\x{09cd}\x{09d7}\x{09e2}\x{09e3}\x{09e6}-\x{09ef}\x{0a01}-\x{0a03}\x{0a3c}\x{0a3e}-\x{0a42}\x{0a47}\x{0a48}\x{0a4b}-\x{0a4d}\x{0a51}\x{0a66}-\x{0a71}\x{0a75}\x{0a81}-\x{0a83}\x{0abc}\x{0abe}-\x{0ac5}\x{0ac7}-\x{0ac9}\x{0acb}-\x{0acd}\x{0ae2}\x{0ae3}\x{0ae6}-\x{0aef}\x{0b01}-\x{0b03}\x{0b3c}\x{0b3e}-\x{0b44}\x{0b47}\x{0b48}\x{0b4b}-\x{0b4d}\x{0b56}\x{0b57}\x{0b62}\x{0b63}\x{0b66}-\x{0b6f}\x{0b82}\x{0bbe}-\x{0bc2}\x{0bc6}-\x{0bc8}\x{0bca}-\x{0bcd}\x{0bd7}\x{0be6}-\x{0bef}\x{0c01}-\x{0c03}\x{0c3e}-\x{0c44}\x{0c46}-\x{0c48}\x{0c4a}-\x{0c4d}\x{0c55}\x{0c56}\x{0c62}\x{0c63}\x{0c66}-\x{0c6f}\x{0c82}\x{0c83}\x{0cbc}\x{0cbe}-\x{0cc4}\x{0cc6}-\x{0cc8}\x{0cca}-\x{0ccd}\x{0cd5}\x{0cd6}\x{0ce2}\x{0ce3}\x{0ce6}-\x{0cef}\x{0d02}\x{0d03}\x{0d3e}-\x{0d44}\x{0d46}-\x{0d48}\x{0d4a}-\x{0d4d}\x{0d57}\x{0d62}\x{0d63}\x{0d66}-\x{0d6f}\x{0d82}\x{0d83}\x{0dca}\x{0dcf}-\x{0dd4}\x{0dd6}\x{0dd8}-\x{0ddf}\x{0df2}\x{0df3}\x{0e31}\x{0e34}-\x{0e3a}\x{0e47}-\x{0e4e}\x{0e50}-\x{0e59}\x{0eb1}\x{0eb4}-\x{0eb9}\x{0ebb}\x{0ebc}\x{0ec8}-\x{0ecd}\x{0ed0}-\x{0ed9}\x{0f18}\x{0f19}\x{0f20}-\x{0f29}\x{0f35}\x{0f37}\x{0f39}\x{0f3e}\x{0f3f}\x{0f71}-\x{0f84}\x{0f86}\x{0f87}\x{0f8d}-\x{0f97}\x{0f99}-\x{0fbc}\x{0fc6}\x{102b}-\x{103e}\x{1040}-\x{1049}\x{1056}-\x{1059}\x{105e}-\x{1060}\x{1062}-\x{1064}\x{1067}-\x{106d}\x{1071}-\x{1074}\x{1082}-\x{108d}\x{108f}-\x{109d}\x{135d}-\x{135f}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}\x{1753}\x{1772}\x{1773}\x{17b4}-\x{17d3}\x{17dd}\x{17e0}-\x{17e9}\x{180b}-\x{180d}\x{1810}-\x{1819}\x{18a9}\x{1920}-\x{192b}\x{1930}-\x{193b}\x{1946}-\x{194f}\x{19b0}-\x{19c0}\x{19c8}\x{19c9}\x{19d0}-\x{19d9}\x{1a17}-\x{1a1b}\x{1a55}-\x{1a5e}\x{1a60}-\x{1a7c}\x{1a7f}-\x{1a89}\x{1a90}-\x{1a99}\x{1b00}-\x{1b04}\x{1b34}-\x{1b44}\x{1b50}-\x{1b59}\x{1b6b}-\x{1b73}\x{1b80}-\x{1b82}\x{1ba1}-\x{1bad}\x{1bb0}-\x{1bb9}\x{1be6}-\x{1bf3}\x{1c24}-\x{1c37}\x{1c40}-\x{1c49}\x{1c50}-\x{1c59}\x{1cd0}-\x{1cd2}\x{1cd4}-\x{1ce8}\x{1ced}\x{1cf2}-\x{1cf4}\x{1dc0}-\x{1de6}\x{1dfc}-\x{1dff}\x{200c}\x{200d}\x{203f}\x{2040}\x{2054}\x{20d0}-\x{20dc}\x{20e1}\x{20e5}-\x{20f0}\x{2cef}-\x{2cf1}\x{2d7f}\x{2de0}-\x{2dff}\x{302a}-\x{302f}\x{3099}\x{309a}\x{a620}-\x{a629}\x{a66f}\x{a674}-\x{a67d}\x{a69f}\x{a6f0}\x{a6f1}\x{a802}\x{a806}\x{a80b}\x{a823}-\x{a827}\x{a880}\x{a881}\x{a8b4}-\x{a8c4}\x{a8d0}-\x{a8d9}\x{a8e0}-\x{a8f1}\x{a900}-\x{a909}\x{a926}-\x{a92d}\x{a947}-\x{a953}\x{a980}-\x{a983}\x{a9b3}-\x{a9c0}\x{a9d0}-\x{a9d9}\x{aa29}-\x{aa36}\x{aa43}\x{aa4c}\x{aa4d}\x{aa50}-\x{aa59}\x{aa7b}\x{aab0}\x{aab2}-\x{aab4}\x{aab7}\x{aab8}\x{aabe}\x{aabf}\x{aac1}\x{aaeb}-\x{aaef}\x{aaf5}\x{aaf6}\x{abe3}-\x{abea}\x{abec}\x{abed}\x{abf0}-\x{abf9}\x{fb1e}\x{fe00}-\x{fe0f}\x{fe20}-\x{fe26}\x{fe33}\x{fe34}\x{fe4d}-\x{fe4f}\x{ff10}-\x{ff19}\x{ff3f}]*\b';
26
27
    /**
28
     * Full list of JavaScript reserved words.
29
     * Will be loaded from /data/js/keywords_reserved.txt.
30
     *
31
     * @see https://mathiasbynens.be/notes/reserved-keywords
32
     *
33
     * @var string[]
34
     */
35
    protected $keywordsReserved = array();
36
37
    /**
38
     * List of JavaScript reserved words that accept a <variable, value, ...>
39
     * after them. Some end of lines are not the end of a statement, like with
40
     * these keywords.
41
     *
42
     * E.g.: we shouldn't insert a ; after this else
43
     * else
44
     *     console.log('this is quite fine')
45
     *
46
     * Will be loaded from /data/js/keywords_before.txt
47
     *
48
     * @var string[]
49
     */
50
    protected $keywordsBefore = array();
51
52
    /**
53
     * List of JavaScript reserved words that accept a <variable, value, ...>
54
     * before them. Some end of lines are not the end of a statement, like when
55
     * continued by one of these keywords on the newline.
56
     *
57
     * E.g.: we shouldn't insert a ; before this instanceof
58
     * variable
59
     *     instanceof String
60
     *
61
     * Will be loaded from /data/js/keywords_after.txt
62
     *
63
     * @var string[]
64
     */
65
    protected $keywordsAfter = array();
66
67
    /**
68
     * List of all JavaScript operators.
69
     *
70
     * Will be loaded from /data/js/operators.txt
71
     *
72
     * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators
73
     *
74
     * @var string[]
75
     */
76
    protected $operators = array();
77
78
    /**
79
     * List of JavaScript operators that accept a <variable, value, ...> after
80
     * them. Some end of lines are not the end of a statement, like with these
81
     * operators.
82
     *
83
     * Note: Most operators are fine, we've only removed !, ++ and --.
84
     * There can't be a newline separating ! and whatever it is negating.
85
     * ++ & -- have to be joined with the value they're in-/decrementing.
86
     *
87
     * Will be loaded from /data/js/operators_before.txt
88
     *
89
     * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators
90
     *
91
     * @var string[]
92
     */
93
    protected $operatorsBefore = array();
94
95
    /**
96
     * List of JavaScript operators that accept a <variable, value, ...> before
97
     * them. Some end of lines are not the end of a statement, like when
98
     * continued by one of these operators on the newline.
99
     *
100
     * Note: Most operators are fine, we've only removed ), ], ++ and --.
101
     * ++ & -- have to be joined with the value they're in-/decrementing.
102
     * ) & ] are "special" in that they have lots or usecases. () for example
103
     * is used for function calls, for grouping, in if () and for (), ...
104
     *
105
     * Will be loaded from /data/js/operators_after.txt
106
     *
107
     * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators
108
     *
109
     * @var string[]
110
     */
111
    protected $operatorsAfter = array();
112
113
    /**
114
     * {@inheritdoc}
115
     */
116
    public function __construct()
117
    {
118
        call_user_func_array(array('parent', '__construct'), func_get_args());
119
120
        $dataDir = __DIR__.'/../data/js/';
121
        $options = FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES;
122
        $this->keywordsReserved = file($dataDir.'keywords_reserved.txt', $options);
123
        $this->keywordsBefore = file($dataDir.'keywords_before.txt', $options);
124
        $this->keywordsAfter = file($dataDir.'keywords_after.txt', $options);
125
        $this->operators = file($dataDir.'operators.txt', $options);
126
        $this->operatorsBefore = file($dataDir.'operators_before.txt', $options);
127
        $this->operatorsAfter = file($dataDir.'operators_after.txt', $options);
128
    }
129
130
    /**
131
     * Minify the data.
132
     * Perform JS optimizations.
133
     *
134
     * @param string[optional] $path Path to write the data to
135
     *
136
     * @return string The minified data
137
     */
138
    public function execute($path = null)
139
    {
140
        $content = '';
141
142
        // loop files
143
        foreach ($this->data as $source => $js) {
144
            /*
145
             * Combine js: separating the scripts by a ;
146
             * I'm also adding a newline: it will be eaten when whitespace is
147
             * stripped, but we need to make sure we're not just appending
148
             * a new script right after a previous script that ended with a
149
             * singe-line comment on the last line (in which case it would also
150
             * be seen as part of that comment)
151
             */
152
            $content .= $js."\n;";
153
        }
154
155
        /*
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
156
         * Let's first take out strings, comments and regular expressions.
157
         * All of these can contain JS code-like characters, and we should make
158
         * sure any further magic ignores anything inside of these.
159
         *
160
         * Consider this example, where we should not strip any whitespace:
161
         * var str = "a   test";
162
         *
163
         * Comments will be removed altogether, strings and regular expressions
164
         * will be replaced by placeholder text, which we'll restore later.
165
         */
166
        $this->extractStrings('\'"`');
167
        $this->stripComments();
168
        $this->extractRegex();
169
        $content = $this->replace($content);
170
171
        $content = $this->propertyNotation($content);
172
        $content = $this->shortenBools($content);
173
        $content = $this->stripWhitespace($content);
174
175
        /*
176
         * Earlier, we extracted strings & regular expressions and replaced them
177
         * with placeholder text. This will restore them.
178
         */
179
        $content = $this->restoreExtractedData($content);
180
181
        return $content;
182
    }
183
184
    /**
185
     * Strip comments from source code.
186
     */
187
    protected function stripComments()
188
    {
189
        // single-line comments
190
        $this->registerPattern('/\/\/.*$/m', '');
191
192
        // multi-line comments
193
        $this->registerPattern('/\/\*.*?\*\//s', '');
194
    }
195
196
    /**
197
     * JS can have /-delimited regular expressions, like: /ab+c/.match(string).
198
     *
199
     * The content inside the regex can contain characters that may be confused
200
     * for JS code: e.g. it could contain whitespace it needs to match & we
201
     * don't want to strip whitespace in there.
202
     *
203
     * The regex can be pretty simple: we don't have to care about comments,
204
     * (which also use slashes) because stripComments() will have stripped those
205
     * already.
206
     *
207
     * This method will replace all string content with simple REGEX#
208
     * placeholder text, so we've rid all regular expressions from characters
209
     * that may be misinterpreted. Original regex content will be saved in
210
     * $this->extracted and after doing all other minifying, we can restore the
211
     * original content via restoreRegex()
212
     */
213
    protected function extractRegex()
214
    {
215
        // PHP only supports $this inside anonymous functions since 5.4
216
        $minifier = $this;
217
        $callback = function ($match) use ($minifier) {
218
            $count = count($minifier->extracted);
219
            $placeholder = '/'.$count.'/';
220
            $minifier->extracted[$placeholder] = $match[0];
221
222
            return $placeholder;
223
        };
224
225
        $pattern = '\/.+?(?<!\\\\)(\\\\\\\\)*\/[gimy]*(?![0-9a-zA-Z\/])';
226
227
        // a regular expression can only be followed by a few operators or some
228
        // of the RegExp methods (a `\` followed by a variable or value is
229
        // likely part of a division, not a regex)
230
        $after = '[\.,;\)\}]';
231
        $methods = '\.(exec|test|match|search|replace|split)\(';
232
        $this->registerPattern('/'.$pattern.'(?=\s*('.$after.'|'.$methods.'))/', $callback);
233
234
        // 1 more edge case: a regex can be followed by a lot more operators or
235
        // keywords if there's a newline (ASI) in between, where the operator
236
        // actually starts a new statement
237
        // (https://github.com/matthiasmullie/minify/issues/56)
238
        $operators = $this->getOperatorsForRegex($this->operatorsBefore, '/');
239
        $operators += $this->getOperatorsForRegex($this->keywordsReserved, '/');
240
        $this->registerPattern('/'.$pattern.'\s*\n(?=\s*('.implode('|', $operators).'))/', $callback);
241
    }
242
243
    /**
244
     * Strip whitespace.
245
     *
246
     * We won't strip *all* whitespace, but as much as possible. The thing that
247
     * we'll preserve are newlines we're unsure about.
248
     * JavaScript doesn't require statements to be terminated with a semicolon.
249
     * It will automatically fix missing semicolons with ASI (automatic semi-
250
     * colon insertion) at the end of line causing errors (without semicolon.)
251
     *
252
     * Because it's sometimes hard to tell if a newline is part of a statement
253
     * that should be terminated or not, we'll just leave some of them alone.
254
     *
255
     * @param string $content The content to strip the whitespace for
256
     *
257
     * @return string
258
     */
259
    protected function stripWhitespace($content)
260
    {
261
        // uniform line endings, make them all line feed
262
        $content = str_replace(array("\r\n", "\r"), "\n", $content);
263
264
        // collapse all non-line feed whitespace into a single space
265
        $content = preg_replace('/[^\S\n]+/', ' ', $content);
266
267
        // strip leading & trailing whitespace
268
        $content = str_replace(array(" \n", "\n "), "\n", $content);
269
270
        // collapse consecutive line feeds into just 1
271
        $content = preg_replace('/\n+/', "\n", $content);
272
273
        $operatorsBefore = $this->getOperatorsForRegex($this->operatorsBefore, '/');
274
        $operatorsAfter = $this->getOperatorsForRegex($this->operatorsAfter, '/');
275
        $operators = $this->getOperatorsForRegex($this->operators, '/');
276
        $keywordsBefore = $this->getKeywordsForRegex($this->keywordsBefore, '/');
277
        $keywordsAfter = $this->getKeywordsForRegex($this->keywordsAfter, '/');
278
279
        // strip whitespace that ends in (or next line begin with) an operator
280
        // that allows statements to be broken up over multiple lines
281
        unset($operatorsBefore['+'], $operatorsBefore['-'], $operatorsAfter['+'], $operatorsAfter['-']);
282
        $content = preg_replace(
283
            array(
284
                '/('.implode('|', $operatorsBefore).')\s+/',
285
                '/\s+('.implode('|', $operatorsAfter).')/',
286
            ), '\\1', $content
287
        );
288
289
        // make sure + and - can't be mistaken for, or joined into ++ and --
290
        $content = preg_replace(
291
            array(
292
                '/(?<![\+\-])\s*([\+\-])(?![\+\-])/',
293
                '/(?<![\+\-])([\+\-])\s*(?![\+\-])/',
294
            ), '\\1', $content
295
        );
296
297
        // collapse whitespace around reserved words into single space
298
        $content = preg_replace('/(^|[;\}\s])\K('.implode('|', $keywordsBefore).')\s+/', '\\2 ', $content);
299
        $content = preg_replace('/\s+('.implode('|', $keywordsAfter).')(?=([;\{\s]|$))/', ' \\1', $content);
300
301
        /*
302
         * We didn't strip whitespace after a couple of operators because they
303
         * could be used in different contexts and we can't be sure it's ok to
304
         * strip the newlines. However, we can safely strip any non-line feed
305
         * whitespace that follows them.
306
         */
307
        $operatorsDiffBefore = array_diff($operators, $operatorsBefore);
308
        $operatorsDiffAfter = array_diff($operators, $operatorsAfter);
309
        $content = preg_replace('/('.implode('|', $operatorsDiffBefore).')[^\S\n]+/', '\\1', $content);
310
        $content = preg_replace('/[^\S\n]+('.implode('|', $operatorsDiffAfter).')/', '\\1', $content);
311
312
        /*
313
         * Get rid of double semicolons, except where they can be used like:
314
         * "for(v=1,_=b;;)", "for(v=1;;v++)" or "for(;;ja||(ja=true))".
315
         * I'll safeguard these double semicolons inside for-loops by
316
         * temporarily replacing them with an invalid condition: they won't have
317
         * a double semicolon and will be easy to spot to restore afterwards.
318
         */
319
        $content = preg_replace('/\bfor\(([^;]*);;([^;]*)\)/', 'for(\\1;-;\\2)', $content);
320
        $content = preg_replace('/;+/', ';', $content);
321
        $content = preg_replace('/\bfor\(([^;]*);-;([^;]*)\)/', 'for(\\1;;\\2)', $content);
322
323
        /*
324
         * Next, we'll be removing all semicolons where ASI kicks in.
325
         * for-loops however, can have an empty body (ending in only a
326
         * semicolon), like: `for(i=1;i<3;i++);`
327
         * Here, nothing happens during the loop; it's just used to keep
328
         * increasing `i`. With that ; omitted, the next line would be expected
329
         * to be the for-loop's body...
330
         * I'm going to double that semicolon (if any) so after the next line,
331
         * which strips semicolons here & there, we're still left with this one.
332
         */
333
        $content = preg_replace('/(for\([^;]*;[^;]*;[^;\{]*\));(\}|$)/s', '\\1;;\\2', $content);
334
335
        /*
336
         * We also can't strip empty else-statements. Even though they're
337
         * useless and probably shouldn't be in the code in the first place, we
338
         * shouldn't be stripping the `;` that follows it as it breaks the code.
339
         * We can just remove those useless else-statements completely.
340
         *
341
         * @see https://github.com/matthiasmullie/minify/issues/91
342
         */
343
        $content = preg_replace('/else;/s', '', $content);
344
345
        /*
346
         * We also don't really want to terminate statements followed by closing
347
         * curly braces (which we've ignored completely up until now) or end-of-
348
         * script: ASI will kick in here & we're all about minifying.
349
         * Semicolons at beginning of the file don't make any sense either.
350
         */
351
        $content = preg_replace('/;(\}|$)/s', '\\1', $content);
352
        $content = ltrim($content, ';');
353
354
        // get rid of remaining whitespace af beginning/end
355
        return trim($content);
356
    }
357
358
    /**
359
     * We'll strip whitespace around certain operators with regular expressions.
360
     * This will prepare the given array by escaping all characters.
361
     *
362
     * @param string[] $operators
363
     * @param string   $delimiter
364
     *
365
     * @return string[]
366
     */
367
    protected function getOperatorsForRegex(array $operators, $delimiter = '/')
368
    {
369
        // escape operators for use in regex
370
        $delimiter = array_fill(0, count($operators), $delimiter);
371
        $escaped = array_map('preg_quote', $operators, $delimiter);
372
373
        $operators = array_combine($operators, $escaped);
374
375
        // ignore + & - for now, they'll get special treatment
376
        unset($operators['+'], $operators['-']);
377
378
        // dot can not just immediately follow a number; it can be confused for
379
        // decimal point, or calling a method on it, e.g. 42 .toString()
380
        $operators['.'] = '(?<![0-9]\s)\.';
381
382
        // don't confuse = with other assignment shortcuts (e.g. +=)
383
        $chars = preg_quote('+-*\=<>%&|');
384
        $operators['='] = '(?<!['.$chars.'])\=';
385
386
        return $operators;
387
    }
388
389
    /**
390
     * We'll strip whitespace around certain keywords with regular expressions.
391
     * This will prepare the given array by escaping all characters.
392
     *
393
     * @param string[] $keywords
394
     * @param string   $delimiter
395
     *
396
     * @return string[]
397
     */
398
    protected function getKeywordsForRegex(array $keywords, $delimiter = '/')
399
    {
400
        // escape keywords for use in regex
401
        $delimiter = array_fill(0, count($keywords), $delimiter);
402
        $escaped = array_map('preg_quote', $keywords, $delimiter);
403
404
        // add word boundaries
405
        array_walk($keywords, function ($value) {
406
            return '\b'.$value.'\b';
407
        });
408
409
        $keywords = array_combine($keywords, $escaped);
410
411
        return $keywords;
412
    }
413
414
    /**
415
     * Replaces all occurrences of array['key'] by array.key.
416
     *
417
     * @param string $content
418
     *
419
     * @return string
420
     */
421
    protected function propertyNotation($content)
422
    {
423
        // PHP only supports $this inside anonymous functions since 5.4
424
        $minifier = $this;
425
        $keywords = $this->keywordsReserved;
426
        $callback = function ($match) use ($minifier, $keywords) {
427
            $property = trim($minifier->extracted[$match[1]], '\'"');
428
429
            /*
430
             * Check if the property is a reserved keyword. In this context (as
431
             * property of an object literal/array) it shouldn't matter, but IE8
432
             * freaks out with "Expected identifier".
433
             */
434
            if (in_array($property, $keywords)) {
435
                return $match[0];
436
            }
437
438
            /*
439
             * See if the property is in a variable-like format (e.g.
440
             * array['key-here'] can't be replaced by array.key-here since '-'
441
             * is not a valid character there.
442
             */
443
            if (!preg_match('/^'.$minifier::REGEX_VARIABLE.'$/u', $property)) {
444
                return $match[0];
445
            }
446
447
            return '.'.$property;
448
        };
449
450
        /*
451
         * Figure out if previous character is a variable name (of the array
452
         * we want to use property notation on) - this is to make sure
453
         * standalone ['value'] arrays aren't confused for keys-of-an-array.
454
         * We can (and only have to) check the last character, because PHP's
455
         * regex implementation doesn't allow unfixed-length look-behind
456
         * assertions.
457
         */
458
        preg_match('/(\[[^\]]+\])[^\]]*$/', static::REGEX_VARIABLE, $previousChar);
459
        $previousChar = $previousChar[1];
460
461
        /*
462
         * Make sure word preceding the ['value'] is not a keyword, e.g.
463
         * return['x']. Because -again- PHP's regex implementation doesn't allow
464
         * unfixed-length look-behind assertions, I'm just going to do a lot of
465
         * separate look-behind assertions, one for each keyword.
466
         */
467
        $keywords = $this->getKeywordsForRegex($keywords);
468
        $keywords = '(?<!'.implode(')(?<!', $keywords).')';
469
470
        return preg_replace_callback('/(?<='.$previousChar.'|\])'.$keywords.'\[\s*(([\'"])[0-9]+\\2)\s*\]/u', $callback, $content);
471
    }
472
473
    /**
474
     * Replaces true & false by !0 and !1.
475
     *
476
     * @param string $content
477
     *
478
     * @return string
479
     */
480
    protected function shortenBools($content)
481
    {
482
        $content = preg_replace('/\btrue\b(?!:)/', '!0', $content);
483
        $content = preg_replace('/\bfalse\b(?!:)/', '!1', $content);
484
485
        // for(;;) is exactly the same as while(true)
0 ignored issues
show
Unused Code Comprehensibility introduced by
48% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
486
        $content = preg_replace('/\bwhile\(!0\){/', 'for(;;){', $content);
487
488
        // now make sure we didn't turn any do ... while(true) into do ... for(;;)
489
        preg_match_all('/\bdo\b/', $content, $dos, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
490
491
        // go backward to make sure positional offsets aren't altered when $content changes
492
        $dos = array_reverse($dos);
493
        foreach ($dos as $do) {
494
            $offsetDo = $do[0][1];
495
496
            // find all `while` (now `for`) following `do`: one of those must be
497
            // associated with the `do` and be turned back into `while`
498
            preg_match_all('/\bfor\(;;\)/', $content, $whiles, PREG_OFFSET_CAPTURE | PREG_SET_ORDER, $offsetDo);
499
            foreach ($whiles as $while) {
0 ignored issues
show
Bug introduced by
The expression $whiles of type null|array<integer,array<integer,string>> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
500
                $offsetWhile = $while[0][1];
501
502
                $open = substr_count($content, '{', $offsetDo, $offsetWhile - $offsetDo);
503
                $close = substr_count($content, '}', $offsetDo, $offsetWhile - $offsetDo);
504
                if ($open === $close) {
505
                    // only restore `while` if amount of `{` and `}` are the same;
506
                    // otherwise, that `for` isn't associated with this `do`
507
                    $content = substr_replace($content, 'while(!0)', $offsetWhile, strlen('for(;;)'));
508
                    break;
509
                }
510
            }
511
        }
512
513
        return $content;
514
    }
515
}
516