Update js_beutify.js in playground
authorMarkus Lanthaler <mark_lanthaler@gmx.net>
Fri, 17 Aug 2012 18:12:55 +0200
changeset 813 fa532f0d901d
parent 812 004fddff90d2
child 814 88bb8d65b0cd
Update js_beutify.js in playground
playground/js_beautify.js
--- a/playground/js_beautify.js	Thu Aug 16 19:16:26 2012 +0200
+++ b/playground/js_beautify.js	Fri Aug 17 18:12:55 2012 +0200
@@ -1,4 +1,5 @@
 /*jslint onevar: false, plusplus: false */
+/*jshint curly:true, eqeqeq:true, laxbreak:true, noempty:false */
 /*
 
  JS Beautifier
@@ -18,21 +19,33 @@
     js_beautify(js_source_text, options);
 
   The options are:
-    indent_size (default 4)          — indentation size,
-    indent_char (default space)      — character to indent with,
-    preserve_newlines (default true) — whether existing line breaks should be preserved,
+    indent_size (default 4)          - indentation size,
+    indent_char (default space)      - character to indent with,
+    preserve_newlines (default true) - whether existing line breaks should be preserved,
     preserve_max_newlines (default unlimited) - maximum number of line breaks to be preserved in one chunk,
-    indent_level (default 0)         — initial indentation level, you probably won't need this ever,
 
-    jslint_happy (default false) — if true, then jslint-stricter mode is enforced.
+    jslint_happy (default false) - if true, then jslint-stricter mode is enforced.
 
             jslint_happy   !jslint_happy
             ---------------------------------
              function ()      function()
 
-    brace_style (default "collapse") - "collapse" | "expand" | "end-expand"
+    brace_style (default "collapse") - "collapse" | "expand" | "end-expand" | "expand-strict"
             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.
 
+            expand-strict: put brace on own line even in such cases:
+
+                var a =
+                {
+                    a: 5,
+                    b: 6
+                }
+            This mode may break your scripts - e.g "return { a: 1 }" will be broken into two lines, so beware.
+
+    space_before_conditional (default true) - should the space before conditional statement be added, "if(true)" vs "if (true)",
+
+    unescape_strings (default false) - should printable characters in strings encoded in \xNN notation be unescaped, "example" vs "\x65\x78\x61\x6d\x70\x6c\x65"
+
     e.g
 
     js_beautify(js_source_text, {
@@ -43,12 +56,15 @@
 
 */
 
