Repository: prettier/prettier (JavaScript)
Date: 2017-01-15 01:50:04+00:00
Task type: Bug Fix

Issue:
Arrow functions which return object literals unnecessarily break
I tried this example:
```
export const setProp = y => ({
  ...y,
  a: 'very, very, very long text'
});

export const log = y => {
  console.log('very, very, very long text')
};
```
For printWidth: 40, prettier outputs:
```
export const setProp = y =>
  ({
    ...y,
    a: "very, very, very long text"
  });

export const log = y => {
  console.log(
    "very, very, very long text"
  );
};
```

I'm not sure if it is intentional, but it seems that brackets break the last function argument rule. I would prefer:
```
export const setProp = y => ({
  ...y,
  a: "very, very, very long text"
});

export const log = y => {
  console.log(
    "very, very, very long text"
  );
};
```
[Example](https://jlongster.github.io/prettier/#%7B%22content%22%3A%22export%20const%20setProp%20%3D%20y%20%3D%3E%20(%7B%5Cn%20%20...y%2C%5Cn%20%20a%3A%20'very%2C%20very%2C%20very%20long%20text'%5Cn%7D)%3B%5Cn%5Cnexport%20const%20log%20%3D%20y%20%3D%3E%20%7B%5Cn%20%20console.log('very%2C%20very%2C%20very%20long%20text')%5Cn%7D%3B%22%2C%22options%22%3A%7B%22printWidth%22%3A40%2C%22tabWidth%22%3A2%2C%22singleQuote%22%3Afalse%2C%22trailingComma%22%3Afalse%2C%22bracketSpacing%22%3Atrue%7D%7D)


Issue discussion:
Yes we need to fix this, I think this might be included in another issue but I'm not sure. This is a regression from another commit. Will fix soon.
I'm sure you're probably up to your neck with edge cases but heres another example of this. 

![image](https://cloud.githubusercontent.com/assets/324928/21895463/d54cd6d6-d8b0-11e6-839a-8c278bf53c65.png)
![image](https://cloud.githubusercontent.com/assets/324928/21895471/dbe1eaae-d8b0-11e6-98a3-db1bd2f92ac3.png)

Love the formatter though. Will definitely start using it at work once it's had a little more time to mature. 

Solution patch:
diff --git a/src/printer.js b/src/printer.js
index fde8865bf0ae..fd652ab11f60 100644
--- a/src/printer.js
+++ b/src/printer.js
@@ -356,7 +356,11 @@ function genericPrintNoParens(path, options, print) {
       const body = path.call(print, "body");
       const collapsed = concat([ concat(parts), " ", body ]);
 
-      if (n.body.type === "JSXElement") {
+      if (
+        n.body.type === 'ArrayExpression' ||
+        n.body.type === 'ObjectExpression' ||
+        n.body.type === 'JSXElement'
+      ) {
         return group(collapsed);
       }
 
@@ -1720,7 +1724,10 @@ function printArgumentsList(path, options, print) {
     lastArg.type === "FunctionExpression" ||
     lastArg.type === "ArrowFunctionExpression" &&
       (lastArg.body.type === "BlockStatement" ||
-        lastArg.body.type === "ArrowFunctionExpression") ||
+        lastArg.body.type === "ArrowFunctionExpression" ||
+        lastArg.body.type === "ObjectExpression" ||
+        lastArg.body.type === "ArrayExpression" ||
+        lastArg.body.type === "JSXElement") ||
     lastArg.type === "NewExpression";
 
   if (groupLastArg) {


Test patch:
diff --git a/tests/last_argument_expansion/__snapshots__/jsfmt.spec.js.snap b/tests/last_argument_expansion/__snapshots__/jsfmt.spec.js.snap
new file mode 100644
index 000000000000..b71d51638ab1
--- /dev/null
+++ b/tests/last_argument_expansion/__snapshots__/jsfmt.spec.js.snap
@@ -0,0 +1,57 @@
+exports[`test jsx.js 1`] = `
+"const els = items.map(item => (
+  <div className=\"whatever\">
+    <span>{children}</span>
+  </div>
+));
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+const els = items.map(item => (
+  <div className=\"whatever\">
+    <span>{children}</span>
+  </div>
+));
+"
+`;
+
+exports[`test object.js 1`] = `
+"const formatData = pipe(
+  zip,
+  map(([ ref, data ]) => ({
+    nodeId: ref.nodeId.toString(),
+    ...attributeFromDataValue(ref.attributeId, data)
+  })),
+  groupBy(prop(\'nodeId\')),
+  map(mergeAll),
+  values
+);
+
+export const setProp = y => ({
+  ...y,
+  a: \'very, very, very long very, very long text\'
+});
+
+export const log = y => {
+  console.log(\'very, very, very long very, very long text\')
+};
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+const formatData = pipe(
+  zip,
+  map(([ ref, data ]) => ({
+    nodeId: ref.nodeId.toString(),
+    ...attributeFromDataValue(ref.attributeId, data)
+  })),
+  groupBy(prop(\"nodeId\")),
+  map(mergeAll),
+  values
+);
+
+export const setProp = y => ({
+  ...y,
+  a: \"very, very, very long very, very long text\"
+});
+
+export const log = y => {
+  console.log(\"very, very, very long very, very long text\");
+};
+"
+`;
diff --git a/tests/last_argument_expansion/jsfmt.spec.js b/tests/last_argument_expansion/jsfmt.spec.js
new file mode 100644
index 000000000000..989047bccc52
--- /dev/null
+++ b/tests/last_argument_expansion/jsfmt.spec.js
@@ -0,0 +1,1 @@
+run_spec(__dirname);
diff --git a/tests/last_argument_expansion/jsx.js b/tests/last_argument_expansion/jsx.js
new file mode 100644
index 000000000000..7a19b18ed031
--- /dev/null
+++ b/tests/last_argument_expansion/jsx.js
@@ -0,0 +1,5 @@
+const els = items.map(item => (
+  <div className="whatever">
+    <span>{children}</span>
+  </div>
+));
diff --git a/tests/last_argument_expansion/object.js b/tests/last_argument_expansion/object.js
new file mode 100644
index 000000000000..9994901836b2
--- /dev/null
+++ b/tests/last_argument_expansion/object.js
@@ -0,0 +1,19 @@
+const formatData = pipe(
+  zip,
+  map(([ ref, data ]) => ({
+    nodeId: ref.nodeId.toString(),
+    ...attributeFromDataValue(ref.attributeId, data)
+  })),
+  groupBy(prop('nodeId')),
+  map(mergeAll),
+  values
+);
+
+export const setProp = y => ({
+  ...y,
+  a: 'very, very, very long very, very long text'
+});
+
+export const log = y => {
+  console.log('very, very, very long very, very long text')
+};