Repository: jlongster/prettier (js)

Issue:
Missing parenthesis around anonymous functions
```js
(function() {})
```

outputs

```js
function() {}
```

which is invalid.

https://jlongster.github.io/prettier/#%7B%22content%22%3A%22(function()%20%7B%7D)%22%2C%22options%22%3A%7B%22printWidth%22%3A80%2C%22tabWidth%22%3A2%2C%22singleQuote%22%3Afalse%2C%22trailingComma%22%3Afalse%2C%22bracketSpacing%22%3Atrue%7D%7D

In itself, it doesn't do anything, but if you eval it, it returns the function! This is pretty crazy code though :p https://github.com/facebook/nuclide/blob/master/pkg/nuclide-debugger-node-rpc/VendorLib/node_modules/v8-debug/InjectedScript/InjectedScriptSource.js#L37

Pull request description:
Fix parens around anonymous functions
Fixes #284

Patch:
diff --git a/src/fast-path.js b/src/fast-path.js
index ca3e73e76..de8b4572d 100644
--- a/src/fast-path.js
+++ b/src/fast-path.js
@@ -373,6 +373,7 @@ FPp.needsParens = function(assumeExpressionContext) {
       }
 
       switch (parent.type) {
+        case "ExpressionStatement":
         case "MemberExpression":
         case "TaggedTemplateExpression":
         case "UnaryExpression":
diff --git a/src/printer.js b/src/printer.js
index fbd6c54d4..52f9ed72b 100644
--- a/src/printer.js
+++ b/src/printer.js
@@ -1830,6 +1830,12 @@ function printReturnType(path, print) {
   return concat(parts);
 }
 
+function typeIsFunction(type) {
+  return type === "FunctionExpression" ||
+    type === "ArrowFunctionExpression" ||
+    type === "NewExpression";
+}
+
 function printExportDeclaration(path, options, print) {
   var decl = path.getValue();
   var parts = [ "export " ];
@@ -1847,7 +1853,8 @@ function printExportDeclaration(path, options, print) {
     if (
       decl.type === "ExportDefaultDeclaration" &&
         (decl.declaration.type == "Identifier" ||
-          decl.declaration.type === "CallExpression")
+          decl.declaration.type === "CallExpression" ||
+          typeIsFunction(decl.declaration.type))
     ) {
       parts.push(";");
     }
@@ -1986,9 +1993,7 @@ function printMemberChain(node, options, print) {
   function argIsFunction(call) {
     if (call.arguments.length > 0) {
       const type = call.arguments[(0)].type;
-      return type === "FunctionExpression" ||
-        type === "ArrowFunctionExpression" ||
-        type === "NewExpression";
+      return typeIsFunction(type);
     }
     return false;
   }


Test patch:
diff --git a/tests/async_iteration/__snapshots__/jsfmt.spec.js.snap b/tests/async_iteration/__snapshots__/jsfmt.spec.js.snap
index 3d2a56d29..8173c5d8c 100644
--- a/tests/async_iteration/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/async_iteration/__snapshots__/jsfmt.spec.js.snap
@@ -40,11 +40,11 @@ async function* delegate_yield() {
   }
   yield* inner();
 }
-async () => {
+(async () => {
   for await (const x of delegate_yield()) {
     (x: void); // error: number ~> void
   }
-};
+});
 
 async function* delegate_return() {
   async function* inner() {
@@ -197,13 +197,13 @@ async function* catch_return() {
   }
 }
 
-async () => {
+(async () => {
   catch_return().throw(\"\").then(({ value }) => {
     if (value !== undefined) {
       (value: void); // error: number ~> void
     }
   });
-};
+});
 
 async function* yield_return() {
   try {
@@ -214,12 +214,12 @@ async function* yield_return() {
   }
 }
 
-async () => {
+(async () => {
   yield_return().throw(\"\").then(({ value }) => {
     if (value !== undefined) {
       (value: void); // error: number ~> void
     }
   });
-};
+});
 "
 `;
diff --git a/tests/es6modules/__snapshots__/jsfmt.spec.js.snap b/tests/es6modules/__snapshots__/jsfmt.spec.js.snap
index df441d6b2..efd59b9c1 100644
--- a/tests/es6modules/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/es6modules/__snapshots__/jsfmt.spec.js.snap
@@ -1347,10 +1347,33 @@ import {
 "
 `;
 
+exports[`test export_default_arrow_expression.js 1`] = `
+"export default () => {};
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+export default () => {
+};
+"
+`;
+
 exports[`test export_default_call_expression.js 1`] = `
-"export default connect(mapStateToProps)(MyComponent);
+"export default foo()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+export default foo();
+"
+`;
+
+exports[`test export_default_function_expression.js 1`] = `
+"export default (function() {});
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+export default function() {
+};
+"
+`;
+
+exports[`test export_default_new_expression.js 1`] = `
+"export default new Foo();
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-export default connect(mapStateToProps)(MyComponent);
+export default new Foo();
 "
 `;
 
diff --git a/tests/es6modules/export_default_arrow_expression.js b/tests/es6modules/export_default_arrow_expression.js
new file mode 100644
index 000000000..2d1ec2382
--- /dev/null
+++ b/tests/es6modules/export_default_arrow_expression.js
@@ -0,0 +1,1 @@
+export default () => {};
diff --git a/tests/es6modules/export_default_call_expression.js b/tests/es6modules/export_default_call_expression.js
index c3fae600c..4b9b7b3d8 100644
--- a/tests/es6modules/export_default_call_expression.js
+++ b/tests/es6modules/export_default_call_expression.js
@@ -1,1 +1,1 @@
-export default connect(mapStateToProps)(MyComponent);
+export default foo()
diff --git a/tests/es6modules/export_default_function_expression.js b/tests/es6modules/export_default_function_expression.js
new file mode 100644
index 000000000..01e4503a7
--- /dev/null
+++ b/tests/es6modules/export_default_function_expression.js
@@ -0,0 +1,1 @@
+export default (function() {});
diff --git a/tests/es6modules/export_default_new_expression.js b/tests/es6modules/export_default_new_expression.js
new file mode 100644
index 000000000..92c970c73
--- /dev/null
+++ b/tests/es6modules/export_default_new_expression.js
@@ -0,0 +1,1 @@
+export default new Foo();
diff --git a/tests/function/__snapshots__/jsfmt.spec.js.snap b/tests/function/__snapshots__/jsfmt.spec.js.snap
index 2cd319933..93ef91369 100644
--- a/tests/function/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/function/__snapshots__/jsfmt.spec.js.snap
@@ -370,6 +370,7 @@ export default (function() {})();
 (function() {})()\`\`;
 (function() {})\`\`;
 new (function() {});
+(function() {})
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 (function() {
 }).length;
@@ -383,6 +384,8 @@ export default (function() {
 })\`\`;
 new (function() {
 })();
+(function() {
+});
 "
 `;
 
diff --git a/tests/function/function_expression.js b/tests/function/function_expression.js
index e680a3d1a..aa9c6c35f 100644
--- a/tests/function/function_expression.js
+++ b/tests/function/function_expression.js
@@ -4,3 +4,4 @@ export default (function() {})();
 (function() {})()``;
 (function() {})``;
 new (function() {});
+(function() {})
diff --git a/tests/predicates-parsing/__snapshots__/jsfmt.spec.js.snap b/tests/predicates-parsing/__snapshots__/jsfmt.spec.js.snap
index b28d1c664..e6078c8e3 100644
--- a/tests/predicates-parsing/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/predicates-parsing/__snapshots__/jsfmt.spec.js.snap
@@ -112,14 +112,14 @@ var a0 = (x: mixed) => x !== null;
 
 var a1 = (x: mixed): %checks => x !== null;
 
-(x): %checks => x !== null;
+((x): %checks => x !== null);
 
 const insert_a_really_big_predicated_arrow_function_name_here = (x): %checks =>
   x !== null;
 
 declare var x;
 x;
-checks => 123;
+(checks => 123);
 
 type checks = any;