Stylusをstylelintするプラグインstylelint-plugin-stylus作ってみた

以前、[VueファイルのStylusをstylelintしたかった話](https://qiita.com/ota-meshi/items/aafe3bbef12ac1f25f51) という記事を書きましたが、その続きです。

[stylelint]はCSSだけでなく[SCSSやSass](https://sass-lang.com/)や[Less](http://lesscss.org/)もサポートしており、Vueファイルの`<style>`タグ内部のスタイルシートも検証できるリンターですが、残念ながら[Stylus]はサポートしていません。

[以前の記事]で[stylelint]が[Stylus]でも動くようにパーサー（[PostCSS]プラグイン）を作りました。
その後、少しづつ、[Stylus]用のルールを作ったり、[stylelint]周辺ツールの[Stylus]をサポートを進めたりしながら、[stylelint]のプラグインを作ってみたのでその紹介です。

# [stylelint]プラグイン [stylelint-plugin-stylus]

[stylelint-plugin-stylus]という[stylelint]で[Stylus]をサポートするためのプラグインを作っています。
このプラグインは下記の特徴を持ちます。

- [stylelint]で[Stylus]をサポートさせ、[stylelint]の多くの検証ルールを[Stylus]で利用できるようにします。
- [stylelint-plugin-stylus]が提供する独自の検証ルールを使用して[Stylus]の潜在的な問題、コードスタイル違反を見つけることができます。
- [stylelintの自動修正]を使用して、自動的に問題を修正したり、コードスタイルを統一させることができます。

## DEMO

ブラウザ上でどう動くか確認できます。

- [DEMO](https://ota-meshi.github.io/stylelint-plugin-stylus/playground/)

## 使用方法

※[stylelint]を導入していない方は、まず[stylelint]を導入してください。
以降の説明は[stylelint]を導入している前提で進めます。

### インストール

[stylelint-plugin-stylus]をインストールしてください。

```bash
npm install --save-dev stylelint-plugin-stylus
```

### カスタムシンタックスの設定

[stylelint]は標準では[Stylus]を正しく解析しないので、[Custom Syntax](https://stylelint.io/user-guide/usage/options#customsyntax)というOptionを使って[Stylus]を解析できるようにします。  

- CLIの場合

`--custom-syntax`オプションで`stylelint-plugin-stylus/custom-syntax`を指定します。

```bash
stylelint ... --custom-syntax stylelint-plugin-stylus/custom-syntax
```

- VSCodeの場合

[stylelint公式のVSCode拡張](https://marketplace.visualstudio.com/items?itemName=stylelint.vscode-stylelint)を利用する場合の設定です。

`.vscode/settings.json`に下記のように追記します。

`"stylelint.customSyntax"`オプションに`"stylelint-plugin-stylus/custom-syntax"`を指定します。

```json-doc:.vscode/settings.json
{
    "stylelint.customSyntax": "stylelint-plugin-stylus/custom-syntax",
}
```

ついでに `"stylelint.validate"` オプションで`"stylus"`を追加して、[stylelintのVSCode拡張](https://marketplace.visualstudio.com/items?itemName=stylelint.vscode-stylelint)で`.styl`や`.stylus`を解析するように設定してください。  

```json-doc:.vscode/settings.json
{
    "stylelint.customSyntax": "stylelint-plugin-stylus/custom-syntax",
    "stylelint.validate": [
        ...,
        // ↓ Add "stylus" language.
        "stylus"
    ]
}
```

これらの設定で、内部的には[以前の記事]で紹介した[postcss-styl]を利用して[Stylus]のソースファイルをパース（および文字列化）するようになります。

### [stylelint]の設定

[stylelint]の設定ファイル`.stylelintrc.*`や`stylelint.config.js`に設定します。
そもそもの設定の詳細は次のリンクを参照してください: https://stylelint.io/user-guide/configure.

この設定を使用して、[stylelint-plugin-stylus]が提供する検証ルールを使用したり、[Stylus]で使えないルールをOFFにしたりします。

- 共有設定を利用 

[stylelint-plugin-stylus]は共有設定を提供しているので、これを使用する場合は次のように設定します。

```js:stylelint.config.js
module.exports = {
  extends: [
    // "stylelint-config-standard", などすでに設定している設定
    // ↓共有設定を追加
    "stylelint-plugin-stylus/standard",
    // ↓または次の共有設定を追加
    // "stylelint-plugin-stylus/recommended",
  ],
}
```

提供する共有設定は次の２つです。

1. `"stylelint-plugin-stylus/recommended"` ... [stylelint-config-recommended]と対になるように設計しているルールセットです。 [stylelint-plugin-stylus]が提供する潜在的な問題を検証するルールを有効にし、[Stylus]で利用することができない（ことが確認できている）[stylelint]の標準ルールをOFFにします。
2. `"stylelint-plugin-stylus/standard"` ... [stylelint-config-standard]と対になるように設計しているルールセットです。 `"stylelint-plugin-stylus/recommended"`の設定に追加して、[stylelint-plugin-stylus]が提供するコードスタイルを検証するルールを有効にします。

- 共有設定を利用しない

共有設定を利用しない場合はpluginsへの追加と個別のルール設定が必要です。

```js:stylelint.config.js
module.exports = {
  plugins: [
    // ↓プラグインを追加
    "stylelint-plugin-stylus"
  ],
  rules: {
    // ↓各ルール設定を追加
    "stylus/declaration-colon": "never",
    "stylus/pythonic": "always",
    "stylus/selector-list-comma": "never",
    "stylus/semicolon": "never",
    "stylus/single-line-comment": "always",
  }
}
```

## [stylelint-plugin-stylus]の提供する検証ルール

[Stylus]用に作成した検証ルールの紹介です。
全量は[ドキュメント](https://ota-meshi.github.io/stylelint-plugin-stylus/#rules)を参照してください。

※ここで紹介するのは[stylelint-plugin-stylus]の提供する検証ルールだけです。
[stylelint組み込みのルール]や、他の[stylelint plugin]のルールも使用できます。

### [stylus/single-line-comment-no-empty](https://ota-meshi.github.io/stylelint-plugin-stylus/rules/single-line-comment-no-empty.html)

シングルラインコメント（`//`形式のコメント）の内容が空のコメントを報告します。
[stylelint]標準ルールにも[comment-no-empty](https://stylelint.io/user-guide/rules/comment-no-empty)というルールがありますが、このルールは見事に`//`形式のコメントを検証してくれないので`//`形式のコメントはこのルールで検証します。  

```scss
// ✓ GOOD
// single line comment

// ✗ BAD
//
```

### [stylus/at-extend-style](https://ota-meshi.github.io/stylelint-plugin-stylus/rules/at-extend-style.html)

`@extend`機能の`@extend`か`@extends`かのスタイル違反を報告します。
`"stylus/at-extend-style": ["@extend"]` と設定すると`@extends`を使っている箇所を報告します。また[自動修正オプション]を利用して自動的に`@extends`を`@extend`に置き換えます。

```stylus
a
  // ✓ GOOD
  @extend .foo
  // ✗ BAD
  @extends .foo
```

### [stylus/declaration-colon](https://ota-meshi.github.io/stylelint-plugin-stylus/rules/declaration-colon.html)

宣言部でコロンを必ず使用するか必ず省略するかのスタイル違反を報告します。
`"stylus/declaration-colon": ["never"]` と設定すると宣言部でコロンを使っている箇所を報告します。また[自動修正オプション]を利用して自動的に不要なコロンを削除します。

```stylus
a
  // ✓ GOOD
  color red
  // ✗ BAD
  color: red
```

### [stylus/hash-object-property-comma](https://ota-meshi.github.io/stylelint-plugin-stylus/rules/hash-object-property-comma.html)

ハッシュオブジェクトの定義でカンマを必ず使用するか必ず省略するかのスタイル違反を報告します。
`"stylus/hash-object-property-comma": ["always"]` と設定すると、ハッシュオブジェクトの定義でカンマをつけていない箇所を報告します。また[自動修正オプション]を利用して自動的にカンマを追加します。

```stylus
foo = {
  // ✓ GOOD
  a: 1,
  b: 2,
  // ✗ BAD
  c: 3
  d: 4
}
```

### [stylus/pythonic](https://ota-meshi.github.io/stylelint-plugin-stylus/rules/pythonic.html)

中括弧を必ず使用するか必ず省略する（インデントベース構文を利用する）かのスタイル違反を報告します。
`"stylus/pythonic": ["always"]` と設定すると中括弧を使っている箇所を報告します。また[自動修正オプション]を利用して自動的に中括弧を削除し、インデントベース構文に修正します。

```stylus
// ✓ GOOD
.foo
  color: red;

// ✗ BAD
.foo {
  color: red;
}
```

### [stylus/selector-list-comma](https://ota-meshi.github.io/stylelint-plugin-stylus/rules/selector-list-comma.html)

CSSセレクターの区切りにカンマを必ず使用するか必ず省略する（インデントベース構文を利用する）かのスタイル違反を報告します。
`"stylus/selector-list-comma": ["never"]` と設定するとカンマを使っている箇所を報告します。また[自動修正オプション]を利用して自動的にカンマを削除し、インデントベース構文に修正します。

```stylus
// ✓ GOOD
.foo
.bar
  color red

// ✗ BAD
.foo,
.bar
  color red

.foo, .bar
  color red
```

### [stylus/semicolon](https://ota-meshi.github.io/stylelint-plugin-stylus/rules/semicolon.html)

セミコロンを必ず使用するか必ず省略するかのスタイル違反を報告します。
`"stylus/semicolon": ["never"]` と設定するとセミコロンを使っている箇所を報告します。また[自動修正オプション]を利用して自動的にセミコロンを削除します。

```stylus
a
  // ✓ GOOD
  color red
  // ✗ BAD
  color red;
```

### [stylus/single-line-comment-double-slash-space-after](https://ota-meshi.github.io/stylelint-plugin-stylus/rules/single-line-comment-double-slash-space-after.html)

シングルラインコメントの`//`後の空白スタイル違反を報告します。
`"stylus/single-line-comment-double-slash-space-after": ["always"]` と設定すると`//`後に空白が無い箇所を報告します。また[自動修正オプション]を利用して自動的に空白を挿入します。

```scss
// ✓ GOOD
// OK

//✗ BAD
//NG
```

### [stylus/single-line-comment](https://ota-meshi.github.io/stylelint-plugin-stylus/rules/single-line-comment.html)

シングルラインコメントが使用できる箇所で必ずシングルラインコメントの使用するか必ずマルチラインコメントを使用するかのスタイル違反を報告します。
`"stylus/single-line-comment": ["always"]` と設定するとシングルラインコメントが使用できる箇所でマルチラインコメントを使用している箇所を報告します。また[自動修正オプション]を利用して自動的にシングルラインコメントに修正します。

```scss
// ✓ GOOD
// マルチラインコメント
.foo { // マルチラインコメント
}
.bar {
/* 行末コメントでは無い場合 */ }
/*
 * 複数行
 * コメント
 */
/*! bufferedスタイル */

/* ✗ BAD */
/* マルチラインコメントだがシングルラインコメントが使用できる */
/*
  マルチラインコメントだが内容は１行なのでシングルラインコメントが使用できる
*/
.foo { /* マルチラインコメントだがシングルラインコメントが使用できる */
}
```

### [stylelint]標準ルールのラッパールール

[stylus/indentation](https://ota-meshi.github.io/stylelint-plugin-stylus/rules/indentation.html)や、[stylus/no-eol-whitespace](https://ota-meshi.github.io/stylelint-plugin-stylus/rules/no-eol-whitespace.html)や、[stylus/block-closing-brace-empty-line-before](https://ota-meshi.github.io/stylelint-plugin-stylus/rules/block-closing-brace-empty-line-before.html)など、[stylelint]本体で持っているルールで[Stylus]ではうまく動かないルールの、[Stylus]でも動くように改良したルールが多数あります。


# 他のツールと比較（してません）

まだ他のツールとの比較はしてません。そのうち気が向いたら比較するかもしれません。

[Stylus]のリンターの有名どころだと[stylint](https://github.com/SimenB/stylint)ですかね。
[Stylus]本家に[stlint](https://github.com/stylus/stlint)なんてのもあるようですがこれは流行っているのでしょうか？
フォーマッターの有名どころだと[Stylus Supremacy](https://thisismanta.github.io/stylus-supremacy/)ですかね。

ドキュメントを眺める限り、`.vue`ファイルの`<style lang="stylus">` まで検証・フォーマットできるのはこの[stylelint]と[stylelint-plugin-stylus]の組み合わせだけですか？さあ？どうなのでしょうか？


[stylelint]: https://stylelint.io/
[stylelint-config-recommended]: https://github.com/stylelint/stylelint-config-recommended
[stylelint-config-standard]: https://github.com/stylelint/stylelint-config-standard
[stylelintの自動修正]: https://stylelint.io/user-guide/usage/options#fix
[自動修正オプション]: https://stylelint.io/user-guide/usage/options#fix
[Stylus]: http://stylus-lang.com/
[PostCSS]: https://postcss.org/
[postcss-styl]: https://github.com/ota-meshi/postcss-styl
[vscode-stylelint]: https://marketplace.visualstudio.com/items?itemName=stylelint.vscode-stylelint
[stylelint-plugin-stylus]: https://ota-meshi.github.io/stylelint-plugin-stylus/
[以前の記事]: https://qiita.com/ota-meshi/items/aafe3bbef12ac1f25f51
[stylelint plugin]: https://stylelint.io/user-guide/configure#plugins
[stylelint組み込みのルール]: https://stylelint.io/user-guide/rules/list