ESLintの導入と警告対応のメモ


React+ES6な環境で開発をしています。
その関係でES6・JSXに対応したLinterが必要と思いまして、ESLintを入れてみました。
その作業時のメモです。

## 環境
Mac OS X 10.10.5(Yosemite)
npm 2.7.5
eslint 2.1.0

## インストール

eslint本体

```
npm install -g eslint
```

今回はJSXも解析対象としたいので、Reactプラグイン追加します。

```
npm install -g eslint-plugin-react
```

## SublimeTextの設定
SublimeText使っているので、こちらでLinterを有効にすべく
Package Controlから[SublimeLinter](https://github.com/SublimeLinter/SublimeLinter3)と[SublimeLinter-contrib-eslint](https://github.com/roadhump/SublimeLinter-eslint)を入れています。
JSHintなどの他のLinterを無効化したい場合は、

Tools → SublimeLinter → Toggle Linter

で、使用可能なLinterのenabled/disabledの切替をしましょう。

## ルールの設定
プロジェクト用に.eslintrcを作成、設定します。
内容は[後述](#eslintrc)。


## ES6のルール・警告

ES6用のルールは以下にまとまってます。

http://eslint.org/docs/rules/#ecmascript-6

とりあえず一通りのルールを設定してみて、自分のコードで警告が出たものについては、以下のように対応をしてみました。

### prefer-allow-callback

```javascript:警告箇所の例
const sortedList = this.state.list.concat().sort(function (s1, s2) {
...中略
});

```

http://eslint.org/docs/rules/prefer-arrow-callback
this束縛もあるので、callback関数はArrow functionsで書いた方がいいですよ、とのこと。

```javascript:修正後
const sortedList = this.state.list.concat().sort((s1, s2) => {
...中略
});
```

### prefer-template

```javascript:警告箇所の例
...中略
{
    url: '/api/sample/' + this.state.hoge
},
...中略
```

http://eslint.org/docs/rules/prefer-template
文字列結合にはTemplate strings使いましょう、とのこと。

```javascript:修正後
...中略
{
    url: `/api/sample/${this.state.hoge}`
},
...中略
```

### object-shotrhand

```javascript:警告箇所の例
const hoge = 'hoge';
this.setState({
    hoge : hoge
});
```

http://eslint.org/docs/rules/object-shorthand
methodsとpropertiesがあり、今回はpropertiesの方に引っかかっています。
プロパティ名と設定する変数名が同じ場合は、プロパティ名を省略できると。
こだわりは無かったので省略してみました。

```javascript:修正後
const hoge = 'hoge';
this.setState({
    hoge
});
```

## Reactプラグインのルール・警告

React関連のルールは以下にまとまってます。

https://github.com/yannickcr/eslint-plugin-react

とりあえず一通りのルールを設定してみて、自分のコードで警告が出たものについては、以下のように対応をしてみました。

### display-name
 
```javascript:警告箇所の例
export default class App extends React.Component {
```

classの所に警告が付きます。
https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/display-name.md

displayNameの有無チェックなので外してもいいかと思いましたが、オプションで
acceptTranspilerNameを設定すれば、Class記法に合わせたチェックが可能になるようだったので、以下の設定で運用することにしました。

```.eslintrc
    "rules": {
...中略
        "react/display-name": [1, {"acceptTranspilerName": true}],
...中略

```

### no-set-state  

```javascript:警告箇所の例
this.setState{ hoge : 'fuga'};
```

みたいな箇所が警告対象となりました。
https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-set-state.md
Fluxしてるのでthis.setStateを呼び出さないようにしたい、というような場合に有効化するものらしく。
今回はFlux使わない/setState呼び出し多数なアプリを対象とした設定なので、ルールを無効化しました。

### prop-types
https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prop-types.md
そのままですが、propsの値に対してPropTypesを指定していない場合に警告となります。
今回はアプリ固有のComponentsしか作成せず、PropTypesを使うメリットがそれほどなかったので（本当は使った方がいいんでしょうが）、ルールを無効化しました。

###jsx-boolean-value

```javascript:警告箇所の例
render() {
    return (
        <div>
            <span aria-hidden={true}>x</span>
        </div>
    );
}
```

https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-boolean-value.md

booleanな属性、かつtrueを設定する場合にはvalueの指定を省略できるよ、とのこと。

```javascript:修正後
render() {
    return (
        <div>
            <span aria-hidden>x</span>
        </div>
    );
}
```

### jsx-no-literals

```javascript:警告箇所の例
render() {
    return (
        <div>hoge</div>
    );
} 
```

「hoge」のテキスト部分が警告となります。
https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-literals.md
リンクの内容そのままなんですが、、、このリテラルがイケてるのかどうかよく分からず違和感あったので、ルールを無効化しました。

### jsx-max-props-per-line

```javascript:警告箇所の例
render() {
    return (
        <div className="topBox" onClick={this.handleClick}>hoge</div>
    );
}
```

onClickの辺りが警告となります。
https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-max-props-per-line.md
JSX上の1行に指定できるprops数を超えた、ということみたいですね。
デフォルトは1とのことですが、このままだと縦長なコードになりそうで微妙だと思ったので、1行あたり2propsまでを許容するようにして一先ず運用することにしました。

```.eslintrc
    "rules": {
...中略
        "react/jsx-max-props-per-line": [1, {"maximum": 2}],
...中略
```

###jsx-sort-props

```javascript:警告箇所の例
render() {
    return (
        <img src={imageUrl} alt={this.props.unit.commodityName} />
    );
}
```

propsがアルファベット順に指定されていない、ということらしく。
(例の場合はsがaより前に来ている。)
propsの並び順、規約的に決めた方がいいのかもしれないとは思いましたが、現状の開発ではメリット感じられなかったので無効化。

## .eslintrc
現状こんな感じ。

```javascript:.eslintrc
{
    "extends": "eslint:recommended",
    "plugins": ["react"],
    "env": {
        "browser": true,
        "es6": true
    },
    parserOptions: {
        "ecmaVersion": 6,
        "sourceType": "module",
        "ecmaFeatures": {
            "jsx": true
        }
    },
    "rules": {
        "semi": 2,
        "no-empty-pattern": 2,
        "arrow-parens": 2,
        "arrow-spacing": 2,
        "constructor-super": 2,
        "generator-star-spacing": 2,
        "no-class-assign": 2,
        "no-const-assign": 2,
        "no-dupe-class-members": 2,
        "no-this-before-super": 2,
        "no-var": 2,
        "object-shorthand": 2,
        "prefer-arrow-callback": 2,
        "prefer-const": 2,
        "prefer-reflect": 2,
        "prefer-spread": 2,
        "prefer-template": 2,
        "require-yield": 2,
        "react/display-name": [1, {"acceptTranspilerName": true}],
        "react/forbid-prop-types": 1,
        "react/jsx-boolean-value": 1,
        "react/jsx-closing-bracket-location": 0,
        "react/jsx-curly-spacing": 1,
        "react/jsx-indent-props": 1,
        "react/jsx-max-props-per-line": [1, {"maximum": 2}],
        "react/jsx-no-duplicate-props": 1,
        "react/jsx-no-literals": 0,
        "react/jsx-no-undef": 1,
        "react/jsx-sort-prop-types": 1,
        "react/jsx-sort-props": 0,
        "react/jsx-uses-react": 1,
        "react/jsx-uses-vars": 1,
        "react/no-danger": 1,
        "react/no-did-mount-set-state": 1,
        "react/no-did-update-set-state": 1,
        "react/no-direct-mutation-state": 1,
        "react/no-multi-comp": 1,
        "react/no-set-state": 0,
        "react/no-unknown-property": 1,
        "react/prefer-es6-class": 1,
        "react/prop-types": 0,
        "react/react-in-jsx-scope": 1,
        "react/require-extension": 1,
        "react/self-closing-comp": 1,
        "react/sort-comp": 1,
        "react/wrap-multilines": 1        
    }
}
```

現状これで事足りてるので、後は運用しながら適宜調整しようと思います。

## checkstyle形式で出力
解析結果のフォーマットについては、コマンドラインの実行オプション「-f」で指定できます。
http://eslint.org/docs/user-guide/command-line-interface#f-format

```checkstyle形式で出力する例
% eslint /project/**/*.js -f checkstyle
```

現状CIにはJenkinsを使っていますが、この結果をcheckstyleプラグインに噛ませれば、CIでlintを回せそうです。

## gulpから使う

現状gulpを使っているので、そちらからも使えるように設定してみました。

必要なmoduleをインストール。

```
npm install gulp-eslint
npm install fs 
```
fsは結果をファイル出力する際に必要になります。

gulpfile書きます。

```javascript:gulpfile.js
var gulp = require('gulp');
var fs = require('fs');
var eslint = require('gulp-eslint');

gulp.task('lint', function () {
    return gulp.src(['**/*.js', '!gulpfile.js', '!node/**', '!node_modules/**'])
        .pipe(eslint('.eslintrc'))
        .pipe(eslint.format()) // 標準出力
        .pipe(eslint.format('checkstyle', fs.createWriteStream('checkstyle-result.xml'))); // checkstyle形式のファイル出力
});
```

package.jsonにscripts追加して

```javascript:package.json
{
...中略
  "scripts": {
    "lint": "gulp lint"
  },
...中略
}

```

```
npm run lint
```

で実行。

## 参考ページ
以下を参考にさせていただきました。
ありがとうございました。  

http://qiita.com/mysticatea/items/f523dab04a25f617c87d
https://www.bountysource.com/issues/29193844-how-to-output-formatter-to-file-using-gulp