MediaWiki REL1_28
JavaScriptMinifier.php
Go to the documentation of this file.
1<?php
2// @codingStandardsIgnoreFile File external to MediaWiki. Ignore coding conventions checks.
20
21 /* Class constants */
22 /* Parsing states.
23 * The state machine is only necessary to decide whether to parse a slash as division
24 * operator or as regexp literal.
25 * States are named after the next expected item. We only distinguish states when the
26 * distinction is relevant for our purpose.
27 */
28 const STATEMENT = 0;
29 const CONDITION = 1;
31 const EXPRESSION = 3;
32 const EXPRESSION_NO_NL = 4; // only relevant for semicolon insertion
33 const EXPRESSION_OP = 5;
34 const EXPRESSION_FUNC = 6;
35 const EXPRESSION_TERNARY = 7; // used to determine the role of a colon
38 const PAREN_EXPRESSION = 10; // expression which is not on the top level
41 const PROPERTY_EXPRESSION = 13; // expression which is within an object literal
44
45 /* Token types */
46 const TYPE_UN_OP = 1; // unary operators
47 const TYPE_INCR_OP = 2; // ++ and --
48 const TYPE_BIN_OP = 3; // binary operators
49 const TYPE_ADD_OP = 4; // + and - which can be either unary or binary ops
50 const TYPE_HOOK = 5; // ?
51 const TYPE_COLON = 6; // :
52 const TYPE_COMMA = 7; // ,
53 const TYPE_SEMICOLON = 8; // ;
54 const TYPE_BRACE_OPEN = 9; // {
55 const TYPE_BRACE_CLOSE = 10; // }
56 const TYPE_PAREN_OPEN = 11; // ( and [
57 const TYPE_PAREN_CLOSE = 12; // ) and ]
58 const TYPE_RETURN = 13; // keywords: break, continue, return, throw
59 const TYPE_IF = 14; // keywords: catch, for, with, switch, while, if
60 const TYPE_DO = 15; // keywords: case, var, finally, else, do, try
61 const TYPE_FUNC = 16; // keywords: function
62 const TYPE_LITERAL = 17; // all literals, identifiers and unrecognised tokens
63
64 // Sanity limit to avoid excessive memory usage
65 const STACK_LIMIT = 1000;
66
67 /* Static functions */
68
81 public static function minify( $s, $statementsOnOwnLine = false, $maxLineLength = 1000 ) {
82 // First we declare a few tables that contain our parsing rules
83
84 // $opChars : characters, which can be combined without whitespace in between them
85 $opChars = array(
86 '!' => true,
87 '"' => true,
88 '%' => true,
89 '&' => true,
90 "'" => true,
91 '(' => true,
92 ')' => true,
93 '*' => true,
94 '+' => true,
95 ',' => true,
96 '-' => true,
97 '.' => true,
98 '/' => true,
99 ':' => true,
100 ';' => true,
101 '<' => true,
102 '=' => true,
103 '>' => true,
104 '?' => true,
105 '[' => true,
106 ']' => true,
107 '^' => true,
108 '{' => true,
109 '|' => true,
110 '}' => true,
111 '~' => true
112 );
113
114 // $tokenTypes : maps keywords and operators to their corresponding token type
115 $tokenTypes = array(
116 '!' => self::TYPE_UN_OP,
117 '~' => self::TYPE_UN_OP,
118 'delete' => self::TYPE_UN_OP,
119 'new' => self::TYPE_UN_OP,
120 'typeof' => self::TYPE_UN_OP,
121 'void' => self::TYPE_UN_OP,
122 '++' => self::TYPE_INCR_OP,
123 '--' => self::TYPE_INCR_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 '||' => self::TYPE_BIN_OP,
156 'in' => self::TYPE_BIN_OP,
157 'instanceof' => self::TYPE_BIN_OP,
158 '+' => self::TYPE_ADD_OP,
159 '-' => self::TYPE_ADD_OP,
160 '?' => self::TYPE_HOOK,
161 ':' => self::TYPE_COLON,
162 ',' => self::TYPE_COMMA,
163 ';' => self::TYPE_SEMICOLON,
164 '{' => self::TYPE_BRACE_OPEN,
165 '}' => self::TYPE_BRACE_CLOSE,
166 '(' => self::TYPE_PAREN_OPEN,
167 '[' => self::TYPE_PAREN_OPEN,
168 ')' => self::TYPE_PAREN_CLOSE,
169 ']' => self::TYPE_PAREN_CLOSE,
170 'break' => self::TYPE_RETURN,
171 'continue' => self::TYPE_RETURN,
172 'return' => self::TYPE_RETURN,
173 'throw' => self::TYPE_RETURN,
174 'catch' => self::TYPE_IF,
175 'for' => self::TYPE_IF,
176 'if' => self::TYPE_IF,
177 'switch' => self::TYPE_IF,
178 'while' => self::TYPE_IF,
179 'with' => self::TYPE_IF,
180 'case' => self::TYPE_DO,
181 'do' => self::TYPE_DO,
182 'else' => self::TYPE_DO,
183 'finally' => self::TYPE_DO,
184 'try' => self::TYPE_DO,
185 'var' => self::TYPE_DO,
186 'function' => self::TYPE_FUNC
187 );
188
189 // $goto : This is the main table for our state machine. For every state/token pair
190 // the following state is defined. When no rule exists for a given pair,
191 // the state is left unchanged.
192 $goto = array(
193 self::STATEMENT => array(
194 self::TYPE_UN_OP => self::EXPRESSION,
195 self::TYPE_INCR_OP => self::EXPRESSION,
196 self::TYPE_ADD_OP => self::EXPRESSION,
197 self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION,
198 self::TYPE_RETURN => self::EXPRESSION_NO_NL,
199 self::TYPE_IF => self::CONDITION,
200 self::TYPE_FUNC => self::CONDITION,
201 self::TYPE_LITERAL => self::EXPRESSION_OP
202 ),
203 self::CONDITION => array(
204 self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION
205 ),
206 self::PROPERTY_ASSIGNMENT => array(
207 self::TYPE_COLON => self::PROPERTY_EXPRESSION,
208 self::TYPE_BRACE_OPEN => self::STATEMENT
209 ),
210 self::EXPRESSION => array(
211 self::TYPE_SEMICOLON => self::STATEMENT,
212 self::TYPE_BRACE_OPEN => self::PROPERTY_ASSIGNMENT,
213 self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION,
214 self::TYPE_FUNC => self::EXPRESSION_FUNC,
215 self::TYPE_LITERAL => self::EXPRESSION_OP
216 ),
217 self::EXPRESSION_NO_NL => array(
218 self::TYPE_SEMICOLON => self::STATEMENT,
219 self::TYPE_BRACE_OPEN => self::PROPERTY_ASSIGNMENT,
220 self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION,
221 self::TYPE_FUNC => self::EXPRESSION_FUNC,
222 self::TYPE_LITERAL => self::EXPRESSION_OP
223 ),
224 self::EXPRESSION_OP => array(
225 self::TYPE_BIN_OP => self::EXPRESSION,
226 self::TYPE_ADD_OP => self::EXPRESSION,
227 self::TYPE_HOOK => self::EXPRESSION_TERNARY,
228 self::TYPE_COLON => self::STATEMENT,
229 self::TYPE_COMMA => self::EXPRESSION,
230 self::TYPE_SEMICOLON => self::STATEMENT,
231 self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION
232 ),
233 self::EXPRESSION_FUNC => array(
234 self::TYPE_BRACE_OPEN => self::STATEMENT
235 ),
236 self::EXPRESSION_TERNARY => array(
237 self::TYPE_BRACE_OPEN => self::PROPERTY_ASSIGNMENT,
238 self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION,
239 self::TYPE_FUNC => self::EXPRESSION_TERNARY_FUNC,
240 self::TYPE_LITERAL => self::EXPRESSION_TERNARY_OP
241 ),
242 self::EXPRESSION_TERNARY_OP => array(
243 self::TYPE_BIN_OP => self::EXPRESSION_TERNARY,
244 self::TYPE_ADD_OP => self::EXPRESSION_TERNARY,
245 self::TYPE_HOOK => self::EXPRESSION_TERNARY,
246 self::TYPE_COMMA => self::EXPRESSION_TERNARY,
247 self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION
248 ),
249 self::EXPRESSION_TERNARY_FUNC => array(
250 self::TYPE_BRACE_OPEN => self::STATEMENT
251 ),
252 self::PAREN_EXPRESSION => array(
253 self::TYPE_BRACE_OPEN => self::PROPERTY_ASSIGNMENT,
254 self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION,
255 self::TYPE_FUNC => self::PAREN_EXPRESSION_FUNC,
256 self::TYPE_LITERAL => self::PAREN_EXPRESSION_OP
257 ),
258 self::PAREN_EXPRESSION_OP => array(
259 self::TYPE_BIN_OP => self::PAREN_EXPRESSION,
260 self::TYPE_ADD_OP => self::PAREN_EXPRESSION,
261 self::TYPE_HOOK => self::PAREN_EXPRESSION,
262 self::TYPE_COLON => self::PAREN_EXPRESSION,
263 self::TYPE_COMMA => self::PAREN_EXPRESSION,
264 self::TYPE_SEMICOLON => self::PAREN_EXPRESSION,
265 self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION
266 ),
267 self::PAREN_EXPRESSION_FUNC => array(
268 self::TYPE_BRACE_OPEN => self::STATEMENT
269 ),
270 self::PROPERTY_EXPRESSION => array(
271 self::TYPE_BRACE_OPEN => self::PROPERTY_ASSIGNMENT,
272 self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION,
273 self::TYPE_FUNC => self::PROPERTY_EXPRESSION_FUNC,
274 self::TYPE_LITERAL => self::PROPERTY_EXPRESSION_OP
275 ),
276 self::PROPERTY_EXPRESSION_OP => array(
277 self::TYPE_BIN_OP => self::PROPERTY_EXPRESSION,
278 self::TYPE_ADD_OP => self::PROPERTY_EXPRESSION,
279 self::TYPE_HOOK => self::PROPERTY_EXPRESSION,
280 self::TYPE_COMMA => self::PROPERTY_ASSIGNMENT,
281 self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION
282 ),
283 self::PROPERTY_EXPRESSION_FUNC => array(
284 self::TYPE_BRACE_OPEN => self::STATEMENT
285 )
286 );
287
288 // $push : This table contains the rules for when to push a state onto the stack.
289 // The pushed state is the state to return to when the corresponding
290 // closing token is found
291 $push = array(
292 self::STATEMENT => array(
293 self::TYPE_BRACE_OPEN => self::STATEMENT,
294 self::TYPE_PAREN_OPEN => self::EXPRESSION_OP
295 ),
296 self::CONDITION => array(
297 self::TYPE_PAREN_OPEN => self::STATEMENT
298 ),
299 self::PROPERTY_ASSIGNMENT => array(
300 self::TYPE_BRACE_OPEN => self::PROPERTY_ASSIGNMENT
301 ),
302 self::EXPRESSION => array(
303 self::TYPE_BRACE_OPEN => self::EXPRESSION_OP,
304 self::TYPE_PAREN_OPEN => self::EXPRESSION_OP
305 ),
306 self::EXPRESSION_NO_NL => array(
307 self::TYPE_BRACE_OPEN => self::EXPRESSION_OP,
308 self::TYPE_PAREN_OPEN => self::EXPRESSION_OP
309 ),
310 self::EXPRESSION_OP => array(
311 self::TYPE_HOOK => self::EXPRESSION,
312 self::TYPE_PAREN_OPEN => self::EXPRESSION_OP
313 ),
314 self::EXPRESSION_FUNC => array(
315 self::TYPE_BRACE_OPEN => self::EXPRESSION_OP
316 ),
317 self::EXPRESSION_TERNARY => array(
318 self::TYPE_BRACE_OPEN => self::EXPRESSION_TERNARY_OP,
319 self::TYPE_PAREN_OPEN => self::EXPRESSION_TERNARY_OP
320 ),
321 self::EXPRESSION_TERNARY_OP => array(
322 self::TYPE_HOOK => self::EXPRESSION_TERNARY,
323 self::TYPE_PAREN_OPEN => self::EXPRESSION_TERNARY_OP
324 ),
325 self::EXPRESSION_TERNARY_FUNC => array(
326 self::TYPE_BRACE_OPEN => self::EXPRESSION_TERNARY_OP
327 ),
328 self::PAREN_EXPRESSION => array(
329 self::TYPE_BRACE_OPEN => self::PAREN_EXPRESSION_OP,
330 self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION_OP
331 ),
332 self::PAREN_EXPRESSION_OP => array(
333 self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION_OP
334 ),
335 self::PAREN_EXPRESSION_FUNC => array(
336 self::TYPE_BRACE_OPEN => self::PAREN_EXPRESSION_OP
337 ),
338 self::PROPERTY_EXPRESSION => array(
339 self::TYPE_BRACE_OPEN => self::PROPERTY_EXPRESSION_OP,
340 self::TYPE_PAREN_OPEN => self::PROPERTY_EXPRESSION_OP
341 ),
342 self::PROPERTY_EXPRESSION_OP => array(
343 self::TYPE_PAREN_OPEN => self::PROPERTY_EXPRESSION_OP
344 ),
345 self::PROPERTY_EXPRESSION_FUNC => array(
346 self::TYPE_BRACE_OPEN => self::PROPERTY_EXPRESSION_OP
347 )
348 );
349
350 // $pop : Rules for when to pop a state from the stack
351 $pop = array(
352 self::STATEMENT => array( self::TYPE_BRACE_CLOSE => true ),
353 self::PROPERTY_ASSIGNMENT => array( self::TYPE_BRACE_CLOSE => true ),
354 self::EXPRESSION => array( self::TYPE_BRACE_CLOSE => true ),
355 self::EXPRESSION_NO_NL => array( self::TYPE_BRACE_CLOSE => true ),
356 self::EXPRESSION_OP => array( self::TYPE_BRACE_CLOSE => true ),
357 self::EXPRESSION_TERNARY_OP => array( self::TYPE_COLON => true ),
358 self::PAREN_EXPRESSION => array( self::TYPE_PAREN_CLOSE => true ),
359 self::PAREN_EXPRESSION_OP => array( self::TYPE_PAREN_CLOSE => true ),
360 self::PROPERTY_EXPRESSION => array( self::TYPE_BRACE_CLOSE => true ),
361 self::PROPERTY_EXPRESSION_OP => array( self::TYPE_BRACE_CLOSE => true )
362 );
363
364 // $semicolon : Rules for when a semicolon insertion is appropriate
365 $semicolon = array(
366 self::EXPRESSION_NO_NL => array(
367 self::TYPE_UN_OP => true,
368 self::TYPE_INCR_OP => true,
369 self::TYPE_ADD_OP => true,
370 self::TYPE_BRACE_OPEN => true,
371 self::TYPE_PAREN_OPEN => true,
372 self::TYPE_RETURN => true,
373 self::TYPE_IF => true,
374 self::TYPE_DO => true,
375 self::TYPE_FUNC => true,
376 self::TYPE_LITERAL => true
377 ),
378 self::EXPRESSION_OP => array(
379 self::TYPE_UN_OP => true,
380 self::TYPE_INCR_OP => true,
381 self::TYPE_BRACE_OPEN => true,
382 self::TYPE_RETURN => true,
383 self::TYPE_IF => true,
384 self::TYPE_DO => true,
385 self::TYPE_FUNC => true,
386 self::TYPE_LITERAL => true
387 )
388 );
389
390 // Rules for when newlines should be inserted if
391 // $statementsOnOwnLine is enabled.
392 // $newlineBefore is checked before switching state,
393 // $newlineAfter is checked after
394 $newlineBefore = array(
395 self::STATEMENT => array(
396 self::TYPE_BRACE_CLOSE => true,
397 ),
398 );
399 $newlineAfter = array(
400 self::STATEMENT => array(
401 self::TYPE_BRACE_OPEN => true,
402 self::TYPE_PAREN_CLOSE => true,
403 self::TYPE_SEMICOLON => true,
404 ),
405 );
406
407 // $divStates : Contains all states that can be followed by a division operator
408 $divStates = array(
409 self::EXPRESSION_OP => true,
410 self::EXPRESSION_TERNARY_OP => true,
411 self::PAREN_EXPRESSION_OP => true,
412 self::PROPERTY_EXPRESSION_OP => true
413 );
414
415 // Here's where the minifying takes place: Loop through the input, looking for tokens
416 // and output them to $out, taking actions to the above defined rules when appropriate.
417 $out = '';
418 $pos = 0;
419 $length = strlen( $s );
420 $lineLength = 0;
421 $newlineFound = true;
422 $state = self::STATEMENT;
423 $stack = array();
424 $last = ';'; // Pretend that we have seen a semicolon yet
425 while( $pos < $length ) {
426 // First, skip over any whitespace and multiline comments, recording whether we
427 // found any newline character
428 $skip = strspn( $s, " \t\n\r\xb\xc", $pos );
429 if( !$skip ) {
430 $ch = $s[$pos];
431 if( $ch === '/' && substr( $s, $pos, 2 ) === '/*' ) {
432 // Multiline comment. Search for the end token or EOT.
433 $end = strpos( $s, '*/', $pos + 2 );
434 $skip = $end === false ? $length - $pos : $end - $pos + 2;
435 }
436 }
437 if( $skip ) {
438 // The semicolon insertion mechanism needs to know whether there was a newline
439 // between two tokens, so record it now.
440 if( !$newlineFound && strcspn( $s, "\r\n", $pos, $skip ) !== $skip ) {
441 $newlineFound = true;
442 }
443 $pos += $skip;
444 continue;
445 }
446 // Handle C++-style comments and html comments, which are treated as single line
447 // comments by the browser, regardless of whether the end tag is on the same line.
448 // Handle --> the same way, but only if it's at the beginning of the line
449 if( ( $ch === '/' && substr( $s, $pos, 2 ) === '//' )
450 || ( $ch === '<' && substr( $s, $pos, 4 ) === '<!--' )
451 || ( $ch === '-' && $newlineFound && substr( $s, $pos, 3 ) === '-->' )
452 ) {
453 $pos += strcspn( $s, "\r\n", $pos );
454 continue;
455 }
456
457 // Find out which kind of token we're handling. $end will point past the end of it.
458 $end = $pos + 1;
459 // Handle string literals
460 if( $ch === "'" || $ch === '"' ) {
461 // Search to the end of the string literal, skipping over backslash escapes
462 $search = $ch . '\\';
463 do{
464 $end += strcspn( $s, $search, $end ) + 2;
465 } while( $end - 2 < $length && $s[$end - 2] === '\\' );
466 $end--;
467 // We have to distinguish between regexp literals and division operators
468 // A division operator is only possible in certain states
469 } elseif( $ch === '/' && !isset( $divStates[$state] ) ) {
470 // Regexp literal, search to the end, skipping over backslash escapes and
471 // character classes
472 for( ; ; ) {
473 do{
474 $end += strcspn( $s, '/[\\', $end ) + 2;
475 } while( $end - 2 < $length && $s[$end - 2] === '\\' );
476 $end--;
477 if( $end - 1 >= $length || $s[$end - 1] === '/' ) {
478 break;
479 }
480 do{
481 $end += strcspn( $s, ']\\', $end ) + 2;
482 } while( $end - 2 < $length && $s[$end - 2] === '\\' );
483 $end--;
484 };
485 // Search past the regexp modifiers (gi)
486 while( $end < $length && ctype_alpha( $s[$end] ) ) {
487 $end++;
488 }
489 } elseif(
490 $ch === '0'
491 && ($pos + 1 < $length) && ($s[$pos + 1] === 'x' || $s[$pos + 1] === 'X' )
492 ) {
493 // Hex numeric literal
494 $end++; // x or X
495 $len = strspn( $s, '0123456789ABCDEFabcdef', $end );
496 if ( !$len ) {
497 return self::parseError($s, $pos, 'Expected a hexadecimal number but found ' . substr( $s, $pos, 5 ) . '...' );
498 }
499 $end += $len;
500 } elseif(
501 ctype_digit( $ch )
502 || ( $ch === '.' && $pos + 1 < $length && ctype_digit( $s[$pos + 1] ) )
503 ) {
504 $end += strspn( $s, '0123456789', $end );
505 $decimal = strspn( $s, '.', $end );
506 if ($decimal) {
507 if ( $decimal > 2 ) {
508 return self::parseError($s, $end, 'The number has too many decimal points' );
509 }
510 $end += strspn( $s, '0123456789', $end + 1 ) + $decimal;
511 }
512 $exponent = strspn( $s, 'eE', $end );
513 if( $exponent ) {
514 if ( $exponent > 1 ) {
515 return self::parseError($s, $end, 'Number with several E' );
516 }
517 $end++;
518
519 // + sign is optional; - sign is required.
520 $end += strspn( $s, '-+', $end );
521 $len = strspn( $s, '0123456789', $end );
522 if ( !$len ) {
523 return self::parseError($s, $pos, 'No decimal digits after e, how many zeroes should be added?' );
524 }
525 $end += $len;
526 }
527 } elseif( isset( $opChars[$ch] ) ) {
528 // Punctuation character. Search for the longest matching operator.
529 while(
530 $end < $length
531 && isset( $tokenTypes[substr( $s, $pos, $end - $pos + 1 )] )
532 ) {
533 $end++;
534 }
535 } else {
536 // Identifier or reserved word. Search for the end by excluding whitespace and
537 // punctuation.
538 $end += strcspn( $s, " \t\n.;,=<>+-{}()[]?:*/%'\"!&|^~\xb\xc\r", $end );
539 }
540
541 // Now get the token type from our type array
542 $token = substr( $s, $pos, $end - $pos ); // so $end - $pos == strlen( $token )
543 $type = isset( $tokenTypes[$token] ) ? $tokenTypes[$token] : self::TYPE_LITERAL;
544
545 if( $newlineFound && isset( $semicolon[$state][$type] ) ) {
546 // This token triggers the semicolon insertion mechanism of javascript. While we
547 // could add the ; token here ourselves, keeping the newline has a few advantages.
548 $out .= "\n";
549 $state = self::STATEMENT;
550 $lineLength = 0;
551 } elseif( $maxLineLength > 0 && $lineLength + $end - $pos > $maxLineLength &&
552 !isset( $semicolon[$state][$type] ) && $type !== self::TYPE_INCR_OP )
553 {
554 // This line would get too long if we added $token, so add a newline first.
555 // Only do this if it won't trigger semicolon insertion and if it won't
556 // put a postfix increment operator on its own line, which is illegal in js.
557 $out .= "\n";
558 $lineLength = 0;
559 // Check, whether we have to separate the token from the last one with whitespace
560 } elseif( !isset( $opChars[$last] ) && !isset( $opChars[$ch] ) ) {
561 $out .= ' ';
562 $lineLength++;
563 // Don't accidentally create ++, -- or // tokens
564 } elseif( $last === $ch && ( $ch === '+' || $ch === '-' || $ch === '/' ) ) {
565 $out .= ' ';
566 $lineLength++;
567 }
568 if (
569 $type === self::TYPE_LITERAL
570 && ( $token === 'true' || $token === 'false' )
571 && ( $state === self::EXPRESSION || $state === self::PROPERTY_EXPRESSION )
572 && $last !== '.'
573 ) {
574 $token = ( $token === 'true' ) ? '!0' : '!1';
575 }
576
577 $out .= $token;
578 $lineLength += $end - $pos; // += strlen( $token )
579 $last = $s[$end - 1];
580 $pos = $end;
581 $newlineFound = false;
582
583 // Output a newline after the token if required
584 // This is checked before AND after switching state
585 $newlineAdded = false;
586 if ( $statementsOnOwnLine && !$newlineAdded && isset( $newlineBefore[$state][$type] ) ) {
587 $out .= "\n";
588 $lineLength = 0;
589 $newlineAdded = true;
590 }
591
592 // Now that we have output our token, transition into the new state.
593 if( isset( $push[$state][$type] ) && count( $stack ) < self::STACK_LIMIT ) {
594 $stack[] = $push[$state][$type];
595 }
596 if( $stack && isset( $pop[$state][$type] ) ) {
597 $state = array_pop( $stack );
598 } elseif( isset( $goto[$state][$type] ) ) {
599 $state = $goto[$state][$type];
600 }
601
602 // Check for newline insertion again
603 if ( $statementsOnOwnLine && !$newlineAdded && isset( $newlineAfter[$state][$type] ) ) {
604 $out .= "\n";
605 $lineLength = 0;
606 }
607 }
608 return $out;
609 }
610
611 static function parseError($fullJavascript, $position, $errorMsg) {
612 // TODO: Handle the error: trigger_error, throw exception, return false...
613 return false;
614 }
615}
This class is meant to safely minify javascript code, while leaving syntactically correct programs in...
static parseError($fullJavascript, $position, $errorMsg)
static minify( $s, $statementsOnOwnLine=false, $maxLineLength=1000)
Returns minified JavaScript code.
the array() calling protocol came about after MediaWiki 1.4rc1.
namespace are movable Hooks may change this value to override the return value of MWNamespace::isMovable(). 'NewDifferenceEngine' do that in ParserLimitReportFormat instead use this to modify the parameters of the image and a DIV can begin in one section and end in another Make sure your code can handle that case gracefully See the EditSectionClearerLink extension for an example zero but section is usually empty its values are the globals values before the output is cached one of or reset my talk my contributions etc etc otherwise the built in rate limiting checks are if enabled allows for interception of redirect as a string mapping parameter names to values & $type
Definition hooks.txt:2568
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that probably a stub it is not rendered in wiki pages or galleries in category pages allow injecting custom HTML after the section Any uses of the hook need to handle escaping see BaseTemplate::getToolbox and BaseTemplate::makeListItem for details on the format of individual items inside of this array or by returning and letting standard HTTP rendering take place modifiable or by returning false and taking over the output $out
Definition hooks.txt:886
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition injection.txt:37
$last