CoffeeScriptをKarma-CoverageしようとしてSyntax Errorが出るときの対処法


はじめに
=====

CoffeeScript で書かれたプログラムを Karma-Coverage でカバレッジを計測しようとしたときに、色々エラーがでて難航したのでそのメモです。
CoffeeScriptを使っていない場合は、こういう問題はおそらく起こらないですが、 **CoffeeScriptを愛する同志の方々**はお気をつけ下さい。

症状としては 「 **preprocessor.coverage で Syntax Errorが出る** 」というものなのですが、
その原因として2つほどありましたので共有します。

おさらい
====

Karma-Coverage をよく知らない方は、

[Karma+istanbulを利用して、AngularJSで構築したプロダクトのCoverage計測](http://qiita.com/matsuzan/items/e7b30b4fa4de216dde07)

を参考にされると良いです。
上記はCoffeeScriptについては触れられていないので、併せて

https://github.com/kylewelsby/karma-coverage-coffee-script-example/blob/master/karma.conf.js

の設定を見ると良いと思います。`preprocessors`の部分が少し変わっている(`coffee`というのが増えている)のがポイントです。


症状1： 変換後のJSファイルをもう一度 Coffee->JS 変換しようとしている
=====

エラーメッセージ
----
例えば、以下の様なエラーが出ます。

```
ERROR [preprocessor.coverage]: Syntax error on line 2, column 5: unexpected 'A' (\u0041)
1 : 'use strict';
2 : var AccountModel;
^ :~~~~~^
3 : 
4 : AccountModel = (function() {
5 :   var _defaultAccount, _q, _tmpAccount;
```

これは一度 Coffee → JS に変換してあるものをもう一度 変換しようとしているように見えます。
そりゃあ Syntax Errorにはなるでしょうが、最初は原因がわかりませんでした。

原因と対策
------

原因は単純で、前述の `karma.conf.js` の中の `preprocessors` で指定したファイルが、
`coffee` `coverage` の両方に含まれていると発生します。
それぞれ重複しないように指定しないといけません。
なので、最初からそれが想定されたDIR構成になっていると楽できますね。

### NG

```
    preprocessors: {
      '**/*.coffee': 'coffee',
      'app/scripts/*/**/*.coffee': 'coverage'
    },
```

### OK

```
    preprocessors: {
      'app/scripts/*.coffee': 'coffee',
      'app/scripts/*/**/*.coffee': 'coverage',
      'test/**/*.coffee': 'coffee'
    },
```

### 一応ドキュメントに書いてある

https://github.com/karma-runner/karma-coverage
のREADMEにそうかいてあります。

```
    preprocessors: {
      // source files, that you wanna generate coverage for
      // do not include tests or libraries
      // (these files will be instrumented by Istanbul via Ibrik unless
      // specified otherwise in coverageReporter.instrumenter)
      'src/*.coffee': ['coverage'],

      // note: project files will already be converted to
      // JavaScript via coverage preprocessor.
      // Thus, you'll have to limit the CoffeeScript preprocessor
      // to uncovered files.
      'test/**/*.coffee': ['coffee']
    },
```

症状2
====
エラーメッセージ
----
例えば、以下の様なエラーが出ます。

```
ERROR [preprocessor.coverage]: Syntax error on line 4, column 29: unexpected '\n' (\u000A)
1 : "use strict"
2 : app = angular.module "myApp"
3 : app.config ($stateProvider, $urlRouterProvider) ->
4 :   $stateProvider.state("tab",
^ :~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
5 :     url: "/tab"
6 :     abstract: true
7 :     templateUrl: "/templates/partial/common/tabs.html"
```

とか

```
ERROR [preprocessor.coverage]: Cannot read property 'loc' of undefined
```

などです。

原因
-----
原因はおそらく以下のスレッドのコメント以降なのだと思います。
https://github.com/karma-runner/karma-coverage/issues/75#issuecomment-43605565


端的に言うと、

[Karma-Coverage](https://github.com/karma-runner/karma-coverage) が利用している [ibrik](https://github.com/Constellation/ibrik) が [Istanbul](https://github.com/gotwarlost/istanbul)というJS Code Coverageツールを使っています。
問題はこの **ibrik**にあって、ibrikの中で [CoffeeScriptRedux compiler](https://github.com/michaelficarra/CoffeeScriptRedux)というのを使っているが、それが現状のCoffeeScriptの仕様に合致していない

ということです。
従って、特定のCoffeeの文法に対してエラーになってしまいます。

ibrik が CoffeeScriptRedux を使用しているので、それを本家CoffeeScriptを使うように変更した、 
[HBOCodeLabs/ibrik](https://github.com/HBOCodeLabs/ibrik)
というForkがあります。しかしこれの CoffeeScriptのVersionも1.6.3のままです。

対策
----

それぞれ別の個人が管理しているため、依存関係的に根が深く、誰にどうPull Requestを送るか悩ましいところです。
そこでとりあえず、

* **HBOCodeLabs/ibrik**を **Fork**して、その package.json を修正して CoffeeScript の Version を 1.7系(最新）にする
* **Karma-Coverage** を **Fork**して、そのforkした **HBOCodeLabs/ibriks** のGithubリポジトリを指すようにする

というやっつけな対策があります。


* 現状：`Karma-Coverage -> ibrik -> CoffeeScript Redux`
* 修正：`Karma-Coverage(fork) -> HBOCodeLabs/ibrik(fork) -> CoffeeScript ~1.7.1`

という感じになります。

私の場合は

* Forkした Karma-Coverage: https://github.com/mokemokechicken/karma-coverage
* Forkした ibrik: https://github.com/mokemokechicken/ibrik

として、 `package.json` の `karma-coverage` を以下のようにしました。

```json:package.json
 "karma-coverage": "git+https://github.com/mokemokechicken/karma-coverage.git#master",
```

これで何とか動くようになりました。

この程度の修正なので、いずれこの辺の依存関係が整理されて、何も考えずに動くようになるとは思います(希望…)。