Angular.jsのDIで注入されたサービスが参照されているかどうか調べるコードを書いた
前提
Angular.jsには、DIの仕組みがあって、あるサービスがどのサービスに依存しているか記述することができる。
(この記事とは関係ないが、DIのための注釈がAngular.jsに触れたことがない人からすると黒魔術のように見えて、敷居を高いように感じるが、その部分だけ切り取ってAngular.jsを避けてしまうのは、もったいないような気がする。サービスが依存するサービスが明確になることと、ユニットテストを書く時に依存するサービスをモックに差し替えやすいメリットは個人的に大きいと感じている。)
モチベーション
開発を進めていて、コードを整理したり、コードレビューを受けて修正したりすると、注入しているが参照していないサービスがでてくる。
前までは気づいたらその都度消していたのだけど、本当に参照していないかどうか調べるのはエネルギーを使う。機械的にできるチェックなので、チェックを自動化して、そのエネルギーをコードを書くのに使ったほうがよい。コードレビューにおいても同様。
IDEを使っていれば、おそらくそのような指摘を勝手にしてくれるかもしれないが、普段はvimでコードを書いているので、このようなチェックをするコードをかなり雑だが書いてみた(正直に白状すれば、CoffeeScriptのASTに触れてみたいという欲求があった)。
利用できる条件
普段のプロジェクトで利用することを考えているので、利用できる条件が少しある(暇があったら、他のDIの注釈にも対応したい)。
- CoffeeScriptで書いている
- CoffeeScriptのファイルが app/scripts 配下にあること
- 「インラインアノテーション」で注釈を記述している(他の注釈については、こちらを参照のこと 依存性注入(DI) | AngularJS 1.2 日本語リファレンス | js STUDIO)
など、汎用的とはいえない。 あと、一つのファイルで色々やっているのでモジュールとしてダメダメなかんじがある。 ちょっとずつ汎用的にしてnpmパッケージにしたい。
利用例
プロジェクトの直下でスクリプトを実行すると以下のような内容が表示される。
--- app/scripts/services/controller-dependency-resolver.coffee 'ControllerDependencyResolver': [ '$location': false, '$q': true, messageCenterService: false, Shop: true, Item: true, basket: true ] --- app/scripts/services/danger-dialog.coffee 'dangerDialog': [ '$window': false, ModalService: true ] ---
この場合、ControllerDependencyResolver というサービスで、$location が注入されているが参照されていないことが分かる。
実装について
やっていることは簡単で、CoffeeScriptがライブラリとして提供してくれているAPIを使って( nodes.coffee )、ASTを取得、走査しているだけ。
最初、APIの使い方がいまいちよく分からなかったので、clutchski/coffeelint · GitHub のコードを読んで、使い方のイメージをつかんだ。
この記事( JSのASTを扱うライブラリをつかって、不要なeval呼び出しを除くコードを書いてみた - きたけーの朝は早いブログ )でも書いたが、ASTという言葉を聞くとなんだか難しそうなイメージが湧いてくるが、思ったよりもシンプルに扱えるし、活用できる範囲が広い。