Repository: jlongster/prettier
Pull request #416 (2017-01-23 01:48:58)

Improve vim integration section
I have a feeling a lot of people are going to want to run prettier on save and it's a relatively lightweight addition to the readme. If you don't think it belongs in the readme, feel free to close this.


Patch:
diff --git a/README.md b/README.md
index 7928dc7a9..832c6e6d8 100644
--- a/README.md
+++ b/README.md
@@ -173,7 +173,12 @@ autocmd FileType javascript set formatprg=prettier\ --stdin
 ```
 
 This makes Prettier power the [`gq` command](http://vimdoc.sourceforge.net/htmldoc/change.html#gq)
-for automatic formatting without any plugins.
+for automatic formatting without any plugins. You can also add the following to your
+`.vimrc` to run prettier when `.js` files are saved:
+
+```
+autocmd BufWritePre *.js :normal gggqG
+```
 
 ### Visual Studio Code
 
diff --git a/commands.md b/commands.md
index 5ea079897..c49bd99ab 100644
--- a/commands.md
+++ b/commands.md
@@ -3,7 +3,7 @@ This is very rough documentation of the formatting commands you can
 use to build a printed version of something. This will be improved
 over time.
 
-The core of the algorithm is implemented in `pp.js`. The printer should
+The core of the algorithm is implemented in `doc-{printer,builders,utils}.js`. The printer should
 use the basic formatting abstractions provided to construct a format
 when printing a node. Parts of the API only exist to be compatible
 with recast's previous API to ease migration, but over time we can
diff --git a/src/fast-path.js b/src/fast-path.js
index da77d6ee2..35bbd28de 100644
--- a/src/fast-path.js
+++ b/src/fast-path.js
@@ -327,8 +327,13 @@ FPp.needsParens = function(assumeExpressionContext) {
           return true;
       }
 
-    case "AwaitExpression":
     case "YieldExpression":
+      if (parent.type === "ConditionalExpression" &&
+          parent.test === node &&
+          !node.argument) {
+        return true;
+      }
+    case "AwaitExpression":
       switch (parent.type) {
         case "TaggedTemplateExpression":
         case "BinaryExpression":
@@ -371,6 +376,12 @@ FPp.needsParens = function(assumeExpressionContext) {
         parent.object === node;
 
     case "AssignmentExpression":
+      if (parent.type === "ArrowFunctionExpression" &&
+          parent.body === node &&
+          node.left.type === "ObjectPattern") {
+        return true;
+      }
+
     case "ConditionalExpression":
       switch (parent.type) {
         case "TaggedTemplateExpression":
@@ -381,6 +392,7 @@ FPp.needsParens = function(assumeExpressionContext) {
         case "LogicalExpression":
         case "LogicalExpression":
         case "NewExpression":
+        case "ExportDefaultDeclaration":
           return true;
 
         case "CallExpression":
@@ -438,6 +450,12 @@ FPp.needsParens = function(assumeExpressionContext) {
           if (parent.callee === node) {
             return true;
           }
+        case "MemberExpression":
+          return name === "object" && parent.object === node;
+        case "ConditionalExpression":
+          if (parent.test === node) {
+            return true;
+          }
       }
 
       return false;
@@ -449,6 +467,9 @@ FPp.needsParens = function(assumeExpressionContext) {
       if (parent.type === "TaggedTemplateExpression") {
         return true;
       }
+      if (parent.type === "MemberExpression") {
+        return name === "object" && parent.object === node;
+      }
 
     default:
       if (
diff --git a/src/printer.js b/src/printer.js
index 8b197e5b9..c7c2873ef 100644
--- a/src/printer.js
+++ b/src/printer.js
@@ -1587,17 +1587,20 @@ function printStatementSequence(path, options, print) {
 }
 
 function printPropertyKey(path, options, print) {
-  var node = path.getNode().key;
+  const node = path.getNode();
+  const key = node.key;
+
   if (
-    (node.type === "StringLiteral" ||
-      node.type === "Literal" && typeof node.value === "string") &&
-      isIdentifierName(node.value) &&
+    (key.type === "StringLiteral" ||
+      key.type === "Literal" && typeof key.value === "string") &&
+      isIdentifierName(key.value) &&
+      !node.computed &&
       // There's a bug in the flow parser where it throws if there are
       // unquoted unicode literals as keys. Let's quote them for now.
-      (options.parser !== "flow" || node.value.match(/[a-zA-Z0-9$_]/))
+      (options.parser !== "flow" || key.value.match(/[a-zA-Z0-9$_]/))
   ) {
     // 'a' -> a
-    return node.value;
+    return key.value;
   }
   return path.call(print, "key");
 }


Test patch:
diff --git a/tests/arrows/__snapshots__/jsfmt.spec.js.snap b/tests/arrows/__snapshots__/jsfmt.spec.js.snap
index 00375d891..3a2606f90 100644
--- a/tests/arrows/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/arrows/__snapshots__/jsfmt.spec.js.snap
@@ -64,6 +64,8 @@ exports[`test arrows.js 1`] = `
     return images.find(image => image.width >= maxPixelWidth) ||
         images[images.length - 1];
 }
