<?php
 
/**
 
 * Cruncher class,
 
 *    single method class to crunch code [default: JavaScript (ActionScript or ECMAScript) source].
 
 * With a dedicated associative array rules and one regexp should crunch other sources too.
 
 * ____________________________________
 
 * @example
 
 *     $cruncher = new Crunch;
 
 *    echo $cruncher->crunch($source, 3);
 
 * --------------------------------------------------------------
 
 * @Compatibility    PHP >= 4 and 5 (E_ALL | E_STRICT) error free
 
 * @Dependencies    SourceMap.class.php
 
 * @Author    Andrea Giammarchi
 
 * @Site        http://www.devpro.it/
 
 * @Date        2007/01/15
 
 * @LastMod    2007/02/11 [supports JavaScript conditional comments]
 
 * @Version    1.0
 
 */
 
require_once 'SourceMap.class.php';
 
class Cruncher {
 
    
 
    /** 
 
     * code rules, by default these are JavaScript (ActionScript or ECMAScript) dedicated
 
     * You could change them setting directly this variable
 
     * (i.e. $cruncher->rules = array(....))
 
     */
 
    /** public */ var    $rules = array(
 
        array('name'=>'doublequote', 'start'=>'"', 'end'=>'"', 'noslash'=>true),
 
        array('name'=>'singlequote', 'start'=>"'", 'end'=>"'", 'noslash'=>true),
 
        array('name'=>'conditionalcomment', 'start'=>'/*@', 'end'=>'@*/'),
 
        array('name'=>'singlelinecomment', 'start'=>'//', 'end'=>array("\n", "\r")),
 
        array('name'=>'multilinecomment', 'start'=>'/*', 'end'=>'*/'),
 
        array('name'=>'regexp', 'start'=>'/', 'end'=>'/', 'match'=>'#^/[^\x0a\x0d]+/$#', 'noslash'=>true)
 
    );
 
    
 
    /**
 
     * regexp to crunch code, by default these are JavaScript (ActionScript or ECMAScript) dedicated
 
     * These regexp should be compatible with CSS sources too
 
     */
 
    /** public */ var    $re = array(
 
        
 
        // find one or more space and return them as value \\1
 
        'space'        => '/([[:space:]]+)/',
 
        
 
        // trim common JavaScript operators and return them as value \\1
 
        'operator'    => '/[[:space:]]?([\.|\(|\)|;|\:|=|\{|\}|\,|\-|\+|\?|>|<|\*|\/|^|\||\!|&|\[|\]|%]+)[[:space:]]?/'
 
    );
 
    
 
    // "private" instance of SourceMap
 
    /** private */ var    $__sourceMap = null;
 
    
 
    /**
 
     * public constructor,
 
     *    init a new cruncher setting private __courceMap variable.
 
     *
 
     *    new Cruncher(Void)
 
     */
 
    /** public /**/ function Cruncher(){
 
        $this->__sourceMap = new SourceMap;
 
    }
 
    
 
    /**
 
     * public method,
 
     *    parse a source code and return them crunched
 
     *
 
     *    self->crunch(source:String [, level:UShortRange(1,3)]):String
 
     *
 
     * @param    String        the source to parse
 
     * @param    UShort        compression level from 1 to 3, default: 1
 
     *                level 1 - removes comments and trim spaces of each block of code
 
     *                level 2 - removes comments and duplicated spaces(should be regressive)
 
     *                level 3 - removes comments and spaces (can be regressive)
 
     * @return    String        crunched string
 
     */
 
    /** public /**/ function crunch($str, $level = 1){
 
        $conditional = create_function('$m', '$tmp=new Cruncher;return $m[1].$tmp->crunch($m[2], '.$level.').$m[3];');
 
        $evalspace = $this->re['space'].'e';
 
        $parsed = array();
 
        $map = $this->__sourceMap->getMap($str, $this->rules);
 
        --$level;
 
        for($i = 0, $j = 0, $k = count($map), $name = ''; $j < $k; $j++) {
 
            $name = &$map[$j]['name'];
 
            switch($name) {
 
                case    'singlelinecomment':
 
                case    'multilinecomment':
 
                    if($level < 2 && $i > 0 && !preg_match("/(\r|\n)$/", $parsed[$i-1]))
 
                        $parsed[$i++] = "\r\n";
 
                    break;
 
                case    'conditionalcomment':
 
                    $parsed[$i++] = preg_replace_callback(
 
                        '/^(\/\*@)([^\a]*?)(@\*\/)$/',
 
                        $conditional,
 
                        substr($str, $map[$j]['start'], $map[$j]['end'] - $map[$j]['start'])
 
                    );
 
                    break;
 
                default:
 
                    $parsed[$i] = substr($str, $map[$j]['start'], $map[$j]['end'] - $map[$j]['start']);
 
                    if($name === 'code') {
 
                        switch($level) {
 
                            case    0:
 
                                $parsed[$i] = trim($parsed[$i]);
 
                                break;
 
                            case    1:
 
                                $parsed[$i] = $this->__trimAndReplace($evalspace, 'substr("\\1", 0, 1)', $parsed[$i]);
 
                                break;
 
                            case    2:
 
                                $parsed[$i] = $this->__trimOperatorsAndReplace($parsed[$i]);
 
                                break;
 
                        }
 
                    }
 
                    ++$i;
 
                    break;
 
            }
 
        }
 
        return implode('', $parsed);
 
    }
 
    
 
    /**
 
     * "private" method,
 
     *    replace using a regexp and return trimmed string
 
     *
 
     *    (self)->__trimAndReplace(re:String, place:String, *source:String):String
 
     *
 
     * @param    String        regexp to use
 
     * @param    String        replacement for used regexp
 
     * @param    String        string to change
 
     * @param    String        trim and replaced string
 
     */
 
    /** private /**/ function __trimAndReplace($re, $place, &$str){
 
        return trim(preg_replace($re, $place, $str));
 
    }
 
    
 
    /**
 
     * "private" method,
 
     *    replace using a regexp and return trimmed string without spaces between operators (defined in self->re['operator'] string)
 
     *
 
     *    (self)->__trimOperatorsAndReplace(*source:String):String
 
     *
 
     * @param    String        string to change
 
     * @param    String        trim and replaced string without spaces between operators
 
     */
 
    /** private /**/ function __trimOperatorsAndReplace(&$str){
 
        return preg_replace($this->re['operator'], '\\1', $this->__trimAndReplace($this->re['space'], ' ', $str));
 
    }
 
}
 
?>
 
 |