IstanbulJS - レポート改善案

# 概要
[IstanbulJS](https://github.com/istanbuljs/istanbuljs)が生成するHTMLレポートでは未網羅のコードがハイライトされて表されるが、ハイライトの範囲が奇妙に感じられた。様々なコードに対してHTMLレポートを生成し、それぞれのハイライト範囲についての考察を以下にまとめる。

![screencapture-takuyahara-github-io-share-20190104_IstanbulJS_Coverage_Issue-00_Problem-javascript_v2-coverage-lcov-report-2_Function-0_Normal-ClassMethod-js-html-2019-01-17-04_51_00.png](https://qiita-image-store.s3.amazonaws.com/0/286440/48cefe4f-d60a-01be-6fc2-fd635b019c42.png)


# 環境
* macOS 10.14.2
* Node v11.1.0
* React 16.7.0
* create-react-app 2.1.2

簡便さのため、Reactプロジェクトで検証を行った。

# 再現用リポジトリ
検証環境を再現するリポジトリを以下に示す。

* [JavaScript - react-scripts@1.xのテンプレートを使用](https://github.com/TakuyaHara/share/tree/master/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v1)
* [JavaScript - react-scripts@2.xのテンプレートを使用](https://github.com/TakuyaHara/share/tree/master/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2)
* [TypeScript - react-scripts@1.xのテンプレートを使用](https://github.com/TakuyaHara/share/tree/master/20190104_IstanbulJS_Coverage_Issue/00_Problem/typescript_v1)
* [TypeScript - react-scripts@2.xのテンプレートを使用](https://github.com/TakuyaHara/share/tree/master/20190104_IstanbulJS_Coverage_Issue/00_Problem/typescript_v2)

# 検証用コード
HTMLレポートにてハイライトの対象となる `ステートメント` `ブランチ` `関数` に対して、4種類の記法を用いたコードで検証を行った。

* Normal - インデントや改行を適宜用いて記述する。
* Split - Normalでハイライトされた箇所を複数行に分割して記述する。
* Nested - `ステートメント` `ブランチ` `関数` をネストして記述する。
* Abuse - `ステートメント` `ブランチ` `関数` を1行にまとめ、同じ行に2回記述する。

# 考察
[JavaScript - react-scripts@2.xのテンプレートを使用](https://github.com/TakuyaHara/share/tree/master/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2)にて生成した各レポートの内容を、以下のアイコンを用いて考察する。

* 🤔 - 奇妙に感じられる点を示す。
* 💡 - 改善案を示す。
* 🚫 - 検証できなかったことを示す。

## Statement
### Normal
#### [Normal](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/0_Statement/0_Normal/Normal.js.html)
🤔 ステートメントが1文字多くハイライトされている。
💡 ステートメントを正確にハイライトさせる。

### Split
#### [Split](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/0_Statement/1_Split/Split.js.html)
🤔 ステートメントの1行目しかハイライトされていない。
💡 複数行にまたがってステートメントの全体をハイライトさせる。

### Nested
#### [Nested](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/0_Statement/2_Nested/Nested.js.html)
🚫 [Normalでハイライトされている箇所](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/0_Statement/0_Normal/Normal.js.html)をネストできないため、検証不可。

### Abuse
#### [Abuse](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/0_Statement/3_Abuse/Abuse.js.html)
🤔 💡 [Normalで言及した内容](#normal-1)と同様。


## Branch
### Normal
#### [Conditional Operator](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/1_Branch/0_Normal/ConditionalOperator.js.html)
🤔 ステートメントが1文字多くハイライトされている。
💡 ステートメントを正確にハイライトさせる。

#### [If](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/1_Branch/0_Normal/If.js.html)
🤔 `else if` 節の1行目しかハイライトされていない。
💡 `else if` 節の全体( `if` キーワード以降)を複数行にまたがってハイライトさせる。

#### [ShortCircuitEvaluation](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/1_Branch/0_Normal/ShortCircuitEvaluation.js.html)
🤔 ステートメントが1文字多くハイライトされている。
💡 ステートメントを正確にハイライトさせる。

#### [Switch](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/1_Branch/0_Normal/Switch.js.html)
🤔 `case` 節、 `default` 節ともに行末までハイライトされている。
💡 `:` 以降のスペースやコメントはプログラムとして意味を持たないので、ハイライトを `:` で終わらせる。



### Split
#### [Conditional Operator](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/1_Branch/1_Split/ConditionalOperator.js.html)
🚫 [Normalでハイライトされている箇所](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/1_Branch/0_Normal/ConditionalOperator.js.html)を分割できないため、検証不可。

#### [If](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/1_Branch/1_Split/If.js.html)
🤔 💡 [Normalで言及した内容](#if)と同様。

#### [ShortCircuitEvaluation](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/1_Branch/1_Split/ShortCircuitEvaluation.js.html)
🚫 [Normalでハイライトされている箇所](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/1_Branch/0_Normal/ShortCircuitEvaluation.js.html)を分割できないため、検証不可。

#### [Switch](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/1_Branch/1_Split/Switch.js.html)
🤔 💡 [Normalで言及した内容](#switch)と同様。



### Nested
#### [Conditional Operator](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/1_Branch/2_Nested/ConditionalOperator.js.html)
🤔 💡 [Normalで言及した内容](#conditional-operator)と同様。

#### [If](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/1_Branch/2_Nested/If.js.html)
🤔 `else` 節がハイライトされていない。
💡 `if` 文の全体をハイライトさせる。

#### [ShortCircuitEvaluation](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/1_Branch/2_Nested/ShortCircuitEvaluation.js.html)
🚫 [Normalでハイライトされている箇所](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/1_Branch/0_Normal/ShortCircuitEvaluation.js.html)をネストできないため、検証不可。

#### [Switch](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/1_Branch/2_Nested/Switch.js.html)
🤔 `default` 節がない場合、`case` 節がハイライト(黄)される。
🤔 `default` 節がある場合、`case` 節と `default` 節がハイライト(黄)されない。
💡 複数行にまたがって `switch` 文の全体をハイライト(赤)する。


### Abuse
#### [Conditional Operator](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/1_Branch/3_Abuse/ConditionalOperator.js.html)
🤔 💡 [Normalで言及した内容](#conditional-operator)と同様。

#### [If](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/1_Branch/3_Abuse/If.js.html)
🤔 `else if` 節が `}` より先までハイライトされており、アイコン[E]がハイライトの上に乗っている。
💡 `else if` 節のハイライトを `}` で終わらせる。

#### [ShortCircuitEvaluation](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/1_Branch/3_Abuse/ShortCircuitEvaluation.js.html)
🤔 💡 [Normalで言及した内容](#shortcircuitevaluation)と同様。

#### [Switch](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/1_Branch/3_Abuse/Switch.js.html)
🤔 `case` 節と `default` 節のハイライト(黄)がステートメントのハイライト(赤)までカバーしている。
💡 `case` 節と `default` 節のハイライトを `:` で終わらせる。

🤔 二つのステートメントが一つにまとめてハイライト(赤)されている。
💡 各ステートメントを独立してハイライトさせる。


## Function
関数の定義部について述べる。

### Normal
#### [ArrowFunction](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/2_Function/0_Normal/ArrowFunction.js.html)
**括弧がある場合**
🤔 `(` から2文字しかハイライトされていない。
💡 `(` から `)` までハイライトさせる。

**括弧がない場合**
🤔 引数名の先頭の2文字しかハイライトされていない。
💡 引数名の全体をハイライトさせる。

#### [ClassMethod](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/2_Function/0_Normal/ClassMethod.js.html)
🤔 クラスメソッド名の先頭の2文字しかハイライトされていない。
💡 クラスメソッド名から`)` までハイライトさせる。

#### [FunctionDeclaration](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/2_Function/0_Normal/FunctionDeclaration.js.html)
🤔 関数名から`(`までしかハイライトされていない。
💡 `function` キーワードから `)` までハイライトさせる。

#### [FunctionExpression](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/2_Function/0_Normal/FunctionExpression.js.html)
**無名関数の場合**
🤔 `function` キーワードの先頭の2文字しかハイライトされていない。
💡 `function` キーワードから `)` までハイライトさせる。

**名前付き関数の場合**
🤔 関数名から`(`までしかハイライトされていない。
💡 `function` キーワードから `)` までハイライトさせる。



### Split
#### [ArrowFunction](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/2_Function/1_Split/ArrowFunction.js.html)
**括弧がある場合**
🤔 `(` から始まる1行目しかハイライトされていない。
💡 `(` から `)` まで複数行にまたがって全てハイライトさせる。

**括弧がない場合**
🚫 [Normalでハイライトされている箇所](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/2_Function/0_Normal/ArrowFunction.js.html)を分割できないため、検証不可。

#### [ClassMethod](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/2_Function/1_Split/ClassMethod.js.html)
🤔 クラスメソッド名の先頭の2文字しかハイライトされていない。
💡 クラスメソッド名から`)` まで複数行にまたがって全てハイライトさせる。

#### [FunctionDeclaration](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/2_Function/1_Split/FunctionDeclaration.js.html)
🤔 関数名から始まる1行目しかハイライトされていない。
💡 `function` キーワードから `)` まで複数行にまたがって全てハイライトさせる。

#### [FunctionExpression](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/2_Function/1_Split/FunctionExpression.js.html)
**無名関数の場合**
🤔 `function` キーワードの先頭の2文字しかハイライトされていない。
💡 `function` キーワードから `)` まで複数行にまたがって全てハイライトさせる。

**名前付き関数の場合**
🤔 関数名から始まる1行目しかハイライトされていない。
💡 `function` キーワードから `)` まで複数行にまたがって全てハイライトさせる。


### Nested
#### [ArrowFunction](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/2_Function/2_Nested/ArrowFunction.js.html)
🤔 ステートメントの1行目しかハイライトされていない。
💡 複数行にまたがってステートメントの全体をハイライトさせる。

#### [ClassMethod](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/2_Function/2_Nested/ClassMethod.js.html)
🚫 クラスメソッドをネストできないため、検証不可。

#### [FunctionDeclaration](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/2_Function/2_Nested/FunctionDeclaration.js.html)
🤔 ステートメントの1行目しかハイライトされていない。
💡 複数行にまたがってステートメントの全体をハイライトさせる。

#### [FunctionExpression](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/2_Function/2_Nested/FunctionExpression.js.html)
🤔 ステートメントの1行目しかハイライトされていない。
💡 複数行にまたがってステートメントの全体をハイライトさせる。


### Abuse
#### [ArrowFunction](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/2_Function/3_Abuse/ArrowFunction.js.html)
🤔 💡 [Normalで言及した内容](#arrowfunction)と同様。

#### [ClassMethod](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/2_Function/3_Abuse/ClassMethod.js.html)
🤔 💡 [Normalで言及した内容](#classmethod)と同様。

#### [FunctionDeclaration](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/2_Function/3_Abuse/FunctionDeclaration.js.html)
🤔 💡 [Normalで言及した内容](#functiondeclaration)と同様。

#### [FunctionExpression](https://takuyahara.github.io/share/20190104_IstanbulJS_Coverage_Issue/00_Problem/javascript_v2/coverage/lcov-report/2_Function/3_Abuse/FunctionExpression.js.html)
🤔 💡 [Normalで言及した内容]( #functionexpression)と同様。



# まとめ
本記事では、IstanbulJSが生成するHTMLレポートにおけるハイライトの問題を検証した。続く別記事にて、ハイライト範囲の代替案と、それを実現するコードを示す。