80 public static function minify(
$s, $statementsOnOwnLine =
false, $maxLineLength = 1000 ) {
115 '!' => self::TYPE_UN_OP,
116 '~' => self::TYPE_UN_OP,
117 'delete' => self::TYPE_UN_OP,
118 'new' => self::TYPE_UN_OP,
119 'typeof' => self::TYPE_UN_OP,
120 'void' => self::TYPE_UN_OP,
121 '++' => self::TYPE_INCR_OP,
122 '--' => self::TYPE_INCR_OP,
123 '!=' => self::TYPE_BIN_OP,
124 '!==' => self::TYPE_BIN_OP,
125 '%' => self::TYPE_BIN_OP,
126 '%=' => self::TYPE_BIN_OP,
127 '&' => self::TYPE_BIN_OP,
128 '&&' => self::TYPE_BIN_OP,
129 '&=' => self::TYPE_BIN_OP,
130 '*' => self::TYPE_BIN_OP,
131 '*=' => self::TYPE_BIN_OP,
132 '+=' => self::TYPE_BIN_OP,
133 '-=' => self::TYPE_BIN_OP,
134 '.' => self::TYPE_BIN_OP,
135 '/' => self::TYPE_BIN_OP,
136 '/=' => self::TYPE_BIN_OP,
137 '<' => self::TYPE_BIN_OP,
138 '<<' => self::TYPE_BIN_OP,
139 '<<=' => self::TYPE_BIN_OP,
140 '<=' => self::TYPE_BIN_OP,
141 '=' => self::TYPE_BIN_OP,
142 '==' => self::TYPE_BIN_OP,
143 '===' => self::TYPE_BIN_OP,
144 '>' => self::TYPE_BIN_OP,
145 '>=' => self::TYPE_BIN_OP,
146 '>>' => self::TYPE_BIN_OP,
147 '>>=' => self::TYPE_BIN_OP,
148 '>>>' => self::TYPE_BIN_OP,
149 '>>>=' => self::TYPE_BIN_OP,
150 '^' => self::TYPE_BIN_OP,
151 '^=' => self::TYPE_BIN_OP,
152 '|' => self::TYPE_BIN_OP,
153 '|=' => self::TYPE_BIN_OP,
154 '||' => self::TYPE_BIN_OP,
155 'in' => self::TYPE_BIN_OP,
156 'instanceof' => self::TYPE_BIN_OP,
157 '+' => self::TYPE_ADD_OP,
158 '-' => self::TYPE_ADD_OP,
159 '?' => self::TYPE_HOOK,
160 ':' => self::TYPE_COLON,
161 ',' => self::TYPE_COMMA,
162 ';' => self::TYPE_SEMICOLON,
163 '{' => self::TYPE_BRACE_OPEN,
164 '}' => self::TYPE_BRACE_CLOSE,
165 '(' => self::TYPE_PAREN_OPEN,
166 '[' => self::TYPE_PAREN_OPEN,
167 ')' => self::TYPE_PAREN_CLOSE,
168 ']' => self::TYPE_PAREN_CLOSE,
169 'break' => self::TYPE_RETURN,
170 'continue' => self::TYPE_RETURN,
171 'return' => self::TYPE_RETURN,
172 'throw' => self::TYPE_RETURN,
173 'catch' => self::TYPE_IF,
174 'for' => self::TYPE_IF,
175 'if' => self::TYPE_IF,
176 'switch' => self::TYPE_IF,
177 'while' => self::TYPE_IF,
178 'with' => self::TYPE_IF,
179 'case' => self::TYPE_DO,
180 'do' => self::TYPE_DO,
181 'else' => self::TYPE_DO,
182 'finally' => self::TYPE_DO,
183 'try' => self::TYPE_DO,
184 'var' => self::TYPE_DO,
185 'function' => self::TYPE_FUNC
192 self::STATEMENT =>
array(
193 self::TYPE_UN_OP => self::EXPRESSION,
194 self::TYPE_INCR_OP => self::EXPRESSION,
195 self::TYPE_ADD_OP => self::EXPRESSION,
196 self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION,
197 self::TYPE_RETURN => self::EXPRESSION_NO_NL,
198 self::TYPE_IF => self::CONDITION,
199 self::TYPE_FUNC => self::CONDITION,
200 self::TYPE_LITERAL => self::EXPRESSION_OP
202 self::CONDITION =>
array(
203 self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION
205 self::PROPERTY_ASSIGNMENT =>
array(
206 self::TYPE_COLON => self::PROPERTY_EXPRESSION,
207 self::TYPE_BRACE_OPEN => self::STATEMENT
209 self::EXPRESSION =>
array(
210 self::TYPE_SEMICOLON => self::STATEMENT,
211 self::TYPE_BRACE_OPEN => self::PROPERTY_ASSIGNMENT,
212 self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION,
213 self::TYPE_FUNC => self::EXPRESSION_FUNC,
214 self::TYPE_LITERAL => self::EXPRESSION_OP
216 self::EXPRESSION_NO_NL =>
array(
217 self::TYPE_SEMICOLON => self::STATEMENT,
218 self::TYPE_BRACE_OPEN => self::PROPERTY_ASSIGNMENT,
219 self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION,
220 self::TYPE_FUNC => self::EXPRESSION_FUNC,
221 self::TYPE_LITERAL => self::EXPRESSION_OP
223 self::EXPRESSION_OP =>
array(
224 self::TYPE_BIN_OP => self::EXPRESSION,
225 self::TYPE_ADD_OP => self::EXPRESSION,
226 self::TYPE_HOOK => self::EXPRESSION_TERNARY,
227 self::TYPE_COLON => self::STATEMENT,
228 self::TYPE_COMMA => self::EXPRESSION,
229 self::TYPE_SEMICOLON => self::STATEMENT,
230 self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION
232 self::EXPRESSION_FUNC =>
array(
233 self::TYPE_BRACE_OPEN => self::STATEMENT
235 self::EXPRESSION_TERNARY =>
array(
236 self::TYPE_BRACE_OPEN => self::PROPERTY_ASSIGNMENT,
237 self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION,
238 self::TYPE_FUNC => self::EXPRESSION_TERNARY_FUNC,
239 self::TYPE_LITERAL => self::EXPRESSION_TERNARY_OP
241 self::EXPRESSION_TERNARY_OP =>
array(
242 self::TYPE_BIN_OP => self::EXPRESSION_TERNARY,
243 self::TYPE_ADD_OP => self::EXPRESSION_TERNARY,
244 self::TYPE_HOOK => self::EXPRESSION_TERNARY,
245 self::TYPE_COMMA => self::EXPRESSION_TERNARY,
246 self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION
248 self::EXPRESSION_TERNARY_FUNC =>
array(
249 self::TYPE_BRACE_OPEN => self::STATEMENT
251 self::PAREN_EXPRESSION =>
array(
252 self::TYPE_BRACE_OPEN => self::PROPERTY_ASSIGNMENT,
253 self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION,
254 self::TYPE_FUNC => self::PAREN_EXPRESSION_FUNC,
255 self::TYPE_LITERAL => self::PAREN_EXPRESSION_OP
257 self::PAREN_EXPRESSION_OP =>
array(
258 self::TYPE_BIN_OP => self::PAREN_EXPRESSION,
259 self::TYPE_ADD_OP => self::PAREN_EXPRESSION,
260 self::TYPE_HOOK => self::PAREN_EXPRESSION,
261 self::TYPE_COLON => self::PAREN_EXPRESSION,
262 self::TYPE_COMMA => self::PAREN_EXPRESSION,
263 self::TYPE_SEMICOLON => self::PAREN_EXPRESSION,
264 self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION
266 self::PAREN_EXPRESSION_FUNC =>
array(
267 self::TYPE_BRACE_OPEN => self::STATEMENT
269 self::PROPERTY_EXPRESSION =>
array(
270 self::TYPE_BRACE_OPEN => self::PROPERTY_ASSIGNMENT,
271 self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION,
272 self::TYPE_FUNC => self::PROPERTY_EXPRESSION_FUNC,
273 self::TYPE_LITERAL => self::PROPERTY_EXPRESSION_OP
275 self::PROPERTY_EXPRESSION_OP =>
array(
276 self::TYPE_BIN_OP => self::PROPERTY_EXPRESSION,
277 self::TYPE_ADD_OP => self::PROPERTY_EXPRESSION,
278 self::TYPE_HOOK => self::PROPERTY_EXPRESSION,
279 self::TYPE_COMMA => self::PROPERTY_ASSIGNMENT,
280 self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION
282 self::PROPERTY_EXPRESSION_FUNC =>
array(
283 self::TYPE_BRACE_OPEN => self::STATEMENT
291 self::STATEMENT =>
array(
292 self::TYPE_BRACE_OPEN => self::STATEMENT,
293 self::TYPE_PAREN_OPEN => self::EXPRESSION_OP
295 self::CONDITION =>
array(
296 self::TYPE_PAREN_OPEN => self::STATEMENT
298 self::PROPERTY_ASSIGNMENT =>
array(
299 self::TYPE_BRACE_OPEN => self::PROPERTY_ASSIGNMENT
301 self::EXPRESSION =>
array(
302 self::TYPE_BRACE_OPEN => self::EXPRESSION_OP,
303 self::TYPE_PAREN_OPEN => self::EXPRESSION_OP
305 self::EXPRESSION_NO_NL =>
array(
306 self::TYPE_BRACE_OPEN => self::EXPRESSION_OP,
307 self::TYPE_PAREN_OPEN => self::EXPRESSION_OP
309 self::EXPRESSION_OP =>
array(
310 self::TYPE_HOOK => self::EXPRESSION,
311 self::TYPE_PAREN_OPEN => self::EXPRESSION_OP
313 self::EXPRESSION_FUNC =>
array(
314 self::TYPE_BRACE_OPEN => self::EXPRESSION_OP
316 self::EXPRESSION_TERNARY =>
array(
317 self::TYPE_BRACE_OPEN => self::EXPRESSION_TERNARY_OP,
318 self::TYPE_PAREN_OPEN => self::EXPRESSION_TERNARY_OP
320 self::EXPRESSION_TERNARY_OP =>
array(
321 self::TYPE_HOOK => self::EXPRESSION_TERNARY,
322 self::TYPE_PAREN_OPEN => self::EXPRESSION_TERNARY_OP
324 self::EXPRESSION_TERNARY_FUNC =>
array(
325 self::TYPE_BRACE_OPEN => self::EXPRESSION_TERNARY_OP
327 self::PAREN_EXPRESSION =>
array(
328 self::TYPE_BRACE_OPEN => self::PAREN_EXPRESSION_OP,
329 self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION_OP
331 self::PAREN_EXPRESSION_OP =>
array(
332 self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION_OP
334 self::PAREN_EXPRESSION_FUNC =>
array(
335 self::TYPE_BRACE_OPEN => self::PAREN_EXPRESSION_OP
337 self::PROPERTY_EXPRESSION =>
array(
338 self::TYPE_BRACE_OPEN => self::PROPERTY_EXPRESSION_OP,
339 self::TYPE_PAREN_OPEN => self::PROPERTY_EXPRESSION_OP
341 self::PROPERTY_EXPRESSION_OP =>
array(
342 self::TYPE_PAREN_OPEN => self::PROPERTY_EXPRESSION_OP
344 self::PROPERTY_EXPRESSION_FUNC =>
array(
345 self::TYPE_BRACE_OPEN => self::PROPERTY_EXPRESSION_OP
351 self::STATEMENT =>
array( self::TYPE_BRACE_CLOSE =>
true ),
352 self::PROPERTY_ASSIGNMENT =>
array( self::TYPE_BRACE_CLOSE =>
true ),
353 self::EXPRESSION =>
array( self::TYPE_BRACE_CLOSE =>
true ),
354 self::EXPRESSION_NO_NL =>
array( self::TYPE_BRACE_CLOSE =>
true ),
355 self::EXPRESSION_OP =>
array( self::TYPE_BRACE_CLOSE =>
true ),
356 self::EXPRESSION_TERNARY_OP =>
array( self::TYPE_COLON =>
true ),
357 self::PAREN_EXPRESSION =>
array( self::TYPE_PAREN_CLOSE =>
true ),
358 self::PAREN_EXPRESSION_OP =>
array( self::TYPE_PAREN_CLOSE =>
true ),
359 self::PROPERTY_EXPRESSION =>
array( self::TYPE_BRACE_CLOSE =>
true ),
360 self::PROPERTY_EXPRESSION_OP =>
array( self::TYPE_BRACE_CLOSE =>
true )
365 self::EXPRESSION_NO_NL =>
array(
366 self::TYPE_UN_OP =>
true,
367 self::TYPE_INCR_OP =>
true,
368 self::TYPE_ADD_OP =>
true,
369 self::TYPE_BRACE_OPEN =>
true,
370 self::TYPE_PAREN_OPEN =>
true,
371 self::TYPE_RETURN =>
true,
372 self::TYPE_IF =>
true,
373 self::TYPE_DO =>
true,
374 self::TYPE_FUNC =>
true,
375 self::TYPE_LITERAL =>
true
377 self::EXPRESSION_OP =>
array(
378 self::TYPE_UN_OP =>
true,
379 self::TYPE_INCR_OP =>
true,
380 self::TYPE_BRACE_OPEN =>
true,
381 self::TYPE_RETURN =>
true,
382 self::TYPE_IF =>
true,
383 self::TYPE_DO =>
true,
384 self::TYPE_FUNC =>
true,
385 self::TYPE_LITERAL =>
true
393 $newlineBefore =
array(
394 self::STATEMENT =>
array(
395 self::TYPE_BRACE_CLOSE =>
true,
398 $newlineAfter =
array(
399 self::STATEMENT =>
array(
400 self::TYPE_BRACE_OPEN =>
true,
401 self::TYPE_PAREN_CLOSE =>
true,
402 self::TYPE_SEMICOLON =>
true,
408 self::EXPRESSION_OP =>
true,
409 self::EXPRESSION_TERNARY_OP =>
true,
410 self::PAREN_EXPRESSION_OP =>
true,
411 self::PROPERTY_EXPRESSION_OP =>
true
418 $length = strlen(
$s );
420 $newlineFound =
true;
424 while( $pos < $length ) {
427 $skip = strspn(
$s,
" \t\n\r\xb\xc", $pos );
430 if( $ch ===
'/' && substr(
$s, $pos, 2 ) ===
'/*' ) {
432 $end = strpos(
$s,
'*/', $pos + 2 );
433 $skip = $end ===
false ? $length - $pos : $end - $pos + 2;
439 if( !$newlineFound && strcspn(
$s,
"\r\n", $pos, $skip ) !== $skip ) {
440 $newlineFound =
true;
448 if( ( $ch ===
'/' && substr(
$s, $pos, 2 ) ===
'//' )
449 || ( $ch ===
'<' && substr(
$s, $pos, 4 ) ===
'<!--' )
450 || ( $ch ===
'-' && $newlineFound && substr(
$s, $pos, 3 ) ===
'-->' )
452 $pos += strcspn(
$s,
"\r\n", $pos );
459 if( $ch ===
"'" || $ch ===
'"' ) {
461 $search = $ch .
'\\';
463 $end += strcspn(
$s, $search, $end ) + 2;
464 }
while( $end - 2 < $length &&
$s[$end - 2] ===
'\\' );
468 } elseif( $ch ===
'/' && !isset( $divStates[$state] ) ) {
473 $end += strcspn(
$s,
'/[\\', $end ) + 2;
474 }
while( $end - 2 < $length &&
$s[$end - 2] ===
'\\' );
476 if( $end - 1 >= $length ||
$s[$end - 1] ===
'/' ) {
480 $end += strcspn(
$s,
']\\', $end ) + 2;
481 }
while( $end - 2 < $length &&
$s[$end - 2] ===
'\\' );
485 while( $end < $length && ctype_alpha(
$s[$end] ) ) {
490 && ($pos + 1 < $length) && (
$s[$pos + 1] ===
'x' ||
$s[$pos + 1] ===
'X' )
494 $len = strspn(
$s,
'0123456789ABCDEFabcdef', $end );
496 return self::parseError(
$s, $pos,
'Expected a hexadecimal number but found ' . substr(
$s, $pos, 5 ) .
'...' );
501 || ( $ch ===
'.' && $pos + 1 < $length && ctype_digit(
$s[$pos + 1] ) )
503 $end += strspn(
$s,
'0123456789', $end );
504 $decimal = strspn(
$s,
'.', $end );
506 if ( $decimal > 2 ) {
509 $end += strspn(
$s,
'0123456789', $end + 1 ) + $decimal;
511 $exponent = strspn(
$s,
'eE', $end );
513 if ( $exponent > 1 ) {
519 $end += strspn(
$s,
'-+', $end );
520 $len = strspn(
$s,
'0123456789', $end );
522 return self::parseError(
$s, $pos,
'No decimal digits after e, how many zeroes should be added?' );
526 } elseif( isset( $opChars[$ch] ) ) {
530 && isset( $tokenTypes[substr(
$s, $pos, $end - $pos + 1 )] )
537 $end += strcspn(
$s,
" \t\n.;,=<>+-{}()[]?:*/%'\"!&|^~\xb\xc\r", $end );
541 $token = substr(
$s, $pos, $end - $pos );
544 if( $newlineFound && isset( $semicolon[$state][
$type] ) ) {
550 } elseif( $maxLineLength > 0 && $lineLength + $end - $pos > $maxLineLength &&
551 !isset( $semicolon[$state][
$type] ) &&
$type !== self::TYPE_INCR_OP )
559 } elseif( !isset( $opChars[
$last] ) && !isset( $opChars[$ch] ) ) {
563 } elseif(
$last === $ch && ( $ch ===
'+' || $ch ===
'-' || $ch ===
'/' ) ) {
569 $lineLength += $end - $pos;
572 $newlineFound =
false;
576 $newlineAdded =
false;
577 if ( $statementsOnOwnLine && !$newlineAdded && isset( $newlineBefore[$state][
$type] ) ) {
580 $newlineAdded =
true;
584 if( isset( $push[$state][
$type] ) && count( $stack ) < self::STACK_LIMIT ) {
585 $stack[] = $push[$state][
$type];
587 if( $stack && isset( $pop[$state][
$type] ) ) {
588 $state = array_pop( $stack );
589 } elseif( isset( $goto[$state][
$type] ) ) {
590 $state = $goto[$state][
$type];
594 if ( $statementsOnOwnLine && !$newlineAdded && isset( $newlineAfter[$state][
$type] ) ) {
602 static function parseError($fullJavascript, $position, $errorMsg) {