Repository: prettier/prettier (JavaScript)

Issue:
Assignment of template literal to indexed access property causes odd formatting
I noticed today that assigning a template literal string to an indexed access property of an object can lead to odd formatting where the property access is broken into many lines.

This does not happen if 1) dot property access is used instead or 2) the RHS string literal uses normal quotes instead of template literal quotes.

Thanks for considering this issue!

**Prettier 3.0.3**
[Playground link](https://prettier.io/playground/#N4Igxg9gdgLgprEAuEAHAhgJ3QWwM4DaAOiJnACYCWZYMAKhCQLoAEAvCwAYAkwA7pSjkIfAHQAbCGHQxK0URhgALKLjgBfXgKEiJUmXKii8cLGCWb+g4WMnTZ8pejwXOAbhAAaEBFQOoeMigWJgiAApYCIEo6OJ86ACegd4ARthgANZwMADKagAygnDIAGaxJqnpWbkYYIIA5sgwmACucN4mOJRNre0geA3icACKLRDwpeV9AFZ4AB45gyNjE0hl4hUgAI4rcGGhqNEgzgC0UHAUFF4gzeiU4g0AwhA4OOjIx+Li1wNQ9UMAQRgzUoKRa8DCcEwhXOkw2fSUMBw4gA6kpKPA8LU4DkohjKAA3DEJD5gPDJEAEtoASSECFyYEwlD8AKEORgCSGcM2qFCJhR2FQH15cBMmAJxW8gjFMH26Hqb25fQwmDFHxS6BScG+3l5ghgKMo5GUyAAHAAGbxkHbUPbYBXvNZTbwwTWG41KZAAJm8LRMdE10XWmzgOC15HIFHy6D+LXlcAAYhBMG9gQ0PuhwRAQOp1EA)
<!-- prettier-ignore -->
```sh
--parser babel
```

**Input:**
<!-- prettier-ignore -->
```jsx
params["redirectTo"] = `${window.location.pathname}${window.location.search}${window.location.hash}`;
```

**Output:**
<!-- prettier-ignore -->
```jsx
params[
  "redirectTo"
] = `${window.location.pathname}${window.location.search}${window.location.hash}`;
```

**Expected behavior:**
<!-- prettier-ignore -->
```jsx
params["redirectTo"] = 
  `${window.location.pathname}${window.location.search}${window.location.hash}`;
```



Hints:
As a temporary solution do `params.redirectTo`. Might be short enough to wrap around

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
@@ -141,11 +141,13 @@ function chooseLayout(path, options, print, leftDoc, rightPropertyName) {
     return "never-break-after-operator";
   }
 
+  const canBreakLeftDoc = canBreak(leftDoc);
+
   if (
     isComplexDestructuring(node) ||
     isComplexTypeAliasParams(node) ||
     hasComplexTypeAnnotation(node) ||
-    (isArrowFunctionVariableDeclarator(node) && canBreak(leftDoc))
+    (isArrowFunctionVariableDeclarator(node) && canBreakLeftDoc)
   ) {
     return "break-lhs";
   }
@@ -163,12 +165,13 @@ function chooseLayout(path, options, print, leftDoc, rightPropertyName) {
   }
 
   if (
-    hasShortKey ||
-    rightNode.type === "TemplateLiteral" ||
-    rightNode.type === "TaggedTemplateExpression" ||
-    rightNode.type === "BooleanLiteral" ||
-    isNumericLiteral(rightNode) ||
-    rightNode.type === "ClassExpression"
+    !canBreakLeftDoc &&
+    (hasShortKey ||
+      rightNode.type === "TemplateLiteral" ||
+      rightNode.type === "TaggedTemplateExpression" ||
+      rightNode.type === "BooleanLiteral" ||
+      isNumericLiteral(rightNode) ||
+      rightNode.type === "ClassExpression")
   ) {
     return "never-break-after-operator";
   }


Test patch:
diff --git a/tests/format/angular/angular/__snapshots__/jsfmt.spec.js.snap b/tests/format/angular/angular/__snapshots__/jsfmt.spec.js.snap
--- a/tests/format/angular/angular/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/format/angular/angular/__snapshots__/jsfmt.spec.js.snap
@@ -1147,7 +1147,8 @@ printWidth: 1
   (target)="
     a[
       b
-    ] = 1
+    ] =
+      1
   "
   (target)="
     (a) // hello
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
@@ -784,6 +784,33 @@ const { _id: id3 } =
 ================================================================================
 `;
 
+exports[`issue-15534.js format 1`] = `
+====================================options=====================================
+parsers: ["babel", "flow", "typescript"]
+printWidth: 80
+                                                                                | printWidth
+=====================================input======================================
+params["redirectTo"] = \`\${window.location.pathname}\${window.location.search}\${window.location.hash}\`;
+
+params["redirectTo"]["codePointAt"]["name"] =
+  \`\${window.location.pathname}\${window.location.search}\${window.location.hash}\`;
+
+params.redirectTo.bar.bar.ba.barab["foo"].abr =
+  \`\${window.location.pathname}\${window.location.search}\${window.location.hash}\`;
+
+=====================================output=====================================
+params["redirectTo"] =
+  \`\${window.location.pathname}\${window.location.search}\${window.location.hash}\`;
+
+params["redirectTo"]["codePointAt"]["name"] =
+  \`\${window.location.pathname}\${window.location.search}\${window.location.hash}\`;
+
+params.redirectTo.bar.bar.ba.barab["foo"].abr =
+  \`\${window.location.pathname}\${window.location.search}\${window.location.hash}\`;
+
+================================================================================
+`;
+
 exports[`lone-arg.js format 1`] = `
 ====================================options=====================================
 parsers: ["babel", "flow", "typescript"]
diff --git a/tests/format/js/assignment/issue-15534.js b/tests/format/js/assignment/issue-15534.js
new file mode 100644
--- /dev/null
+++ b/tests/format/js/assignment/issue-15534.js
@@ -0,0 +1,7 @@
+params["redirectTo"] = `${window.location.pathname}${window.location.search}${window.location.hash}`;
+
+params["redirectTo"]["codePointAt"]["name"] =
+  `${window.location.pathname}${window.location.search}${window.location.hash}`;
+
+params.redirectTo.bar.bar.ba.barab["foo"].abr =
+  `${window.location.pathname}${window.location.search}${window.location.hash}`;