From 3a0d7989778b074c53c5c63a395113b356631cec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Lu=C4=8Div=C5=88=C3=A1k?= Date: Wed, 7 Oct 2020 12:19:49 +0200 Subject: [PATCH 01/12] fix issue #365. Fix by yWorks --- escodegen.js | 43 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/escodegen.js b/escodegen.js index 847fc370..5c5eb2fc 100644 --- a/escodegen.js +++ b/escodegen.js @@ -1490,9 +1490,23 @@ }, ThrowStatement: function (stmt, flags) { + var shouldParenthesize = false; + estraverse.traverse(stmt.argument, { + enter: function (node, parent) { + if (node.leadingComments && node.leadingComments.length) { + shouldParenthesize = true; + this.break(); + } + } + }); + var right = this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT) + if (shouldParenthesize) { + right = ['(', right, ')'] + } + return [join( - 'throw', - this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT) + 'throw', + right ), this.semicolon(flags)]; }, @@ -1747,10 +1761,27 @@ ReturnStatement: function (stmt, flags) { if (stmt.argument) { - return [join( - 'return', - this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT) - ), this.semicolon(flags)]; + var shouldParenthesize = false; + estraverse.traverse(stmt.argument, { + enter: function (node, parent) { + if (node.leadingComments && node.leadingComments.length) { + shouldParenthesize = true; + this.break(); + } + } + }); + var result = []; + if (shouldParenthesize) { + var that = this; + result.push('(', newline) + withIndent(function () { + result.push(addIndent(that.generateExpression(stmt.argument, Precedence.Sequence, E_TTT)), newline) + }); + result.push(addIndent(')')) + } else { + result.push(this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT)); + } + return [join('return', result), this.semicolon(flags)]; } return ['return' + this.semicolon(flags)]; }, From e93336eaca5e30de4e9ce8912eef50ea11efe591 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Lu=C4=8Div=C5=88=C3=A1k?= Date: Wed, 7 Oct 2020 15:25:05 +0200 Subject: [PATCH 02/12] add tests --- .../comment-in-return-parenthesis-statement.expected.js | 6 ++++++ test/comment/comment-in-return-parenthesis-statement.js | 7 +++++++ .../comment-in-throw-parenthesis-statement.expected.js | 6 ++++++ test/comment/comment-in-throw-parenthesis-statement.js | 7 +++++++ 4 files changed, 26 insertions(+) create mode 100644 test/comment/comment-in-return-parenthesis-statement.expected.js create mode 100644 test/comment/comment-in-return-parenthesis-statement.js create mode 100644 test/comment/comment-in-throw-parenthesis-statement.expected.js create mode 100644 test/comment/comment-in-throw-parenthesis-statement.js diff --git a/test/comment/comment-in-return-parenthesis-statement.expected.js b/test/comment/comment-in-return-parenthesis-statement.expected.js new file mode 100644 index 00000000..16757429 --- /dev/null +++ b/test/comment/comment-in-return-parenthesis-statement.expected.js @@ -0,0 +1,6 @@ +function foo(a, b, c) { + return ( + // comment + a >= b && a <= c || a === 42 || a === 666 + ); +} diff --git a/test/comment/comment-in-return-parenthesis-statement.js b/test/comment/comment-in-return-parenthesis-statement.js new file mode 100644 index 00000000..824e7510 --- /dev/null +++ b/test/comment/comment-in-return-parenthesis-statement.js @@ -0,0 +1,7 @@ +function foo(a, b, c) { + return ( + // comment + (a >= b && a <= c) + || a === 42 || a === 666 + ); +} \ No newline at end of file diff --git a/test/comment/comment-in-throw-parenthesis-statement.expected.js b/test/comment/comment-in-throw-parenthesis-statement.expected.js new file mode 100644 index 00000000..ed3aa70f --- /dev/null +++ b/test/comment/comment-in-throw-parenthesis-statement.expected.js @@ -0,0 +1,6 @@ +function foo(a, b, c) { + throw ( + // comment + a >= b && a <= c || a === 42 || a === 666 + ); +} diff --git a/test/comment/comment-in-throw-parenthesis-statement.js b/test/comment/comment-in-throw-parenthesis-statement.js new file mode 100644 index 00000000..5703b338 --- /dev/null +++ b/test/comment/comment-in-throw-parenthesis-statement.js @@ -0,0 +1,7 @@ +function foo(a, b, c) { + throw ( + // comment + (a >= b && a <= c) + || a === 42 || a === 666 + ); +} \ No newline at end of file From c1cda7d89a5349fb59f00ce8d4f29b4affab5c91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Lu=C4=8Div=C5=88=C3=A1k?= Date: Wed, 7 Oct 2020 16:15:17 +0200 Subject: [PATCH 03/12] improve the "throw" fix --- escodegen.js | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/escodegen.js b/escodegen.js index 5c5eb2fc..baea50f1 100644 --- a/escodegen.js +++ b/escodegen.js @@ -1499,15 +1499,18 @@ } } }); - var right = this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT) + var result = []; if (shouldParenthesize) { - right = ['(', right, ')'] + var that = this; + result.push('(', newline) + withIndent(function () { + result.push(addIndent(that.generateExpression(stmt.argument, Precedence.Sequence, E_TTT)), newline) + }); + result.push(addIndent(')')) + } else { + result.push(this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT)); } - - return [join( - 'throw', - right - ), this.semicolon(flags)]; + return [join('throw', result), this.semicolon(flags)]; }, TryStatement: function (stmt, flags) { From c1e8a4207765f1ca7a0d918888a059393f7ae37e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Lu=C4=8Div=C5=88=C3=A1k?= Date: Tue, 13 Oct 2020 10:21:40 +0200 Subject: [PATCH 04/12] add failing arrow function test --- ...ment-in-arrow-function-parenthesis-statement.expected.js | 6 ++++++ .../comment-in-arrow-function-parenthesis-statement.js | 6 ++++++ 2 files changed, 12 insertions(+) create mode 100644 test/comment/comment-in-arrow-function-parenthesis-statement.expected.js create mode 100644 test/comment/comment-in-arrow-function-parenthesis-statement.js diff --git a/test/comment/comment-in-arrow-function-parenthesis-statement.expected.js b/test/comment/comment-in-arrow-function-parenthesis-statement.expected.js new file mode 100644 index 00000000..044d5563 --- /dev/null +++ b/test/comment/comment-in-arrow-function-parenthesis-statement.expected.js @@ -0,0 +1,6 @@ +let arrowFn = () => ( + // comment + { + a: 1, b: 2 + } +); \ No newline at end of file diff --git a/test/comment/comment-in-arrow-function-parenthesis-statement.js b/test/comment/comment-in-arrow-function-parenthesis-statement.js new file mode 100644 index 00000000..044d5563 --- /dev/null +++ b/test/comment/comment-in-arrow-function-parenthesis-statement.js @@ -0,0 +1,6 @@ +let arrowFn = () => ( + // comment + { + a: 1, b: 2 + } +); \ No newline at end of file From fae05b394dd3db4d8b89485fa145c646cc4c8c60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Lu=C4=8Div=C5=88=C3=A1k?= Date: Tue, 13 Oct 2020 14:32:30 +0200 Subject: [PATCH 05/12] replace the tests with a single thorough test --- ...ment-in-parenthesis-expression.expected.js | 52 ++++++++++++++++++ ...first-element-in-parenthesis-expression.js | 54 +++++++++++++++++++ ...function-parenthesis-statement.expected.js | 6 --- ...in-arrow-function-parenthesis-statement.js | 6 --- ...n-return-parenthesis-statement.expected.js | 6 --- ...comment-in-return-parenthesis-statement.js | 7 --- ...in-throw-parenthesis-statement.expected.js | 6 --- .../comment-in-throw-parenthesis-statement.js | 7 --- 8 files changed, 106 insertions(+), 38 deletions(-) create mode 100644 test/comment/comment-as-first-element-in-parenthesis-expression.expected.js create mode 100644 test/comment/comment-as-first-element-in-parenthesis-expression.js delete mode 100644 test/comment/comment-in-arrow-function-parenthesis-statement.expected.js delete mode 100644 test/comment/comment-in-arrow-function-parenthesis-statement.js delete mode 100644 test/comment/comment-in-return-parenthesis-statement.expected.js delete mode 100644 test/comment/comment-in-return-parenthesis-statement.js delete mode 100644 test/comment/comment-in-throw-parenthesis-statement.expected.js delete mode 100644 test/comment/comment-in-throw-parenthesis-statement.js diff --git a/test/comment/comment-as-first-element-in-parenthesis-expression.expected.js b/test/comment/comment-as-first-element-in-parenthesis-expression.expected.js new file mode 100644 index 00000000..a23c59a4 --- /dev/null +++ b/test/comment/comment-as-first-element-in-parenthesis-expression.expected.js @@ -0,0 +1,52 @@ +let variable = ( + // comment + 3+3 +); + +function foo(a, b, c) { + return ( + // comment + a >= b && a <= c || a === 42 || a === 666 + ); +} + +function foo(a, b, c) { + throw ( + // comment + a >= b && a <= c || a === 42 || a === 666 + ); +} + +let arrowFn = () => ( + // comment + { + a: 1, b: 2 + } +); + +let variable = ( // comment + 3+3 +); + +let variable = ( /* comment */ + 3+3 +); + +let variable = ( /* comment + comment + comment + */ + 3+3 +); + +let variable = ( + // comment + /* comment */ + // comment + 3+3 +); + +let variable = /* comment */ ( + // comment + 3+3 +); \ No newline at end of file diff --git a/test/comment/comment-as-first-element-in-parenthesis-expression.js b/test/comment/comment-as-first-element-in-parenthesis-expression.js new file mode 100644 index 00000000..2da15762 --- /dev/null +++ b/test/comment/comment-as-first-element-in-parenthesis-expression.js @@ -0,0 +1,54 @@ +let variable = ( + // comment + 3+3 +); + +function foo(a, b, c) { + return ( + // comment + (a >= b && a <= c) + || a === 42 || a === 666 + ); +} + +function foo(a, b, c) { + throw ( + // comment + (a >= b && a <= c) + || a === 42 || a === 666 + ); +} + +let arrowFn = () => ( + // comment + { + a: 1, b: 2 + } +); + +let variable = ( // comment + 3+3 +); + +let variable = ( /* comment */ + 3+3 +); + +let variable = ( /* comment + comment + comment + */ + 3+3 +); + +let variable = ( + // comment + /* comment */ + // comment + 3+3 +); + +let variable = /* comment */ ( + // comment + 3+3 +); \ No newline at end of file diff --git a/test/comment/comment-in-arrow-function-parenthesis-statement.expected.js b/test/comment/comment-in-arrow-function-parenthesis-statement.expected.js deleted file mode 100644 index 044d5563..00000000 --- a/test/comment/comment-in-arrow-function-parenthesis-statement.expected.js +++ /dev/null @@ -1,6 +0,0 @@ -let arrowFn = () => ( - // comment - { - a: 1, b: 2 - } -); \ No newline at end of file diff --git a/test/comment/comment-in-arrow-function-parenthesis-statement.js b/test/comment/comment-in-arrow-function-parenthesis-statement.js deleted file mode 100644 index 044d5563..00000000 --- a/test/comment/comment-in-arrow-function-parenthesis-statement.js +++ /dev/null @@ -1,6 +0,0 @@ -let arrowFn = () => ( - // comment - { - a: 1, b: 2 - } -); \ No newline at end of file diff --git a/test/comment/comment-in-return-parenthesis-statement.expected.js b/test/comment/comment-in-return-parenthesis-statement.expected.js deleted file mode 100644 index 16757429..00000000 --- a/test/comment/comment-in-return-parenthesis-statement.expected.js +++ /dev/null @@ -1,6 +0,0 @@ -function foo(a, b, c) { - return ( - // comment - a >= b && a <= c || a === 42 || a === 666 - ); -} diff --git a/test/comment/comment-in-return-parenthesis-statement.js b/test/comment/comment-in-return-parenthesis-statement.js deleted file mode 100644 index 824e7510..00000000 --- a/test/comment/comment-in-return-parenthesis-statement.js +++ /dev/null @@ -1,7 +0,0 @@ -function foo(a, b, c) { - return ( - // comment - (a >= b && a <= c) - || a === 42 || a === 666 - ); -} \ No newline at end of file diff --git a/test/comment/comment-in-throw-parenthesis-statement.expected.js b/test/comment/comment-in-throw-parenthesis-statement.expected.js deleted file mode 100644 index ed3aa70f..00000000 --- a/test/comment/comment-in-throw-parenthesis-statement.expected.js +++ /dev/null @@ -1,6 +0,0 @@ -function foo(a, b, c) { - throw ( - // comment - a >= b && a <= c || a === 42 || a === 666 - ); -} diff --git a/test/comment/comment-in-throw-parenthesis-statement.js b/test/comment/comment-in-throw-parenthesis-statement.js deleted file mode 100644 index 5703b338..00000000 --- a/test/comment/comment-in-throw-parenthesis-statement.js +++ /dev/null @@ -1,7 +0,0 @@ -function foo(a, b, c) { - throw ( - // comment - (a >= b && a <= c) - || a === 42 || a === 666 - ); -} \ No newline at end of file From d0a7843338b31077e8f7285f78a897ec7ab7c180 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Lu=C4=8Div=C5=88=C3=A1k?= Date: Tue, 13 Oct 2020 15:19:52 +0200 Subject: [PATCH 06/12] add another test - ()expression inside of a return expression --- ...s-first-element-in-parenthesis-expression.expected.js | 7 +++++++ ...comment-as-first-element-in-parenthesis-expression.js | 9 +++++++++ 2 files changed, 16 insertions(+) diff --git a/test/comment/comment-as-first-element-in-parenthesis-expression.expected.js b/test/comment/comment-as-first-element-in-parenthesis-expression.expected.js index a23c59a4..89c4c540 100644 --- a/test/comment/comment-as-first-element-in-parenthesis-expression.expected.js +++ b/test/comment/comment-as-first-element-in-parenthesis-expression.expected.js @@ -10,6 +10,13 @@ function foo(a, b, c) { ); } +function foo(a, b, c) { + return ( + // comment + a >= b && a <= c || a === 42 || a === 666 + ); +} + function foo(a, b, c) { throw ( // comment diff --git a/test/comment/comment-as-first-element-in-parenthesis-expression.js b/test/comment/comment-as-first-element-in-parenthesis-expression.js index 2da15762..3c9cc197 100644 --- a/test/comment/comment-as-first-element-in-parenthesis-expression.js +++ b/test/comment/comment-as-first-element-in-parenthesis-expression.js @@ -11,6 +11,15 @@ function foo(a, b, c) { ); } +function foo(a, b, c) { + return ( + ( // comment + a >= b && + a <= c) + || a === 42 || a === 666 + ); +} + function foo(a, b, c) { throw ( // comment From 30a90f3356428539c3b840cc20d531872afc5adf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Lu=C4=8Div=C5=88=C3=A1k?= Date: Thu, 15 Oct 2020 21:57:42 +0200 Subject: [PATCH 07/12] more thought out fix; WIP --- escodegen.js | 117 ++++++++++-------- ...ment-in-parenthesis-expression.expected.js | 64 +++++----- ...first-element-in-parenthesis-expression.js | 54 ++++---- 3 files changed, 125 insertions(+), 110 deletions(-) diff --git a/escodegen.js b/escodegen.js index baea50f1..b8577810 100644 --- a/escodegen.js +++ b/escodegen.js @@ -229,6 +229,37 @@ return len && esutils.code.isLineTerminator(str.charCodeAt(len - 1)); } + function removeComments(str) { + // https://stackoverflow.com/a/59094308 + return str.replace(/\/\*[\s\S]*?\*\/|\/\/.*/g, ''); + } + + function removeTrailingWhiteSpaces(str) { + return str.replace(/\S(\s+)$/g, ''); + } + + function isParenthesized(str) { + str = removeComments(str); + str = removeTrailingWhiteSpaces(str); + var counter = 0; + for (var i = 0; i < str.length; ++i) { + if (str[i] == '(') { + counter++; + } + else if (str[i] == ')') { + if (counter == 0) { + return false; + } + counter--; + } + } + return counter == 0 && str[str.length-1] == ')'; + } + + function hasComment(str) { + return (/(\/\/|\/\*)/g).test(str); + } + function merge(target, override) { var key; for (key in override) { @@ -703,10 +734,10 @@ } else { comment = stmt.leadingComments[0]; result = []; - if (safeConcatenation && stmt.type === Syntax.Program && stmt.body.length === 0) { - result.push('\n'); - } - result.push(generateComment(comment)); + result.push('\n'); + withIndent(function() { + result.push(addIndent(generateComment(comment))); + }); if (!endsWithLineTerminator(toSourceNodeWhenNeeded(result).toString())) { result.push('\n'); } @@ -717,11 +748,15 @@ if (!endsWithLineTerminator(toSourceNodeWhenNeeded(fragment).toString())) { fragment.push('\n'); } - result.push(addIndent(fragment)); + withIndent(function() { + result.push(addIndent(fragment)); + }); } } - result.push(addIndent(save)); + withIndent(function () { + result.push(addIndent(save)); + }); } if (stmt.trailingComments) { @@ -1490,27 +1525,10 @@ }, ThrowStatement: function (stmt, flags) { - var shouldParenthesize = false; - estraverse.traverse(stmt.argument, { - enter: function (node, parent) { - if (node.leadingComments && node.leadingComments.length) { - shouldParenthesize = true; - this.break(); - } - } - }); - var result = []; - if (shouldParenthesize) { - var that = this; - result.push('(', newline) - withIndent(function () { - result.push(addIndent(that.generateExpression(stmt.argument, Precedence.Sequence, E_TTT)), newline) - }); - result.push(addIndent(')')) - } else { - result.push(this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT)); - } - return [join('throw', result), this.semicolon(flags)]; + return [join( + 'throw', + this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT) + ), this.semicolon(flags)]; }, TryStatement: function (stmt, flags) { @@ -1764,27 +1782,10 @@ ReturnStatement: function (stmt, flags) { if (stmt.argument) { - var shouldParenthesize = false; - estraverse.traverse(stmt.argument, { - enter: function (node, parent) { - if (node.leadingComments && node.leadingComments.length) { - shouldParenthesize = true; - this.break(); - } - } - }); - var result = []; - if (shouldParenthesize) { - var that = this; - result.push('(', newline) - withIndent(function () { - result.push(addIndent(that.generateExpression(stmt.argument, Precedence.Sequence, E_TTT)), newline) - }); - result.push(addIndent(')')) - } else { - result.push(this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT)); - } - return [join('return', result), this.semicolon(flags)]; + return [join( + 'return', + this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT) + ), this.semicolon(flags)]; } return ['return' + this.semicolon(flags)]; }, @@ -2531,8 +2532,26 @@ if (extra.comment) { - result = addComments(expr, result); + if (!expr.leadingComments) { + // TODO! + //addComments(expr, result); + } + else { + result = addComments(expr, result); + result = ['(', result, newline, ')']; + + /* this fix is now syntactically correct, but we must (try) to maintain the original formatting... */ + /* which was not really correctly implemented in my original PR ... */ + // notice that when the comment is removed, the formatting is correct... + } + } + + /* TODO: this should be only executed e.g. when returning to the ReturnStatement, ThrowStatement, ArrayFunction .... */ + var text = toSourceNodeWhenNeeded(result).toString(); + if (hasLineTerminator(text) && !isParenthesized(text)) { + result = ['(', result, ')']; } + return toSourceNodeWhenNeeded(result, expr); }; diff --git a/test/comment/comment-as-first-element-in-parenthesis-expression.expected.js b/test/comment/comment-as-first-element-in-parenthesis-expression.expected.js index 89c4c540..36f27689 100644 --- a/test/comment/comment-as-first-element-in-parenthesis-expression.expected.js +++ b/test/comment/comment-as-first-element-in-parenthesis-expression.expected.js @@ -1,59 +1,55 @@ let variable = ( // comment - 3+3 + 3 + 3 +); +let variable = ( + // comment + 3 + 3 +); +let variable = ( + /* comment */ + 3 + 3 +); +let variable = ( + /* comment + comment + comment + */ + 3 + 3 +); +let variable = ( + // comment + /* comment */ + // comment + 3 + 3 +); +let variable = ( + // comment + 3 + 3 ); - function foo(a, b, c) { return ( // comment a >= b && a <= c || a === 42 || a === 666 ); } - function foo(a, b, c) { return ( - // comment - a >= b && a <= c || a === 42 || a === 666 + ( + // comment + a >= b && a <= c + ) || a === 42 || a === 666 ); } - function foo(a, b, c) { throw ( // comment a >= b && a <= c || a === 42 || a === 666 ); } - let arrowFn = () => ( // comment { a: 1, b: 2 } ); - -let variable = ( // comment - 3+3 -); - -let variable = ( /* comment */ - 3+3 -); - -let variable = ( /* comment - comment - comment - */ - 3+3 -); - -let variable = ( - // comment - /* comment */ - // comment - 3+3 -); - -let variable = /* comment */ ( - // comment - 3+3 -); \ No newline at end of file diff --git a/test/comment/comment-as-first-element-in-parenthesis-expression.js b/test/comment/comment-as-first-element-in-parenthesis-expression.js index 3c9cc197..3e95458e 100644 --- a/test/comment/comment-as-first-element-in-parenthesis-expression.js +++ b/test/comment/comment-as-first-element-in-parenthesis-expression.js @@ -3,6 +3,33 @@ let variable = ( 3+3 ); +let variable = ( // comment + 3+3 +); + +let variable = ( /* comment */ + 3+3 +); + +let variable = ( /* comment + comment + comment + */ + 3+3 +); + +let variable = ( + // comment + /* comment */ + // comment + 3+3 +); + +let variable = /* comment */ ( + // comment + 3+3 +); + function foo(a, b, c) { return ( // comment @@ -34,30 +61,3 @@ let arrowFn = () => ( a: 1, b: 2 } ); - -let variable = ( // comment - 3+3 -); - -let variable = ( /* comment */ - 3+3 -); - -let variable = ( /* comment - comment - comment - */ - 3+3 -); - -let variable = ( - // comment - /* comment */ - // comment - 3+3 -); - -let variable = /* comment */ ( - // comment - 3+3 -); \ No newline at end of file From 680ea9788dae8232f2329186d6c3114eb69d734d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Lu=C4=8Div=C5=88=C3=A1k?= Date: Mon, 19 Oct 2020 20:28:08 +0200 Subject: [PATCH 08/12] proper fix --- escodegen.js | 127 +++++++++++------- gulpfile.js | 2 + test/comment.js | 2 + ...ment-in-parenthesis-expression.expected.js | 30 ++++- ...first-element-in-parenthesis-expression.js | 24 ++++ test/compare-harmony.js | 1 + 6 files changed, 134 insertions(+), 52 deletions(-) diff --git a/escodegen.js b/escodegen.js index b8577810..917466af 100644 --- a/escodegen.js +++ b/escodegen.js @@ -238,26 +238,49 @@ return str.replace(/\S(\s+)$/g, ''); } - function isParenthesized(str) { + function isParenthesized(str, leftPar, rightPar) { str = removeComments(str); str = removeTrailingWhiteSpaces(str); var counter = 0; for (var i = 0; i < str.length; ++i) { - if (str[i] == '(') { + if (str[i] == leftPar) { counter++; } - else if (str[i] == ')') { + else if (str[i] == rightPar) { if (counter == 0) { return false; } counter--; } } - return counter == 0 && str[str.length-1] == ')'; + return counter == 0 && str[str.length-1] == rightPar; } - function hasComment(str) { - return (/(\/\/|\/\*)/g).test(str); + function isParenthesizedByAnyBracketKind(str) { + return isParenthesized(str, '(', ')') || + isParenthesized(str, '{', '}') || + isParenthesized(str, '[', ']'); + } + + function shouldParenthesize(str, parentStmt) { + if (!hasLineTerminator(str)) { + return false; + } + if (parentStmt !== undefined && ( + parentStmt.type == Syntax.ObjectExpression || + parentStmt.type == Syntax.ArrayExpression || + parentStmt.type == Syntax.Property + )) { + return false; + } + if (!isParenthesizedByAnyBracketKind(str)) { + return true; + } + + str = removeComments(str); + var firstNewlineIdx = str.indexOf(newline); + var firstParenthesisIdx = str.match(/[\(\[\{)]/).index; + return firstNewlineIdx < firstParenthesisIdx; } function merge(target, override) { @@ -601,6 +624,18 @@ return [base, stmt]; } + function addMultiLineIndent(stmt) { + var str = base + flattenToString(stmt); + var split = str.split(/\n/g); + var suffix = ''; + // do not replace the last newline + if (split[split.length-1].length == 0) { + split = split.slice(0, split.length-1); + suffix = newline; + } + return split.join(newline + base) + suffix; + } + function withIndent(fn) { var previousBase; previousBase = base; @@ -690,14 +725,14 @@ return '/*' + comment.value + '*/'; } - function addComments(stmt, result) { + function addComments(stmt, result, parentStmt) { var i, len, comment, save, tailingToStatement, specialBase, fragment, extRange, range, prevRange, prefix, infix, suffix, count; if (stmt.leadingComments && stmt.leadingComments.length > 0) { save = result; - if (preserveBlankLines) { + if (preserveBlankLines) { // TODO? comment = stmt.leadingComments[0]; result = []; @@ -734,10 +769,12 @@ } else { comment = stmt.leadingComments[0]; result = []; - result.push('\n'); - withIndent(function() { - result.push(addIndent(generateComment(comment))); - }); + + if (safeConcatenation && stmt.type === Syntax.Program && stmt.body.length === 0) { + result.push('\n'); + } + result.push(generateComment(comment)); + if (!endsWithLineTerminator(toSourceNodeWhenNeeded(result).toString())) { result.push('\n'); } @@ -748,18 +785,33 @@ if (!endsWithLineTerminator(toSourceNodeWhenNeeded(fragment).toString())) { fragment.push('\n'); } - withIndent(function() { - result.push(addIndent(fragment)); - }); + result.push(addIndent(fragment)); } } - withIndent(function () { + if (!isExpression(stmt)) { result.push(addIndent(save)); - }); + } else { + var text = toSourceNodeWhenNeeded(result).toString(); + if (shouldParenthesize(text, parentStmt)) { + withIndent(function () { + result = addMultiLineIndent(result); + }); + + result = ['(', newline, result]; + + withIndent(function () { + result.push(addMultiLineIndent(save)); + }); + + result.push([newline, base, ')']); + } else { + result.push(addIndent(save)); + } + } } - if (stmt.trailingComments) { + if (stmt.trailingComments) { // TODO? if (preserveBlankLines) { comment = stmt.trailingComments[0]; @@ -1012,14 +1064,14 @@ return result; }; - CodeGenerator.prototype.generatePropertyKey = function (expr, computed) { + CodeGenerator.prototype.generatePropertyKey = function (expr, computed, parentStmt) { var result = []; if (computed) { result.push('['); } - result.push(this.generateExpression(expr, Precedence.Assignment, E_TTT)); + result.push(this.generateExpression(expr, Precedence.Assignment, E_TTT, parentStmt)); if (computed) { result.push(']'); @@ -2130,7 +2182,7 @@ } } else { result.push(multiline ? indent : ''); - result.push(that.generateExpression(expr.elements[i], Precedence.Assignment, E_TTT)); + result.push(that.generateExpression(expr.elements[i], Precedence.Assignment, E_TTT, expr)); } if (i + 1 < iz) { result.push(',' + (multiline ? newline : space)); @@ -2190,7 +2242,7 @@ if (expr.kind === 'get' || expr.kind === 'set') { return [ expr.kind, noEmptySpace(), - this.generatePropertyKey(expr.key, expr.computed), + this.generatePropertyKey(expr.key, expr.computed, expr), this.generateFunctionBody(expr.value) ]; } @@ -2199,19 +2251,19 @@ if (expr.value.type === "AssignmentPattern") { return this.AssignmentPattern(expr.value, Precedence.Sequence, E_TTT); } - return this.generatePropertyKey(expr.key, expr.computed); + return this.generatePropertyKey(expr.key, expr.computed, expr); } if (expr.method) { return [ generateMethodPrefix(expr), - this.generatePropertyKey(expr.key, expr.computed), + this.generatePropertyKey(expr.key, expr.computed, expr), this.generateFunctionBody(expr.value) ]; } return [ - this.generatePropertyKey(expr.key, expr.computed), + this.generatePropertyKey(expr.key, expr.computed, expr), ':' + space, this.generateExpression(expr.value, Precedence.Assignment, E_TTT) ]; @@ -2226,7 +2278,7 @@ multiline = expr.properties.length > 1; withIndent(function () { - fragment = that.generateExpression(expr.properties[0], Precedence.Sequence, E_TTT); + fragment = that.generateExpression(expr.properties[0], Precedence.Sequence, E_TTT, expr); }); if (!multiline) { @@ -2251,7 +2303,7 @@ result.push(',' + newline); for (i = 1, iz = expr.properties.length; i < iz; ++i) { result.push(indent); - result.push(that.generateExpression(expr.properties[i], Precedence.Sequence, E_TTT)); + result.push(that.generateExpression(expr.properties[i], Precedence.Sequence, E_TTT, expr)); if (i + 1 < iz) { result.push(',' + newline); } @@ -2519,7 +2571,7 @@ merge(CodeGenerator.prototype, CodeGenerator.Expression); - CodeGenerator.prototype.generateExpression = function (expr, precedence, flags) { + CodeGenerator.prototype.generateExpression = function (expr, precedence, flags, parentStmt) { var result, type; type = expr.type || Syntax.Property; @@ -2532,24 +2584,7 @@ if (extra.comment) { - if (!expr.leadingComments) { - // TODO! - //addComments(expr, result); - } - else { - result = addComments(expr, result); - result = ['(', result, newline, ')']; - - /* this fix is now syntactically correct, but we must (try) to maintain the original formatting... */ - /* which was not really correctly implemented in my original PR ... */ - // notice that when the comment is removed, the formatting is correct... - } - } - - /* TODO: this should be only executed e.g. when returning to the ReturnStatement, ThrowStatement, ArrayFunction .... */ - var text = toSourceNodeWhenNeeded(result).toString(); - if (hasLineTerminator(text) && !isParenthesized(text)) { - result = ['(', result, ')']; + result = addComments(expr, result, parentStmt); } return toSourceNodeWhenNeeded(result, expr); diff --git a/gulpfile.js b/gulpfile.js index 590e1274..c9ef2e04 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -28,6 +28,8 @@ var gulp = require('gulp'); var mocha = require('gulp-mocha'); var eslint = require('gulp-eslint'); +//var TEST = [ 'test/comment.js' ]; +//var TEST = [ 'test/compare.js' ]; var TEST = [ 'test/*.js' ]; var LINT = [ diff --git a/test/comment.js b/test/comment.js index 57806f39..42bcc36e 100644 --- a/test/comment.js +++ b/test/comment.js @@ -62,6 +62,8 @@ function test(code, expected) { describe('comment test', function () { fs.readdirSync(__dirname + '/comment').sort().forEach(function(file) { var code, expected, p; + //if (/comment-as-first-element-in-parenthesis-expression\.js$/.test(file) && !/comment-as-first-element-in-parenthesis-expression\.expected\.js$/.test(file)) { + //if (/^computed-property-comments-2\.js$/.test(file) && !/^computed-property-comments-2\.expected\.js$/.test(file)) { if (/\.js$/.test(file) && !/expected\.js$/.test(file)) { it(file, function () { p = file.replace(/\.js$/, '.expected.js'); diff --git a/test/comment/comment-as-first-element-in-parenthesis-expression.expected.js b/test/comment/comment-as-first-element-in-parenthesis-expression.expected.js index 36f27689..f1a36326 100644 --- a/test/comment/comment-as-first-element-in-parenthesis-expression.expected.js +++ b/test/comment/comment-as-first-element-in-parenthesis-expression.expected.js @@ -27,6 +27,13 @@ let variable = ( // comment 3 + 3 ); +let variable = ( + // one + 3 + 3 +) - ( + // two + (1 + 1) +); function foo(a, b, c) { return ( // comment @@ -35,11 +42,9 @@ function foo(a, b, c) { } function foo(a, b, c) { return ( - ( - // comment - a >= b && a <= c - ) || a === 42 || a === 666 - ); + // comment + a >= b && a <= c + ) || a === 42 || a === 666; } function foo(a, b, c) { throw ( @@ -50,6 +55,19 @@ function foo(a, b, c) { let arrowFn = () => ( // comment { - a: 1, b: 2 + a: 1, + b: 2 } ); +var test = [ + /** + * Test 2 + */ + a, + /* + * Test 1 + */ + 2, + // Test 3 + 3 + 3 +]; diff --git a/test/comment/comment-as-first-element-in-parenthesis-expression.js b/test/comment/comment-as-first-element-in-parenthesis-expression.js index 3e95458e..bea0dab4 100644 --- a/test/comment/comment-as-first-element-in-parenthesis-expression.js +++ b/test/comment/comment-as-first-element-in-parenthesis-expression.js @@ -30,6 +30,17 @@ let variable = /* comment */ ( 3+3 ); +let variable = ( + ( + // one + 3+3 + ) - + ( + // two + 1+1 + ) +); + function foo(a, b, c) { return ( // comment @@ -61,3 +72,16 @@ let arrowFn = () => ( a: 1, b: 2 } ); + +var test = [ + /** + * Test 2 + */ + a, + /* + * Test 1 + */ + 2, + // Test 3 + 3+3 +]; \ No newline at end of file diff --git a/test/compare-harmony.js b/test/compare-harmony.js index 3579da9a..ae314eb3 100644 --- a/test/compare-harmony.js +++ b/test/compare-harmony.js @@ -87,6 +87,7 @@ DIR = 'compare-harmony'; describe('compare harmony test', function () { fs.readdirSync(__dirname + '/' + DIR).sort().forEach(function(file) { var code, expected, exp, min; + //if (/templates-escape\.js$/.test(file) && !/templates-escape\.expected\.js$/.test(file) && !/templates-escape\.expected\.min\.js$/.test(file)) { if (/\.js$/.test(file) && !/expected\.js$/.test(file) && !/expected\.min\.js$/.test(file)) { it(file, function () { exp = file.replace(/\.js$/, '.expected.js'); From d40ca355e14a6f2946a6d951a98754629af65fa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Lu=C4=8Div=C5=88=C3=A1k?= Date: Mon, 19 Oct 2020 21:24:28 +0200 Subject: [PATCH 09/12] cleanup --- escodegen.js | 2 +- gulpfile.js | 2 -- test/comment.js | 2 -- .../comment-as-first-element-in-parenthesis-expression.js | 2 +- 4 files changed, 2 insertions(+), 6 deletions(-) diff --git a/escodegen.js b/escodegen.js index 917466af..00440538 100644 --- a/escodegen.js +++ b/escodegen.js @@ -811,7 +811,7 @@ } } - if (stmt.trailingComments) { // TODO? + if (stmt.trailingComments) { if (preserveBlankLines) { comment = stmt.trailingComments[0]; diff --git a/gulpfile.js b/gulpfile.js index c9ef2e04..590e1274 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -28,8 +28,6 @@ var gulp = require('gulp'); var mocha = require('gulp-mocha'); var eslint = require('gulp-eslint'); -//var TEST = [ 'test/comment.js' ]; -//var TEST = [ 'test/compare.js' ]; var TEST = [ 'test/*.js' ]; var LINT = [ diff --git a/test/comment.js b/test/comment.js index 42bcc36e..57806f39 100644 --- a/test/comment.js +++ b/test/comment.js @@ -62,8 +62,6 @@ function test(code, expected) { describe('comment test', function () { fs.readdirSync(__dirname + '/comment').sort().forEach(function(file) { var code, expected, p; - //if (/comment-as-first-element-in-parenthesis-expression\.js$/.test(file) && !/comment-as-first-element-in-parenthesis-expression\.expected\.js$/.test(file)) { - //if (/^computed-property-comments-2\.js$/.test(file) && !/^computed-property-comments-2\.expected\.js$/.test(file)) { if (/\.js$/.test(file) && !/expected\.js$/.test(file)) { it(file, function () { p = file.replace(/\.js$/, '.expected.js'); diff --git a/test/comment/comment-as-first-element-in-parenthesis-expression.js b/test/comment/comment-as-first-element-in-parenthesis-expression.js index bea0dab4..e87d0528 100644 --- a/test/comment/comment-as-first-element-in-parenthesis-expression.js +++ b/test/comment/comment-as-first-element-in-parenthesis-expression.js @@ -84,4 +84,4 @@ var test = [ 2, // Test 3 3+3 -]; \ No newline at end of file +]; From d9005c90e2d013d2c290b9760840e50b043be1cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Lu=C4=8Div=C5=88=C3=A1k?= Date: Mon, 19 Oct 2020 21:25:06 +0200 Subject: [PATCH 10/12] cleanup --- escodegen.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/escodegen.js b/escodegen.js index 00440538..044b1a8e 100644 --- a/escodegen.js +++ b/escodegen.js @@ -732,7 +732,7 @@ if (stmt.leadingComments && stmt.leadingComments.length > 0) { save = result; - if (preserveBlankLines) { // TODO? + if (preserveBlankLines) { comment = stmt.leadingComments[0]; result = []; From a5ed1fd33570fa404b415ce084bfa10a10381c45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Lu=C4=8Div=C5=88=C3=A1k?= Date: Mon, 19 Oct 2020 21:25:34 +0200 Subject: [PATCH 11/12] cleanup --- test/compare-harmony.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/compare-harmony.js b/test/compare-harmony.js index ae314eb3..3579da9a 100644 --- a/test/compare-harmony.js +++ b/test/compare-harmony.js @@ -87,7 +87,6 @@ DIR = 'compare-harmony'; describe('compare harmony test', function () { fs.readdirSync(__dirname + '/' + DIR).sort().forEach(function(file) { var code, expected, exp, min; - //if (/templates-escape\.js$/.test(file) && !/templates-escape\.expected\.js$/.test(file) && !/templates-escape\.expected\.min\.js$/.test(file)) { if (/\.js$/.test(file) && !/expected\.js$/.test(file) && !/expected\.min\.js$/.test(file)) { it(file, function () { exp = file.replace(/\.js$/, '.expected.js'); From 5f13bfd48db7fb61b781c9df394608d730847cc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Lu=C4=8Div=C5=88=C3=A1k?= Date: Mon, 19 Oct 2020 21:30:25 +0200 Subject: [PATCH 12/12] prettify --- escodegen.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/escodegen.js b/escodegen.js index 044b1a8e..eb06961f 100644 --- a/escodegen.js +++ b/escodegen.js @@ -262,14 +262,14 @@ isParenthesized(str, '[', ']'); } - function shouldParenthesize(str, parentStmt) { + function shouldParenthesize(str, parent) { if (!hasLineTerminator(str)) { return false; } - if (parentStmt !== undefined && ( - parentStmt.type == Syntax.ObjectExpression || - parentStmt.type == Syntax.ArrayExpression || - parentStmt.type == Syntax.Property + if (parent !== undefined && ( + parent.type == Syntax.ObjectExpression || + parent.type == Syntax.ArrayExpression || + parent.type == Syntax.Property )) { return false; } @@ -725,7 +725,7 @@ return '/*' + comment.value + '*/'; } - function addComments(stmt, result, parentStmt) { + function addComments(stmt, result, parent) { var i, len, comment, save, tailingToStatement, specialBase, fragment, extRange, range, prevRange, prefix, infix, suffix, count; @@ -793,7 +793,7 @@ result.push(addIndent(save)); } else { var text = toSourceNodeWhenNeeded(result).toString(); - if (shouldParenthesize(text, parentStmt)) { + if (shouldParenthesize(text, parent)) { withIndent(function () { result = addMultiLineIndent(result); }); @@ -1064,14 +1064,14 @@ return result; }; - CodeGenerator.prototype.generatePropertyKey = function (expr, computed, parentStmt) { + CodeGenerator.prototype.generatePropertyKey = function (expr, computed, parent) { var result = []; if (computed) { result.push('['); } - result.push(this.generateExpression(expr, Precedence.Assignment, E_TTT, parentStmt)); + result.push(this.generateExpression(expr, Precedence.Assignment, E_TTT, parent)); if (computed) { result.push(']'); @@ -2571,7 +2571,7 @@ merge(CodeGenerator.prototype, CodeGenerator.Expression); - CodeGenerator.prototype.generateExpression = function (expr, precedence, flags, parentStmt) { + CodeGenerator.prototype.generateExpression = function (expr, precedence, flags, parent) { var result, type; type = expr.type || Syntax.Property; @@ -2584,7 +2584,7 @@ if (extra.comment) { - result = addComments(expr, result, parentStmt); + result = addComments(expr, result, parent); } return toSourceNodeWhenNeeded(result, expr);