Repository: prettier/prettier (JavaScript)

Issue:
line breaks after assignment instead of between parentheses / around parameters
### Discussed in https://github.com/prettier/prettier/discussions/15196

<div type='discussions-op-text'>

<sup>Originally posted by **macgyver** August  1, 2023</sup>
Just wondering if anybody can explain the formatting philosophy of converting a line like 
```js
  const { section, rubric, authors, tags } = await utils.upsertCommonData(mainData);
```

into this:
```js
  const { section, rubric, authors, tags } = await utils.upsertCommonData(
    mainData
  );
```

vs. this:
```js
  const { section, rubric, authors, tags } =
    await utils.upsertCommonData(mainData);
```

or even
```js
  const { section, rubric, authors, tags }
    = await utils.upsertCommonData(mainData);
```
(though I recognize that [putting operators at the start of a line](https://github.com/prettier/prettier/issues/3806) is controversial)

it seems like keeping the code on two lines vs. three is more parsimonious in terms of vertical space, and groups the concepts better by dividing the code neatly into variable names, and assigned values. Having  `mainData` dangling by itself at the end there just doesn't read that well (to me at least).

What do other folks think? Is there a bigger concept at play here that prevents this from being the behavior? Thanks for your time and insights.  

My guess is that Prettier is trying to produce the longest line it can without exceeding the maximum line length, but in cases like this my feeling is that balancing the length of the lines it produces or trying to reduce the total number of lines produced would be a _prettier_ result.</div>


Hints:

Patch:
diff --git a/src/language-js/print/assignment.js b/src/language-js/print/assignment.js
--- a/src/language-js/print/assignment.js
+++ b/src/language-js/print/assignment.js
@@ -205,7 +205,11 @@ function shouldBreakAfterOperator(path, options, print, hasShortKey) {
   let node = rightNode;
   const propertiesForPath = [];
   for (;;) {
-    if (node.type === "UnaryExpression") {
+    if (
+      node.type === "UnaryExpression" ||
+      node.type === "AwaitExpression" ||
+      (node.type === "YieldExpression" && node.argument !== null)
+    ) {
       node = node.argument;
       propertiesForPath.push("argument");
     } else if (node.type === "TSNonNullExpression") {


Test patch:
diff --git a/tests/format/js/assignment/__snapshots__/jsfmt.spec.js.snap b/tests/format/js/assignment/__snapshots__/jsfmt.spec.js.snap
--- a/tests/format/js/assignment/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/format/js/assignment/__snapshots__/jsfmt.spec.js.snap
@@ -278,6 +278,104 @@ printWidth: 80
 ================================================================================
 `;
 
+exports[`discussion-15196.js format 1`] = `
+====================================options=====================================
+parsers: ["babel", "flow", "typescript"]
+printWidth: 80
+                                                                                | printWidth
+=====================================input======================================
+async function f() {
+  const { section, rubric, authors, tags } = await utils.upsertCommonData(mainData);
+
+  const loooooooooooooooooooooooooong1 = await looooooooooooooong.looooooooooooooong.loooooong;
+  const loooooooooooooooooooooooooong2 = await looooooooooooooong.looooooooooooooong.loooooong();
+  const loooooooooooooooooooooooooong3 = await looooooooooooooooooooooooooooooooooooooooooooog();
+  const loooooooooooooooooooooooooong4 = !await looooooooooooooong.looooooooooooooong.loooooong;
+  const loooooooooooooooooooooooooong5 = void !!await looooooooooooooong.looooooooooooooong.loooooong;
+
+  const longlonglonglonglonglonglong1 = await new Promise((resolve, reject) => { setTimeout(() => { resolve('foo'); }, 300); })
+  const longlonglonglonglonglonglong2 = await { then(onFulfilled, onRejected) { onFulfilled(1234567890) } };
+}
+
+function* g() {
+  const { section, rubric, authors, tags } = yield utils.upsertCommonData(mainData);
+
+  const loooooooooooooooooooooooooong1 = yield looooooooooooooong.looooooooooooooong.loooooong;
+  const loooooooooooooooooooooooooong2 = yield looooooooooooooong.looooooooooooooong.loooooong();
+  const loooooooooooooooooooooooooong3 = yield looooooooooooooooooooooooooooooooooooooooooooog();
+  const loooooooooooooooooooooooooong4 = !(yield looooooooooooooong.looooooooooooooong.loooooong);
+  const loooooooooooooooooooooooooong5 = void !!(yield looooooooooooooong.looooooooooooooong.loooooong);
+  const loooooooooooooooooooooooooong6 = yield* looooooooooooooong.looooooooooooooong.loooooong;
+
+  const longlonglonglonglonglonglong1 = yield qwertyuiop(asdfghjkl, zxcvbnm, qwertyuiop, asdfghjkl);
+  const longlonglonglonglonglonglong2 = yield { qwertyuiop: 1234567890, asdfghjkl: 1234567890, zxcvbnm: 123456789 };
+
+  const x = yield;
+}
+
+=====================================output=====================================
+async function f() {
+  const { section, rubric, authors, tags } =
+    await utils.upsertCommonData(mainData);
+
+  const loooooooooooooooooooooooooong1 =
+    await looooooooooooooong.looooooooooooooong.loooooong;
+  const loooooooooooooooooooooooooong2 =
+    await looooooooooooooong.looooooooooooooong.loooooong();
+  const loooooooooooooooooooooooooong3 =
+    await looooooooooooooooooooooooooooooooooooooooooooog();
+  const loooooooooooooooooooooooooong4 =
+    !(await looooooooooooooong.looooooooooooooong.loooooong);
+  const loooooooooooooooooooooooooong5 =
+    void !!(await looooooooooooooong.looooooooooooooong.loooooong);
+
+  const longlonglonglonglonglonglong1 = await new Promise((resolve, reject) => {
+    setTimeout(() => {
+      resolve("foo");
+    }, 300);
+  });
+  const longlonglonglonglonglonglong2 = await {
+    then(onFulfilled, onRejected) {
+      onFulfilled(1234567890);
+    },
+  };
+}
+
+function* g() {
+  const { section, rubric, authors, tags } =
+    yield utils.upsertCommonData(mainData);
+
+  const loooooooooooooooooooooooooong1 =
+    yield looooooooooooooong.looooooooooooooong.loooooong;
+  const loooooooooooooooooooooooooong2 =
+    yield looooooooooooooong.looooooooooooooong.loooooong();
+  const loooooooooooooooooooooooooong3 =
+    yield looooooooooooooooooooooooooooooooooooooooooooog();
+  const loooooooooooooooooooooooooong4 =
+    !(yield looooooooooooooong.looooooooooooooong.loooooong);
+  const loooooooooooooooooooooooooong5 =
+    void !!(yield looooooooooooooong.looooooooooooooong.loooooong);
+  const loooooooooooooooooooooooooong6 =
+    yield* looooooooooooooong.looooooooooooooong.loooooong;
+
+  const longlonglonglonglonglonglong1 = yield qwertyuiop(
+    asdfghjkl,
+    zxcvbnm,
+    qwertyuiop,
+    asdfghjkl,
+  );
+  const longlonglonglonglonglonglong2 = yield {
+    qwertyuiop: 1234567890,
+    asdfghjkl: 1234567890,
+    zxcvbnm: 123456789,
+  };
+
+  const x = yield;
+}
+
+================================================================================
+`;
+
 exports[`issue-1419.js format 1`] = `
 ====================================options=====================================
 parsers: ["babel", "flow", "typescript"]
diff --git a/tests/format/js/assignment/discussion-15196.js b/tests/format/js/assignment/discussion-15196.js
new file mode 100644
--- /dev/null
+++ b/tests/format/js/assignment/discussion-15196.js
@@ -0,0 +1,28 @@
+async function f() {
+  const { section, rubric, authors, tags } = await utils.upsertCommonData(mainData);
+
+  const loooooooooooooooooooooooooong1 = await looooooooooooooong.looooooooooooooong.loooooong;
+  const loooooooooooooooooooooooooong2 = await looooooooooooooong.looooooooooooooong.loooooong();
+  const loooooooooooooooooooooooooong3 = await looooooooooooooooooooooooooooooooooooooooooooog();
+  const loooooooooooooooooooooooooong4 = !await looooooooooooooong.looooooooooooooong.loooooong;
+  const loooooooooooooooooooooooooong5 = void !!await looooooooooooooong.looooooooooooooong.loooooong;
+
+  const longlonglonglonglonglonglong1 = await new Promise((resolve, reject) => { setTimeout(() => { resolve('foo'); }, 300); })
+  const longlonglonglonglonglonglong2 = await { then(onFulfilled, onRejected) { onFulfilled(1234567890) } };
+}
+
+function* g() {
+  const { section, rubric, authors, tags } = yield utils.upsertCommonData(mainData);
+
+  const loooooooooooooooooooooooooong1 = yield looooooooooooooong.looooooooooooooong.loooooong;
+  const loooooooooooooooooooooooooong2 = yield looooooooooooooong.looooooooooooooong.loooooong();
+  const loooooooooooooooooooooooooong3 = yield looooooooooooooooooooooooooooooooooooooooooooog();
+  const loooooooooooooooooooooooooong4 = !(yield looooooooooooooong.looooooooooooooong.loooooong);
+  const loooooooooooooooooooooooooong5 = void !!(yield looooooooooooooong.looooooooooooooong.loooooong);
+  const loooooooooooooooooooooooooong6 = yield* looooooooooooooong.looooooooooooooong.loooooong;
+
+  const longlonglonglonglonglonglong1 = yield qwertyuiop(asdfghjkl, zxcvbnm, qwertyuiop, asdfghjkl);
+  const longlonglonglonglonglonglong2 = yield { qwertyuiop: 1234567890, asdfghjkl: 1234567890, zxcvbnm: 123456789 };
+
+  const x = yield;
+}