├── README.md ├── composer.json └── src └── jsmin-1.1.1.php /README.md: -------------------------------------------------------------------------------- 1 | # jsmin-php 2 | 3 | Unofficial repo containing a composer enabled jsmin-php 4 | 5 | Please check the composer.json for original authors and credits. 6 | 7 | ## Brought to you by the LinkORB Engineering team 8 | 9 |
10 | Check out our other projects at [linkorb.com/engineering](http://www.linkorb.com/engineering). 11 | 12 | Btw, we're hiring! 13 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "linkorb/jsmin-php", 3 | "description": "Unofficial package of jsmin-php", 4 | "homepage": "http://www.github.com/linkorb/jsmin-php", 5 | "keywords": ["minify", "jsmin", "javascript"], 6 | "type": "library", 7 | "authors": [ 8 | { 9 | "name": "Joost Faassen", 10 | "email": "j.faassen@linkorb.com", 11 | "role": "Packaging for composer" 12 | }, 13 | { 14 | "name": "Douglas Crockford", 15 | "email": "douglas@crockford.com", 16 | "role": "" 17 | }, 18 | { 19 | "name": "Ryan Grove", 20 | "email": "ryan@wonko.com", 21 | "role": "PHP port" 22 | }, 23 | { 24 | "name": "Adam Gofort", 25 | "email": "aag@adamgoforth.com", 26 | "role": "Updates to the PHP port" 27 | } 28 | ], 29 | "require": { 30 | "php": ">=5.0.0" 31 | }, 32 | "autoload": { 33 | "classmap": ["src/"] 34 | }, 35 | "license": "MIT" 36 | } 37 | -------------------------------------------------------------------------------- /src/jsmin-1.1.1.php: -------------------------------------------------------------------------------- 1 | 41 | * @copyright 2002 Douglas Crockford (jsmin.c) 42 | * @copyright 2008 Ryan Grove (PHP port) 43 | * @license http://opensource.org/licenses/mit-license.php MIT License 44 | * @version 1.1.1 (2008-03-02) 45 | * @link http://code.google.com/p/jsmin-php/ 46 | */ 47 | 48 | class JSMin { 49 | const ORD_LF = 10; 50 | const ORD_SPACE = 32; 51 | 52 | protected $a = ''; 53 | protected $b = ''; 54 | protected $input = ''; 55 | protected $inputIndex = 0; 56 | protected $inputLength = 0; 57 | protected $lookAhead = null; 58 | protected $output = ''; 59 | 60 | // -- Public Static Methods -------------------------------------------------- 61 | 62 | public static function minify($js) { 63 | $jsmin = new JSMin($js); 64 | return $jsmin->min(); 65 | } 66 | 67 | // -- Public Instance Methods ------------------------------------------------ 68 | 69 | public function __construct($input) { 70 | $this->input = str_replace("\r\n", "\n", $input); 71 | $this->inputLength = strlen($this->input); 72 | } 73 | 74 | // -- Protected Instance Methods --------------------------------------------- 75 | 76 | protected function action($d) { 77 | switch($d) { 78 | case 1: 79 | $this->output .= $this->a; 80 | 81 | case 2: 82 | $this->a = $this->b; 83 | 84 | if ($this->a === "'" || $this->a === '"') { 85 | for (;;) { 86 | $this->output .= $this->a; 87 | $this->a = $this->get(); 88 | 89 | if ($this->a === $this->b) { 90 | break; 91 | } 92 | 93 | if (ord($this->a) <= self::ORD_LF) { 94 | throw new JSMinException('Unterminated string literal.'); 95 | } 96 | 97 | if ($this->a === '\\') { 98 | $this->output .= $this->a; 99 | $this->a = $this->get(); 100 | } 101 | } 102 | } 103 | 104 | case 3: 105 | $this->b = $this->next(); 106 | 107 | if ($this->b === '/' && ( 108 | $this->a === '(' || $this->a === ',' || $this->a === '=' || 109 | $this->a === ':' || $this->a === '[' || $this->a === '!' || 110 | $this->a === '&' || $this->a === '|' || $this->a === '?')) { 111 | 112 | $this->output .= $this->a . $this->b; 113 | 114 | for (;;) { 115 | $this->a = $this->get(); 116 | 117 | if ($this->a === '/') { 118 | break; 119 | } elseif ($this->a === '\\') { 120 | $this->output .= $this->a; 121 | $this->a = $this->get(); 122 | } elseif (ord($this->a) <= self::ORD_LF) { 123 | throw new JSMinException('Unterminated regular expression '. 124 | 'literal.'); 125 | } 126 | 127 | $this->output .= $this->a; 128 | } 129 | 130 | $this->b = $this->next(); 131 | } 132 | } 133 | } 134 | 135 | protected function get() { 136 | $c = $this->lookAhead; 137 | $this->lookAhead = null; 138 | 139 | if ($c === null) { 140 | if ($this->inputIndex < $this->inputLength) { 141 | $c = $this->input[$this->inputIndex]; 142 | $this->inputIndex += 1; 143 | } else { 144 | $c = null; 145 | } 146 | } 147 | 148 | if ($c === "\r") { 149 | return "\n"; 150 | } 151 | 152 | if ($c === null || $c === "\n" || ord($c) >= self::ORD_SPACE) { 153 | return $c; 154 | } 155 | 156 | return ' '; 157 | } 158 | 159 | protected function isAlphaNum($c) { 160 | return ord($c) > 126 || $c === '\\' || preg_match('/^[\w\$]$/', $c) === 1; 161 | } 162 | 163 | protected function min() { 164 | $this->a = "\n"; 165 | $this->action(3); 166 | 167 | while ($this->a !== null) { 168 | switch ($this->a) { 169 | case ' ': 170 | if ($this->isAlphaNum($this->b)) { 171 | $this->action(1); 172 | } else { 173 | $this->action(2); 174 | } 175 | break; 176 | 177 | case "\n": 178 | switch ($this->b) { 179 | case '{': 180 | case '[': 181 | case '(': 182 | case '+': 183 | case '-': 184 | $this->action(1); 185 | break; 186 | 187 | case ' ': 188 | $this->action(3); 189 | break; 190 | 191 | default: 192 | if ($this->isAlphaNum($this->b)) { 193 | $this->action(1); 194 | } 195 | else { 196 | $this->action(2); 197 | } 198 | } 199 | break; 200 | 201 | default: 202 | switch ($this->b) { 203 | case ' ': 204 | if ($this->isAlphaNum($this->a)) { 205 | $this->action(1); 206 | break; 207 | } 208 | 209 | $this->action(3); 210 | break; 211 | 212 | case "\n": 213 | switch ($this->a) { 214 | case '}': 215 | case ']': 216 | case ')': 217 | case '+': 218 | case '-': 219 | case '"': 220 | case "'": 221 | $this->action(1); 222 | break; 223 | 224 | default: 225 | if ($this->isAlphaNum($this->a)) { 226 | $this->action(1); 227 | } 228 | else { 229 | $this->action(3); 230 | } 231 | } 232 | break; 233 | 234 | default: 235 | $this->action(1); 236 | break; 237 | } 238 | } 239 | } 240 | 241 | return $this->output; 242 | } 243 | 244 | protected function next() { 245 | $c = $this->get(); 246 | 247 | if ($c === '/') { 248 | switch($this->peek()) { 249 | case '/': 250 | for (;;) { 251 | $c = $this->get(); 252 | 253 | if (ord($c) <= self::ORD_LF) { 254 | return $c; 255 | } 256 | } 257 | 258 | case '*': 259 | $this->get(); 260 | 261 | for (;;) { 262 | switch($this->get()) { 263 | case '*': 264 | if ($this->peek() === '/') { 265 | $this->get(); 266 | return ' '; 267 | } 268 | break; 269 | 270 | case null: 271 | throw new JSMinException('Unterminated comment.'); 272 | } 273 | } 274 | 275 | default: 276 | return $c; 277 | } 278 | } 279 | 280 | return $c; 281 | } 282 | 283 | protected function peek() { 284 | $this->lookAhead = $this->get(); 285 | return $this->lookAhead; 286 | } 287 | } 288 | 289 | // -- Exceptions --------------------------------------------------------------- 290 | class JSMinException extends Exception {} 291 | ?> --------------------------------------------------------------------------------