diff --git a/changelog_unreleased/javascript/13438.md b/changelog_unreleased/javascript/13438.md new file mode 100644 index 000000000..b2e2d52f2 --- /dev/null +++ b/changelog_unreleased/javascript/13438.md @@ -0,0 +1,16 @@ +#### Fix interleaved comments (#13438 by @thorn0) + + +```js +// Input +function x() { +} // first +; // second + +// Prettier stable +function x() {} // first // second + +// Prettier main +function x() {} // first +// second +``` diff --git a/src/language-js/print/comment.js b/src/language-js/print/comment.js index 3b3b4d33d..1215580af 100644 --- a/src/language-js/print/comment.js +++ b/src/language-js/print/comment.js @@ -1,4 +1,3 @@ -import { hasNewline } from "../../common/util.js"; import { join, hardline } from "../../document/builders.js"; import { replaceEndOfLine } from "../../document/utils.js"; @@ -18,19 +17,7 @@ function printComment(commentPath, options) { if (isBlockComment(comment)) { if (isIndentableBlockComment(comment)) { - const printed = printIndentableBlockComment(comment); - // We need to prevent an edge case of a previous trailing comment - // printed as a `lineSuffix` which causes the comments to be - // interleaved. See https://github.com/prettier/prettier/issues/4412 - if ( - comment.trailing && - !hasNewline(options.originalText, locStart(comment), { - backwards: true, - }) - ) { - return [hardline, printed]; - } - return printed; + return printIndentableBlockComment(comment); } const commentEnd = locEnd(comment); diff --git a/src/main/comments.js b/src/main/comments.js index a3a719f5d..1825daecf 100644 --- a/src/main/comments.js +++ b/src/main/comments.js @@ -461,14 +461,17 @@ function printLeadingComment(path, options) { return parts; } -function printTrailingComment(path, options) { +function printTrailingComment(path, options, previousComment) { const comment = path.getValue(); const printed = printComment(path, options); const { printer, originalText, locStart } = options; - const isBlock = printer.isBlockComment && printer.isBlockComment(comment); + const isBlock = printer.isBlockComment?.(comment); - if (hasNewline(originalText, locStart(comment), { backwards: true })) { + if ( + (previousComment?.hasLineSuffix && !previousComment?.isBlock) || + hasNewline(originalText, locStart(comment), { backwards: true }) + ) { // This allows comments at the end of nested structures: // { // x: 1, @@ -487,17 +490,22 @@ function printTrailingComment(path, options) { locStart ); - return lineSuffix([hardline, isLineBeforeEmpty ? hardline : "", printed]); + return { + doc: lineSuffix([hardline, isLineBeforeEmpty ? hardline : "", printed]), + isBlock, + hasLineSuffix: true, + }; } - let parts = [" ", printed]; - - // Trailing block comments never need a newline - if (!isBlock) { - parts = [lineSuffix(parts), breakParent]; + if (!isBlock || previousComment?.hasLineSuffix) { + return { + doc: [lineSuffix([" ", printed]), breakParent], + isBlock, + hasLineSuffix: true, + }; } - return parts; + return { doc: [" ", printed], isBlock, hasLineSuffix: false }; } function printDanglingComments(path, options, sameIndent, filter) { @@ -544,6 +552,7 @@ function printCommentsSeparately(path, options, ignored) { const leadingParts = []; const trailingParts = []; + let printedTrailingComment; path.each(() => { const comment = path.getValue(); if (ignored && ignored.has(comment)) { @@ -554,7 +563,12 @@ function printCommentsSeparately(path, options, ignored) { if (leading) { leadingParts.push(printLeadingComment(path, options)); } else if (trailing) { - trailingParts.push(printTrailingComment(path, options)); + printedTrailingComment = printTrailingComment( + path, + options, + printedTrailingComment + ); + trailingParts.push(printedTrailingComment.doc); } }, "comments"); diff --git a/tests/format/js/comments/__snapshots__/jsfmt.spec.js.snap b/tests/format/js/comments/__snapshots__/jsfmt.spec.js.snap index 9f5f3c984..17507615b 100644 --- a/tests/format/js/comments/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/js/comments/__snapshots__/jsfmt.spec.js.snap @@ -1444,6 +1444,101 @@ const test = "💖"; ================================================================================ `; +exports[`empty-statements.js - {"semi":false} format 1`] = ` +====================================options===================================== +parsers: ["babel", "flow", "typescript"] +printWidth: 80 +semi: false + | printWidth +=====================================input====================================== +a; /* a */ // b +; /* c */ + +foo; // first +;// second +;// third + +function x() { +} // first +; // second + +a = ( + b // 1 + + // 2 + c // 3 + + // 4 + d // 5 + + /* 6 */ + e // 7 +); + +=====================================output===================================== +a /* a */ // b +/* c */ +foo // first +// second +// third +function x() {} // first +// second +a = + b + // 1 + // 2 + c + // 3 + // 4 + d + // 5 + /* 6 */ + e // 7 + +================================================================================ +`; + +exports[`empty-statements.js format 1`] = ` +====================================options===================================== +parsers: ["babel", "flow", "typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +a; /* a */ // b +; /* c */ + +foo; // first +;// second +;// third + +function x() { +} // first +; // second + +a = ( + b // 1 + + // 2 + c // 3 + + // 4 + d // 5 + + /* 6 */ + e // 7 +); + +=====================================output===================================== +a; /* a */ // b +/* c */ +foo; // first +// second +// third +function x() {} // first +// second +a = + b + // 1 + // 2 + c + // 3 + // 4 + d + // 5 + /* 6 */ + e; // 7 + +================================================================================ +`; + exports[`export.js - {"semi":false} format 1`] = ` ====================================options===================================== parsers: ["babel", "flow", "typescript"] @@ -3189,8 +3284,7 @@ onClick={() => {}}> ;
{ - a - /* comment + a /* comment */ }
@@ -3430,8 +3524,7 @@ onClick={() => {}}>
{ - a - /* comment + a /* comment */ }
; @@ -3924,8 +4017,7 @@ a b a /* -1*/ /*2*/ -/*3 +1*/ /*2*/ /*3 */ b @@ -4116,8 +4208,7 @@ a; b; a; /* -1*/ /*2*/ -/*3 +1*/ /*2*/ /*3 */ b; @@ -5489,11 +5580,9 @@ const CONNECTION_STATUS = (exports.CONNECTION_STATUS = { NOT_CONNECTED: Object.freeze({ kind: "NOT_CONNECTED" }), }) -/* A comment */ -/** +/* A comment */ /** * A type that can be written to a buffer. - */ -/** + */ /** * Describes the connection status of a ReactiveSocket/DuplexConnection. * - NOT_CONNECTED: no connection established or pending. * - CONNECTING: when \`connect()\` has been called but a connection is not yet @@ -5501,12 +5590,10 @@ const CONNECTION_STATUS = (exports.CONNECTION_STATUS = { * - CONNECTED: when a connection is established. * - CLOSED: when the connection has been explicitly closed via \`close()\`. * - ERROR: when the connection has been closed for any other reason. - */ -/** + */ /** * A contract providing different interaction models per the [ReactiveSocket protocol] * (https://github.com/ReactiveSocket/reactivesocket/blob/master/Protocol.md). - */ -/** + */ /** * A single unit of data exchanged between the peers of a \`ReactiveSocket\`. */ @@ -5550,11 +5637,9 @@ const CONNECTION_STATUS = (exports.CONNECTION_STATUS = { NOT_CONNECTED: Object.freeze({ kind: "NOT_CONNECTED" }), }); -/* A comment */ -/** +/* A comment */ /** * A type that can be written to a buffer. - */ -/** + */ /** * Describes the connection status of a ReactiveSocket/DuplexConnection. * - NOT_CONNECTED: no connection established or pending. * - CONNECTING: when \`connect()\` has been called but a connection is not yet @@ -5562,12 +5647,10 @@ const CONNECTION_STATUS = (exports.CONNECTION_STATUS = { * - CONNECTED: when a connection is established. * - CLOSED: when the connection has been explicitly closed via \`close()\`. * - ERROR: when the connection has been closed for any other reason. - */ -/** + */ /** * A contract providing different interaction models per the [ReactiveSocket protocol] * (https://github.com/ReactiveSocket/reactivesocket/blob/master/Protocol.md). - */ -/** + */ /** * A single unit of data exchanged between the peers of a \`ReactiveSocket\`. */ diff --git a/tests/format/js/comments/empty-statements.js b/tests/format/js/comments/empty-statements.js new file mode 100644 index 000000000..c2386508a --- /dev/null +++ b/tests/format/js/comments/empty-statements.js @@ -0,0 +1,20 @@ +a; /* a */ // b +; /* c */ + +foo; // first +;// second +;// third + +function x() { +} // first +; // second + +a = ( + b // 1 + + // 2 + c // 3 + + // 4 + d // 5 + + /* 6 */ + e // 7 +);