ESLintのパラメーターにGlobを渡すときに注意すること

## 背景

ESLintエラーが自分の環境では検知されず、他の開発者さんの環境では検知されるという現象がありました。

正直なところ、ESLintの知識が浅いまま組んだコンフィグが何となく正常に動作しているという認識だったので、.eslintrcファイル内のミスを疑っていましたが、最終的にはShell（PowerShellとBash）による動作の違いにたどり着きました。

<br/>

## 環境

OS
Windows WSL2 Ubuntu 20.04


<br/>

## 結論

注意すべきことは単純なので、先に書きます。

**Globをクォーテーションで囲む**

です。[ドキュメント](https://eslint.org/docs/latest/use/command-line-interface#run-the-cli)にも以下の記載があります。

> Please note that when passing a glob as a parameter, it is expanded by your shell. The results of the expansion can vary depending on your shell, and its configuration. If you want to use node glob syntax, you have to quote your parameter (using double quotes if you need it to run in Windows), as follows:
`npx eslint "lib/**"`

> Globをパラメーターに渡すときは、使用しているShellによって拡張されることに注意してください。Globの動作はShellや、Shell設定などで異なります。node globを利用したければ、以下に記載のようにクォーテーションで囲んでください。(Windowsで動作させる場合は、ダブルクォーテーションを利用してください。)
`npx eslint "lib/**"`

まさに注意書きです。

↓がコマンド例です。

```bash:package.json
"lint": "eslint ./**/*.tsx" #これはだめ×
```

これを以下のように修正したところ、私の環境でも検知されるようになりました。

```bash:package.json
"lint": "eslint \"./**/*.tsx\"" #ダブルクォーテーションを置く〇
```

この分かりやすい注意書きを見逃して、ESLintを設定したつもりになっていた自分が恥ずかしくなる半面、正常に動作している環境もあるし、実のところある時期までは自分の環境でも正常に動作していました。

ミスの言い訳を増やすために、原因をもう少し深堀してみたいと思います。


<br/>

## クォーテーション無しでも動作していた？

そもそも最初に私がコマンドを組んだときから、クォーテーションが無かったので、その時にESLintが正常に検知できていなければ気づいたはずです。現に他の開発者さんの環境では今も動いています。

**原因はPowerShellを使っていたことにありました。**

PowerShellは、コマンド引数となる対象文字列をダブルクオーテーションで扱うようです。
[PowerShell Language Specification セクション 8.2](https://www.microsoft.com/en-us/download/details.aspx?id=36389) 

>A command invocation consists of the command's name followed by zero or more arguments. The rules governing arguments are as follows:
>- An argument that is not an expression, but which contains arbitrary text without unescaped white space, is treated as though it were double quoted. Letter case is preserved.

> コマンド呼び出しは、コマンド名とそれに続く引数から成ります。ルールは以下です。
> - 式ではなく、スペースを含まない任意の文字列を含む引数は、ダブルクォーテーションを付加され、大文字・小文字の状態が保持されます。

これによって、以下のESLintコマンドのGlob引数も見た目はクオーテーション無しでしたが、実行時にちゃんとダブルクォーテーションが付加されて実行されていたわけです。

```bash
# Power Shellでは、以下のようにクオーテーション無しでも、、
"lint": "eslint ./**/*.tsx"

# ダブルクォーテーションが自動補完されて動作していた！
eslint "./**/*.tsx"
```

私のマシンで動作しなくなったのは、PJ期間中にWSL(Bash)環境に移行したため、上記の自動補完が動いてくれなくなったことが原因でした。

ちなみにBashでは、クォーテーションが無いGlob文字列は展開されます。つまり、解析が先に行われます。また、「\**」という表現も、globstarオプションが有効になっていない限り、すべてのサブディレクトリを検索してくれるわけではないのではありません。

したがって、`eslint ./**/*.tsx`という表現は、**一つ下の階層のtsx拡張子を持つファイルに**ESLintチェックを行うということになり、対象範囲がものすごく狭くなり、想定とは異なるチェック範囲になっていました。


<br/>

## glob-parent

ここまでの調査で言い訳は十分に整いました。

最後にeslintに渡されたGlobがどうなるかだけ簡単に見てみたいと思います。

私のリーディングにミスが無ければ、この[箇所](https://github.com/eslint/eslint/blob/03fc4aa847bd0445e7b3ea81bcc9523b1847facc/lib/cli-engine/file-enumerator.js#LL402C10-L402C10)でパターンマッチングをしています。[glob-parent](https://github.com/gulpjs/glob-parent)がESLintのGlobを処理しているんですね。

<br/>

## 最後に

**Bash -> 引数にテキスト -> クオーテーションをつける**

ESLintの検知エラーから、最終的にはBashの使い方を学ぶことができました。

今日も仕事が無い分、時間を有意義に使えたと思います:innocent:

<br/>

## 参考

[ESLintコマンドライン（公式ドキュメント）](https://eslint.org/docs/latest/use/command-line-interface#run-the-cli)

[PowerShellのクォーテーションについて](https://www.red-gate.com/simple-talk/sysadmin/powershell/when-to-quote-in-powershell/)

[PowerShell Language Specification](https://www.microsoft.com/en-us/download/details.aspx?id=36389)

[Glob](https://mywiki.wooledge.org/glob)