Repository: jlongster/prettier (js)

Issue:
Disable leading & for flow types
```js
type ResponseMessage = MessageCommon & {
  messageType: 'RESPONSE',
  sequenceID: 'number',
};
```

turns into

```js
type ResponseMessage =
  & MessageCommon
  & {
    messageType: "RESPONSE",
    sequenceID: "number"
  };
```

which looks really weird. For `|`, they are usually chained so it feels nice, but you only have maximum one `&` so we should just display it inline like we do with #692

Pull request:
Fix leading & operators in flow types
This one should fix #702.

Patch:
diff --git a/README.md b/README.md
index ae0745a72..3568abf6a 100644
--- a/README.md
+++ b/README.md
@@ -174,6 +174,9 @@ prettier.format(source, {
   // "none" - No trailing commas
   // "es5"  - Trailing commas where valid in ES5 (objects, arrays, etc)
   // "all"  - Trailing commas wherever possible (function arguments)
+  //
+  // NOTE: Above is only available in 0.19.0 and above. Previously this was
+  // a boolean argument.
   trailingComma: "none",
 
   // Controls the printing of spaces inside object literals
diff --git a/src/fast-path.js b/src/fast-path.js
index 84afe6be3..f98277420 100644
--- a/src/fast-path.js
+++ b/src/fast-path.js
@@ -354,12 +354,14 @@ FPp.needsParens = function(assumeExpressionContext) {
       }
 
     case "YieldExpression":
+      if (parent.type === "UnaryExpression") {
+        return true;
+      }
     case "AwaitExpression":
       switch (parent.type) {
         case "TaggedTemplateExpression":
         case "BinaryExpression":
         case "LogicalExpression":
-        case "UnaryExpression":
         case "SpreadElement":
         case "SpreadProperty":
         case "NewExpression":
@@ -419,6 +421,7 @@ FPp.needsParens = function(assumeExpressionContext) {
         case "LogicalExpression":
         case "NewExpression":
         case "ExportDefaultDeclaration":
+        case "AwaitExpression":
           return true;
 
         case "CallExpression":
diff --git a/src/printer.js b/src/printer.js
index 80b59eb91..be633e247 100644
--- a/src/printer.js
+++ b/src/printer.js
@@ -814,6 +814,7 @@ function genericPrintNoParens(path, options, print) {
                   ? ","
                   : ""
               ),
+              comments.printDanglingComments(path, options, /* sameIndent */ true),
               softline,
               "]"
             ])
@@ -988,11 +989,18 @@ function genericPrintNoParens(path, options, print) {
     case "ForStatement": {
       const body = adjustClause(path.call(print, "body"), options);
 
+      // We want to keep dangling comments above the loop to stay consistent.
+      // Any comment positioned between the for statement and the parentheses
+      // is going to be printed before the statement.
+      const dangling = comments.printDanglingComments(path, options, /* sameLine */ true);
+      const printedComments = dangling ? concat([dangling, softline]) : "";
+
       if (!n.init && !n.test && !n.update) {
-        return concat(["for (;;)", body]);
+        return concat([printedComments, "for (;;)", body]);
       }
 
       return concat([
+        printedComments,
         "for (",
         group(
           concat([
@@ -1539,7 +1547,9 @@ function genericPrintNoParens(path, options, print) {
     case "IntersectionTypeAnnotation":
     case "UnionTypeAnnotation": {
       const types = path.map(print, "types");
-      const op = n.type === "IntersectionTypeAnnotation" ? "&" : "|";
+      const isIntersection = n.type === "IntersectionTypeAnnotation"
+      const shouldInline = isIntersection &&
+        !(n.types.length > 1 && n.types[0].type === "ObjectTypeAnnotation")
 
       // single-line variation
       // A | B | C
@@ -1548,12 +1558,18 @@ function genericPrintNoParens(path, options, print) {
       // | A
       // | B
       // | C
+
+      // We want & operators to be inlined.
+      if (shouldInline) {
+        return join(" & ", types);
+      }
+
       return group(
         indent(
           options.tabWidth,
           concat([
-            ifBreak(concat([line, op, " "])),
-            join(concat([line, op, " "]), types)
+            ifBreak(concat([line, isIntersection ? "&" : "|", " "])),
+            join(concat([line, isIntersection ? "&" : "|", " "]), types)
           ])
         )
       );
@@ -2025,6 +2041,8 @@ function printExportDeclaration(path, options, print) {
     parts.push("default ");
   }
 
+  parts.push(comments.printDanglingComments(path, options, /* sameIndent */ true));
+
   if (decl.declaration) {
     parts.push(path.call(print, "declaration"));
 


Test patch:
diff --git a/tests/async/__snapshots__/jsfmt.spec.js.snap b/tests/async/__snapshots__/jsfmt.spec.js.snap
index 208c7fca7..5f48fac00 100644
--- a/tests/async/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/async/__snapshots__/jsfmt.spec.js.snap
@@ -4,13 +4,26 @@ async function g() {
   invariant(
     (await driver.navigator.getUrl()).substr(-7)
   );
-}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+}
+function *f(){
+  !(yield a);
+}
+async function f() {
+  a = !(await f());
+}
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 async function f() {
   (await f()).length;
 }
 async function g() {
   invariant((await driver.navigator.getUrl()).substr(-7));
 }
+function* f() {
+  !(yield a);
+}
+async function f() {
+  a = !await f();
+}
 "
 `;
 
@@ -18,9 +31,19 @@ exports[`test conditional-expression.js 1`] = `
 "async function f() {
   const result = typeof fn === \'function\' ? await fn() : null;
 }
+
+(async function() {
+  console.log(
+    await (true ? Promise.resolve(\"A\") : Promise.resolve(\"B\"))
+  );
+})()
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 async function f() {
   const result = typeof fn === \"function\" ? await fn() : null;
 }
+
+(async function() {
+  console.log(await (true ? Promise.resolve(\"A\") : Promise.resolve(\"B\")));
+})();
 "
 `;
diff --git a/tests/async/await_parse.js b/tests/async/await_parse.js
index 96ebb82e5..dd2de424b 100644
--- a/tests/async/await_parse.js
+++ b/tests/async/await_parse.js
@@ -3,4 +3,10 @@ async function g() {
   invariant(
     (await driver.navigator.getUrl()).substr(-7)
   );
-}
\ No newline at end of file
+}
+function *f(){
+  !(yield a);
+}
+async function f() {
+  a = !(await f());
+}
diff --git a/tests/async/conditional-expression.js b/tests/async/conditional-expression.js
index 532c66d6a..73d846394 100644
--- a/tests/async/conditional-expression.js
+++ b/tests/async/conditional-expression.js
@@ -1,3 +1,9 @@
 async function f() {
   const result = typeof fn === 'function' ? await fn() : null;
 }
+
+(async function() {
+  console.log(
+    await (true ? Promise.resolve("A") : Promise.resolve("B"))
+  );
+})()
diff --git a/tests/comments/__snapshots__/jsfmt.spec.js.snap b/tests/comments/__snapshots__/jsfmt.spec.js.snap
index d70983ab8..1c50b6e53 100644
--- a/tests/comments/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/comments/__snapshots__/jsfmt.spec.js.snap
@@ -38,6 +38,7 @@ function x() {
   /* dangling */
 }
 declare class Foo extends Qux<string> {/* dangling */}
+export /* dangling */{};
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 var x = {
   /* dangling */
@@ -54,6 +55,7 @@ function x() {
 declare class Foo extends Qux<string> {
   /* dangling */
 }
+export /* dangling */{};
 "
 `;
 
@@ -67,6 +69,7 @@ function x() {
   /* dangling */
 }
 declare class Foo extends Qux<string> {/* dangling */}
+export /* dangling */{};
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 var x = {
   /* dangling */
@@ -83,6 +86,7 @@ function x() {
 declare class Foo extends Qux<string> {
   /* dangling */
 }
+export /* dangling */{};
 "
 `;
 
@@ -90,12 +94,16 @@ exports[`test dangling_array.js 1`] = `
 "expect(() => {}).toTriggerReadyStateChanges([
   // Nothing.
 ]);
+
+[1 /* first comment */, 2 /* second comment */, 3];
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 expect(() => {}).toTriggerReadyStateChanges(
   [
     // Nothing.
   ]
 );
+
+[1 /* first comment */, 2 /* second comment */, 3];
 "
 `;
 
@@ -103,12 +111,44 @@ exports[`test dangling_array.js 2`] = `
 "expect(() => {}).toTriggerReadyStateChanges([
   // Nothing.
 ]);
+
+[1 /* first comment */, 2 /* second comment */, 3];
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 expect(() => {}).toTriggerReadyStateChanges(
   [
     // Nothing.
   ]
 );
+
+[1 /* first comment */, 2 /* second comment */, 3];
+"
+`;
+
+exports[`test dangling_for.js 1`] = `
+"for // comment
+(;;);
+
+for /* comment */(;;);
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// comment
+for (;;);
+
+/* comment */
+for (;;);
+"
+`;
+
+exports[`test dangling_for.js 2`] = `
+"for // comment
+(;;);
+
+for /* comment */(;;);
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// comment
+for (;;);
+
+/* comment */
+for (;;);
 "
 `;
 
@@ -384,13 +424,11 @@ const rootEpic = (actions, store) => combineEpics(...epics)(actions, store)
   });
 
 // Two extra levels of indentation because of the comment
-export type AsyncExecuteOptions =
-  & child_process$execFileOpts
-  & {
-    // The contents to write to stdin.
-    stdin?: ?string,
-    dontLogInNuclide?: ?boolean
-  };
+export type AsyncExecuteOptions = child_process$execFileOpts & {
+  // The contents to write to stdin.
+  stdin?: ?string,
+  dontLogInNuclide?: ?boolean
+};
 
 // optional trailing comma gets moved all the way to the beginning
 const regex = new RegExp(
@@ -611,13 +649,11 @@ const rootEpic = (actions, store) => combineEpics(...epics)(actions, store)
   });
 
 // Two extra levels of indentation because of the comment
-export type AsyncExecuteOptions =
-  & child_process$execFileOpts
-  & {
-    // The contents to write to stdin.
-    stdin?: ?string,
-    dontLogInNuclide?: ?boolean
-  };
+export type AsyncExecuteOptions = child_process$execFileOpts & {
+  // The contents to write to stdin.
+  stdin?: ?string,
+  dontLogInNuclide?: ?boolean
+};
 
 // optional trailing comma gets moved all the way to the beginning
 const regex = new RegExp(
diff --git a/tests/comments/dangling.js b/tests/comments/dangling.js
index 22208dee5..f041ce3dc 100644
--- a/tests/comments/dangling.js
+++ b/tests/comments/dangling.js
@@ -7,3 +7,4 @@ function x() {
   /* dangling */
 }
 declare class Foo extends Qux<string> {/* dangling */}
+export /* dangling */{};
diff --git a/tests/comments/dangling_array.js b/tests/comments/dangling_array.js
index 599897d57..6559ed64a 100644
--- a/tests/comments/dangling_array.js
+++ b/tests/comments/dangling_array.js
@@ -1,3 +1,5 @@
 expect(() => {}).toTriggerReadyStateChanges([
   // Nothing.
 ]);
+
+[1 /* first comment */, 2 /* second comment */, 3];
diff --git a/tests/comments/dangling_for.js b/tests/comments/dangling_for.js
new file mode 100644
index 000000000..047f46929
--- /dev/null
+++ b/tests/comments/dangling_for.js
@@ -0,0 +1,4 @@
+for // comment
+(;;);
+
+for /* comment */(;;);
diff --git a/tests/flow/intersection/__snapshots__/jsfmt.spec.js.snap b/tests/flow/intersection/__snapshots__/jsfmt.spec.js.snap
index 25b95564d..59f55cf40 100644
--- a/tests/flow/intersection/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/flow/intersection/__snapshots__/jsfmt.spec.js.snap
@@ -77,14 +77,11 @@ function hasObjectMode_ok(options: DuplexStreamOptions): boolean {
  * @flow
  */
 
-type DuplexStreamOptions =
-  & ReadableStreamOptions
-  & WritableStreamOptions
-  & {
-    allowHalfOpen?: boolean,
-    readableObjectMode?: boolean,
-    writableObjectMode?: boolean
-  };
+type DuplexStreamOptions = ReadableStreamOptions & WritableStreamOptions & {
+  allowHalfOpen?: boolean,
+  readableObjectMode?: boolean,
+  writableObjectMode?: boolean
+};
 
 function hasObjectMode_bad(options: DuplexStreamOptions): boolean {
   return options.objectMode ||
diff --git a/tests/flow/typeapp_perf/__snapshots__/jsfmt.spec.js.snap b/tests/flow/typeapp_perf/__snapshots__/jsfmt.spec.js.snap
index 1feb00422..2089a496a 100644
--- a/tests/flow/typeapp_perf/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/flow/typeapp_perf/__snapshots__/jsfmt.spec.js.snap
@@ -25,19 +25,17 @@ declare var b: B<any>;
 
 class A {}
 
-type B<T> =
-  & A
-  & {
-    +a: () => B<T>,
-    +b: () => B<T>,
-    +c: () => B<T>,
-    +d: () => B<T>,
-    +e: () => B<T>,
-    +f: () => B<T>,
-    +g: () => B<T>,
-    +h: () => B<T>,
-    +i: () => B<T>
-  };
+type B<T> = A & {
+  +a: () => B<T>,
+  +b: () => B<T>,
+  +c: () => B<T>,
+  +d: () => B<T>,
+  +e: () => B<T>,
+  +f: () => B<T>,
+  +g: () => B<T>,
+  +h: () => B<T>,
+  +i: () => B<T>
+};
 
 declare var b: B<any>;
 
@@ -72,19 +70,17 @@ declare var b: B<any>;
 
 class A {}
 
-type B<T> =
-  & A
-  & {
-    +a: (x: B<T>) => void,
-    +b: (x: B<T>) => void,
-    +c: (x: B<T>) => void,
-    +d: (x: B<T>) => void,
-    +e: (x: B<T>) => void,
-    +f: (x: B<T>) => void,
-    +g: (x: B<T>) => void,
-    +h: (x: B<T>) => void,
-    +i: (x: B<T>) => void
-  };
+type B<T> = A & {
+  +a: (x: B<T>) => void,
+  +b: (x: B<T>) => void,
+  +c: (x: B<T>) => void,
+  +d: (x: B<T>) => void,
+  +e: (x: B<T>) => void,
+  +f: (x: B<T>) => void,
+  +g: (x: B<T>) => void,
+  +h: (x: B<T>) => void,
+  +i: (x: B<T>) => void
+};
 
 declare var b: B<any>;
 
diff --git a/tests/flow/union_new/__snapshots__/jsfmt.spec.js.snap b/tests/flow/union_new/__snapshots__/jsfmt.spec.js.snap
index f6a4580f7..d08fb0a16 100644
--- a/tests/flow/union_new/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/flow/union_new/__snapshots__/jsfmt.spec.js.snap
@@ -205,19 +205,15 @@ function printAll(val: MyType) {
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 type Common = {};
 
-type A =
-  & Common
-  & {
-    type: \"A\",
-    foo: number
-  };
+type A = Common & {
+  type: \"A\",
+  foo: number
+};
 
-type B =
-  & Common
-  & {
-    type: \"B\",
-    foo: Array<number>
-  };
+type B = Common & {
+  type: \"B\",
+  foo: Array<number>
+};
 
 type MyType = A | B;
 
@@ -327,17 +323,13 @@ type DataBase = {
   name: string
 };
 
-type UserData =
-  & DataBase
-  & {
-    kind: \"user\"
-  };
+type UserData = DataBase & {
+  kind: \"user\"
+};
 
-type SystemData =
-  & DataBase
-  & {
-    kind: \"system\"
-  };
+type SystemData = DataBase & {
+  kind: \"system\"
+};
 
 type Data = UserData | SystemData;
 
@@ -410,18 +402,14 @@ declare type Entity<T> = {
 
 declare type StringEntity = Entity<string>;
 
-declare type Foo =
-  & StringEntity
-  & {
-    bars: Object,
-    kind: 1
-  };
-declare type EmptyFoo =
-  & StringEntity
-  & {
-    bars: null,
-    kind: 2
-  };
+declare type Foo = StringEntity & {
+  bars: Object,
+  kind: 1
+};
+declare type EmptyFoo = StringEntity & {
+  bars: null,
+  kind: 2
+};
 
 function test(f: Foo | EmptyFoo) {
   if (f.kind === 1) {