From 0d54237542de61a492a7e4e0e737e7a889781138 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 01/26] 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 d5a507da557516ee39229f09f9b3de45ab840467 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 02/26] improve the "throw" fix --- escodegen.js | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/escodegen.js b/escodegen.js index 847fc370..76fe431c 100644 --- a/escodegen.js +++ b/escodegen.js @@ -1490,10 +1490,27 @@ }, ThrowStatement: function (stmt, flags) { - return [join( - 'throw', - 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('throw', result), this.semicolon(flags)]; }, TryStatement: function (stmt, flags) { From 2cc7937bd69a28dfad4270d19e314ecd2533be0f 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 03/26] 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 3394a26d24c0eede0c9c7090e2b596d25c3c0a15 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 04/26] 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 a80ae883c9e62e5eeb533b7237dd6644c8db58c5 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 05/26] 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 a5790be102dd91a803dd64dada86ef3de624c346 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 06/26] more thought out fix; WIP --- escodegen.js | 92 +++++++++++++------ ...ment-in-parenthesis-expression.expected.js | 64 ++++++------- ...first-element-in-parenthesis-expression.js | 54 +++++------ 3 files changed, 121 insertions(+), 89 deletions(-) diff --git a/escodegen.js b/escodegen.js index 76fe431c..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) { @@ -2514,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 2a1ed4e0683411fe573bfe7468194f455b9d7398 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 07/26] 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 4fa78f0d5cabccbf3e64acb6c2d8e017dc751a8d 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 08/26] 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 6bb44bb2b7903dcb4d04cdeffb3e91a3dfee4aa8 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 09/26] 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 b44cff17033b0c1fa9ccfe6ec43483717e84720f 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 10/26] 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 6e566cfce6eb59210346e4e6b5c2cace127471a6 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 11/26] 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); From 0ff6beb27bdbdafe641664e4e4b7eb67d95920d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Lu=C4=8Div=C5=88=C3=A1k?= Date: Thu, 26 Nov 2020 17:13:53 +0100 Subject: [PATCH 12/26] fix problem with with default function parameters --- escodegen.js | 544 ++++++++++-------- test/comment.js | 2 +- test/comment/array-elements.expected.js | 12 + test/comment/array-elements.js | 12 + ...ment-in-parenthesis-expression.expected.js | 12 - ...first-element-in-parenthesis-expression.js | 13 - test/comment/method-description.expected.js | 15 + test/comment/method-description.js | 17 + .../try-block-line-comment.expected.js | 6 +- 9 files changed, 368 insertions(+), 265 deletions(-) create mode 100644 test/comment/array-elements.expected.js create mode 100644 test/comment/array-elements.js create mode 100644 test/comment/method-description.expected.js create mode 100644 test/comment/method-description.js diff --git a/escodegen.js b/escodegen.js index eb06961f..3cc99487 100644 --- a/escodegen.js +++ b/escodegen.js @@ -168,6 +168,12 @@ S_TFTF = F_ALLOW_IN | F_DIRECTIVE_CTX, S_TTFF = F_ALLOW_IN | F_FUNC_BODY; + + function PathToNode(currentNode, pathToCurrentNode) { + this.node = currentNode; + this.parent = pathToCurrentNode; + } + function getDefaultOptions() { // default options return { @@ -262,17 +268,26 @@ isParenthesized(str, '[', ']'); } - function shouldParenthesize(str, parent) { + function shouldParenthesize(str, stmt, path) { if (!hasLineTerminator(str)) { return false; } - if (parent !== undefined && ( - parent.type == Syntax.ObjectExpression || - parent.type == Syntax.ArrayExpression || - parent.type == Syntax.Property + if (path.parent !== null && ( + path.parent.node.type == Syntax.ObjectExpression || + path.parent.node.type == Syntax.ArrayExpression || + path.parent.node.type == Syntax.Property )) { return false; } + if (path.parent !== null && path.parent.parent !== null && + path.parent.parent.node.type == Syntax.MethodDefinition && + path.parent.node.type == Syntax.FunctionExpression && + path.node.type == Syntax.AssignmentPattern) { + return false; + } + if (stmt.type === Syntax.MethodDefinition) { + return false; + } if (!isParenthesizedByAnyBracketKind(str)) { return true; } @@ -725,7 +740,7 @@ return '/*' + comment.value + '*/'; } - function addComments(stmt, result, parent) { + function addComments(stmt, result, path) { var i, len, comment, save, tailingToStatement, specialBase, fragment, extRange, range, prevRange, prefix, infix, suffix, count; @@ -793,7 +808,7 @@ result.push(addIndent(save)); } else { var text = toSourceNodeWhenNeeded(result).toString(); - if (shouldParenthesize(text, parent)) { + if (shouldParenthesize(text, stmt, path)) { withIndent(function () { result = addMultiLineIndent(result); }); @@ -910,13 +925,18 @@ // Helpers. - CodeGenerator.prototype.maybeBlock = function(stmt, flags) { + // NOTE: adds `node` to the path, unless `updatePath` is set to `false` + CodeGenerator.prototype.maybeBlock = function(stmt, flags, path, updatePath) { + updatePath = (updatePath === undefined) ? true : updatePath; + if (updatePath) { + path = new PathToNode(stmt, path); + } var result, noLeadingComment, that = this; noLeadingComment = !extra.comment || !stmt.leadingComments; if (stmt.type === Syntax.BlockStatement && noLeadingComment) { - return [space, this.generateStatement(stmt, flags)]; + return [space, this.generateStatement(stmt, flags, path, false)]; } if (stmt.type === Syntax.EmptyStatement && noLeadingComment) { @@ -926,7 +946,7 @@ withIndent(function () { result = [ newline, - addIndent(that.generateStatement(stmt, flags)) + addIndent(that.generateStatement(stmt, flags, path, false)) ]; }); @@ -969,15 +989,25 @@ return prefix; } - CodeGenerator.prototype.generatePattern = function (node, precedence, flags) { + // NOTE: adds `node` to the path, unless `updatePath` is set to `false` + CodeGenerator.prototype.generatePattern = function (node, precedence, flags, path, updatePath) { + updatePath = (updatePath === undefined) ? true : updatePath; + if (updatePath) { + path = new PathToNode(node, path); + } if (node.type === Syntax.Identifier) { return generateIdentifier(node); } - return this.generateExpression(node, precedence, flags); + return this.generateExpression(node, precedence, flags, path, false); }; - CodeGenerator.prototype.generateFunctionParams = function (node) { + // NOTE: adds `node` to the path, unless `updatePath` is set to `false` + CodeGenerator.prototype.generateFunctionParams = function (node, path, updatePath) { + updatePath = (updatePath === undefined) ? true : updatePath; var i, iz, result, hasDefault; + if (updatePath) { + path = new PathToNode(node, path); + } hasDefault = false; @@ -993,11 +1023,12 @@ hasDefault = true; } for (i = 0, iz = node.params.length; i < iz; ++i) { + var childNode = node.params[i]; if (hasDefault && node.defaults[i]) { // Handle default values. - result.push(this.generateAssignment(node.params[i], node.defaults[i], '=', Precedence.Assignment, E_TTT)); + result.push(this.generateAssignment(childNode, node.defaults[i], '=', Precedence.Assignment, E_TTT, path)); } else { - result.push(this.generatePattern(node.params[i], Precedence.Assignment, E_TTT)); + result.push(this.generatePattern(childNode, Precedence.Assignment, E_TTT, path)); } if (i + 1 < iz) { result.push(',' + space); @@ -1018,60 +1049,78 @@ return result; }; - CodeGenerator.prototype.generateFunctionBody = function (node) { + // NOTE: adds `node` to `path`, unless `updatePath` is set to `false` + CodeGenerator.prototype.generateFunctionBody = function (node, path, updatePath) { + updatePath = (updatePath === undefined) ? true : updatePath; var result, expr; + if (updatePath) { + path = new PathToNode(node, path); + } - result = this.generateFunctionParams(node); + result = this.generateFunctionParams(node, path, false); if (node.type === Syntax.ArrowFunctionExpression) { result.push(space); result.push('=>'); } + var childNode = node.body; if (node.expression) { result.push(space); - expr = this.generateExpression(node.body, Precedence.Assignment, E_TTT); + expr = this.generateExpression(childNode, Precedence.Assignment, E_TTT, path); if (expr.toString().charAt(0) === '{') { expr = ['(', expr, ')']; } result.push(expr); } else { - result.push(this.maybeBlock(node.body, S_TTFF)); + result.push(this.maybeBlock(childNode, S_TTFF, path)); } return result; }; - CodeGenerator.prototype.generateIterationForStatement = function (operator, stmt, flags) { + // NOTE: adds `stmt` to `path`, unless `updatePath` is set to `false` + CodeGenerator.prototype.generateIterationForStatement = function (operator, stmt, flags, path, updatePath) { + updatePath = (updatePath === undefined) ? true : updatePath; var result = ['for' + (stmt.await ? noEmptySpace() + 'await' : '') + space + '('], that = this; + if (updatePath) { + path = new PathToNode(stmt, path); + } withIndent(function () { if (stmt.left.type === Syntax.VariableDeclaration) { withIndent(function () { result.push(stmt.left.kind + noEmptySpace()); - result.push(that.generateStatement(stmt.left.declarations[0], S_FFFF)); + var partialChild = stmt.left; + var partialChildPath = new PathToNode(partialChild, path); + result.push(that.generateStatement(partialChild.declarations[0], S_FFFF, partialChildPath)); }); } else { - result.push(that.generateExpression(stmt.left, Precedence.Call, E_TTT)); + result.push(that.generateExpression(stmt.left, Precedence.Call, E_TTT, path)); } result = join(result, operator); result = [join( result, - that.generateExpression(stmt.right, Precedence.Assignment, E_TTT) + that.generateExpression(stmt.right, Precedence.Assignment, E_TTT, path) ), ')']; }); - result.push(this.maybeBlock(stmt.body, flags)); + result.push(this.maybeBlock(stmt.body, flags, path)); return result; }; - CodeGenerator.prototype.generatePropertyKey = function (expr, computed, parent) { + // NOTE: adds `expr` to `path`, unless `updatePath` is set to `false` + CodeGenerator.prototype.generatePropertyKey = function (expr, computed, path, updatePath) { + updatePath = (updatePath === undefined) ? true : updatePath; var result = []; + if (updatePath) { + path = new PathToNode(expr, path); + } if (computed) { result.push('['); } - result.push(this.generateExpression(expr, Precedence.Assignment, E_TTT, parent)); + result.push(this.generateExpression(expr, Precedence.Assignment, E_TTT, path, false)); if (computed) { result.push(']'); @@ -1080,16 +1129,18 @@ return result; }; - CodeGenerator.prototype.generateAssignment = function (left, right, operator, precedence, flags) { + // NOTE: adds `left`, `right` to the path + CodeGenerator.prototype.generateAssignment = function (left, right, operator, precedence, flags, path) { + if (Precedence.Assignment < precedence) { flags |= F_ALLOW_IN; } return parenthesize( [ - this.generateExpression(left, Precedence.Call, flags), + this.generateExpression(left, Precedence.Call, flags, new PathToNode(left, path)), space + operator + space, - this.generateExpression(right, Precedence.Assignment, flags) + this.generateExpression(right, Precedence.Assignment, flags, new PathToNode(right, path)) ], Precedence.Assignment, precedence @@ -1107,7 +1158,7 @@ CodeGenerator.Statement = { - BlockStatement: function (stmt, flags) { + BlockStatement: function (stmt, flags, path) { var range, content, result = ['{', newline], that = this; withIndent(function () { @@ -1157,10 +1208,11 @@ bodyFlags |= F_SEMICOLON_OPT; } + var childNode = stmt.body[i]; if (stmt.body[i].leadingComments && preserveBlankLines) { - fragment = that.generateStatement(stmt.body[i], bodyFlags); + fragment = that.generateStatement(childNode, bodyFlags, path); } else { - fragment = addIndent(that.generateStatement(stmt.body[i], bodyFlags)); + fragment = addIndent(that.generateStatement(childNode, bodyFlags, path)); } result.push(fragment); @@ -1191,21 +1243,21 @@ return result; }, - BreakStatement: function (stmt, flags) { + BreakStatement: function (stmt, flags, path) { if (stmt.label) { return 'break ' + stmt.label.name + this.semicolon(flags); } return 'break' + this.semicolon(flags); }, - ContinueStatement: function (stmt, flags) { + ContinueStatement: function (stmt, flags, path) { if (stmt.label) { return 'continue ' + stmt.label.name + this.semicolon(flags); } return 'continue' + this.semicolon(flags); }, - ClassBody: function (stmt, flags) { + ClassBody: function (stmt, flags, path) { var result = [ '{', newline], that = this; withIndent(function (indent) { @@ -1213,7 +1265,7 @@ for (i = 0, iz = stmt.body.length; i < iz; ++i) { result.push(indent); - result.push(that.generateExpression(stmt.body[i], Precedence.Sequence, E_TTT)); + result.push(that.generateExpression(stmt.body[i], Precedence.Sequence, E_TTT, path)); if (i + 1 < iz) { result.push(newline); } @@ -1228,40 +1280,40 @@ return result; }, - ClassDeclaration: function (stmt, flags) { + ClassDeclaration: function (stmt, flags, path) { var result, fragment; result = ['class']; if (stmt.id) { - result = join(result, this.generateExpression(stmt.id, Precedence.Sequence, E_TTT)); + result = join(result, this.generateExpression(stmt.id, Precedence.Sequence, E_TTT, path)); } if (stmt.superClass) { - fragment = join('extends', this.generateExpression(stmt.superClass, Precedence.Unary, E_TTT)); + fragment = join('extends', this.generateExpression(stmt.superClass, Precedence.Unary, E_TTT, path)); result = join(result, fragment); } result.push(space); - result.push(this.generateStatement(stmt.body, S_TFFT)); + result.push(this.generateStatement(stmt.body, S_TFFT, path)); return result; }, - DirectiveStatement: function (stmt, flags) { + DirectiveStatement: function (stmt, flags, path) { if (extra.raw && stmt.raw) { return stmt.raw + this.semicolon(flags); } return escapeDirective(stmt.directive) + this.semicolon(flags); }, - DoWhileStatement: function (stmt, flags) { + DoWhileStatement: function (stmt, flags, path) { // Because `do 42 while (cond)` is Syntax Error. We need semicolon. - var result = join('do', this.maybeBlock(stmt.body, S_TFFF)); + var result = join('do', this.maybeBlock(stmt.body, S_TFFF, path)); result = this.maybeBlockSuffix(stmt.body, result); return join(result, [ 'while' + space + '(', - this.generateExpression(stmt.test, Precedence.Sequence, E_TTT), + this.generateExpression(stmt.test, Precedence.Sequence, E_TTT, path), ')' + this.semicolon(flags) ]); }, - CatchClause: function (stmt, flags) { + CatchClause: function (stmt, flags, path) { var result, that = this; withIndent(function () { var guard; @@ -1269,31 +1321,31 @@ if (stmt.param) { result = [ 'catch' + space + '(', - that.generateExpression(stmt.param, Precedence.Sequence, E_TTT), + that.generateExpression(stmt.param, Precedence.Sequence, E_TTT, path), ')' ]; if (stmt.guard) { - guard = that.generateExpression(stmt.guard, Precedence.Sequence, E_TTT); + guard = that.generateExpression(stmt.guard, Precedence.Sequence, E_TTT, path); result.splice(2, 0, ' if ', guard); } } else { result = ['catch']; } }); - result.push(this.maybeBlock(stmt.body, S_TFFF)); + result.push(this.maybeBlock(stmt.body, S_TFFF, path)); return result; }, - DebuggerStatement: function (stmt, flags) { + DebuggerStatement: function (stmt, flags, path) { return 'debugger' + this.semicolon(flags); }, - EmptyStatement: function (stmt, flags) { + EmptyStatement: function (stmt, flags, path) { return ';'; }, - ExportDefaultDeclaration: function (stmt, flags) { + ExportDefaultDeclaration: function (stmt, flags, path) { var result = [ 'export' ], bodyFlags; bodyFlags = (flags & F_SEMICOLON_OPT) ? S_TFFT : S_TFFF; @@ -1301,15 +1353,17 @@ // export default HoistableDeclaration[Default] // export default AssignmentExpression[In] ; result = join(result, 'default'); + var childNode = stmt.declaration; if (isStatement(stmt.declaration)) { - result = join(result, this.generateStatement(stmt.declaration, bodyFlags)); + result = join(result, this.generateStatement(childNode, bodyFlags, path)); } else { - result = join(result, this.generateExpression(stmt.declaration, Precedence.Assignment, E_TTT) + this.semicolon(flags)); + result = join(result, this.generateExpression(childNode, Precedence.Assignment, E_TTT, path) + + this.semicolon(flags)); } return result; }, - ExportNamedDeclaration: function (stmt, flags) { + ExportNamedDeclaration: function (stmt, flags, path) { var result = [ 'export' ], bodyFlags, that = this; bodyFlags = (flags & F_SEMICOLON_OPT) ? S_TFFT : S_TFFF; @@ -1317,7 +1371,7 @@ // export VariableStatement // export Declaration[Default] if (stmt.declaration) { - return join(result, this.generateStatement(stmt.declaration, bodyFlags)); + return join(result, this.generateStatement(stmt.declaration, bodyFlags, path)); } // export ExportClause[NoReference] FromClause ; @@ -1326,7 +1380,7 @@ if (stmt.specifiers.length === 0) { result = join(result, '{' + space + '}'); } else if (stmt.specifiers[0].type === Syntax.ExportBatchSpecifier) { - result = join(result, this.generateExpression(stmt.specifiers[0], Precedence.Sequence, E_TTT)); + result = join(result, this.generateExpression(stmt.specifiers[0], Precedence.Sequence, E_TTT, path)); } else { result = join(result, '{'); withIndent(function (indent) { @@ -1334,7 +1388,7 @@ result.push(newline); for (i = 0, iz = stmt.specifiers.length; i < iz; ++i) { result.push(indent); - result.push(that.generateExpression(stmt.specifiers[i], Precedence.Sequence, E_TTT)); + result.push(that.generateExpression(stmt.specifiers[i], Precedence.Sequence, E_TTT, path)); if (i + 1 < iz) { result.push(',' + newline); } @@ -1350,7 +1404,7 @@ result = join(result, [ 'from' + space, // ModuleSpecifier - this.generateExpression(stmt.source, Precedence.Sequence, E_TTT), + this.generateExpression(stmt.source, Precedence.Sequence, E_TTT, path), this.semicolon(flags) ]); } else { @@ -1360,19 +1414,19 @@ return result; }, - ExportAllDeclaration: function (stmt, flags) { + ExportAllDeclaration: function (stmt, flags, path) { // export * FromClause ; return [ 'export' + space, '*' + space, 'from' + space, // ModuleSpecifier - this.generateExpression(stmt.source, Precedence.Sequence, E_TTT), + this.generateExpression(stmt.source, Precedence.Sequence, E_TTT, path), this.semicolon(flags) ]; }, - ExpressionStatement: function (stmt, flags) { + ExpressionStatement: function (stmt, flags, path) { var result, fragment; function isClassPrefixed(fragment) { @@ -1416,7 +1470,7 @@ return code === 0x28 /* '(' */ || esutils.code.isWhiteSpace(code) || code === 0x2A /* '*' */ || esutils.code.isLineTerminator(code); } - result = [this.generateExpression(stmt.expression, Precedence.Sequence, E_TTT)]; + result = [this.generateExpression(stmt.expression, Precedence.Sequence, E_TTT, path)]; // 12.4 '{', 'function', 'class' is not allowed in this position. // wrap expression with parentheses fragment = toSourceNodeWhenNeeded(result).toString(); @@ -1432,7 +1486,7 @@ return result; }, - ImportDeclaration: function (stmt, flags) { + ImportDeclaration: function (stmt, flags, path) { // ES6: 15.2.1 valid import declarations: // - import ImportClause FromClause ; // - import ModuleSpecifier ; @@ -1447,7 +1501,7 @@ 'import', space, // ModuleSpecifier - this.generateExpression(stmt.source, Precedence.Sequence, E_TTT), + this.generateExpression(stmt.source, Precedence.Sequence, E_TTT, path), this.semicolon(flags) ]; } @@ -1461,7 +1515,7 @@ // ImportedBinding if (stmt.specifiers[cursor].type === Syntax.ImportDefaultSpecifier) { result = join(result, [ - this.generateExpression(stmt.specifiers[cursor], Precedence.Sequence, E_TTT) + this.generateExpression(stmt.specifiers[cursor], Precedence.Sequence, E_TTT, path) ]); ++cursor; } @@ -1475,7 +1529,7 @@ // NameSpaceImport result = join(result, [ space, - this.generateExpression(stmt.specifiers[cursor], Precedence.Sequence, E_TTT) + this.generateExpression(stmt.specifiers[cursor], Precedence.Sequence, E_TTT, path) ]); } else { // NamedImports @@ -1484,7 +1538,7 @@ if ((stmt.specifiers.length - cursor) === 1) { // import { ... } from "..."; result.push(space); - result.push(this.generateExpression(stmt.specifiers[cursor], Precedence.Sequence, E_TTT)); + result.push(this.generateExpression(stmt.specifiers[cursor], Precedence.Sequence, E_TTT, path)); result.push(space + '}' + space); } else { // import { @@ -1496,7 +1550,7 @@ result.push(newline); for (i = cursor, iz = stmt.specifiers.length; i < iz; ++i) { result.push(indent); - result.push(that.generateExpression(stmt.specifiers[i], Precedence.Sequence, E_TTT)); + result.push(that.generateExpression(stmt.specifiers[i], Precedence.Sequence, E_TTT, path)); if (i + 1 < iz) { result.push(',' + newline); } @@ -1513,27 +1567,27 @@ result = join(result, [ 'from' + space, // ModuleSpecifier - this.generateExpression(stmt.source, Precedence.Sequence, E_TTT), + this.generateExpression(stmt.source, Precedence.Sequence, E_TTT, path), this.semicolon(flags) ]); return result; }, - VariableDeclarator: function (stmt, flags) { + VariableDeclarator: function (stmt, flags, path) { var itemFlags = (flags & F_ALLOW_IN) ? E_TTT : E_FTT; if (stmt.init) { return [ - this.generateExpression(stmt.id, Precedence.Assignment, itemFlags), + this.generateExpression(stmt.id, Precedence.Assignment, itemFlags, path), space, '=', space, - this.generateExpression(stmt.init, Precedence.Assignment, itemFlags) + this.generateExpression(stmt.init, Precedence.Assignment, itemFlags, path) ]; } - return this.generatePattern(stmt.id, Precedence.Assignment, itemFlags); + return this.generatePattern(stmt.id, Precedence.Assignment, itemFlags, path); }, - VariableDeclaration: function (stmt, flags) { + VariableDeclaration: function (stmt, flags, path) { // VariableDeclarator is typed as Statement, // but joined with comma (not LineTerminator). // So if comment is attached to target node, we should specialize. @@ -1547,20 +1601,20 @@ node = stmt.declarations[0]; if (extra.comment && node.leadingComments) { result.push('\n'); - result.push(addIndent(that.generateStatement(node, bodyFlags))); + result.push(addIndent(that.generateStatement(node, bodyFlags, path, false))); } else { result.push(noEmptySpace()); - result.push(that.generateStatement(node, bodyFlags)); + result.push(that.generateStatement(node, bodyFlags, path, false)); } for (i = 1, iz = stmt.declarations.length; i < iz; ++i) { node = stmt.declarations[i]; if (extra.comment && node.leadingComments) { result.push(',' + newline); - result.push(addIndent(that.generateStatement(node, bodyFlags))); + result.push(addIndent(that.generateStatement(node, bodyFlags, path, false))); } else { result.push(',' + space); - result.push(that.generateStatement(node, bodyFlags)); + result.push(that.generateStatement(node, bodyFlags, path, false)); } } } @@ -1576,32 +1630,33 @@ return result; }, - ThrowStatement: function (stmt, flags) { + ThrowStatement: function (stmt, flags, path) { return [join( 'throw', - this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT) + this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT, path) ), this.semicolon(flags)]; }, - TryStatement: function (stmt, flags) { + TryStatement: function (stmt, flags, path) { var result, i, iz, guardedHandlers; - result = ['try', this.maybeBlock(stmt.block, S_TFFF)]; + result = ['try', this.maybeBlock(stmt.block, S_TFFF, path)]; result = this.maybeBlockSuffix(stmt.block, result); if (stmt.handlers) { // old interface for (i = 0, iz = stmt.handlers.length; i < iz; ++i) { - result = join(result, this.generateStatement(stmt.handlers[i], S_TFFF)); + var partialChild = stmt.handlers[i]; + result = join(result, this.generateStatement(partialChild, S_TFFF, path)); if (stmt.finalizer || i + 1 !== iz) { - result = this.maybeBlockSuffix(stmt.handlers[i].body, result); + result = this.maybeBlockSuffix(partialChild.body, result); } } } else { guardedHandlers = stmt.guardedHandlers || []; for (i = 0, iz = guardedHandlers.length; i < iz; ++i) { - result = join(result, this.generateStatement(guardedHandlers[i], S_TFFF)); + result = join(result, this.generateStatement(guardedHandlers[i], S_TFFF, path)); if (stmt.finalizer || i + 1 !== iz) { result = this.maybeBlockSuffix(guardedHandlers[i].body, result); } @@ -1611,13 +1666,13 @@ if (stmt.handler) { if (Array.isArray(stmt.handler)) { for (i = 0, iz = stmt.handler.length; i < iz; ++i) { - result = join(result, this.generateStatement(stmt.handler[i], S_TFFF)); + result = join(result, this.generateStatement(stmt.handler[i], S_TFFF, path)); if (stmt.finalizer || i + 1 !== iz) { result = this.maybeBlockSuffix(stmt.handler[i].body, result); } } } else { - result = join(result, this.generateStatement(stmt.handler, S_TFFF)); + result = join(result, this.generateStatement(stmt.handler, S_TFFF, path)); if (stmt.finalizer) { result = this.maybeBlockSuffix(stmt.handler.body, result); } @@ -1625,17 +1680,17 @@ } } if (stmt.finalizer) { - result = join(result, ['finally', this.maybeBlock(stmt.finalizer, S_TFFF)]); + result = join(result, ['finally', this.maybeBlock(stmt.finalizer, S_TFFF, path)]); } return result; }, - SwitchStatement: function (stmt, flags) { + SwitchStatement: function (stmt, flags, path) { var result, fragment, i, iz, bodyFlags, that = this; withIndent(function () { result = [ 'switch' + space + '(', - that.generateExpression(stmt.discriminant, Precedence.Sequence, E_TTT), + that.generateExpression(stmt.discriminant, Precedence.Sequence, E_TTT, path), ')' + space + '{' + newline ]; }); @@ -1645,7 +1700,7 @@ if (i === iz - 1) { bodyFlags |= F_SEMICOLON_OPT; } - fragment = addIndent(this.generateStatement(stmt.cases[i], bodyFlags)); + fragment = addIndent(this.generateStatement(stmt.cases[i], bodyFlags, path)); result.push(fragment); if (!endsWithLineTerminator(toSourceNodeWhenNeeded(fragment).toString())) { result.push(newline); @@ -1656,12 +1711,12 @@ return result; }, - SwitchCase: function (stmt, flags) { + SwitchCase: function (stmt, flags, path) { var result, fragment, i, iz, bodyFlags, that = this; withIndent(function () { if (stmt.test) { result = [ - join('case', that.generateExpression(stmt.test, Precedence.Sequence, E_TTT)), + join('case', that.generateExpression(stmt.test, Precedence.Sequence, E_TTT, path)), ':' ]; } else { @@ -1671,7 +1726,7 @@ i = 0; iz = stmt.consequent.length; if (iz && stmt.consequent[0].type === Syntax.BlockStatement) { - fragment = that.maybeBlock(stmt.consequent[0], S_TFFF); + fragment = that.maybeBlock(stmt.consequent[0], S_TFFF, path); result.push(fragment); i = 1; } @@ -1685,7 +1740,7 @@ if (i === iz - 1 && flags & F_SEMICOLON_OPT) { bodyFlags |= F_SEMICOLON_OPT; } - fragment = addIndent(that.generateStatement(stmt.consequent[i], bodyFlags)); + fragment = addIndent(that.generateStatement(stmt.consequent[i], bodyFlags, path)); result.push(fragment); if (i + 1 !== iz && !endsWithLineTerminator(toSourceNodeWhenNeeded(fragment).toString())) { result.push(newline); @@ -1695,12 +1750,12 @@ return result; }, - IfStatement: function (stmt, flags) { + IfStatement: function (stmt, flags, path) { var result, bodyFlags, semicolonOptional, that = this; withIndent(function () { result = [ 'if' + space + '(', - that.generateExpression(stmt.test, Precedence.Sequence, E_TTT), + that.generateExpression(stmt.test, Precedence.Sequence, E_TTT, path), ')' ]; }); @@ -1710,29 +1765,29 @@ bodyFlags |= F_SEMICOLON_OPT; } if (stmt.alternate) { - result.push(this.maybeBlock(stmt.consequent, S_TFFF)); - result = this.maybeBlockSuffix(stmt.consequent, result); + result.push(this.maybeBlock(stmt.consequent, S_TFFF, path)); + result = this.maybeBlockSuffix(stmt.consequent, result, path); if (stmt.alternate.type === Syntax.IfStatement) { - result = join(result, ['else ', this.generateStatement(stmt.alternate, bodyFlags)]); + result = join(result, ['else ', this.generateStatement(stmt.alternate, bodyFlags, path)]); } else { - result = join(result, join('else', this.maybeBlock(stmt.alternate, bodyFlags))); + result = join(result, join('else', this.maybeBlock(stmt.alternate, bodyFlags, path))); } } else { - result.push(this.maybeBlock(stmt.consequent, bodyFlags)); + result.push(this.maybeBlock(stmt.consequent, bodyFlags, path)); } return result; }, - ForStatement: function (stmt, flags) { + ForStatement: function (stmt, flags, path) { var result, that = this; withIndent(function () { result = ['for' + space + '(']; if (stmt.init) { if (stmt.init.type === Syntax.VariableDeclaration) { - result.push(that.generateStatement(stmt.init, S_FFFF)); + result.push(that.generateStatement(stmt.init, S_FFFF, path)); } else { // F_ALLOW_IN becomes false. - result.push(that.generateExpression(stmt.init, Precedence.Sequence, E_FTT)); + result.push(that.generateExpression(stmt.init, Precedence.Sequence, E_FTT, path)); result.push(';'); } } else { @@ -1741,7 +1796,7 @@ if (stmt.test) { result.push(space); - result.push(that.generateExpression(stmt.test, Precedence.Sequence, E_TTT)); + result.push(that.generateExpression(stmt.test, Precedence.Sequence, E_TTT, path)); result.push(';'); } else { result.push(';'); @@ -1749,30 +1804,30 @@ if (stmt.update) { result.push(space); - result.push(that.generateExpression(stmt.update, Precedence.Sequence, E_TTT)); + result.push(that.generateExpression(stmt.update, Precedence.Sequence, E_TTT, path)); result.push(')'); } else { result.push(')'); } }); - result.push(this.maybeBlock(stmt.body, flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF)); + result.push(this.maybeBlock(stmt.body, flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF, path)); return result; }, - ForInStatement: function (stmt, flags) { - return this.generateIterationForStatement('in', stmt, flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF); + ForInStatement: function (stmt, flags, path) { + return this.generateIterationForStatement('in', stmt, flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF, path); }, - ForOfStatement: function (stmt, flags) { - return this.generateIterationForStatement('of', stmt, flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF); + ForOfStatement: function (stmt, flags, path) { + return this.generateIterationForStatement('of', stmt, flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF, path); }, - LabeledStatement: function (stmt, flags) { - return [stmt.label.name + ':', this.maybeBlock(stmt.body, flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF)]; + LabeledStatement: function (stmt, flags, path) { + return [stmt.label.name + ':', this.maybeBlock(stmt.body, flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF, path)]; }, - Program: function (stmt, flags) { + Program: function (stmt, flags, path) { var result, fragment, i, iz, bodyFlags; iz = stmt.body.length; result = [safeConcatenation && iz > 0 ? '\n' : '']; @@ -1798,7 +1853,7 @@ } } - fragment = addIndent(this.generateStatement(stmt.body[i], bodyFlags)); + fragment = addIndent(this.generateStatement(stmt.body[i], bodyFlags, path)); result.push(fragment); if (i + 1 < iz && !endsWithLineTerminator(toSourceNodeWhenNeeded(fragment).toString())) { if (preserveBlankLines) { @@ -1822,49 +1877,49 @@ return result; }, - FunctionDeclaration: function (stmt, flags) { + FunctionDeclaration: function (stmt, flags, path) { return [ generateAsyncPrefix(stmt, true), 'function', generateStarSuffix(stmt) || noEmptySpace(), stmt.id ? generateIdentifier(stmt.id) : '', - this.generateFunctionBody(stmt) + this.generateFunctionBody(stmt, path, false) ]; }, - ReturnStatement: function (stmt, flags) { + ReturnStatement: function (stmt, flags, path) { if (stmt.argument) { return [join( 'return', - this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT) + this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT, path) ), this.semicolon(flags)]; } return ['return' + this.semicolon(flags)]; }, - WhileStatement: function (stmt, flags) { + WhileStatement: function (stmt, flags, path) { var result, that = this; withIndent(function () { result = [ 'while' + space + '(', - that.generateExpression(stmt.test, Precedence.Sequence, E_TTT), + that.generateExpression(stmt.test, Precedence.Sequence, E_TTT, path), ')' ]; }); - result.push(this.maybeBlock(stmt.body, flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF)); + result.push(this.maybeBlock(stmt.body, flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF, path)); return result; }, - WithStatement: function (stmt, flags) { + WithStatement: function (stmt, flags, path) { var result, that = this; withIndent(function () { result = [ 'with' + space + '(', - that.generateExpression(stmt.object, Precedence.Sequence, E_TTT), + that.generateExpression(stmt.object, Precedence.Sequence, E_TTT, path), ')' ]; }); - result.push(this.maybeBlock(stmt.body, flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF)); + result.push(this.maybeBlock(stmt.body, flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF, path)); return result; } @@ -1876,14 +1931,14 @@ CodeGenerator.Expression = { - SequenceExpression: function (expr, precedence, flags) { + SequenceExpression: function (expr, precedence, flags, path) { var result, i, iz; if (Precedence.Sequence < precedence) { flags |= F_ALLOW_IN; } result = []; for (i = 0, iz = expr.expressions.length; i < iz; ++i) { - result.push(this.generateExpression(expr.expressions[i], Precedence.Assignment, flags)); + result.push(this.generateExpression(expr.expressions[i], Precedence.Assignment, flags, path)); if (i + 1 < iz) { result.push(',' + space); } @@ -1891,36 +1946,36 @@ return parenthesize(result, Precedence.Sequence, precedence); }, - AssignmentExpression: function (expr, precedence, flags) { - return this.generateAssignment(expr.left, expr.right, expr.operator, precedence, flags); + AssignmentExpression: function (expr, precedence, flags, path) { + return this.generateAssignment(expr.left, expr.right, expr.operator, precedence, flags, path); }, - ArrowFunctionExpression: function (expr, precedence, flags) { - return parenthesize(this.generateFunctionBody(expr), Precedence.ArrowFunction, precedence); + ArrowFunctionExpression: function (expr, precedence, flags, path) { + return parenthesize(this.generateFunctionBody(expr, path, false), Precedence.ArrowFunction, precedence); }, - ConditionalExpression: function (expr, precedence, flags) { + ConditionalExpression: function (expr, precedence, flags, path) { if (Precedence.Conditional < precedence) { flags |= F_ALLOW_IN; } return parenthesize( [ - this.generateExpression(expr.test, Precedence.LogicalOR, flags), + this.generateExpression(expr.test, Precedence.LogicalOR, flags, path), space + '?' + space, - this.generateExpression(expr.consequent, Precedence.Assignment, flags), + this.generateExpression(expr.consequent, Precedence.Assignment, flags, path), space + ':' + space, - this.generateExpression(expr.alternate, Precedence.Assignment, flags) + this.generateExpression(expr.alternate, Precedence.Assignment, flags, path) ], Precedence.Conditional, precedence ); }, - LogicalExpression: function (expr, precedence, flags) { - return this.BinaryExpression(expr, precedence, flags); + LogicalExpression: function (expr, precedence, flags, path) { + return this.BinaryExpression(expr, precedence, flags, path); }, - BinaryExpression: function (expr, precedence, flags) { + BinaryExpression: function (expr, precedence, flags, path) { var result, leftPrecedence, rightPrecedence, currentPrecedence, fragment, leftSource; currentPrecedence = BinaryPrecedence[expr.operator]; leftPrecedence = expr.operator === '**' ? Precedence.Postfix : currentPrecedence; @@ -1930,7 +1985,7 @@ flags |= F_ALLOW_IN; } - fragment = this.generateExpression(expr.left, leftPrecedence, flags); + fragment = this.generateExpression(expr.left, leftPrecedence, flags, path); leftSource = fragment.toString(); @@ -1940,7 +1995,7 @@ result = join(fragment, expr.operator); } - fragment = this.generateExpression(expr.right, rightPrecedence, flags); + fragment = this.generateExpression(expr.right, rightPrecedence, flags, path); if (expr.operator === '/' && fragment.toString().charAt(0) === '/' || expr.operator.slice(-1) === '<' && fragment.toString().slice(0, 3) === '!--') { @@ -1957,11 +2012,11 @@ return parenthesize(result, currentPrecedence, precedence); }, - CallExpression: function (expr, precedence, flags) { + CallExpression: function (expr, precedence, flags, path) { var result, i, iz; // F_ALLOW_UNPARATH_NEW becomes false. - result = [this.generateExpression(expr.callee, Precedence.Call, E_TTF)]; + result = [this.generateExpression(expr.callee, Precedence.Call, E_TTF, path)]; if (expr.optional) { result.push('?.'); @@ -1969,7 +2024,7 @@ result.push('('); for (i = 0, iz = expr['arguments'].length; i < iz; ++i) { - result.push(this.generateExpression(expr['arguments'][i], Precedence.Assignment, E_TTT)); + result.push(this.generateExpression(expr['arguments'][i], Precedence.Assignment, E_TTT, path)); if (i + 1 < iz) { result.push(',' + space); } @@ -1983,17 +2038,17 @@ return parenthesize(result, Precedence.Call, precedence); }, - ChainExpression: function (expr, precedence, flags) { + ChainExpression: function (expr, precedence, flags, path) { if (Precedence.OptionalChaining < precedence) { flags |= F_ALLOW_CALL; } - var result = this.generateExpression(expr.expression, Precedence.OptionalChaining, flags); + var result = this.generateExpression(expr.expression, Precedence.OptionalChaining, flags, path); return parenthesize(result, Precedence.OptionalChaining, precedence); }, - NewExpression: function (expr, precedence, flags) { + NewExpression: function (expr, precedence, flags, path) { var result, length, i, iz, itemFlags; length = expr['arguments'].length; @@ -2003,13 +2058,13 @@ result = join( 'new', - this.generateExpression(expr.callee, Precedence.New, itemFlags) + this.generateExpression(expr.callee, Precedence.New, itemFlags, path) ); if (!(flags & F_ALLOW_UNPARATH_NEW) || parentheses || length > 0) { result.push('('); for (i = 0, iz = length; i < iz; ++i) { - result.push(this.generateExpression(expr['arguments'][i], Precedence.Assignment, E_TTT)); + result.push(this.generateExpression(expr['arguments'][i], Precedence.Assignment, E_TTT, path)); if (i + 1 < iz) { result.push(',' + space); } @@ -2020,11 +2075,11 @@ return parenthesize(result, Precedence.New, precedence); }, - MemberExpression: function (expr, precedence, flags) { + MemberExpression: function (expr, precedence, flags, path) { var result, fragment; // F_ALLOW_UNPARATH_NEW becomes false. - result = [this.generateExpression(expr.object, Precedence.Call, (flags & F_ALLOW_CALL) ? E_TTF : E_TFF)]; + result = [this.generateExpression(expr.object, Precedence.Call, (flags & F_ALLOW_CALL) ? E_TTF : E_TFF, path)]; if (expr.computed) { if (expr.optional) { @@ -2032,7 +2087,7 @@ } result.push('['); - result.push(this.generateExpression(expr.property, Precedence.Sequence, flags & F_ALLOW_CALL ? E_TTT : E_TFT)); + result.push(this.generateExpression(expr.property, Precedence.Sequence, flags & F_ALLOW_CALL ? E_TTT : E_TFT, path)); result.push(']'); } else { if (!expr.optional && expr.object.type === Syntax.Literal && typeof expr.object.value === 'number') { @@ -2059,7 +2114,7 @@ return parenthesize(result, Precedence.Member, precedence); }, - MetaProperty: function (expr, precedence, flags) { + MetaProperty: function (expr, precedence, flags, path) { var result; result = []; result.push(typeof expr.meta === "string" ? expr.meta : generateIdentifier(expr.meta)); @@ -2068,9 +2123,9 @@ return parenthesize(result, Precedence.Member, precedence); }, - UnaryExpression: function (expr, precedence, flags) { + UnaryExpression: function (expr, precedence, flags, path) { var result, fragment, rightCharCode, leftSource, leftCharCode; - fragment = this.generateExpression(expr.argument, Precedence.Unary, E_TTT); + fragment = this.generateExpression(expr.argument, Precedence.Unary, E_TTT, path); if (space === '') { result = join(expr.operator, fragment); @@ -2099,7 +2154,7 @@ return parenthesize(result, Precedence.Unary, precedence); }, - YieldExpression: function (expr, precedence, flags) { + YieldExpression: function (expr, precedence, flags, path) { var result; if (expr.delegate) { result = 'yield*'; @@ -2109,26 +2164,26 @@ if (expr.argument) { result = join( result, - this.generateExpression(expr.argument, Precedence.Yield, E_TTT) + this.generateExpression(expr.argument, Precedence.Yield, E_TTT, path) ); } return parenthesize(result, Precedence.Yield, precedence); }, - AwaitExpression: function (expr, precedence, flags) { + AwaitExpression: function (expr, precedence, flag, path) { var result = join( expr.all ? 'await*' : 'await', - this.generateExpression(expr.argument, Precedence.Await, E_TTT) + this.generateExpression(expr.argument, Precedence.Await, E_TTT, path) ); return parenthesize(result, Precedence.Await, precedence); }, - UpdateExpression: function (expr, precedence, flags) { + UpdateExpression: function (expr, precedence, flags, path) { if (expr.prefix) { return parenthesize( [ expr.operator, - this.generateExpression(expr.argument, Precedence.Unary, E_TTT) + this.generateExpression(expr.argument, Precedence.Unary, E_TTT, path) ], Precedence.Unary, precedence @@ -2136,7 +2191,7 @@ } return parenthesize( [ - this.generateExpression(expr.argument, Precedence.Postfix, E_TTT), + this.generateExpression(expr.argument, Precedence.Postfix, E_TTT, path), expr.operator ], Precedence.Postfix, @@ -2144,7 +2199,7 @@ ); }, - FunctionExpression: function (expr, precedence, flags) { + FunctionExpression: function (expr, precedence, flags, path) { var result = [ generateAsyncPrefix(expr, true), 'function' @@ -2155,15 +2210,15 @@ } else { result.push(generateStarSuffix(expr) || space); } - result.push(this.generateFunctionBody(expr)); + result.push(this.generateFunctionBody(expr, path, false)); return result; }, - ArrayPattern: function (expr, precedence, flags) { - return this.ArrayExpression(expr, precedence, flags, true); + ArrayPattern: function (expr, precedence, flags, path) { + return this.ArrayExpression(expr, precedence, flags, path, true); }, - ArrayExpression: function (expr, precedence, flags, isPattern) { + ArrayExpression: function (expr, precedence, flags, path, isPattern) { var result, multiline, that = this; if (!expr.elements.length) { return '[]'; @@ -2182,7 +2237,7 @@ } } else { result.push(multiline ? indent : ''); - result.push(that.generateExpression(expr.elements[i], Precedence.Assignment, E_TTT, expr)); + result.push(that.generateExpression(expr.elements[i], Precedence.Assignment, E_TTT, path)); } if (i + 1 < iz) { result.push(',' + (multiline ? newline : space)); @@ -2197,26 +2252,26 @@ return result; }, - RestElement: function(expr, precedence, flags) { - return '...' + this.generatePattern(expr.argument); + RestElement: function(expr, precedence, flags, path) { + return '...' + this.generatePattern(expr.argument, undefined, undefined, path); }, - ClassExpression: function (expr, precedence, flags) { + ClassExpression: function (expr, precedence, flags, path) { var result, fragment; result = ['class']; if (expr.id) { - result = join(result, this.generateExpression(expr.id, Precedence.Sequence, E_TTT)); + result = join(result, this.generateExpression(expr.id, Precedence.Sequence, E_TTT, path)); } if (expr.superClass) { - fragment = join('extends', this.generateExpression(expr.superClass, Precedence.Unary, E_TTT)); + fragment = join('extends', this.generateExpression(expr.superClass, Precedence.Unary, E_TTT, path)); result = join(result, fragment); } result.push(space); - result.push(this.generateStatement(expr.body, S_TFFT)); + result.push(this.generateStatement(expr.body, S_TFFT, path)); return result; }, - MethodDefinition: function (expr, precedence, flags) { + MethodDefinition: function (expr, precedence, flags, path) { var result, fragment; if (expr['static']) { result = ['static' + space]; @@ -2225,51 +2280,52 @@ } if (expr.kind === 'get' || expr.kind === 'set') { fragment = [ - join(expr.kind, this.generatePropertyKey(expr.key, expr.computed)), - this.generateFunctionBody(expr.value) + join(expr.kind, this.generatePropertyKey(expr.key, expr.computed, path)), + this.generateFunctionBody(expr.value, path, path) ]; } else { fragment = [ generateMethodPrefix(expr), - this.generatePropertyKey(expr.key, expr.computed), - this.generateFunctionBody(expr.value) + this.generatePropertyKey(expr.key, expr.computed, path), + this.generateFunctionBody(expr.value, path) ]; } return join(result, fragment); }, - Property: function (expr, precedence, flags) { + Property: function (expr, precedence, flags, path) { if (expr.kind === 'get' || expr.kind === 'set') { return [ expr.kind, noEmptySpace(), - this.generatePropertyKey(expr.key, expr.computed, expr), - this.generateFunctionBody(expr.value) + this.generatePropertyKey(expr.key, expr.computed, path), + this.generateFunctionBody(expr.value, path) ]; } if (expr.shorthand) { if (expr.value.type === "AssignmentPattern") { - return this.AssignmentPattern(expr.value, Precedence.Sequence, E_TTT); + var childNode = expr.value; + return this.AssignmentPattern(childNode, Precedence.Sequence, E_TTT, new PathToNode(childNode, path)); } - return this.generatePropertyKey(expr.key, expr.computed, expr); + return this.generatePropertyKey(expr.key, expr.computed, path); } if (expr.method) { return [ generateMethodPrefix(expr), - this.generatePropertyKey(expr.key, expr.computed, expr), - this.generateFunctionBody(expr.value) + this.generatePropertyKey(expr.key, expr.computed, path), + this.generateFunctionBody(expr.value, path) ]; } return [ - this.generatePropertyKey(expr.key, expr.computed, expr), + this.generatePropertyKey(expr.key, expr.computed, path), ':' + space, - this.generateExpression(expr.value, Precedence.Assignment, E_TTT) + this.generateExpression(expr.value, Precedence.Assignment, E_TTT, path) ]; }, - ObjectExpression: function (expr, precedence, flags) { + ObjectExpression: function (expr, precedence, flags, path) { var multiline, result, fragment, that = this; if (!expr.properties.length) { @@ -2278,7 +2334,7 @@ multiline = expr.properties.length > 1; withIndent(function () { - fragment = that.generateExpression(expr.properties[0], Precedence.Sequence, E_TTT, expr); + fragment = that.generateExpression(expr.properties[0], Precedence.Sequence, E_TTT, path); }); if (!multiline) { @@ -2303,7 +2359,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, expr)); + result.push(that.generateExpression(expr.properties[i], Precedence.Sequence, E_TTT, path)); if (i + 1 < iz) { result.push(',' + newline); } @@ -2319,11 +2375,11 @@ return result; }, - AssignmentPattern: function(expr, precedence, flags) { - return this.generateAssignment(expr.left, expr.right, '=', precedence, flags); + AssignmentPattern: function(expr, precedence, flags, path) { + return this.generateAssignment(expr.left, expr.right, '=', precedence, flags, path); }, - ObjectPattern: function (expr, precedence, flags) { + ObjectPattern: function (expr, precedence, flags, path) { var result, i, iz, multiline, property, that = this; if (!expr.properties.length) { return '{}'; @@ -2356,7 +2412,7 @@ var i, iz; for (i = 0, iz = expr.properties.length; i < iz; ++i) { result.push(multiline ? indent : ''); - result.push(that.generateExpression(expr.properties[i], Precedence.Sequence, E_TTT)); + result.push(that.generateExpression(expr.properties[i], Precedence.Sequence, E_TTT, path)); if (i + 1 < iz) { result.push(',' + (multiline ? newline : space)); } @@ -2371,23 +2427,23 @@ return result; }, - ThisExpression: function (expr, precedence, flags) { + ThisExpression: function (expr, precedence, flags, path) { return 'this'; }, - Super: function (expr, precedence, flags) { + Super: function (expr, precedence, flags, path) { return 'super'; }, - Identifier: function (expr, precedence, flags) { + Identifier: function (expr, precedence, flags, path) { return generateIdentifier(expr); }, - ImportDefaultSpecifier: function (expr, precedence, flags) { + ImportDefaultSpecifier: function (expr, precedence, flags, path) { return generateIdentifier(expr.id || expr.local); }, - ImportNamespaceSpecifier: function (expr, precedence, flags) { + ImportNamespaceSpecifier: function (expr, precedence, flags, path) { var result = ['*']; var id = expr.id || expr.local; if (id) { @@ -2396,7 +2452,7 @@ return result; }, - ImportSpecifier: function (expr, precedence, flags) { + ImportSpecifier: function (expr, precedence, flags, path) { var imported = expr.imported; var result = [ imported.name ]; var local = expr.local; @@ -2406,7 +2462,7 @@ return result; }, - ExportSpecifier: function (expr, precedence, flags) { + ExportSpecifier: function (expr, precedence, flags, path) { var local = expr.local; var result = [ local.name ]; var exported = expr.exported; @@ -2416,7 +2472,7 @@ return result; }, - Literal: function (expr, precedence, flags) { + Literal: function (expr, precedence, flags, path) { var raw; if (expr.hasOwnProperty('raw') && parse && extra.raw) { try { @@ -2454,11 +2510,11 @@ return generateRegExp(expr.value); }, - GeneratorExpression: function (expr, precedence, flags) { - return this.ComprehensionExpression(expr, precedence, flags); + GeneratorExpression: function (expr, precedence, flags, path) { + return this.ComprehensionExpression(expr, precedence, flags, path); }, - ComprehensionExpression: function (expr, precedence, flags) { + ComprehensionExpression: function (expr, precedence, flags, path) { // GeneratorExpression should be parenthesized with (...), ComprehensionExpression with [...] // Due to https://bugzilla.mozilla.org/show_bug.cgi?id=883468 position of expr.body can differ in Spidermonkey and ES6 @@ -2466,14 +2522,14 @@ result = (expr.type === Syntax.GeneratorExpression) ? ['('] : ['[']; if (extra.moz.comprehensionExpressionStartsWithAssignment) { - fragment = this.generateExpression(expr.body, Precedence.Assignment, E_TTT); + fragment = this.generateExpression(expr.body, Precedence.Assignment, E_TTT, path); result.push(fragment); } if (expr.blocks) { withIndent(function () { for (i = 0, iz = expr.blocks.length; i < iz; ++i) { - fragment = that.generateExpression(expr.blocks[i], Precedence.Sequence, E_TTT); + fragment = that.generateExpression(expr.blocks[i], Precedence.Sequence, E_TTT, path); if (i > 0 || extra.moz.comprehensionExpressionStartsWithAssignment) { result = join(result, fragment); } else { @@ -2485,12 +2541,12 @@ if (expr.filter) { result = join(result, 'if' + space); - fragment = this.generateExpression(expr.filter, Precedence.Sequence, E_TTT); + fragment = this.generateExpression(expr.filter, Precedence.Sequence, E_TTT, path); result = join(result, [ '(', fragment, ')' ]); } if (!extra.moz.comprehensionExpressionStartsWithAssignment) { - fragment = this.generateExpression(expr.body, Precedence.Assignment, E_TTT); + fragment = this.generateExpression(expr.body, Precedence.Assignment, E_TTT, path); result = join(result, fragment); } @@ -2499,56 +2555,58 @@ return result; }, - ComprehensionBlock: function (expr, precedence, flags) { + ComprehensionBlock: function (expr, precedence, flags, path) { var fragment; + var leftChildNode = expr.left; + var leftChildPath = new PathToNode(leftChildNode, path); if (expr.left.type === Syntax.VariableDeclaration) { fragment = [ expr.left.kind, noEmptySpace(), - this.generateStatement(expr.left.declarations[0], S_FFFF) + this.generateStatement(leftChildNode.declarations[0], S_FFFF, leftChildPath) ]; } else { - fragment = this.generateExpression(expr.left, Precedence.Call, E_TTT); + fragment = this.generateExpression(leftChildNode, Precedence.Call, E_TTT, path); } fragment = join(fragment, expr.of ? 'of' : 'in'); - fragment = join(fragment, this.generateExpression(expr.right, Precedence.Sequence, E_TTT)); + fragment = join(fragment, this.generateExpression(expr.right, Precedence.Sequence, E_TTT, path)); return [ 'for' + space + '(', fragment, ')' ]; }, - SpreadElement: function (expr, precedence, flags) { + SpreadElement: function (expr, precedence, flags, path) { return [ '...', - this.generateExpression(expr.argument, Precedence.Assignment, E_TTT) + this.generateExpression(expr.argument, Precedence.Assignment, E_TTT, path) ]; }, - TaggedTemplateExpression: function (expr, precedence, flags) { + TaggedTemplateExpression: function (expr, precedence, flags, path) { var itemFlags = E_TTF; if (!(flags & F_ALLOW_CALL)) { itemFlags = E_TFF; } var result = [ - this.generateExpression(expr.tag, Precedence.Call, itemFlags), - this.generateExpression(expr.quasi, Precedence.Primary, E_FFT) + this.generateExpression(expr.tag, Precedence.Call, itemFlags, path), + this.generateExpression(expr.quasi, Precedence.Primary, E_FFT, path) ]; return parenthesize(result, Precedence.TaggedTemplate, precedence); }, - TemplateElement: function (expr, precedence, flags) { + TemplateElement: function (expr, precedence, flags, path) { // Don't use "cooked". Since tagged template can use raw template // representation. So if we do so, it breaks the script semantics. return expr.value.raw; }, - TemplateLiteral: function (expr, precedence, flags) { + TemplateLiteral: function (expr, precedence, flags, path) { var result, i, iz; result = [ '`' ]; for (i = 0, iz = expr.quasis.length; i < iz; ++i) { - result.push(this.generateExpression(expr.quasis[i], Precedence.Primary, E_TTT)); + result.push(this.generateExpression(expr.quasis[i], Precedence.Primary, E_TTT, path)); if (i + 1 < iz) { result.push('${' + space); - result.push(this.generateExpression(expr.expressions[i], Precedence.Sequence, E_TTT)); + result.push(this.generateExpression(expr.expressions[i], Precedence.Sequence, E_TTT, path)); result.push(space + '}'); } } @@ -2556,14 +2614,14 @@ return result; }, - ModuleSpecifier: function (expr, precedence, flags) { - return this.Literal(expr, precedence, flags); + ModuleSpecifier: function (expr, precedence, flags, path) { + return this.Literal(expr, precedence, flags, path); }, - ImportExpression: function(expr, precedence, flag) { + ImportExpression: function(expr, precedence, flag, path) { return parenthesize([ 'import(', - this.generateExpression(expr.source, Precedence.Assignment, E_TTT), + this.generateExpression(expr.source, Precedence.Assignment, E_TTT, path), ')' ], Precedence.Call, precedence); } @@ -2571,35 +2629,47 @@ merge(CodeGenerator.prototype, CodeGenerator.Expression); - CodeGenerator.prototype.generateExpression = function (expr, precedence, flags, parent) { + // NOTE: adds `expr` to the path, unless `updatePath` is set to `false` + CodeGenerator.prototype.generateExpression = function (expr, precedence, flags, path, updatePath) { + updatePath = (updatePath === undefined) ? true : updatePath; var result, type; + if (updatePath) { + path = new PathToNode(expr, path); + } + type = expr.type || Syntax.Property; if (extra.verbatim && expr.hasOwnProperty(extra.verbatim)) { return generateVerbatim(expr, precedence); } - result = this[type](expr, precedence, flags); + result = this[type](expr, precedence, flags, path); if (extra.comment) { - result = addComments(expr, result, parent); + result = addComments(expr, result, path); } return toSourceNodeWhenNeeded(result, expr); }; - CodeGenerator.prototype.generateStatement = function (stmt, flags) { + // NOTE: adds `stmt` to the path, unless `updatePath` is set to `false` + CodeGenerator.prototype.generateStatement = function (stmt, flags, path, updatePath) { + updatePath = (updatePath === undefined) ? true : updatePath; var result, fragment; - result = this[stmt.type](stmt, flags); + if (updatePath) { + path = new PathToNode(stmt, path); + } + + result = this[stmt.type](stmt, flags, path); // Attach comments if (extra.comment) { - result = addComments(stmt, result); + result = addComments(stmt, result, path); } fragment = toSourceNodeWhenNeeded(result).toString(); @@ -2610,16 +2680,16 @@ return toSourceNodeWhenNeeded(result, stmt); }; - function generateInternal(node) { + function generateInternal(node, path) { var codegen; codegen = new CodeGenerator(); if (isStatement(node)) { - return codegen.generateStatement(node, S_TFFF); + return codegen.generateStatement(node, S_TFFF, path, false); } if (isExpression(node)) { - return codegen.generateExpression(node, Precedence.Sequence, E_TTT); + return codegen.generateExpression(node, Precedence.Sequence, E_TTT, path, false); } throw new Error('Unknown node type: ' + node.type); @@ -2683,7 +2753,7 @@ } } - result = generateInternal(node); + result = generateInternal(node, new PathToNode(node, null)); if (!sourceMap) { pair = {code: result.toString(), map: null}; diff --git a/test/comment.js b/test/comment.js index 57806f39..04740da5 100644 --- a/test/comment.js +++ b/test/comment.js @@ -25,7 +25,7 @@ 'use strict'; var fs = require('fs'), - esprima = require('./3rdparty/esprima-harmony.original'), + esprima = require('esprima'), escodegen = require('./loader'), chai = require('chai'), expect = chai.expect; diff --git a/test/comment/array-elements.expected.js b/test/comment/array-elements.expected.js new file mode 100644 index 00000000..f4d9acd7 --- /dev/null +++ b/test/comment/array-elements.expected.js @@ -0,0 +1,12 @@ +var test = [ + /** + * Test 2 + */ + a, + /* + * Test 1 + */ + 2, + // Test 3 + 3 + 3 +]; diff --git a/test/comment/array-elements.js b/test/comment/array-elements.js new file mode 100644 index 00000000..a32e39e2 --- /dev/null +++ b/test/comment/array-elements.js @@ -0,0 +1,12 @@ +var test = [ + /** + * Test 2 + */ + a, + /* + * Test 1 + */ + 2, + // Test 3 + 3+3 +]; 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 f1a36326..b97d2186 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 @@ -59,15 +59,3 @@ let arrowFn = () => ( 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 e87d0528..d3aaf5b8 100644 --- a/test/comment/comment-as-first-element-in-parenthesis-expression.js +++ b/test/comment/comment-as-first-element-in-parenthesis-expression.js @@ -72,16 +72,3 @@ let arrowFn = () => ( a: 1, b: 2 } ); - -var test = [ - /** - * Test 2 - */ - a, - /* - * Test 1 - */ - 2, - // Test 3 - 3+3 -]; diff --git a/test/comment/method-description.expected.js b/test/comment/method-description.expected.js new file mode 100644 index 00000000..4bbb13f3 --- /dev/null +++ b/test/comment/method-description.expected.js @@ -0,0 +1,15 @@ +class MyClass { + /** + * description + */ + foo(a, b) { + a.bar(b); + } +} +class MyClass2 { + // description + foo(a, b, c, // NOTE: ... + d = false) { + return 42; + } +} diff --git a/test/comment/method-description.js b/test/comment/method-description.js new file mode 100644 index 00000000..9f40653a --- /dev/null +++ b/test/comment/method-description.js @@ -0,0 +1,17 @@ +class MyClass { + /** + * description + */ + foo(a, b) { + a.bar(b); + } +} + +class MyClass2 { + // description + foo(a, b, c, + // NOTE: ... + d = false) { + return 42; + } +} diff --git a/test/comment/try-block-line-comment.expected.js b/test/comment/try-block-line-comment.expected.js index d46d7867..726ada5b 100644 --- a/test/comment/try-block-line-comment.expected.js +++ b/test/comment/try-block-line-comment.expected.js @@ -4,11 +4,13 @@ finally { } try { } catch (e) { -} finally { +} // +finally { } { try { } catch (e) { - } finally { + } // + finally { } } From ce9e1ceff7266513920d75867c42987b1145c441 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Lu=C4=8Div=C5=88=C3=A1k?= Date: Thu, 26 Nov 2020 17:41:11 +0100 Subject: [PATCH 13/26] fix problem with unwanted parentheses in imports --- escodegen.js | 9 ++++++++- test/comment.js | 4 +++- test/comment/imports.expected.js | 11 +++++++++++ test/comment/imports.js | 11 +++++++++++ 4 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 test/comment/imports.expected.js create mode 100644 test/comment/imports.js diff --git a/escodegen.js b/escodegen.js index 3cc99487..0cc84566 100644 --- a/escodegen.js +++ b/escodegen.js @@ -275,10 +275,17 @@ if (path.parent !== null && ( path.parent.node.type == Syntax.ObjectExpression || path.parent.node.type == Syntax.ArrayExpression || - path.parent.node.type == Syntax.Property + path.parent.node.type == Syntax.Property || + path.parent.node.type == Syntax.ImportExpression )) { return false; } + if (path.parent !== null && + path.node.type == Syntax.ImportSpecifier && + path.parent.node.type == Syntax.ImportDeclaration + ) { + return false; + } if (path.parent !== null && path.parent.parent !== null && path.parent.parent.node.type == Syntax.MethodDefinition && path.parent.node.type == Syntax.FunctionExpression && diff --git a/test/comment.js b/test/comment.js index 04740da5..fb0d342f 100644 --- a/test/comment.js +++ b/test/comment.js @@ -41,7 +41,8 @@ function test(code, expected) { range: true, loc: false, tokens: true, - raw: false + raw: false, + sourceType: 'module' }; tree = esprima.parse(code, options); @@ -63,6 +64,7 @@ describe('comment test', function () { fs.readdirSync(__dirname + '/comment').sort().forEach(function(file) { var code, expected, p; if (/\.js$/.test(file) && !/expected\.js$/.test(file)) { + //if (/imports\.js$/.test(file) && !/expected\.js$/.test(file)) { it(file, function () { p = file.replace(/\.js$/, '.expected.js'); code = fs.readFileSync(__dirname + '/comment/' + file, 'utf-8'); diff --git a/test/comment/imports.expected.js b/test/comment/imports.expected.js new file mode 100644 index 00000000..2a4def42 --- /dev/null +++ b/test/comment/imports.expected.js @@ -0,0 +1,11 @@ +// this import is important +import 'foo'; +import { foo } from 'foo'; +import { foo as bar } from 'foo'; +// this import is important too +import { + foo as bar, + // alias needed because of ... + test as testing, + logging +} from 'foo'; diff --git a/test/comment/imports.js b/test/comment/imports.js new file mode 100644 index 00000000..d693c138 --- /dev/null +++ b/test/comment/imports.js @@ -0,0 +1,11 @@ +// this import is important +import 'foo'; +import {foo} from 'foo'; +import {foo as bar} from 'foo'; +// this import is important too +import { + foo as bar, + // alias needed because of ... + test as testing, + logging +} from 'foo'; From acc9cd02f22db16a0c25fbf130f27f7173b0761c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Lu=C4=8Div=C5=88=C3=A1k?= Date: Mon, 14 Dec 2020 09:27:15 +0100 Subject: [PATCH 14/26] revert no-op change --- test/comment.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/comment.js b/test/comment.js index fb0d342f..393bf80e 100644 --- a/test/comment.js +++ b/test/comment.js @@ -64,7 +64,6 @@ describe('comment test', function () { fs.readdirSync(__dirname + '/comment').sort().forEach(function(file) { var code, expected, p; if (/\.js$/.test(file) && !/expected\.js$/.test(file)) { - //if (/imports\.js$/.test(file) && !/expected\.js$/.test(file)) { it(file, function () { p = file.replace(/\.js$/, '.expected.js'); code = fs.readFileSync(__dirname + '/comment/' + file, 'utf-8'); From da7d71cb689714647afd9730d55f29eb6a3a3004 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Lu=C4=8Div=C5=88=C3=A1k?= Date: Thu, 17 Dec 2020 16:46:15 +0100 Subject: [PATCH 15/26] dont parenthesize variable declaration expressions --- escodegen.js | 26 +++--- ...ment-in-parenthesis-expression.expected.js | 89 +++++++++++-------- ...in-parenthesis-expression.expected.js.todo | 9 ++ ...first-element-in-parenthesis-expression.js | 89 +++++++++++-------- ...-element-in-parenthesis-expression.js.todo | 9 ++ test/comment/debug.expected.js | 1 + test/comment/debug.js | 1 + test/comment/variable-declaration.expected.js | 7 ++ .../variable-declaration.expected.js.todo | 27 ++++++ test/comment/variable-declaration.js | 9 ++ test/comment/variable-declaration.js.todo | 33 +++++++ 11 files changed, 216 insertions(+), 84 deletions(-) create mode 100644 test/comment/comment-as-first-element-in-parenthesis-expression.expected.js.todo create mode 100644 test/comment/comment-as-first-element-in-parenthesis-expression.js.todo create mode 100644 test/comment/debug.expected.js create mode 100644 test/comment/debug.js create mode 100644 test/comment/variable-declaration.expected.js create mode 100644 test/comment/variable-declaration.expected.js.todo create mode 100644 test/comment/variable-declaration.js create mode 100644 test/comment/variable-declaration.js.todo diff --git a/escodegen.js b/escodegen.js index 0cc84566..15a258c8 100644 --- a/escodegen.js +++ b/escodegen.js @@ -273,28 +273,31 @@ return false; } if (path.parent !== null && ( - path.parent.node.type == Syntax.ObjectExpression || - path.parent.node.type == Syntax.ArrayExpression || - path.parent.node.type == Syntax.Property || - path.parent.node.type == Syntax.ImportExpression + path.parent.node.type === Syntax.ObjectExpression || + path.parent.node.type === Syntax.ArrayExpression || + path.parent.node.type === Syntax.Property || + path.parent.node.type === Syntax.ImportExpression )) { return false; } if (path.parent !== null && - path.node.type == Syntax.ImportSpecifier && - path.parent.node.type == Syntax.ImportDeclaration + path.node.type === Syntax.ImportSpecifier && + path.parent.node.type === Syntax.ImportDeclaration ) { return false; } if (path.parent !== null && path.parent.parent !== null && - path.parent.parent.node.type == Syntax.MethodDefinition && - path.parent.node.type == Syntax.FunctionExpression && - path.node.type == Syntax.AssignmentPattern) { + path.parent.parent.node.type === Syntax.MethodDefinition && + path.parent.node.type === Syntax.FunctionExpression && + path.node.type === Syntax.AssignmentPattern) { return false; } if (stmt.type === Syntax.MethodDefinition) { return false; } + if (path.parent !== null && path.parent.node.type === Syntax.VariableDeclaration) { + return false; + } if (!isParenthesizedByAnyBracketKind(str)) { return true; } @@ -816,9 +819,8 @@ } else { var text = toSourceNodeWhenNeeded(result).toString(); if (shouldParenthesize(text, stmt, path)) { - withIndent(function () { - result = addMultiLineIndent(result); - }); + result = addMultiLineIndent(result); + result = [indent, result]; result = ['(', newline, result]; 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 b97d2186..ea097464 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,39 +1,56 @@ -let variable = ( - // comment - 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 -); -let variable = ( - // one - 3 + 3 -) - ( - // two - (1 + 1) -); +function foo() { + return ( + // comment + 3 + 3 + ); +} +function foo() { + return ( + // comment + 3 + 3 + ); +} +function foo() { + return ( + /* comment */ + 3 + 3 + ); +} +function foo() { + return ( + /* comment + comment + comment + */ + 3 + 3 + ); +} +function foo() { + return ( + /* comment + comment + comment + */ + 3 + 3 + ); +} +function foo() { + return ( + // comment + /* comment */ + // comment + 3 + 3 + ); +} +function foo() { + return ( + // one + 3 + 3 + ) - ( + // two + (1 + 1) + ); +} function foo(a, b, c) { return ( // comment diff --git a/test/comment/comment-as-first-element-in-parenthesis-expression.expected.js.todo b/test/comment/comment-as-first-element-in-parenthesis-expression.expected.js.todo new file mode 100644 index 00000000..c48f6153 --- /dev/null +++ b/test/comment/comment-as-first-element-in-parenthesis-expression.expected.js.todo @@ -0,0 +1,9 @@ +// this test should pass, but it is not passing due to a bug +// https://github.com/estools/escodegen/issues/433 + +function foo() { + return /* comment */ ( + // comment + 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 d3aaf5b8..8d261607 100644 --- a/test/comment/comment-as-first-element-in-parenthesis-expression.js +++ b/test/comment/comment-as-first-element-in-parenthesis-expression.js @@ -1,45 +1,62 @@ -let variable = ( - // comment - 3+3 -); - -let variable = ( // comment - 3+3 -); +function foo() { + return ( + // comment + 3+3 + ); +} -let variable = ( /* comment */ - 3+3 -); +function foo() { + return ( // comment + 3+3 + ); +} -let variable = ( /* comment - comment - comment - */ - 3+3 -); +function foo() { + return ( /* comment */ + 3+3 + ); +} -let variable = ( - // comment - /* comment */ - // comment - 3+3 -); +function foo() { + return ( /* comment + comment + comment + */ + 3+3 + ); +} -let variable = /* comment */ ( - // comment - 3+3 -); +function foo() { + return ( + /* comment + comment + comment + */ + 3+3 + ); +} -let variable = ( - ( - // one +function foo() { + return ( + // comment + /* comment */ + // comment 3+3 - ) - - ( - // two - 1+1 - ) -); + ); +} + +function foo() { + return ( + ( + // one + 3+3 + ) - + ( + // two + 1+1 + ) + ); +} function foo(a, b, c) { return ( diff --git a/test/comment/comment-as-first-element-in-parenthesis-expression.js.todo b/test/comment/comment-as-first-element-in-parenthesis-expression.js.todo new file mode 100644 index 00000000..82b420e7 --- /dev/null +++ b/test/comment/comment-as-first-element-in-parenthesis-expression.js.todo @@ -0,0 +1,9 @@ +// this test should pass, but it is not passing due to a bug +// https://github.com/estools/escodegen/issues/433 + +function foo() { + return /* comment */ ( + // comment + 3+3 + ); +} diff --git a/test/comment/debug.expected.js b/test/comment/debug.expected.js new file mode 100644 index 00000000..96f6d3a3 --- /dev/null +++ b/test/comment/debug.expected.js @@ -0,0 +1 @@ +var x; diff --git a/test/comment/debug.js b/test/comment/debug.js new file mode 100644 index 00000000..96f6d3a3 --- /dev/null +++ b/test/comment/debug.js @@ -0,0 +1 @@ +var x; diff --git a/test/comment/variable-declaration.expected.js b/test/comment/variable-declaration.expected.js new file mode 100644 index 00000000..180e75e2 --- /dev/null +++ b/test/comment/variable-declaration.expected.js @@ -0,0 +1,7 @@ +let variable = ( + // one + 3 + 3 +) - ( + // two + (1 + 1) +); diff --git a/test/comment/variable-declaration.expected.js.todo b/test/comment/variable-declaration.expected.js.todo new file mode 100644 index 00000000..d1dcc44a --- /dev/null +++ b/test/comment/variable-declaration.expected.js.todo @@ -0,0 +1,27 @@ +// this test should pass, but it is not passing due to a bug +// https://github.com/estools/escodegen/issues/435 + +let variable = + // comment + 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; +let age = // comment + 42, + // comment + height = 165; diff --git a/test/comment/variable-declaration.js b/test/comment/variable-declaration.js new file mode 100644 index 00000000..94290ad6 --- /dev/null +++ b/test/comment/variable-declaration.js @@ -0,0 +1,9 @@ +let variable = + ( + // one + 3+3 + ) - + ( + // two + 1+1 + ) \ No newline at end of file diff --git a/test/comment/variable-declaration.js.todo b/test/comment/variable-declaration.js.todo new file mode 100644 index 00000000..78ad8ff7 --- /dev/null +++ b/test/comment/variable-declaration.js.todo @@ -0,0 +1,33 @@ +// this test should pass, but it is not passing due to a bug +// https://github.com/estools/escodegen/issues/435 + +let variable = + // comment + 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; + +let age = // comment + 42, + // comment + height = 165; From 873307fdd7f7ff5f62d21c3707f607682303e188 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Lu=C4=8Div=C5=88=C3=A1k?= Date: Thu, 17 Dec 2020 16:50:08 +0100 Subject: [PATCH 16/26] revert unwanted new files --- test/comment/debug.expected.js | 1 - test/comment/debug.js | 1 - 2 files changed, 2 deletions(-) delete mode 100644 test/comment/debug.expected.js delete mode 100644 test/comment/debug.js diff --git a/test/comment/debug.expected.js b/test/comment/debug.expected.js deleted file mode 100644 index 96f6d3a3..00000000 --- a/test/comment/debug.expected.js +++ /dev/null @@ -1 +0,0 @@ -var x; diff --git a/test/comment/debug.js b/test/comment/debug.js deleted file mode 100644 index 96f6d3a3..00000000 --- a/test/comment/debug.js +++ /dev/null @@ -1 +0,0 @@ -var x; From bb30704670b90f78b55b997510d543635df43ebc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Lu=C4=8Div=C5=88=C3=A1k?= Date: Thu, 17 Dec 2020 23:09:21 +0100 Subject: [PATCH 17/26] revert logic to simplify PR; only parenthesize at a level where it is necessary; improve tests --- escodegen.js | 94 +++++++++---------- ...ment-in-parenthesis-expression.expected.js | 8 +- test/comment/variable-declaration.expected.js | 34 +++++-- .../variable-declaration.expected.js.todo | 27 ------ test/comment/variable-declaration.js | 40 +++++++- .../variable-declaration.js.expected.todo | 2 + test/comment/variable-declaration.js.todo | 33 ------- 7 files changed, 114 insertions(+), 124 deletions(-) delete mode 100644 test/comment/variable-declaration.expected.js.todo create mode 100644 test/comment/variable-declaration.js.expected.todo delete mode 100644 test/comment/variable-declaration.js.todo diff --git a/escodegen.js b/escodegen.js index 15a258c8..2c2e3aa1 100644 --- a/escodegen.js +++ b/escodegen.js @@ -240,6 +240,11 @@ return str.replace(/\/\*[\s\S]*?\*\/|\/\/.*/g, ''); } + function startsWithComment(result) { + var str = toSourceNodeWhenNeeded(result).toString(); + return (/^\/\*[\s\S]*?\*\/|^\/\/.*/).test(str); + } + function removeTrailingWhiteSpaces(str) { return str.replace(/\S(\s+)$/g, ''); } @@ -249,17 +254,17 @@ str = removeTrailingWhiteSpaces(str); var counter = 0; for (var i = 0; i < str.length; ++i) { - if (str[i] == leftPar) { + if (str[i] === leftPar) { counter++; } - else if (str[i] == rightPar) { - if (counter == 0) { + else if (str[i] === rightPar) { + if (counter === 0) { return false; } counter--; } } - return counter == 0 && str[str.length-1] == rightPar; + return counter === 0 && str[0] === leftPar && str[str.length-1] === rightPar; } function isParenthesizedByAnyBracketKind(str) { @@ -272,40 +277,18 @@ if (!hasLineTerminator(str)) { return false; } - if (path.parent !== null && ( - path.parent.node.type === Syntax.ObjectExpression || - path.parent.node.type === Syntax.ArrayExpression || - path.parent.node.type === Syntax.Property || - path.parent.node.type === Syntax.ImportExpression - )) { - return false; - } - if (path.parent !== null && - path.node.type === Syntax.ImportSpecifier && - path.parent.node.type === Syntax.ImportDeclaration - ) { + if (path.parent === null) { return false; } - if (path.parent !== null && path.parent.parent !== null && - path.parent.parent.node.type === Syntax.MethodDefinition && - path.parent.node.type === Syntax.FunctionExpression && - path.node.type === Syntax.AssignmentPattern) { - return false; - } - if (stmt.type === Syntax.MethodDefinition) { + var parentNodeType = path.parent.node.type; + if (parentNodeType !== Syntax.ReturnStatement && + parentNodeType !== Syntax.ThrowStatement && + parentNodeType !== Syntax.ArrowFunctionExpression) { return false; - } - if (path.parent !== null && path.parent.node.type === Syntax.VariableDeclaration) { + }; + if (isParenthesizedByAnyBracketKind(str)) return false; - } - if (!isParenthesizedByAnyBracketKind(str)) { - return true; - } - - str = removeComments(str); - var firstNewlineIdx = str.indexOf(newline); - var firstParenthesisIdx = str.match(/[\(\[\{)]/).index; - return firstNewlineIdx < firstParenthesisIdx; + return true; } function merge(target, override) { @@ -752,10 +735,11 @@ function addComments(stmt, result, path) { var i, len, comment, save, tailingToStatement, specialBase, fragment, - extRange, range, prevRange, prefix, infix, suffix, count; + extRange, range, prevRange, prefix, infix, suffix, count, + generatedLeadingComments, hasLeadingComments; + save = result; if (stmt.leadingComments && stmt.leadingComments.length > 0) { - save = result; if (preserveBlankLines) { comment = stmt.leadingComments[0]; @@ -813,26 +797,34 @@ result.push(addIndent(fragment)); } } + generatedLeadingComments = true; + } - if (!isExpression(stmt)) { - result.push(addIndent(save)); - } else { - var text = toSourceNodeWhenNeeded(result).toString(); - if (shouldParenthesize(text, stmt, path)) { - result = addMultiLineIndent(result); - result = [indent, result]; + hasLeadingComments = generatedLeadingComments || startsWithComment(result); + var text = toSourceNodeWhenNeeded(result).toString(); + var parenthesize = shouldParenthesize(text, stmt, path); - result = ['(', newline, result]; + if (!hasLeadingComments) { + result = save; + } else if (hasLeadingComments && parenthesize) { + if (generatedLeadingComments) { + result = addMultiLineIndent(result); + result = [indent, result]; - withIndent(function () { - result.push(addMultiLineIndent(save)); - }); + result = ['(', newline, result]; - result.push([newline, base, ')']); - } else { - result.push(addIndent(save)); - } + withIndent(function () { + result.push(addMultiLineIndent(save)); + }); + + result.push([newline, base, ')']); + } else { + result = ['(', newline, indent, addMultiLineIndent(result), newline, base, ')']; } + } else if (generatedLeadingComments) { + result.push(addIndent(save)); + } else { + result = save; } if (stmt.trailingComments) { 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 ea097464..b9471e3c 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 @@ -45,9 +45,7 @@ function foo() { function foo() { return ( // one - 3 + 3 - ) - ( - // two + 3 + 3 - // two (1 + 1) ); } @@ -60,8 +58,8 @@ function foo(a, b, c) { function foo(a, b, c) { return ( // comment - a >= b && a <= c - ) || a === 42 || a === 666; + a >= b && a <= c || a === 42 || a === 666 + ); } function foo(a, b, c) { throw ( diff --git a/test/comment/variable-declaration.expected.js b/test/comment/variable-declaration.expected.js index 180e75e2..287acd0f 100644 --- a/test/comment/variable-declaration.expected.js +++ b/test/comment/variable-declaration.expected.js @@ -1,7 +1,27 @@ -let variable = ( - // one - 3 + 3 -) - ( - // two - (1 + 1) -); +let variable = // comment +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; +let variable = // one +3 + 3 - // two +(1 + 1); +let age = // comment + 42, + // comment + height = 165; +let variable = // comment +a >= b && a <= c || a === 42 || a === 666; diff --git a/test/comment/variable-declaration.expected.js.todo b/test/comment/variable-declaration.expected.js.todo deleted file mode 100644 index d1dcc44a..00000000 --- a/test/comment/variable-declaration.expected.js.todo +++ /dev/null @@ -1,27 +0,0 @@ -// this test should pass, but it is not passing due to a bug -// https://github.com/estools/escodegen/issues/435 - -let variable = - // comment - 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; -let age = // comment - 42, - // comment - height = 165; diff --git a/test/comment/variable-declaration.js b/test/comment/variable-declaration.js index 94290ad6..42ef993d 100644 --- a/test/comment/variable-declaration.js +++ b/test/comment/variable-declaration.js @@ -1,3 +1,29 @@ +let variable = + // comment + 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; + let variable = ( // one @@ -6,4 +32,16 @@ let variable = ( // two 1+1 - ) \ No newline at end of file + ); + +let age = // comment + 42, + // comment + height = 165; + +let variable = ( + ( // comment + a >= b && + a <= c) + || a === 42 || a === 666 +); diff --git a/test/comment/variable-declaration.js.expected.todo b/test/comment/variable-declaration.js.expected.todo new file mode 100644 index 00000000..0d403f34 --- /dev/null +++ b/test/comment/variable-declaration.js.expected.todo @@ -0,0 +1,2 @@ +// TOOD: https://github.com/estools/escodegen/issues/435 +// the existing non-todo test expectation shall be adjusted accordingly once the issue is resolved \ No newline at end of file diff --git a/test/comment/variable-declaration.js.todo b/test/comment/variable-declaration.js.todo deleted file mode 100644 index 78ad8ff7..00000000 --- a/test/comment/variable-declaration.js.todo +++ /dev/null @@ -1,33 +0,0 @@ -// this test should pass, but it is not passing due to a bug -// https://github.com/estools/escodegen/issues/435 - -let variable = - // comment - 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; - -let age = // comment - 42, - // comment - height = 165; From 34cd8c6d3de02342a4b391007dfc11d7e86936f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Lu=C4=8Div=C5=88=C3=A1k?= Date: Wed, 6 Jan 2021 09:53:21 +0100 Subject: [PATCH 18/26] nits --- escodegen.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/escodegen.js b/escodegen.js index 024f47d2..5cab0c46 100644 --- a/escodegen.js +++ b/escodegen.js @@ -289,9 +289,10 @@ parentNodeType !== Syntax.ThrowStatement && parentNodeType !== Syntax.ArrowFunctionExpression) { return false; - }; - if (isParenthesizedByAnyBracketKind(str)) + } + if (isParenthesizedByAnyBracketKind(str)) { return false; + } return true; } @@ -782,7 +783,6 @@ } else { comment = stmt.leadingComments[0]; result = []; - if (safeConcatenation && stmt.type === Syntax.Program && stmt.body.length === 0) { result.push('\n'); } From fae4df210a0bb5a4e65212213dc6a150d8128a7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Lu=C4=8Div=C5=88=C3=A1k?= Date: Wed, 6 Jan 2021 11:00:12 +0100 Subject: [PATCH 19/26] nit --- escodegen.js | 1 - 1 file changed, 1 deletion(-) diff --git a/escodegen.js b/escodegen.js index 5cab0c46..622eff14 100644 --- a/escodegen.js +++ b/escodegen.js @@ -787,7 +787,6 @@ result.push('\n'); } result.push(generateComment(comment)); - if (!endsWithLineTerminator(toSourceNodeWhenNeeded(result).toString())) { result.push('\n'); } From 91c5ee09a378c1545258ae79c96631016b2fc2b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Lu=C4=8Div=C5=88=C3=A1k?= Date: Wed, 6 Jan 2021 11:12:04 +0100 Subject: [PATCH 20/26] improve performance --- escodegen.js | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/escodegen.js b/escodegen.js index 622eff14..df5a6075 100644 --- a/escodegen.js +++ b/escodegen.js @@ -253,9 +253,7 @@ return str.replace(/\S(\s+)$/g, ''); } - function isParenthesized(str, leftPar, rightPar) { - str = removeComments(str); - str = removeTrailingWhiteSpaces(str); + function isParenthesizedCached(str, leftPar, rightPar) { var counter = 0; for (var i = 0; i < str.length; ++i) { if (str[i] === leftPar) { @@ -271,10 +269,18 @@ return counter === 0 && str[0] === leftPar && str[str.length-1] === rightPar; } + function isParenthesized(str, leftPar, rightPar) { + str = removeComments(str); + str = removeTrailingWhiteSpaces(str); + return isParenthesizedCached(str, leftPar, rightPar); + } + function isParenthesizedByAnyBracketKind(str) { - return isParenthesized(str, '(', ')') || - isParenthesized(str, '{', '}') || - isParenthesized(str, '[', ']'); + str = removeComments(str); + str = removeTrailingWhiteSpaces(str); + return isParenthesizedCached(str, '(', ')') || + isParenthesizedCached(str, '{', '}') || + isParenthesizedCached(str, '[', ']'); } function shouldParenthesize(str, stmt, path) { From 2cfc0902d3a3fbb1e4caa0e0b9086f4d2bd2d25e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Lu=C4=8Div=C5=88=C3=A1k?= Date: Wed, 6 Jan 2021 11:15:58 +0100 Subject: [PATCH 21/26] fix isParenthesized zero length input behavior --- escodegen.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/escodegen.js b/escodegen.js index df5a6075..c6522a6a 100644 --- a/escodegen.js +++ b/escodegen.js @@ -254,6 +254,9 @@ } function isParenthesizedCached(str, leftPar, rightPar) { + if (str.length === 0) { + return false; + } var counter = 0; for (var i = 0; i < str.length; ++i) { if (str[i] === leftPar) { From 9bc0f1271282ff3ad4527f3d62ed547a5201af9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Lu=C4=8Div=C5=88=C3=A1k?= Date: Wed, 6 Jan 2021 11:18:09 +0100 Subject: [PATCH 22/26] use a single isParenthesized() fn instead of additional isParenthesizedCached() fn --- escodegen.js | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/escodegen.js b/escodegen.js index c6522a6a..081a66ac 100644 --- a/escodegen.js +++ b/escodegen.js @@ -253,7 +253,8 @@ return str.replace(/\S(\s+)$/g, ''); } - function isParenthesizedCached(str, leftPar, rightPar) { + // assumes no comments and no trailing white spaces are present in `str` + function isParenthesized(str, leftPar, rightPar) { if (str.length === 0) { return false; } @@ -272,18 +273,12 @@ return counter === 0 && str[0] === leftPar && str[str.length-1] === rightPar; } - function isParenthesized(str, leftPar, rightPar) { - str = removeComments(str); - str = removeTrailingWhiteSpaces(str); - return isParenthesizedCached(str, leftPar, rightPar); - } - function isParenthesizedByAnyBracketKind(str) { str = removeComments(str); str = removeTrailingWhiteSpaces(str); - return isParenthesizedCached(str, '(', ')') || - isParenthesizedCached(str, '{', '}') || - isParenthesizedCached(str, '[', ']'); + return isParenthesized(str, '(', ')') || + isParenthesized(str, '{', '}') || + isParenthesized(str, '[', ']'); } function shouldParenthesize(str, stmt, path) { From ca686774e76f389170893c2d1f124c71a105bd67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Lu=C4=8Div=C5=88=C3=A1k?= Date: Wed, 6 Jan 2021 11:20:26 +0100 Subject: [PATCH 23/26] use constant for newline instead of a literal --- escodegen.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/escodegen.js b/escodegen.js index 081a66ac..29777fe6 100644 --- a/escodegen.js +++ b/escodegen.js @@ -643,7 +643,7 @@ function addMultiLineIndent(stmt) { var str = base + flattenToString(stmt); - var split = str.split(/\n/g); + var split = str.split(new RegExp(newline, 'g')); var suffix = ''; // do not replace the last newline if (split[split.length-1].length == 0) { From d669661668a36bed64d3851913a1e6ed80d04cb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Lu=C4=8Div=C5=88=C3=A1k?= Date: Wed, 6 Jan 2021 11:27:00 +0100 Subject: [PATCH 24/26] handle edge case in addMultiLineIndent() --- escodegen.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/escodegen.js b/escodegen.js index 29777fe6..4c7534d5 100644 --- a/escodegen.js +++ b/escodegen.js @@ -643,10 +643,13 @@ function addMultiLineIndent(stmt) { var str = base + flattenToString(stmt); + if (str.length === 0) { + return ''; + } var split = str.split(new RegExp(newline, 'g')); var suffix = ''; // do not replace the last newline - if (split[split.length-1].length == 0) { + if (split[split.length-1].length === 0) { split = split.slice(0, split.length-1); suffix = newline; } From fb1ab8606364067060250d1419a6d3ea9cc1a1dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Lu=C4=8Div=C5=88=C3=A1k?= Date: Wed, 13 Jan 2021 13:20:18 +0100 Subject: [PATCH 25/26] add test, where parenthesis should not be added --- ...ement-in-non-parenthesis-expression.expected.js | 14 ++++++++++++++ ...-in-non-parenthesis-expression.expected.js.todo | 14 ++++++++++++++ ...-first-element-in-non-parenthesis-expression.js | 10 ++++++++++ ...t-element-in-non-parenthesis-expression.js.todo | 14 ++++++++++++++ 4 files changed, 52 insertions(+) create mode 100644 test/comment/comment-as-first-element-in-non-parenthesis-expression.expected.js create mode 100644 test/comment/comment-as-first-element-in-non-parenthesis-expression.expected.js.todo create mode 100644 test/comment/comment-as-first-element-in-non-parenthesis-expression.js create mode 100644 test/comment/comment-as-first-element-in-non-parenthesis-expression.js.todo diff --git a/test/comment/comment-as-first-element-in-non-parenthesis-expression.expected.js b/test/comment/comment-as-first-element-in-non-parenthesis-expression.expected.js new file mode 100644 index 00000000..02872abd --- /dev/null +++ b/test/comment/comment-as-first-element-in-non-parenthesis-expression.expected.js @@ -0,0 +1,14 @@ +function foo(x) { + return ( + /* comment 1 */ + x > 0 || // comment 2 + x < 5 + ); +} +function foo(x) { + return ( + /* comment 1 */ + x > 0 || // comment 2 + x < 5 + ); +} diff --git a/test/comment/comment-as-first-element-in-non-parenthesis-expression.expected.js.todo b/test/comment/comment-as-first-element-in-non-parenthesis-expression.expected.js.todo new file mode 100644 index 00000000..da0e8d98 --- /dev/null +++ b/test/comment/comment-as-first-element-in-non-parenthesis-expression.expected.js.todo @@ -0,0 +1,14 @@ +// this test should pass, but it is not passing due to a bug +// https://github.com/estools/escodegen/issues/336 +// https://github.com/estools/escodegen/issues/435 + +function foo(x) { + return /* comment 1 */ x > 0 || // comment 2 + x < 5; +} + +function foo(x) { + return /* comment 1 */ x > 0 || + // comment 2 + x < 5; +} diff --git a/test/comment/comment-as-first-element-in-non-parenthesis-expression.js b/test/comment/comment-as-first-element-in-non-parenthesis-expression.js new file mode 100644 index 00000000..bc82a68c --- /dev/null +++ b/test/comment/comment-as-first-element-in-non-parenthesis-expression.js @@ -0,0 +1,10 @@ +function foo(x) { + return /* comment 1 */ x > 0 || // comment 2 + x < 5; +} + +function foo(x) { + return /* comment 1 */ x > 0 || + // comment 2 + x < 5; +} diff --git a/test/comment/comment-as-first-element-in-non-parenthesis-expression.js.todo b/test/comment/comment-as-first-element-in-non-parenthesis-expression.js.todo new file mode 100644 index 00000000..da0e8d98 --- /dev/null +++ b/test/comment/comment-as-first-element-in-non-parenthesis-expression.js.todo @@ -0,0 +1,14 @@ +// this test should pass, but it is not passing due to a bug +// https://github.com/estools/escodegen/issues/336 +// https://github.com/estools/escodegen/issues/435 + +function foo(x) { + return /* comment 1 */ x > 0 || // comment 2 + x < 5; +} + +function foo(x) { + return /* comment 1 */ x > 0 || + // comment 2 + x < 5; +} From 3f8ae4705037587060e93e6f07abd5b00ab70ff1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Lu=C4=8Div=C5=88=C3=A1k?= Date: Thu, 14 Jan 2021 09:35:00 +0100 Subject: [PATCH 26/26] remove unused function parameter --- escodegen.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/escodegen.js b/escodegen.js index 4c7534d5..49497eea 100644 --- a/escodegen.js +++ b/escodegen.js @@ -281,7 +281,7 @@ isParenthesized(str, '[', ']'); } - function shouldParenthesize(str, stmt, path) { + function shouldParenthesize(str, path) { if (!hasLineTerminator(str)) { return false; } @@ -812,7 +812,7 @@ hasLeadingComments = generatedLeadingComments || startsWithComment(result); var text = toSourceNodeWhenNeeded(result).toString(); - var parenthesize = shouldParenthesize(text, stmt, path); + var parenthesize = shouldParenthesize(text, path); if (!hasLeadingComments) { result = save;