browser/devtools/shared/Jsbeautify.jsm

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /*jslint onevar: false, plusplus: false */
michael@0 2 /*jshint curly:true, eqeqeq:true, laxbreak:true, noempty:false */
michael@0 3 /*
michael@0 4
michael@0 5 JS Beautifier
michael@0 6 ---------------
michael@0 7
michael@0 8
michael@0 9 Written by Einar Lielmanis, <einar@jsbeautifier.org>
michael@0 10 http://jsbeautifier.org/
michael@0 11
michael@0 12 Originally converted to javascript by Vital, <vital76@gmail.com>
michael@0 13 "End braces on own line" added by Chris J. Shull, <chrisjshull@gmail.com>
michael@0 14
michael@0 15 You are free to use this in any way you want, in case you find this useful or working for you.
michael@0 16
michael@0 17 Usage:
michael@0 18 js_beautify(js_source_text);
michael@0 19 js_beautify(js_source_text, options);
michael@0 20
michael@0 21 The options are:
michael@0 22 indent_size (default 4) - indentation size,
michael@0 23 indent_char (default space) - character to indent with,
michael@0 24 preserve_newlines (default true) - whether existing line breaks should be preserved,
michael@0 25 max_preserve_newlines (default unlimited) - maximum number of line breaks to be preserved in one chunk,
michael@0 26
michael@0 27 jslint_happy (default false) - if true, then jslint-stricter mode is enforced.
michael@0 28
michael@0 29 jslint_happy !jslint_happy
michael@0 30 ---------------------------------
michael@0 31 function () function()
michael@0 32
michael@0 33 brace_style (default "collapse") - "collapse" | "expand" | "end-expand" | "expand-strict"
michael@0 34 put braces on the same line as control statements (default), or put braces on own line (Allman / ANSI style), or just put end braces on own line.
michael@0 35
michael@0 36 expand-strict: put brace on own line even in such cases:
michael@0 37
michael@0 38 var a =
michael@0 39 {
michael@0 40 a: 5,
michael@0 41 b: 6
michael@0 42 }
michael@0 43 This mode may break your scripts - e.g "return { a: 1 }" will be broken into two lines, so beware.
michael@0 44
michael@0 45 space_before_conditional (default true) - should the space before conditional statement be added, "if(true)" vs "if (true)",
michael@0 46
michael@0 47 unescape_strings (default false) - should printable characters in strings encoded in \xNN notation be unescaped, "example" vs "\x65\x78\x61\x6d\x70\x6c\x65"
michael@0 48
michael@0 49 e.g
michael@0 50
michael@0 51 js_beautify(js_source_text, {
michael@0 52 'indent_size': 1,
michael@0 53 'indent_char': '\t'
michael@0 54 });
michael@0 55
michael@0 56
michael@0 57 */
michael@0 58
michael@0 59 this.EXPORTED_SYMBOLS = ["js_beautify"];
michael@0 60
michael@0 61 this.js_beautify = function js_beautify(js_source_text, options) {
michael@0 62
michael@0 63 var input, output, token_text, last_type, last_text, last_last_text, last_word, flags, flag_store, indent_string;
michael@0 64 var whitespace, wordchar, punct, parser_pos, line_starters, digits;
michael@0 65 var prefix, token_type, do_block_just_closed;
michael@0 66 var wanted_newline, just_added_newline, n_newlines;
michael@0 67 var preindent_string = '';
michael@0 68
michael@0 69
michael@0 70 // Some interpreters have unexpected results with foo = baz || bar;
michael@0 71 options = options ? options : {};
michael@0 72
michael@0 73 var opt_brace_style;
michael@0 74
michael@0 75 // compatibility
michael@0 76 if (options.space_after_anon_function !== undefined && options.jslint_happy === undefined) {
michael@0 77 options.jslint_happy = options.space_after_anon_function;
michael@0 78 }
michael@0 79 if (options.braces_on_own_line !== undefined) { //graceful handling of deprecated option
michael@0 80 opt_brace_style = options.braces_on_own_line ? "expand" : "collapse";
michael@0 81 }
michael@0 82 opt_brace_style = options.brace_style ? options.brace_style : (opt_brace_style ? opt_brace_style : "collapse");
michael@0 83
michael@0 84
michael@0 85 var opt_indent_size = options.indent_size ? options.indent_size : 4;
michael@0 86 var opt_indent_char = options.indent_char ? options.indent_char : ' ';
michael@0 87 var opt_preserve_newlines = typeof options.preserve_newlines === 'undefined' ? true : options.preserve_newlines;
michael@0 88 var opt_max_preserve_newlines = typeof options.max_preserve_newlines === 'undefined' ? false : options.max_preserve_newlines;
michael@0 89 var opt_jslint_happy = options.jslint_happy === 'undefined' ? false : options.jslint_happy;
michael@0 90 var opt_keep_array_indentation = typeof options.keep_array_indentation === 'undefined' ? false : options.keep_array_indentation;
michael@0 91 var opt_space_before_conditional = typeof options.space_before_conditional === 'undefined' ? true : options.space_before_conditional;
michael@0 92 var opt_indent_case = typeof options.indent_case === 'undefined' ? false : options.indent_case;
michael@0 93 var opt_unescape_strings = typeof options.unescape_strings === 'undefined' ? false : options.unescape_strings;
michael@0 94
michael@0 95 just_added_newline = false;
michael@0 96
michael@0 97 // cache the source's length.
michael@0 98 var input_length = js_source_text.length;
michael@0 99
michael@0 100 function trim_output(eat_newlines) {
michael@0 101 eat_newlines = typeof eat_newlines === 'undefined' ? false : eat_newlines;
michael@0 102 while (output.length && (output[output.length - 1] === ' '
michael@0 103 || output[output.length - 1] === indent_string
michael@0 104 || output[output.length - 1] === preindent_string
michael@0 105 || (eat_newlines && (output[output.length - 1] === '\n' || output[output.length - 1] === '\r')))) {
michael@0 106 output.pop();
michael@0 107 }
michael@0 108 }
michael@0 109
michael@0 110 function trim(s) {
michael@0 111 return s.replace(/^\s\s*|\s\s*$/, '');
michael@0 112 }
michael@0 113
michael@0 114 // we could use just string.split, but
michael@0 115 // IE doesn't like returning empty strings
michael@0 116 function split_newlines(s) {
michael@0 117 return s.split(/\x0d\x0a|\x0a/);
michael@0 118 }
michael@0 119
michael@0 120 function force_newline() {
michael@0 121 var old_keep_array_indentation = opt_keep_array_indentation;
michael@0 122 opt_keep_array_indentation = false;
michael@0 123 print_newline();
michael@0 124 opt_keep_array_indentation = old_keep_array_indentation;
michael@0 125 }
michael@0 126
michael@0 127 function print_newline(ignore_repeated) {
michael@0 128
michael@0 129 flags.eat_next_space = false;
michael@0 130 if (opt_keep_array_indentation && is_array(flags.mode)) {
michael@0 131 return;
michael@0 132 }
michael@0 133
michael@0 134 ignore_repeated = typeof ignore_repeated === 'undefined' ? true : ignore_repeated;
michael@0 135
michael@0 136 flags.if_line = false;
michael@0 137 trim_output();
michael@0 138
michael@0 139 if (!output.length) {
michael@0 140 return; // no newline on start of file
michael@0 141 }
michael@0 142
michael@0 143 if (output[output.length - 1] !== "\n" || !ignore_repeated) {
michael@0 144 just_added_newline = true;
michael@0 145 output.push("\n");
michael@0 146 }
michael@0 147 if (preindent_string) {
michael@0 148 output.push(preindent_string);
michael@0 149 }
michael@0 150 for (var i = 0; i < flags.indentation_level; i += 1) {
michael@0 151 output.push(indent_string);
michael@0 152 }
michael@0 153 if (flags.var_line && flags.var_line_reindented) {
michael@0 154 output.push(indent_string); // skip space-stuffing, if indenting with a tab
michael@0 155 }
michael@0 156 if (flags.case_body) {
michael@0 157 output.push(indent_string);
michael@0 158 }
michael@0 159 }
michael@0 160
michael@0 161
michael@0 162
michael@0 163 function print_single_space() {
michael@0 164
michael@0 165 if (last_type === 'TK_COMMENT') {
michael@0 166 return print_newline();
michael@0 167 }
michael@0 168 if (flags.eat_next_space) {
michael@0 169 flags.eat_next_space = false;
michael@0 170 return;
michael@0 171 }
michael@0 172 var last_output = ' ';
michael@0 173 if (output.length) {
michael@0 174 last_output = output[output.length - 1];
michael@0 175 }
michael@0 176 if (last_output !== ' ' && last_output !== '\n' && last_output !== indent_string) { // prevent occassional duplicate space
michael@0 177 output.push(' ');
michael@0 178 }
michael@0 179 }
michael@0 180
michael@0 181
michael@0 182 function print_token() {
michael@0 183 just_added_newline = false;
michael@0 184 flags.eat_next_space = false;
michael@0 185 output.push(token_text);
michael@0 186 }
michael@0 187
michael@0 188 function indent() {
michael@0 189 flags.indentation_level += 1;
michael@0 190 }
michael@0 191
michael@0 192
michael@0 193 function remove_indent() {
michael@0 194 if (output.length && output[output.length - 1] === indent_string) {
michael@0 195 output.pop();
michael@0 196 }
michael@0 197 }
michael@0 198
michael@0 199 function set_mode(mode) {
michael@0 200 if (flags) {
michael@0 201 flag_store.push(flags);
michael@0 202 }
michael@0 203 flags = {
michael@0 204 previous_mode: flags ? flags.mode : 'BLOCK',
michael@0 205 mode: mode,
michael@0 206 var_line: false,
michael@0 207 var_line_tainted: false,
michael@0 208 var_line_reindented: false,
michael@0 209 in_html_comment: false,
michael@0 210 if_line: false,
michael@0 211 in_case_statement: false, // switch(..){ INSIDE HERE }
michael@0 212 in_case: false, // we're on the exact line with "case 0:"
michael@0 213 case_body: false, // the indented case-action block
michael@0 214 eat_next_space: false,
michael@0 215 indentation_baseline: -1,
michael@0 216 indentation_level: (flags ? flags.indentation_level + (flags.case_body ? 1 : 0) + ((flags.var_line && flags.var_line_reindented) ? 1 : 0) : 0),
michael@0 217 ternary_depth: 0
michael@0 218 };
michael@0 219 }
michael@0 220
michael@0 221 function is_array(mode) {
michael@0 222 return mode === '[EXPRESSION]' || mode === '[INDENTED-EXPRESSION]';
michael@0 223 }
michael@0 224
michael@0 225 function is_expression(mode) {
michael@0 226 return in_array(mode, ['[EXPRESSION]', '(EXPRESSION)', '(FOR-EXPRESSION)', '(COND-EXPRESSION)']);
michael@0 227 }
michael@0 228
michael@0 229 function restore_mode() {
michael@0 230 do_block_just_closed = flags.mode === 'DO_BLOCK';
michael@0 231 if (flag_store.length > 0) {
michael@0 232 var mode = flags.mode;
michael@0 233 flags = flag_store.pop();
michael@0 234 flags.previous_mode = mode;
michael@0 235 }
michael@0 236 }
michael@0 237
michael@0 238 function all_lines_start_with(lines, c) {
michael@0 239 for (var i = 0; i < lines.length; i++) {
michael@0 240 var line = trim(lines[i]);
michael@0 241 if (line.charAt(0) !== c) {
michael@0 242 return false;
michael@0 243 }
michael@0 244 }
michael@0 245 return true;
michael@0 246 }
michael@0 247
michael@0 248 function is_special_word(word) {
michael@0 249 return in_array(word, ['case', 'return', 'do', 'if', 'throw', 'else']);
michael@0 250 }
michael@0 251
michael@0 252 function in_array(what, arr) {
michael@0 253 for (var i = 0; i < arr.length; i += 1) {
michael@0 254 if (arr[i] === what) {
michael@0 255 return true;
michael@0 256 }
michael@0 257 }
michael@0 258 return false;
michael@0 259 }
michael@0 260
michael@0 261 function look_up(exclude) {
michael@0 262 var local_pos = parser_pos;
michael@0 263 var c = input.charAt(local_pos);
michael@0 264 while (in_array(c, whitespace) && c !== exclude) {
michael@0 265 local_pos++;
michael@0 266 if (local_pos >= input_length) {
michael@0 267 return 0;
michael@0 268 }
michael@0 269 c = input.charAt(local_pos);
michael@0 270 }
michael@0 271 return c;
michael@0 272 }
michael@0 273
michael@0 274 function get_next_token() {
michael@0 275 var i;
michael@0 276 var resulting_string;
michael@0 277
michael@0 278 n_newlines = 0;
michael@0 279
michael@0 280 if (parser_pos >= input_length) {
michael@0 281 return ['', 'TK_EOF'];
michael@0 282 }
michael@0 283
michael@0 284 wanted_newline = false;
michael@0 285
michael@0 286 var c = input.charAt(parser_pos);
michael@0 287 parser_pos += 1;
michael@0 288
michael@0 289
michael@0 290 var keep_whitespace = opt_keep_array_indentation && is_array(flags.mode);
michael@0 291
michael@0 292 if (keep_whitespace) {
michael@0 293
michael@0 294 //
michael@0 295 // slight mess to allow nice preservation of array indentation and reindent that correctly
michael@0 296 // first time when we get to the arrays:
michael@0 297 // var a = [
michael@0 298 // ....'something'
michael@0 299 // we make note of whitespace_count = 4 into flags.indentation_baseline
michael@0 300 // so we know that 4 whitespaces in original source match indent_level of reindented source
michael@0 301 //
michael@0 302 // and afterwards, when we get to
michael@0 303 // 'something,
michael@0 304 // .......'something else'
michael@0 305 // we know that this should be indented to indent_level + (7 - indentation_baseline) spaces
michael@0 306 //
michael@0 307 var whitespace_count = 0;
michael@0 308
michael@0 309 while (in_array(c, whitespace)) {
michael@0 310
michael@0 311 if (c === "\n") {
michael@0 312 trim_output();
michael@0 313 output.push("\n");
michael@0 314 just_added_newline = true;
michael@0 315 whitespace_count = 0;
michael@0 316 } else {
michael@0 317 if (c === '\t') {
michael@0 318 whitespace_count += 4;
michael@0 319 } else if (c === '\r') {
michael@0 320 // nothing
michael@0 321 } else {
michael@0 322 whitespace_count += 1;
michael@0 323 }
michael@0 324 }
michael@0 325
michael@0 326 if (parser_pos >= input_length) {
michael@0 327 return ['', 'TK_EOF'];
michael@0 328 }
michael@0 329
michael@0 330 c = input.charAt(parser_pos);
michael@0 331 parser_pos += 1;
michael@0 332
michael@0 333 }
michael@0 334 if (flags.indentation_baseline === -1) {
michael@0 335 flags.indentation_baseline = whitespace_count;
michael@0 336 }
michael@0 337
michael@0 338 if (just_added_newline) {
michael@0 339 for (i = 0; i < flags.indentation_level + 1; i += 1) {
michael@0 340 output.push(indent_string);
michael@0 341 }
michael@0 342 if (flags.indentation_baseline !== -1) {
michael@0 343 for (i = 0; i < whitespace_count - flags.indentation_baseline; i++) {
michael@0 344 output.push(' ');
michael@0 345 }
michael@0 346 }
michael@0 347 }
michael@0 348
michael@0 349 } else {
michael@0 350 while (in_array(c, whitespace)) {
michael@0 351
michael@0 352 if (c === "\n") {
michael@0 353 n_newlines += ((opt_max_preserve_newlines) ? (n_newlines <= opt_max_preserve_newlines) ? 1 : 0 : 1);
michael@0 354 }
michael@0 355
michael@0 356
michael@0 357 if (parser_pos >= input_length) {
michael@0 358 return ['', 'TK_EOF'];
michael@0 359 }
michael@0 360
michael@0 361 c = input.charAt(parser_pos);
michael@0 362 parser_pos += 1;
michael@0 363
michael@0 364 }
michael@0 365
michael@0 366 if (opt_preserve_newlines) {
michael@0 367 if (n_newlines > 1) {
michael@0 368 for (i = 0; i < n_newlines; i += 1) {
michael@0 369 print_newline(i === 0);
michael@0 370 just_added_newline = true;
michael@0 371 }
michael@0 372 }
michael@0 373 }
michael@0 374 wanted_newline = n_newlines > 0;
michael@0 375 }
michael@0 376
michael@0 377
michael@0 378 if (in_array(c, wordchar)) {
michael@0 379 if (parser_pos < input_length) {
michael@0 380 while (in_array(input.charAt(parser_pos), wordchar)) {
michael@0 381 c += input.charAt(parser_pos);
michael@0 382 parser_pos += 1;
michael@0 383 if (parser_pos === input_length) {
michael@0 384 break;
michael@0 385 }
michael@0 386 }
michael@0 387 }
michael@0 388
michael@0 389 // small and surprisingly unugly hack for 1E-10 representation
michael@0 390 if (parser_pos !== input_length && c.match(/^[0-9]+[Ee]$/) && (input.charAt(parser_pos) === '-' || input.charAt(parser_pos) === '+')) {
michael@0 391
michael@0 392 var sign = input.charAt(parser_pos);
michael@0 393 parser_pos += 1;
michael@0 394
michael@0 395 var t = get_next_token();
michael@0 396 c += sign + t[0];
michael@0 397 return [c, 'TK_WORD'];
michael@0 398 }
michael@0 399
michael@0 400 if (c === 'in') { // hack for 'in' operator
michael@0 401 return [c, 'TK_OPERATOR'];
michael@0 402 }
michael@0 403 if (wanted_newline && last_type !== 'TK_OPERATOR'
michael@0 404 && last_type !== 'TK_EQUALS'
michael@0 405 && !flags.if_line && (opt_preserve_newlines || last_text !== 'var')) {
michael@0 406 print_newline();
michael@0 407 }
michael@0 408 return [c, 'TK_WORD'];
michael@0 409 }
michael@0 410
michael@0 411 if (c === '(' || c === '[') {
michael@0 412 return [c, 'TK_START_EXPR'];
michael@0 413 }
michael@0 414
michael@0 415 if (c === ')' || c === ']') {
michael@0 416 return [c, 'TK_END_EXPR'];
michael@0 417 }
michael@0 418
michael@0 419 if (c === '{') {
michael@0 420 return [c, 'TK_START_BLOCK'];
michael@0 421 }
michael@0 422
michael@0 423 if (c === '}') {
michael@0 424 return [c, 'TK_END_BLOCK'];
michael@0 425 }
michael@0 426
michael@0 427 if (c === ';') {
michael@0 428 return [c, 'TK_SEMICOLON'];
michael@0 429 }
michael@0 430
michael@0 431 if (c === '/') {
michael@0 432 var comment = '';
michael@0 433 // peek for comment /* ... */
michael@0 434 var inline_comment = true;
michael@0 435 if (input.charAt(parser_pos) === '*') {
michael@0 436 parser_pos += 1;
michael@0 437 if (parser_pos < input_length) {
michael@0 438 while (parser_pos < input_length &&
michael@0 439 ! (input.charAt(parser_pos) === '*' && input.charAt(parser_pos + 1) && input.charAt(parser_pos + 1) === '/')) {
michael@0 440 c = input.charAt(parser_pos);
michael@0 441 comment += c;
michael@0 442 if (c === "\n" || c === "\r") {
michael@0 443 inline_comment = false;
michael@0 444 }
michael@0 445 parser_pos += 1;
michael@0 446 if (parser_pos >= input_length) {
michael@0 447 break;
michael@0 448 }
michael@0 449 }
michael@0 450 }
michael@0 451 parser_pos += 2;
michael@0 452 if (inline_comment && n_newlines === 0) {
michael@0 453 return ['/*' + comment + '*/', 'TK_INLINE_COMMENT'];
michael@0 454 } else {
michael@0 455 return ['/*' + comment + '*/', 'TK_BLOCK_COMMENT'];
michael@0 456 }
michael@0 457 }
michael@0 458 // peek for comment // ...
michael@0 459 if (input.charAt(parser_pos) === '/') {
michael@0 460 comment = c;
michael@0 461 while (input.charAt(parser_pos) !== '\r' && input.charAt(parser_pos) !== '\n') {
michael@0 462 comment += input.charAt(parser_pos);
michael@0 463 parser_pos += 1;
michael@0 464 if (parser_pos >= input_length) {
michael@0 465 break;
michael@0 466 }
michael@0 467 }
michael@0 468 if (wanted_newline) {
michael@0 469 print_newline();
michael@0 470 }
michael@0 471 return [comment, 'TK_COMMENT'];
michael@0 472 }
michael@0 473
michael@0 474 }
michael@0 475
michael@0 476 if (c === "'" || // string
michael@0 477 c === '"' || // string
michael@0 478 (c === '/' &&
michael@0 479 ((last_type === 'TK_WORD' && is_special_word(last_text)) ||
michael@0 480 (last_text === ')' && in_array(flags.previous_mode, ['(COND-EXPRESSION)', '(FOR-EXPRESSION)'])) ||
michael@0 481 (last_type === 'TK_COMMA' || last_type === 'TK_COMMENT' || last_type === 'TK_START_EXPR' || last_type === 'TK_START_BLOCK' || last_type === 'TK_END_BLOCK' || last_type === 'TK_OPERATOR' || last_type === 'TK_EQUALS' || last_type === 'TK_EOF' || last_type === 'TK_SEMICOLON')))) { // regexp
michael@0 482 var sep = c;
michael@0 483 var esc = false;
michael@0 484 var esc1 = 0;
michael@0 485 var esc2 = 0;
michael@0 486 resulting_string = c;
michael@0 487
michael@0 488 if (parser_pos < input_length) {
michael@0 489 if (sep === '/') {
michael@0 490 //
michael@0 491 // handle regexp separately...
michael@0 492 //
michael@0 493 var in_char_class = false;
michael@0 494 while (esc || in_char_class || input.charAt(parser_pos) !== sep) {
michael@0 495 resulting_string += input.charAt(parser_pos);
michael@0 496 if (!esc) {
michael@0 497 esc = input.charAt(parser_pos) === '\\';
michael@0 498 if (input.charAt(parser_pos) === '[') {
michael@0 499 in_char_class = true;
michael@0 500 } else if (input.charAt(parser_pos) === ']') {
michael@0 501 in_char_class = false;
michael@0 502 }
michael@0 503 } else {
michael@0 504 esc = false;
michael@0 505 }
michael@0 506 parser_pos += 1;
michael@0 507 if (parser_pos >= input_length) {
michael@0 508 // incomplete string/rexp when end-of-file reached.
michael@0 509 // bail out with what had been received so far.
michael@0 510 return [resulting_string, 'TK_STRING'];
michael@0 511 }
michael@0 512 }
michael@0 513
michael@0 514 } else {
michael@0 515 //
michael@0 516 // and handle string also separately
michael@0 517 //
michael@0 518 while (esc || input.charAt(parser_pos) !== sep) {
michael@0 519 resulting_string += input.charAt(parser_pos);
michael@0 520 if (esc1 && esc1 >= esc2) {
michael@0 521 esc1 = parseInt(resulting_string.substr(-esc2), 16);
michael@0 522 if (esc1 && esc1 >= 0x20 && esc1 <= 0x7e) {
michael@0 523 esc1 = String.fromCharCode(esc1);
michael@0 524 resulting_string = resulting_string.substr(0, resulting_string.length - esc2 - 2) + (((esc1 === sep) || (esc1 === '\\')) ? '\\' : '') + esc1;
michael@0 525 }
michael@0 526 esc1 = 0;
michael@0 527 }
michael@0 528 if (esc1) {
michael@0 529 esc1++;
michael@0 530 } else if (!esc) {
michael@0 531 esc = input.charAt(parser_pos) === '\\';
michael@0 532 } else {
michael@0 533 esc = false;
michael@0 534 if (opt_unescape_strings) {
michael@0 535 if (input.charAt(parser_pos) === 'x') {
michael@0 536 esc1++;
michael@0 537 esc2 = 2;
michael@0 538 } else if (input.charAt(parser_pos) === 'u') {
michael@0 539 esc1++;
michael@0 540 esc2 = 4;
michael@0 541 }
michael@0 542 }
michael@0 543 }
michael@0 544 parser_pos += 1;
michael@0 545 if (parser_pos >= input_length) {
michael@0 546 // incomplete string/rexp when end-of-file reached.
michael@0 547 // bail out with what had been received so far.
michael@0 548 return [resulting_string, 'TK_STRING'];
michael@0 549 }
michael@0 550 }
michael@0 551 }
michael@0 552
michael@0 553
michael@0 554
michael@0 555 }
michael@0 556
michael@0 557 parser_pos += 1;
michael@0 558
michael@0 559 resulting_string += sep;
michael@0 560
michael@0 561 if (sep === '/') {
michael@0 562 // regexps may have modifiers /regexp/MOD , so fetch those, too
michael@0 563 while (parser_pos < input_length && in_array(input.charAt(parser_pos), wordchar)) {
michael@0 564 resulting_string += input.charAt(parser_pos);
michael@0 565 parser_pos += 1;
michael@0 566 }
michael@0 567 }
michael@0 568 return [resulting_string, 'TK_STRING'];
michael@0 569 }
michael@0 570
michael@0 571 if (c === '#') {
michael@0 572
michael@0 573
michael@0 574 if (output.length === 0 && input.charAt(parser_pos) === '!') {
michael@0 575 // shebang
michael@0 576 resulting_string = c;
michael@0 577 while (parser_pos < input_length && c !== '\n') {
michael@0 578 c = input.charAt(parser_pos);
michael@0 579 resulting_string += c;
michael@0 580 parser_pos += 1;
michael@0 581 }
michael@0 582 output.push(trim(resulting_string) + '\n');
michael@0 583 print_newline();
michael@0 584 return get_next_token();
michael@0 585 }
michael@0 586
michael@0 587
michael@0 588
michael@0 589 // Spidermonkey-specific sharp variables for circular references
michael@0 590 // https://developer.mozilla.org/En/Sharp_variables_in_JavaScript
michael@0 591 // http://mxr.mozilla.org/mozilla-central/source/js/src/jsscan.cpp around line 1935
michael@0 592 var sharp = '#';
michael@0 593 if (parser_pos < input_length && in_array(input.charAt(parser_pos), digits)) {
michael@0 594 do {
michael@0 595 c = input.charAt(parser_pos);
michael@0 596 sharp += c;
michael@0 597 parser_pos += 1;
michael@0 598 } while (parser_pos < input_length && c !== '#' && c !== '=');
michael@0 599 if (c === '#') {
michael@0 600 //
michael@0 601 } else if (input.charAt(parser_pos) === '[' && input.charAt(parser_pos + 1) === ']') {
michael@0 602 sharp += '[]';
michael@0 603 parser_pos += 2;
michael@0 604 } else if (input.charAt(parser_pos) === '{' && input.charAt(parser_pos + 1) === '}') {
michael@0 605 sharp += '{}';
michael@0 606 parser_pos += 2;
michael@0 607 }
michael@0 608 return [sharp, 'TK_WORD'];
michael@0 609 }
michael@0 610 }
michael@0 611
michael@0 612 if (c === '<' && input.substring(parser_pos - 1, parser_pos + 3) === '<!--') {
michael@0 613 parser_pos += 3;
michael@0 614 c = '<!--';
michael@0 615 while (input.charAt(parser_pos) !== '\n' && parser_pos < input_length) {
michael@0 616 c += input.charAt(parser_pos);
michael@0 617 parser_pos++;
michael@0 618 }
michael@0 619 flags.in_html_comment = true;
michael@0 620 return [c, 'TK_COMMENT'];
michael@0 621 }
michael@0 622
michael@0 623 if (c === '-' && flags.in_html_comment && input.substring(parser_pos - 1, parser_pos + 2) === '-->') {
michael@0 624 flags.in_html_comment = false;
michael@0 625 parser_pos += 2;
michael@0 626 if (wanted_newline) {
michael@0 627 print_newline();
michael@0 628 }
michael@0 629 return ['-->', 'TK_COMMENT'];
michael@0 630 }
michael@0 631
michael@0 632 if (in_array(c, punct)) {
michael@0 633 while (parser_pos < input_length && in_array(c + input.charAt(parser_pos), punct)) {
michael@0 634 c += input.charAt(parser_pos);
michael@0 635 parser_pos += 1;
michael@0 636 if (parser_pos >= input_length) {
michael@0 637 break;
michael@0 638 }
michael@0 639 }
michael@0 640
michael@0 641 if (c === ',') {
michael@0 642 return [c, 'TK_COMMA'];
michael@0 643 } else if (c === '=') {
michael@0 644 return [c, 'TK_EQUALS'];
michael@0 645 } else {
michael@0 646 return [c, 'TK_OPERATOR'];
michael@0 647 }
michael@0 648 }
michael@0 649
michael@0 650 return [c, 'TK_UNKNOWN'];
michael@0 651 }
michael@0 652
michael@0 653 //----------------------------------
michael@0 654 indent_string = '';
michael@0 655 while (opt_indent_size > 0) {
michael@0 656 indent_string += opt_indent_char;
michael@0 657 opt_indent_size -= 1;
michael@0 658 }
michael@0 659
michael@0 660 while (js_source_text && (js_source_text.charAt(0) === ' ' || js_source_text.charAt(0) === '\t')) {
michael@0 661 preindent_string += js_source_text.charAt(0);
michael@0 662 js_source_text = js_source_text.substring(1);
michael@0 663 }
michael@0 664 input = js_source_text;
michael@0 665
michael@0 666 last_word = ''; // last 'TK_WORD' passed
michael@0 667 last_type = 'TK_START_EXPR'; // last token type
michael@0 668 last_text = ''; // last token text
michael@0 669 last_last_text = ''; // pre-last token text
michael@0 670 output = [];
michael@0 671
michael@0 672 do_block_just_closed = false;
michael@0 673
michael@0 674 whitespace = "\n\r\t ".split('');
michael@0 675 wordchar = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$'.split('');
michael@0 676 digits = '0123456789'.split('');
michael@0 677
michael@0 678 punct = '+ - * / % & ++ -- = += -= *= /= %= == === != !== > < >= <= >> << >>> >>>= >>= <<= && &= | || ! !! , : ? ^ ^= |= ::';
michael@0 679 punct += ' <%= <% %> <?= <? ?>'; // try to be a good boy and try not to break the markup language identifiers
michael@0 680 punct = punct.split(' ');
michael@0 681
michael@0 682 // words which should always start on new line.
michael@0 683 line_starters = 'continue,try,throw,return,var,if,switch,case,default,for,while,break,function'.split(',');
michael@0 684
michael@0 685 // states showing if we are currently in expression (i.e. "if" case) - 'EXPRESSION', or in usual block (like, procedure), 'BLOCK'.
michael@0 686 // some formatting depends on that.
michael@0 687 flag_store = [];
michael@0 688 set_mode('BLOCK');
michael@0 689
michael@0 690 parser_pos = 0;
michael@0 691 while (true) {
michael@0 692 var t = get_next_token();
michael@0 693 token_text = t[0];
michael@0 694 token_type = t[1];
michael@0 695 if (token_type === 'TK_EOF') {
michael@0 696 break;
michael@0 697 }
michael@0 698
michael@0 699 switch (token_type) {
michael@0 700
michael@0 701 case 'TK_START_EXPR':
michael@0 702
michael@0 703 if (token_text === '[') {
michael@0 704
michael@0 705 if (last_type === 'TK_WORD' || last_text === ')') {
michael@0 706 // this is array index specifier, break immediately
michael@0 707 // a[x], fn()[x]
michael@0 708 if (in_array(last_text, line_starters)) {
michael@0 709 print_single_space();
michael@0 710 }
michael@0 711 set_mode('(EXPRESSION)');
michael@0 712 print_token();
michael@0 713 break;
michael@0 714 }
michael@0 715
michael@0 716 if (flags.mode === '[EXPRESSION]' || flags.mode === '[INDENTED-EXPRESSION]') {
michael@0 717 if (last_last_text === ']' && last_text === ',') {
michael@0 718 // ], [ goes to new line
michael@0 719 if (flags.mode === '[EXPRESSION]') {
michael@0 720 flags.mode = '[INDENTED-EXPRESSION]';
michael@0 721 if (!opt_keep_array_indentation) {
michael@0 722 indent();
michael@0 723 }
michael@0 724 }
michael@0 725 set_mode('[EXPRESSION]');
michael@0 726 if (!opt_keep_array_indentation) {
michael@0 727 print_newline();
michael@0 728 }
michael@0 729 } else if (last_text === '[') {
michael@0 730 if (flags.mode === '[EXPRESSION]') {
michael@0 731 flags.mode = '[INDENTED-EXPRESSION]';
michael@0 732 if (!opt_keep_array_indentation) {
michael@0 733 indent();
michael@0 734 }
michael@0 735 }
michael@0 736 set_mode('[EXPRESSION]');
michael@0 737
michael@0 738 if (!opt_keep_array_indentation) {
michael@0 739 print_newline();
michael@0 740 }
michael@0 741 } else {
michael@0 742 set_mode('[EXPRESSION]');
michael@0 743 }
michael@0 744 } else {
michael@0 745 set_mode('[EXPRESSION]');
michael@0 746 }
michael@0 747
michael@0 748
michael@0 749
michael@0 750 } else {
michael@0 751 if (last_word === 'for') {
michael@0 752 set_mode('(FOR-EXPRESSION)');
michael@0 753 } else if (in_array(last_word, ['if', 'while'])) {
michael@0 754 set_mode('(COND-EXPRESSION)');
michael@0 755 } else {
michael@0 756 set_mode('(EXPRESSION)');
michael@0 757 }
michael@0 758 }
michael@0 759
michael@0 760 if (last_text === ';' || last_type === 'TK_START_BLOCK') {
michael@0 761 print_newline();
michael@0 762 } else if (last_type === 'TK_END_EXPR' || last_type === 'TK_START_EXPR' || last_type === 'TK_END_BLOCK' || last_text === '.') {
michael@0 763 if (wanted_newline) {
michael@0 764 print_newline();
michael@0 765 }
michael@0 766 // do nothing on (( and )( and ][ and ]( and .(
michael@0 767 } else if (last_type !== 'TK_WORD' && last_type !== 'TK_OPERATOR') {
michael@0 768 print_single_space();
michael@0 769 } else if (last_word === 'function' || last_word === 'typeof') {
michael@0 770 // function() vs function ()
michael@0 771 if (opt_jslint_happy) {
michael@0 772 print_single_space();
michael@0 773 }
michael@0 774 } else if (in_array(last_text, line_starters) || last_text === 'catch') {
michael@0 775 if (opt_space_before_conditional) {
michael@0 776 print_single_space();
michael@0 777 }
michael@0 778 }
michael@0 779 print_token();
michael@0 780
michael@0 781 break;
michael@0 782
michael@0 783 case 'TK_END_EXPR':
michael@0 784 if (token_text === ']') {
michael@0 785 if (opt_keep_array_indentation) {
michael@0 786 if (last_text === '}') {
michael@0 787 // trim_output();
michael@0 788 // print_newline(true);
michael@0 789 remove_indent();
michael@0 790 print_token();
michael@0 791 restore_mode();
michael@0 792 break;
michael@0 793 }
michael@0 794 } else {
michael@0 795 if (flags.mode === '[INDENTED-EXPRESSION]') {
michael@0 796 if (last_text === ']') {
michael@0 797 restore_mode();
michael@0 798 print_newline();
michael@0 799 print_token();
michael@0 800 break;
michael@0 801 }
michael@0 802 }
michael@0 803 }
michael@0 804 }
michael@0 805 restore_mode();
michael@0 806 print_token();
michael@0 807 break;
michael@0 808
michael@0 809 case 'TK_START_BLOCK':
michael@0 810
michael@0 811 if (last_word === 'do') {
michael@0 812 set_mode('DO_BLOCK');
michael@0 813 } else {
michael@0 814 set_mode('BLOCK');
michael@0 815 }
michael@0 816 if (opt_brace_style === "expand" || opt_brace_style === "expand-strict") {
michael@0 817 var empty_braces = false;
michael@0 818 if (opt_brace_style === "expand-strict") {
michael@0 819 empty_braces = (look_up() === '}');
michael@0 820 if (!empty_braces) {
michael@0 821 print_newline(true);
michael@0 822 }
michael@0 823 } else {
michael@0 824 if (last_type !== 'TK_OPERATOR') {
michael@0 825 if (last_text === '=' || (is_special_word(last_text) && last_text !== 'else')) {
michael@0 826 print_single_space();
michael@0 827 } else {
michael@0 828 print_newline(true);
michael@0 829 }
michael@0 830 }
michael@0 831 }
michael@0 832 print_token();
michael@0 833 if (!empty_braces) {
michael@0 834 indent();
michael@0 835 }
michael@0 836 } else {
michael@0 837 if (last_type !== 'TK_OPERATOR' && last_type !== 'TK_START_EXPR') {
michael@0 838 if (last_type === 'TK_START_BLOCK') {
michael@0 839 print_newline();
michael@0 840 } else {
michael@0 841 print_single_space();
michael@0 842 }
michael@0 843 } else {
michael@0 844 // if TK_OPERATOR or TK_START_EXPR
michael@0 845 if (is_array(flags.previous_mode) && last_text === ',') {
michael@0 846 if (last_last_text === '}') {
michael@0 847 // }, { in array context
michael@0 848 print_single_space();
michael@0 849 } else {
michael@0 850 print_newline(); // [a, b, c, {
michael@0 851 }
michael@0 852 }
michael@0 853 }
michael@0 854 indent();
michael@0 855 print_token();
michael@0 856 }
michael@0 857
michael@0 858 break;
michael@0 859
michael@0 860 case 'TK_END_BLOCK':
michael@0 861 restore_mode();
michael@0 862 if (opt_brace_style === "expand" || opt_brace_style === "expand-strict") {
michael@0 863 if (last_text !== '{') {
michael@0 864 print_newline();
michael@0 865 }
michael@0 866 print_token();
michael@0 867 } else {
michael@0 868 if (last_type === 'TK_START_BLOCK') {
michael@0 869 // nothing
michael@0 870 if (just_added_newline) {
michael@0 871 remove_indent();
michael@0 872 } else {
michael@0 873 // {}
michael@0 874 trim_output();
michael@0 875 }
michael@0 876 } else {
michael@0 877 if (is_array(flags.mode) && opt_keep_array_indentation) {
michael@0 878 // we REALLY need a newline here, but newliner would skip that
michael@0 879 opt_keep_array_indentation = false;
michael@0 880 print_newline();
michael@0 881 opt_keep_array_indentation = true;
michael@0 882
michael@0 883 } else {
michael@0 884 print_newline();
michael@0 885 }
michael@0 886 }
michael@0 887 print_token();
michael@0 888 }
michael@0 889 break;
michael@0 890
michael@0 891 case 'TK_WORD':
michael@0 892
michael@0 893 // no, it's not you. even I have problems understanding how this works
michael@0 894 // and what does what.
michael@0 895 if (do_block_just_closed) {
michael@0 896 // do {} ## while ()
michael@0 897 print_single_space();
michael@0 898 print_token();
michael@0 899 print_single_space();
michael@0 900 do_block_just_closed = false;
michael@0 901 break;
michael@0 902 }
michael@0 903
michael@0 904 prefix = 'NONE';
michael@0 905
michael@0 906 if (token_text === 'function') {
michael@0 907 if (flags.var_line && last_type !== 'TK_EQUALS' ) {
michael@0 908 flags.var_line_reindented = true;
michael@0 909 }
michael@0 910 if ((just_added_newline || last_text === ';') && last_text !== '{'
michael@0 911 && last_type !== 'TK_BLOCK_COMMENT' && last_type !== 'TK_COMMENT') {
michael@0 912 // make sure there is a nice clean space of at least one blank line
michael@0 913 // before a new function definition
michael@0 914 n_newlines = just_added_newline ? n_newlines : 0;
michael@0 915 if (!opt_preserve_newlines) {
michael@0 916 n_newlines = 1;
michael@0 917 }
michael@0 918
michael@0 919 for (var i = 0; i < 2 - n_newlines; i++) {
michael@0 920 print_newline(false);
michael@0 921 }
michael@0 922 }
michael@0 923 if (last_type === 'TK_WORD') {
michael@0 924 if (last_text === 'get' || last_text === 'set' || last_text === 'new' || last_text === 'return') {
michael@0 925 print_single_space();
michael@0 926 } else {
michael@0 927 print_newline();
michael@0 928 }
michael@0 929 } else if (last_type === 'TK_OPERATOR' || last_text === '=') {
michael@0 930 // foo = function
michael@0 931 print_single_space();
michael@0 932 } else if (is_expression(flags.mode)) {
michael@0 933 //ää print nothing
michael@0 934 } else {
michael@0 935 print_newline();
michael@0 936 }
michael@0 937
michael@0 938 print_token();
michael@0 939 last_word = token_text;
michael@0 940 break;
michael@0 941 }
michael@0 942
michael@0 943 if (token_text === 'case' || (token_text === 'default' && flags.in_case_statement)) {
michael@0 944 if (last_text === ':' || flags.case_body) {
michael@0 945 // switch cases following one another
michael@0 946 remove_indent();
michael@0 947 } else {
michael@0 948 // case statement starts in the same line where switch
michael@0 949 if (!opt_indent_case) {
michael@0 950 flags.indentation_level--;
michael@0 951 }
michael@0 952 print_newline();
michael@0 953 if (!opt_indent_case) {
michael@0 954 flags.indentation_level++;
michael@0 955 }
michael@0 956 }
michael@0 957 print_token();
michael@0 958 flags.in_case = true;
michael@0 959 flags.in_case_statement = true;
michael@0 960 flags.case_body = false;
michael@0 961 break;
michael@0 962 }
michael@0 963
michael@0 964 if (last_type === 'TK_END_BLOCK') {
michael@0 965
michael@0 966 if (!in_array(token_text.toLowerCase(), ['else', 'catch', 'finally'])) {
michael@0 967 prefix = 'NEWLINE';
michael@0 968 } else {
michael@0 969 if (opt_brace_style === "expand" || opt_brace_style === "end-expand" || opt_brace_style === "expand-strict") {
michael@0 970 prefix = 'NEWLINE';
michael@0 971 } else {
michael@0 972 prefix = 'SPACE';
michael@0 973 print_single_space();
michael@0 974 }
michael@0 975 }
michael@0 976 } else if (last_type === 'TK_SEMICOLON' && (flags.mode === 'BLOCK' || flags.mode === 'DO_BLOCK')) {
michael@0 977 prefix = 'NEWLINE';
michael@0 978 } else if (last_type === 'TK_SEMICOLON' && is_expression(flags.mode)) {
michael@0 979 prefix = 'SPACE';
michael@0 980 } else if (last_type === 'TK_STRING') {
michael@0 981 prefix = 'NEWLINE';
michael@0 982 } else if (last_type === 'TK_WORD') {
michael@0 983 if (last_text === 'else') {
michael@0 984 // eat newlines between ...else *** some_op...
michael@0 985 // won't preserve extra newlines in this place (if any), but don't care that much
michael@0 986 trim_output(true);
michael@0 987 }
michael@0 988 prefix = 'SPACE';
michael@0 989 } else if (last_type === 'TK_START_BLOCK') {
michael@0 990 prefix = 'NEWLINE';
michael@0 991 } else if (last_type === 'TK_END_EXPR') {
michael@0 992 print_single_space();
michael@0 993 prefix = 'NEWLINE';
michael@0 994 }
michael@0 995
michael@0 996 if (in_array(token_text, line_starters) && last_text !== ')') {
michael@0 997 if (last_text === 'else') {
michael@0 998 prefix = 'SPACE';
michael@0 999 } else {
michael@0 1000 prefix = 'NEWLINE';
michael@0 1001 }
michael@0 1002
michael@0 1003 }
michael@0 1004
michael@0 1005 if (flags.if_line && last_type === 'TK_END_EXPR') {
michael@0 1006 flags.if_line = false;
michael@0 1007 }
michael@0 1008 if (in_array(token_text.toLowerCase(), ['else', 'catch', 'finally'])) {
michael@0 1009 if (last_type !== 'TK_END_BLOCK' || opt_brace_style === "expand" || opt_brace_style === "end-expand" || opt_brace_style === "expand-strict") {
michael@0 1010 print_newline();
michael@0 1011 } else {
michael@0 1012 trim_output(true);
michael@0 1013 print_single_space();
michael@0 1014 }
michael@0 1015 } else if (prefix === 'NEWLINE') {
michael@0 1016 if (is_special_word(last_text)) {
michael@0 1017 // no newline between 'return nnn'
michael@0 1018 print_single_space();
michael@0 1019 } else if (last_type !== 'TK_END_EXPR') {
michael@0 1020 if ((last_type !== 'TK_START_EXPR' || token_text !== 'var') && last_text !== ':') {
michael@0 1021 // no need to force newline on 'var': for (var x = 0...)
michael@0 1022 if (token_text === 'if' && last_word === 'else' && last_text !== '{') {
michael@0 1023 // no newline for } else if {
michael@0 1024 print_single_space();
michael@0 1025 } else {
michael@0 1026 flags.var_line = false;
michael@0 1027 flags.var_line_reindented = false;
michael@0 1028 print_newline();
michael@0 1029 }
michael@0 1030 }
michael@0 1031 } else if (in_array(token_text, line_starters) && last_text !== ')') {
michael@0 1032 flags.var_line = false;
michael@0 1033 flags.var_line_reindented = false;
michael@0 1034 print_newline();
michael@0 1035 }
michael@0 1036 } else if (is_array(flags.mode) && last_text === ',' && last_last_text === '}') {
michael@0 1037 print_newline(); // }, in lists get a newline treatment
michael@0 1038 } else if (prefix === 'SPACE') {
michael@0 1039 print_single_space();
michael@0 1040 }
michael@0 1041 print_token();
michael@0 1042 last_word = token_text;
michael@0 1043
michael@0 1044 if (token_text === 'var') {
michael@0 1045 flags.var_line = true;
michael@0 1046 flags.var_line_reindented = false;
michael@0 1047 flags.var_line_tainted = false;
michael@0 1048 }
michael@0 1049
michael@0 1050 if (token_text === 'if') {
michael@0 1051 flags.if_line = true;
michael@0 1052 }
michael@0 1053 if (token_text === 'else') {
michael@0 1054 flags.if_line = false;
michael@0 1055 }
michael@0 1056
michael@0 1057 break;
michael@0 1058
michael@0 1059 case 'TK_SEMICOLON':
michael@0 1060
michael@0 1061 print_token();
michael@0 1062 flags.var_line = false;
michael@0 1063 flags.var_line_reindented = false;
michael@0 1064 if (flags.mode === 'OBJECT') {
michael@0 1065 // OBJECT mode is weird and doesn't get reset too well.
michael@0 1066 flags.mode = 'BLOCK';
michael@0 1067 }
michael@0 1068 break;
michael@0 1069
michael@0 1070 case 'TK_STRING':
michael@0 1071
michael@0 1072 if (last_type === 'TK_END_EXPR' && in_array(flags.previous_mode, ['(COND-EXPRESSION)', '(FOR-EXPRESSION)'])) {
michael@0 1073 print_single_space();
michael@0 1074 } else if (last_type === 'TK_COMMENT' || last_type === 'TK_STRING' || last_type === 'TK_START_BLOCK' || last_type === 'TK_END_BLOCK' || last_type === 'TK_SEMICOLON') {
michael@0 1075 print_newline();
michael@0 1076 } else if (last_type === 'TK_WORD') {
michael@0 1077 print_single_space();
michael@0 1078 }
michael@0 1079 print_token();
michael@0 1080 break;
michael@0 1081
michael@0 1082 case 'TK_EQUALS':
michael@0 1083 if (flags.var_line) {
michael@0 1084 // just got an '=' in a var-line, different formatting/line-breaking, etc will now be done
michael@0 1085 flags.var_line_tainted = true;
michael@0 1086 }
michael@0 1087 print_single_space();
michael@0 1088 print_token();
michael@0 1089 print_single_space();
michael@0 1090 break;
michael@0 1091
michael@0 1092 case 'TK_COMMA':
michael@0 1093 if (flags.var_line) {
michael@0 1094 if (is_expression(flags.mode) || last_type === 'TK_END_BLOCK' ) {
michael@0 1095 // do not break on comma, for(var a = 1, b = 2)
michael@0 1096 flags.var_line_tainted = false;
michael@0 1097 }
michael@0 1098 if (flags.var_line_tainted) {
michael@0 1099 print_token();
michael@0 1100 flags.var_line_reindented = true;
michael@0 1101 flags.var_line_tainted = false;
michael@0 1102 print_newline();
michael@0 1103 break;
michael@0 1104 } else {
michael@0 1105 flags.var_line_tainted = false;
michael@0 1106 }
michael@0 1107
michael@0 1108 print_token();
michael@0 1109 print_single_space();
michael@0 1110 break;
michael@0 1111 }
michael@0 1112
michael@0 1113 if (last_type === 'TK_COMMENT') {
michael@0 1114 print_newline();
michael@0 1115 }
michael@0 1116
michael@0 1117 if (last_type === 'TK_END_BLOCK' && flags.mode !== "(EXPRESSION)") {
michael@0 1118 print_token();
michael@0 1119 if (flags.mode === 'OBJECT' && last_text === '}') {
michael@0 1120 print_newline();
michael@0 1121 } else {
michael@0 1122 print_single_space();
michael@0 1123 }
michael@0 1124 } else {
michael@0 1125 if (flags.mode === 'OBJECT') {
michael@0 1126 print_token();
michael@0 1127 print_newline();
michael@0 1128 } else {
michael@0 1129 // EXPR or DO_BLOCK
michael@0 1130 print_token();
michael@0 1131 print_single_space();
michael@0 1132 }
michael@0 1133 }
michael@0 1134 break;
michael@0 1135
michael@0 1136
michael@0 1137 case 'TK_OPERATOR':
michael@0 1138
michael@0 1139 var space_before = true;
michael@0 1140 var space_after = true;
michael@0 1141
michael@0 1142 if (is_special_word(last_text)) {
michael@0 1143 // "return" had a special handling in TK_WORD. Now we need to return the favor
michael@0 1144 print_single_space();
michael@0 1145 print_token();
michael@0 1146 break;
michael@0 1147 }
michael@0 1148
michael@0 1149 // hack for actionscript's import .*;
michael@0 1150 if (token_text === '*' && last_type === 'TK_UNKNOWN' && !last_last_text.match(/^\d+$/)) {
michael@0 1151 print_token();
michael@0 1152 break;
michael@0 1153 }
michael@0 1154
michael@0 1155 if (token_text === ':' && flags.in_case) {
michael@0 1156 if (opt_indent_case) {
michael@0 1157 flags.case_body = true;
michael@0 1158 }
michael@0 1159 print_token(); // colon really asks for separate treatment
michael@0 1160 print_newline();
michael@0 1161 flags.in_case = false;
michael@0 1162 break;
michael@0 1163 }
michael@0 1164
michael@0 1165 if (token_text === '::') {
michael@0 1166 // no spaces around exotic namespacing syntax operator
michael@0 1167 print_token();
michael@0 1168 break;
michael@0 1169 }
michael@0 1170
michael@0 1171 if (in_array(token_text, ['--', '++', '!']) || (in_array(token_text, ['-', '+']) && (in_array(last_type, ['TK_START_BLOCK', 'TK_START_EXPR', 'TK_EQUALS', 'TK_OPERATOR']) || in_array(last_text, line_starters)))) {
michael@0 1172 // unary operators (and binary +/- pretending to be unary) special cases
michael@0 1173
michael@0 1174 space_before = false;
michael@0 1175 space_after = false;
michael@0 1176
michael@0 1177 if (last_text === ';' && is_expression(flags.mode)) {
michael@0 1178 // for (;; ++i)
michael@0 1179 // ^^^
michael@0 1180 space_before = true;
michael@0 1181 }
michael@0 1182 if (last_type === 'TK_WORD' && in_array(last_text, line_starters)) {
michael@0 1183 space_before = true;
michael@0 1184 }
michael@0 1185
michael@0 1186 if (flags.mode === 'BLOCK' && (last_text === '{' || last_text === ';')) {
michael@0 1187 // { foo; --i }
michael@0 1188 // foo(); --bar;
michael@0 1189 print_newline();
michael@0 1190 }
michael@0 1191 } else if (token_text === '.') {
michael@0 1192 // decimal digits or object.property
michael@0 1193 space_before = false;
michael@0 1194
michael@0 1195 } else if (token_text === ':') {
michael@0 1196 if (flags.ternary_depth === 0) {
michael@0 1197 if (flags.mode === 'BLOCK') {
michael@0 1198 flags.mode = 'OBJECT';
michael@0 1199 }
michael@0 1200 space_before = false;
michael@0 1201 } else {
michael@0 1202 flags.ternary_depth -= 1;
michael@0 1203 }
michael@0 1204 } else if (token_text === '?') {
michael@0 1205 flags.ternary_depth += 1;
michael@0 1206 }
michael@0 1207 if (space_before) {
michael@0 1208 print_single_space();
michael@0 1209 }
michael@0 1210
michael@0 1211 print_token();
michael@0 1212
michael@0 1213 if (space_after) {
michael@0 1214 print_single_space();
michael@0 1215 }
michael@0 1216
michael@0 1217 break;
michael@0 1218
michael@0 1219 case 'TK_BLOCK_COMMENT':
michael@0 1220
michael@0 1221 var lines = split_newlines(token_text);
michael@0 1222 var j; // iterator for this case
michael@0 1223
michael@0 1224 if (all_lines_start_with(lines.slice(1), '*')) {
michael@0 1225 // javadoc: reformat and reindent
michael@0 1226 print_newline();
michael@0 1227 output.push(lines[0]);
michael@0 1228 for (j = 1; j < lines.length; j++) {
michael@0 1229 print_newline();
michael@0 1230 output.push(' ');
michael@0 1231 output.push(trim(lines[j]));
michael@0 1232 }
michael@0 1233
michael@0 1234 } else {
michael@0 1235
michael@0 1236 // simple block comment: leave intact
michael@0 1237 if (lines.length > 1) {
michael@0 1238 // multiline comment block starts with a new line
michael@0 1239 print_newline();
michael@0 1240 } else {
michael@0 1241 // single-line /* comment */ stays where it is
michael@0 1242 if (last_type === 'TK_END_BLOCK') {
michael@0 1243 print_newline();
michael@0 1244 } else {
michael@0 1245 print_single_space();
michael@0 1246 }
michael@0 1247
michael@0 1248 }
michael@0 1249
michael@0 1250 for (j = 0; j < lines.length; j++) {
michael@0 1251 output.push(lines[j]);
michael@0 1252 output.push("\n");
michael@0 1253 }
michael@0 1254
michael@0 1255 }
michael@0 1256 if (look_up('\n') !== '\n') {
michael@0 1257 print_newline();
michael@0 1258 }
michael@0 1259 break;
michael@0 1260
michael@0 1261 case 'TK_INLINE_COMMENT':
michael@0 1262 print_single_space();
michael@0 1263 print_token();
michael@0 1264 if (is_expression(flags.mode)) {
michael@0 1265 print_single_space();
michael@0 1266 } else {
michael@0 1267 force_newline();
michael@0 1268 }
michael@0 1269 break;
michael@0 1270
michael@0 1271 case 'TK_COMMENT':
michael@0 1272
michael@0 1273 if (last_text === ',' && !wanted_newline) {
michael@0 1274 trim_output(true);
michael@0 1275 }
michael@0 1276 if (last_type !== 'TK_COMMENT') {
michael@0 1277 if (wanted_newline) {
michael@0 1278 print_newline();
michael@0 1279 } else {
michael@0 1280 print_single_space();
michael@0 1281 }
michael@0 1282 }
michael@0 1283 print_token();
michael@0 1284 print_newline();
michael@0 1285 break;
michael@0 1286
michael@0 1287 case 'TK_UNKNOWN':
michael@0 1288 if (is_special_word(last_text)) {
michael@0 1289 print_single_space();
michael@0 1290 }
michael@0 1291 print_token();
michael@0 1292 break;
michael@0 1293 }
michael@0 1294
michael@0 1295 last_last_text = last_text;
michael@0 1296 last_type = token_type;
michael@0 1297 last_text = token_text;
michael@0 1298 }
michael@0 1299
michael@0 1300 var sweet_code = preindent_string + output.join('').replace(/[\r\n ]+$/, '');
michael@0 1301 return sweet_code;
michael@0 1302
michael@0 1303 }

mercurial