+
+
 function js_beautify(js_source_text, options) {
 
     var input, output, token_text, last_type, last_text, last_last_text, last_word, flags, flag_store, indent_string;
     var whitespace, wordchar, punct, parser_pos, line_starters, digits;
     var prefix, token_type, do_block_just_closed;
     var wanted_newline, just_added_newline, n_newlines;
+    var preindent_string = '';
 
 
     // Some interpreters have unexpected results with foo = baz || bar;
@@ -60,7 +76,7 @@
     if (options.space_after_anon_function !== undefined && options.jslint_happy === undefined) {
         options.jslint_happy = options.space_after_anon_function;
     }
-    if (options.braces_on_own_line !== undefined) { //graceful handling of depricated option
+    if (options.braces_on_own_line !== undefined) { //graceful handling of deprecated option
         opt_brace_style = options.braces_on_own_line ? "expand" : "collapse";
     }
     opt_brace_style = options.brace_style ? options.brace_style : (opt_brace_style ? opt_brace_style : "collapse");
@@ -70,9 +86,11 @@
     var opt_indent_char = options.indent_char ? options.indent_char : ' ';
     var opt_preserve_newlines = typeof options.preserve_newlines === 'undefined' ? true : options.preserve_newlines;
     var opt_max_preserve_newlines = typeof options.max_preserve_newlines === 'undefined' ? false : options.max_preserve_newlines;
-    var opt_indent_level = options.indent_level ? options.indent_level : 0; // starting indentation
     var opt_jslint_happy = options.jslint_happy === 'undefined' ? false : options.jslint_happy;
     var opt_keep_array_indentation = typeof options.keep_array_indentation === 'undefined' ? false : options.keep_array_indentation;
+    var opt_space_before_conditional = typeof options.space_before_conditional === 'undefined' ? true : options.space_before_conditional;
+    var opt_indent_case = typeof options.indent_case === 'undefined' ? false : options.indent_case;
+    var opt_unescape_strings = typeof options.unescape_strings === 'undefined' ? false : options.unescape_strings;
 
     just_added_newline = false;
 
@@ -83,6 +101,7 @@
         eat_newlines = typeof eat_newlines === 'undefined' ? false : eat_newlines;
         while (output.length && (output[output.length - 1] === ' '
             || output[output.length - 1] === indent_string
+            || output[output.length - 1] === preindent_string
             || (eat_newlines && (output[output.length - 1] === '\n' || output[output.length - 1] === '\r')))) {
             output.pop();
         }
@@ -92,11 +111,29 @@
         return s.replace(/^\s\s*|\s\s*$/, '');
     }
 
-    function force_newline()
-    {
+    // we could use just string.split, but
+    // IE doesn't like returning empty strings
+    function split_newlines(s) {
+        //return s.split(/\x0d\x0a|\x0a/);
+
+        s = s.replace(/\x0d/g, '');
+        var out = [],
+            idx = s.indexOf("\n");
+        while (idx !== -1) {
+            out.push(s.substring(0, idx));
+            s = s.substring(idx + 1);
+            idx = s.indexOf("\n");
+        }
+        if (s.length) {
+            out.push(s);
+        }
+        return out;
+    }
+
+    function force_newline() {
         var old_keep_array_indentation = opt_keep_array_indentation;
         opt_keep_array_indentation = false;
-        print_newline()
+        print_newline();
         opt_keep_array_indentation = old_keep_array_indentation;
     }
 
@@ -120,21 +157,27 @@
             just_added_newline = true;
             output.push("\n");
         }
-        for (var i = 0; i < flags.indentation_level + opt_indent_level; i += 1) {
+        if (preindent_string) {
+            output.push(preindent_string);
+        }
+        for (var i = 0; i < flags.indentation_level; i += 1) {
             output.push(indent_string);
         }
         if (flags.var_line && flags.var_line_reindented) {
-            if (opt_indent_char === ' ') {
-                output.push('    '); // var_line always pushes 4 spaces, so that the variables would be one under another
-            } else {
-                output.push(indent_string); // skip space-stuffing, if indenting with a tab
-            }
+            output.push(indent_string); // skip space-stuffing, if indenting with a tab
+        }
+        if (flags.case_body) {
+            output.push(indent_string);
         }
     }
 
 
 
     function print_single_space() {
+
+        if (last_type === 'TK_COMMENT') {
+            return print_newline();
+        }
         if (flags.eat_next_space) {
             flags.eat_next_space = false;
             return;
@@ -178,10 +221,12 @@
             var_line_reindented: false,
             in_html_comment: false,
             if_line: false,
-            in_case: false,
+            in_case_statement: false, // switch(..){ INSIDE HERE }
+            in_case: false, // we're on the exact line with "case 0:"
+            case_body: false, // the indented case-action block
             eat_next_space: false,
             indentation_baseline: -1,
-            indentation_level: (flags ? flags.indentation_level + ((flags.var_line && flags.var_line_reindented) ? 1 : 0) : 0),
+            indentation_level: (flags ? flags.indentation_level + (flags.case_body ? 1 : 0) + ((flags.var_line && flags.var_line_reindented) ? 1 : 0) : 0),
             ternary_depth: 0
         };
     }
@@ -191,25 +236,32 @@
     }
 
     function is_expression(mode) {
-        return mode === '[EXPRESSION]' || mode === '[INDENTED-EXPRESSION]' || mode === '(EXPRESSION)';
+        return in_array(mode, ['[EXPRESSION]', '(EXPRESSION)', '(FOR-EXPRESSION)', '(COND-EXPRESSION)']);
     }
 
     function restore_mode() {
         do_block_just_closed = flags.mode === 'DO_BLOCK';
         if (flag_store.length > 0) {
+            var mode = flags.mode;
             flags = flag_store.pop();
+            flags.previous_mode = mode;
         }
     }
 
     function all_lines_start_with(lines, c) {
         for (var i = 0; i < lines.length; i++) {
-            if (trim(lines[i])[0] != c) {
+            var line = trim(lines[i]);
+            if (line.charAt(0) !== c) {
                 return false;
             }
         }
         return true;
     }
 
+    function is_special_word(word) {
+        return in_array(word, ['case', 'return', 'do', 'if', 'throw', 'else']);
+    }
+
     function in_array(what, arr) {
         for (var i = 0; i < arr.length; i += 1) {
             if (arr[i] === what) {
@@ -219,7 +271,23 @@
         return false;
     }
 
+    function look_up(exclude) {
+        var local_pos = parser_pos;
+        var c = input.charAt(local_pos);
+        while (in_array(c, whitespace) && c !== exclude) {
+            local_pos++;
+            if (local_pos >= input_length) {
+                return 0;
+            }
+            c = input.charAt(local_pos);
+        }
+        return c;
+    }
+
     function get_next_token() {
+        var i;
+        var resulting_string;
+
         n_newlines = 0;
 
         if (parser_pos >= input_length) {
@@ -281,7 +349,6 @@
             }
 
             if (just_added_newline) {
-                var i;
                 for (i = 0; i < flags.indentation_level + 1; i += 1) {
                     output.push(indent_string);
                 }
@@ -296,7 +363,7 @@
             while (in_array(c, whitespace)) {
 
                 if (c === "\n") {
-                    n_newlines += ( (opt_max_preserve_newlines) ? (n_newlines <= opt_max_preserve_newlines) ? 1: 0: 1 );
+                    n_newlines += ((opt_max_preserve_newlines) ? (n_newlines <= opt_max_preserve_newlines) ? 1 : 0 : 1);
                 }
 
 
@@ -338,7 +405,7 @@
                 var sign = input.charAt(parser_pos);
                 parser_pos += 1;
 
-                var t = get_next_token(parser_pos);
+                var t = get_next_token();
                 c += sign + t[0];
                 return [c, 'TK_WORD'];
             }
@@ -381,10 +448,11 @@
             if (input.charAt(parser_pos) === '*') {
                 parser_pos += 1;
                 if (parser_pos < input_length) {
-                    while (! (input.charAt(parser_pos) === '*' && input.charAt(parser_pos + 1) && input.charAt(parser_pos + 1) === '/') && parser_pos < input_length) {
+                    while (parser_pos < input_length &&
+                        ! (input.charAt(parser_pos) === '*' && input.charAt(parser_pos + 1) && input.charAt(parser_pos + 1) === '/')) {
                         c = input.charAt(parser_pos);
                         comment += c;
-                        if (c === '\x0d' || c === '\x0a') {
+                        if (c === "\n" || c === "\r") {
                             inline_comment = false;
                         }
                         parser_pos += 1;
@@ -394,7 +462,7 @@
                     }
                 }
                 parser_pos += 2;
-                if (inline_comment) {
+                if (inline_comment && n_newlines === 0) {
                     return ['/*' + comment + '*/', 'TK_INLINE_COMMENT'];
                 } else {
                     return ['/*' + comment + '*/', 'TK_BLOCK_COMMENT'];
@@ -410,7 +478,6 @@
                         break;
                     }
                 }
-                parser_pos += 1;
                 if (wanted_newline) {
                     print_newline();
                 }
@@ -422,11 +489,14 @@
         if (c === "'" || // string
         c === '"' || // string
         (c === '/' &&
-            ((last_type === 'TK_WORD' && in_array(last_text, ['return', 'do'])) ||
-                (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
+            ((last_type === 'TK_WORD' && is_special_word(last_text)) ||
+                (last_text === ')' && in_array(flags.previous_mode, ['(COND-EXPRESSION)', '(FOR-EXPRESSION)'])) ||
+                (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
             var sep = c;
             var esc = false;
-            var resulting_string = c;
+            var esc1 = 0;
+            var esc2 = 0;
+            resulting_string = c;
 
             if (parser_pos < input_length) {
                 if (sep === '/') {
@@ -460,10 +530,29 @@
                     //
                     while (esc || input.charAt(parser_pos) !== sep) {
                         resulting_string += input.charAt(parser_pos);
-                        if (!esc) {
+                        if (esc1 && esc1 >= esc2) {
+                            esc1 = parseInt(resulting_string.substr(-esc2), 16);
+                            if (esc1 && esc1 >= 0x20 && esc1 <= 0x7e) {
+                                esc1 = String.fromCharCode(esc1);
+                                resulting_string = resulting_string.substr(0, resulting_string.length - esc2 - 2) + (((esc1 === sep) || (esc1 === '\\')) ? '\\' : '') + esc1;
+                            }
+                            esc1 = 0;
+                        }
+                        if (esc1) {
+                            esc1++;
+                        } else if (!esc) {
                             esc = input.charAt(parser_pos) === '\\';
                         } else {
                             esc = false;
+                            if (opt_unescape_strings) {
+                                if (input.charAt(parser_pos) === 'x') {
+                                    esc1++;
+                                    esc2 = 2;
+                                } else if (input.charAt(parser_pos) === 'u') {
+                                    esc1++;
+                                    esc2 = 4;
+                                }
+                            }
                         }
                         parser_pos += 1;
                         if (parser_pos >= input_length) {
@@ -498,7 +587,7 @@
             if (output.length === 0 && input.charAt(parser_pos) === '!') {
                 // shebang
                 resulting_string = c;
-                while (parser_pos < input_length && c != '\n') {
+                while (parser_pos < input_length && c !== '\n') {
                     c = input.charAt(parser_pos);
                     resulting_string += c;
                     parser_pos += 1;
@@ -535,8 +624,13 @@
 
         if (c === '<' && input.substring(parser_pos - 1, parser_pos + 3) === '<!--') {
             parser_pos += 3;
+            c = '<!--';
+            while (input.charAt(parser_pos) !== '\n' && parser_pos < input_length) {
+                c += input.charAt(parser_pos);
+                parser_pos++;
+            }
             flags.in_html_comment = true;
-            return ['<!--', 'TK_COMMENT'];
+            return [c, 'TK_COMMENT'];
         }
 
         if (c === '-' && flags.in_html_comment && input.substring(parser_pos - 1, parser_pos + 2) === '-->') {
@@ -557,7 +651,9 @@
                 }
             }
 
-            if (c === '=') {
+            if (c === ',') {
+                return [c, 'TK_COMMA'];
+            } else if (c === '=') {
                 return [c, 'TK_EQUALS'];
             } else {
                 return [c, 'TK_OPERATOR'];
@@ -574,6 +670,10 @@
         opt_indent_size -= 1;
     }
 
+    while (js_source_text && (js_source_text.charAt(0) === ' ' || js_source_text.charAt(0) === '\t')) {
+        preindent_string += js_source_text.charAt(0);
+        js_source_text = js_source_text.substring(1);
+    }
     input = js_source_text;
 
     last_word = ''; // last 'TK_WORD' passed
@@ -588,7 +688,9 @@
     wordchar = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$'.split('');
     digits = '0123456789'.split('');
 
-    punct = '+ - * / % & ++ -- = += -= *= /= %= == === != !== > < >= <= >> << >>> >>>= >>= <<= && &= | || ! !! , : ? ^ ^= |= ::'.split(' ');
+    punct = '+ - * / % & ++ -- = += -= *= /= %= == === != !== > < >= <= >> << >>> >>>= >>= <<= && &= | || ! !! , : ? ^ ^= |= ::';
+    punct += ' <%= <% %> <?= <? ?>'; // try to be a good boy and try not to break the markup language identifiers
+    punct = punct.split(' ');
 
     // words which should always start on new line.
     line_starters = 'continue,try,throw,return,var,if,switch,case,default,for,while,break,function'.split(',');
@@ -600,7 +702,7 @@
 
     parser_pos = 0;
     while (true) {
-        var t = get_next_token(parser_pos);
+        var t = get_next_token();
         token_text = t[0];
         token_type = t[1];
         if (token_type === 'TK_EOF') {
@@ -659,12 +761,21 @@
 
 
             } else {
-                set_mode('(EXPRESSION)');
+                if (last_word === 'for') {
+                    set_mode('(FOR-EXPRESSION)');
+                } else if (in_array(last_word, ['if', 'while'])) {
+                    set_mode('(COND-EXPRESSION)');
+                } else {
+                    set_mode('(EXPRESSION)');
+                }
             }
 
             if (last_text === ';' || last_type === 'TK_START_BLOCK') {
                 print_newline();
             } else if (last_type === 'TK_END_EXPR' || last_type === 'TK_START_EXPR' || last_type === 'TK_END_BLOCK' || last_text === '.') {
+                if (wanted_newline) {
+                    print_newline();
+                }
                 // do nothing on (( and )( and ][ and ]( and .(
             } else if (last_type !== 'TK_WORD' && last_type !== 'TK_OPERATOR') {
                 print_single_space();
@@ -674,7 +785,9 @@
                     print_single_space();
                 }
             } else if (in_array(last_text, line_starters) || last_text === 'catch') {
-                print_single_space();
+                if (opt_space_before_conditional) {
+                    print_single_space();
+                }
             }
             print_token();
 
@@ -713,16 +826,26 @@
             } else {
                 set_mode('BLOCK');
             }
-            if (opt_brace_style=="expand") {
-                if (last_type !== 'TK_OPERATOR') {
-                    if (last_text === 'return' || last_text === '=') {
-                        print_single_space();
-                    } else {
+            if (opt_brace_style === "expand" || opt_brace_style === "expand-strict") {
+                var empty_braces = false;
+                if (opt_brace_style === "expand-strict") {
+                    empty_braces = (look_up() === '}');
+                    if (!empty_braces) {
                         print_newline(true);
                     }
+                } else {
+                    if (last_type !== 'TK_OPERATOR') {
+                        if (last_text === '=' || (is_special_word(last_text) && last_text !== 'else')) {
+                            print_single_space();
+                        } else {
+                            print_newline(true);
+                        }
+                    }
                 }
                 print_token();
-                indent();
+                if (!empty_braces) {
+                    indent();
+                }
             } else {
                 if (last_type !== 'TK_OPERATOR' && last_type !== 'TK_START_EXPR') {
                     if (last_type === 'TK_START_BLOCK') {
@@ -749,7 +872,7 @@
 
         case 'TK_END_BLOCK':
             restore_mode();
-            if (opt_brace_style=="expand") {
+            if (opt_brace_style === "expand" || opt_brace_style === "expand-strict") {
                 if (last_text !== '{') {
                     print_newline();
                 }
@@ -791,15 +914,18 @@
                 break;
             }
 
+            prefix = 'NONE';
+
             if (token_text === 'function') {
-                if (flags.var_line) {
+                if (flags.var_line && last_type !== 'TK_EQUALS' ) {
                     flags.var_line_reindented = true;
                 }
-                if ((just_added_newline || last_text === ';') && last_text !== '{') {
+                if ((just_added_newline || last_text === ';') && last_text !== '{'
+                && last_type !== 'TK_BLOCK_COMMENT' && last_type !== 'TK_COMMENT') {
                     // make sure there is a nice clean space of at least one blank line
                     // before a new function definition
                     n_newlines = just_added_newline ? n_newlines : 0;
-                    if ( ! opt_preserve_newlines) {
+                    if (!opt_preserve_newlines) {
                         n_newlines = 1;
                     }
 
@@ -807,31 +933,53 @@
                         print_newline(false);
                     }
                 }
+                if (last_type === 'TK_WORD') {
+                    if (last_text === 'get' || last_text === 'set' || last_text === 'new' || last_text === 'return') {
+                        print_single_space();
+                    } else {
+                        print_newline();
+                    }
+                } else if (last_type === 'TK_OPERATOR' || last_text === '=') {
+                    // foo = function
+                    print_single_space();
+                } else if (is_expression(flags.mode)) {
+                        //ää print nothing
+                } else {
+                    print_newline();
+                }
+
+                print_token();
+                last_word = token_text;
+                break;
             }
 
-            if (token_text === 'case' || token_text === 'default') {
-                if (last_text === ':') {
+            if (token_text === 'case' || (token_text === 'default' && flags.in_case_statement)) {
+                if (last_text === ':' || flags.case_body) {
                     // switch cases following one another
                     remove_indent();
                 } else {
                     // case statement starts in the same line where switch
-                    flags.indentation_level--;
+                    if (!opt_indent_case) {
+                        flags.indentation_level--;
+                    }
                     print_newline();
-                    flags.indentation_level++;
+                    if (!opt_indent_case) {
+                        flags.indentation_level++;
+                    }
                 }
                 print_token();
                 flags.in_case = true;
+                flags.in_case_statement = true;
+                flags.case_body = false;
                 break;
             }
 
-            prefix = 'NONE';
-
             if (last_type === 'TK_END_BLOCK') {
 
                 if (!in_array(token_text.toLowerCase(), ['else', 'catch', 'finally'])) {
                     prefix = 'NEWLINE';
                 } else {
-                    if (opt_brace_style=="expand" || opt_brace_style=="end-expand") {
+                    if (opt_brace_style === "expand" || opt_brace_style === "end-expand" || opt_brace_style === "expand-strict") {
                         prefix = 'NEWLINE';
                     } else {
                         prefix = 'SPACE';
@@ -859,30 +1007,26 @@
             }
 
             if (in_array(token_text, line_starters) && last_text !== ')') {
-                if (last_text == 'else') {
+                if (last_text === 'else') {
                     prefix = 'SPACE';
                 } else {
                     prefix = 'NEWLINE';
                 }
+
             }
 
             if (flags.if_line && last_type === 'TK_END_EXPR') {
                 flags.if_line = false;
             }
             if (in_array(token_text.toLowerCase(), ['else', 'catch', 'finally'])) {
-                if (last_type !== 'TK_END_BLOCK' || opt_brace_style=="expand" || opt_brace_style=="end-expand") {
+                if (last_type !== 'TK_END_BLOCK' || opt_brace_style === "expand" || opt_brace_style === "end-expand" || opt_brace_style === "expand-strict") {
                     print_newline();
                 } else {
                     trim_output(true);
                     print_single_space();
                 }
             } else if (prefix === 'NEWLINE') {
-                if ((last_type === 'TK_START_EXPR' || last_text === '=' || last_text === ',') && token_text === 'function') {
-                    // no need to force newline on 'function': (function
-                    // DONOTHING
-                } else if (token_text === 'function' && last_text == 'new') {
-                    print_single_space();
-                } else if (last_text === 'return' || last_text === 'throw') {
+                if (is_special_word(last_text)) {
                     // no newline between 'return nnn'
                     print_single_space();
                 } else if (last_type !== 'TK_END_EXPR') {
@@ -897,7 +1041,7 @@
                             print_newline();
                         }
                     }
-                } else if (in_array(token_text, line_starters) && last_text != ')') {
+                } else if (in_array(token_text, line_starters) && last_text !== ')') {
                     flags.var_line = false;
                     flags.var_line_reindented = false;
                     print_newline();
@@ -930,7 +1074,7 @@
             print_token();
             flags.var_line = false;
             flags.var_line_reindented = false;
-            if (flags.mode == 'OBJECT') {
+            if (flags.mode === 'OBJECT') {
                 // OBJECT mode is weird and doesn't get reset too well.
                 flags.mode = 'BLOCK';
             }
@@ -938,7 +1082,9 @@
 
         case 'TK_STRING':
 
-            if (last_type === 'TK_START_BLOCK' || last_type === 'TK_END_BLOCK' || last_type === 'TK_SEMICOLON') {
+            if (last_type === 'TK_END_EXPR' && in_array(flags.previous_mode, ['(COND-EXPRESSION)', '(FOR-EXPRESSION)'])) {
+                print_single_space();
+            } else if (last_type === 'TK_COMMENT' || last_type === 'TK_STRING' || last_type === 'TK_START_BLOCK' || last_type === 'TK_END_BLOCK' || last_type === 'TK_SEMICOLON') {
                 print_newline();
             } else if (last_type === 'TK_WORD') {
                 print_single_space();
@@ -956,41 +1102,73 @@
             print_single_space();
             break;
 
+        case 'TK_COMMA':
+            if (flags.var_line) {
+                if (is_expression(flags.mode) || last_type === 'TK_END_BLOCK' ) {
+                    // do not break on comma, for(var a = 1, b = 2)
+                    flags.var_line_tainted = false;
+                }
+                if (flags.var_line_tainted) {
+                    print_token();
+                    flags.var_line_reindented = true;
+                    flags.var_line_tainted = false;
+                    print_newline();
+                    break;
+                } else {
+                    flags.var_line_tainted = false;
+                }
+
+                print_token();
+                print_single_space();
+                break;
+            }
+
+            if (last_type === 'TK_COMMENT') {
+                print_newline();
+            }
+
+            if (last_type === 'TK_END_BLOCK' && flags.mode !== "(EXPRESSION)") {
+                print_token();
+                if (flags.mode === 'OBJECT' && last_text === '}') {
+                    print_newline();
+                } else {
+                    print_single_space();
+                }
+            } else {
+                if (flags.mode === 'OBJECT') {
+                    print_token();
+                    print_newline();
+                } else {
+                    // EXPR or DO_BLOCK
+                    print_token();
+                    print_single_space();
+                }
+            }
+            break;
+
+
         case 'TK_OPERATOR':
 
             var space_before = true;
             var space_after = true;
 
-            if (flags.var_line && token_text === ',' && (is_expression(flags.mode))) {
-                // do not break on comma, for(var a = 1, b = 2)
-                flags.var_line_tainted = false;
-            }
-
-            if (flags.var_line) {
-                if (token_text === ',') {
-                    if (flags.var_line_tainted) {
-                        print_token();
-                        flags.var_line_reindented = true;
-                        flags.var_line_tainted = false;
-                        print_newline();
-                        break;
-                    } else {
-                        flags.var_line_tainted = false;
-                    }
-                // } else if (token_text === ':') {
-                    // hmm, when does this happen? tests don't catch this
-                    // flags.var_line = false;
-                }
-            }
-
-            if (last_text === 'return' || last_text === 'throw') {
+            if (is_special_word(last_text)) {
                 // "return" had a special handling in TK_WORD. Now we need to return the favor
                 print_single_space();
                 print_token();
                 break;
             }
 
+            // hack for actionscript's import .*;
+            if (token_text === '*' && last_type === 'TK_UNKNOWN' && !last_last_text.match(/^\d+$/)) {
+                print_token();
+                break;
+            }
+
             if (token_text === ':' && flags.in_case) {
+                if (opt_indent_case) {
+                    flags.case_body = true;
+                }
                 print_token(); // colon really asks for separate treatment
                 print_newline();
                 flags.in_case = false;
@@ -1003,36 +1181,7 @@
                 break;
             }
 
-            if (token_text === ',') {
-                if (flags.var_line) {
-                    if (flags.var_line_tainted) {
-                        print_token();
-                        print_newline();
-                        flags.var_line_tainted = false;
-                    } else {
-                        print_token();
-                        print_single_space();
-                    }
-                } else if (last_type === 'TK_END_BLOCK' && flags.mode !== "(EXPRESSION)") {
-                    print_token();
-                    if (flags.mode === 'OBJECT' && last_text === '}') {
-                        print_newline();
-                    } else {
-                        print_single_space();
-                    }
-                } else {
-                    if (flags.mode === 'OBJECT') {
-                        print_token();
-                        print_newline();
-                    } else {
-                        // EXPR or DO_BLOCK
-                        print_token();
-                        print_single_space();
-                    }
-                }
-                break;
-            // } else if (in_array(token_text, ['--', '++', '!']) || (in_array(token_text, ['-', '+']) && (in_array(last_type, ['TK_START_BLOCK', 'TK_START_EXPR', 'TK_EQUALS']) || in_array(last_text, line_starters) || in_array(last_text, ['==', '!=', '+=', '-=', '*=', '/=', '+', '-'])))) {
-            } else 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)))) {
+            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)))) {
                 // unary operators (and binary +/- pretending to be unary) special cases
 
                 space_before = false;
@@ -1057,8 +1206,10 @@
                 space_before = false;
 
             } else if (token_text === ':') {
-                if (flags.ternary_depth == 0) {
-                    flags.mode = 'OBJECT';
+                if (flags.ternary_depth === 0) {
+                    if (flags.mode === 'BLOCK') {
+                        flags.mode = 'OBJECT';
+                    }
                     space_before = false;
                 } else {
                     flags.ternary_depth -= 1;
@@ -1076,24 +1227,21 @@
                 print_single_space();
             }
 
-            if (token_text === '!') {
-                // flags.eat_next_space = true;
-            }
-
             break;
 
         case 'TK_BLOCK_COMMENT':
 
-            var lines = token_text.split(/\x0a|\x0d\x0a/);
+            var lines = split_newlines(token_text);
+            var j; // iterator for this case
 
             if (all_lines_start_with(lines.slice(1), '*')) {
                 // javadoc: reformat and reindent
                 print_newline();
                 output.push(lines[0]);
-                for (i = 1; i < lines.length; i++) {
+                for (j = 1; j < lines.length; j++) {
                     print_newline();
                     output.push(' ');
-                    output.push(trim(lines[i]));
+                    output.push(trim(lines[j]));
                 }
 
             } else {
@@ -1102,24 +1250,28 @@
                 if (lines.length > 1) {
                     // multiline comment block starts with a new line
                     print_newline();
-                    trim_output();
                 } else {
                     // single-line /* comment */ stays where it is
-                    print_single_space();
+                    if (last_type === 'TK_END_BLOCK') {
+                        print_newline();
+                    } else {
+                        print_single_space();
+                    }
 
                 }
 
-                for (i = 0; i < lines.length; i++) {
-                    output.push(lines[i]);
-                    output.push('\n');
+                for (j = 0; j < lines.length; j++) {
+                    output.push(lines[j]);
+                    output.push("\n");
                 }
 
             }
-            print_newline();
+            if (look_up('\n') !== '\n') {
+                print_newline();
+            }
             break;
 
         case 'TK_INLINE_COMMENT':
-
             print_single_space();
             print_token();
             if (is_expression(flags.mode)) {
@@ -1131,18 +1283,22 @@
 
         case 'TK_COMMENT':
 
-            // print_newline();
-            if (wanted_newline) {
-                print_newline();
-            } else {
-                print_single_space();
+            if (last_text === ',' && !wanted_newline) {
+                trim_output(true);
+            }
+            if (last_type !== 'TK_COMMENT') {
+                if (wanted_newline) {
+                    print_newline();
+                } else {
+                    print_single_space();
+                }
             }
             print_token();
-            force_newline();
+            print_newline();
             break;
 
         case 'TK_UNKNOWN':
-            if (last_text === 'return' || last_text === 'throw') {
+            if (is_special_word(last_text)) {
                 print_single_space();
             }
             print_token();
@@ -1154,17 +1310,13 @@
         last_text = token_text;
     }
 
-    var sweet_code = output.join('').replace(/[\n ]+$/, '');
-    if (opt_indent_level) {
-        for (i = 0 ; i < opt_indent_level; i++) {
-            sweet_code = indent_string + sweet_code;
-        }
-    }
+    var sweet_code = preindent_string + output.join('').replace(/[\r\n ]+$/, '');
     return sweet_code;
 
 }
 
 // Add support for CommonJS. Just put this file somewhere on your require.paths
 // and you will be able to `var js_beautify = require("beautify").js_beautify`.
-if (typeof exports !== "undefined")
+if (typeof exports !== "undefined") {
     exports.js_beautify = js_beautify;
+}