Repository: jlongster/prettier
Pull request #714 (2017-02-15 14:16:37)

docs: Add pre-commit hook with 🚫💩 lint-staged section to the README
As discussed on twitter: https://twitter.com/dan_abramov/status/831616492068290561


Patch:
diff --git a/README.md b/README.md
index d408e9786..c4ab30824 100644
--- a/README.md
+++ b/README.md
@@ -124,6 +124,34 @@ prettier --write 'src/**/*.js' 'bin/*.js'
 
 In the future we will have better support for formatting whole projects.
 
+#### Pre-commit hook for changed files
+
+[🚫💩 lint-staged](https://github.com/okonet/lint-staged) can re-format your files that are marked as "staged" via `git add`  before you commit.
+
+Install it along with [pre-commit](https://github.com/observing/pre-commit) (or [husky](https://github.com/typicode/husky)):
+
+```bash
+npm install --save-dev lint-staged pre-commit
+```
+
+and add this config to your `package.json`:
+
+```json
+{
+  "scripts": {
+    "lint:staged": "lint-staged"
+  },
+  "lint-staged": {
+    "*.js": [
+      "prettier --write",
+      "git add"
+    ]
+  },
+  "pre-commit": "lint:staged"
+}
+```
+
+
 ### API
 
 The API is a single function exported as `format`. The options
@@ -200,9 +228,13 @@ Can also be installed using `ext install prettier-vscode`
 
 [Check repository for configuration and shortcuts](https://github.com/esbenp/prettier-vscode)
 
+### Visual Studio
+
+Install the [JavaScript Prettier extension](https://github.com/madskristensen/JavaScriptPrettier)
+
 ### Sublime Text
 
-Sublime Text support is available through Package Control and 
+Sublime Text support is available through Package Control and
 the [JsPrettier](https://packagecontrol.io/packages/JsPrettier) plug-in.
 
 ### JetBrains
diff --git a/src/printer.js b/src/printer.js
index 188f30d2d..e8bfe91be 100644
--- a/src/printer.js
+++ b/src/printer.js
@@ -185,7 +185,8 @@ function genericPrintNoParens(path, options, print) {
       const parent = path.getParentNode();
 
       // Avoid indenting sub-expressions in if/etc statements.
-      if(
+      if (
+        shouldInlineLogicalExpression(n) ||
         (parent.type === "IfStatement" ||
          parent.type === "WhileStatement" ||
          parent.type === "DoStatement" ||
@@ -375,6 +376,10 @@ function genericPrintNoParens(path, options, print) {
       return join(" ", parts);
     case "ImportSpecifier":
       if (n.imported) {
+        if (n.importKind) {
+          parts.push(path.call(print, "importKind"), " ");
+        }
+
         parts.push(path.call(print, "imported"));
 
         if (n.local && n.local.name !== n.imported.name) {
@@ -703,21 +708,7 @@ function genericPrintNoParens(path, options, print) {
         } else {
           parts.push(printPropertyKey(path, options, print));
         }
-
-        let printedValue = path.call(print, "value");
-        if (shouldPrintSameLine(n.value)) {
-          parts.push(concat([": ", printedValue]));
-        } else {
-          parts.push(
-            group(concat([
-              ":",
-              ifBreak(" (", " "),
-              indent(options.tabWidth, concat([softline, printedValue])),
-              softline,
-              ifBreak(")")
-            ]))
-          );
-        }
+        parts.push(concat([": ", path.call(print, "value")]));
       }
 
       return concat(parts); // Babel 6
@@ -1828,8 +1819,7 @@ function printArgumentsList(path, options, print) {
           lastArg.body.type === "ObjectExpression" ||
           lastArg.body.type === "ArrayExpression" ||
           lastArg.body.type === "CallExpression" ||
-          lastArg.body.type === "JSXElement") ||
-      lastArg.type === "NewExpression");
+          lastArg.body.type === "JSXElement"));
 
   if (groupLastArg) {
     const shouldBreak = printed.slice(0, -1).some(willBreak);
@@ -2574,6 +2564,13 @@ function isBinaryish(node) {
   return node.type === "BinaryExpression" || node.type === "LogicalExpression";
 }
 
+function shouldInlineLogicalExpression(node) {
+  return node.type === "LogicalExpression" && (
+    node.right.type === "ObjectExpression" ||
+    node.right.type === "ArrayExpression"
+  );
+}
+
 // For binary expressions to be consistent, we need to group
 // subsequent operators with the same precedence level under a single
 // group. Otherwise they will be nested such that some of them break
@@ -2616,7 +2613,11 @@ function printBinaryishExpressions(path, parts, print, options, isNested) {
       parts.push(path.call(print, "left"));
     }
 
-    const right = concat([node.operator, line, path.call(print, "right")]);
+    const right = concat([
+      node.operator,
+      shouldInlineLogicalExpression(node) ? " " : line,
+      path.call(print, "right")
+    ]);
 
     // If there's only a single binary expression: everything except && and ||,
     // we want to create a group in order to avoid having a small right part
@@ -2784,28 +2785,6 @@ function isObjectTypePropertyAFunction(node) {
     util.locStart(node.key) !== util.locStart(node.value);
 }
 
-function shouldPrintSameLine(node) {
-  const type = node.type;
-  return namedTypes.Literal.check(node) ||
-    type === "ArrayExpression" ||
-    type === "ArrayPattern" ||
-    type === "ArrowFunctionExpression" ||
-    type === "AssignmentPattern" ||
-    type === "CallExpression" ||
-    type === "FunctionExpression" ||
-    type === "Identifier" ||
-    type === "JSXElement" ||
-    type === "Literal" ||
-    type === "MemberExpression" ||
-    type === "NewExpression" ||
-    type === "ObjectExpression" ||
-    type === "ObjectPattern" ||
-    type === "StringLiteral" ||
-    type === "ThisExpression" ||
-    type === "TypeCastExpression" ||
-    type === "UnaryExpression";
-}
-
 function isFlowNodeStartingWithDeclare(node, options) {
   if (options.parser !== "flow") {
     return false;


Test patch:
diff --git a/tests/binary-expressions/__snapshots__/jsfmt.spec.js.snap b/tests/binary-expressions/__snapshots__/jsfmt.spec.js.snap
index 31d4ce314..5ce0e6c95 100644
--- a/tests/binary-expressions/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/binary-expressions/__snapshots__/jsfmt.spec.js.snap
@@ -1,3 +1,36 @@
+exports[`test inline-object-array.js 1`] = `
+"prevState = prevState || {
+  catalogs: [],
+  loadState: LOADED,
+  opened: false,
+  searchQuery: \'\',
+  selectedCatalog: null,
+};
+
+this.steps = steps || [
+  {
+    name: \'mock-module\',
+    path: \'/nux/mock-module\',
+  },
+];
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+prevState = prevState || {
+  catalogs: [],
+  loadState: LOADED,
+  opened: false,
+  searchQuery: \"\",
+  selectedCatalog: null
+};
+
+this.steps = steps || [
+  {
+    name: \"mock-module\",
+    path: \"/nux/mock-module\"
+  }
+];
+"
+`;
+
 exports[`test short-right.js 1`] = `
 "this._cumulativeHeights &&
  Math.abs(
diff --git a/tests/binary-expressions/inline-object-array.js b/tests/binary-expressions/inline-object-array.js
new file mode 100644
index 000000000..76d47eabc
--- /dev/null
+++ b/tests/binary-expressions/inline-object-array.js
@@ -0,0 +1,14 @@
+prevState = prevState || {
+  catalogs: [],
+  loadState: LOADED,
+  opened: false,
+  searchQuery: '',
+  selectedCatalog: null,
+};
+
+this.steps = steps || [
+  {
+    name: 'mock-module',
+    path: '/nux/mock-module',
+  },
+];
diff --git a/tests/flow/import_type/__snapshots__/jsfmt.spec.js.snap b/tests/flow/import_type/__snapshots__/jsfmt.spec.js.snap
index 0beb91ee7..059cd220d 100644
--- a/tests/flow/import_type/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/flow/import_type/__snapshots__/jsfmt.spec.js.snap
@@ -345,6 +345,21 @@ function foo() {
 "
 `;
 
+exports[`test import_type_specifier.js 1`] = `
+"/**
+ * @flow
+ */
+
+import { Foo, type Baz } from \"../module\";
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+/**
+ * @flow
+ */
+
+import { Foo, type Baz } from \"../module\";
+"
+`;
+
 exports[`test issue-359.js 1`] = `
 "/* @flow */
 
diff --git a/tests/flow/import_type/import_type_specifier.js b/tests/flow/import_type/import_type_specifier.js
new file mode 100644
index 000000000..4e5d1bfae
--- /dev/null
+++ b/tests/flow/import_type/import_type_specifier.js
@@ -0,0 +1,5 @@
+/**
+ * @flow
+ */
+
+import { Foo, type Baz } from "../module";
diff --git a/tests/flow/promises/__snapshots__/jsfmt.spec.js.snap b/tests/flow/promises/__snapshots__/jsfmt.spec.js.snap
index 62b8c4e86..abd7104a9 100644
--- a/tests/flow/promises/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/flow/promises/__snapshots__/jsfmt.spec.js.snap
@@ -376,9 +376,11 @@ new Promise((resolve, reject) => resolve(0)).then(function(num) {
 
 // Promise constructor resolve(Promise<T>) -> then(T)
 new Promise(function(resolve, reject) {
-  resolve(new Promise(function(resolve, reject) {
-    resolve(0);
-  }));
+  resolve(
+    new Promise(function(resolve, reject) {
+      resolve(0);
+    })
+  );
 }).then(function(num) {
   var a: number = num;
   var b: string = num; // Error: number ~> string
@@ -386,11 +388,15 @@ new Promise(function(resolve, reject) {
 
 // Promise constructor resolve(Promise<Promise<T>>) -> then(T)
 new Promise(function(resolve, reject) {
-  resolve(new Promise(function(resolve, reject) {
-    resolve(new Promise(function(resolve, reject) {
-      resolve(0);
-    }));
-  }));
+  resolve(
+    new Promise(function(resolve, reject) {
+      resolve(
+        new Promise(function(resolve, reject) {
+          resolve(0);
+        })
+      );
+    })
+  );
 }).then(function(num) {
   var a: number = num;
   var b: string = num; // Error: number ~> string
@@ -428,9 +434,11 @@ new Promise(function(resolve, reject) {
 
 // TODO: Promise constructor reject(Promise<T>) ~> catch(Promise<T>)
 new Promise(function(resolve, reject) {
-  reject(new Promise(function(resolve, reject) {
-    reject(0);
-  }));
+  reject(
+    new Promise(function(resolve, reject) {
+      reject(0);
+    })
+  );
 }).catch(function(num) {
   var a: Promise<number> = num;
 
diff --git a/tests/object-prop-break-in/__snapshots__/jsfmt.spec.js.snap b/tests/object-prop-break-in/__snapshots__/jsfmt.spec.js.snap
index cb925d852..7bb3a515e 100644
--- a/tests/object-prop-break-in/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/object-prop-break-in/__snapshots__/jsfmt.spec.js.snap
@@ -49,9 +49,8 @@ const a = classnames({
 });
 
 const b = classnames({
-  \"some-prop\": (
-    this.state.longLongLongLongLongLongLongLongLongTooLongProp === true
-  )
+  \"some-prop\": this.state.longLongLongLongLongLongLongLongLongTooLongProp ===
+    true
 });
 
 const c = classnames({
@@ -71,9 +70,8 @@ const f = classnames({
 });
 
 const g = classnames({
-  \"some-prop\": (
-    longLongLongLongLongLongLongLongLongLongLongLongLongTooLongVar || 1337
-  )
+  \"some-prop\": longLongLongLongLongLongLongLongLongLongLongLongLongTooLongVar ||
+    1337
 });
 "
 `;
diff --git a/tests/object_colon_bug/__snapshots__/jsfmt.spec.js.snap b/tests/object_colon_bug/__snapshots__/jsfmt.spec.js.snap
index a2cc5d93c..6e02fe691 100644
--- a/tests/object_colon_bug/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/object_colon_bug/__snapshots__/jsfmt.spec.js.snap
@@ -5,9 +5,9 @@ exports[`test bug.js 1`] = `
 }
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 const foo = {
-  bar: (
-    props.bar ? props.bar : noop
-  ),
+  bar: props.bar
+    ? props.bar
+    : noop,
   baz: props.baz
 };
 "