CSSのLintをstylelintにする


JavaScriptのLintは、[ESLint](http://eslint.org/)で設定が柔軟に出来て良かったんで、ESLintでやっているけれども、CSSの方でも同じようなLintツール無いのかなと思っていたら、[stylelint](http://stylelint.io/)が近い感じだった。


## Install

```
$ npm i stylelint --save-dev

or 

$ npm i -g stylelint
```
v1系だと[PostCSS](https://github.com/postcss/postcss)のプラグインとして使う以外なかったけれども、数時間前に[v2.0.0](https://github.com/stylelint/stylelint/releases/tag/2.0.0)がリリースされて、CLIで使えるようになってた。


## Usage

v1系だと、設定は`require('stylelint')()`の引数に渡す形で、ESLintの`.eslintrc`みたいに設定ファイルを自動で読み込むようにはなってなかったけど、v2.0.0から`.stylelintrc`があればその設定を読み込むようになった。

### CLI

CLIだと、

```sh
$ stylelint path/to/target.css [options]
```
の形。

使用できるオプションは、

```sh
$ stylelint --help
```
で見られる。

```sh 
    --config            設定ファイルのJSONへのパス
    --version           インストールしてあるstylelintのバージョン
    --custom-formatter  出力するフォーマットをカスタムするJSファイルへのパス
    -f, --formatter     出力するフォーマットを`json`か`string`か指定
    -q, --quiet         警告は出力しない(エラーのみ出力)
    -s, --syntax        標準ではないシンタックスを指定
```

### PostCSS

PostCSSのプラグインで使う場合、`stylelint`だけだとレポートが出力されないので、[postcss-reporter](https://github.com/postcss/postcss-reporter)を使う。

```js
var gulp = require('gulp'),
  postcss = require('gulp-postcss');

gulp.task('css', function () {
  return gulp
    .src('./src/css/*.css')
    .pipe(postcss([
      require('stylelint')(),
      require('postcss-reporter')()
    ]))
    .pipe(gulp.dest('./dist/css'));
});
```

オプションは、以下3つ。
- `config`: 設定オブジェクト。`config`がない場合、`.stylelintrc`を探すようになっている。
-  `configBasedir`: `extends`や`plugins`の設定に記述されるファイルのディレクトリパス。
-  `configOverrides`: `.stylelintrc`を読み込んだ上で、その設定を上書きして使う設定がある場合にこのオプションに記述する。


## 設定オブジェクト

設定オブジェクトには [rules](https://github.com/stylelint/stylelint/blob/master/docs/user-guide/rules.md)、extends、[plugins](https://github.com/stylelint/stylelint/blob/master/docs/user-guide/plugins.md)の3つがあって、それぞれ[ESLint](http://eslint.org/docs/user-guide/configuring.html)のそれと同じ意味合いのもの。

### rules

各ルールは、デフォルトが無効の状態、かつオプション値も設定されてない。
なので、自分で有効にして、必要に応じてオプションを設定しない限りは警告もエラーも出ない。  
ESLintと同じく、各ルールの有効無効は、`0`から`2`の数値で設定する。  

| 値  | 設定   |
|:----|--------|
| `0` | 無効   |
| `1` | 警告   |
| `2` | エラー |


v1.2.1 でのルールは以下。 (※ v2.0.0でルールの追加、オプション値の追加がされているので、最新のルールとは微妙に違う)  

| カテゴリ          | ルール                                              | 内容                                                                              | オプション                                                    |
|:------------------|-----------------------------------------------------|-----------------------------------------------------------------------------------|---------------------------------------------------------------|
| String            | `string-quotes`                                     | クォーテーションをシングルかダブルか統一                                          | string : "single" &#124; "double"                             |
| Color             | `color-hex-case`                                    | 16進数のカラーコードを大文字か小文字で統一する                                    | string : "upper" &#124; "lower"                               |
|                   | `color-hex-length`                                  | 16進数のカラーコードを省略するか否か                                              | string : "short" &#124; "long"                                |
|                   | `color-no-invalid-hex`                              | 無効なカラーコードを許可しない                                                    |                                                               |
| Number            | `number-leading-zero`                               | 1以下の少数の値で、小数点の前に0を入れるか入れないかを統一                        | string : "always" &#124; "never"                              |
|                   | `number-max-precision`                              | 小数点以下の桁数を制御                                                            | int                                                           |
|                   | `number-no-trailing-zeros`                          | 不要な0を許可しない                                                               |                                                               |
|                   | `number-zero-length-no-unit`                        | 値が0の場合に単位をつけない                                                       |                                                               |
| Function          | `function-calc-no-unspaced-operator`                | 関数calcの中でスペースなしの式を許可しない                                        |                                                               |
|                   | `function-comma-space-after`                        | 関数の中でカンマの直後にスペースを空けることを許可するか否か                      | string : "always" &#124; "never"                              |
|                   | `function-comma-space-before`                       | 関数の中でカンマの直前にスペースを空けることを許可するか否か                      | string : "always" &#124; "never"                              |
|                   | `function-linear-gradient-no-nonstandard-direction` | `linear-gradient`の仕様に沿ってない方角の値を許可しない                           |                                                               |
|                   | `function-parentheses-space-inside`                 | 関数の()の内側にスペースを許可しないか否か                                        | string : "always" &#124; "never"                              |
|                   | `function-space-after`                              | 関数の直後にスペースを許可しないか否か                                            | string : "always" &#124; "never"                              |
|                   | `function-url-quotes`                               | urlをダブル or シングルクォーテーションで囲うか、クォーテーションで囲わないか     | string : "single" &#124; "double" &#124; "none"               |
| Value             | `value-no-vendor-prefix`                            | ベンダープレフィックスを許可しない                                                |                                                               |
| Value list        | `value-list-comma-newline-after`                    | リストの値で、カンマの直後にスペースを許可しないか、改行を必須にするか            | string : "always" &#124; "always-multi-line" &#124; "never-multi-line"  |
|                   | `value-list-comma-newline-before`                   | リストの値で、カンマの直前にスペースを許可しないか、改行を必須にするか            | string : "always" &#124; "always-multi-line" &#124; "never-multi-line"  |
|                   | `value-list-comma-space-after`                      | リストの値で、カンマの直後にスペースを許可するか否か                              | string : "always" &#124; "never" &#124; "always-single-line" &#124; "never-single-line"  |
|                   | `value-list-comma-space-before`                     | リストの値で、カンマの直前にスペースを許可するか否か                              | string : "always" &#124; "never" &#124; "always-single-line" &#124; "never-single-line"  |
| Property          | `property-blacklist`                                | 許可しないプロパティをリストで指定                                                | array                                                         |
|                   | `property-no-vendor-prefix`                         | 不要なベンダープレフィックスのプロパティを許可しない                              |                                                               |
|                   | `property-whitelist`                                | 許可するプロパティをリストで指定                                                  | array                                                         |
| Custom property   | `custom-property-no-outside-root`                   | `:root`セレクタ以外でのカスタムプロパティを許可しない                             |                                                               |
|                   | `custom-property-pattern`                           | カスタムプロパティのパターンを指定                                                | regex or string                                               |
| Declaration       | `declaration-bang-space-after`                      | エクスクラメーションマークの直後にスペースを入れることを許可するか否か            | string : "always" &#124; "never"                              |
|                   | `declaration-bang-space-before`                     | エクスクラメーションマークの直前にスペースを入れることを許可するか否か            | string : "always" &#124; "never"                              |
|                   | `declaration-colon-newline-after`                   | コロンの直後に改行を必須にするかスペースを許可しないか                            | string : "always" &#124; "always-multi-line"                  |
|                   | `declaration-colon-space-after`                     | コロンの直後にスペースを入れることを許可するか否か                                | string : "always" &#124; "never" &#124; "always-single-line"  |
|                   | `declaration-colon-space-before`                    | コロンの直前にスペースを入れることを許可するか否か                                | string : "always" &#124; "never"                              |
|                   | `declaration-no-important`                          | `!important`の使用を許可しない                                                    |                                                               |
| Declaration block | `declaration-block-semicolon-newline-after`         | セミコロンの直後にスペースを許可しないか改行を必須にするか                        | string : "always" &#124; "always-multi-line" &#124; "never-multi-line"  |
|                   | `declaration-block-semicolon-newline-before`        | セミコロンの直前にスペースを許可しないか改行を必須にするか                        | string : "always" &#124; "always-multi-line" &#124; "never-multi-line"  |
|                   | `declaration-block-semicolon-space-after`           | セミコロンの直後にスペースを入れることを許可するか否か                            | string : "always" &#124; "never" &#124; "always-single-line" &#124; "never-single-line"  |
|                   | `declaration-block-semicolon-space-before`          | セミコロンの直前にスペースを入れることを許可するか否か                            | string : "always" &#124; "never" &#124; "always-single-line" &#124; "never-single-line"  |
| Nesting Block     | `nesting-block-opening-brace-newline-before`        | ネストしたブロックの開き括弧の直前に改行を必須にするかスペースを許可しないか      | string : "always" &#124; "always-single-line" &#124; "never-single-line" &#124; "always-multi-line" &#124; "never-multi-line"  |
|                   | `nesting-block-opening-brace-space-before`          | ネストしたブロックの開き括弧の直前にスペースを許可するか否か                      | string : "always" &#124; "never" &#124; "always-single-line" &#124; "never-single-line" &#124; "always-multi-line" &#124; "never-multi-line"  |
| Block             | `block-closing-brace-newline-after`                 | ブロックの閉じ括弧の直後に改行を必須にするかスペースを許可しないか                | string : "always" &#124; "always-single-line" &#124; "never-single-line" &#124; "always-multi-line" &#124; "never-multi-line"  |
|                   | `block-closing-brace-newline-before`                | ブロックの閉じ括弧の直前に改行を必須にするかスペースを許可しないか                | string : "always" &#124; "always-multi-line" &#124; "never-multi-line"  |
|                   | `block-closing-brace-space-after`                   | ブロックの閉じ括弧の直後にスペースを許可するか否か                                | string : "always" &#124; "never" &#124; "always-single-line" &#124; "never-single-line" &#124; "always-multi-line" &#124; "never-multi-line"  |
|                   | `block-closing-brace-space-before`                  | ブロックの閉じ括弧の直前にスペースを許可するか否か                                | string : "always" &#124; "never" &#124; "always-single-line" &#124; "never-single-line" &#124; "always-multi-line" &#124; "never-multi-line"  |
|                   | `block-no-empty`                                    | 空のブロックを許可しない                                                          |                                                               |
|                   | `block-opening-brace-newline-after`                 | ブロックの開き括弧の直後に改行を必須にするか                                      | string : "always" &#124; "always-multi-line" &#124; "never-multi-line"  |
|                   | `block-opening-brace-newline-before`                | ブロックの開き括弧の直前に改行を必須にするかスペースを許可しないか                | string : "always" &#124; "always-single-line" &#124; "never-single-line" &#124; "always-multi-line" &#124; "never-multi-line"
|                   | `block-opening-brace-space-after`                   | ブロックの開き括弧の直後に改行を必須にするかスペースを許可しないか                | string : "always" &#124; "never" &#124; "always-single-line" &#124; "never-single-line" &#124; "always-multi-line" &#124; "never-multi-line"  |
|                   | `block-opening-brace-space-before`                  | ブロックの開き括弧の直前にスペースを許可するか否か                                | string : "always" &#124; "never" &#124; "always-single-line" &#124; "never-single-line" &#124; "always-multi-line" &#124; "never-multi-line"  |
| Selector          | `selector-combinator-space-after`                   | セレクタの組み合わせの直後にスペースを許可するか否か                              | string : "always" &#124; "never"                              |
|                   | `selector-combinator-space-before`                  | セレクタの組み合わせの直前にスペースを許可するか否か                              | string : "always" &#124; "never"                              |
|                   | `selector-no-attribute`                             | 属性セレクタを許可しない                                                          |                                                               |
|                   | `selector-no-combinator`                            | セレクタの組み合わせを許可しない                                                  |                                                               |
|                   | `selector-no-id`                                    | idセレクタを許可しない                                                            |                                                               |
|                   | `selector-no-type`                                  | 要素型セレクタを許可しない                                                        |                                                               |
|                   | `selector-no-universal`                             | ユニバーサルセレクタを許可しない                                                  |                                                               |
|                   | `selector-no-vendor-prefix`                         | ベンダープレフィックスつきのセレクタを許可しない                                  |                                                               |
|                   | `selector-pseudo-element-colon-notation`            | 疑似要素のコロンを1つにするか2つにするか                                          | string : "single" &#124; "double"                             |
|                   | `selector-root-no-composition`                      | `:root` を他のセレクタと合わせて記述することを許可しない                          |                                                               |
| Selector list     | `selector-list-comma-newline-after`                 | セレクタのリストで、カンマの直後に改行を必須にするかスペースを許可しないか        | string : "always" &#124; "always-multi-line" &#124; "never-multi-line"  |
|                   | `selector-list-comma-newline-before`                | セレクタのリストで、カンマの直前に改行を必須にするかスペースを許可しないか        | string : "always" &#124; "always-multi-line" &#124; "never-multi-line"  |
|                   | `selector-list-comma-space-after`                   | セレクタのリストで、カンマの直後にスペースを許可するか否か                        | string : "always" &#124; "never" &#124; "always-single-line" &#124; "never-single-line"  |
|                   | `selector-list-comma-space-before`                  | セレクタのリストで、カンマの直前にスペースを許可するか否か                        | string : "always" &#124; "never" &#124; "always-single-line" &#124; "never-single-line"  |
| Rule              | `rule-nested-empty-line-before`                     | ネストしたルールの直前に空白行を必須にするか許可しないか                          | string : "always" &#124; "never" &#124; "always-multi-line" &#124; "never-multi-line"  |
|                   | `rule-no-duplicate-properties`                      | ルールの中でプロパティの重複を許可しない                                          |                                                               |
|                   | `rule-no-shorthand-property-overrides`              | ショートハンドプロパティで上書きすることを許可しない                              |                                                               |
|                   | `rule-no-single-line`                               | 単一行でルールを記述することを許可しない                                          |                                                               |
|                   | `rule-non-nested-empty-line-before`                 | ネストしてないルールの直前に空白行を必須にするか許可しないか                      | string : "always" &#124; "never" &#124; "always-multi-line" &#124; "never-multi-line"  |
|                   | `rule-properties-order`                             | ルールの中でのプロパティの順序を指定                                              | string or array : "alphabetical" &#124; array                 |
|                   | `rule-trailing-semicolon`                           | 省略可能なセミコロンを必須にするか許可しないか                                    | string : "always" &#124; "never"                              |
| Root              | `root-no-standard-properties`                       | 標準のプロパティを`:root`の中で許可しない                                         |                                                               |
| Media feature     | `media-feature-colon-space-after`                   | メディアフィーチャーの中で、コロンの直後にスペースを必須にするか許可しないか      | string : "always" &#124; "never"                              |
|                   | `media-feature-colon-space-before`                  | メディアフィーチャーの中で、コロンの直前にスペースを必須にするか許可しないか      | string : "always" &#124; "never"                              |
|                   | `media-feature-name-no-vendor-prefix`               | メディアフィーチャーの名前にベンダープレフィックスを許可しない                    |                                                               |
|                   | `media-feature-range-operator-space-after`          | メディアフィーチャーの中で、範囲演算子の直後にスペースを必須にするか許可しないか  | string : "always" &#124; "never"                              |
|                   | `media-feature-range-operator-space-before`         | メディアフィーチャーの中で、範囲演算子の直前にスペースを必須にするか許可しないか  | string : "always" &#124; "never"                              |
| Custom media      | `custom-media-pattern`                              | カスタムメディアクエリの命名パターンを指定                                        | regex or string                                               |
| Media query       | `media-query-parentheses-space-inside`              | メディアクエリの括弧の内側にスペースを必須にするか許可しないか                    | string : "always" &#124; "never"                              |
| Media query list  | `media-query-list-comma-newline-after`              | メディアクエリのリストで、カンマの直後に改行を必須にするかスペースを許可しないか  | string : "always" &#124; "always-multi-line" &#124; "never-multi-line"  |
|                   | `media-query-list-comma-newline-before`             | メディアクエリのリストで、カンマの直前に改行を必須にするか、スペースを許可しないか| string : "always" &#124; "always-multi-line" &#124; "never-multi-line"  |
|                   | `media-query-list-comma-space-after`                | メディアクエリのリストで、カンマの直後にスペースを必須にするか否か                | string : "always" &#124; "never" &#124; "always-single-line" &#124; "never-single-line"  |
|                   | `media-query-list-comma-space-before`               | メディアクエリのリストで、カンマの直前にスペースを必須にするか否か                | string : "always" &#124; "never" &#124; "always-single-line" &#124; "never-single-line"  |
| At rule           | `at-rule-empty-line-before`                         | @ルールの前に1行空けることを必須にするか否か                                      | string : "always" &#124; "never"                              |
|                   | `at-rule-no-vendor-prefix`                          | @ルールにベンダープレフィックスを許可しない                                       |                                                               |
| Comment           | `comment-empty-line-before`                         | コメントの前に1行空けることを必須にするか否か                                     | string : "always" &#124; "never"                              |
|                   | `comment-space-inside`                              | コメントマークの内側にスペースを必須にするか許可しないか                          | string : "always" &#124; "never"                              |
| General / Sheet   | `indentation`                                       | インデントを指定                                                                  | init or string : "tab"                                        |
|                   | `no-eol-whitespace`                                 | 行末のスペースを許可しない                                                        |                                                               |
|                   | `no-missing-eof-newline`                            | ファイルの最終行に空白行を必須にする                                              |                                                               |
|                   | `no-multiple-empty-lines`                           | 連続した空白行を許可しない                                                        |                                                               |

### extends

ESLintと同様に、`extends`で設定を読み込んで、その設定を拡張して使うことができる。


### plugins

ユーザが独自のルールを追加する場合、`plugins`で設定することで、`rules`に追加することができる。



## Links

- [stylelint](http://stylelint.io/)
- [Floss your style sheets with Stylelint - Ben Frain](http://benfrain.com/floss-your-style-sheets-with-stylelint/)