prettier-v1.13.7チートシート

# インストール
```bash
node -v && yarn -v
# v10.5.0
# 1.8.0

yarn add -D prettier
# └─ prettier@1.13.7
```

# オプション

`prettier`にはどのようなオプションがあり、それを設定すると、どうコードが整形されるかが分からなかったので、`v1.13.7`現在のオプションと整形結果をざっと書いていきます。

## デフォルト

```js
{
  "printWidth": 80,
  "tabWidth": 2,
  "useTabs": false,
  "semi": true,
  "singleQuote": false,
  "trailingComma": "none",
  "bracketSpacing": true,
  "jsxBracketSameLine": false,
  "arrowParens": "avoid",
  "rangeStart": 0,
  "rangeEnd": Infinity,
  "parser": "babylon",
  "filepath": undefined,
  "requirePragma": false,
  "insertPragma": false,
  "proseWrap": "preserve"
}
```

上記がオプション指定無しの設定のようです。[v1.13.7/docs/options](https://github.com/prettier/prettier/blob/1.13.7/docs/options.md)

下記のプログラムを

```js:index.js
// const code = `
describe('API',()=>{
  it('black 10x10 rect',done =>{
    let black= fs.readFileSync('test/10x10.png')
    pixel.parse(black)
    .then(images =>{
      let svg= pixelToSvg.convert(images[0])
      let $= cheerio.load(svg)

      let {width,height}= $('svg').attr()
      let colors= $('path').length
      let underFileSize= svg.length < limitFileSize

      equal(width,10)
      equal(height,10)
      equal(colors,1)
      equal(underFileSize,true)

      done()
    })
  })
})
// `
```

`console.log(require('prettier').format(code, opts))`のように実行すると、以下のように整形されます。

```js
describe("API", () => {
  it("black 10x10 rect", done => {
    let black = fs.readFileSync("test/10x10.png");
    pixel.parse(black).then(images => {
      let svg = pixelToSvg.convert(images[0]);
      let $ = cheerio.load(svg);

      let { width, height } = $("svg").attr();
      let colors = $("path").length;
      let underFileSize = svg.length < limitFileSize;

      equal(width, 10);
      equal(height, 10);
      equal(colors, 1);
      equal(underFileSize, true);

      done();
    });
  });
});
```

## [printWidth](https://github.com/prettier/prettier/blob/1.13.7/docs/options.md#print-width)
opts=`{printWidth:30}`とした場合

```js
describe("API", () => {
  it("black 10x10 rect", done => {
    let black = fs.readFileSync(
      "test/10x10.png"
    );
    pixel
      .parse(black)
      .then(images => {
        let svg = pixelToSvg.convert(
/// ...
```

## [tabWidth](https://github.com/prettier/prettier/blob/1.13.7/docs/options.md#tab-width)

opts=`{tabWidth:8}`とした場合

```js
describe("API", () => {
        it("black 10x10 rect", done => {
                let black = fs.readFileSync("test/10x10.png");
                pixel.parse(black).then(images => {
                        let svg = pixelToSvg.convert(images[0]);
/// ...
```

## [useTabs](https://github.com/prettier/prettier/blob/1.13.7/docs/options.md#tabs)

opts=`{useTabs:true}`とした場合

```js
describe("API", () => {
	it("black 10x10 rect", done => {
		let black = fs.readFileSync("test/10x10.png");
		pixel.parse(black).then(images => {
			let svg = pixelToSvg.convert(images[0]);
///...
```

> ※ qiita上では半角スペースで表示されるようです

## [semi](https://github.com/prettier/prettier/blob/1.13.7/docs/options.md#semicolons)

opts=`{semi:false}`とした場合

```js
describe("API", () => {
  it("black 10x10 rect", done => {
    let black = fs.readFileSync("test/10x10.png")
    pixel.parse(black).then(images => {
      let svg = pixelToSvg.convert(images[0])
///...
```

## [singleQuote](https://github.com/prettier/prettier/blob/1.13.7/docs/options.md#quotes) (Quotes)

opts=`{singleQuote:true}`とした場合

```js
describe('API', () => {
  it('black 10x10 rect', done => {
    let black = fs.readFileSync('test/10x10.png');
    pixel.parse(black).then(images => {
      let svg = pixelToSvg.convert(images[0]);
///...
```

## [trailingComma](https://github.com/prettier/prettier/blob/1.13.7/docs/options.md#trailing-commas)

opts=`{trailingComma:"es5",printWidth:30}`とした場合

```js
///...
        let $ = cheerio.load(
          svg
        );

        let {
          width,
          height,
        } = $("svg").attr();
///...
```

opts=`{trailingComma:"all",printWidth:30}`とした場合

```js
///...
        let $ = cheerio.load(
          svg,
        );

        let {
          width,
          height,
        } = $("svg").attr();
///...
```
## [bracketSpacing](https://github.com/prettier/prettier/blob/1.13.7/docs/options.md#bracket-spacing)

opts=`{bracketSpacing:false}`とした場合

```js
///...
      let {width, height} = $("svg").attr();
///...
```

## [jsxBracketSameLine](https://github.com/prettier/prettier/blob/1.13.7/docs/options.md#jsx-brackets) (JSX Brackets)

リンク先参照。

## [arrowParens](https://github.com/prettier/prettier/blob/1.13.7/docs/options.md#arrow-function-parentheses) (Arrow Function Parentheses)

opts=`{arrowParens:"always"}`とした場合

```js
describe("API", () => {
  it("black 10x10 rect", (done) => {
    let black = fs.readFileSync("test/10x10.png");
    pixel.parse(black).then((images) => {
///...
```

## `rangeStart`, `rangeEnd` ([Range](https://github.com/prettier/prettier/blob/1.13.7/docs/options.md#range))

リンク先参照。

## [parser](https://github.com/prettier/prettier/blob/1.13.7/docs/options.md#parser)

opts=`{parser:"markdown"}`とした場合、codeはmarkdownとしてマークダウン内のjsが整形されるようです。

[prettier.io/playground](https://prettier.io/playground/) 参照

## [filepath](https://github.com/prettier/prettier/blob/1.13.7/docs/options.md#filepath)

リンク先参照。

## [insertPragma](https://github.com/prettier/prettier/blob/1.13.7/docs/options.md#insert-pragma)

opts=`{insertPragma:true}`とした場合

```js
/** @format */

describe("API", () => {
///...
```

## [requirePragma](https://github.com/prettier/prettier/blob/1.13.7/docs/options.md#require-pragma)

opts=`{requirePragma:true}`とした場合

```js
describe('API',()=>{
  it('black 10x10 rect',done =>{
    let black= fs.readFileSync('test/10x10.png')
    pixel.parse(black)
///...
```

`code`内に既に`/** @format */`が存在する場合のみ、整形されます

## [proseWrap](https://github.com/prettier/prettier/blob/1.13.7/docs/options.md#prose-wrap)

markdown用のオプションです。

opts=`{parser:"markdown",proseWrap:"never"}`とした場合、平文などが一行にまとめられます。

[prettier.io/playground](https://prettier.io/playground/#N4Igxg9gdgLgprEAuEAJOBDAJnATgHSgF4TTDCB9AGQggGsAaCgAkh2YCMAbCMOgZ2YZccZgDMIuALYYY8LMwBUMWgEJF5KAAMdzAFb9CYgK5QwMAJbRmFnLAswAngAoAHgEpmwZiJjHcUMyuzAC+hDpamgAKFjwwAD4Agha4AA6SCagQ-oZQALR58UgFSPElhABSEAAWgQAiEHDxAMoA0gDi8QCMAMw9AByVGFCiAEqN8RUAYq3xPV0ALJp5zCtrqxvrW5ubmgDUzFQW-DCEzAcA7g7VQswA2lwWUHQAuszOAPQqH-wQUnAXap4ODuQgHYYKO7DCAwIG4ZjQOAvTRne7Q2F4BEjF5IZjMapyVJID4fOCuDBSVJcOAAOkgUmYAHIAKLkynU5iWGDUxmaGgiBkWVL8YwMrAQHjw-gOIT-GAMVjQfhwcxwPzw7BC45gJ4Ac2YcEeMBphAAwv4MBwHP5FVBlar1cwZK4LFJjIJcMd3QrlQpna73ZzDVxA5YzLZTDADcaQAwQBBUpYlchQMJcBALlFhAh+MgQBgAG4QWyxkAcXAYPhq5qpSt65AwXDGOBxp7K3AwKIV3UyZBiDBcZVxgyuABCFarMGaFLgRxGfYHQ5Atdw7bzMlwdHFFygpdSntgAHVbLDkAAmAAMcf3EGVh4rqTzIwLeFLIgAjsYUnAuxgexgF0HFsQGVKQLAbJtgOlKBdWpABFYwYTgQClxgS1jywU8kDPONGwwWI9VNP5exQKBEVLd04AAFUtXMkH7ICQhCIA) 参照。

# eslintと併用する

```yaml:.eslintrc
---
parser: babel-eslint

extends:
  - plugin:prettier/recommended

rules:
  prettier/prettier:
    - error
    -
      printWidth: 80
      tabWidth: 2
      useTabs: false
      semi: true
      singleQuote: false
      trailingComma: none
      bracketSpacing: true
      jsxBracketSameLine: false
      arrowParens: avoid
```

`prettier`に加え、いくつかのモジュールが必要になります。

```bash
yarn add -D babel-eslint eslint eslint-config-prettier eslint-plugin-prettier
# ├─ babel-eslint@8.2.5
# ├─ eslint-config-prettier@2.9.0
# ├─ eslint-plugin-prettier@2.6.1
# └─ eslint@5.0.1
```

整形対象がeslintのエラーとして表示されるようになり、`--fix`でprettierの整形が行えるようになります。

```bash
npx eslint index.js
# 1:10  error  Replace `'API',()=>` with `"API",·()·=>·`                                                   prettier/prettier
# 2:6   error  Replace `'black·10x10·rect',done·=>` with `"black·10x10·rect",·done·=>·`                    prettier/prettier
# 3:14  error  Replace `=·fs.readFileSync('test/10x10.png')` with `·=·fs.readFileSync("test/10x10.png");`  prettier/prettier
# 4:23  error  Replace `⏎····.then(images·=>` with `.then(images·=>·`                                      prettier/prettier
# 6:14  error  Replace `=·pixelToSvg.convert(images[0])` with `·=·pixelToSvg.convert(images[0]);`          prettier/prettier

npx eslint index.js --fix
cat index.js
# describe("API", () => {
#   it("black 10x10 rect", done => {
#     let black = fs.readFileSync("test/10x10.png");
#     pixel.parse(black).then(images => {
# ...
```

# eslint-config-vue + standardと併用する

`eslint-config-vue`と併用する場合は、下記のように追記します。

```yaml:.eslintrc
# parser: babel-eslint
parserOptions:
  parser: babel-eslint
  ecmaVersion: 2017
  sourceType: module

env:
  browser: true

extends:
  - standard
  - plugin:vue/recommended
  - plugin:prettier/recommended
# ...
```

```bash
yarn add -D eslint-config-standard
# └─ eslint-config-standard@11.0.0

yarn add -D eslint-plugin-standard eslint-plugin-import eslint-plugin-node eslint-plugin-promise
# ├─ eslint-plugin-import@2.13.0
# ├─ eslint-plugin-node@6.0.1
# ├─ eslint-plugin-promise@3.8.0
# └─ eslint-plugin-standard@3.1.0

yarn add -D eslint-plugin-vue@next
# └─ eslint-plugin-vue@4.0.0
```

```vue:src/components/App.vue
<template>
  <div>
    <ul>
      <li v-for="tweet in tweets" :key="tweet.id_str">
        {{tweet.id}}{{tweet.name}}
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  data() {
    return {
      tweets: []
    }
  }
}
</script>

<style scoped>
p{font-weight:bold}
li{font-family:monospace}
</style>
```

```bash
npx eslint src --ext vue --fix
```

```vue
<template>
  <div>
    <ul>
      <li v-for="tweet in tweets" :key="tweet.id_str">
        {{ tweet.id }}{{ tweet.name }}
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  data() {
    return {
      tweets: []
    }
  }
}
</script>

<style scoped>
p {
  font-weight: bold;
}
li {
  font-family: monospace;
}
</style>
```

Atomで`.vue`を`--fix`する場合、[linter-eslintの設定を修正する必要](https://github.com/vuejs/eslint-plugin-vue/issues/220#issuecomment-365596963)があります。

# eslint-config-airbnbと併用する(react用)

`eslint-config-airbnb`と併用する場合は、下記のように追記します。

```yaml:.eslintrc
# ...
extends:
  - airbnb
  - plugin:react/recommended
  - plugin:prettier/recommended
  - prettier/react
# ...
```

```bash
yarn add -D eslint-config-airbnb
# eslint-config-airbnb@17.0.0" has incorrect peer dependency "eslint@^4.19.1".
# eslint-config-airbnb@17.0.0" has unmet peer dependency "eslint-plugin-import@^2.12.0".
# eslint-config-airbnb@17.0.0" has unmet peer dependency "eslint-plugin-jsx-a11y@^6.0.3".
# eslint-config-airbnb@17.0.0" has unmet peer dependency "eslint-plugin-react@^7.9.1".
# └─ eslint-config-airbnb@17.0.0

yarn add -D eslint-plugin-import eslint-plugin-jsx-a11y eslint-plugin-react
# ├─ eslint-plugin-import@2.13.0
# ├─ eslint-plugin-jsx-a11y@6.0.3
# └─ eslint-plugin-react@7.10.0
```

```jsx:main.jsx
import React from 'react'
import {render} from 'react-dom'

render(
  <h1>Hello, world!</h1>,
  document.getElementById('root')
);
```

```bash
npx eslint main.jsx --fix
# /Users/59naga/Downloads/REPOS/prettier-cheat/index.js
#   1:19  error  Unable to resolve path to module 'react'       import/no-unresolved
#   2:24  error  Unable to resolve path to module 'react-dom'   import/no-unresolved
#   4:32  error  'document' is not defined
```

```jsx:main.jsx
import React from "react";
import { render } from "react-dom";

render(<h1>Hello, world!</h1>, document.getElementById("root"));
```

>
```bash
# (node:9942) [ESLINT_LEGACY_OBJECT_REST_SPREAD] DeprecationWarning: The 'parserOptions.ecmaFeatures.experimentalObjectRestSpread' option is deprecated. Use 'parserOptions.ecmaVersion' instead. (found in "node_modules/eslint-config-airbnb-base/index.js")
```
> `eslint-config-airbnb@17.0.0`現在、`eslint@5.0.1`との[互換性が保証されていません](https://github.com/airbnb/javascript/issues/1846)ので、`eslint@4`の使用を推奨します。

# eslint-config-flowtypeと併用する

`eslint-config-flowtype`と併用する場合は、下記のように追記します。

```yaml:.eslintrc
# ...
extends:
  - airbnb
  - plugin:flowtype/recommended
  - plugin:prettier/recommended
  - prettier/react
plugins:
  - flowtype
settings:
  flowtype:
    onlyFilesWithFlowAnnotation: true
# ...
```

```bash
yarn add -D eslint-plugin-flowtype
# └─ eslint-plugin-flowtype@2.49.3
```

```jsx:main.jsx
// @flow
import React from "react";
import { render } from "react-dom";

type Props = { label?: string };
type State = { count: number };

class MyComponent extends React.Component<Props, State> {
  // static defaultProps = {
  //   label: "Count"
  // };

  state = {
    count: 0
  };

  componentDidMount() {
    setInterval(() => {
      this.setState(prevState => ({
        count: prevState.count + 1
      }));
    }, 1000);
  }

  render() {
    const { count } = this.state;
    const { label } = this.props;
    return (
      <div>
        <p>
          {label} {count}
        </p>
      </div>
    );
  }
}

render(<MyComponent label="Count" />, document.getElementById("root"));
```

```bash
npx eslint main.jsx
# /Users/59naga/Downloads/REPOS/prettier-cheat/main.jsx
#    5:16  error  propType "label" is not required, but has no corresponding defaultProp declaration  react/require-default-props
# ...
```

flowの警告は、`--fix`を使わず手動で直すものが殆どと思います。（上記は`static`部分のコメントを戻すと警告は消えます）

必要に応じて、IDEからも警告を出したり、`--fix`できると使いやすいです。（自分はATOMの`linter-eslint`,`linter-flow`を使っています）

# 参考記事
* [prettier-v1.13.7/docs](https://github.com/prettier/prettier/tree/1.13.7/docs)
* [prettier.io/playground (バージョン差異に注意)](https://prettier.io/playground/)
* [React Components | Flow](https://flow.org/en/docs/react/components/)
* [Prettier 入門 ～ESLintとの違いを理解して併用する～](https://qiita.com/soarflat/items/06377f3b96964964a65d)
* [ESLintを使ってるプロジェクトにPrettierを導入した | yosuke.saito](https://saitoxu.io/2018/01/31/prettier.html)
* [古いJavaScript(ES5)でもESLint・Prettierの恩恵を受けよう :: JavaScript | Refills](https://syon.github.io/refills/rid/1518800/)
* [ESLintをAtomに導入し、Reactの構文にも対応したAirbnbのJSスタイルガイドを使う | maesblog](https://mae.chab.in/archives/2874)