ESLintのprefer-templateルールの話

Hacktoberfest期間中ということで、Serverless Frameworkにプルリクエストを送っている。

github.com

 

途中、ESLintの動作で気になる部分があったのでメモしておく。

 

 

[ESLintとは]

ESLintはJavaScript用の静的解析ツールである。return文に続けてコードが書かれており到達不可能な箇所や、未使用の変数などプログラムのミスを検出してくれるだけでなく、それらを自動的に修正することもできる。

eslint.org

 

ミスとして検出可能なルールはデフォルトで250以上用意されており、JSXやNode.js専用のルールも存在する。

 

利用する場合にはプロジェクトのルートディレクトリでnpm i -D eslintのコマンドを実行したのち、$(npm bin)/eslint --initコマンドで設定ファイルを生成する。package.jsonに以下のようにscripts定義を追加し、npm run lintコマンドを実行するとミスを検出することができる。

  "scripts": {
    "lint": "eslint . --cache"
  }

 

[prefer-templateルール]

いくつか用意されているデフォルトのルールのうちの一つが「prefer-templateルール」である。端的に言えば、'foo'+barのようなコードがあった時に、JavaScriptの言語機能であるテンプレートリテラル(テンプレート文字列)を用いて`foo${bar}`と記述しよう、というルールだ。

eslint.org

developer.mozilla.org

 

利用ルールに関する設定が記述されている.eslintrcファイルに以下のように追記するとprefer-templateルールを利用できる。

  "rules": {
    "prefer-template": "error"
  }

 

テストのために以下のような内容をindex.jsファイルに追記する。

  var name = 'bar'
  console.log('foo' + name)

 

この状態でnpm run lintを実行すると

index.js
  3:15  error  Unexpected string concatenation  prefer-template

✖ 1 problem (1 error, 0 warnings)
  1 error and 0 warnings potentially fixable with the `--fix` option.

のようにエラーとなり、--fixオプションをつけてコマンドを実行し、問題を自動的に修正するように伝えてくる。

 

[困ったことと回避策]

ここで、自動修正をすべく、package.jsonスクリプトを以下のように修正する。

  "scripts": {
    "lint": "eslint . --cache",
    "lint:fix": "npm run lint -- --fix",
  } 

 

これで、npm run lint:fixコマンドを実行すると自動的にソースコードが修正されるようになる。

実際にやってみると、以下のようになる。

【修正前】
  console.log('foo' + name)
【修正後】
  console.log(`foo${  name}`)

 

お分かりいただけるだろうか。なぜか${name}ではなく、${ name}と半角スペースが2つ混入してしまっている。

ルールの説明ページをみる限りでは、

【修正前】
  var str = "Hello, " + name + "!";
【修正後】
  var str = `Hello, ${name}!`;

となるように読めるが、実際にはスペースが混入して以下のようになる。

【修正前】
  var str = "Hello, " + name + "!";
【修正後】
  var str = `Hello, ${  name  }!`;

 

サイトが正しくて、バグっているのかとも思ったが、テストコードをみる限りどうやら意図した動作であるらしい。ルールの実装箇所を読むと、どうやらこの辺りで+演算子の前後の空白を取り出してテンプレートリテラルの変数に付加しているらしかった。

実際、ローカルにインストールされたこのファイルに、以下のように.trim()を追加する修正を加えて、改めてnpm run lint:fixコマンドを実行すると、不要なスペースのない意図した結果が得られた。

  const textBeforePlus = getTextBetween(currentNode.left, plusSign).trim();
  const textAfterPlus = getTextBetween(plusSign, currentNode.right).trim();

 

せっかくのHacktoberfestなのでプルリクエストを送ろうかとも考えたが、元の動きからかなり変わってしまうので、オプション化するなどした方がいいのだろうか……と迷っているうちに眠くなってしまったので、止めておいた。

 

Serverless Frameworkに提出中のプルリクエストにESLintを実行してこの問題が生じたが、結局手で不要なスペースを取り除いて回避することにした。

ESLint実行前のプログラムの+演算子の前後に半角スペースを入れず、'foo'+nameのように実装していれば、問題なく`foo${name}`に修正されるのだが、すでに`foo${  name}`と修正された後だったので、仕方なく手作業をした。

 

[まとめ]

これまでESLintあまり気にしていなかったけど、細かいところが気になってソースコードを読んだ。

細かいところを気にする前に、一度ちゃんとESLintの基本的な使い方学んで、いつかはESLintに修正される箇所のない高品質なJavaScriptプログラムを書きたい。