There’s minify and a bunch of other JS compactors/compressors out there, but nothing that I’ve found works with any of the massive scripts I’ve written. Enter the Hx JavaScript compactor. It’s too easy to use so I won’t bother explaining it.
Right now it’s just PHP. I’ll be porting it to Python when I have a chance.
class Hx {
public static function compact_js($js) {
$cp='`^\s*/[/*]\s*<!\[CDATA\[\s*(?:\*/)?(.*)/[/*]\s*\]\]>\s*(?:\*/)?\s*$`s';
$cd=0;
if(preg_match($cp,$js)) {
$cd=1;
$js=preg_replace($cp,'\1',$js,1);
}
$ph=0;
while(strpos($js,strval($ph))!==false) $ph++;
$lines=preg_split('`\s*[\r\n]+\s*`',trim($js));
$fr=array(
'`\s*//.*$`' => '',
'`\s*([^\w$])\s*`' => '\1',
'`;}`' => '}'
);
$find=array_keys($fr);
$repl=array_values($fr);
$s=array();
$cm=null;
foreach($lines as $k=>$l) {
if($cm) {
if(strpos($l,'*/')!==false) {
$l=preg_replace('`^.*?\*/`','',$l);
$cm=0;
} else $l='';
}
if(!$cm) {
for($c=0;$c<strlen($l);$c++) {
$n=$l{$c};
if($n=='"'||$n=="'"||$n=='/') if(preg_match('`([=(?:]\s*/|[\'"])$`',substr($l,0,$c+1))) {
$cl=self::find_delimiter($l,$c);
if($cl!==false) {
$s[]=substr($l,$c,$cl-$c+1);
$l=substr($l,0,$c).$ph. '.' .strval(count($s)-1).substr($l,$cl+1);
}
}
}
$l=preg_replace('`/\*.*?\*/`','',$l);
if(strpos($l,'/*')!==false) {
$l=preg_replace('`/\*.*$`','',$l);
$cm=1;
}
$l=trim(preg_replace($find,$repl,$l));
if($k<count($lines)-1) if($nl=$lines[$k+1]) if(!preg_match('`^\s*[-{};:+=&|^,?.]`',$nl)) {
if(preg_match('`([^-{};:+=&|^,.?([\\]]|[-+]{2})$`',$l)) $l.=';';
if(preg_match('`^(.*)(if|for|while|with)(\(.*?\));$`i',$l,$r)) if(self::find_delimiter($r[3])==strlen($r[3])-1) $l=$r[1].$r[2].$r[3];
}
}
$l=str_ireplace('else;','else ',$l);
$lines[$k]=$l;
}
$ret=implode('',$lines);
$f=-1;
while($f=stripos($ret,'do{',$f+1)) {
$b=self::find_delimiter($ret,$f+2);
if($b!==false) {
$b=strpos($ret,'while(',$b);
if($b!==false) {
$b+=5;
$b=self::find_delimiter($ret,$b);
$ret=substr($ret,0,$b+1).';'.substr($ret,$b+1);
}
}
}
for($i=0;$i<strlen($ret);$i++) if($ret{$i}==':'||$ret{$i}=='=') {
$o=$i+1;
if(strtolower(substr($ret, $o, 9))=='function(') $o=self::find_delimiter($ret,$o+8)+1;
if($ret{$o}=='{') {
$cl=self::find_delimiter($ret,$o);
if($cl<strlen($ret)) if(preg_match('`[-\w(${["\']`',$ret{$cl+1})) $ret=substr($ret,0,$cl+1).';'.substr($ret,$cl+1);
}
}
$ret=str_replace(';}','}',$ret);
$ret=preg_replace("`$ph\.(\d+)`e",'$s[\1]',$ret);
if($cd) $ret="/*<![CDATA[*/$ret//]]>";
return $ret;
}
private static function find_delimiter($str,$pos=0,$dir=0,$esc='\\') {
if($pos>=strlen($str)) return false;
static $pairs='\'\'""//<>[]{}()';
$pp=strpos($pairs,$str{$pos});
if($pp===false) return false;
$op=$pp%2?-1:1;
$o=null;
if($pairs{$pp}!=$pairs{$pp+$op}) {
$dir=$op;
$o=$pairs{$pp};
}
if(!$dir) $dir=1;
$c=$pairs{$pp+$op};
$nest=1;
for($pos+=$dir;$pos>=0&&$pos<strlen($str);$pos+=$dir) {
if($esc) if($pos<(strlen($str)-1)) if($str{$pos+$dir-1}==$esc) $pos+=($dir*2);
if($str{$pos}==$o) $nest++;
if($str{$pos}==$c) $nest--;
if(!$nest) return $pos;
}
return false;
}
}