Example #1
0
        public JSBeautify(string js_source_text, JSBeautifyOptions options)
        {
            opt_indent_size = options.indent_size ?? 4;
            opt_indent_char = options.indent_char ?? ' ';
            opt_indent_level = options.indent_level ?? 0;
            opt_preserve_newlines = options.preserve_newlines ?? true;
            output = new StringBuilder();
            modes = new Stack<string>();

            

            indent_string = "";
            
            while (opt_indent_size > 0) {
                indent_string += opt_indent_char;
                opt_indent_size -= 1;
            }

            indent_level = opt_indent_level;

            

            input = js_source_text.Replace("<script type=\"text/javascript\">","").Replace("</script>","");
            if (input.Length != js_source_text.Length)
            {
                output.AppendLine("<script type=\"text/javascript\">");
                add_script_tags = true;
            }

            last_word = ""; // last 'TK_WORD' passed
            last_type = "TK_START_EXPR"; // last token type
            last_text = ""; // last token text
            
            do_block_just_closed = false;
            var_line = false;         // currently drawing var .... ;
            var_line_tainted = false; // false: var a = 5; true: var a = 5, b = 6

            whitespace = "\n\r\t ";
            wordchar = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$";
            digits = "0123456789";

            // <!-- is a special case (ok, it's a minor hack actually)
            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(',');

            // states showing if we are currently in expression (i.e. "if" case) - 'EXPRESSION', or in usual block (like, procedure), 'BLOCK'.
            // some formatting depends on that.
            current_mode = "BLOCK";
            modes.Push(current_mode);

            parser_pos = 0;
            in_case = false;

            while (true) {
                var t = get_next_token(ref parser_pos);
                token_text = t[0];
                token_type = t[1];
                if (token_type == "TK_EOF") {
                    break;
                }

                switch (token_type) {

                case "TK_START_EXPR":
                    var_line = false;
                    set_mode("EXPRESSION");
                    if ((last_text == ";") || (last_type == "TK_START_BLOCK")) {
                        print_newline(null);
                    } else if ((last_type == "TK_END_EXPR") ||( last_type == "TK_START_EXPR")) {
                        // do nothing on (( and )( and ][ and ]( ..
                    } else if ((last_type != "TK_WORD") && (last_type != "TK_OPERATOR")) {
                        print_space();
                    } else if (line_starters.Contains(last_word)) {
                        print_space();
                    }
                    print_token();
                    break;

                case "TK_END_EXPR":
                    print_token();
                    restore_mode();
                    break;

                case "TK_START_BLOCK":

                    if (last_word == "do") {
                        set_mode("DO_BLOCK");
                    } else {
                        set_mode("BLOCK");
                    }
                    if ((last_type != "TK_OPERATOR") && (last_type != "TK_START_EXPR")) {
                        if (last_type == "TK_START_BLOCK") {
                            print_newline(null);
                        } else {
                            print_space();
                        }
                    }
                    print_token();
                    indent();
                    break;

                case "TK_END_BLOCK":
                    if (last_type == "TK_START_BLOCK") {
                        // nothing
                        trim_output();
                        unindent();
                    } else {
                        unindent();
                        print_newline(null);
                    }
                    print_token();
                    restore_mode();
                    break;

                case "TK_WORD":

                    if (do_block_just_closed) {
                        // do {} ## while ()
                        print_space();
                        print_token();
                        print_space();
                        do_block_just_closed = false;
                        break;
                    }

                    if ((token_text == "case" )|| (token_text == "default")) {
                        if (last_text == ":") {
                            // switch cases following one another
                            remove_indent();
                        } else {
                            // case statement starts in the same line where switch
                            unindent();
                            print_newline(null);
                            indent();
                        }
                        print_token();
                        in_case = true;
                        break;
                    }

                    prefix = "NONE";

                    if (last_type == "TK_END_BLOCK") {
                        if (!(new string[] {"else", "catch", "finally" }).Contains(token_text.ToLower())) {
                            prefix = "NEWLINE";
                        } else {
                            prefix = "SPACE";
                            print_space();
                        }
                    } else if ((last_type == "TK_SEMICOLON") && ((current_mode == "BLOCK") ||( current_mode == "DO_BLOCK"))) {
                        prefix = "NEWLINE";
                    } else if ((last_type == "TK_SEMICOLON") && (current_mode == "EXPRESSION")) {
                        prefix = "SPACE";
                    } else if (last_type == "TK_STRING") {
                        prefix = "NEWLINE";
                    } else if (last_type == "TK_WORD") {
                        prefix = "SPACE";
                    } else if (last_type == "TK_START_BLOCK") {
                        prefix = "NEWLINE";
                    } else if (last_type == "TK_END_EXPR") {
                        print_space();
                        prefix = "NEWLINE";
                    }

                    if ((last_type != "TK_END_BLOCK") && ((new string[] {"else", "catch", "finally"}).Contains(token_text.ToLower()))) {
                        print_newline(null);
                    } else if ((line_starters.Contains(token_text)) ||( prefix == "NEWLINE")) {
                        if (last_text == "else") {
                            // no need to force newline on else break
                            print_space();
                        } else if (((last_type == "TK_START_EXPR") ||( last_text == "=") || (last_text == ",")) && (token_text == "function")) {
                            // no need to force newline on "function": (function
                            // DONOTHING
                        } else if ((last_type == "TK_WORD") && ((last_text == "return") || (last_text == "throw"))) {
                            // no newline between "return nnn"
                            print_space();
                        } else if (last_type != "TK_END_EXPR") {
                            if (((last_type != "TK_START_EXPR") || (token_text != "var")) && (last_text != ":")) {
                                // no need to force newline on "var": for (var x = 0...)
                                if ((token_text == "if") && (last_type == "TK_WORD") && (last_word == "else")) {
                                    // no newline for } else if {
                                    print_space();
                                } else {
                                    print_newline(null);
                                }
                            }
                        } else {
                            if ((line_starters.Contains(token_text)) && (last_text != ")")) {
                                print_newline(null);
                            }
                        }
                    } else if (prefix == "SPACE") {
                        print_space();
                    }
                    print_token();
                    last_word = token_text;

                    if (token_text == "var") {
                        var_line = true;
                        var_line_tainted = false;
                    }

                    if (token_text == "if" || token_text == "else") {
                        if_line_flag = true;
                    }

                    break;

                case "TK_SEMICOLON":

                    print_token();
                    var_line = false;
                    break;

                case "TK_STRING":

                    if ((last_type == "TK_START_BLOCK" )||( last_type == "TK_END_BLOCK") || (last_type == "TK_SEMICOLON")) {
                        print_newline(null);
                    } else if (last_type == "TK_WORD") {
                        print_space();
                    }
                    print_token();
                    break;

                case "TK_OPERATOR":

                    var start_delim = true;
                    var end_delim = true;
                    if (var_line && (token_text != ",")) {
                        var_line_tainted = true;
                        if (token_text == ":") {
                            var_line = false;
                        }
                    }
                    if (var_line && (token_text == ",") && (current_mode == "EXPRESSION")) {
                        // do not break on comma, for(var a = 1, b = 2)
                        var_line_tainted = false;
                    }

                    if (token_text == ":" && in_case) {
                        print_token(); // colon really asks for separate treatment
                        print_newline(null);
                        in_case = false; 
                        break;
                    }

                    if (token_text == "::") {
                        // no spaces around exotic namespacing syntax operator
                        print_token();
                        break;
                    }

                    if (token_text == ",") {
                        if (var_line) {
                            if (var_line_tainted) {
                                print_token();
                                print_newline(null);
                                var_line_tainted = false;
                            } else {
                                print_token();
                                print_space();
                            }
                        } else if (last_type == "TK_END_BLOCK") {
                            print_token();
                            print_newline(null);
                        } else {
                            if (current_mode == "BLOCK") {
                                print_token();
                                print_newline(null);
                            } else {
                                // EXPR od DO_BLOCK
                                print_token();
                                print_space();
                            }
                        }
                        break;
                    } else if ((token_text == "--" )|| (token_text == "++")) { // unary operators special case
                        if (last_text == ";") {
                            if (current_mode == "BLOCK") {
                                // { foo; --i }
                                print_newline(null);
                                start_delim = true;
                                end_delim = false;
                            } else {
                                // space for (;; ++i)
                                start_delim = true;
                                end_delim = false;
                            }
                        } else {
                            if (last_text == "{") {
                                // {--i
                                print_newline(null);
                            }
                            start_delim = false;
                            end_delim = false;
                        }
                    } else if (((token_text == "!") ||( token_text == "+") || (token_text == "-")) && ((last_text == "return" )|| (last_text == "case"))) {
                        start_delim = true;
                        end_delim = false;
                    } else if (((token_text == "!" )||( token_text == "+") || (token_text == "-")) && (last_type == "TK_START_EXPR")) {
                        // special case handling: if (!a)
                        start_delim = false;
                        end_delim = false;
                    } else if (last_type == "TK_OPERATOR") {
                        start_delim = false;
                        end_delim = false;
                    } else if (last_type == "TK_END_EXPR") {
                        start_delim = true;
                        end_delim = true;
                    } else if (token_text == ".") {
                        // decimal digits or object.property
                        start_delim = false;
                        end_delim = false;

                    } else if (token_text == ":") {
                        if (is_ternary_op()) {
                            start_delim = true;
                        } else {
                            start_delim = false;
                        }
                    }
                    if (start_delim) {
                        print_space();
                    }

                    print_token();

                    if (end_delim) {
                        print_space();
                    }
                    break;

                case "TK_BLOCK_COMMENT":

                    print_newline(null);
                    print_token();
                    print_newline(null);
                    break;

                case "TK_COMMENT":

                    // print_newline();
                    print_space();
                    print_token();
                    print_newline(null);
                    break;

                case "TK_UNKNOWN":
                    print_token();
                    break;
                }

                last_type = token_type;
                last_text = token_text;
            }


        }
