Repository: prettier/prettier (JavaScript)
Date: 2018-01-15 09:29:18+00:00
Task type: Bug Fix

Issue:
wrong indent (tab width) when using ternary in jsx
**Prettier 1.7.4**
[Playground link](https://prettier.io/playground/#N4Igxg9gdgLgprEAuc0DOMAEAxCFMC8mAFAJSEB8JAOlJvZgDwAmAlgG4W0M+bABmeQgSJQArgBsJ3XrID8maiCUzZPJJkH4RRGACcxcVWp4KlATThoVdE7w1KAchCUBfY4wD0bTrVIBuWhAAGhAIAAcYVnRkUABDDGR+OIk0OFCAIz04sABrOBgAZXCc1igAc2R9Q1DmCDAklLTQgCs0AA8AIWy8gsK4gFs4ABkyuEbU9LCxGHCZgCYJ5pASvTS9ZBAMuIyATwloEJW9MpgAdVZmGAALZAAWAAZQtIHWKoMptDLyiTgARTEEHgSymMB2FyutyQd1C+jirAk3wAwhABgM4psoNBxqExGkACo7NAg1yuIA)
```sh
--print-width 40
--tab-width 4
```

**Input:**
```jsx
const Foo = () => (
    <div>
        {foo === null
            ? ""
            : foo === true
              ? "Yes"
              : "No"}
    </div>
);

```

**Output:**
```jsx
const Foo = () => (
    <div>
        {foo === null
            ? ""
            : foo === true
              ? "Yes"
              : "No"}
    </div>
);

```

**Expected behavior:**
```diff
 const Foo = () => (
     <div>
         {foo === null
             ? ""
             : foo === true
-              ? "Yes"
-              : "No"}
+               ? "Yes"
+               : "No"}
     </div>
 );

```

BTW thank you all!


Issue discussion:
My guess is that only the “align with two spaces in ternaries” thing is done here, and we forgot to indent. Most tests use 2-space indentation, so this probably slipped through because of that...
@lydell great it should be easy to fix then :)
Similar to #2771

