AST クエリ

パース済みの構文木を直接扱うレシピです。ノード型の検索、そのカウント、ツリーのダンプを行います。

ライブラリ側の同等物。 以下の各レシピには、AST を直接歩く にプロセス内で動く Rust 版の対応物があります — ファイルごとのシェル起動が遅すぎる場合や、1 回のパースでメトリクスとカスタム AST 分析を組み合わせたい場合に有用です。

コミット前にパースエラーを検出する

tree-sitter はパースできなかったあらゆる箇所に合成の ERROR ノードを出します。find でそれらを表面化させます:

bca find \
    --include "*.rs" \
    --paths "$PWD" \
    -t ERROR

1 回の指定につきグロブ 1 つ。 --include--exclude は出現ごとにちょうど 1 つの値を取ります。複数のグロブにはフラグを繰り返してください(--include "*.rs" --include "*.py")。後続の位置引数パスが飲み込まれることはありません。= 形式(--include="*.rs")も使えます。

クリーンな実行は何も出力しません。これを pre-commit フックに組み込めば、構文的に壊れたファイルがステージされたときに素早く失敗させられます。

特定の構文要素を数える

count は繰り返し可能な -t/--type フラグで 1 つ以上のノード型を受け取り、合計を報告します。たとえば Rust プロジェクト全体で ifforwhile の構文を数えるには:

bca count \
    --include "*.rs" \
    --paths src/ \
    -t if_expression -t for_expression -t while_expression

正確なノード型名は下層の tree-sitter 文法に由来します。見つけるには、小さなサンプルファイルの AST をダンプし(下記参照)、ツリーからノード名を読み取ってください。

Rust クレート内のすべての unsafe ブロックを見つける

bca find \
    --include "*.rs" \
    --paths src/ \
    -t unsafe_block

各マッチはファイルパスとノードの行範囲を出力します。

ファイルの AST をダンプする

メトリクスがなぜその値になったのかを理解したり、find / count に必要な tree-sitter ノード名を発見したりするのに便利です:

bca dump --paths src/lib.rs

ダンプを特定の関数やブロックに絞るには、--line-start--line-end フラグで行範囲を追加します(dump サブコマンドの後に置く必要があります):

bca dump \
    --paths src/lib.rs \
    --line-start 42 --line-end 88

--line-start / --line-enddumpfind に適用されるため、同じ範囲指定で検索を単一の関数にスコープできます:

bca find \
    --paths src/lib.rs \
    --line-start 42 --line-end 88 -t return_expression

短縮形の --ls / --le は非推奨エイリアスとして残っていますが、次のメジャーリリースで削除される予定です。

すべての関数・メソッドを一覧する

人間が読むための簡単なインベントリには:

bca functions \
    --include "*.rs" \
    --paths src/

出力はファイルごとのツリーです。In file … ヘッダーに続き、関数ごとに名前と行スパンを持つインデントされた行が並びます。読むためのものであり、パースするためのものではありません。

構造化されたインベントリが必要なツール(カバレッジマッピング、ドキュメント生成、コードオーナーレポート)には、代わりに JSON の metrics 出力を使い、.spaces[] を再帰的に歩いて kindfunction のエントリを取り出します:

bca metrics \
    --include "*.rs" \
    --paths src/ \
    -O json \
  | jq -c '
      . as $root
      | def funcs: if .kind == "function" then [.] else [] end
                   + (.spaces // [] | map(funcs) | add // []);
      funcs[] | {file: $root.name, name, start_line, end_line}
    '

これは関数ごとに 1 つの JSON オブジェクトを出力し、下流のツールへ安全にパイプできます。