Example #2
0
        public JSBeautify(string js_source_text, JSBeautifyOptions options)
        {
            opt_indent_size       = options.indent_size ?? 4;
            opt_indent_char       = options.indent_char ?? ' ';
            opt_indent_level      = options.indent_level ?? 0;
            opt_preserve_newlines = options.preserve_newlines ?? true;
            output = new StringBuilder();
            modes  = new Stack <string>();



            indent_string = "";

            while (opt_indent_size > 0)
            {
                indent_string   += opt_indent_char;
                opt_indent_size -= 1;
            }

            indent_level = opt_indent_level;



            input = js_source_text.Replace("<script type=\"text/javascript\">", "").Replace("</script>", "");
            if (input.Length != js_source_text.Length)
            {
                output.AppendLine("<script type=\"text/javascript\">");
                add_script_tags = true;
            }

            last_word = "";              // last 'TK_WORD' passed
            last_type = "TK_START_EXPR"; // last token type
            last_text = "";              // last token text

            do_block_just_closed = false;
            var_line             = false; // currently drawing var .... ;
            var_line_tainted     = false; // false: var a = 5; true: var a = 5, b = 6

            whitespace = "\n\r\t ";
            wordchar   = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$";
            digits     = "0123456789";

            // <!-- is a special case (ok, it's a minor hack actually)
            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(',');

            // states showing if we are currently in expression (i.e. "if" case) - 'EXPRESSION', or in usual block (like, procedure), 'BLOCK'.
            // some formatting depends on that.
            current_mode = "BLOCK";
            modes.Push(current_mode);

            parser_pos = 0;
            in_case    = false;

            while (true)
            {
                var t = get_next_token(ref parser_pos);
                token_text = t[0];
                token_type = t[1];
                if (token_type == "TK_EOF")
                {
                    break;
                }

                switch (token_type)
                {
                case "TK_START_EXPR":
                    var_line = false;
                    set_mode("EXPRESSION");
                    if ((last_text == ";") || (last_type == "TK_START_BLOCK"))
                    {
                        print_newline(null);
                    }
                    else if ((last_type == "TK_END_EXPR") || (last_type == "TK_START_EXPR"))
                    {
                        // do nothing on (( and )( and ][ and ]( ..
                    }
                    else if ((last_type != "TK_WORD") && (last_type != "TK_OPERATOR"))
                    {
                        print_space();
                    }
                    else if (line_starters.Contains(last_word))
                    {
                        print_space();
                    }
                    print_token();
                    break;

                case "TK_END_EXPR":
                    print_token();
                    restore_mode();
                    break;

                case "TK_START_BLOCK":

                    if (last_word == "do")
                    {
                        set_mode("DO_BLOCK");
                    }
                    else
                    {
                        set_mode("BLOCK");
                    }
                    if ((last_type != "TK_OPERATOR") && (last_type != "TK_START_EXPR"))
                    {
                        if (last_type == "TK_START_BLOCK")
                        {
                            print_newline(null);
                        }
                        else
                        {
                            print_space();
                        }
                    }
                    print_token();
                    indent();
                    break;

                case "TK_END_BLOCK":
                    if (last_type == "TK_START_BLOCK")
                    {
                        // nothing
                        trim_output();
                        unindent();
                    }
                    else
                    {
                        unindent();
                        print_newline(null);
                    }
                    print_token();
                    restore_mode();
                    break;

                case "TK_WORD":

                    if (do_block_just_closed)
                    {
                        // do {} ## while ()
                        print_space();
                        print_token();
                        print_space();
                        do_block_just_closed = false;
                        break;
                    }

                    if ((token_text == "case") || (token_text == "default"))
                    {
                        if (last_text == ":")
                        {
                            // switch cases following one another
                            remove_indent();
                        }
                        else
                        {
                            // case statement starts in the same line where switch
                            unindent();
                            print_newline(null);
                            indent();
                        }
                        print_token();
                        in_case = true;
                        break;
                    }

                    prefix = "NONE";

                    if (last_type == "TK_END_BLOCK")
                    {
                        if (!(new string[] { "else", "catch", "finally" }).Contains(token_text.ToLower()))
                        {
                            prefix = "NEWLINE";
                        }
                        else
                        {
                            prefix = "SPACE";
                            print_space();
                        }
                    }
                    else if ((last_type == "TK_SEMICOLON") && ((current_mode == "BLOCK") || (current_mode == "DO_BLOCK")))
                    {
                        prefix = "NEWLINE";
                    }
                    else if ((last_type == "TK_SEMICOLON") && (current_mode == "EXPRESSION"))
                    {
                        prefix = "SPACE";
                    }
                    else if (last_type == "TK_STRING")
                    {
                        prefix = "NEWLINE";
                    }
                    else if (last_type == "TK_WORD")
                    {
                        prefix = "SPACE";
                    }
                    else if (last_type == "TK_START_BLOCK")
                    {
                        prefix = "NEWLINE";
                    }
                    else if (last_type == "TK_END_EXPR")
                    {
                        print_space();
                        prefix = "NEWLINE";
                    }

                    if ((last_type != "TK_END_BLOCK") && ((new string[] { "else", "catch", "finally" }).Contains(token_text.ToLower())))
                    {
                        print_newline(null);
                    }
                    else if ((line_starters.Contains(token_text)) || (prefix == "NEWLINE"))
                    {
                        if (last_text == "else")
                        {
                            // no need to force newline on else break
                            print_space();
                        }
                        else if (((last_type == "TK_START_EXPR") || (last_text == "=") || (last_text == ",")) && (token_text == "function"))
                        {
                            // no need to force newline on "function": (function
                            // DONOTHING
                        }
                        else if ((last_type == "TK_WORD") && ((last_text == "return") || (last_text == "throw")))
                        {
                            // no newline between "return nnn"
                            print_space();
                        }
                        else if (last_type != "TK_END_EXPR")
                        {
                            if (((last_type != "TK_START_EXPR") || (token_text != "var")) && (last_text != ":"))
                            {
                                // no need to force newline on "var": for (var x = 0...)
                                if ((token_text == "if") && (last_type == "TK_WORD") && (last_word == "else"))
                                {
                                    // no newline for } else if {
                                    print_space();
                                }
                                else
                                {
                                    print_newline(null);
                                }
                            }
                        }
                        else
                        {
                            if ((line_starters.Contains(token_text)) && (last_text != ")"))
                            {
                                print_newline(null);
                            }
                        }
                    }
                    else if (prefix == "SPACE")
                    {
                        print_space();
                    }
                    print_token();
                    last_word = token_text;

                    if (token_text == "var")
                    {
                        var_line         = true;
                        var_line_tainted = false;
                    }

                    if (token_text == "if" || token_text == "else")
                    {
                        if_line_flag = true;
                    }

                    break;

                case "TK_SEMICOLON":

                    print_token();
                    var_line = false;
                    break;

                case "TK_STRING":

                    if ((last_type == "TK_START_BLOCK") || (last_type == "TK_END_BLOCK") || (last_type == "TK_SEMICOLON"))
                    {
                        print_newline(null);
                    }
                    else if (last_type == "TK_WORD")
                    {
                        print_space();
                    }
                    print_token();
                    break;

                case "TK_OPERATOR":

                    var start_delim = true;
                    var end_delim   = true;
                    if (var_line && (token_text != ","))
                    {
                        var_line_tainted = true;
                        if (token_text == ":")
                        {
                            var_line = false;
                        }
                    }
                    if (var_line && (token_text == ",") && (current_mode == "EXPRESSION"))
                    {
                        // do not break on comma, for(var a = 1, b = 2)
                        var_line_tainted = false;
                    }

                    if (token_text == ":" && in_case)
                    {
                        print_token();     // colon really asks for separate treatment
                        print_newline(null);
                        in_case = false;
                        break;
                    }

                    if (token_text == "::")
                    {
                        // no spaces around exotic namespacing syntax operator
                        print_token();
                        break;
                    }

                    if (token_text == ",")
                    {
                        if (var_line)
                        {
                            if (var_line_tainted)
                            {
                                print_token();
                                print_newline(null);
                                var_line_tainted = false;
                            }
                            else
                            {
                                print_token();
                                print_space();
                            }
                        }
                        else if (last_type == "TK_END_BLOCK")
                        {
                            print_token();
                            print_newline(null);
                        }
                        else
                        {
                            if (current_mode == "BLOCK")
                            {
                                print_token();
                                print_newline(null);
                            }
                            else
                            {
                                // EXPR od DO_BLOCK
                                print_token();
                                print_space();
                            }
                        }
                        break;
                    }
                    else if ((token_text == "--") || (token_text == "++"))
                    {     // unary operators special case
                        if (last_text == ";")
                        {
                            if (current_mode == "BLOCK")
                            {
                                // { foo; --i }
                                print_newline(null);
                                start_delim = true;
                                end_delim   = false;
                            }
                            else
                            {
                                // space for (;; ++i)
                                start_delim = true;
                                end_delim   = false;
                            }
                        }
                        else
                        {
                            if (last_text == "{")
                            {
                                // {--i
                                print_newline(null);
                            }
                            start_delim = false;
                            end_delim   = false;
                        }
                    }
                    else if (((token_text == "!") || (token_text == "+") || (token_text == "-")) && ((last_text == "return") || (last_text == "case")))
                    {
                        start_delim = true;
                        end_delim   = false;
                    }
                    else if (((token_text == "!") || (token_text == "+") || (token_text == "-")) && (last_type == "TK_START_EXPR"))
                    {
                        // special case handling: if (!a)
                        start_delim = false;
                        end_delim   = false;
                    }
                    else if (last_type == "TK_OPERATOR")
                    {
                        start_delim = false;
                        end_delim   = false;
                    }
                    else if (last_type == "TK_END_EXPR")
                    {
                        start_delim = true;
                        end_delim   = true;
                    }
                    else if (token_text == ".")
                    {
                        // decimal digits or object.property
                        start_delim = false;
                        end_delim   = false;
                    }
                    else if (token_text == ":")
                    {
                        if (is_ternary_op())
                        {
                            start_delim = true;
                        }
                        else
                        {
                            start_delim = false;
                        }
                    }
                    if (start_delim)
                    {
                        print_space();
                    }

                    print_token();

                    if (end_delim)
                    {
                        print_space();
                    }
                    break;

                case "TK_BLOCK_COMMENT":

                    print_newline(null);
                    print_token();
                    print_newline(null);
                    break;

                case "TK_COMMENT":

                    // print_newline();
                    print_space();
                    print_token();
                    print_newline(null);
                    break;

                case "TK_UNKNOWN":
                    print_token();
                    break;
                }

                last_type = token_type;
                last_text = token_text;
            }
        }