diff --git a/changelog_unreleased/javascript/18615-2.md b/changelog_unreleased/javascript/18615-2.md
new file mode 100644
index 000000000..e79990344
--- /dev/null
+++ b/changelog_unreleased/javascript/18615-2.md
@@ -0,0 +1,53 @@
+#### Improve comment handling around empty call argument list (#18615 by @fisker)
+
+
+```jsx
+// Input
+call
+// line comment
+();
+call(// line comment
+);
+call(
+ // line comment
+);
+
+call
+/* block comment */
+();
+call(/* block comment */
+);
+call(
+ /* block comment */
+);
+
+// Prettier stable
+call();
+// line comment
+call(); // line comment
+call();
+// line comment
+
+call();
+/* block comment */
+call /* block comment */();
+call();
+/* block comment */
+
+// Prettier main
+call
+// line comment
+();
+call(
+ // line comment
+);
+call(
+ // line comment
+);
+
+call
+/* block comment */
+();
+call(/* block comment */);
+call(/* block comment */);
+```
diff --git a/changelog_unreleased/javascript/18615-3.md b/changelog_unreleased/javascript/18615-3.md
new file mode 100644
index 000000000..33379c67b
--- /dev/null
+++ b/changelog_unreleased/javascript/18615-3.md
@@ -0,0 +1,21 @@
+#### Fix unstable comment in call expression (#18615 by @fisker)
+
+
+```jsx
+// Input
+foo =
+ call(
+ /* call argument */);
+
+// Prettier stable (First format)
+foo =
+ call();
+ /* call argument */
+
+// Prettier stable (Second format)
+foo = call();
+/* call argument */
+
+// Prettier main
+foo = call(/* call argument */);
+```
diff --git a/changelog_unreleased/javascript/18615.md b/changelog_unreleased/javascript/18615.md
new file mode 100644
index 000000000..b650a00d6
--- /dev/null
+++ b/changelog_unreleased/javascript/18615.md
@@ -0,0 +1,29 @@
+#### Allow empty call expression argument list with long comments to break (#18615 by @fisker)
+
+
+```jsx
+// Input
+call(/* a long long long long long long long long long long long long comment */);
+array = [/* a long long long long long long long long long long long long comment */];
+object = {/* a long long long long long long long long long long long long comment */};
+
+// Prettier stable
+call(/* a long long long long long long long long long long long long comment */);
+array = [
+ /* a long long long long long long long long long long long long comment */
+];
+object = {
+ /* a long long long long long long long long long long long long comment */
+};
+
+// Prettier main
+call(
+ /* a long long long long long long long long long long long long comment */
+);
+array = [
+ /* a long long long long long long long long long long long long comment */
+];
+object = {
+ /* a long long long long long long long long long long long long comment */
+};
+```
diff --git a/src/language-js/comments/handle-comments.js b/src/language-js/comments/handle-comments.js
index bbbe73736..a7cd47a44 100644
--- a/src/language-js/comments/handle-comments.js
+++ b/src/language-js/comments/handle-comments.js
@@ -82,6 +82,7 @@ function handleOwnLineComment(context) {
handleCommentsInDestructuringPattern,
handleTSMappedTypeComments,
handleBinaryCastExpressionComment,
+ handleCommentInEmptyParens,
].some((fn) => fn(context));
}
@@ -112,6 +113,7 @@ function handleEndOfLineComment(context) {
handleCommentAfterArrowExpression,
handlePropertySignatureComments,
handleBinaryCastExpressionComment,
+ handleCommentInEmptyParens,
].some((fn) => fn(context));
}
@@ -635,10 +637,14 @@ function handleCommentInEmptyParens({ comment, enclosingNode, options }) {
return false;
}
+ // This condition should be removed, but excluded for function parameters in #18615 to make PRs smaller
+ const isRemainingComment = comment.placement === "remaining";
+
// Only add dangling comments to fix the case when no params are present,
// i.e. a function without any argument.
if (
- ((isRealFunctionLikeNode(enclosingNode) &&
+ ((isRemainingComment &&
+ isRealFunctionLikeNode(enclosingNode) &&
getFunctionParameters(enclosingNode).length === 0) ||
(isCallLikeExpression(enclosingNode) &&
getCallArguments(enclosingNode).length === 0)) &&
@@ -649,6 +655,7 @@ function handleCommentInEmptyParens({ comment, enclosingNode, options }) {
}
if (
+ isRemainingComment &&
(enclosingNode.type === "MethodDefinition" ||
enclosingNode.type === "TSAbstractMethodDefinition") &&
getFunctionParameters(enclosingNode.value).length === 0 &&
diff --git a/src/language-js/print/call-arguments.js b/src/language-js/print/call-arguments.js
index c076fc87c..01bce68b5 100644
--- a/src/language-js/print/call-arguments.js
+++ b/src/language-js/print/call-arguments.js
@@ -49,8 +49,23 @@ function printCallArguments(path, options, print) {
const { node } = path;
const args = getCallArguments(node);
+
if (args.length === 0) {
- return ["(", printDanglingComments(path, options), ")"];
+ return group([
+ "(",
+ hasComment(node, CommentCheckFlags.Dangling)
+ ? [
+ indent([softline, printDanglingComments(path, options)]),
+ hasComment(
+ node,
+ CommentCheckFlags.Dangling | CommentCheckFlags.Line,
+ )
+ ? hardline
+ : softline,
+ ]
+ : [],
+ ")",
+ ]);
}
const lastArgIndex = args.length - 1;
diff --git a/src/language-js/print/call-expression.js b/src/language-js/print/call-expression.js
index d199510e5..5dd726f0c 100644
--- a/src/language-js/print/call-expression.js
+++ b/src/language-js/print/call-expression.js
@@ -1,4 +1,4 @@
-import { group, join } from "../../document/index.js";
+import { group, join, lineSuffixBoundary } from "../../document/index.js";
import needsParentheses from "../parentheses/needs-parentheses.js";
import {
getCallArguments,
@@ -93,6 +93,7 @@ function printCallExpression(path, options, print) {
printCallee(path, print),
optional,
typeArgumentsDoc,
+ lineSuffixBoundary,
printCallArguments(path, options, print),
];
diff --git a/tests/config/run-format-test.js b/tests/config/run-format-test.js
index 780c39142..921b00d63 100644
--- a/tests/config/run-format-test.js
+++ b/tests/config/run-format-test.js
@@ -27,7 +27,6 @@ const unstableTests = new Map(
"js/comments/return-statement.js",
"js/comments/tagged-template-literal.js",
"js/for/9812-unstable.js",
- "js/comments/in-list/dangling-comment-in-list.js",
[
"js/multiparser-markdown/codeblock.js",
(options) => options.proseWrap === "always",
diff --git a/tests/format/js/call/no-argument/__snapshots__/format.test.js.snap b/tests/format/js/call/no-argument/__snapshots__/format.test.js.snap
index 881f34e8a..1df42afa4 100644
--- a/tests/format/js/call/no-argument/__snapshots__/format.test.js.snap
+++ b/tests/format/js/call/no-argument/__snapshots__/format.test.js.snap
@@ -1,5 +1,112 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
+exports[`no-arguments.js format 1`] = `
+====================================options=====================================
+parsers: ["babel", "flow", "typescript"]
+printWidth: 80
+ | printWidth
+=====================================input======================================
+call// 101
+()
+call
+// 102
+()
+call(// 103
+ )
+call
+ (// 104
+ )
+call(
+ // 105
+ )
+call// 106
+?.(
+ )
+call// 107
+?.(
+ )
+call?.// 108
+(
+ )
+
+call/* 201 */
+()
+call
+/* 202 */
+()
+call/* 203 */()
+call(/* 204 */
+ )
+call(
+ /* 205 */
+ )
+call/* 206 */?.
+()
+call/* 207 */
+?.
+()
+call
+/* 208 */?.
+()
+
+call/* 209 */
+?.
+()
+call?./* 210 */
+()
+call
+?./* 211 */
+()
+call
+?.
+/* 212 */
+()
+
+=====================================output=====================================
+call // 101
+();
+call
+// 102
+();
+call(
+ // 103
+);
+call(
+ // 104
+);
+call(
+ // 105
+);
+call?. // 106
+();
+call?. // 107
+();
+call?. // 108
+();
+
+call /* 201 */();
+call
+/* 202 */
+();
+call /* 203 */();
+call(/* 204 */);
+call(/* 205 */);
+call /* 206 */?.();
+call /* 207 */?.();
+call?.
+/* 208 */
+();
+
+call /* 209 */?.();
+call /* 210 */?.();
+call /* 211 */?.();
+call?.
+/* 212 */
+();
+
+================================================================================
+`;
+
exports[`special-cases.js format 1`] = `
====================================options=====================================
parsers: ["babel", "flow", "typescript"]
diff --git a/tests/format/js/call/no-argument/no-arguments.js b/tests/format/js/call/no-argument/no-arguments.js
new file mode 100644
index 000000000..8d428999d
--- /dev/null
+++ b/tests/format/js/call/no-argument/no-arguments.js
@@ -0,0 +1,55 @@
+call// 101
+()
+call
+// 102
+()
+call(// 103
+ )
+call
+ (// 104
+ )
+call(
+ // 105
+ )
+call// 106
+?.(
+ )
+call// 107
+?.(
+ )
+call?.// 108
+(
+ )
+
+call/* 201 */
+()
+call
+/* 202 */
+()
+call/* 203 */()
+call(/* 204 */
+ )
+call(
+ /* 205 */
+ )
+call/* 206 */?.
+()
+call/* 207 */
+?.
+()
+call
+/* 208 */?.
+()
+
+call/* 209 */
+?.
+()
+call?./* 210 */
+()
+call
+?./* 211 */
+()
+call
+?.
+/* 212 */
+()
diff --git a/tests/format/js/comments/in-list/__snapshots__/format.test.js.snap b/tests/format/js/comments/in-list/__snapshots__/format.test.js.snap
index 4a973e97c..3f1a1cc7c 100644
--- a/tests/format/js/comments/in-list/__snapshots__/format.test.js.snap
+++ b/tests/format/js/comments/in-list/__snapshots__/format.test.js.snap
@@ -12,13 +12,13 @@ call = call(/* call argument */)
fn = function(/* function parameter */) {}
newFoo = new Foo(/* new argument */)
-// TODO[@fisker]: fix the following
array = [
/* array */]
object = {
/* object */}
call = call(
/* call argument */)
+// TODO[@fisker]: fix this
fn = function(
/* function parameter */) {}
newFoo = new Foo
@@ -27,6 +27,7 @@ newFoo = new Foo
array = [/* array long long long long long long long long long long long long long long */]
object = {/* object long long long long long long long long long long long long long long */}
call = call(/* call argument long long long long long long long long long long long long long long */)
+// TODO[@fisker]: fix this
fn = function (/* function long parameter long long long long long long long long long long long long long */) {}
newFoo = new Foo(/* new argument long long long long long long long long long long long long long long */)
@@ -37,12 +38,10 @@ call = call(/* call argument */);
fn = function (/* function parameter */) {};
newFoo = new Foo(/* new argument */);
-// TODO[@fisker]: fix the following
array = [/* array */];
object = {/* object */};
-call =
- call();
- /* call argument */
+call = call(/* call argument */);
+// TODO[@fisker]: fix this
fn = function () /* function parameter */ {};
newFoo = new Foo(/* new argument */);
@@ -53,11 +52,15 @@ object = {
/* object long long long long long long long long long long long long long long */
};
call =
- call(/* call argument long long long long long long long long long long long long long long */);
+ call(
+ /* call argument long long long long long long long long long long long long long long */
+ );
+// TODO[@fisker]: fix this
fn =
function (/* function long parameter long long long long long long long long long long long long long */) {};
-newFoo =
- new Foo(/* new argument long long long long long long long long long long long long long long */);
+newFoo = new Foo(
+ /* new argument long long long long long long long long long long long long long long */
+);
================================================================================
`;
diff --git a/tests/format/js/comments/in-list/dangling-comment-in-list.js b/tests/format/js/comments/in-list/dangling-comment-in-list.js
index 46c665cf1..32f33773a 100644
--- a/tests/format/js/comments/in-list/dangling-comment-in-list.js
+++ b/tests/format/js/comments/in-list/dangling-comment-in-list.js
@@ -4,13 +4,13 @@ call = call(/* call argument */)
fn = function(/* function parameter */) {}
newFoo = new Foo(/* new argument */)
-// TODO[@fisker]: fix the following
array = [
/* array */]
object = {
/* object */}
call = call(
/* call argument */)
+// TODO[@fisker]: fix this
fn = function(
/* function parameter */) {}
newFoo = new Foo
@@ -19,5 +19,6 @@ newFoo = new Foo
array = [/* array long long long long long long long long long long long long long long */]
object = {/* object long long long long long long long long long long long long long long */}
call = call(/* call argument long long long long long long long long long long long long long long */)
+// TODO[@fisker]: fix this
fn = function (/* function long parameter long long long long long long long long long long long long long */) {}
newFoo = new Foo(/* new argument long long long long long long long long long long long long long long */)
diff --git a/tests/format/typescript/comments/__snapshots__/format.test.js.snap b/tests/format/typescript/comments/__snapshots__/format.test.js.snap
index b755fabe0..f08ae0fc8 100644
--- a/tests/format/typescript/comments/__snapshots__/format.test.js.snap
+++ b/tests/format/typescript/comments/__snapshots__/format.test.js.snap
@@ -1364,7 +1364,8 @@ interface Foo {
=====================================output=====================================
functionName();
-functionName(); // comment
+functionName // comment
+();
interface Foo {
<
A, // comment