Biome コードリーディング

CLI の最初から読んでいく
biome check の entry
execute_mode がメインの処理。
exeute はさらに traverse を呼び出している。
traverse は複雑だけど、メインの処理は thread::scope で囲われている traverse_inputs の処理
thread::scope で囲われているから複数スレッドで traverse していそう。rayon で threadpool 作っていた。
rayon というライブラリを使ってた

traverse_inputs が難しい
引数の fs は dyn なので動的ディスパッチ。fs.traversal は、説明は次のとおり
This method creates a new "traversal scope" that can be used to efficiently batch many filesystem read operations
ファイルを読み込んで traverse のスコープを生成する関数ってことかな。fs の実装は、OsFileSystem と MemoryFileSystem がありそう。
scope.spawn はスコープの生成を実行してそうで、これも実際の実装は OsTraversalScope や MemoryTraversalScope にある。
ここでは rayon のスコープを生成しながら ctx.handle_file を実行している。
ctx は TraversalOptions のことで、実際の handle_file は次の処理になっている。
ここでよんでいる process_file は次のとおり。コメントにも書かれているとおり、ここが実際のファイルを読み込んだり、パースしたりしている箇所らしい。確かに、 lint
/ check
などを関数を実行していて、次はこれ読んでいくのが良さそう。ここまで来るのが長かった。

check 関数を見ていく
ここでは lint_with_guard / format_with_guard などを呼んでいる。
lint_with_guard 関数を見ていく。みると guard の pull_diagnostics とかを呼んでいそう。
guard の実体は FileGuard
FileGuard の実装は workspace の pull_diagnostics を呼んでいる。
この workspace は実装を辿っていくと、cli の main.rs で生成されている workspace だった。
ということで pull_diagnostics の本当の中身はここにある。

pull_diagnostics の中身を読む。言語に依存しない処理になっている。
get_parse では GreenNode を含む AnyParse という構造体を返していそう。
lint は LintParams を受け取って、LintResults を返す関数。
parse も lint も関数の実態は、JSだと以下のファイルに実装されている。
parse は parse_js_with_cache が根本の処理。event、trivia、error の配列を parse 関数がまずは返していそう。events を使って green node (tree) を構築している。
lint は analyze が根本の処理で、さらにたどると以下の関数に辿り着く。add_visitor してたりして、いかにもという感じのコード。

lint が実際に実行するまでの流れを次に理解する。
parse.tree() で AST を構築してそう。構築のロジックはあんまりわからず... SynatxNode をツリーの親から再帰的にキャストしてそう? token の kind の情報を使いながらキャストしている。 (多分)
Parse の構造体も関係してそう。Generics の T には AnyJsRoot が渡っている。
AST を作ったあとは、visitor の登録をしている。実際の処理は次の run 関数。
preorder でツリーを走査して、イベントに対して visitor を適用させている。
ルールは visit_registry で visitor として登録されていそう。最終的に record_rules が呼ばれていて、そこで Ast の構造体に実装されている build_visitor が呼ばれてた。
build_visitor では次のような visitor を登録する。
match_query が重要で、ここで対応する node に関する lint ルールが実行されていそう

難しかった... ふわっとした理解をしているところもそれなりにある。
カスタムルール対応はどうすればいんだろか... もう少し lint 周りを読んで、カスタムルールを WASM にコンパイルしたものを既存のルールと I/F 合わせる wrapper みたいなのかませたらいけるのだろうか