+
+a = () => ({} = this);
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 function selectBestEffortImageForWidth(
   maxWidth: number,
@@ -75,6 +77,8 @@ function selectBestEffortImageForWidth(
   return images.find(image => image.width >= maxPixelWidth) ||
     images[images.length - 1];
 }
+
+a = () => ({} = this);
 "
 `;
 
diff --git a/tests/arrows/arrows.js b/tests/arrows/arrows.js
index f25cc0fb3..93f6b3c46 100644
--- a/tests/arrows/arrows.js
+++ b/tests/arrows/arrows.js
@@ -8,3 +8,5 @@ function selectBestEffortImageForWidth(
     return images.find(image => image.width >= maxPixelWidth) ||
         images[images.length - 1];
 }
+
+a = () => ({} = this);
diff --git a/tests/classes/__snapshots__/jsfmt.spec.js.snap b/tests/classes/__snapshots__/jsfmt.spec.js.snap
index 0a7f5ef2d..28a1e1e84 100644
--- a/tests/classes/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/classes/__snapshots__/jsfmt.spec.js.snap
@@ -264,6 +264,15 @@ class Foo {} // error, shadows type Foo
 "
 `;
 
+exports[`test member.js 1`] = `
+"(class {})[1];
+(class {}).a;
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+(class {})[1];
+(class {}).a;
+"
+`;
+
 exports[`test statics.js 1`] = `
 "/* @flow */
 
@@ -296,3 +305,10 @@ declare var o: { p: number };
 (o: Class<C>); // error, object type incompatible with class type
 "
 `;
+
+exports[`test ternary.js 1`] = `
+"if (1) (class {}) ? 1 : 2;
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+if (1) (class {}) ? 1 : 2;
+"
+`;
diff --git a/tests/classes/member.js b/tests/classes/member.js
new file mode 100644
index 000000000..128236eba
--- /dev/null
+++ b/tests/classes/member.js
@@ -0,0 +1,2 @@
+(class {})[1];
+(class {}).a;
diff --git a/tests/classes/ternary.js b/tests/classes/ternary.js
new file mode 100644
index 000000000..3d6727056
--- /dev/null
+++ b/tests/classes/ternary.js
@@ -0,0 +1,1 @@
+if (1) (class {}) ? 1 : 2;
diff --git a/tests/computed_props/__snapshots__/jsfmt.spec.js.snap b/tests/computed_props/__snapshots__/jsfmt.spec.js.snap
index 518241ff8..b8d4c32a4 100644
--- a/tests/computed_props/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/computed_props/__snapshots__/jsfmt.spec.js.snap
@@ -1,3 +1,15 @@
+exports[`test classes.js 1`] = `
+"class c {
+  [\"i\"]() {}
+}
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class c {
+  [\"i\"]() {
+  }
+}
+"
+`;
+
 exports[`test test.js 1`] = `
 "var ColorId = {
   RED: \'R\',
diff --git a/tests/computed_props/classes.js b/tests/computed_props/classes.js
new file mode 100644
index 000000000..d85ace1ac
--- /dev/null
+++ b/tests/computed_props/classes.js
@@ -0,0 +1,3 @@
+class c {
+  ["i"]() {}
+}
diff --git a/tests/export_default/__snapshots__/jsfmt.spec.js.snap b/tests/export_default/__snapshots__/jsfmt.spec.js.snap
index 7a5c5da54..6d57d6ba3 100644
--- a/tests/export_default/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/export_default/__snapshots__/jsfmt.spec.js.snap
@@ -5,6 +5,13 @@ module.exports = require(\"M\");
 "
 `;
 
+exports[`test body.js 1`] = `
+"export default (class {}[1] = 1);
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+export default ((class {})[1] = 1);
+"
+`;
+
 exports[`test test.js 1`] = `
 "var M = require(\'M\');
 var N = require(\'N\');
diff --git a/tests/export_default/body.js b/tests/export_default/body.js
new file mode 100644
index 000000000..7a2f3c475
--- /dev/null
+++ b/tests/export_default/body.js
@@ -0,0 +1,1 @@
+export default (class {}[1] = 1);
diff --git a/tests/objects/__snapshots__/jsfmt.spec.js.snap b/tests/objects/__snapshots__/jsfmt.spec.js.snap
index c3fa28ebb..2b8644ba8 100644
--- a/tests/objects/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/objects/__snapshots__/jsfmt.spec.js.snap
@@ -46,9 +46,11 @@ var z = Object(123);
 exports[`test expression.js 1`] = `
 "() => ({}\`\`);
 ({})\`\`;
+a = () => ({}).x;
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 (() => ({})\`\`);
 ({})\`\`;
+a = () => ({}).x;
 "
 `;
 
diff --git a/tests/objects/expression.js b/tests/objects/expression.js
index fd92a69bf..861275eb0 100644
--- a/tests/objects/expression.js
+++ b/tests/objects/expression.js
@@ -1,2 +1,3 @@
 () => ({}``);
 ({})``;
+a = () => ({}).x;
diff --git a/tests/refinements/__snapshots__/jsfmt.spec.js.snap b/tests/refinements/__snapshots__/jsfmt.spec.js.snap
index 249a95d4d..47713d4d6 100644
--- a/tests/refinements/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/refinements/__snapshots__/jsfmt.spec.js.snap
@@ -2565,7 +2565,7 @@ let tests = [
     if (x.kind === null.toString()) {
     }
     // error, method on null
-    if ({ kind: 1 }.kind === null.toString()) {
+    if (({ kind: 1 }).kind === null.toString()) {
     } // error, method on null
   },
   // non-objects on LHS
diff --git a/tests/yield/__snapshots__/jsfmt.spec.js.snap b/tests/yield/__snapshots__/jsfmt.spec.js.snap
new file mode 100644
index 000000000..68d2aaeb0
--- /dev/null
+++ b/tests/yield/__snapshots__/jsfmt.spec.js.snap
@@ -0,0 +1,16 @@
+exports[`test conditional.js 1`] = `
+"function* f() {
+  a = (yield) ? 1 : 1;
+  a = yield 1 ? 1 : 1;
+  a = 1 ? yield : yield;
+  a = 1 ? yield 1 : yield 1;
+}
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+function* f() {
+  a = (yield) ? 1 : 1;
+  a = yield 1 ? 1 : 1;
+  a = 1 ? yield : yield;
+  a = 1 ? yield 1 : yield 1;
+}
+"
+`;
diff --git a/tests/yield/conditional.js b/tests/yield/conditional.js
new file mode 100644
index 000000000..8abd9d310
--- /dev/null
+++ b/tests/yield/conditional.js
@@ -0,0 +1,6 @@
+function* f() {
+  a = (yield) ? 1 : 1;
+  a = yield 1 ? 1 : 1;
+  a = 1 ? yield : yield;
+  a = 1 ? yield 1 : yield 1;
+}
diff --git a/tests/yield/jsfmt.spec.js b/tests/yield/jsfmt.spec.js
new file mode 100644
index 000000000..939578260
--- /dev/null
+++ b/tests/yield/jsfmt.spec.js
@@ -0,0 +1,1 @@
+run_spec(__dirname, {parser: 'babylon'});