| [ Index ] |
PHP Cross Reference of Drupal 6 (gatewave) |
[Summary view] [Print] [Text view]
1 /* 2 3 JS Beautifier 4 --------------- 5 $Date: 2008-04-21 16:13:36 +0300 (Mon, 21 Apr 2008) $ 6 $Revision: 53 $ 7 8 9 Written by Einars "elfz" Lielmanis, <elfz@laacz.lv> 10 http://elfz.laacz.lv/beautify/ 11 12 Originally converted to javascript by Vital, <vital76@gmail.com> 13 http://my.opera.com/Vital/blog/2007/11/21/javascript-beautify-on-javascript-translated 14 15 16 You are free to use this in any way you want, in case you find this useful or working for you. 17 18 Usage: 19 js_beautify(js_source_text); 20 21 */ 22 23 24 function js_beautify(js_source_text, indent_size, indent_character) 25 { 26 27 var input, output, token_text, last_type, last_text, last_word, current_mode, modes, indent_level, indent_string; 28 var whitespace, wordchar, punct, parser_pos, line_starters, in_case; 29 var prefix, token_type; 30 31 function print_newline(ignore_repeated) 32 { 33 ignore_repeated = typeof ignore_repeated === 'undefined' ? true: ignore_repeated; 34 35 // remove trailing whitespace and indent 36 while (output.length && (output[output.length - 1] === ' ' || output[output.length - 1] === indent_string)) { 37 output.pop(); 38 } 39 40 if (!output.length) { 41 return; // no newline on start of file 42 } 43 44 if (output[output.length - 1] !== "\n" || !ignore_repeated) { 45 output.push("\n"); 46 } 47 for (var i = 0; i < indent_level; i++) { 48 output.push(indent_string); 49 } 50 } 51 52 53 54 function print_space() 55 { 56 var last_output = output.length ? output[output.length - 1] : ' '; 57 if (last_output !== ' ' && last_output !== '\n' && last_output !== indent_string) { // prevent occassional duplicate space 58 output.push(' '); 59 } 60 } 61 62 63 function print_token() 64 { 65 output.push(token_text); 66 } 67 68 function indent() 69 { 70 indent_level++; 71 } 72 73 74 function unindent() 75 { 76 if (indent_level) { 77 indent_level--; 78 } 79 } 80 81 82 function remove_indent() 83 { 84 if (output.length && output[output.length - 1] === indent_string) { 85 output.pop(); 86 } 87 } 88 89 90 function set_mode(mode) 91 { 92 modes.push(current_mode); 93 current_mode = mode; 94 } 95 96 97 function restore_mode() 98 { 99 current_mode = modes.pop(); 100 } 101 102 103 function in_array(what, arr) 104 { 105 for (var i = 0; i < arr.length; i++) 106 { 107 if (arr[i] === what) { 108 return true; 109 } 110 } 111 return false; 112 } 113 114 115 116 function get_next_token() 117 { 118 var n_newlines = 0; 119 var c = ''; 120 121 do { 122 if (parser_pos >= input.length) { 123 return ['', 'TK_EOF']; 124 } 125 c = input.charAt(parser_pos); 126 127 parser_pos += 1; 128 if (c === "\n") { 129 n_newlines += 1; 130 } 131 } 132 while (in_array(c, whitespace)); 133 134 if (n_newlines > 1) { 135 for (var i = 0; i < 2; i++) { 136 print_newline(i === 0); 137 } 138 } 139 var wanted_newline = (n_newlines === 1); 140 141 142 if (in_array(c, wordchar)) { 143 if (parser_pos < input.length) { 144 while (in_array(input.charAt(parser_pos), wordchar)) { 145 c += input.charAt(parser_pos); 146 parser_pos += 1; 147 if (parser_pos === input.length) { 148 break; 149 } 150 } 151 } 152 153 // small and surprisingly unugly hack for 1E-10 representation 154 if (parser_pos !== input.length && c.match(/^[0-9]+[Ee]$/) && input.charAt(parser_pos) === '-') { 155 parser_pos += 1; 156 157 var t = get_next_token(parser_pos); 158 c += '-' + t[0]; 159 return [c, 'TK_WORD']; 160 } 161 162 if (c === 'in') { // hack for 'in' operator 163 return [c, 'TK_OPERATOR']; 164 } 165 return [c, 'TK_WORD']; 166 } 167 168 if (c === '(' || c === '[') { 169 return [c, 'TK_START_EXPR']; 170 } 171 172 if (c === ')' || c === ']') { 173 return [c, 'TK_END_EXPR']; 174 } 175 176 if (c === '{') { 177 return [c, 'TK_START_BLOCK']; 178 } 179 180 if (c === '}') { 181 return [c, 'TK_END_BLOCK']; 182 } 183 184 if (c === ';') { 185 return [c, 'TK_END_COMMAND']; 186 } 187 188 if (c === '/') { 189 var comment = ''; 190 // peek for comment /* ... */ 191 if (input.charAt(parser_pos) === '*') { 192 parser_pos += 1; 193 if (parser_pos < input.length) { 194 while (! (input.charAt(parser_pos) === '*' && input.charAt(parser_pos + 1) && input.charAt(parser_pos + 1) === '/') && parser_pos < input.length) { 195 comment += input.charAt(parser_pos); 196 parser_pos += 1; 197 if (parser_pos >= input.length) { 198 break; 199 } 200 } 201 } 202 parser_pos += 2; 203 return ['/*' + comment + '*/', 'TK_BLOCK_COMMENT']; 204 } 205 // peek for comment // ... 206 if (input.charAt(parser_pos) === '/') { 207 comment = c; 208 while (input.charAt(parser_pos) !== "\x0d" && input.charAt(parser_pos) !== "\x0a") { 209 comment += input.charAt(parser_pos); 210 parser_pos += 1; 211 if (parser_pos >= input.length) { 212 break; 213 } 214 } 215 parser_pos += 1; 216 if (wanted_newline) { 217 print_newline(); 218 } 219 return [comment, 'TK_COMMENT']; 220 } 221 222 } 223 224 if (c === "'" || // string 225 c === '"' || // string 226 (c === '/' && 227 ((last_type === 'TK_WORD' && last_text === 'return') || (last_type === 'TK_START_EXPR' || last_type === 'TK_END_BLOCK' || last_type === 'TK_OPERATOR' || last_type === 'TK_EOF' || last_type === 'TK_END_COMMAND')))) { // regexp 228 var sep = c; 229 var esc = false; 230 c = ''; 231 232 if (parser_pos < input.length) { 233 234 while (esc || input.charAt(parser_pos) !== sep) { 235 c += input.charAt(parser_pos); 236 if (!esc) { 237 esc = input.charAt(parser_pos) === '\\'; 238 } else { 239 esc = false; 240 } 241 parser_pos += 1; 242 if (parser_pos >= input.length) { 243 break; 244 } 245 } 246 247 } 248 249 parser_pos += 1; 250 if (last_type === 'TK_END_COMMAND') { 251 print_newline(); 252 } 253 return [sep + c + sep, 'TK_STRING']; 254 } 255 256 if (in_array(c, punct)) { 257 while (parser_pos < input.length && in_array(c + input.charAt(parser_pos), punct)) { 258 c += input.charAt(parser_pos); 259 parser_pos += 1; 260 if (parser_pos >= input.length) { 261 break; 262 } 263 } 264 return [c, 'TK_OPERATOR']; 265 } 266 267 return [c, 'TK_UNKNOWN']; 268 } 269 270 271 //---------------------------------- 272 273 indent_character = indent_character || ' '; 274 indent_size = indent_size || 4; 275 276 indent_string = ''; 277 while (indent_size--) { 278 indent_string += indent_character; 279 } 280 281 input = js_source_text; 282 283 last_word = ''; // last 'TK_WORD' passed 284 last_type = 'TK_START_EXPR'; // last token type 285 last_text = ''; // last token text 286 output = []; 287 288 whitespace = "\n\r\t ".split(''); 289 wordchar = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$'.split(''); 290 punct = '+ - * / % & ++ -- = += -= *= /= %= == === != !== > < >= <= >> << >>> >>>= >>= <<= && &= | || ! !! , : ? ^ ^= |='.split(' '); 291 292 // words which should always start on new line. 293 line_starters = 'continue,try,throw,return,var,if,switch,case,default,for,while,break,function'.split(','); 294 295 // states showing if we are currently in expression (i.e. "if" case) - 'EXPRESSION', or in usual block (like, procedure), 'BLOCK'. 296 // some formatting depends on that. 297 current_mode = 'BLOCK'; 298 modes = [current_mode]; 299 300 indent_level = 0; 301 parser_pos = 0; // parser position 302 in_case = false; // flag for parser that case/default has been processed, and next colon needs special attention 303 while (true) { 304 var t = get_next_token(parser_pos); 305 token_text = t[0]; 306 token_type = t[1]; 307 if (token_type === 'TK_EOF') { 308 break; 309 } 310 311 switch (token_type) { 312 313 case 'TK_START_EXPR': 314 315 set_mode('EXPRESSION'); 316 if (last_type === 'TK_END_EXPR' || last_type === 'TK_START_EXPR') { 317 // do nothing on (( and )( and ][ and ]( .. 318 } else if (last_type !== 'TK_WORD' && last_type !== 'TK_OPERATOR') { 319 print_space(); 320 } else if (in_array(last_word, line_starters) && last_word !== 'function') { 321 print_space(); 322 } 323 print_token(); 324 break; 325 326 case 'TK_END_EXPR': 327 328 print_token(); 329 restore_mode(); 330 break; 331 332 case 'TK_START_BLOCK': 333 334 set_mode('BLOCK'); 335 if (last_type !== 'TK_OPERATOR' && last_type !== 'TK_START_EXPR') { 336 if (last_type === 'TK_START_BLOCK') { 337 print_newline(); 338 } else { 339 print_space(); 340 } 341 } 342 print_token(); 343 indent(); 344 break; 345 346 case 'TK_END_BLOCK': 347 if (last_type === 'TK_START_BLOCK') { 348 // nothing 349 unindent(); 350 } else { 351 unindent(); 352 print_newline(); 353 } 354 print_token(); 355 restore_mode(); 356 break; 357 358 case 'TK_WORD': 359 360 if (token_text === 'case' || token_text === 'default') { 361 if (last_text === ':') { 362 // switch cases following one another 363 remove_indent(); 364 } else { 365 // case statement starts in the same line where switch 366 unindent(); 367 print_newline(); 368 indent(); 369 } 370 print_token(); 371 in_case = true; 372 break; 373 } 374 375 prefix = 'NONE'; 376 if (last_type === 'TK_END_BLOCK') { 377 if (!in_array(token_text.toLowerCase(), ['else', 'catch', 'finally'])) { 378 prefix = 'NEWLINE'; 379 } else { 380 prefix = 'SPACE'; 381 print_space(); 382 } 383 } else if (last_type === 'TK_END_COMMAND' && current_mode === 'BLOCK') { 384 prefix = 'NEWLINE'; 385 } else if (last_type === 'TK_END_COMMAND' && current_mode === 'EXPRESSION') { 386 prefix = 'SPACE'; 387 } else if (last_type === 'TK_WORD') { 388 prefix = 'SPACE'; 389 } else if (last_type === 'TK_START_BLOCK') { 390 prefix = 'NEWLINE'; 391 } else if (last_type === 'TK_END_EXPR') { 392 print_space(); 393 prefix = 'NEWLINE'; 394 } 395 396 if (in_array(token_text, line_starters) || prefix === 'NEWLINE') { 397 398 if (last_text === 'else') { 399 // no need to force newline on else break 400 print_space(); 401 } else if ((last_type === 'TK_START_EXPR' || last_text === '=') && token_text === 'function') { 402 // no need to force newline on 'function': (function 403 // DONOTHING 404 } else if (last_type === 'TK_WORD' && (last_text === 'return' || last_text === 'throw')) { 405 // no newline between 'return nnn' 406 print_space(); 407 } else if (last_type !== 'TK_END_EXPR') { 408 if ((last_type !== 'TK_START_EXPR' || token_text !== 'var') && last_text !== ':') { 409 // no need to force newline on 'var': for (var x = 0...) 410 if (token_text === 'if' && last_type === 'TK_WORD' && last_word === 'else') { 411 // no newline for } else if { 412 print_space(); 413 } else { 414 print_newline(); 415 } 416 } 417 } 418 } else if (prefix === 'SPACE') { 419 print_space(); 420 } 421 print_token(); 422 last_word = token_text; 423 break; 424 425 case 'TK_END_COMMAND': 426 427 print_token(); 428 break; 429 430 case 'TK_STRING': 431 432 if (last_type === 'TK_START_BLOCK' || last_type === 'TK_END_BLOCK') { 433 print_newline(); 434 } else if (last_type === 'TK_WORD') { 435 print_space(); 436 } 437 print_token(); 438 break; 439 440 case 'TK_OPERATOR': 441 442 var start_delim = true; 443 var end_delim = true; 444 445 if (token_text === ':' && in_case) { 446 print_token(); // colon really asks for separate treatment 447 print_newline(); 448 break; 449 } 450 451 in_case = false; 452 453 if (token_text === ',') { 454 if (last_type === 'TK_END_BLOCK') { 455 print_token(); 456 print_newline(); 457 } else { 458 if (current_mode === 'BLOCK') { 459 print_token(); 460 print_newline(); 461 } else { 462 print_token(); 463 print_space(); 464 } 465 } 466 break; 467 } else if (token_text === '--' || token_text === '++') { // unary operators special case 468 if (last_text === ';') { 469 // space for (;; ++i) 470 start_delim = true; 471 end_delim = false; 472 } else { 473 start_delim = false; 474 end_delim = false; 475 } 476 } else if (token_text === '!' && last_type === 'TK_START_EXPR') { 477 // special case handling: if (!a) 478 start_delim = false; 479 end_delim = false; 480 } else if (last_type === 'TK_OPERATOR') { 481 start_delim = false; 482 end_delim = false; 483 } else if (last_type === 'TK_END_EXPR') { 484 start_delim = true; 485 end_delim = true; 486 } else if (token_text === '.') { 487 // decimal digits or object.property 488 start_delim = false; 489 end_delim = false; 490 491 } else if (token_text === ':') { 492 // zz: xx 493 // can't differentiate ternary op, so for now it's a ? b: c; without space before colon 494 start_delim = false; 495 } 496 if (start_delim) { 497 print_space(); 498 } 499 500 print_token(); 501 502 if (end_delim) { 503 print_space(); 504 } 505 break; 506 507 case 'TK_BLOCK_COMMENT': 508 509 print_newline(); 510 print_token(); 511 print_newline(); 512 break; 513 514 case 'TK_COMMENT': 515 516 // print_newline(); 517 print_space(); 518 print_token(); 519 print_newline(); 520 break; 521 522 case 'TK_UNKNOWN': 523 print_token(); 524 break; 525 } 526 527 last_type = token_type; 528 last_text = token_text; 529 } 530 531 return output.join(''); 532 533 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Thu Mar 24 11:18:33 2011 | Cross-referenced by PHPXref 0.7 |