Merge upstream changes into node-package

This commit is contained in:
Daniel Stockman 2013-03-19 11:19:08 -07:00
commit a42a7a0a01
2 changed files with 92 additions and 59 deletions

View File

@ -77,12 +77,13 @@ unescape_strings = %s
class BeautifierFlags:
def __init__(self, mode):
self.previous_mode = 'BLOCK'
self.previous_mode = MODE.BlockStatement
self.mode = mode
self.var_line = False
self.var_line_tainted = False
self.var_line_reindented = False
self.in_html_comment = False
self.multiline_array = False
self.if_block = False
self.do_block = False
self.do_while = False
@ -158,7 +159,9 @@ Rarely needed options:
class MODE:
BlockStatement, Statement, ObjectLiteral, ArrayLiteral, \
ForInitializer, Conditional, Expression = range(7)
class Beautifier:
@ -170,7 +173,7 @@ class Beautifier:
def blank_state(self):
# internal flags
self.flags = BeautifierFlags('BLOCK')
self.flags = BeautifierFlags(MODE.BlockStatement)
self.flag_store = []
self.wanted_newline = False
@ -201,7 +204,8 @@ class Beautifier:
# Words which always should start on a new line
self.line_starters = 'continue,try,throw,return,var,if,switch,case,default,for,while,break,function'.split(',')
self.set_mode('BLOCK')
self.set_mode(MODE.BlockStatement)
self.parser_pos = 0
@ -296,11 +300,11 @@ class Beautifier:
return s in ['case', 'return', 'do', 'if', 'throw', 'else']
def is_array(self, mode):
return mode in ['[EXPRESSION]', '[INDENTED-EXPRESSION]']
return mode == MODE.ArrayLiteral
def is_expression(self, mode):
return mode in ['[EXPRESSION]', '[INDENTED-EXPRESSION]', '(EXPRESSION)', '(FOR-EXPRESSION)', '(COND-EXPRESSION)']
return mode in [MODE.ArrayLiteral, MODE.Expression, MODE.ForInitializer, MODE.Conditional]
def just_added_newline(self):
return len(self.output) and self.output[-1] == '\n'
@ -342,9 +346,13 @@ class Beautifier:
if not preserve_statement_flags:
if self.last_text != ';':
while self.flags.mode == 'STATEMENT' and not self.flags.if_block:
while self.flags.mode == MODE.Statement and not self.flags.if_block:
self.restore_mode();
if self.flags.mode == MODE.ArrayLiteral:
self.flags.multiline_array = True
if len(self.output) == 0:
# no newline on start of file
return
@ -398,7 +406,7 @@ class Beautifier:
def set_mode(self, mode):
prev = BeautifierFlags('BLOCK')
prev = BeautifierFlags(MODE.BlockStatement)
if self.flags:
self.flag_store.append(self.flags)
@ -423,9 +431,9 @@ class Beautifier:
def start_of_statement(self):
if (self.last_text == 'do' \
or (self.last_text == 'else' and self.token_text != 'if' ) \
or (self.last_type == 'TK_END_EXPR' and (self.flags.previous_mode == '(FOR-EXPRESSION)' or self.flags.previous_mode == '(COND-EXPRESSION)'))):
or (self.last_type == 'TK_END_EXPR' and (self.flags.previous_mode == MODE.ForInitializer or self.flags.previous_mode == MODE.Conditional))):
self.allow_wrap_or_preserved_newline(self.token_text)
self.set_mode('STATEMENT')
self.set_mode(MODE.Statement)
self.indent()
self.output_wrapped = False
return True
@ -550,7 +558,7 @@ class Beautifier:
if c == "'" or c == '"' or \
(c == '/' and ((self.last_type == 'TK_WORD' and self.is_special_word(self.last_text)) or \
(self.last_type == 'TK_END_EXPR' and self.flags.previous_mode in ['(FOR-EXPRESSION)', '(COND-EXPRESSION)']) or \
(self.last_type == 'TK_END_EXPR' and self.flags.previous_mode in [MODE.ForInitializer, MODE.Conditional]) or \
(self.last_type in ['TK_COMMENT', 'TK_START_EXPR', 'TK_START_BLOCK', 'TK_END_BLOCK', 'TK_OPERATOR',
'TK_EQUALS', 'TK_EOF', 'TK_SEMICOLON', 'TK_COMMA']))):
sep = c
@ -700,40 +708,23 @@ class Beautifier:
if self.last_type == 'TK_WORD' or self.last_text == ')':
if self.last_text in self.line_starters:
self.output_space_before_token = True
self.set_mode('(EXPRESSION)')
self.set_mode(MODE.Expression)
self.append_token(token_text)
return
if self.flags.mode in ['[EXPRESSION]', '[INDENTED-EXPRESSION]']:
if self.last_last_text == ']' and self.last_text == ',':
if self.is_array(self.flags.mode):
if self.last_text == '[' or (self.last_last_text == ']' and self.last_text == ','):
# ], [ goes to a new line
if self.flags.mode == '[EXPRESSION]':
self.flags.mode = '[INDENTED-EXPRESSION]'
if not self.opts.keep_array_indentation:
self.indent()
self.set_mode('[EXPRESSION]')
if not self.opts.keep_array_indentation:
self.append_newline()
elif self.last_text == '[':
if self.flags.mode == '[EXPRESSION]':
self.flags.mode = '[INDENTED-EXPRESSION]'
if not self.opts.keep_array_indentation:
self.indent()
self.set_mode('[EXPRESSION]')
if not self.opts.keep_array_indentation:
self.append_newline()
else:
self.set_mode('[EXPRESSION]')
else:
self.set_mode('[EXPRESSION]')
else:
if self.last_text == 'for':
self.set_mode('(FOR-EXPRESSION)')
self.set_mode(MODE.ForInitializer)
elif self.last_text in ['if', 'while']:
self.set_mode('(COND-EXPRESSION)')
self.set_mode(MODE.Conditional)
else:
self.set_mode('(EXPRESSION)')
self.set_mode(MODE.Expression)
if self.last_text == ';' or self.last_type == 'TK_START_BLOCK':
@ -760,28 +751,32 @@ class Beautifier:
self.allow_wrap_or_preserved_newline(token_text)
self.append_token(token_text)
if self.token_text == '[':
self.set_mode(MODE.ArrayLiteral)
self.indent()
def handle_end_expr(self, token_text):
if token_text == ']':
if not self.opts.keep_array_indentation:
if self.flags.mode == '[INDENTED-EXPRESSION]':
if self.last_text == ']':
self.restore_mode()
self.append_newline()
self.append_token(token_text)
return
# statements inside expressions are not valid syntax, but...
# statements must all be closed when their container closes
while self.flags.mode == MODE.Statement:
self.restore_mode()
if self.token_text == ']' and self.is_array(self.flags.mode) and self.flags.multiline_array and not self.opts.keep_array_indentation:
self.append_newline()
self.restore_mode()
self.append_token(token_text)
# do {} while () // no statement required after
if self.flags.do_while and self.flags.previous_mode == '(COND-EXPRESSION)':
self.flags.previous_mode = '(EXPRESSION)'
if self.flags.do_while and self.flags.previous_mode == MODE.Conditional:
self.flags.previous_mode = MODE.Expression
self.flags.do_block = False
self.flags.do_while = False
def handle_start_block(self, token_text):
self.set_mode('BLOCK')
self.set_mode(MODE.BlockStatement)
empty_braces = self.is_next('}')
if self.opts.brace_style == 'expand-strict':
@ -812,6 +807,10 @@ class Beautifier:
def handle_end_block(self, token_text):
# statements must all be closed when their container closes
while self.flags.mode == MODE.Statement:
self.restore_mode()
self.restore_mode()
if self.opts.brace_style == 'expand' or self.opts.brace_style == 'expand-strict':
if self.last_text != '{':
@ -858,7 +857,7 @@ class Beautifier:
# Need to unwind the modes correctly: if (a) if (b) c(); else d(); else e();
if self.flags.if_block:
if token_text != 'else':
while self.flags.mode == 'STATEMENT':
while self.flags.mode == MODE.Statement:
self.restore_mode()
self.flags.if_block = False;
@ -917,7 +916,7 @@ class Beautifier:
else:
prefix = 'SPACE'
self.output_space_before_token = True
elif self.last_type == 'TK_SEMICOLON' and self.flags.mode in 'BLOCK':
elif self.last_type == 'TK_SEMICOLON' and self.flags.mode == MODE.BlockStatement:
# TODO: Should this be for STATEMENT as well?
prefix = 'NEWLINE'
elif self.last_type == 'TK_SEMICOLON' and self.is_expression(self.flags.mode):
@ -992,7 +991,7 @@ class Beautifier:
def handle_semicolon(self, token_text):
while self.flags.mode == 'STATEMENT' and not self.flags.if_block:
while self.flags.mode == MODE.Statement and not self.flags.if_block:
self.restore_mode()
self.append_token(token_text)
@ -1000,7 +999,7 @@ class Beautifier:
self.flags.var_line_reindented = False
if self.flags.mode == 'OBJECT':
# OBJECT mode is weird and doesn't get reset too well.
self.flags.mode = 'BLOCK'
self.flags.mode = MODE.BlockStatement
def handle_string(self, token_text):
@ -1010,7 +1009,7 @@ class Beautifier:
self.output_space_before_token = True
elif self.last_type == 'TK_WORD':
self.output_space_before_token = True
elif self.last_type == 'TK_END_EXPR' and self.flags.previous_mode in ['(COND-EXPRESSION)', '(FOR-EXPRESSION)']:
elif self.last_type == 'TK_END_EXPR' and self.flags.previous_mode in [MODE.Conditional, MODE.ForInitializer]:
self.output_space_before_token = True
elif self.last_type in ['TK_COMMA', 'TK_START_EXPR', 'TK_EQUALS', 'TK_OPERATOR']:
if self.flags.mode != 'OBJECT':
@ -1050,7 +1049,7 @@ class Beautifier:
return
if self.last_type == 'TK_END_BLOCK' and self.flags.mode != '(EXPRESSION)':
if self.last_type == 'TK_END_BLOCK' and self.flags.mode != MODE.Expression:
self.append_token(token_text)
if self.flags.mode == 'OBJECT' and self.last_text == '}':
self.append_newline()
@ -1112,14 +1111,14 @@ class Beautifier:
if self.last_type == 'TK_WORD' and self.last_text in self.line_starters:
space_before = True
if self.flags.mode == 'BLOCK' and self.last_text in ['{', ';']:
if self.flags.mode == MODE.BlockStatement and self.last_text in ['{', ';']:
# { foo: --i }
# foo(): --bar
self.append_newline()
elif token_text == ':':
if self.flags.ternary_depth == 0:
if self.flags.mode == 'BLOCK':
if self.flags.mode == MODE.BlockStatement:
self.flags.mode = 'OBJECT'
space_before = False
else:

