From 01111faed551209a29d89f33059eeb011ff45694 Mon Sep 17 00:00:00 2001 From: Liam Newman Date: Fri, 11 May 2018 15:18:42 -0700 Subject: [PATCH 1/2] Rearrange expression start formatting code --- js/lib/beautify.js | 93 +++++++------ js/src/javascript/beautifier.js | 93 +++++++------ .../generated/beautify-javascript-tests.js | 126 +++++++++++++++--- python/jsbeautifier/javascript/beautifier.py | 80 ++++++----- python/jsbeautifier/javascript/options.py | 1 + python/jsbeautifier/tests/generated/tests.py | 120 ++++++++++++++--- test/data/javascript/node.mustache | 6 - test/data/javascript/tests.js | 49 ++++++- 8 files changed, 381 insertions(+), 187 deletions(-) diff --git a/js/lib/beautify.js b/js/lib/beautify.js index 59843e20..4e0b3020 100644 --- a/js/lib/beautify.js +++ b/js/lib/beautify.js @@ -851,62 +851,59 @@ function Beautifier(js_source_text, options) { } } - } else { - if (last_type === 'TK_RESERVED' && flags.last_text === 'for') { - next_mode = MODE.ForInitializer; - } else if (last_type === 'TK_RESERVED' && in_array(flags.last_text, ['if', 'while'])) { - next_mode = MODE.Conditional; - } else { - // next_mode = MODE.Expression; + if (!in_array(last_type, ['TK_START_EXPR', 'TK_END_EXPR', 'TK_WORD', 'TK_OPERATOR'])) { + output.space_before_token = true; } + } else { + if (last_type === 'TK_RESERVED') { + if (flags.last_text === 'for') { + output.space_before_token = opt.space_before_conditional; + next_mode = MODE.ForInitializer; + } else if (in_array(flags.last_text, ['if', 'while'])) { + output.space_before_token = opt.space_before_conditional; + next_mode = MODE.Conditional; + } else if (in_array(flags.last_word, ['await', 'async'])) { + // Should be a space between await and an IIFE, or async and an arrow function + output.space_before_token = true; + } else if (in_array(flags.last_text, tokenizer.line_starters) || flags.last_text === 'catch') { + output.space_before_token = true; + } + } else if (last_type === 'TK_EQUALS' || last_type === 'TK_OPERATOR') { + // Support of this kind of newline preservation. + // a = (b && + // (c || d)); + if (!start_of_object_property()) { + allow_wrap_or_preserved_newline(); + } + } else if (last_type === 'TK_WORD') { + output.space_before_token = false; + } else { + // Support preserving wrapped arrow function expressions + // a.b('c', + // () => d.e + // ) + allow_wrap_or_preserved_newline(); + } + + // function() vs function () + // yield*() vs yield* () + // function*() vs function* () + if ((last_type === 'TK_RESERVED' && (flags.last_word === 'function' || flags.last_word === 'typeof')) || + (flags.last_text === '*' && + (in_array(last_last_text, ['function', 'yield']) || + (flags.mode === MODE.ObjectLiteral && in_array(last_last_text, ['{', ',']))))) { + + output.space_before_token = opt.space_after_anon_function; + } + } if (flags.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' || flags.last_text === '.') { + // do nothing on (( and )( and ][ and ]( and .( // TODO: Consider whether forcing this is required. Review failing tests when removed. allow_wrap_or_preserved_newline(current_token.wanted_newline); - // do nothing on (( and )( and ][ and ]( and .( - } else if (!(last_type === 'TK_RESERVED' && current_token.text === '(') && last_type !== 'TK_WORD' && last_type !== 'TK_OPERATOR') { - output.space_before_token = true; - } else if ((last_type === 'TK_RESERVED' && (flags.last_word === 'function' || flags.last_word === 'typeof')) || - (flags.last_text === '*' && - (in_array(last_last_text, ['function', 'yield']) || - (flags.mode === MODE.ObjectLiteral && in_array(last_last_text, ['{', ',']))))) { - // function() vs function () - // yield*() vs yield* () - // function*() vs function* () - if (opt.space_after_anon_function) { - output.space_before_token = true; - } - } else if (last_type === 'TK_RESERVED' && (in_array(flags.last_text, tokenizer.line_starters) || flags.last_text === 'catch')) { - if (opt.space_before_conditional) { - output.space_before_token = true; - } - } - - // Should be a space between await and an IIFE, or async and an arrow function - if (current_token.text === '(' && last_type === 'TK_RESERVED' && in_array(flags.last_word, ['await', 'async'])) { - output.space_before_token = true; - } - - // Support of this kind of newline preservation. - // a = (b && - // (c || d)); - if (current_token.text === '(') { - if (last_type === 'TK_EQUALS' || last_type === 'TK_OPERATOR') { - if (!start_of_object_property()) { - allow_wrap_or_preserved_newline(); - } - } - } - - // Support preserving wrapped arrow function expressions - // a.b('c', - // () => d.e - // ) - if (current_token.text === '(' && last_type !== 'TK_WORD' && last_type !== 'TK_RESERVED') { - allow_wrap_or_preserved_newline(); } set_mode(next_mode); diff --git a/js/src/javascript/beautifier.js b/js/src/javascript/beautifier.js index 2f39a905..7ab8dace 100644 --- a/js/src/javascript/beautifier.js +++ b/js/src/javascript/beautifier.js @@ -619,62 +619,59 @@ function Beautifier(js_source_text, options) { } } - } else { - if (last_type === 'TK_RESERVED' && flags.last_text === 'for') { - next_mode = MODE.ForInitializer; - } else if (last_type === 'TK_RESERVED' && in_array(flags.last_text, ['if', 'while'])) { - next_mode = MODE.Conditional; - } else { - // next_mode = MODE.Expression; + if (!in_array(last_type, ['TK_START_EXPR', 'TK_END_EXPR', 'TK_WORD', 'TK_OPERATOR'])) { + output.space_before_token = true; } + } else { + if (last_type === 'TK_RESERVED') { + if (flags.last_text === 'for') { + output.space_before_token = opt.space_before_conditional; + next_mode = MODE.ForInitializer; + } else if (in_array(flags.last_text, ['if', 'while'])) { + output.space_before_token = opt.space_before_conditional; + next_mode = MODE.Conditional; + } else if (in_array(flags.last_word, ['await', 'async'])) { + // Should be a space between await and an IIFE, or async and an arrow function + output.space_before_token = true; + } else if (in_array(flags.last_text, tokenizer.line_starters) || flags.last_text === 'catch') { + output.space_before_token = true; + } + } else if (last_type === 'TK_EQUALS' || last_type === 'TK_OPERATOR') { + // Support of this kind of newline preservation. + // a = (b && + // (c || d)); + if (!start_of_object_property()) { + allow_wrap_or_preserved_newline(); + } + } else if (last_type === 'TK_WORD') { + output.space_before_token = false; + } else { + // Support preserving wrapped arrow function expressions + // a.b('c', + // () => d.e + // ) + allow_wrap_or_preserved_newline(); + } + + // function() vs function () + // yield*() vs yield* () + // function*() vs function* () + if ((last_type === 'TK_RESERVED' && (flags.last_word === 'function' || flags.last_word === 'typeof')) || + (flags.last_text === '*' && + (in_array(last_last_text, ['function', 'yield']) || + (flags.mode === MODE.ObjectLiteral && in_array(last_last_text, ['{', ',']))))) { + + output.space_before_token = opt.space_after_anon_function; + } + } if (flags.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' || flags.last_text === '.') { + // do nothing on (( and )( and ][ and ]( and .( // TODO: Consider whether forcing this is required. Review failing tests when removed. allow_wrap_or_preserved_newline(current_token.wanted_newline); - // do nothing on (( and )( and ][ and ]( and .( - } else if (!(last_type === 'TK_RESERVED' && current_token.text === '(') && last_type !== 'TK_WORD' && last_type !== 'TK_OPERATOR') { - output.space_before_token = true; - } else if ((last_type === 'TK_RESERVED' && (flags.last_word === 'function' || flags.last_word === 'typeof')) || - (flags.last_text === '*' && - (in_array(last_last_text, ['function', 'yield']) || - (flags.mode === MODE.ObjectLiteral && in_array(last_last_text, ['{', ',']))))) { - // function() vs function () - // yield*() vs yield* () - // function*() vs function* () - if (opt.space_after_anon_function) { - output.space_before_token = true; - } - } else if (last_type === 'TK_RESERVED' && (in_array(flags.last_text, tokenizer.line_starters) || flags.last_text === 'catch')) { - if (opt.space_before_conditional) { - output.space_before_token = true; - } - } - - // Should be a space between await and an IIFE, or async and an arrow function - if (current_token.text === '(' && last_type === 'TK_RESERVED' && in_array(flags.last_word, ['await', 'async'])) { - output.space_before_token = true; - } - - // Support of this kind of newline preservation. - // a = (b && - // (c || d)); - if (current_token.text === '(') { - if (last_type === 'TK_EQUALS' || last_type === 'TK_OPERATOR') { - if (!start_of_object_property()) { - allow_wrap_or_preserved_newline(); - } - } - } - - // Support preserving wrapped arrow function expressions - // a.b('c', - // () => d.e - // ) - if (current_token.text === '(' && last_type !== 'TK_WORD' && last_type !== 'TK_RESERVED') { - allow_wrap_or_preserved_newline(); } set_mode(next_mode); diff --git a/js/test/generated/beautify-javascript-tests.js b/js/test/generated/beautify-javascript-tests.js index da06d719..c417a625 100644 --- a/js/test/generated/beautify-javascript-tests.js +++ b/js/test/generated/beautify-javascript-tests.js @@ -1028,24 +1028,25 @@ function run_javascript_tests(test_obj, Urlencoded, js_beautify, html_beautify, 'function g(a, b) {\n' + ' if (!a) b()\n' + '}'); - bt('a=[];', 'a = [];'); + bt('a=[][ ]( );', 'a = [][]();'); + bt('a=()( )[ ];', 'a = ()()[];'); bt('a=[b,c,d];', 'a = [b, c, d];'); bt('a= f[b];', 'a = f[b];'); bt( '{\n' + - ' files: [ {\n' + + ' files: a[][ {\n' + ' expand: true,\n' + ' cwd: "www/gui/",\n' + - ' src: [ "im/design_standards/*.*" ],\n' + + ' src: b(c)[ "im/design_standards/*.*" ],\n' + ' dest: "www/gui/build"\n' + ' } ]\n' + '}', // -- output -- '{\n' + - ' files: [{\n' + + ' files: a[][{\n' + ' expand: true,\n' + ' cwd: "www/gui/",\n' + - ' src: ["im/design_standards/*.*"],\n' + + ' src: b(c)["im/design_standards/*.*"],\n' + ' dest: "www/gui/build"\n' + ' }]\n' + '}'); @@ -1077,24 +1078,25 @@ function run_javascript_tests(test_obj, Urlencoded, js_beautify, html_beautify, 'function g(a, b) {\n' + ' if (!a) b()\n' + '}'); - bt('a=[];', 'a = [];'); + bt('a=[][ ]( );', 'a = [][]();'); + bt('a=()( )[ ];', 'a = ()()[];'); bt('a=[b,c,d];', 'a = [b, c, d];'); bt('a= f[b];', 'a = f[b];'); bt( '{\n' + - ' files: [ {\n' + + ' files: a[][ {\n' + ' expand: true,\n' + ' cwd: "www/gui/",\n' + - ' src: [ "im/design_standards/*.*" ],\n' + + ' src: b(c)[ "im/design_standards/*.*" ],\n' + ' dest: "www/gui/build"\n' + ' } ]\n' + '}', // -- output -- '{\n' + - ' files: [{\n' + + ' files: a[][{\n' + ' expand: true,\n' + ' cwd: "www/gui/",\n' + - ' src: ["im/design_standards/*.*"],\n' + + ' src: b(c)["im/design_standards/*.*"],\n' + ' dest: "www/gui/build"\n' + ' }]\n' + '}'); @@ -1126,15 +1128,25 @@ function run_javascript_tests(test_obj, Urlencoded, js_beautify, html_beautify, 'function g( a, b ) {\n' + ' if ( !a ) b()\n' + '}'); - bt('a=[];', 'a = [];'); + bt('a=[][ ]( );', 'a = [][]();'); + bt('a=()( )[ ];', 'a = ()()[];'); bt('a=[b,c,d];', 'a = [ b, c, d ];'); bt('a= f[b];', 'a = f[ b ];'); bt( '{\n' + - ' files: [ {\n' + + ' files: a[][ {\n' + ' expand: true,\n' + ' cwd: "www/gui/",\n' + - ' src: [ "im/design_standards/*.*" ],\n' + + ' src: b(c)[ "im/design_standards/*.*" ],\n' + + ' dest: "www/gui/build"\n' + + ' } ]\n' + + '}', + // -- output -- + '{\n' + + ' files: a[][ {\n' + + ' expand: true,\n' + + ' cwd: "www/gui/",\n' + + ' src: b( c )[ "im/design_standards/*.*" ],\n' + ' dest: "www/gui/build"\n' + ' } ]\n' + '}'); @@ -1166,15 +1178,25 @@ function run_javascript_tests(test_obj, Urlencoded, js_beautify, html_beautify, 'function g( a, b ) {\n' + ' if ( !a ) b( )\n' + '}'); - bt('a=[];', 'a = [ ];'); + bt('a=[][ ]( );', 'a = [ ][ ]( );'); + bt('a=()( )[ ];', 'a = ( )( )[ ];'); bt('a=[b,c,d];', 'a = [ b, c, d ];'); bt('a= f[b];', 'a = f[ b ];'); bt( '{\n' + - ' files: [ {\n' + + ' files: a[][ {\n' + ' expand: true,\n' + ' cwd: "www/gui/",\n' + - ' src: [ "im/design_standards/*.*" ],\n' + + ' src: b(c)[ "im/design_standards/*.*" ],\n' + + ' dest: "www/gui/build"\n' + + ' } ]\n' + + '}', + // -- output -- + '{\n' + + ' files: a[ ][ {\n' + + ' expand: true,\n' + + ' cwd: "www/gui/",\n' + + ' src: b( c )[ "im/design_standards/*.*" ],\n' + ' dest: "www/gui/build"\n' + ' } ]\n' + '}'); @@ -2161,6 +2183,72 @@ function run_javascript_tests(test_obj, Urlencoded, js_beautify, html_beautify, '}'); + //============================================================ + // Space before conditional - (s = "") + reset_options(); + opts.space_before_conditional = false; + bt('if(a) b()'); + bt('while(a) b()'); + bt( + 'do\n' + + ' c();\n' + + 'while(a) b()'); + bt( + 'if(a)\n' + + 'b();', + // -- output -- + 'if(a)\n' + + ' b();'); + bt( + 'while(a)\n' + + 'b();', + // -- output -- + 'while(a)\n' + + ' b();'); + bt( + 'do\n' + + 'c();\n' + + 'while(a);', + // -- output -- + 'do\n' + + ' c();\n' + + 'while(a);'); + bt('return [];'); + bt('return ();'); + + // Space before conditional - (s = " ") + reset_options(); + opts.space_before_conditional = true; + bt('if (a) b()'); + bt('while (a) b()'); + bt( + 'do\n' + + ' c();\n' + + 'while (a) b()'); + bt( + 'if(a)\n' + + 'b();', + // -- output -- + 'if (a)\n' + + ' b();'); + bt( + 'while(a)\n' + + 'b();', + // -- output -- + 'while (a)\n' + + ' b();'); + bt( + 'do\n' + + 'c();\n' + + 'while(a);', + // -- output -- + 'do\n' + + ' c();\n' + + 'while (a);'); + bt('return [];'); + bt('return ();'); + + //============================================================ // Beautify preserve formatting reset_options(); @@ -5329,12 +5417,6 @@ function run_javascript_tests(test_obj, Urlencoded, js_beautify, html_beautify, bt('createdAt = {\n type: Date,\n default: Date.now\n}'); bt('switch (createdAt) {\n case a:\n Date,\n default:\n Date.now\n}'); - reset_options(); - //============================================================ - opts.space_before_conditional = false; - bt('if(a) b()'); - - reset_options(); //============================================================ opts.preserve_newlines = true; diff --git a/python/jsbeautifier/javascript/beautifier.py b/python/jsbeautifier/javascript/beautifier.py index 19d98486..bc8b1123 100644 --- a/python/jsbeautifier/javascript/beautifier.py +++ b/python/jsbeautifier/javascript/beautifier.py @@ -458,14 +458,46 @@ class Beautifier: if not self.opts.keep_array_indentation: self.print_newline() - else: - if self.last_type == 'TK_RESERVED' and self.flags.last_text == 'for': - next_mode = MODE.ForInitializer - elif self.last_type == 'TK_RESERVED' and self.flags.last_text in ['if', 'while']: - next_mode = MODE.Conditional - else: - next_mode = MODE.Expression + if self.last_type not in ['TK_START_EXPR', 'TK_END_EXPR', 'TK_WORD', 'TK_OPERATOR']: + self.output.space_before_token = True + else: + if self.last_type == 'TK_RESERVED': + if self.flags.last_text == 'for': + self.output.space_before_token = self.opts.space_before_conditional + next_mode = MODE.ForInitializer + elif self.flags.last_text in ['if', 'while']: + self.output.space_before_token = self.opts.space_before_conditional + next_mode = MODE.Conditional + elif self.flags.last_word in ['await', 'async']: + # Should be a space between await and an IIFE, or async and an arrow function + self.output.space_before_token = True + elif self.flags.last_text in Tokenizer.line_starters or self.flags.last_text == 'catch': + self.output.space_before_token = True + + elif self.last_type in ['TK_EQUALS', 'TK_OPERATOR']: + # Support of this kind of newline preservation: + # a = (b && + # (c || d)); + if not self.start_of_object_property(): + self.allow_wrap_or_preserved_newline(current_token) + elif self.last_type == 'TK_WORD': + self.output.space_before_token = False + else: + # Support preserving wrapped arrow function expressions + # a.b('c', + # () => d.e + # ) + self.allow_wrap_or_preserved_newline(current_token) + + + # function() vs function (), typeof() vs typeof () + # function*() vs function* (), yield*() vs yield* () + if (self.last_type == 'TK_RESERVED' and (self.flags.last_word == 'function' or self.flags.last_word == 'typeof')) or \ + (self.flags.last_text == '*' and ( + self.last_last_text in ['function', 'yield'] or + (self.flags.mode == MODE.ObjectLiteral and self.last_last_text in ['{', ',']))): + self.output.space_before_token = self.opts.space_after_anon_function if self.flags.last_text == ';' or self.last_type == 'TK_START_BLOCK': self.print_newline() @@ -474,40 +506,6 @@ class Beautifier: # TODO: Consider whether forcing this is required. Review failing tests when removed. self.allow_wrap_or_preserved_newline(current_token, current_token.wanted_newline) - elif not (self.last_type == 'TK_RESERVED' and current_token.text == '(') and self.last_type not in ['TK_WORD', 'TK_OPERATOR']: - self.output.space_before_token = True - elif (self.last_type == 'TK_RESERVED' and (self.flags.last_word == 'function' or self.flags.last_word == 'typeof')) or \ - (self.flags.last_text == '*' and ( - self.last_last_text in ['function', 'yield'] or - (self.flags.mode == MODE.ObjectLiteral and self.last_last_text in ['{', ',']))): - # function() vs function (), typeof() vs typeof () - # function*() vs function* (), yield*() vs yield* () - if self.opts.space_after_anon_function: - self.output.space_before_token = True - elif self.last_type == 'TK_RESERVED' and (self.flags.last_text in Tokenizer.line_starters or self.flags.last_text == 'catch'): - # TODO: option space_before_conditional - self.output.space_before_token = True - - elif current_token.text == '(' and self.last_type == 'TK_RESERVED' and self.flags.last_word in ['await', 'async']: - self.output.space_before_token = True - - - # Support of this kind of newline preservation: - # a = (b && - # (c || d)); - if self.last_type in ['TK_EQUALS', 'TK_OPERATOR']: - if not self.start_of_object_property(): - self.allow_wrap_or_preserved_newline(current_token) - - - # Support preserving wrapped arrow function expressions - # a.b('c', - # () => d.e - # ) - if current_token.text == '(' and self.last_type not in ['TK_WORD', 'TK_RESERVED']: - self.allow_wrap_or_preserved_newline(current_token) - - self.set_mode(next_mode) self.print_token(current_token) diff --git a/python/jsbeautifier/javascript/options.py b/python/jsbeautifier/javascript/options.py index 51d52db3..7cbdd446 100644 --- a/python/jsbeautifier/javascript/options.py +++ b/python/jsbeautifier/javascript/options.py @@ -37,6 +37,7 @@ class BeautifierOptions: self.space_after_anon_function = False self.brace_style = 'collapse' self.keep_array_indentation = False + self.space_before_conditional = True self.keep_function_indentation = False self.eval_code = False self.unescape_strings = False diff --git a/python/jsbeautifier/tests/generated/tests.py b/python/jsbeautifier/tests/generated/tests.py index dc2a526f..e766d5b9 100644 --- a/python/jsbeautifier/tests/generated/tests.py +++ b/python/jsbeautifier/tests/generated/tests.py @@ -856,24 +856,25 @@ class TestJSBeautifier(unittest.TestCase): 'function g(a, b) {\n' + ' if (!a) b()\n' + '}') - bt('a=[];', 'a = [];') + bt('a=[][ ]( );', 'a = [][]();') + bt('a=()( )[ ];', 'a = ()()[];') bt('a=[b,c,d];', 'a = [b, c, d];') bt('a= f[b];', 'a = f[b];') bt( '{\n' + - ' files: [ {\n' + + ' files: a[][ {\n' + ' expand: true,\n' + ' cwd: "www/gui/",\n' + - ' src: [ "im/design_standards/*.*" ],\n' + + ' src: b(c)[ "im/design_standards/*.*" ],\n' + ' dest: "www/gui/build"\n' + ' } ]\n' + '}', # -- output -- '{\n' + - ' files: [{\n' + + ' files: a[][{\n' + ' expand: true,\n' + ' cwd: "www/gui/",\n' + - ' src: ["im/design_standards/*.*"],\n' + + ' src: b(c)["im/design_standards/*.*"],\n' + ' dest: "www/gui/build"\n' + ' }]\n' + '}') @@ -905,24 +906,25 @@ class TestJSBeautifier(unittest.TestCase): 'function g(a, b) {\n' + ' if (!a) b()\n' + '}') - bt('a=[];', 'a = [];') + bt('a=[][ ]( );', 'a = [][]();') + bt('a=()( )[ ];', 'a = ()()[];') bt('a=[b,c,d];', 'a = [b, c, d];') bt('a= f[b];', 'a = f[b];') bt( '{\n' + - ' files: [ {\n' + + ' files: a[][ {\n' + ' expand: true,\n' + ' cwd: "www/gui/",\n' + - ' src: [ "im/design_standards/*.*" ],\n' + + ' src: b(c)[ "im/design_standards/*.*" ],\n' + ' dest: "www/gui/build"\n' + ' } ]\n' + '}', # -- output -- '{\n' + - ' files: [{\n' + + ' files: a[][{\n' + ' expand: true,\n' + ' cwd: "www/gui/",\n' + - ' src: ["im/design_standards/*.*"],\n' + + ' src: b(c)["im/design_standards/*.*"],\n' + ' dest: "www/gui/build"\n' + ' }]\n' + '}') @@ -954,15 +956,25 @@ class TestJSBeautifier(unittest.TestCase): 'function g( a, b ) {\n' + ' if ( !a ) b()\n' + '}') - bt('a=[];', 'a = [];') + bt('a=[][ ]( );', 'a = [][]();') + bt('a=()( )[ ];', 'a = ()()[];') bt('a=[b,c,d];', 'a = [ b, c, d ];') bt('a= f[b];', 'a = f[ b ];') bt( '{\n' + - ' files: [ {\n' + + ' files: a[][ {\n' + ' expand: true,\n' + ' cwd: "www/gui/",\n' + - ' src: [ "im/design_standards/*.*" ],\n' + + ' src: b(c)[ "im/design_standards/*.*" ],\n' + + ' dest: "www/gui/build"\n' + + ' } ]\n' + + '}', + # -- output -- + '{\n' + + ' files: a[][ {\n' + + ' expand: true,\n' + + ' cwd: "www/gui/",\n' + + ' src: b( c )[ "im/design_standards/*.*" ],\n' + ' dest: "www/gui/build"\n' + ' } ]\n' + '}') @@ -994,15 +1006,25 @@ class TestJSBeautifier(unittest.TestCase): 'function g( a, b ) {\n' + ' if ( !a ) b( )\n' + '}') - bt('a=[];', 'a = [ ];') + bt('a=[][ ]( );', 'a = [ ][ ]( );') + bt('a=()( )[ ];', 'a = ( )( )[ ];') bt('a=[b,c,d];', 'a = [ b, c, d ];') bt('a= f[b];', 'a = f[ b ];') bt( '{\n' + - ' files: [ {\n' + + ' files: a[][ {\n' + ' expand: true,\n' + ' cwd: "www/gui/",\n' + - ' src: [ "im/design_standards/*.*" ],\n' + + ' src: b(c)[ "im/design_standards/*.*" ],\n' + + ' dest: "www/gui/build"\n' + + ' } ]\n' + + '}', + # -- output -- + '{\n' + + ' files: a[ ][ {\n' + + ' expand: true,\n' + + ' cwd: "www/gui/",\n' + + ' src: b( c )[ "im/design_standards/*.*" ],\n' + ' dest: "www/gui/build"\n' + ' } ]\n' + '}') @@ -1989,6 +2011,72 @@ class TestJSBeautifier(unittest.TestCase): '}') + #============================================================ + # Space before conditional - (s = "") + self.reset_options(); + self.options.space_before_conditional = false + bt('if(a) b()') + bt('while(a) b()') + bt( + 'do\n' + + ' c();\n' + + 'while(a) b()') + bt( + 'if(a)\n' + + 'b();', + # -- output -- + 'if(a)\n' + + ' b();') + bt( + 'while(a)\n' + + 'b();', + # -- output -- + 'while(a)\n' + + ' b();') + bt( + 'do\n' + + 'c();\n' + + 'while(a);', + # -- output -- + 'do\n' + + ' c();\n' + + 'while(a);') + bt('return [];') + bt('return ();') + + # Space before conditional - (s = " ") + self.reset_options(); + self.options.space_before_conditional = true + bt('if (a) b()') + bt('while (a) b()') + bt( + 'do\n' + + ' c();\n' + + 'while (a) b()') + bt( + 'if(a)\n' + + 'b();', + # -- output -- + 'if (a)\n' + + ' b();') + bt( + 'while(a)\n' + + 'b();', + # -- output -- + 'while (a)\n' + + ' b();') + bt( + 'do\n' + + 'c();\n' + + 'while(a);', + # -- output -- + 'do\n' + + ' c();\n' + + 'while (a);') + bt('return [];') + bt('return ();') + + #============================================================ # Beautify preserve formatting self.reset_options(); diff --git a/test/data/javascript/node.mustache b/test/data/javascript/node.mustache index db6f120d..99aa6a00 100644 --- a/test/data/javascript/node.mustache +++ b/test/data/javascript/node.mustache @@ -547,12 +547,6 @@ function run_javascript_tests(test_obj, Urlencoded, js_beautify, html_beautify, bt('createdAt = {\n type: Date,\n default: Date.now\n}'); bt('switch (createdAt) {\n case a:\n Date,\n default:\n Date.now\n}'); - reset_options(); - //============================================================ - opts.space_before_conditional = false; - bt('if(a) b()'); - - reset_options(); //============================================================ opts.preserve_newlines = true; diff --git a/test/data/javascript/tests.js b/test/data/javascript/tests.js index cdce3611..413123e9 100644 --- a/test/data/javascript/tests.js +++ b/test/data/javascript/tests.js @@ -501,8 +501,12 @@ exports.test_data = { output: 'function f({{s}}a, b{{s}}) {\n if ({{s}}a{{s}}) b({{e}})\n}\n\nfunction g({{s}}a, b{{s}}) {\n if ({{s}}!a{{s}}) b({{e}})\n}' }, { - input: 'a=[];', - output: 'a = [{{e}}];' + input: 'a=[][ ]( );', + output: 'a = [{{e}}][{{e}}]({{e}});' + }, + { + input: 'a=()( )[ ];', + output: 'a = ({{e}})({{e}})[{{e}}];' }, { input: 'a=[b,c,d];', @@ -515,20 +519,20 @@ exports.test_data = { { input: [ '{', - ' files: [ {', + ' files: a[][ {', ' expand: true,', ' cwd: "www/gui/",', - ' src: [ "im/design_standards/*.*" ],', + ' src: b(c)[ "im/design_standards/*.*" ],', ' dest: "www/gui/build"', ' } ]', '}' ], output: [ '{', - ' files: [{{s}}{', + ' files: a[{{e}}][{{s}}{', ' expand: true,', ' cwd: "www/gui/",', - ' src: [{{s}}"im/design_standards/*.*"{{s}}],', + ' src: b({{s}}c{{s}})[{{s}}"im/design_standards/*.*"{{s}}],', ' dest: "www/gui/build"', ' }{{s}}]', '}' @@ -1260,6 +1264,39 @@ exports.test_data = { tests: [ { input: '{{}/z/}', output: '{\n {}\n /z/\n}' } ] + }, { + name: "Space before conditional", + description: "", + matrix: [{ + options: [ + { name: "space_before_conditional", value: "false" } + ], + s: '', + }, { + options: [ + { name: "space_before_conditional", value: "true" } + ], + s: ' ', + }], + tests: [ + { unchanged: 'if{{s}}(a) b()' }, + { unchanged: 'while{{s}}(a) b()' }, + { unchanged: 'do\n c();\nwhile{{s}}(a) b()' }, + { + input: 'if(a)\nb();', + output: 'if{{s}}(a)\n b();' + }, + { + input: 'while(a)\nb();', + output: 'while{{s}}(a)\n b();' + }, + { + input: 'do\nc();\nwhile(a);', + output: 'do\n c();\nwhile{{s}}(a);' + }, + { unchanged: 'return [];' }, + { unchanged: 'return ();' }, + ] }, { name: "Beautify preserve formatting", description: "Allow beautifier to preserve sections", From 5329720021c221d92753dfa60e758bef16afa4e2 Mon Sep 17 00:00:00 2001 From: Liam Newman Date: Fri, 11 May 2018 15:29:07 -0700 Subject: [PATCH 2/2] Support dynamic import Fixes #1393 --- js/lib/beautify.js | 2 ++ js/src/javascript/beautifier.js | 2 ++ js/test/generated/beautify-javascript-tests.js | 11 ++++++++++- python/jsbeautifier/javascript/beautifier.py | 2 ++ python/jsbeautifier/tests/generated/tests.py | 11 ++++++++++- test/data/javascript/tests.js | 13 ++++++++++++- 6 files changed, 38 insertions(+), 3 deletions(-) diff --git a/js/lib/beautify.js b/js/lib/beautify.js index 4e0b3020..6a2e86e9 100644 --- a/js/lib/beautify.js +++ b/js/lib/beautify.js @@ -865,6 +865,8 @@ function Beautifier(js_source_text, options) { } else if (in_array(flags.last_word, ['await', 'async'])) { // Should be a space between await and an IIFE, or async and an arrow function output.space_before_token = true; + } else if (flags.last_text === 'import' && current_token.whitespace_before === '') { + output.space_before_token = false; } else if (in_array(flags.last_text, tokenizer.line_starters) || flags.last_text === 'catch') { output.space_before_token = true; } diff --git a/js/src/javascript/beautifier.js b/js/src/javascript/beautifier.js index 7ab8dace..9a784b9b 100644 --- a/js/src/javascript/beautifier.js +++ b/js/src/javascript/beautifier.js @@ -633,6 +633,8 @@ function Beautifier(js_source_text, options) { } else if (in_array(flags.last_word, ['await', 'async'])) { // Should be a space between await and an IIFE, or async and an arrow function output.space_before_token = true; + } else if (flags.last_text === 'import' && current_token.whitespace_before === '') { + output.space_before_token = false; } else if (in_array(flags.last_text, tokenizer.line_starters) || flags.last_text === 'catch') { output.space_before_token = true; } diff --git a/js/test/generated/beautify-javascript-tests.js b/js/test/generated/beautify-javascript-tests.js index c417a625..9d524985 100644 --- a/js/test/generated/beautify-javascript-tests.js +++ b/js/test/generated/beautify-javascript-tests.js @@ -3747,7 +3747,16 @@ function run_javascript_tests(test_obj, Urlencoded, js_beautify, html_beautify, 'import { member1, member2 as alias2 } from "module-name";\n' + 'import defaultMember, { member, member2 } from "module-name";\n' + 'import defaultMember, * as name from "module-name";\n' + - 'import "module-name";'); + 'import "module-name";\n' + + 'import("module-name")'); + + // Issue #1393 - dynamic import() + bt( + 'if (from < to) {\n' + + ' import(`dynamic${library}`);\n' + + '} else {\n' + + ' import("otherdynamic");\n' + + '}'); // Issue 858 - from is a keyword only after import bt( diff --git a/python/jsbeautifier/javascript/beautifier.py b/python/jsbeautifier/javascript/beautifier.py index bc8b1123..4c5f863c 100644 --- a/python/jsbeautifier/javascript/beautifier.py +++ b/python/jsbeautifier/javascript/beautifier.py @@ -472,6 +472,8 @@ class Beautifier: elif self.flags.last_word in ['await', 'async']: # Should be a space between await and an IIFE, or async and an arrow function self.output.space_before_token = True + elif self.flags.last_text == 'import' and current_token.whitespace_before == '': + self.output.space_before_token = False elif self.flags.last_text in Tokenizer.line_starters or self.flags.last_text == 'catch': self.output.space_before_token = True diff --git a/python/jsbeautifier/tests/generated/tests.py b/python/jsbeautifier/tests/generated/tests.py index e766d5b9..e50463eb 100644 --- a/python/jsbeautifier/tests/generated/tests.py +++ b/python/jsbeautifier/tests/generated/tests.py @@ -3575,7 +3575,16 @@ class TestJSBeautifier(unittest.TestCase): 'import { member1, member2 as alias2 } from "module-name";\n' + 'import defaultMember, { member, member2 } from "module-name";\n' + 'import defaultMember, * as name from "module-name";\n' + - 'import "module-name";') + 'import "module-name";\n' + + 'import("module-name")') + + # Issue #1393 - dynamic import() + bt( + 'if (from < to) {\n' + + ' import(`dynamic${library}`);\n' + + '} else {\n' + + ' import("otherdynamic");\n' + + '}') # Issue 858 - from is a keyword only after import bt( diff --git a/test/data/javascript/tests.js b/test/data/javascript/tests.js index 413123e9..740297d3 100644 --- a/test/data/javascript/tests.js +++ b/test/data/javascript/tests.js @@ -2556,7 +2556,18 @@ exports.test_data = { 'import { member1, member2 as alias2 } from "module-name";', 'import defaultMember, { member, member2 } from "module-name";', 'import defaultMember, * as name from "module-name";', - 'import "module-name";' + 'import "module-name";', + 'import("module-name")' + ] + }, + { + comment: "Issue #1393 - dynamic import()", + unchanged: [ + 'if (from < to) {', + ' import(`dynamic${library}`);', + '} else {', + ' import("otherdynamic");', + '}' ] }, {