Solution patch:
diff --git a/src/language-js/printer-estree.js b/src/language-js/printer-estree.js
index 85b74ed568cb..38a5215b57d3 100644
--- a/src/language-js/printer-estree.js
+++ b/src/language-js/printer-estree.js
@@ -1259,7 +1259,7 @@ function printPathNoParens(path, options, print, args) {
         );
       } else {
         // normal mode
-        parts.push(
+        const part = concat([
           line,
           "? ",
           n.consequent.type === "ConditionalExpression" ? ifBreak("", "(") : "",
@@ -1268,6 +1268,12 @@ function printPathNoParens(path, options, print, args) {
           line,
           ": ",
           align(2, path.call(print, "alternate"))
+        ]);
+        parts.push(
+          // TODO: remove `!options.useTabs` condition if #3745 merged
+          parent.type === "ConditionalExpression" && !options.useTabs
+            ? align(Math.max(0, options.tabWidth - 2), part)
+            : part
         );
       }
 


Test patch:
diff --git a/tests/ternaries/__snapshots__/jsfmt.spec.js.snap b/tests/ternaries/__snapshots__/jsfmt.spec.js.snap
index 5eff19d98a66..34781507df8d 100644
--- a/tests/ternaries/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/ternaries/__snapshots__/jsfmt.spec.js.snap
@@ -105,8 +105,57 @@ room = room.map((row, rowIndex) =>
 
 `;
 
+exports[`binary.js 4`] = `
+const funnelSnapshotCard = (report === MY_OVERVIEW &&
+  !ReportGK.xar_metrics_active_capitol_v2) ||
+  (report === COMPANY_OVERVIEW &&
+    !ReportGK.xar_metrics_active_capitol_v2_company_metrics)
+  ? <ReportMetricsFunnelSnapshotCard metrics={metrics} />
+  : null;
+
+room = room.map((row, rowIndex) => (
+  row.map((col, colIndex) => (
+    (rowIndex === 0 || colIndex === 0 || rowIndex === height || colIndex === width) ? 1 : 0
+  ))
+))
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+const funnelSnapshotCard =
+	(report === MY_OVERVIEW && !ReportGK.xar_metrics_active_capitol_v2) ||
+	(report === COMPANY_OVERVIEW &&
+		!ReportGK.xar_metrics_active_capitol_v2_company_metrics) ? (
+		<ReportMetricsFunnelSnapshotCard metrics={metrics} />
+	) : null;
+
+room = room.map((row, rowIndex) =>
+	row.map(
+		(col, colIndex) =>
+			rowIndex === 0 ||
+			colIndex === 0 ||
+			rowIndex === height ||
+			colIndex === width
+				? 1
+				: 0
+	)
+);
+
+`;
+
 exports[`indent.js 1`] = `
 aaaaaaaaaaaaaaa ? bbbbbbbbbbbbbbbbbb : ccccccccccccccc ? ddddddddddddddd : eeeeeeeeeeeeeee ? fffffffffffffff : gggggggggggggggg
+
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+?
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+?
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+?
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+:
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+:
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+:
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 aaaaaaaaaaaaaaa
   ? bbbbbbbbbbbbbbbbbb
@@ -114,21 +163,98 @@ aaaaaaaaaaaaaaa
     ? ddddddddddddddd
     : eeeeeeeeeeeeeee ? fffffffffffffff : gggggggggggggggg;
 
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+  ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+    ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+      ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+      : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+    : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+  : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
+
 `;
 
 exports[`indent.js 2`] = `
 aaaaaaaaaaaaaaa ? bbbbbbbbbbbbbbbbbb : ccccccccccccccc ? ddddddddddddddd : eeeeeeeeeeeeeee ? fffffffffffffff : gggggggggggggggg
+
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+?
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+?
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+?
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+:
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+:
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+:
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 aaaaaaaaaaaaaaa
     ? bbbbbbbbbbbbbbbbbb
     : ccccccccccccccc
-      ? ddddddddddddddd
-      : eeeeeeeeeeeeeee ? fffffffffffffff : gggggggggggggggg;
+        ? ddddddddddddddd
+        : eeeeeeeeeeeeeee ? fffffffffffffff : gggggggggggggggg;
+
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+    ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+        ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+            ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+            : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+        : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+    : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
 
 `;
 
 exports[`indent.js 3`] = `
 aaaaaaaaaaaaaaa ? bbbbbbbbbbbbbbbbbb : ccccccccccccccc ? ddddddddddddddd : eeeeeeeeeeeeeee ? fffffffffffffff : gggggggggggggggg
+
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+?
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+?
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+?
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+:
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+:
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+:
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+aaaaaaaaaaaaaaa
+	? bbbbbbbbbbbbbbbbbb
+	: ccccccccccccccc
+		? ddddddddddddddd
+		: eeeeeeeeeeeeeee ? fffffffffffffff : gggggggggggggggg;
+
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+	? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+		? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+			? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+			: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+		: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+	: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
+
+`;
+
+exports[`indent.js 4`] = `
+aaaaaaaaaaaaaaa ? bbbbbbbbbbbbbbbbbb : ccccccccccccccc ? ddddddddddddddd : eeeeeeeeeeeeeee ? fffffffffffffff : gggggggggggggggg
+
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+?
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+?
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+?
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+:
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+:
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+:
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 aaaaaaaaaaaaaaa
 	? bbbbbbbbbbbbbbbbbb
@@ -136,6 +262,14 @@ aaaaaaaaaaaaaaa
 		? ddddddddddddddd
 		: eeeeeeeeeeeeeee ? fffffffffffffff : gggggggggggggggg;
 
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+	? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+		? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+			? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+			: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+		: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+	: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
+
 `;
 
 exports[`nested.js 1`] = `
@@ -174,6 +308,18 @@ let icecream =
 
 `;
 
+exports[`nested.js 4`] = `
+let icecream = what == "cone"
+  ? p => !!p ? \`here's your \${p} cone\` : \`just the empty cone for you\`
+  : p => \`here's your \${p} \${what}\`;
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+let icecream =
+	what == "cone"
+		? p => (!!p ? \`here's your \${p} cone\` : \`just the empty cone for you\`)
+		: p => \`here's your \${p} \${what}\`;
+
+`;
+
 exports[`parenthesis.js 1`] = `
 debug ? this.state.isVisible ? "partially visible" : "hidden" : null;
 debug ? this.state.isVisible && somethingComplex ? "partially visible" : "hidden" : null;
@@ -255,6 +401,33 @@ a =>
 
 `;
 
+exports[`parenthesis.js 4`] = `
+debug ? this.state.isVisible ? "partially visible" : "hidden" : null;
+debug ? this.state.isVisible && somethingComplex ? "partially visible" : "hidden" : null;
+
+a => a ? () => {a} : () => {a}
+a => a ? a : a
+a => a ? aasdasdasdasdasdasdaaasdasdasdasdasdasdasdasdasdasdasdasdasdaaaaaa : a
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+debug ? (this.state.isVisible ? "partially visible" : "hidden") : null;
+debug
+	? this.state.isVisible && somethingComplex ? "partially visible" : "hidden"
+	: null;
+
+a =>
+	a
+		? () => {
+				a;
+			}
+		: () => {
+				a;
+			};
+a => (a ? a : a);
+a =>
+	a ? aasdasdasdasdasdasdaaasdasdasdasdasdasdasdasdasdasdasdasdasdaaaaaa : a;
+
+`;
+
 exports[`test.js 1`] = `
 const obj0 = conditionIsTruthy ? shortThing : otherShortThing
 
@@ -410,3 +583,55 @@ const obj5 = conditionIsTruthy
 		};
 
 `;
+
+exports[`test.js 4`] = `
+const obj0 = conditionIsTruthy ? shortThing : otherShortThing
+
+const obj1 = conditionIsTruthy ? { some: 'long', object: 'with', lots: 'of', stuff } : shortThing
+
+const obj2 = conditionIsTruthy ? shortThing : { some: 'long', object: 'with', lots: 'of', stuff }
+
+const obj3 = conditionIsTruthy ? { some: 'eeeeeeeeeeeeven looooooooooooooooooooooooooooooonger', object: 'with', lots: 'of', stuff } : shortThing
+
+const obj4 = conditionIsTruthy ? shortThing : { some: 'eeeeeeeeeeeeven looooooooooooooooooooooooooooooonger', object: 'with', lots: 'of', stuff }
+
+const obj5 = conditionIsTruthy ? { some: 'long', object: 'with', lots: 'of', stuff } : { some: 'eeeeeeeeeeeeven looooooooooooooooooooooooooooooonger', object: 'with', lots: 'of', stuff }
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+const obj0 = conditionIsTruthy ? shortThing : otherShortThing;
+
+const obj1 = conditionIsTruthy
+	? { some: "long", object: "with", lots: "of", stuff }
+	: shortThing;
+
+const obj2 = conditionIsTruthy
+	? shortThing
+	: { some: "long", object: "with", lots: "of", stuff };
+
+const obj3 = conditionIsTruthy
+	? {
+			some: "eeeeeeeeeeeeven looooooooooooooooooooooooooooooonger",
+			object: "with",
+			lots: "of",
+			stuff
+		}
+	: shortThing;
+
+const obj4 = conditionIsTruthy
+	? shortThing
+	: {
+			some: "eeeeeeeeeeeeven looooooooooooooooooooooooooooooonger",
+			object: "with",
+			lots: "of",
+			stuff
+		};
+
+const obj5 = conditionIsTruthy
+	? { some: "long", object: "with", lots: "of", stuff }
+	: {
+			some: "eeeeeeeeeeeeven looooooooooooooooooooooooooooooonger",
+			object: "with",
+			lots: "of",
+			stuff
+		};
+
+`;
diff --git a/tests/ternaries/indent.js b/tests/ternaries/indent.js
index b6b2380b290e..8481f285a5ca 100644
--- a/tests/ternaries/indent.js
+++ b/tests/ternaries/indent.js
@@ -1,1 +1,15 @@
 aaaaaaaaaaaaaaa ? bbbbbbbbbbbbbbbbbb : ccccccccccccccc ? ddddddddddddddd : eeeeeeeeeeeeeee ? fffffffffffffff : gggggggggggggggg
+
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+?
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+?
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+?
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+:
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+:
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+:
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
diff --git a/tests/ternaries/jsfmt.spec.js b/tests/ternaries/jsfmt.spec.js
index db53feeb1b17..3f4ea6ad5241 100644
--- a/tests/ternaries/jsfmt.spec.js
+++ b/tests/ternaries/jsfmt.spec.js
@@ -1,3 +1,4 @@
 run_spec(__dirname, ["flow", "typescript"]);
 run_spec(__dirname, ["flow", "typescript"], { tabWidth: 4 });
 run_spec(__dirname, ["flow", "typescript"], { useTabs: true });
+run_spec(__dirname, ["flow", "typescript"], { useTabs: true, tabWidth: 4 });