View File

@ -129,7 +129,13 @@ class TestJSBeautifier(unittest.TestCase):
bt("a = 1;\n // comment", "a = 1;\n// comment");
bt('a = [-1, -1, -1]');
bt('o = [{a:b},{c:d}]', 'o = [{\n a: b\n}, {\n c: d\n}]');
# The exact formatting these should have is open for discussion, but they are at least reasonable
bt('a = [ // comment\n -1, -1, -1\n]');
bt('var a = [ // comment\n -1, -1, -1\n]');
bt('a = [ // comment\n -1, // comment\n -1, -1\n]');
bt('var a = [ // comment\n -1, // comment\n -1, -1\n]');
bt('o = [{a:b},{c:d}]', 'o = [{\n a: b\n }, {\n c: d\n }\n]');
bt("if (a) {\n do();\n}"); # was: extra space appended
@ -183,7 +189,7 @@ class TestJSBeautifier(unittest.TestCase):
test_fragment('/incomplete-regex');
test_fragment('{a:1},{a:2}', '{\n a: 1\n}, {\n a: 2\n}');
test_fragment('var ary=[{a:1}, {a:2}];', 'var ary = [{\n a: 1\n}, {\n a: 2\n}];');
test_fragment('var ary=[{a:1}, {a:2}];', 'var ary = [{\n a: 1\n }, {\n a: 2\n }\n];');
test_fragment('{a:#1', '{\n a: #1'); # incomplete
test_fragment('{a:#', '{\n a: #'); # incomplete
@ -295,7 +301,7 @@ class TestJSBeautifier(unittest.TestCase):
bt("var a2, b2, c2, d2 = 0, c = function() {},\nd = '';", "var a2, b2, c2, d2 = 0,\n c = function() {},\n d = '';");
bt('var o2=$.extend(a);function(){alert(x);}', 'var o2 = $.extend(a);\n\nfunction() {\n alert(x);\n}');
bt('{"x":[{"a":1,"b":3},7,8,8,8,8,{"b":99},{"a":11}]}', '{\n "x": [{\n "a": 1,\n "b": 3\n },\n 7, 8, 8, 8, 8, {\n "b": 99\n }, {\n "a": 11\n }]\n}');
bt('{"x":[{"a":1,"b":3},7,8,8,8,8,{"b":99},{"a":11}]}', '{\n "x": [{\n "a": 1,\n "b": 3\n },\n 7, 8, 8, 8, 8, {\n "b": 99\n }, {\n "a": 11\n }\n ]\n}');
bt('{"1":{"1a":"1b"},"2"}', '{\n "1": {\n "1a": "1b"\n },\n "2"\n}');
bt('{a:{a:b},c}', '{\n a: {\n a: b\n },\n c\n}');
@ -353,12 +359,12 @@ class TestJSBeautifier(unittest.TestCase):
bt('var x = [{}\n]', 'var x = [{}\n]');
bt('var x = [{foo:bar}\n]', 'var x = [{\n foo: bar\n}\n]');
bt("a = ['something',\n'completely',\n'different'];\nif (x);");
bt('var x = [{foo:bar}\n]', 'var x = [{\n foo: bar\n }\n]');
bt("a = ['something',\n 'completely',\n 'different'];\nif (x);");
bt("a = ['a','b','c']", "a = ['a', 'b', 'c']");
bt("a = ['a', 'b','c']", "a = ['a', 'b', 'c']");
bt("x = [{'a':0}]", "x = [{\n 'a': 0\n}]");
bt("x = [{'a':0}]", "x = [{\n 'a': 0\n }]");
bt('{a([[a1]], {b;});}', '{\n a([[a1]], {\n b;\n });\n}');
@ -673,6 +679,20 @@ class TestJSBeautifier(unittest.TestCase):
bt('if (foo) if (bar) if (baz) whee();\na();');
bt('if (foo) a()\nif (bar) if (baz) whee();\na();');
bt('if (options)\n' +
' for (var p in options)\n' +
' this[p] = options[p];',
'if (options) for (var p in options) this[p] = options[p];');
bt('function f(a,b) {if(a) b()}function g(a,b) {if(!a) b()}',
'function f(a, b) {\n if (a) b()\n}\nfunction g(a, b) {\n if (!a) b()\n}');
bt('function f(a,b) {if(a) b()}\n\n\n\nfunction g(a,b) {if(!a) b()}',
'function f(a, b) {\n if (a) b()\n}\n\nfunction g(a, b) {\n if (!a) b()\n}');
# This is not valid syntax, but still want to behave reasonably and not side-effect
bt('(if(a) b())(if(a) b())',
'(\nif (a) b())(\nif (a) b())');
bt('(if(a) b())\n\n\n(if(a) b())',
'(\nif (a) b())\n(\nif (a) b())');
bt("if\n(a)\nb();", "if (a) b();");
bt('var a =\nfoo', 'var a = foo');
@ -700,6 +720,20 @@ class TestJSBeautifier(unittest.TestCase):
bt('if (foo) if (bar) if (baz) whee();\na();');
bt('if (foo) a()\nif (bar) if (baz) whee();\na();');
bt('if (options)\n' +
' for (var p in options)\n' +
' this[p] = options[p];');
bt('function f(a,b) {if(a) b()}function g(a,b) {if(!a) b()}',
'function f(a, b) {\n if (a) b()\n}\nfunction g(a, b) {\n if (!a) b()\n}');
bt('function f(a,b) {if(a) b()}\n\n\n\nfunction g(a,b) {if(!a) b()}',
'function f(a, b) {\n if (a) b()\n}\n\n\n\nfunction g(a, b) {\n if (!a) b()\n}');
# This is not valid syntax, but still want to behave reasonably and not side-effect
bt('(if(a) b())(if(a) b())',
'(\nif (a) b())(\nif (a) b())');
bt('(if(a) b())\n\n\n(if(a) b())',
'(\nif (a) b())\n\n\n(\nif (a) b())');
bt("if\n(a)\nb();", "if (a)\n b();");
bt('var a =\nfoo', 'var a =\n foo');