ApexLibrarian

Apex Stem ドキュメント
Apex StemApexLibrariannpmCLISalesforce
Apex クラスを @directory doc コメントタグの宣言どおりのディレクトリに戻す npm 製 CLI。org を経由すると剥がれるリポジトリの階層を、retrieve のあとにコマンド 1 つで復元します。

Apex クラスの司書。床に散らばった本を拾い、あるべき棚に戻します。

Salesforce の org には Apex クラスのフォルダという概念がありません。リポジトリには Usecases/opportunity/Handlers/account/ といった階層があるのに、クラスが org を経由した瞬間 (同僚が Setup 画面で作った、別リポジトリに retrieve した、パッケージをインストールして取得した) にその配置は剥がれ落ち、ファイルは classes/ 直下にフラットに着地します。

ApexLibrarian は、置き場所を クラス自身の doc コメントに宣言させる ことでこの問題を解決する npm 製 CLI です。宣言はこう書きます。

APEX
/**
 * 商談の値引き額を明細から再計算する。
 * @directory Usecases/opportunity
 */
public with sharing class ReconcileDiscount {

doc コメントはクラス本体の一部なので、@directory タグは org との往復を何度でも生き延びます。retrieve のあとにコマンドを 1 回叩けば、すべてのクラスがあるべき棚に戻ります。

Install

BASH
npm install --save-dev apex-librarian
# または直接実行
npx apex-librarian check

ファイルを動かすツールなので、チーム全員と CI で同じ挙動になるよう devDependency としてバージョンを固定するのがおすすめです。

Commands

タグが 宣言、ファイルシステムが 現実 です。各コマンドは両者のズレを一方向に解消します。

Command方向使う場面
apex-librarian check比較のみCI / pre-commit。ズレがあれば exit 1
apex-librarian arrangeタグ → 配置sf project retrieve のあと。タグの示すディレクトリへファイルを移動する (.cls-meta.xml も一緒に)
apex-librarian stamp配置 → タグ既存プロジェクトへの導入時、意図的な git mv のあと

Options

CODE
--root <dir>     対象のクラスルート (複数指定可。省略時は見つかった "classes" ディレクトリすべて)
--dry-run        ファイルに触れず、何が起きるかだけ表示する
--require-tag    check のみ: サブディレクトリにある未タグのクラスも失敗にする
--include-submodules
                 stamp/check のみ: git submodule 内のファイルも対象にする (下記「For framework authors」)

Behavior notes

  • .cls-meta.xml必ずクラスとペアで 移動します。
  • git submodule は自動で除外されます (.gitmodules のパスを見ます)。取り込んだフレームワークの配置は upstream の管轄なので、司書は submodule 内のファイルを動かしたりタグを書き込んだりしません。
  • arrange決して上書きしません。移動先が埋まっていたら報告してスキップします (exit 1)。
  • タグは トップレベルの型宣言に付いた doc ブロック にのみ結び付きます。ファイル先頭のライセンスヘッダは数えず、inner class は無視します。
  • @directory . はクラスルート直下を意味します。絶対パスと .. は拒否されます。
  • タグの無いクラスは arrange / check では放置されます (--require-tag を付ければタグ必須にできます)。stamp はサブディレクトリに既に置かれているクラスへタグを追記します。
  • できればコミット済みのワーキングツリーで実行してください。移動はすべて単純な rename なので、git status で司書がやったことがそのまま見え、git checkout . で取り消せます。

Typical flows

既存プロジェクトへの導入

現在の配置を全クラスに一度だけ書き込みます。

BASH
npx apex-librarian stamp
git add -A && git commit -m "Stamp @directory tags"

retrieve のあと

同僚が org 上で作ったクラスはフラットに落ちてきます。まとめて棚に戻します。

BASH
sf project retrieve start -o my-org ...
npx apex-librarian arrange

クラスを意図的に移動したあと

新しい置き場所をタグへ書き戻します。

BASH
git mv force-app/main/default/classes/Foo.cls force-app/main/default/classes/Services/
npx apex-librarian stamp

CI example (GitHub Actions)

YAML
- uses: actions/setup-node@v4
  with:
    node-version: 20
- run: npm ci
- run: npx apex-librarian check --require-tag

For framework authors

フレームワークを unlocked package として配布すると、利用者が retrieve したクラスはフラットに落ちます。行き先をソース自体に焼き込んでおきましょう。利用者に置いてほしい形 (classes/<YourFramework>/ 配下の submodule) でフレームワークを配置したチェックアウトから、実際の階層をそのまま刻印します。

BASH
npx apex-librarian stamp --include-submodules
npx apex-librarian check --include-submodules   # 確認

これで各クラスが @directory MyFramework/Eloquents/tests のように実際の位置を持ちます。submodule 側でタグをコミットしてリリースすれば、パッケージをインストールした利用者は npx apex-librarian arrange を叩くだけで、クラスが classes/MyFramework/... に自動で並びます。どの経路で導入しても配置は同じになり、その配置はクラス自身が宣言しています。

取り込んだフレームワークのファイルは利用者が動かしてよいものではないので、submodule のパスは既定で除外されています。--include-submodules は、その除外をフレームワーク作者側のチェックアウトでだけ解除するためのフラグです。arrange はこのフラグ自体を受け付けません (submodule のワーキングツリーからファイルを持ち出すと submodule が壊れるためです)。

Apex Stem の 4 フレームワーク (ApexEloquent v3.7.0 / ApexBlueprint v2.1.0 / ApexTrace v1.5.0 / ApexTools v1.1.0 以降) は、この方法で全クラスに刻印済みです。インストールガイド も参照してください。

  • GitHub: krile136/ApexLibrarian
  • npm: apex-librarian
  • CLI の全機能は通常の関数 (analyze, planArrange, applyMoves など) としても export されているので、ライブラリとして他のツールに組み込めます