Repository: jlongster/prettier
Pull request #168 (2017-01-13 17:44:44)

Add trailing comma support for multiline exports
```js
echo "export { aaaaaaaa, bbbbbb, cccccc, dddddddd, eeeeeee, fffffffff, ggggggggg } from 'vjeux';" | ./bin/prettier.js --stdin --trailing-comma
export {
  aaaaaaaa,
  bbbbbb,
  cccccc,
  dddddddd,
  eeeeeee,
  fffffffff,
  ggggggggg,
} from "vjeux";
```


Patch:
diff --git a/bin/prettier.js b/bin/prettier.js
index a5b6229f0..f034c7e3c 100755
--- a/bin/prettier.js
+++ b/bin/prettier.js
@@ -33,6 +33,13 @@ if (!filenames.length && !stdin) {
   process.exit(1);
 }
 
+function formatWithShebang(input) {
+  const index = input.indexOf("\n");
+  const shebang = input.slice(0, index + 1);
+  const programInput = input.slice(index + 1);
+  return shebang + format(programInput);
+}
+
 function format(input) {
   return jscodefmt.format(input, {
     printWidth: argv["print-width"],
@@ -70,7 +77,7 @@ if (stdin) {
 
       let output;
       try {
-        output = format(input);
+        output = input.startsWith("#!") ? formatWithShebang(input) : format(input);
       } catch (e) {
         process.exitCode = 2;
         console.error(e);
diff --git a/src/printer.js b/src/printer.js
index b121e7d51..fd335cb76 100644
--- a/src/printer.js
+++ b/src/printer.js
@@ -465,40 +465,48 @@ function genericPrintNoParens(path, options, print) {
     }
 
     if (n.specifiers && n.specifiers.length > 0) {
-      var foundImportSpecifier = false;
+      var standalones = [];
+      var grouped = [];
 
-      path.each(
-        function(specifierPath) {
-          var i = specifierPath.getName();
-
-          if (i > 0) {
-            parts.push(", ");
-          }
-
-          var value = specifierPath.getValue();
-
-          if (
-            namedTypes.ImportDefaultSpecifier.check(value) ||
-              namedTypes.ImportNamespaceSpecifier.check(value)
-          ) {
-            assert.strictEqual(foundImportSpecifier, false);
-          } else {
-            namedTypes.ImportSpecifier.assert(value);
+      path.each(function(specifierPath) {
+        var value = specifierPath.getValue();
+        if (
+          namedTypes.ImportDefaultSpecifier.check(value) ||
+          namedTypes.ImportNamespaceSpecifier.check(value)
+        ) {
+          standalones.push(print(specifierPath));
+        } else {
+          grouped.push(print(specifierPath));
+        }
+      }, "specifiers");
 
-            if (!foundImportSpecifier) {
-              foundImportSpecifier = true;
+      assert.ok(standalones.length <= 1);
 
-              parts.push(options.bracketSpacing ? "{ " : "{");
-            }
-          }
+      if (standalones.length > 0) {
+        parts.push(standalones[0]);
+      }
 
-          parts.push(print(specifierPath));
-        },
-        "specifiers"
-      );
+      if (standalones.length > 0 && grouped.length > 0) {
+        parts.push(", ");
+      }
 
-      if (foundImportSpecifier) {
-        parts.push(options.bracketSpacing ? " }" : "}");
+      if (grouped.length > 0) {
+        parts.push(
+          group(concat([
+            "{",
+            indent(
+              options.tabWidth,
+              concat([
+                options.bracketSpacing ? line : softline,
+                join(concat([",", options.bracketSpacing ? line : softline]),
+                     grouped)
+              ])
+            ),
+            ifBreak(options.trailingComma ? "," : ""),
+            options.bracketSpacing ? line : softline,
+            "}",
+          ]))
+        );
       }
 
       parts.push(" from ");
@@ -866,7 +874,15 @@ function genericPrintNoParens(path, options, print) {
 
     return group(concat(parts));
   case "ForStatement":
-    // TODO Get the for (;;) case right.
+    const body = adjustClause(path.call(print, "body"), options);
+
+    if (!n.init && !n.test && !n.update) {
+      return concat([
+        'for (;;)',
+        body,
+      ]);
+    }
+
     return concat([
       "for (",
       group(
@@ -888,7 +904,7 @@ function genericPrintNoParens(path, options, print) {
         ])
       ),
       ")",
-      adjustClause(path.call(print, "body"), options)
+      body,
     ]);
   case "WhileStatement":
     return concat([
@@ -1876,6 +1892,7 @@ function printExportDeclaration(path, options, print) {
                    path.map(print, "specifiers"))
             ])
           ),
+          ifBreak(options.trailingComma ? "," : ""),
           options.bracketSpacing ? line : softline,
           "}"
         ]))


Test patch:
diff --git a/tests/config_module_name_mapper_filetype/__snapshots__/jsfmt.spec.js.snap b/tests/config_module_name_mapper_filetype/__snapshots__/jsfmt.spec.js.snap
index b81d9d8a8..ab98a17c5 100644
--- a/tests/config_module_name_mapper_filetype/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/config_module_name_mapper_filetype/__snapshots__/jsfmt.spec.js.snap
@@ -7,6 +7,8 @@ import {doesntExist} from \"./SomeCSSFile.css\"; // Error: \`doestExist\` isn\'t
 // @flow
 
 import { className } from \"./SomeCSSFile.css\";
-import { doesntExist } from \"./SomeCSSFile.css\"; // Error: \`doestExist\` isn\'t an export
+import {
+  doesntExist
+} from \"./SomeCSSFile.css\"; // Error: \`doestExist\` isn\'t an export
 "
 `;
diff --git a/tests/declare_export/__snapshots__/jsfmt.spec.js.snap b/tests/declare_export/__snapshots__/jsfmt.spec.js.snap
index d9a5c75e7..fa2f9202e 100644
--- a/tests/declare_export/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/declare_export/__snapshots__/jsfmt.spec.js.snap
@@ -1144,7 +1144,10 @@ import { specifierNumber } from \"ES6_Named1\";
 ///////////////////////////////////////////////////
 // == Multi \`export *\` should combine exports == //
 ///////////////////////////////////////////////////
-import { numberValue1 as numberValue8, numberValue2 as numberValue9 } from \"./ES6_ExportAllFromMulti\";
+import {
+  numberValue1 as numberValue8,
+  numberValue2 as numberValue9
+} from \"./ES6_ExportAllFromMulti\";
 
 var at1: number = numberValue8;
 var at2: string = numberValue8;
diff --git a/tests/es6modules/__snapshots__/jsfmt.spec.js.snap b/tests/es6modules/__snapshots__/jsfmt.spec.js.snap
index f5c5abbef..b04c6bf61 100644
--- a/tests/es6modules/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/es6modules/__snapshots__/jsfmt.spec.js.snap
@@ -1275,7 +1275,10 @@ import { specifierNumber } from \"ES6_Named1\";
 ///////////////////////////////////////////////////
 // == Multi \`export *\` should combine exports == //
 ///////////////////////////////////////////////////
-import { numberValue1 as numberValue8, numberValue2 as numberValue9 } from \"./ES6_ExportAllFromMulti\";
+import {
+  numberValue1 as numberValue8,
+  numberValue2 as numberValue9
+} from \"./ES6_ExportAllFromMulti\";
 
 var at1: number = numberValue8;
 var at2: string = numberValue8;
@@ -1286,7 +1289,9 @@ var at4: string = numberValue9;
 /////////////////////////////////////////////////////////////
 // == Vanilla \`import\` cannot import a type-only export == //
 /////////////////////////////////////////////////////////////
-import { typeAlias } from \"./ExportType\"; // Error: Cannot vanilla-import a type alias!
+import {
+  typeAlias
+} from \"./ExportType\"; // Error: Cannot vanilla-import a type alias!
 "
 `;
 
diff --git a/tests/export_type/__snapshots__/jsfmt.spec.js.snap b/tests/export_type/__snapshots__/jsfmt.spec.js.snap
index e4cbb356c..cb79c85b4 100644
--- a/tests/export_type/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/export_type/__snapshots__/jsfmt.spec.js.snap
@@ -51,7 +51,12 @@ var n: IFoo2 = {prop: 42}; // Error: {prop:number} ~> {prop:string}
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 /* @flow */
 
-import type { inlinedType1, standaloneType1, talias1, talias3 } from \"./types_only\";
+import type {
+  inlinedType1,
+  standaloneType1,
+  talias1,
+  talias3
+} from \"./types_only\";
 
 var a: inlinedType1 = 42;
 var b: inlinedType1 = \"asdf\";
diff --git a/tests/for/__snapshots__/jsfmt.spec.js.snap b/tests/for/__snapshots__/jsfmt.spec.js.snap
index 13b0549ec..2f651c203 100644
--- a/tests/for/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/for/__snapshots__/jsfmt.spec.js.snap
@@ -280,3 +280,12 @@ function corge(x: boolean) {
 }
 "
 `;
+
+exports[`test for.js 1`] = `
+"for (;;) {}
+for (var i = 0; i < 10; ++i) {}
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+for (;;) {}
+for (var i = 0; i < 10; ++i) {}
+"
+`;
diff --git a/tests/for/for.js b/tests/for/for.js
new file mode 100644
index 000000000..2f4f7ad1a
--- /dev/null
+++ b/tests/for/for.js
@@ -0,0 +1,2 @@
+for (;;) {}
+for (var i = 0; i < 10; ++i) {}