1 Star 0 Fork 122

mircle/DevelopAssistant

加入 Gitee
与超过 1400万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
JSBeautify.cs 27.93 KB
一键复制 编辑 原始数据 按行查看 历史
wxd_tony1984 提交于 2017-12-01 10:34 +08:00 . 一些修改
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Text.RegularExpressions;
namespace DevelopAssistant.Format
{
public class JSBeautifyOptions
{
public int? indent_size { get; set; }
public char? indent_char { get; set; }
public int? indent_level { get; set; }
public bool? preserve_newlines { get; set; }
}
public class JSBeautify
{
private StringBuilder output;
private string indent_string;
private int indent_level;
private string token_text;
private Stack<string> modes;
private string current_mode;
private int opt_indent_size;
private char opt_indent_char;
private int opt_indent_level;
private bool opt_preserve_newlines;
private bool if_line_flag;
private bool do_block_just_closed;
private string input;
private void trim_output()
{
while ((output.Length>0) && ((output[output.Length-1]==' ')||(output[output.Length-1].ToString()==indent_string)))
{
output.Remove(output.Length-1,1);
}
}
private void print_newline(bool? ignore_repeated)
{
ignore_repeated = ignore_repeated ?? true;
if_line_flag = false;
trim_output();
if (output.Length == 0)
return;
if ((output[output.Length - 1] != '\n') || !ignore_repeated.Value)
{
output.Append(Environment.NewLine);
}
for (var i = 0; i < indent_level; i++)
{
output.Append(indent_string);
}
}
private void print_space()
{
var last_output = " ";
if (output.Length > 0)
last_output = output[output.Length - 1].ToString();
if ((last_output != " ") && (last_output != "\n") && (last_output != indent_string))
{
output.Append(' ');
}
}
private void print_token()
{
output.Append(token_text);
}
private void indent()
{
indent_level++;
}
private void unindent()
{
if (indent_level > 0)
indent_level--;
}
private void remove_indent()
{
if ((output.Length>0) && (output[output.Length-1].ToString()==indent_string))
{
output.Remove(output.Length-1,1);
}
}
private void set_mode(string mode)
{
modes.Push(current_mode);
current_mode = mode;
}
private void restore_mode()
{
do_block_just_closed = (current_mode == "DO_BLOCK");
current_mode = modes.Pop();
}
private bool in_array(object what, ArrayList arr)
{
return arr.Contains(what);
}
private bool is_ternary_op()
{
int level = 0;
int colon_count = 0;
for (var i = output.Length - 1; i >= 0; i--)
{
switch (output[i])
{
case ':':
if (level == 0)
colon_count++;
break;
case '?':
if (level == 0)
{
if (colon_count == 0)
{
return true;
}
else
{
colon_count--;
}
}
break;
case '{':
if (level == 0) return false;
level--;
break;
case '(':
case '[':
level--;
break;
case ')':
case ']':
case '}':
level++;
break;
}
}
return false;
}
private string whitespace;
private string wordchar;
private int parser_pos;
private string last_type;
private string last_text;
private string digits;
private string[] punct;
private string prefix;
private string[] get_next_token(ref int parser_pos)
{
var n_newlines = 0;
if (parser_pos >= input.Length)
{
return new string[] { "", "TK_EOF" };
}
string c = input[parser_pos].ToString();
parser_pos++;
while (whitespace.Contains(c))
{
if (parser_pos >= input.Length)
{
return new string[] { "", "TK_EOF" };
}
if (c == "\n")
n_newlines++;
c = input[parser_pos].ToString();
parser_pos++;
}
var wanted_newline = false;
if (opt_preserve_newlines)
{
if (n_newlines > 1)
{
for (var i = 0; i < 2; i++)
{
print_newline(i == 0);
}
}
wanted_newline = (n_newlines == 1);
}
if (wordchar.Contains(c))
{
if (parser_pos < input.Length)
{
while (wordchar.Contains(input[parser_pos]))
{
c += input[parser_pos];
parser_pos++;
if (parser_pos == input.Length)
break;
}
}
if ((parser_pos!=input.Length) && (Regex.IsMatch(c,"^[0-9]+[Ee]$")) && ((input[parser_pos] == '-') || (input[parser_pos]=='+')))
{
var sign = input[parser_pos];
parser_pos++;
var t = get_next_token(ref parser_pos);
c += sign + t[0];
return new string[] { c, "TK_WORD" };
}
if (c == "in")
{
return new string[] { c, "TK_OPERATOR" };
}
if (wanted_newline && last_type != "TK_OPERATOR" && !if_line_flag)
{
print_newline(null);
}
return new string[] { c, "TK_WORD" };
}
if ((c == "(") || (c == "["))
return new string[] {c,"TK_START_EXPR"};
if (c == ")" || c == "]") {
return new string[] {c, "TK_END_EXPR"};
}
if (c == "{") {
return new string[] {c, "TK_START_BLOCK"};
}
if (c == "}") {
return new string[] {c, "TK_END_BLOCK"};
}
if (c == ";") {
return new string[] {c, "TK_SEMICOLON"};
}
if (c=="/") {
var comment = "";
if (input[parser_pos]=='*') {
parser_pos++;
if (parser_pos<input.Length){
while (!((input[parser_pos]=='*') && (input[parser_pos+1]>'\0') && (input[parser_pos+1]=='/') && (parser_pos<input.Length)))
{
comment+=input[parser_pos];
parser_pos++;
if (parser_pos>=input.Length) {
break;
}
}
}
parser_pos+=2;
return new string[] { "/*"+comment+"*/", "TK_BLOCK_COMMENT"};
}
if (input[parser_pos]=='/') {
comment = c;
while ((input[parser_pos]!='\x0d') && (input[parser_pos]!='\x0a')) {
comment+=input[parser_pos];
parser_pos++;
if (parser_pos>=input.Length){
break;
}
}
parser_pos++;
if (wanted_newline){
print_newline(null);
}
return new string[] {comment,"TK_COMMENT"};
}
}
if ( (c=="'") || (c=="\"") || ((c=="/")
&& ((last_type=="TK_WORD" && last_text=="return") || ((last_type=="TK_START_EXPR") || (last_type=="TK_START_BLOCK") || (last_type=="TK_END_BLOCK")
|| (last_type=="TK_OPERATOR") || (last_type=="TK_EOF") || (last_type=="TK_SEMICOLON"))))
) {
var sep = c;
var esc = false;
var resulting_string = c;
if (parser_pos<input.Length) {
if (sep=="/") {
var in_char_class=false;
while ((esc) || (in_char_class) || (input[parser_pos].ToString()!=sep)) {
resulting_string+=input[parser_pos];
if (!esc) {
esc = input[parser_pos]=='\\';
if (input[parser_pos]=='['){
in_char_class=true;
}
else if (input[parser_pos]==']') {
in_char_class=false;
}
}
else {
esc=false;
}
parser_pos++;
if (parser_pos>=input.Length) {
return new string[] { resulting_string, "TK_STRING"};
}
}
}
else {
while ((esc) || (input[parser_pos].ToString()!=sep)) {
resulting_string += input[parser_pos];
if (!esc) {
esc = input[parser_pos]=='\\';
} else {
esc=false;
}
parser_pos++;
if (parser_pos>=input.Length){
return new string[] {resulting_string,"TK_STRING"};
}
}
}
}
parser_pos += 1;
resulting_string += sep;
if (sep == "/") {
// regexps may have modifiers /regexp/MOD , so fetch those, too
while ((parser_pos < input.Length) && (wordchar.Contains(input[parser_pos]))) {
resulting_string += input[parser_pos];
parser_pos += 1;
}
}
return new string [] {resulting_string, "TK_STRING"};
}
if (c == "#") {
var sharp = "#";
if ((parser_pos < input.Length) && (digits.Contains(input[parser_pos]))) {
do {
c = input[parser_pos].ToString();
sharp += c;
parser_pos += 1;
} while ((parser_pos < input.Length ) && (c != "#") && (c != "="));
if (c == "#") {
return new string[] {sharp, "TK_WORD"};;
} else {
return new string[] {sharp, "TK_OPERATOR"};;
}
}
}
if ((c == "<") && (input.Substring(parser_pos - 1, 3) == "<!--")) {
parser_pos += 3;
return new string[] {"<!--", "TK_COMMENT"};;
}
if ((c == "-") && (input.Substring(parser_pos - 1, 2) == "-->")) {
parser_pos += 2;
if (wanted_newline) {
print_newline(null);
}
return new string[] {"-->", "TK_COMMENT"};
}
if (punct.Contains(c)) {
while ((parser_pos < input.Length) && (punct.Contains(c + input[parser_pos]))) {
c += input[parser_pos];
parser_pos += 1;
if (parser_pos >= input.Length) {
break;
}
}
return new string[] {c, "TK_OPERATOR"};
}
return new string[] {c, "TK_UNKNOWN"};
}
private string last_word;
private bool var_line;
private bool var_line_tainted;
private string[] line_starters;
private bool in_case;
private bool add_script_tags;
private string token_type;
public string GetResult()
{
if (add_script_tags)
{
output.AppendLine().AppendLine("</script>");
}
return output.ToString();
}
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;
}
}
}
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C#
1
https://gitee.com/mircle/DevelopAssistant.git
git@gitee.com:mircle/DevelopAssistant.git
mircle
DevelopAssistant
DevelopAssistant
master

搜索帮助