MediaWiki  1.27.2
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
39  const PAREN_EXPRESSION_OP = 11;
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 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:762
the array() calling protocol came about after MediaWiki 1.4rc1.
This class is meant to safely minify javascript code, while leaving syntactically correct programs in...
$last
static parseError($fullJavascript, $position, $errorMsg)
static minify($s, $statementsOnOwnLine=false, $maxLineLength=1000)
Returns minified JavaScript code.
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:35
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:2338