Skip to content

Commit

Permalink
Merge pull request #439 from bitwiseman/reserved-words
Browse files Browse the repository at this point in the history
Support for keywords as IdentifierNames such as .catch()
  • Loading branch information
bitwiseman committed Mar 28, 2014
2 parents 6a3f667 + f7602b2 commit 2ae6bb9
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 82 deletions.
82 changes: 44 additions & 38 deletions js/lib/beautify.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@
var input, output_lines;
var token_text, token_type, last_type, last_last_text, indent_string;
var flags, previous_flags, flag_store;
var whitespace, wordchar, punct, parser_pos, line_starters, digits;
var whitespace, wordchar, punct, parser_pos, line_starters, reserved_words, digits;
var prefix;
var input_wanted_newline;
var output_wrapped, output_space_before_token;
Expand All @@ -104,6 +104,8 @@

// words which should always start on new line.
line_starters = 'continue,try,throw,return,var,let,const,if,switch,case,default,for,while,break,function'.split(',');
reserved_words = line_starters.concat(['do', 'in', 'else', 'get', 'set', 'new', 'catch', 'finally', 'typeof']);


MODE = {
BlockStatement: 'BlockStatement', // 'BLOCK'
Expand All @@ -121,6 +123,7 @@
'TK_START_BLOCK': handle_start_block,
'TK_END_BLOCK': handle_end_block,
'TK_WORD': handle_word,
'TK_RESERVED': handle_word,
'TK_SEMICOLON': handle_semicolon,
'TK_STRING': handle_string,
'TK_EQUALS': handle_equals,
Expand Down Expand Up @@ -553,14 +556,14 @@

function start_of_statement() {
if (
(flags.last_text === 'do' ||
(flags.last_text === 'else' && token_text !== 'if') ||
((last_type === 'TK_RESERVED' && flags.last_text === 'do') ||
(last_type === 'TK_RESERVED' && flags.last_text === 'else' && !(token_type === 'TK_RESERVED' && token_text === 'if')) ||
(last_type === 'TK_END_EXPR' && (previous_flags.mode === MODE.ForInitializer || previous_flags.mode === MODE.Conditional)))) {
// Issue #276:
// If starting a new statement with [if, for, while, do], push to a new line.
// if (a) if (b) if(c) d(); else e(); else f();
allow_wrap_or_preserved_newline(
in_array(token_text, ['do', 'for', 'if', 'while']));
token_type === 'TK_RESERVED' && in_array(token_text, ['do', 'for', 'if', 'while']));

set_mode(MODE.Statement);
// Issue #275:
Expand Down Expand Up @@ -733,8 +736,11 @@
return [c, 'TK_WORD'];
}

if (c === 'in') { // hack for 'in' operator
return [c, 'TK_OPERATOR'];
if (last_type !== 'TK_DOT' && in_array(c, reserved_words)) {
if (c === 'in') { // hack for 'in' operator
return [c, 'TK_OPERATOR'];
}
return [c, 'TK_RESERVED'];
}
return [c, 'TK_WORD'];
}
Expand Down Expand Up @@ -806,7 +812,7 @@
(c === '/') || // regexp
(opt.e4x && c === "<" && input.slice(parser_pos - 1).match(/^<([-a-zA-Z:0-9_.]+|{[^{}]*}|!\[CDATA\[[\s\S]*?\]\])\s*([-a-zA-Z:0-9_.]+=('[^']*'|"[^"]*"|{[^{}]*})\s*)*\/?\s*>/)) // xml
) && ( // regex and xml can only appear in specific locations during parsing
(last_type === 'TK_WORD' && is_special_word(flags.last_text)) ||
(last_type === 'TK_RESERVED' && is_special_word(flags.last_text)) ||
(last_type === 'TK_END_EXPR' && in_array(previous_flags.mode, [MODE.Conditional, MODE.ForInitializer])) ||
(in_array(last_type, ['TK_COMMENT', 'TK_START_EXPR', 'TK_START_BLOCK',
'TK_END_BLOCK', 'TK_OPERATOR', 'TK_EQUALS', 'TK_EOF', 'TK_SEMICOLON', 'TK_COMMA'
Expand Down Expand Up @@ -1006,10 +1012,10 @@
var next_mode = MODE.Expression;
if (token_text === '[') {

if (last_type === 'TK_WORD' || flags.last_text === ')') {
if (last_type === 'TK_WORD' || last_type === 'TK_RESERVED' || flags.last_text === ')') {
// this is array index specifier, break immediately
// a[x], fn()[x]
if (in_array(flags.last_text, line_starters)) {
if (last_type === 'TK_RESERVED' && in_array(flags.last_text, line_starters)) {
output_space_before_token = true;
}
set_mode(next_mode);
Expand All @@ -1034,9 +1040,9 @@
}

} else {
if (flags.last_text === 'for') {
if (last_type === 'TK_RESERVED' && flags.last_text === 'for') {
next_mode = MODE.ForInitializer;
} else if (in_array(flags.last_text, ['if', 'while'])) {
} else if (last_type === 'TK_RESERVED' && in_array(flags.last_text, ['if', 'while'])) {
next_mode = MODE.Conditional;
} else {
// next_mode = MODE.Expression;
Expand All @@ -1050,14 +1056,14 @@
allow_wrap_or_preserved_newline(input_wanted_newline);
output_wrapped = false;
// do nothing on (( and )( and ][ and ]( and .(
} else if (last_type !== 'TK_WORD' && last_type !== 'TK_OPERATOR') {
} else if (last_type !== 'TK_RESERVED' && last_type !== 'TK_WORD' && last_type !== 'TK_OPERATOR') {
output_space_before_token = true;
} else if (flags.last_word === 'function' || flags.last_word === 'typeof') {
} else if (last_type === 'TK_RESERVED' && (flags.last_word === 'function' || flags.last_word === 'typeof')) {
// function() vs function ()
if (opt.jslint_happy) {
output_space_before_token = true;
}
} else if (in_array(flags.last_text, line_starters) || flags.last_text === 'catch') {
} else if (last_type === 'TK_RESERVED' && (in_array(flags.last_text, line_starters) || flags.last_text === 'catch')) {
if (opt.space_before_conditional) {
output_space_before_token = true;
}
Expand Down Expand Up @@ -1136,7 +1142,7 @@
if (last_type !== 'TK_OPERATOR' &&
(empty_anonymous_function ||
last_type === 'TK_EQUALS' ||
(is_special_word(flags.last_text) && flags.last_text !== 'else'))) {
(last_type === 'TK_RESERVED' && is_special_word(flags.last_text) && flags.last_text !== 'else'))) {
output_space_before_token = true;
} else {
print_newline();
Expand Down Expand Up @@ -1199,13 +1205,13 @@
} else if (input_wanted_newline && !is_expression(flags.mode) &&
(last_type !== 'TK_OPERATOR' || (flags.last_text === '--' || flags.last_text === '++')) &&
last_type !== 'TK_EQUALS' &&
(opt.preserve_newlines || !in_array(flags.last_text, ['var', 'let', 'const']))) {
(opt.preserve_newlines || !(last_type === 'TK_RESERVED' && in_array(flags.last_text, ['var', 'let', 'const'])))) {

print_newline();
}

if (flags.do_block && !flags.do_while) {
if (token_text === 'while') {
if (token_type === 'TK_RESERVED' && token_text === 'while') {
// do {} ## while ()
output_space_before_token = true;
print_token();
Expand All @@ -1224,15 +1230,15 @@
// Bare/inline ifs are tricky
// Need to unwind the modes correctly: if (a) if (b) c(); else d(); else e();
if (flags.if_block) {
if (token_text !== 'else') {
if (!(token_type === 'TK_RESERVED' && token_text === 'else')) {
while (flags.mode === MODE.Statement) {
restore_mode();
}
flags.if_block = false;
}
}

if (token_text === 'case' || (token_text === 'default' && flags.in_case_statement)) {
if (token_type === 'TK_RESERVED' && (token_text === 'case' || (token_text === 'default' && flags.in_case_statement))) {
print_newline();
if (flags.case_body || opt.jslint_happy) {
// switch cases following one another
Expand All @@ -1245,7 +1251,7 @@
return;
}

if (token_text === 'function') {
if (token_type === 'TK_RESERVED' && token_text === 'function') {
if (flags.var_line && last_type !== 'TK_EQUALS') {
flags.var_line_reindented = true;
}
Expand All @@ -1257,8 +1263,8 @@
print_newline(true);
}
}
if (last_type === 'TK_WORD') {
if (flags.last_text === 'get' || flags.last_text === 'set' || flags.last_text === 'new' || flags.last_text === 'return') {
if (last_type === 'TK_RESERVED' || last_type === 'TK_WORD') {
if (last_type === 'TK_RESERVED' && in_array(flags.last_text, ['get', 'set', 'new', 'return'])) {
output_space_before_token = true;
} else {
print_newline();
Expand All @@ -1279,7 +1285,7 @@
}
}

if (token_text === 'function') {
if (token_type === 'TK_RESERVED' && token_text === 'function') {
print_token();
flags.last_word = token_text;
return;
Expand All @@ -1288,7 +1294,7 @@
prefix = 'NONE';

if (last_type === 'TK_END_BLOCK') {
if (!in_array(token_text, ['else', 'catch', 'finally'])) {
if (!(token_type === 'TK_RESERVED' && in_array(token_text, ['else', 'catch', 'finally']))) {
prefix = 'NEWLINE';
} else {
if (opt.brace_style === "expand" || opt.brace_style === "end-expand") {
Expand All @@ -1305,7 +1311,7 @@
prefix = 'SPACE';
} else if (last_type === 'TK_STRING') {
prefix = 'NEWLINE';
} else if (last_type === 'TK_WORD') {
} else if (last_type === 'TK_RESERVED' || last_type === 'TK_WORD') {
prefix = 'SPACE';
} else if (last_type === 'TK_START_BLOCK') {
prefix = 'NEWLINE';
Expand All @@ -1314,7 +1320,7 @@
prefix = 'NEWLINE';
}

if (in_array(token_text, line_starters) && flags.last_text !== ')') {
if (token_type === 'TK_RESERVED' && in_array(token_text, line_starters) && flags.last_text !== ')') {
if (flags.last_text === 'else') {
prefix = 'SPACE';
} else {
Expand All @@ -1323,7 +1329,7 @@

}

if (in_array(token_text, ['else', 'catch', 'finally'])) {
if (token_type === 'TK_RESERVED' && in_array(token_text, ['else', 'catch', 'finally'])) {
if (last_type !== 'TK_END_BLOCK' || opt.brace_style === "expand" || opt.brace_style === "end-expand") {
print_newline();
} else {
Expand All @@ -1337,13 +1343,13 @@
output_space_before_token = true;
}
} else if (prefix === 'NEWLINE') {
if (is_special_word(flags.last_text)) {
if (last_type === 'TK_RESERVED' && is_special_word(flags.last_text)) {
// no newline between 'return nnn'
output_space_before_token = true;
} else if (last_type !== 'TK_END_EXPR') {
if ((last_type !== 'TK_START_EXPR' || !in_array(token_text, ['var', 'let', 'const'])) && flags.last_text !== ':') {
if ((last_type !== 'TK_START_EXPR' || !(token_type === 'TK_RESERVED' && in_array(token_text, ['var', 'let', 'const']))) && flags.last_text !== ':') {
// no need to force newline on 'var': for (var x = 0...)
if (token_text === 'if' && flags.last_word === 'else' && flags.last_text !== '{') {
if (token_type === 'TK_RESERVED' && token_text === 'if' && flags.last_word === 'else' && flags.last_text !== '{') {
// no newline for } else if {
output_space_before_token = true;
} else {
Expand All @@ -1352,7 +1358,7 @@
print_newline();
}
}
} else if (in_array(token_text, line_starters) && flags.last_text !== ')') {
} else if (token_type === 'TK_RESERVED' && in_array(token_text, line_starters) && flags.last_text !== ')') {
flags.var_line = false;
flags.var_line_reindented = false;
print_newline();
Expand All @@ -1365,17 +1371,17 @@
print_token();
flags.last_word = token_text;

if (in_array(token_text, ['var', 'let', 'const'])) {
if (token_type === 'TK_RESERVED' && in_array(token_text, ['var', 'let', 'const'])) {
flags.var_line = true;
flags.var_line_reindented = false;
flags.var_line_tainted = false;
}

if (token_text === 'do') {
if (token_type === 'TK_RESERVED' && token_text === 'do') {
flags.do_block = true;
}

if (token_text === 'if') {
if (token_type === 'TK_RESERVED' && token_text === 'if') {
flags.if_block = true;
}
}
Expand Down Expand Up @@ -1404,7 +1410,7 @@
// The conditional starts the statement if appropriate.
// One difference - strings want at least a space before
output_space_before_token = true;
} else if (last_type === 'TK_WORD') {
} else if (last_type === 'TK_RESERVED' || last_type === 'TK_WORD') {
output_space_before_token = true;
} else if (last_type === 'TK_COMMA' || last_type === 'TK_START_EXPR' || last_type === 'TK_EQUALS' || last_type === 'TK_OPERATOR') {
if (!start_of_object_property()) {
Expand Down Expand Up @@ -1470,7 +1476,7 @@
function handle_operator() {
var space_before = true;
var space_after = true;
if (is_special_word(flags.last_text)) {
if (last_type === 'TK_RESERVED' && is_special_word(flags.last_text)) {
// "return" had a special handling in TK_WORD. Now we need to return the favor
output_space_before_token = true;
print_token();
Expand Down Expand Up @@ -1516,7 +1522,7 @@
space_before = true;
}

if (last_type === 'TK_WORD' && in_array(flags.last_text, line_starters)) {
if (last_type === 'TK_RESERVED') {
space_before = true;
}

Expand Down Expand Up @@ -1591,7 +1597,7 @@
}

function handle_dot() {
if (is_special_word(flags.last_text)) {
if (last_type === 'TK_RESERVED' && is_special_word(flags.last_text)) {
output_space_before_token = true;
} else {
// allow preserved newlines before dots in general
Expand Down
6 changes: 6 additions & 0 deletions js/test/beautify-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,12 @@ function run_beautifier_tests(test_obj, Urlencoded, js_beautify, html_beautify,
// a common snippet in jQuery plugins
bt("settings = $.extend({},defaults,settings);", "settings = $.extend({}, defaults, settings);");

// reserved words used as property names
bt("$http().then().finally().default()", "$http().then().finally().default()");
bt("$http()\n.then()\n.finally()\n.default()", "$http()\n .then()\n .finally()\n .default()");
bt("$http().when.in.new.catch().throw()", "$http().when.in.new.catch().throw()");
bt("$http()\n.when\n.in\n.new\n.catch()\n.throw()", "$http()\n .when\n .in\n .new\n .catch()\n .throw()");

bt('{xxx;}()', '{\n xxx;\n}()');

bt("a = 'a'\nb = 'b'");
Expand Down
Loading

0 comments on commit 2ae6bb9

Please sign in to comment.