dx-code-analyzer-custom-rule-create について
Regex、PMD/XPath、ESLint で Salesforce Code Analyzer のカスタムルールを作成するスキルです。エンジン選択を案内し、AST の確認、スクリプトによる作成、検証、正例・負例のテストを求めます。
主な機能
- 01パターンに応じたエンジン選択
- 02Regex、PMD/XPath、ESLint ルールの作成
- 03ast-dump による Apex 構造の確認
- 04ルール検証と正例・負例のテスト
- 05エンジン別のテストファイル除外
活用シーン
- 01チーム固有のコーディング規約の適用
- 02禁止するコードやメタデータの検出
- 03Apex、XML、JavaScript 向けルールの作成
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ forcedotcom/ sf-skills --skill dx-code-analyzer-custom-rule-createインストール後、Claude Code で/dx-code-analyzer-custom-rule-createを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
assets/pmd-ruleset-template.xmlexamples/metadata-xml-example-fields-api.mdmetadata-xml-example-flows.mdmetadata-xml-example-permissions.mdmetadata-xml-examples.mdregex-examples.mdxpath-examples.mdreferences/advanced-pmd-patterns.mdapex-ast-reference.mdeslint-custom-plugins.mdeslint-rules-discovery.mdeslint-tier2-configurable.mdeslint-tier3-custom-plugins.mdmetadata-xml-rules.mdregex-rule-schema.mdtroubleshooting.mdxpath-patterns-governor-limits.mdxpath-patterns-method-calls.mdxpath-patterns-security.mdxpath-patterns-structure.mdxpath-patterns.mdscripts/create-pmd-rule.jscreate-regex-rule.js詳細
dx-code-analyzer-custom-rule-create:カスタムコードアナライザールールの作成
エコシステム: このスキルは、3 つのスキルで構成されるコードアナライザースイートの一部です。
dx-code-analyzer-run(スキャンと結果)・dx-code-analyzer-configure(セットアップ、設定、CI/CD)・dx-code-analyzer-custom-rule-create(カスタムルールの作成)。
コードアナライザーの組み込みルールではカバーされないパターンを適用するカスタムルールの作成が必要な場合に、このスキルを使用します。Regex エンジン(テキストパターンマッチング)と PMD エンジン(AST に対する構造的な XPath クエリ)をサポートします。
このスキルが担当するタスク
次の作業には dx-code-analyzer-custom-rule-create を使用します。
- コードアナライザーの新しいカスタムルールを作成する(エンジンは問いません)
- 静的解析によって、チーム固有のコーディング規約を適用する
- 特定のパターン(System.debug、ハードコードされた ID、TODO など)を禁止する
- PMD ルール用の XPath 式を作成する(Apex またはメタデータ XML)
- Regex エンジン用の正規表現パターンを作成する
- LWC/JavaScript 用のカスタム ESLint ルール/プラグインを設定する
- メタデータガバナンスを適用する(API バージョン、項目の説明、危険な権限など)
- 組み込みルールのしきい値を上書きする(CyclomaticComplexity、ExcessiveParameterList など)
- 複数のルールを共有ルールセットにまとめる
- 正しくマッチしないカスタムルールを調整する
次の場合は、別のスキルに委ねてください。
- 既存のルールを使ってスキャンを実行する →
dx-code-analyzer-runスキル - エンジン、前提条件、CI/CD を設定する →
dx-code-analyzer-configureスキル - 既存の組み込みルールの意味を説明する →
dx-code-analyzer-runスキル - Apex コードまたはテストを作成する →
generating-apex/running-apex-testsスキル
最初に確認する必要があるコンテキスト
以下について尋ねるか、推測してください。
- 検出するパターン — どのコードを指摘すべきですか?(ユーザーが IDE でコードを選択している場合、その選択範囲が回答です。聞き直さないでください。)
- 許可するもの — 例外はありますか?(テストクラス、特定のコンテキストなど)
- ファイルの対象範囲 — どのファイル形式ですか?(.cls、.trigger、.js、すべてなど)
- 重大度 — どの程度重要ですか?(デフォルト:3/中程度)
ユーザーがコードを選択している場合(IDE の選択コンテキストがある場合)、その選択範囲をパターンの定義として扱います。選択範囲のどの要素を対象にするかが本当に曖昧な場合を除き、確認は不要です。
選択範囲がなく、依頼が曖昧な場合(「ベストプラクティスのルールを追加して」など)は、確認の質問を 1 つだけします。
「このルールで具体的にどのようなパターンを指摘しますか?」
厳守事項
これらは譲れないルールです。出力がたまたま動作したとしても、いずれかに違反するとスキル失敗となります。
-
XPath を記述する前に、必ず
ast-dumpを実行してください。 例外はありません。ノード名を記憶や参考資料、過去の会話から使わないでください。AST が信頼できる唯一の情報源です。sf code-analyzer ast-dumpを実行して出力を読み、その内容に合致する XPath を記述してください。「SOQL-in-loop」のようなよく知られたパターンでも、まず ast-dump を実行してください。この手順を省略してルールが動作したとしても、プロセス上の失敗です。 -
ルールの作成には必ずスクリプトを使用してください。 正規表現ルールには必ず
create-regex-rule.jsを使用してください。PMD ルールには必ずcreate-pmd-rule.jsを使用してください。ルール定義を追加するためにcode-analyzer.ymlを手動で編集してはいけません。YAML 内の正規表現パターンはエスケープに失敗する原因になります(引用符の中の引用符、バックスラッシュの消失など)。スクリプトなら毎回、正しく YAML にシリアライズできます。 -
スクリプトが
code-analyzer.ymlに書き込んだ後は、値を修正する場合でも、絶対に手動編集しないでください。 スクリプトは正しくエスケープされた YAML を生成します。その後、ファイルを書き換えたり構成し直したりすると、エスケープが壊れます。ユーザーがトップレベルの設定(ignores.filesなど)を追加している場合も、そのままにしてください。自分が書き込んだ部分だけを変更してください。スクリプトの出力がおかしい場合(ルールの検証に失敗する、YAML の解析エラー、正規表現に余計な文字が含まれるなど):
- YAML を手作業で修正してはいけません。それこそ、この制約が防ごうとしている失敗です。
- 必ず、壊れたルールの YAML ブロック全体を削除してから、引数を修正してスクリプトを再実行してください。自分が書き込んだブロックを削除することは、このルールに違反しません。ブロック内のフィールドを書き換えることは違反です。
- スクリプトが誤った入力を受け付けて誤った出力を生成した場合、問題は入力にあります(例:
--regex "/.../ g"のように余分なスペースがある。フラグは空白を入れず、正確に/gとしてください)。引数を修正して再実行してください。 - スクリプトに本当にバグがあると思われる場合は、作業を中止してユーザーに伝えてください。回避策として手動編集してはいけません。
-
--regexは、空白を入れずに/pattern/flagsの形式で指定してください。 スクリプトはフラグを厳密にトリミングして検証し、使用できるのはg、i、m、s、u、yのみです。/pat/ g(空白あり)は拒否されます。/pat/x(無効なフラグ)も/pat/(フラグなし)も拒否されます。グローバルフラグgは必須です。検証に失敗した場合は引数を修正してください。YAML を直接書いて回避してはいけません。 -
作成後は必ず検証してください。 テストの前に
sf code-analyzer rules --rule-selector <engine>:<name>を実行してください。Found 0 rulesと表示された場合、YAML の解析に失敗しています。ブロックを削除し、引数を修正してスクリプトを再実行してください。 -
必ずサンプルファイルでテストしてください。 少なくとも 1 つの真陽性と 1 つの真陰性を確認してください。
正規表現ルールでは、陰性サンプルにパターンのテキストがどこにも含まれないようにしてください。コメントや文字列リテラル内も対象です。正規表現エンジンは生テキストを検索するため、
// no System.debug hereも/System\.debug/gに一致します。実行前に、陰性ファイルに対してパターンを適用した場合の結果を頭の中でたどって確認してください。 -
ルールは 1 つずつ、順番に作成してください。 ユーザーが複数のルールを要求した場合は、次のルールに進む前に、各ルールについて作成から検証、陽性テスト、陰性テストまでの一連の作業を個別に完了してください。ルールをまとめて作成してはいけません。1 つでも失敗すると、それ以降のすべてのルールの設定が壊れる可能性があります。各ルールの作業を最後まで完了し、動作を確認してから次に進んでください。
-
正規表現ルールでテストクラスを除外する場合は、
ignores.filesを使用してください。regex_ignoreでは除外できません。regex_ignoreは行単位のフィルターです(行がルールと除外パターンの両方に一致する必要があります)。そのため、テストクラス全体を除外することはできません。ユーザーの意図が「テストクラスをスキップする」ことであれば、すべてのルールの作成後に、"**/*Test.cls"のような glob を指定したトップレベルのignores.filesブロックを追加してください。スクリプトの実行の合間に設定を編集してはいけません。
エンジンの選択
| パターンの種類 | エンジン | 理由 |
|---|---|---|
| テキスト/文字列パターン(TODO、ハードコードされた ID、キーワード) | Regex | シンプルで高速であり、Java が不要です |
| Apex コード構造(メソッド呼び出し、ネスト、ループ内の SOQL) | PMD/XPath(language=apex) | AST を理解し、コメントや文字列に惑わされません |
| メタデータ XML のガバナンス(API バージョン、権限、説明) | PMD/XPath(language=xml) | 名前空間を処理しながら、XML の構造に基づいてマッチングします |
| LWC/JavaScript/TypeScript のパターン | ESLint* | 標準的な JS ツールとプラグインのエコシステムを利用できます |
| どちらでも対応できる場合(Apex/メタデータのみ) | まず Regex | 作成と保守がより簡単です |
* ESLint の場合: カスタムプラグインを作成する前に、必ず Tier 1(組み込みルール)と Tier 2(設定可能なルール)を確認してください。references/eslint-rules-discovery.md を参照してください。
「どちらでも対応できる場合はまず Regex」は、JavaScript/LWC/TypeScript ファイルには絶対に適用されません。 JS/LWC/TS のパターンでは、必ず ESLint を使用してください。Regex では JS のコードとコメント/文字列を区別できず、誤検出が発生します。「シンプルだから」または「npm 依存関係が不要だから」という理由で、JS ファイルに Regex を使うのは正当化できません。
選択したエンジンとその理由をユーザーに伝えてください。ユーザーが異議を唱えた場合は、その希望を尊重してください。
テストクラスの除外 — エンジン別の方法
ルールをテストクラスに適用しない場合、方法はエンジンによって異なります。
| エンジン | テストクラスの除外方法 | 備考 |
|---|---|---|
| PMD(Apex) | XPath に [not(ancestor::UserClass[ModifierNode[@Test = true()]])] を追加します | 構造に基づいて除外できます。設定変更は不要で、確実に機能します |
| Regex | code-analyzer.yml で ignores.files を使用し、**/*Test.cls のような glob を指定します | regex_ignore はファイル単位ではなく行単位です。テストクラス全体を除外することはできません。// NOPMD のような行単位のパターンにのみ使用してください |
| ESLint | eslint.config.js で ignores 配列を使用します | ESLint 標準のファイル単位の除外方法です |
regex_ignore はファイル単位の除外ではありません。 除外パターンにもマッチする行のマッチだけをスキップします。例:regex_ignore: "/@isTest/i" は、@isTest を含む行での違反だけを抑制します。テストクラスの 50 行目にある SOQL クエリは、50 行目に @isTest が含まれていないため、引き続き検出されます。Regex ルールからテストファイル全体を除外するには、次を使用してください。
ignores:
files:
- "**/*Test.cls"
- "**/*_Test.cls"
ignores.files はグローバル設定です。すべてのエンジンとすべてのルールに影響します。一部のルールではテストクラスを除外し、他のルールでは除外しない場合(例:SOQL ルールではテストを除外するが、@AuraEnabled のスキャンはテストでも行う場合)は、選択的な除外が必要なルールに XPath を使った PMD を使用してください。PMD の XPath では、メソッド単位またはクラス単位で @Test = true() を構造的に確認できますが、Regex ではできません。
テストクラスをスキップする Apex ルールの判断ガイド:
- パターンが構造的な場合(メソッド呼び出し、アノテーション、ネスト)→ PMD を使用します。XPath はテストクラスの除外をネイティブに処理できます。
- パターンが純粋にテキストベースで、すべての Regex ルールでテストをスキップする場合 → Regex と
ignores.filesを使用します。 - ルールが混在する場合(テストをスキップするルールと、しないルールがある場合)→ テストの扱いに応じて除外するルールには PMD を、その他のルールには Regex を使用します。
ワークフロー
ユーザーがコードを選択したとき(IDE での選択)
ユーザーがエディターでコードブロックをハイライトし、「これを捕まえて」「このパターンにフラグを付けて」「これ用のルールを作って」などと依頼した場合:
- 選択範囲が正例です。「このルールでどんなパターンにフラグを付けますか?」と尋ねないでください。ユーザーはすでに例を示しています。サンプルを一から書かないでください。
- 選択範囲のうち、構造的な要素と付随的な要素を見極めます。
- 構造的(ルールにする価値がある要素):メソッド呼び出し、ループのパターン、欠けているキーワード、ネスト
- 付随的(無視する要素):具体的な変数名、文字列の値、パラメーター数
- 曖昧な場合は、質問を1つだけします:「ルールではすべての
System.debug呼び出しを検出しますか。それとも、LoggingLevel パラメーターがないものだけを検出しますか?」
- ユーザーが開いている実際のファイルを AST ダンプします(新しいサンプルファイルではありません)。
sf code-analyzer ast-dump --file <the-open-file.cls> --output-file <ast.xml> - AST 出力から選択範囲を見つけます。ハイライトされた行に対応するノードを特定してください。これらが対象ノードです。
- XPath を一般化します。特定のコードではなく、構造的なパターンに一致する XPath を記述します。具体的な変数名はワイルドカードに置き換え、構造ノードと識別に使う属性は残します。
- 標準ワークフロー(負例の作成、ルール作成、検証、正例と負例のテスト)を続行します。
フローの例:
- ユーザーが選択:
Database.query('SELECT Id FROM ' + objectName) - 構造的なパターン:
Database.query呼び出し(動的 SOQL) - 付随的な要素:内部の具体的な文字列連結
- エンジン:PMD(構造的な呼び出しの検出)
- XPath:
//MethodCallExpression[@FullMethodName='Database.query'] - 不適切な例:正規表現で
Database.queryに一致させる方法(複数行のコードを検出できず、コメントにも一致するため)
フローの例(ブロック選択):
- ユーザーが SOQL を含む 5 行のブロックを for-each ループ内で選択
- 構造的な要素:ループ本体の子孫としての SOQL クエリ
- 付随的な要素:具体的なクエリフィールド、変数名
- エンジン:PMD
- 開いているファイルを AST ダンプし、ループ本体内の ForEachStatement と SoqlExpression を見つける
- XPath:
//ForEachStatement/BlockStatement//SoqlExpression
正規表現ルールの場合
- 正例を作成します(違反を示す 5~10 行)。Code Analyzer が対象にできるよう、プロジェクトのワークスペース内(たとえば、プロジェクトルートに一時的な
samples/ディレクトリを作成)にサンプルファイルを作成します。 - 別の負例ファイルを作成します。似ているものの、フラグが付いてはいけないコードを記述します。ルールを作成する前に、このファイルに対して正規表現がどう一致するか、頭の中でテストします。
- ルールをビルドして作成します。完全なスキーマについては
references/regex-rule-schema.mdを読み、その後スクリプトを実行します。
必ずスクリプトを使用してください。node "<skill_dir>/scripts/create-regex-rule.js" \ --name "<RuleName>" --regex "<pattern>" --description "<desc>" \ --severity <1-5> --file-extensions ".cls,.trigger"code-analyzer.ymlに正規表現パターンを手動で記述しないでください。YAML 内の正規表現文字(引用符、バックスラッシュ、中括弧)は解析エラーの原因になります。スクリプトを使えば正しくシリアライズされます。 - 検証します。
sf code-analyzer rules --rule-selector regex:<RuleName> - 正例をテストします。
sf code-analyzer run --rule-selector regex:<RuleName> --target <violation-sample>を実行し、違反が検出されることを確認します。 - 負例をテストします。
sf code-analyzer run --rule-selector regex:<RuleName> --target <clean-sample>を実行し、違反が0件検出されることを確認します。クリーンなコードにフラグが付く場合は、正規表現の範囲が広すぎます。戻ってパターンを絞り込んでください。 - テストに失敗した場合は反復します(正規表現を調整し、
regex_ignoreを追加し、拡張子を限定します)。 - クリーンアップします。作成したサンプルファイルをすべて削除してください。ユーザーのプロジェクトに一時的なテスト用ファイルを残さないでください。
PMD/XPath ルール(Apex)の場合
- 最小限のサンプルを書く(5~10 行)。違反を示すサンプルファイルは、Code Analyzer が対象にできるようにプロジェクトのワークスペース内(例:プロジェクトルートに一時的な
samples/ディレクトリを作成)に配置します。肯定テストと否定テストの両方に合格したら、作成したサンプルファイルをすべて削除してください。元のサンプルとテスト中に作成したコピーの両方が対象です。ユーザーのプロジェクトに一時的なテスト用フィクスチャを残さないでください。ループベースのルールでは、肯定サンプルに Apex の 3 種類のループ(for-each、従来のfor、while)をすべて含める必要があります。いずれかのループタイプを省略すると、その XPath が検証されず、違反を見落とす可能性があります。 - 必須:AST をダンプする —
sf code-analyzer ast-dump --file <sample.cls> --output-file <ast.xml>— この手順は任意ではありません。ノード名を「すでに知っている」としても、省略しないでください。実行して出力を読み、正確なノード名と属性を確認してください。 - AST 出力を読む —
references/apex-ast-reference.mdとreferences/xpath-patterns.mdは補足情報としてのみ使用し、実際の ast-dump 出力から対象ノードとその属性を特定してください。記憶に頼らないでください。 - XPath を書く — 識別に使える属性を持つ、最小で安定したノードを対象にします。XPath 内の各ノード名は、直前に読んだ ast-dump 出力にそのまま記載されている必要があります。
/Child(直接の子)と//Descendant(子孫)を意図的に使い分けてください。ast-dump を確認し、ノードが兄弟なのかネストされているのかを把握してください。 - ルールを作成する前に、別個の否定サンプルファイルを書く(5~10 行)。正しく、検出されてはならないコードを示します。このファイルは肯定サンプルとは別ファイルにする必要があります。肯定ケースと否定ケースを 1 つのファイルにまとめないでください。ループベースのルールでは、
for (x : [SELECT...])のイディオムを含めてください。この否定サンプルファイルについてもsf code-analyzer ast-dumpを実行します。出力を読み、XPath が適用される箇所を追跡し、否定 AST 内のどのノードにも一致しないことを確認してください。一致する場合は手順 4 に戻り、先に XPath を絞り込んでください。この手順を省略したり、ルール作成後に先送りしたりしないでください。否定ファイルは手順 9 で違反数が 0 であることを明示的に確認する際にも使用します。 - ルールを作成する — スクリプトを実行します:
node "<skill_dir>/scripts/create-pmd-rule.js" \ --name "<RuleName>" --xpath "<expression>" --message "<msg>" \ --language apex --priority <1-5> - 検証する —
sf code-analyzer rules --rule-selector pmd:<RuleName> - 肯定テストを実行する —
sf code-analyzer run --rule-selector pmd:<RuleName> --target <violation-sample.cls>— 違反が検出される必要があります。 - 否定テストを実行する —
sf code-analyzer run --rule-selector pmd:<RuleName> --target <clean-sample.cls>— 違反数が 0 である必要があります。正しいコードが検出された場合、XPath の範囲が広すぎます。手順 4 に戻ってください。 - テストに失敗した場合は反復する(AST を再確認し、XPath を調整し、ノード名を確認します)。
- クリーンアップ — 作成したサンプルファイルをすべて削除します(肯定サンプルと否定サンプル、および ast-dump の出力ファイルを含みます)。ユーザーのプロジェクトに一時的なテスト用フィクスチャを残さないでください。
PMD/XPath ルールの場合(メタデータ XML)
- メタデータファイルの種類を特定します(field、permissionset、profile、flow など)
- XML AST をダンプします —
sf code-analyzer ast-dump --file <file>-meta.xml --language xml --output-file <ast.xml>。ast-dump がエラー(例:"XmlEncoding is not a valid XML name")で失敗した場合は、生の XML ファイルを直接読み取ります。XML メタデータファイルでは、XML DOM 構造が AST そのものです(ファイル内で確認できる内容が PMD に表示されます)。ファイルを読み取り、要素名、階層、テキスト内容を確認します。 - DOM 構造を読み取ります — ast-dump の出力または生のファイルから、要素名、階層、テキスト内容を確認します。
references/metadata-xml-rules.mdは補足情報としてのみ使用してください。 - PMD 7 用の XPath を記述します — XML メタデータ XPath に関する重要なルール:
- すべての要素の照合には
local-name()='ElementName'を使用する必要があります(名前空間があるため、要素名だけの指定はできません) - テキスト内容の照合には
@Text属性を使用する必要があります(text()は使用しないでください — PMD 7 の XML 言語ではtext()関数は機能しません)。例://*[@Text='ModifyAllData'] ../..を使用して、テキストノードから親要素へ移動します(テキストノード → 要素 → 親要素)- 親要素に対する
.//*[@Text='value']で兄弟要素の条件を確認します - PMD 7 の XPath パターンの全容については、
references/metadata-xml-rules.mdを参照してください
- すべての要素の照合には
- ファイル拡張子を設定します — PMD の XML 言語がデフォルトで処理するのは
.xmlのみです。Salesforce メタデータファイルは複合拡張子(.permissionset-meta.xml、.field-meta.xmlなど)を使用しますが、path.extname()はこれらから.xmlを返すため、.xmlで十分です:engines: pmd: file_extensions: xml: [".xml"].permissionset-meta.xmlのような複合拡張子は追加しないでください — Code Analyzer のバリデーターで拒否されます(/^[.][a-zA-Z0-9]+$/パターン)。.xmlだけで、すべての Salesforce メタデータファイルが自動的に対象になります。 - 別個のネガティブサンプルファイルを作成します — Apex ルールと同様に、正しく、フラグが付いてはならないメタデータファイルを作成します。ルールを作成する前に、XPath がこのファイルに一致しないことを確認してください。ポジティブサンプルとネガティブサンプルはどちらも、PMD が直接スキャンできるよう、ワークスペース内に
.xml拡張子のファイルとして作成します。 - ルールを作成します — スクリプトを実行します:
node "<skill_dir>/scripts/create-pmd-rule.js" \ --name "<RuleName>" --xpath "<expression>" --message "<msg>" \ --language xml --priority <1-5> - 検証します —
sf code-analyzer rules --rule-selector pmd:<RuleName> - ポジティブテストを実行します —
sf code-analyzer run --rule-selector pmd:<RuleName> --target <violation-sample>.xml— 違反が検出される必要があります - ネガティブテストを実行します —
sf code-analyzer run --rule-selector pmd:<RuleName> --target <clean-sample>.xml— 違反が 0 件である必要があります - テストが失敗した場合は繰り返し調整します(
@Textとtext()の違いを確認し、local-name()の使用を検証し、ファイル拡張子の設定を確認します) - クリーンアップします — 作成したサンプルファイルをすべて削除します(ポジティブサンプルとネガティブサンプル、およびテスト用に作成した
.xmlのコピーを含みます)。ユーザーのプロジェクトに一時的なテスト用ファイルを残さないでください。
ESLint ルールの場合(LWC/JavaScript/TypeScript)
ESLint の検出ワークフロー(最初にお読みください)
ESLint には、200 を超える組み込みルールと、プラグインから提供される何千ものルールがあります。組み込みルールが存在するかどうかを確認する前に、カスタムプラグインを作成しようとしないでください。検出ワークフローは次のとおりです。
-
Tier 1(組み込みルール) — リクエストの 70%
- 実行します:
sf code-analyzer rules --rule-selector eslint - キーワード(例:「console」、「unused」、「equal」)で検索します
- LWC プラグインのルール(
@lwc/lwc/*)を確認します - 見つかった場合:設定して終了します
- 実行します:
-
Tier 2(設定可能なルール) — リクエストの 20%
- パターンが「関数 X を禁止する」? →
no-restricted-globals - パターンが「構文 Y を禁止する」? →
no-restricted-syntax - パターンが「プロパティ Z を禁止する」? →
no-restricted-properties - 該当する場合:設定して終了します
- パターンが「関数 X を禁止する」? →
-
Tier 3(カスタムプラグイン) — リクエストの 10%
- ドメイン固有の複数ノードパターンに限ります
- Node.js コード、テスト、meta.docs メタデータが必要です
- 参照先:
references/eslint-custom-plugins.md
参照: 具体例を含む検出ガイドの全容については、references/eslint-rules-discovery.md を参照してください。
-
必須:まず ESLint の検出ワークフローを実行してください。 ESLint に関する依頼の 90% は、組み込みルール(Tier 1)または
no-restricted-syntaxのような設定可能なルール(Tier 2)で解決できます。カスタムプラグインの作成(Tier 3)は最終手段です。先に進む前に、次の手順を実行してください。a) 実行:
sf code-analyzer rules --rule-selector eslintb) 検索: 出力からユーザーの依頼に含まれるキーワード(例:「console」、「equal」、「unused」)を検索します c) LWC プラグインのルールを確認: 出力内で@lwc/lwc/を grep します d) 見つかった場合: 設定して(references/eslint-rules-discovery.mdを参照)、そこで終了します。カスタムプラグインは作成しないでください。 e) 見つからない場合:no-restricted-globals、no-restricted-syntax、no-restricted-propertiesでパターンを表現できるか確認します(Tier 2)。 f) Tier 1 または Tier 2 の解決策がない場合に限り: カスタムプラグインの作成に進みます。検証: 設定後、
sf code-analyzer rules --rule-selector eslint:<ruleName>を実行して、ルールが表示されることを確認します。表示されない場合は、設定が誤っています。
組み込み ESLint ルールと設定可能な ESLint ルールの違い: Code Analyzer は、ベース設定に ESLint ルールの一部を含めています。no-restricted-globals、no-restricted-syntax、no-restricted-properties のようなルールは ESLint のコアルールですが、eslint.config.js で有効にするまでは有効になりません。設定後にのみ、sf code-analyzer rules の出力に表示されます。ルールが実際に読み込まれたことを確認するため、必ず検証(手順 4)してください。ESLint のコアルールだから存在するはずだと決めつけないでください。
- ESLint プラグインをインストールします(組み込み/コア ESLint ルールを使用する場合は省略します) —
npm install --save-dev eslint-plugin-<name> eslint.config.jsを作成/更新します — プラグインとルールの設定を追加します(または組み込みルールを"error"の重大度で有効にするだけでも構いません)。code-analyzer.ymlのengines.eslint.eslint_config_fileを設定する前に、必ずこのファイルを作成してください。Code Analyzer はパスを検証し、ファイルがない場合は失敗します。- Code Analyzer を設定します —
code-analyzer.ymlでengines.eslint.eslint_config_fileを設定します。ファイルの作成後に行ってください。 - 検証 —
sf code-analyzer rules --rule-selector eslint:<ruleName>。ルールが表示されない場合は、設定が誤っています。テストに進まず、次の点を確認してください:(a)eslint.config.jsファイルは正しい場所にありますか?(b)プラグインにmeta.docs.descriptionとmeta.docs.urlがありますか?(c)ルールは非推奨になっていますか?Code Analyzer は非推奨ルールを通知なく除外します。 - 違反を示すテスト用サンプルファイルをワークスペースに作成します(例:
lwc/testSample/testSample.js) - 陽性テスト —
sf code-analyzer run --rule-selector eslint:<ruleName> --target <test-sample>を実行します。違反が検出される必要があります。 - 陰性テスト — 既存の問題のない LWC ファイルに対して実行します。違反は 0 件である必要があります。
- クリーンアップ — すべてのサンプルファイルと、その親ディレクトリを削除します(LWC ではコンポーネントごとにフォルダーが必要です)。
rm <file>だけでなく、rm -rf <directory>を使用してください。空のディレクトリや一時的なテスト用ファイルをユーザーのプロジェクトに残さないでください。 - 完全なガイドについては
references/eslint-custom-plugins.mdを参照してください。
カスタムプラグインを使わない一般的な ESLint パターン
no-restricted-globals、no-restricted-syntax、no-restricted-properties の設定例については、<skill_dir>/references/eslint-custom-plugins.md の「Banning APIs Without a Custom Plugin」セクションを参照してください。
ESLint のルール検出例
例 1:組み込みルール(Tier 1)
- ユーザー:「LWC で console.log を禁止する」
- 検出:
sf code-analyzer rules --rule-selector eslint | grep console→no-consoleが見つかります - 対応:eslint.config.js で
no-consoleを有効にします - 結果:2 分で完了(カスタムプラグインは不要)
例 2:設定可能なルール(Tier 2)
- ユーザー:「LWC で setTimeout を禁止する」
- 検出:組み込みの
no-setTimeoutルールはありません - 対応:カスタムメッセージを指定して
no-restricted-globalsを使用します - 結果:5 分で完了(カスタムプラグインは不要)
例 3:LWC プラグインのルール(Tier 1)
- ユーザー:「XSS 対策として innerHTML を禁止する」
- 検出:
@lwc/lwc/no-inner-htmlがすでにあります - 対応:設定で
@lwc/lwc/no-inner-htmlを有効にします - 結果:2 分で完了(カスタムプラグインは不要)
例 4:カスタムプラグインが妥当な場合(Tier 3)
- ユーザー:「エラーハンドリングのない命令型 Apex 呼び出しを検出する」
- 検出:このパターンに対応する組み込みルールはありません
- 分析:
importと.then()を確認し、.catch()がないことを判定する必要があります。これは複数ノードの走査を伴います - 対応:ビジターパターンを使用してカスタムプラグインを作成します
- 結果:カスタムプラグインを作成するのが妥当です(20 分以上かかります)
検出ワークフローの全容については、references/eslint-rules-discovery.md を参照してください。
組み込みルールのしきい値の上書き
新しいルールを作成せずに、既存のルールの重大度やプロパティをカスタマイズするには:
- カスタムルールセットを作成し、上書き設定を使って組み込みルールを参照します
- 設定に追加します —
code-analyzer.ymlのengines.pmd.custom_rulesets - 上書きの構文と一般的な例については、
references/advanced-pmd-patterns.mdを参照してください
複数ルールのリクエスト
ユーザーが一度に複数のルール(例:「AppExchange レビュー用に 5 つのルールを作成して」)を依頼した場合は、次の手順に従います。
ステップ 1:最初にエンジンの割り当てを計画する
ルールを作成する前に、依頼されたルールをすべて列挙し、それぞれに使用するエンジンを割り当てます。この計画をユーザーに提示してください。
Rule plan:
1. RequireUserMode → PMD/XPath (needs test-class exclusion via AST)
2. NoHardcodedIds → Regex (text pattern, no structural context needed)
3. AuraEnabledCacheable → PMD/XPath (needs annotation + DML structural check)
4. CustomFieldDescription → PMD/XML (metadata governance)
5. NoSetTimeout → ESLint (JavaScript pattern)
エンジンの割り当てを決める際の主な要素:
- テストクラスを選択的に除外する必要がありますか? → PMD(XPath で
@Test = true()を確認できます) - 構造的なコンテキストを必要としない純粋なテキストパターンですか? → Regex
- コード構造(アノテーション、ネスト、DML)を理解する必要がありますか? → PMD
- JavaScript/LWC ですか? → ESLint(Regex は使用しないでください)
- メタデータ XML ですか? →
language="xml"を指定した PMD
ステップ 2:ルールは 1 つずつ順番に作成する
次のルールに着手する前に、各ルールのワークフロー(作成 → 検証 → 正例でテスト → 負例でテスト → 動作を確認)を完了させます。ルールをまとめて作成しないでください。1 つでも失敗すると、それ以降のすべてのルールの設定が破損するためです。
作成順序:
- Regex ルール(最速で、依存関係が最も少ない)
- PMD Apex ルール(ルールごとに ast-dump が必要)
- PMD XML ルール(単一のルールセットファイルを共有できる場合があります)
- ESLint ルール(npm/設定の準備が必要なため、最後に作成)
ステップ 3:複数の PMD ルールで 1 つのルールセットファイルを共有できる
複数の PMD ルールを作成する場合は、最初のルールに create-pmd-rule.js スクリプトを使用します(ルールセット XML ファイルが作成されます)。同じルールセットファイルに追加する 2 つ目以降の PMD ルールは、既存の XML ファイルに手動で追加してもかまいません。これは「手動で編集しない」というルールの唯一の例外です。このスクリプトは常に新しいファイルを作成するため、既存のファイルにルールを追加するには XML を直接編集する必要があります。
してはいけないこと
code-analyzer.yml全体を書き直して構成し直さないでください- すべてのルールを並行して作成してから、一括で検証しないでください
- 参照ドキュメントにある未検証の XPath を使って PMD ルールを作成しないでください。各パターンに対して ast-dump を実行してください
- 1 回の作成手順で異なる種類のエンジンを混在させないでください(例:Regex ルールと PMD ルールを同時に作成する)
- ファイルが存在する前に、
code-analyzer.ymlにengines.eslint.eslint_config_fileを追加しないでください
シグナルの高いルール
| ルール | 根拠 |
|---|---|
ルール名は /^[A-Za-z@][A-Za-z_0-9@\-/]*$/ に一致する必要があります | Code Analyzer の検証で、それ以外は拒否されます |
正規表現は /pattern/flags 形式である必要があります | JavaScript の正規表現リテラル表記が必要です |
ファイル拡張子は . で始まる必要があります | 検証では /^([.][a-zA-Z0-9-_]+)+$/ が強制されます |
| 作成後は必ず検証してください | sf code-analyzer rules --rule-selector <engine>:<name> で設定エラーを検出できます |
| サンプルコードに対して必ずテストしてください | 全体スキャンの前に XPath/正規表現の不一致を検出できます |
XPath でメソッド呼び出しを検索するときは @FullMethodName を使用してください | @Image や @MethodName のみを使うより信頼性が高くなります |
ast-dump を絶対に省略しないでください | ast-dump を実行して出力を読み、その後で XPath を作成してください。例外はありません。「明白な」パターンであっても同様です。ast-dump による検証なしに、記憶を頼りにノード名を使用するのはスキル不足です。 |
PMD 7 のブール属性には = false() XPath 関数を使用してください | PMD 7 では、@WithSharing、@Abstract、@Final のようなブール属性はノード上に常に存在し、存在しないことはありません。'false' という文字列ではなく、= false()(XPath ブール関数)で比較してください。@WithSharing = false() は機能します。@WithSharing='false'(文字列)は機能しません。not(@WithSharing) も機能しません(属性は常に存在します)。 |
プロジェクトルートに code-analyzer.yml を配置してください | CLI によって自動検出されます。別の場所に置くと、ルール作成者にとってエラーが通知されないまま発生します |
XML ルールでは必ず local-name() を使用してください | Salesforce のメタデータ名前空間により、要素名だけの指定は機能しません |
XML のテキスト照合では必ず @Text 属性を使用してください | PMD 7 の XML 言語では text() は機能しません。//*[@Text='value'] でテキストの内容を照合し、../.. を使って親要素に移動してください。 |
@Text は要素ではなく、子テキストノードにあります | //*[local-name()='apiVersion'][@Text < 60] → 誤り(一致数 0)。//*[local-name()='apiVersion']/*[number(@Text) < 60] → 正しい。/* で子テキストノードに移動します。完全一致のパターンでは、テキストノードも含むすべてのノードを検索するため、//*[@Text='value'] が機能します。しかし、最初に local-name() で特定の要素を対象にする場合は、テキストの子ノードにアクセスするために /*[@Text...] を使用する必要があります。 |
XML ルールには file_extensions 設定が必要です | PMD はデフォルトで .xml のみをスキャンします。engines.pmd の下に file_extensions: { xml: [".xml"] } を追加してください。複合拡張子(.permissionset-meta.xml)は追加しないでください。バリデーターに拒否されます。また、.xml だけですべての Salesforce メタデータファイルをカバーできます。 |
正規表現の名前付きキャプチャグループ (?<target>...) | 違反のハイライトを、キャプチャした部分だけに絞り込めます |
Salesforce ID は 0 で始まり、長さは正確に 15 または 18 文字です | /['"](?<target>0[a-zA-Z0-9]{14}(?:[a-zA-Z0-9]{3})?)['\"]/g を使用してください。{15,18} は使用しないでください。16/17 文字の文字列にも一致し、'BusinessAccount' のような通常の単語で誤検出が発生します |
regex_ignore はファイル単位ではなく行単位です | 無視パターンに一致する行のみがスキップされます。ファイル全体やクラス全体は除外されません。テストクラスの 10 行目にあるハードコードされた ID は、その行に無視パターン(例:@isTest)が含まれない限り、引き続き検出されます。 |
| ルールの作成には必ずスクリプトを使用してください | 正規表現ルールで code-analyzer.yml を手動編集しないでください。YAML 内の正規表現に含まれる引用符やバックスラッシュが、解析エラーの原因になります。create-regex-rule.js スクリプトなら正しくシリアライズできます。 |
<rule ref="..."> を使って組み込みルールをオーバーライドしてください | 新しいルールを作成せずにしきい値を変更できます |
| JS/LWC/TS ファイルでは正規表現を絶対に使用しないでください | JavaScript の正規表現では、コードとコメント/文字列を区別できません。JavaScript のパターンには必ず ESLint を使用してください |
| カスタムルールを作成する前に、組み込みの ESLint ルールを確認してください | no-console、no-debugger、no-alert、eqeqeq、no-eval などはすでに存在します。設定で有効にするだけです |
注意点
| 問題 | 解決方法 |
|---|---|
| ast-dump を実行せずに XPath を記述する | 必ず最初に ast-dump を実行してください。 ルールが機能する場合でも、ast-dump を省略するのはプロセス上の失敗です。ノード名は PMD のバージョンによって変わるため、推測できません。 |
SOQL-in-loop ルールが for (x : [SELECT...]) に警告する | //ForEachStatement/BlockStatement//SoqlExpression を使用してください(本体にスコープを限定します)。反復可能な SOQL は、BlockStatement と並んで ForEachStatement の直接の子になっています。//ForEachStatement//SoqlExpression では誤検知として一致してしまいます。 |
| JS/LWC/TS のパターンに Regex を使用した | JavaScript ファイルでは Regex を絶対に使用しないでください。 Regex では JS のコードとコメント/文字列を区別できません。必ず ESLint を使用してください。まず、組み込みルール(例:no-console)がすでに存在するか確認します。 |
| XPath が 0 件に一致する(XML メタデータ) | よくある原因は 3 つです。(1)local-name() を忘れている — 名前空間があると、要素名をそのまま指定しても一致しません。(2)text()='value' を使用している — PMD 7 では機能しません。代わりに @Text='value' を使用します。(3)要素に [@Text] 述語を指定している — @Text は子テキストノードにあります。/*[@Text...] を使用してたどります。 |
Regex ルールを code-analyzer.yml に直接記述した — YAML の解析エラー | 必ず create-regex-rule.js を使用してください — YAML 内の引用符やバックスラッシュが原因でエスケープに失敗します。設定ファイルに Regex を手書きしないでください。 |
regex_ignore でテストクラスが除外されない | regex_ignore は行単位のみです。テストクラスの 50 行目にある SOQL クエリは、50 行目に @isTest が含まれていないため警告されます。ファイル単位で除外するには、ignores.files(グローバル)または PMD XPath [not(ancestor::UserClass[ModifierNode[@Test = true()]])](ルール単位)を使用します。 |
XPath の @WithSharing='false' または not(@WithSharing) が機能しない | PMD 7 のブール属性(@WithSharing、@Abstract、@Final)は必ず存在します。文字列の ='false' は一致しません(ブール値であるため)。属性は常に存在するため、not(@attr) も機能しません。XPath のブール関数 @WithSharing = false() を使用します。 |
ループベースのルールが ForEachStatement のみを対象としている | Apex には 3 種類のループがあります:ForEachStatement、ForLoopStatement、WhileLoopStatement。3 つすべてを XPath に含める必要があります。いずれかを省くと、気づきにくいカバレッジの欠落が生じます。 |
スクリプト実行後に code-analyzer.yml を書き換えた — YAML の解析エラー | スクリプト実行後にファイルを手動で書き換えないでください。 ignores.files のようなトップレベルの設定ブロックは新しいエントリとして追加するだけにし、スクリプトが生成した engines.regex.custom_rules セクションには手を加えないでください。 |
| 複数のルールを一度に作成した — 1 つの失敗で後続のルールがすべて失敗する | ルールは 1 つずつ順番に作成してください。 次のルールを開始する前に、各ルールについてワークフロー全体(作成 → 検証 → テスト)を完了させます。 |
誤った重大度、Java が見つからない、ESLint の設定パス、メタデータのファイル種別によるスコープ指定など、その他の診断については <skill_dir>/references/troubleshooting.md を参照してください。
スキル間の連携
| 必要な作業 | 委任先 | 理由 |
|---|---|---|
| ルール作成後に全体スキャンを実行する | dx-code-analyzer-run | スキャンの実行と結果の提示 |
| Code Analyzer をインストールする/前提条件の問題を解決する | dx-code-analyzer-configure | セットアップとトラブルシューティング |
| 既存の組み込みルールについて説明する | dx-code-analyzer-run | ルールの説明とドキュメントの検索 |
エンジン設定のために code-analyzer.yml を編集する | dx-code-analyzer-configure | 設定管理 |
スクリプトの実行
<skill_dir> は、この SKILL.md ファイルがあるディレクトリの絶対パスです。
すべてのスクリプトは、この SKILL.md ファイルがあるディレクトリと同じディレクトリ内の scripts/ サブディレクトリに格納されています。そのディレクトリの絶対パスを使用してください。./scripts/ は現在の作業ディレクトリを基準に解決され、スキルのディレクトリを基準にしないため、使用しないでください。
node "<skill_dir>/scripts/create-regex-rule.js" \
--name "RuleName" --regex "/pattern/flags" ...
次のことはしないでください:
- スクリプトコードを独自に考案したり生成したりしない
node scripts/create-regex-rule.jsのような相対パスをそのまま使用しない(ユーザーの CWD からは解決できません)- ヒアドキュメントやインラインのスクリプト内容を使用しない
<skill_dir>の解決を省略しない — まず絶対パスを見つけてください
リファレンスファイル一覧
| ファイル | 読むタイミング |
|---|---|
references/regex-rule-schema.md | 正規表現ルールを作成するとき — フィールドの完全なリファレンス、検証ルール、複数ルールの例 |
references/xpath-patterns.md | Apex 用の XPath を記述するとき — 構文リファレンスと AST ノード用語を含むパターンカテゴリの一覧 |
references/xpath-patterns-governor-limits.md | ループ内の SOQL/DML、ループ内の Database メソッドに対する XPath パターン |
references/xpath-patterns-method-calls.md | メソッドの禁止とアノテーション(@AuraEnabled、@future、@IsTest)パターンに対する XPath パターン |
references/xpath-patterns-security.md | 共有宣言、SOQL セキュリティ、ハードコードされた ID に対する XPath パターン |
references/xpath-patterns-structure.md | コード構造、テスト品質、命名規則に対する XPath パターン |
references/apex-ast-reference.md | Apex AST ダンプの読み方 — ノード階層、修飾子属性、主要なノード型 |
references/metadata-xml-rules.md | メタデータ XML のルールを記述するとき — 名前空間の回避策、一般的な構造、XPath パターン |
references/advanced-pmd-patterns.md | 複数ルールのルールセット、組み込みルールの上書き、除外パターン、Java ルール、プロジェクト間での共有 |
references/eslint-rules-discovery.md | あらゆる ESLint に関する依頼で最初に読むこと — 検索ワークフロー、組み込みルール、Tier 1~3 の一覧 |
references/eslint-tier2-configurable.md | ESLint Tier 2:no-restricted-globals、no-restricted-syntax、no-restricted-properties のパターン |
references/eslint-tier3-custom-plugins.md | ESLint Tier 3:カスタムプラグインを作成する場合と、すべての Tier の完全な例 |
references/eslint-custom-plugins.md | カスタム ESLint プラグインの作成 — 検索ワークフローで組み込みルールも設定可能なルールも存在しないと確認された場合に限る(Tier 3) |
references/troubleshooting.md | 検証またはテストに失敗したとき — エンジンの種類ごとのエラー診断 |
assets/pmd-ruleset-template.xml | create-pmd-rule スクリプト用のプレースホルダーを含む PMD XML スケルトン |
examples/regex-examples.md | コミュニティから報告された問題を解決する、実際の正規表現ルール 6 件 |
examples/xpath-examples.md | AST コンテキストと段階的な作成手順を含む、Apex 用の実際の XPath ルール 6 件 |
examples/metadata-xml-examples.md | 実際のメタデータ XML ルール 6 件(権限、説明、API バージョン、フロー)の一覧 |
examples/metadata-xml-example-permissions.md | メタデータの例:ModifyAllData/ViewAllData、プロファイル内の項目権限 |
examples/metadata-xml-example-fields-api.md | メタデータの例:カスタム項目の説明、最小 API バージョン |
examples/metadata-xml-example-flows.md | メタデータの例:フローの自動レイアウト、フローの障害ハンドラー |