npmパッケージのhtmllintについて - Lintルールのカスタマイズ -

HTMLの構文チェックにnpmパッケージの「htmllint」を使っているのですが、カスタマイズ関連でいつも忘れてググってしまうので備忘録として残す。

## 概要
- [htmllintについて](https://qiita.com/deren2525/items/a3ae60e1364830474635#htmllint%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)
- [Lintルールをカスタマイズしたい](https://qiita.com/deren2525/items/a3ae60e1364830474635#lint%E3%83%AB%E3%83%BC%E3%83%AB%E3%81%AE%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%9E%E3%82%A4%E3%82%BA)
- [Lintルールをカスタマイズしたはいいけど、ここの部分だけLintルールを変えたい。柔軟にルールを決めたいんだって時](https://qiita.com/deren2525/items/a3ae60e1364830474635#%E3%81%93%E3%81%93%E3%81%AE%E9%83%A8%E5%88%86%E3%81%A0%E3%81%91lint%E3%83%AB%E3%83%BC%E3%83%AB%E3%82%92%E5%A4%89%E3%81%88%E3%81%9F%E3%81%84%E3%82%93%E3%81%A0%E3%81%A3%E3%81%A6%E6%99%82)

## htmllintについて

- [htmllint](https://www.npmjs.com/package/htmllint)

「htmllint」をgulpで利用している場合は[gulp-htmllint](https://github.com/yvanavermaet/gulp-htmllint)
CLI で実行する場合は[htmllint-cli](https://github.com/htmllint/htmllint-cli) を使います。

node.js が入っている前提で進めます。

```
// インストール
$ npm install -g htmllint --save-dev
```


ルートディレクトリに`.htmllintrc`ファイルを生成します。
以下コマンドで自動生成されます。
自動生成された`.htmllintrc`にはデフォルトでLintルールが記載されています。
それについては後ほど。

```
// .htmllintrc 自動生成
$ htmllint init
```

LintチェックしてほしいHTMLファイルを指定すれば対象ページの構文チェックが行われます。

```
$ htmllint ファイルパス指定
```

デフォルトのLintルールでほぼほぼ空のHTMLをLintかけてみます。

```index.html
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>HTMLLint</title>
</head>
<body>
</body>
</html>
```

結果。怒られました。

```
$ htmllint index.html
index.html: line 4, col 1, indenting spaces must be used in groups of 4
index.html: line 5, col 1, indenting spaces must be used in groups of 4
```
Lintのルールでは、インデントの空白4文字分と決めているのに
このHTMLのインデントは空白2文字分になってるよ。と怒られています。

とはいえ、私は空白2文字分でいきたいので
ルールの方を変えていきます。

## Lintルールのカスタマイズ

先ほど自動生成された `.htmllintrc` を見てみると色々書かれています。
構文ルールのデフォルト値が指定されています。

```.htmllintrc
{
    "plugins": [],  // npm modules to load

    "maxerr": false,
    "raw-ignore-regex": false,
    "attr-bans": [
        "align",
        "background",
        "bgcolor",
        "border",
        "frameborder",
        "longdesc",
        "marginwidth",
        "marginheight",
        "scrolling",
        "style",
        "width"
    ],
    "indent-delta": false,
    "indent-style": "nonmixed",
    "indent-width": 4,
    "indent-width-cont": false,
    "spec-char-escape": true,
    "text-ignore-regex": false,
    "tag-bans": [
        "style",
        "b",
        "i"
    ],
    "tag-close": true,
    "tag-name-lowercase": true,
    "tag-name-match": true,
    "tag-self-close": false,
    "doctype-first": false,
    "doctype-html5": false,
    "attr-name-style": "dash",
    "attr-name-ignore-regex": false,
    "attr-no-dup": true,
    "attr-no-unsafe-char": true,
    "attr-order": false,
    "attr-quote-style": "double",
    "attr-req-value": true,
    "attr-new-line": false,
    "attr-validate": true,
    "id-no-dup": true,
    "id-class-no-ad": true,
    "id-class-style": "underscore",
    "class-no-dup": true,
    "class-style": false,
    "id-class-ignore-regex": false,
    "img-req-alt": true,
    "img-req-src": true,
    "html-valid-content-model": true,
    "head-valid-content-model": true,
    "href-style": false,
    "link-req-noopener": true,
    "label-req-for": true,
    "line-end-style": "lf",
    "line-no-trailing-whitespace": true,
    "line-max-len": false,
    "line-max-len-ignore-regex": false,
    "head-req-title": true,
    "title-no-dup": true,
    "title-max-len": 60,
    "html-req-lang": false,
    "lang-style": "case",
    "fig-req-figcaption": false,
    "focusable-tabindex-style": false,
    "input-radio-req-name": true,
    "input-req-label": false,
    "table-req-caption": false,
    "table-req-header": false,
    "tag-req-attr": false
}
```
どんな意味なのか下に書いていきますが、たくさんあるので
よく変更されがちなもののみ抜粋して下に記載します。大体はデフォルトのままでいいと思います。

構文エラーになった時のエラーメッセージも合わせて記載します。

ドキュメントはこちら
[Options List](https://github.com/htmllint/htmllint/wiki/Options)

### attr-bans
デフォルト：`["align", "background", "bgcolor", "border", "frameborder", "longdesc", "marginwidth", "marginheight", "scrolling", "style", "width"]`
属性禁止を指定する

```
// 構文エラーメッセージ ： <img>にwidthをHTML上に記述した場合（<img src="" alt="" width="">）
the `width` attribute is banned
```

### indent-style
デフォルト： `"nonmixed"`
インデントの空白をタブを使うか半角スペースを使うか

- `"tabs"` : タブ使用
- `"spaces"` : スペース使用
- `"nonmixed"` : タブでもスペースでもどちらでも良いけど統一はしてね
- `"false"` : 無制限

```
// 構文エラーメッセージ
invalid value for option indent-style: nonmixed
```

### indent-width
デフォルト：`4`
インデント空白を何文字分


```
// 構文エラーメッセージ
indenting spaces must be used in groups of 4
```

### tag-bans
デフォルト：`["style", "b", "i"]`
使用禁止のタグを指定する

```
// 構文エラーメッセージ ： <style>を使用した場合
the style tag is banned
```

### tag-self-close
デフォルト：`false`

最後に`/`を入れるかどうか（HTML5ルールにするのかそれ以下にするのか）

- `"always"` : HTML4仕様 （ 例 `<meta charset="UTF-8" />`）
- `"never"` : HTML5仕様 （ 例 `<meta charset="UTF-8">`）
- `false` : 制限なし

```
// 構文エラーメッセージ : "always"で 「/」 なしにした場合
void element should always close itself
```

### attr-name-style
デフォルト：`"dash"`
属性名の命名規則

- `"lowercase"` : 小文字で表現
- `"underscore"` : 小文字とアンダースコアで表現
- `"dash"` : 小文字とハイフンで表現
- `"camel"` : キャメルケースで表現
- `"bem"` : BEMで表現
- 自分で正規表現で指定 (`'/^[a-z]+$/g'`など).

```
// 構文エラーメッセージ
attribute names must match the format: 
```

### attr-quote-style
デフォルト : `"double"`
属性値を囲う手段

- `"double"` : ダブルクォーテーションのみ
- `"single"` : シングルクォーテーションのみ
- `"quoted"` : ダブルクォーテーションまたはシングルクォーテーション
- `false` : 制限なし

```
// 構文エラーメッセージ ： <body class='hoge'>
the `class` attribute is not double quoted
```

### id-class-style
デフォルト : `"underscore"`
クラス名、id名の命名規則指定

- `"lowercase"` : 小文字で表現
- `"underscore"` : 小文字とアンダースコアで表現
- `"dash"` : 小文字とハイフンで表現
- `"camel"` : キャメルケースで表現
- `"bem"` : BEMで表現
- 自分で正規表現で指定 (`'/^[a-z]+$/g'`など).

```
// 構文エラーメッセージ
class value must match the format: underscore
```

### class-style
デフォルト：`false`（制限なし）
id-class-style とほぼ同じ。
対象がクラスのみになります。
class-style が`false`の場合 id-class-style のルールが適用されます。

- `"lowercase"` : 小文字で表現
- `"underscore"` : 小文字とアンダースコアで表現
- `"dash"` : 小文字とハイフンで表現
- `"camel"` : キャメルケースで表現
- `"bem"` : BEMで表現
- `"none"` : 制限なし（id-class-style のルールも無視して制限なし）
- 自分で正規表現で指定 (`'/^[a-z]+$/g'`など).

### img-req-alt
デフォルト：`true`
`<img>`タグの`alt`属性の扱い

- `true` : `<img>`タグの`alt`属性には必ず値を入れること
- `"allownull"` : `alt`属性は必須だが値は空でもOK（`alt=""`でもOK）
- `false` : 制限なし

```
// 構文エラーメッセージ
the `alt` property must be set for image tags
```

### line-end-style
デフォルト：`lf`
改行コードの指定

- `"lf"` : LF
- `"crlf"` : CRLF
- `"cr"` : CR
- `false` : 制限なし

```
// 構文エラーメッセージ
line ending does not match format: lf
```
## ここの部分だけLintルールを変えたいんだって時

`.htmllint` にルールを一通り書いていますが
HTMLに直接Lintルールを書くこともできます。
その場合、優先度はHTMLに書いたルールが高です。

```
<!-- htmllint Lintのオプション = "値" -->
```

**こんな時に使いそうな場面の例**

1. クラス名を BEM で書いている（`.htmllintrc`に`class-style : "bem"`と設定）
2. JSライブラリを利用する時、そのライブラリのクラス名がBEMではなくキャメルで書かれている
3. このままだとJSライブラリを使用している部分がLintに引っかかる。
けどLintの設定は`class-style : "bem"`と変えたくない

みたいなパターンがあるとします。

```index.html
<div class="box">
  <div class="box__wrapper">
    <!-- ここからJSライブラリ使用 -->
    <div class="dropdown animate arrowTop open"> <!-- キャメルでアウト -->
      <div class="dropdownWrapper"> <!-- キャメルでアウト -->
        ....中略....
      </div>
    </div>
  </div>
</div>
```

今回は`class-style`のルールを変更したいので
`<!-- htmllint class-style = "none" -->`と書きます。（または`"camel"`）
JSライブラリの部分だけ変更したい時は以下のように置きます。

```index.html
<div class="box">
  <div class="box__wrapper">
    <!-- htmllint class-style = "none" -->
    <div class="dropdown">
      <div class="dropdownWrapper">
        ....中略....
      </div>
    </div>
  </div>
</div>
```

こうすることでLintはルールを変更した部分に対してはそこを見てLintチェックを行ってくれます。

複数指定も可能です。

```
<!-- htmllint class-style = "none"
     htmllint attr-name-style = "false"
     htmllint attr-validate = "false"
--> 
```

## まとめ


- 「htmllint」で Lintルールをカスタマイズする方法は`.htmllintrc`に記載するか、HTMLに直接記載する方法がある。
- `.htmllintrc`のルールだけでなくHTMLごとに設定を変更できるため柔軟性がある


ページを作っていくと、いつのまにかLintに引っかかってる事がよくあります。こまめのチェック大事

### 今回記事にした部分に関するドキュメント
[Options List](https://github.com/htmllint/htmllint/wiki/Options)
`.htmllintrc`オプションについて

[Inline Configurations
](https://github.com/htmllint/htmllint/wiki/Inline-Configurationshttps)HTMLにLintルールを記載する方法について