自己紹介
- mizchi
- フリーランス
- リクルートでは yosuke_furukawa の元でR&Dみたいなことをしている
飛び入りLT用(発表ないかも)
yosuke_furukawa 「コードメトリクスツール作って」
コンテキスト
- リクルート社内に膨大なJS含むプロジェクトがある
- JSを(僕や yosuke_furukawa ぐらいに)真っ当に書ける人が少ない
- いろんなプロダクトを串刺しでスコアリングして可視化したい
eslint は?
- プロジェクトごとに運用のされ方が違う || そもそもない
- 「1件でも落とすと exit-status = 1」 なので攻めたルールを採用しにくい
どうせだったらOSSにしようぜ => はい
※ 画面は開発中のものです
sonarish (仮)
$ npm i -g sonarish-cli
$ cd your-repo
$ sonarish src
実行例
$ cd sonarish
$ sonarish --detail
--- complexity
score: 96.4/100
┌──────────────────────┬───────┬──────────┬───────┐
│ rule │ score │ priority │ count │
├──────────────────────┼───────┼──────────┼───────┤
│ no-shadow │ -2.6 │ 2 │ 2 │
├──────────────────────┼───────┼──────────┼───────┤
│ mutation/no-mutation │ -0.9 │ 1 │ 1 │
└──────────────────────┴───────┴──────────┴───────┘
--- best-practice
score: 92.9/100
┌───────────────────────────────────┬───────┬──────────┬───────┐
│ rule │ score │ priority │ count │
├───────────────────────────────────┼───────┼──────────┼───────┤
│ import/no-extraneous-dependencies │ -2.5 │ 3 │ 4 │
├───────────────────────────────────┼───────┼──────────┼───────┤
│ no-console │ -2 │ 1 │ 22 │
├───────────────────────────────────┼───────┼──────────┼───────┤
│ no-unused-vars │ -1.8 │ 1 │ 18 │
├───────────────────────────────────┼───────┼──────────┼───────┤
│ compat/compat │ -0.6 │ 1 │ 2 │
└───────────────────────────────────┴───────┴──────────┴───────┘
--- meta-comments
score: 63.8/100
┌───────────────────────────────────┬───────┬──────────┬───────┐
│ rule │ score │ priority │ count │
├───────────────────────────────────┼───────┼──────────┼───────┤
│ no-warning-comments │ -20.2 │ 4 │ 4 │
├───────────────────────────────────┼───────┼──────────┼───────┤
│ eslint-comments/no-use │ -7.9 │ 1 │ 10 │
├───────────────────────────────────┼───────┼──────────┼───────┤
│ eslint-comments/no-unused-disable │ -7.9 │ 1 │ 10 │
└───────────────────────────────────┴───────┴──────────┴───────┘
babel/babel
--- complexity
score: 61.1/100
┌──────────────────────┬───────┬──────────┬───────┐
│ rule │ score │ priority │ count │
├──────────────────────┼───────┼──────────┼───────┤
│ no-param-reassign │ -15.7 │ 3 │ 106 │
├──────────────────────┼───────┼──────────┼───────┤
│ no-shadow │ -9.2 │ 2 │ 78 │
├──────────────────────┼───────┼──────────┼───────┤
│ max-lines │ -5.5 │ 2 │ 28 │
├──────────────────────┼───────┼──────────┼───────┤
│ mutation/no-mutation │ -5.2 │ 1 │ 601 │
├──────────────────────┼───────┼──────────┼───────┤
│ no-unreachable │ -2.9 │ 4 │ 2 │
└──────────────────────┴───────┴──────────┴───────┘
--- best-practice
score: 86.4/100
┌───────────────────────────────────┬───────┬──────────┬───────┐
│ rule │ score │ priority │ count │
├───────────────────────────────────┼───────┼──────────┼───────┤
│ prefer-arrow-callback │ -4.8 │ 2 │ 503 │
├───────────────────────────────────┼───────┼──────────┼───────┤
│ import/no-extraneous-dependencies │ -3.6 │ 3 │ 25 │
├───────────────────────────────────┼───────┼──────────┼───────┤
│ promise/always-return │ -2 │ 2 │ 17 │
├───────────────────────────────────┼───────┼──────────┼───────┤
│ no-console │ -1.2 │ 1 │ 25 │
├───────────────────────────────────┼───────┼──────────┼───────┤
│ eqeqeq │ -0.8 │ 1 │ 13 │
├───────────────────────────────────┼───────┼──────────┼───────┤
│ import/no-mutable-exports │ -0.6 │ 2 │ 2 │
├───────────────────────────────────┼───────┼──────────┼───────┤
│ no-unused-vars │ -0.2 │ 1 │ 1 │
└───────────────────────────────────┴───────┴──────────┴───────┘
--- meta-comments
score: 34.1/100
┌───────────────────────────────────┬───────┬──────────┬───────┐
│ rule │ score │ priority │ count │
├───────────────────────────────────┼───────┼──────────┼───────┤
│ no-warning-comments │ -49.4 │ 4 │ 75 │
├───────────────────────────────────┼───────┼──────────┼───────┤
│ eslint-comments/no-use │ -9.2 │ 1 │ 42 │
├───────────────────────────────────┼───────┼──────────┼───────┤
│ eslint-comments/no-unused-disable │ -7.1 │ 1 │ 25 │
└───────────────────────────────────┴───────┴──────────┴───────┘
オプション
$ sonarish [--root <root-path>] [--detail] 'src/**' 'subdir/**'
sonarish の 設計
- 空白のスタイリングなどには関与しない(prettierでやれ)
- ルールが落ちることを前提に、エラーカウント/合計ファイル数 で減点
- 複数のカテゴリごとにeslintのルールセットを作る
- カテゴリ内の priority を設定
「攻めたルール」の例
- object-rest-spread あれば代入なんていらねーよな!
- クラス以外で this なんてつかわねーよな!
- 二重 if / switch はダサいよな!
- 複雑な論理オペレータのネストはダサいよな!
- TODOコメントなんて残んねーよな!
ダサいを可視化する
- いわゆる codesmell の検出
- 自分でそのためのeslintルールを書いてる(既存のものにそういうルール集はあんまりない)
スコアリングルール
そのルールの (エラー数/総ファイル数) * (priority/合計priority)
(実際は細かい正規化とスレッショルドがいっぱいあって調整中)
TODO
- 自分でスコアルールを書けるようにする
- ソースの公開
- eslint 以外のツール対応
- package.json の health check
- コピペ検出
- etc...
わかったこと
- no-unused-vars は結構効く
- TODO コメントはめっちゃ残ってる
- eslintをまともに運用してるように見えてもeslint-disableを数えると結構やばい