【ESLint】eslint-plugin-lodash-templateがEJSを（部分的に）サポートしたよ

かなり前に、[【ESLint】eslint-plugin-lodash-template作ってみたよ](https://qiita.com/ota-meshi/items/6e218768c7483e279898) という記事を書き、ちょっと前に [【ESLint】eslint-plugin-lodash-templateがJavaScriptテンプレートをサポートしたよ](https://qiita.com/ota-meshi/items/3f90e70e485ff3684416) という記事を書きましたが、[eslint-plugin-lodash-template]をJavaScriptテンプレートサポートさせたときついでに、部分的に[EJS]をサポートをしたのでその思い出を残します。 

[eslint-plugin-lodash-template]を基本的な使い方で使えば、[EJS]で[ESLint]が動くはずなので、
[EJS]での使い方の説明は無いです。仕組みをどう変えたかの思い出の話がメインです。

# [eslint-plugin-lodash-template]とは

[Lodashの`_.template`](https://lodash.com/docs/#template)に渡して使えるテンプレートタグ内のJavaScriptに対して[ESLint]で検証できるようにする[ESLint]のプラグインです。

今回の変更で[EJS]構文でも[ESLint]でエラー検出ができるようになりました！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84259/bf5b3b99-8180-3e22-4859-c3d64ab87777.png)

[WEBで試す]

# [EJS]とは

JavaScriptを使ったテンプレート構文です。

```erb
<% if (user) { %>
  <h2><%= user.name %></h2>
<% } %>
```

公式はこちら https://ejs.co/

[Lodashの`_.template`]に似た構文ですが、
HTMLエスケープする([EJS]は`<%=`)、しない([EJS]は`<%-`)、の意味が逆だったり、
`<%_ ... _%>`のような無駄な空白を除去するタグ記法があったり、
`<%# ... %>`というコメントタグ記法があったり、
`<%%`というリテラルを表現する記法があったりします。

# [EJS]を部分的にサポートしました

以前から、受け入れる[タグ構文をカスタマイズ](https://github.com/ota-meshi/eslint-plugin-lodash-template#customize-parser)する機能(`parserOptions`を利用)がありましたが、
これを拡張して[EJS]の記法を設定できるようにしました。
（拡張子`.ejs`に自動的に適用する共有設定も提供するようにしました。）

## [EJS]のタグを処理できるように変更しました。

[EJS]はタグ記法は[Lodashの`_.template`]に比べてタグの記法が豊富です。
開始タグ・終了タグに様々な種類があり、組み合わせることができます。
以前までは、開始タグ・終了タグを１種類ずつしか受け入れられなかったのですが、
[EJS]をサポートするために、開始タグ・終了タグの種類を配列で受け入れ、構文解析できるようにしました。

```js
// script部分
evaluate:    [ ["<%", "<%_"] /*開始タグ２種類*/, ["%>", "-%>", "_%>"] /*終了タグ3種類*/ ],
// 補完部分（HTMLエスケープなし）
interpolate: [  "<%-"        /*開始タグ*/    , ["%>", "-%>", "_%>"] /*終了タグ3種類*/ ],
// 補完部分（HTMLエスケープあり）
escape:      [  "<%="        /*開始タグ*/    , ["%>", "-%>", "_%>"] /*終了タグ3種類*/ ],
```

また、以前までは、コメントやリテラルを処理する機能はなかったのですが、（[Lodashの`_.template`]にはコメントやリテラルという概念はなかったので。）
コメントタグ記法、リテラルタグ記法も受け入れ、構文解析できるようにしました。

```js
// コメント部分
comment:    [ "<%#" /*開始タグ*/, ["%>", "-%>", "_%>"] /*終了タグ3種類*/ ],
// リテラル
literal:    [ "<%%" /*タグ （リテラルには終了タグの概念はない様子）*/ ],
```

## 共有設定で`.ejs`用の設定を適用

[eslint-plugin-lodash-template]の提供する共有設定で、以下ように`overrides`を利用して、拡張子`.ejs`のファイルに[EJS]で動作する用の`parserOptions`を設定しています。
これによって`.ejs`のファイルでは自動的に[EJS]のタグで構文解析するようになりました。

```js
module.exports = {
    // ...
    overrides: [
        {
            files: ["*.ejs"], // `.ejs`に適用
            parserOptions: {
                // eslint-plugin-lodash-template用の設定
                templateSettings: {
                    // 上記で書いたやつ
                    evaluate: [["<%", "<%_"], ["%>", "-%>", "_%>"]],
                    interpolate: ["<%-", ["%>", "-%>", "_%>"]],
                    escape: ["<%=", ["%>", "-%>", "_%>"]],
                    comment: ["<%#", ["%>", "-%>", "_%>"]],
                    literal: ["<%%"],
                },
            },
        },
    ],
}
```

# 結果

これらの変更で[EJS]構文でも[ESLint]でエラー検出ができるようになりました！（再掲）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84259/bf5b3b99-8180-3e22-4859-c3d64ab87777.png)


# なぜ（部分的）と言っているのか？

[EJS]には古い構文で`<% include _header %>`というようなincludeディレクティブというのがまだ息してるらしく、[eslint-plugin-lodash-template]はこれを解析できません。なので（部分的）サポートということにしています。

[eslint-plugin-lodash-template]: https://github.com/ota-meshi/eslint-plugin-lodash-template
[EJS]: https://ejs.co/
[Lodashの`_.template`]: https://lodash.com/docs/#template
[ESLint]: https://eslint.org/
[WEBで試す]: https://ota-meshi.github.io/eslint-plugin-lodash-template/playground/#eJyVVttu4zYQ/RVChYF2EdZoHwOv3/vQPwgQjKixxA1FanlJ7AYB9l/7Iz2kLMn22kn6JOnMmeHcqddKuYar+2qzehTrL6I1riYjUmAf7kTn6lozXpxSaaConRVf1uJxtd00+lkoQyF8fYAJG9nGh2q7WQPfPtgHu0kGTyE2q1+EZ9uwF0aHKNxuNP67WB3lj2LnvPj1mXyRzIzfxGs+KZNAM3q7WX0dGfn8NYBJ/23kbdblTLyMTkDY/bH9+yAs9Sx0ENlAeS8GICucYfsXXHviIj5GnBmiTlF0FFnUrG0rqBBOMlGsDP/++FHOngKv7iqfDIfq/jUnJkSfVHRehjSwr+7/vKsQrmy0Z5WtFKTlGNlLzzH5ETGuodDJyP1g4MKaYvQaDrHMAUhFAS59wHwmk1h+Ty7yVSYb7lG2Dy12sTdSGZcJsvaknhhK/GK0vW74qkIYSL1/guuLO8du+sQJR4VPWP6kRY0+tfGqvKe9nFMbJGopb9qyTjZpMFrh40TpFhev8TAjMtL1UMA8DfumOW1ReN0sBjWi94MzNPfbNS3vuU2GvHzpNJxFTm8G1ycTdUk7MqHt6NY7bl/yg/J6iIavZxoKI0EO5EsLsffO3+Ryr7PR/xducWapjeTviYwMur2p8ULeZmc+rsEc3nv9dFrusw7GURQOVsnBu14HuLZnleIxAZBiUlk2jOXrS4hhFuR1DOU5ioy5HlnE1uBW/sPeLbhtfqJiWV3DaBzKRs8JHSXRO4Od1fJ+AhuuU9uyX76RhbyIFgRbUJJvwxkwet5zX2Pvn0me+HAKHGcqp2BCy/ScfUjVITUqb9Ri+FyI5Q3JHAfvL0LmffQka+cMk80nxXNJ7rcJ2ZExsfMutd0MJZTu3OJ4p16A2lr4d62M0/yWzA4zems+83zpAGeb3J03Qu/1nptpAgmlj1TPQqxFGQ597cyEuPobIjdmpjgVaZaiMaOLB1SnThqTvbjueQyIFwAxHM+dsMBmd5GM0FHjXsDGbanhfVPupEUjL4LcNp6WboidDrJmXKZ8crdCkDB0u+UDOeRismyheWcXmWdCwmpzAgXasdxpi+gPFyhmiE5HIFn8jTTSUM1Lpo4gWn6BEDGjv9G6qrsEOSga5vNPJuVFx5HssZvwt4BlhX2gZBoami6TSXTQbJqCwKzUwdLo5PEiQKlczsjbXcXfoIlfEn77D9n5dzw=