mcpField
D
dx-code-analyzer-custom-rule-create

dx-code-analyzer-custom-rule-create

github.com/forcedotcom测试与质量1.1k4.9k 次安装1 天前更新
代码仓库

关于 dx-code-analyzer-custom-rule-create

用于通过 Regex、PMD/XPath 或 ESLint 创建 Salesforce Code Analyzer 自定义规则的 Skill。它指导选择引擎,并要求检查 AST、使用脚本创建规则、验证及进行正反样例测试。

主要功能

  1. 01根据模式选择规则引擎
  2. 02创建 Regex、PMD/XPath 和 ESLint 规则
  3. 03使用 ast-dump 检查 Apex 结构
  4. 04验证规则并测试正反样例
  5. 05按引擎处理测试文件排除

适用场景

  1. 01落实团队专属编码规范
  2. 02标记禁止的代码或元数据模式
  3. 03为 Apex、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.xml
examples/
metadata-xml-example-fields-api.md
metadata-xml-example-flows.md
metadata-xml-example-permissions.md
metadata-xml-examples.md
regex-examples.md
xpath-examples.md
references/
advanced-pmd-patterns.md
apex-ast-reference.md
eslint-custom-plugins.md
eslint-rules-discovery.md
eslint-tier2-configurable.md
eslint-tier3-custom-plugins.md
metadata-xml-rules.md
regex-rule-schema.md
troubleshooting.md
xpath-patterns-governor-limits.md
xpath-patterns-method-calls.md
xpath-patterns-security.md
xpath-patterns-structure.md
xpath-patterns.md
scripts/
create-pmd-rule.js
create-regex-rule.js

详细介绍

dx-code-analyzer-custom-rule-create:自定义代码分析器规则编写

生态系统: 此技能属于包含 3 项技能的 Code Analyzer 套件:dx-code-analyzer-run(扫描和结果)· dx-code-analyzer-configure(设置、配置、CI/CD)· dx-code-analyzer-custom-rule-create(自定义规则编写)。

当用户需要创建自定义规则来强制执行 Code Analyzer 内置规则未涵盖的模式时,使用此技能。支持 Regex 引擎(文本模式匹配)和 PMD 引擎(针对 AST 的结构化 XPath 查询)。

此技能适用的任务

在工作涉及以下内容时,使用 dx-code-analyzer-custom-rule-create:

  • 为 Code Analyzer 创建新的自定义规则(适用于任意引擎)
  • 通过静态分析强制执行团队特定的编码规范
  • 禁止特定模式(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),也必须先运行 ast-dump。如果跳过此步骤,但规则能够正常工作,仍然属于流程失败。

  2. 创建规则时必须始终使用脚本。 对于 regex 规则,必须始终使用 create-regex-rule.js。对于 PMD 规则,必须始终使用 create-pmd-rule.js。不得手动编辑 code-analyzer.yml 来添加规则定义——YAML 中的 regex 模式会导致转义失败(引号中的引号、反斜杠被吞掉)。脚本每次都能正确处理 YAML 序列化。

  3. 脚本写入 code-analyzer.yml 后,绝不能手动编辑该文件——即使只是修正错误值也不行。 脚本会生成转义正确的 YAML。之后如果重写或重新组织文件,就会破坏转义。如果用户添加了顶层配置(例如 ignores.files),也不要改动——只处理你自己写入的内容。

    如果脚本的输出看起来有误(规则无法通过验证、YAML 解析错误、regex 中有多余字符):

    • 不要手动修补 YAML。这正是此约束要避免的失败方式。
    • 务必删除出问题规则的整个 YAML 块,然后使用修正后的参数重新调用脚本。删除你刚写入的块不违反此规则;重写块内字段则违反。
    • 如果脚本接受了错误的输入并生成了错误的输出,那么错误在于输入(例如,--regex "/.../ g" 中多了空格——标志必须严格为 /g,不得有空格)。使用修正后的参数重新调用脚本。
    • 如果你确实认为脚本有缺陷,请停止操作并告知用户。不得手动编辑来绕过问题。
  4. --regex 必须采用 /pattern/flags 格式,且不得包含空格。 脚本会严格去除并验证标志——只允许 g、i、m、s、u、y。/pat/ g(含空格)会被拒绝,/pat/x(无效标志)也会被拒绝,/pat/(没有标志)同样会被拒绝。必须包含全局标志 g。如果验证失败,请修正参数——不得绕过验证直接编写 YAML。

  5. 创建后必须始终进行验证。 运行 sf code-analyzer rules --rule-selector <engine>:<name>,然后再测试。如果显示 Found 0 rules,说明 YAML 解析失败——删除该块、修正参数,并重新调用脚本。

  6. 必须始终使用示例文件进行测试。 至少确认一个真正例和一个真反例。

    对于 regex 规则,反例样本中不得在任何位置包含该模式文本,包括注释和字符串字面量。Regex 引擎会扫描原始文本;// no System.debug here 会匹配 /System\.debug/g。运行前,请先在脑中检查该模式对反例文件的匹配情况。

  7. 按顺序一次创建一条规则。 用户请求多条规则时,每条规则都要分别完成完整流程(创建 → 验证 → 正例测试 → 反例测试),再开始下一条。不得批量创建规则——如果其中一条失败,会导致后续所有规则的配置都出问题。完成每条规则的端到端流程并确认其有效后,再继续下一条。

  8. 对于 regex 规则,使用 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 之类的 globregex_ignore 按行生效,而不是按文件生效——它无法排除整个测试类。仅将 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),请对需要选择性排除的规则使用 PMD 和 XPath。PMD 的 XPath 可以按方法或类结构检查 @Test = true()——Regex 无法做到这一点。

Apex 规则跳过测试类的决策指南:

  • 如果模式具有结构性(方法调用、注解、嵌套)→ 使用 PMD。XPath 原生支持排除测试类。
  • 如果模式纯属文本 AND 所有 regex 规则都应跳过测试类 → 使用 Regex + ignores.files。
  • 如果规则要求不一(部分规则跳过测试类,其他规则不跳过)→ 对需要考虑测试类的规则使用 PMD,其他规则使用 Regex。

工作流

用户选择代码时(IDE 中的选区)

当用户在编辑器中选中一段代码,并要求“捕获这个”“标记这种模式”“为此创建一条规则”或提出类似要求时:

  1. 选区就是你的正例。 不要问“这条规则应该标记什么模式?”——用户已经展示给你了。不要从头编写新的示例。
  2. 判断选区中哪些是结构性的,哪些是偶然的:
    • 结构性(值得编写规则):方法调用、循环模式、缺失的关键字、嵌套结构
    • 偶然的(忽略):具体变量名、字符串值、参数数量
    • 如果有歧义,只问一个问题:“这条规则应该捕获所有 System.debug 调用,还是只捕获没有 LoggingLevel 参数的调用?”
  3. 对用户打开的实际文件执行 Ast-dump(不要创建新示例文件):
    sf code-analyzer ast-dump --file <the-open-file.cls> --output-file <ast.xml>
    
  4. 在 AST 输出中查找选区——定位与高亮行对应的节点。这些就是目标节点。
  5. 泛化 XPath——编写与结构模式匹配的 XPath,而不是与具体实例匹配。将具体变量名替换为通配符,保留结构节点和有区分作用的属性。
  6. 继续执行标准工作流(负例、创建规则、验证、测试正例和负例)。

示例流程:

  • 用户选中:Database.query('SELECT Id FROM ' + objectName)
  • 结构模式:Database.query 调用(动态 SOQL)
  • 偶然因素:其中具体的字符串拼接
  • 引擎:PMD(结构化调用检测)
  • XPath://MethodCallExpression[@FullMethodName='Database.query']
  • 不要使用:匹配 Database.query 的正则表达式(会漏掉多行调用,也会匹配注释)

示例流程(选中代码块):

  • 用户选中一个包含 for-each 循环内 SOQL 语句的 5 行代码块
  • 结构模式:循环体的后代节点中的 SOQL 查询
  • 偶然因素:具体查询字段、变量名
  • 引擎:PMD
  • 对打开的文件执行 Ast-dump → 在循环体中查找 ForEachStatement + SoqlExpression
  • XPath://ForEachStatement/BlockStatement//SoqlExpression

正则表达式规则
  1. 编写正例(5-10 行)来展示违规情况。将示例文件放在项目工作区内(例如项目根目录下临时创建 samples/ 目录),以便 Code Analyzer 能够扫描这些文件。
  2. 单独编写一个负例文件——代码看起来相似,但绝不能被标记。创建规则前,先在脑中用正则表达式检查此文件。
  3. 构建并创建规则——阅读 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 中的正则表达式字符(引号、反斜杠、大括号)会导致解析失败。脚本会正确处理序列化。
  4. 验证——sf code-analyzer rules --rule-selector regex:<RuleName>
  5. 测试正例——sf code-analyzer run --rule-selector regex:<RuleName> --target <violation-sample>——必须找到违规。
  6. 测试负例——sf code-analyzer run --rule-selector regex:<RuleName> --target <clean-sample>——必须找到 0 个违规。如果干净代码被标记,说明正则表达式范围太宽——返回并收紧模式。
  7. 如果测试失败,则迭代调整(调整正则表达式、添加 regex_ignore、缩小扩展名范围)
  8. 清理——删除你创建的所有示例文件。不要在用户的项目中留下临时测试文件。
适用于 PMD/XPath 规则(Apex)
  1. 编写最小示例(5–10 行),展示违规情况。请在项目工作区内编写示例文件(例如,在项目根目录下创建临时 samples/ 目录),以便 Code Analyzer 能对其进行检查。正向和负向测试都通过后,请删除你创建的所有示例文件——包括原始示例和测试期间创建的所有副本。不要在用户的项目中留下临时测试样例。对于基于循环的规则,正向示例必须包含 Apex 的全部 3 种循环类型(for-each、传统 for 和 while)——遗漏任何一种循环类型,就意味着 XPath 未针对该类型进行验证,可能会悄悄漏掉违规情况。
  2. 必须:导出 AST——sf code-analyzer ast-dump --file <sample.cls> --output-file <ast.xml>——此步骤不可省略。即使你“已经知道”节点名称,也不得跳过。请运行命令、阅读输出,并确认确切的节点名称和属性。
  3. 阅读 AST 输出——根据实际的 ast-dump 输出(而非记忆)识别目标节点及其属性。仅将 references/apex-ast-reference.md 和 references/xpath-patterns.md 用作补充参考。
  4. 编写 XPath——使用具有区分性属性的最小稳定节点作为目标。XPath 中的每个节点名称都必须原样出现在你刚刚阅读的 ast-dump 输出中。要有意区分使用 /Child(直接子节点)和 //Descendant(后代节点)——请检查 ast-dump,了解哪些节点是同级节点,哪些是嵌套节点。
  5. 创建规则之前:编写单独的负向示例文件(5–10 行),展示正确且不应被标记的代码。该文件必须与正向示例分开——不得将正向和负向案例合并到同一个文件中。对于基于循环的规则,请包含 for (x : [SELECT...]) 这种写法。也要对此负向示例文件运行 sf code-analyzer ast-dump。阅读输出并对照检查 XPath,确认它不会匹配负向 AST 中的任何节点。如果会匹配,请返回第 4 步,在继续之前收紧 XPath。不得跳过此步骤,也不得推迟到创建规则之后再做。第 9 步还会再次使用该负向文件,明确确认违规数为零。
  6. 创建规则——运行脚本:
    node "<skill_dir>/scripts/create-pmd-rule.js" \
      --name "<RuleName>" --xpath "<expression>" --message "<msg>" \
      --language apex --priority <1-5>
    
  7. 验证——sf code-analyzer rules --rule-selector pmd:<RuleName>
  8. 测试正向案例——sf code-analyzer run --rule-selector pmd:<RuleName> --target <violation-sample.cls>——必须检测到违规情况
  9. 测试负向案例——sf code-analyzer run --rule-selector pmd:<RuleName> --target <clean-sample.cls>——必须检测到 0 个违规。如果标记了正确代码,说明 XPath 范围过宽——请返回第 4 步。
  10. 如果测试失败,请迭代调整(重新检查 AST、调整 XPath、检查节点名称)
  11. 清理——删除你创建的所有示例文件(正向和负向示例,以及所有 ast-dump 输出文件)。不要在用户的项目中留下临时测试样例。
对于 PMD/XPath 规则(元数据 XML)
  1. 识别元数据文件类型(field、permissionset、profile、flow 等)
  2. 导出 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 DOM 结构就是 AST(文件中看到的内容就是 PMD 看到的内容)。读取文件并记录元素名称、嵌套关系和文本内容。
  3. 读取 DOM 结构 — 根据 ast-dump 输出或原始文件确认元素名称、嵌套关系和文本内容。仅将 references/metadata-xml-rules.md 用作补充参考。
  4. 为 PMD 7 编写 XPath — 元数据 XML XPath 的关键规则:
    • 匹配所有元素时必须使用 local-name()='ElementName'(命名空间会屏蔷裸名称)
    • 匹配文本内容时必须使用 @Text 属性(不能用 text() — text() 函数在 PMD 7 的 XML 语言中不起作用)。示例://*[@Text='ModifyAllData']
    • 使用 ../.. 从文本节点向上导航到父元素(文本节点 → 元素 → 父元素)
    • 使用父元素上的 .//*[@Text='value'] 检查同级条件
    • 完整的 PMD 7 XPath 模式请参见 references/metadata-xml-rules.md
  5. 配置文件扩展名 — 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 元数据文件。
  6. 单独编写负向样本文件 — 与 Apex 规则相同:创建一个正确且不应被标记的元数据文件。在创建规则前,验证 XPath 不会匹配该文件。正向和负向样本都应在工作区中使用 .xml 扩展名,以便 PMD 直接扫描。
  7. 创建规则 — 运行脚本:
    node "<skill_dir>/scripts/create-pmd-rule.js" \
      --name "<RuleName>" --xpath "<expression>" --message "<msg>" \
      --language xml --priority <1-5>
    
  8. 验证 — sf code-analyzer rules --rule-selector pmd:<RuleName>
  9. 测试正向样本 — sf code-analyzer run --rule-selector pmd:<RuleName> --target <violation-sample>.xml — 必须找到违规项
  10. 测试负向样本 — sf code-analyzer run --rule-selector pmd:<RuleName> --target <clean-sample>.xml — 必须找到 0 个违规项
  11. 如果测试失败,则迭代调整(检查 @Text 与 text() 的使用是否正确,确认使用了 local-name(),检查文件扩展名配置)
  12. 清理 — 删除你创建的所有样本文件(正向和负向样本,以及为测试制作的任何 .xml 副本)。不要在用户的项目中留下临时测试文件。
对于 ESLint 规则(LWC/JavaScript/TypeScript)
ESLint 发现工作流(请先阅读)

ESLint 有 200 多条内置规则,以及数千条来自插件的规则。在检查内置规则是否存在之前,切勿尝试创建自定义插件。发现工作流如下:

  1. 第 1 层(内置规则) — 占请求的 70%

    • 运行:sf code-analyzer rules --rule-selector eslint
    • 搜索关键词(例如“console”“unused”“equal”)
    • 检查 LWC 插件规则(@lwc/lwc/*)
    • 如果找到匹配项:配置后停止
  2. 第 2 层(可配置规则) — 占请求的 20%

    • 如果模式是“禁止函数 X”?→ no-restricted-globals
    • 如果模式是“禁止语法 Y”?→ no-restricted-syntax
    • 如果模式是“禁止属性 Z”?→ no-restricted-properties
    • 如果适用:配置后停止
  3. 第 3 层(自定义插件) — 占请求的 10%

    • 仅用于特定领域的多节点模式
    • 需要 Node.js 代码、测试和 meta.docs 元数据
    • 参见:references/eslint-custom-plugins.md

参见: references/eslint-rules-discovery.md,其中提供了完整的发现指南和示例。


  1. 必须:先运行 ESLint 发现工作流。 90% 的 ESLint 请求都可以通过内置规则(第 1 层)或可配置规则(如 no-restricted-syntax,第 2 层)解决。创建自定义插件(第 3 层)是最后的手段。继续操作前:

    a) 运行: sf code-analyzer rules --rule-selector eslint b) 在输出中搜索用户请求中的关键词(例如“console”“equal”“unused”) c) **检查 LWC 插件规则:**在输出中搜索 @lwc/lwc/ d) **如果找到:**配置该规则(参见 references/eslint-rules-discovery.md)并停止。不要创建自定义插件。 e) **如果未找到:**检查 no-restricted-globals、no-restricted-syntax 或 no-restricted-properties 是否能够表达该模式(第 2 层)。 f) **只有在第 1 层和第 2 层均无可行方案时:**才创建自定义插件。

    **验证:**配置后,运行 sf code-analyzer rules --rule-selector eslint:<ruleName>,确认规则已显示。如果没有显示,说明配置有误。

    跳过此发现工作流,在存在内置规则时创建自定义插件,属于技能缺陷,无论自定义插件是否有效。

**ESLint 内置规则与可配置规则:**Code Analyzer 在其基础配置中包含一部分 ESLint 规则。no-restricted-globals、no-restricted-syntax 和 no-restricted-properties 等规则是 ESLint 核心规则,但在 eslint.config.js 中启用之前不会生效。只有在配置后,它们才会显示在 sf code-analyzer rules 的输出中。务必验证(第 4 步),确认规则确实已加载——不要仅因某条规则是 ESLint 核心规则就认定它已存在。

  1. 安装 ESLint 插件(使用 ESLint 内置/核心规则时跳过)—— npm install --save-dev eslint-plugin-<name>
  2. 创建/更新 eslint.config.js——添加插件和规则配置(或仅启用内置规则并将严重级别设为 "error")。在 code-analyzer.yml 中配置 engines.eslint.eslint_config_file 之前,必须先创建此文件——Code Analyzer 会验证该路径,若文件缺失则会失败。
  3. 配置 Code Analyzer——在 code-analyzer.yml 中设置 engines.eslint.eslint_config_file。此操作必须在文件创建后进行。
  4. 验证——运行 sf code-analyzer rules --rule-selector eslint:<ruleName>。如果规则没有显示,说明配置有误——不要继续测试。请检查:(a) eslint.config.js 文件是否位于正确位置?(b) 插件是否包含 meta.docs.description 和 meta.docs.url?(c) 规则是否已弃用?Code Analyzer 会静默排除已弃用的规则。
  5. 在工作区中编写一个测试示例文件(例如 lwc/testSample/testSample.js),展示违规情况
  6. 正向测试——运行 sf code-analyzer run --rule-selector eslint:<ruleName> --target <test-sample>——必须能发现违规
  7. 反向测试——对现有的干净 LWC 文件运行——必须发现 0 个违规
  8. 清理——删除所有示例文件及其父目录(LWC 要求每个组件都有独立文件夹)。使用 rm -rf <directory>,不要只使用 rm <file>。不要在用户的项目中留下空目录或临时测试夹具。
  9. 完整指南参见 references/eslint-custom-plugins.md
不使用自定义插件的常见 ESLint 模式

no-restricted-globals、no-restricted-syntax 和 no-restricted-properties 的配置示例,请参阅 <skill_dir>/references/eslint-custom-plugins.md 中的“禁止 API 而不使用自定义插件”部分。

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)

  • 用户:“禁止使用 innerHTML 以防止 XSS”
  • 发现:已有 @lwc/lwc/no-inner-html
  • 操作:在配置中启用 @lwc/lwc/no-inner-html
  • 结果:2 分钟内完成(无需自定义插件)

示例 4:适合使用自定义插件(Tier 3)

  • 用户:“标记未进行错误处理的命令式 Apex 调用”
  • 发现:没有针对这种模式的内置规则
  • 分析:该模式需要检查没有 .catch() 的 import + .then()——需要遍历多个节点
  • 操作:使用 visitor 模式创建自定义插件
  • 结果:适合使用自定义插件(耗时 20 分钟以上)

完整的发现工作流请参阅 references/eslint-rules-discovery.md。


覆盖内置规则的阈值

无需编写新规则,即可自定义现有规则的严重性或属性:

  1. 创建自定义规则集,引用带有覆盖项的内置规则
  2. 添加到配置中——code-analyzer.yml 中的 engines.pmd.custom_rulesets
  3. 覆盖语法和常见示例请参阅 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. 先创建 Regex 规则(最快、依赖最少)
  2. PMD Apex 规则(每条规则都需要 ast-dump)
  3. PMD XML 规则(可以共用一个规则集文件)
  4. 最后创建 ESLint 规则(需要 npm/配置设置)
第 3 步:多条 PMD 规则可以共用一个规则集文件

创建多条 PMD 规则时,第一条规则使用 create-pmd-rule.js 脚本(该脚本会创建规则集 XML 文件)。对于后续要添加到同一个规则集文件中的 PMD 规则,可以手动添加到现有 XML 文件中——这是“绝不手动编辑”规则的唯一例外。该脚本始终会创建新文件;将规则添加到现有文件需要直接编辑 XML。

不要这样做
  • 不要重写整个 code-analyzer.yml 来重新组织配置
  • 不要并行创建所有规则,然后一次性验证
  • 不要使用未经验证、来自参考文档的 XPath 创建 PMD 规则——应对每种模式运行 ast-dump
  • 不要在一个创建步骤中混用引擎类型(例如,同时创建 Regex 和 PMD 规则)
  • 在文件尚不存在时,不要将 engines.eslint.eslint_config_file 添加到 code-analyzer.yml

高信号规则

规则原因
规则名称必须匹配 /^[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()(XPath 布尔函数)进行比较,不要使用字符串 'false'。@WithSharing = false() 可行。@WithSharing='false'(字符串)不可行。not(@WithSharing) 不可行(该属性始终存在)。
项目根目录中的 code-analyzer.ymlCLI 会自动发现该文件——将其放在其他位置会导致规则作者遇到无提示的失败
XML 规则必须使用 local-name()Salesforce 元数据命名空间会导致裸元素名称无法匹配
XML 文本匹配必须使用 @Text 属性text() 在 PMD 7 的 XML 语言中不起作用。使用 //*[@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 文件使用 RegexRegex 无法区分 JS 中的代码、注释和字符串——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 是 ForEachStatement 的直接子节点,与 BlockStatement 同级;//ForEachStatement//SoqlExpression 会匹配到它,造成误报。
用 Regex 检查 JS/LWC/TS 模式绝不要对 JavaScript 文件使用 Regex。 Regex 无法区分 JS 中的代码、注释和字符串。始终使用 ESLint——先检查是否已有内置规则(例如 no-console)。
XPath 返回 0 个匹配项(XML 元数据)常见原因有三种:(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()。
基于循环的规则只覆盖 ForEachStatementApex 有 3 种循环类型:ForEachStatement、ForLoopStatement 和 WhileLoopStatement。XPath 中必须包含这 3 种类型——漏掉任何一种都会留下隐蔽的覆盖缺口。
脚本写入后又重写了 code-analyzer.yml——导致 YAML 解析错误脚本运行后绝不要手动重写文件。 只需新增顶层配置块(例如 ignores.files)——不要改动脚本生成的 engines.regex.custom_rules 部分。
一次创建多条规则——一条失败会导致后续规则全部失败逐条依次创建规则。 每条规则都完成完整工作流(创建 → 验证 → 测试)后,再开始下一条。

如需了解更多诊断信息(严重级别错误、找不到 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(无法从用户的当前工作目录解析)
  • 使用 heredoc 或内联脚本内容
  • 跳过 <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.mdESLint Tier 2:no-restricted-globals、no-restricted-syntax、no-restricted-properties 模式
references/eslint-tier3-custom-plugins.mdESLint Tier 3:何时创建自定义插件,以及涵盖所有 Tier 的完整示例
references/eslint-custom-plugins.md创建自定义 ESLint 插件——仅在发现工作流确认不存在内置或可配置规则后使用(Tier 3)
references/troubleshooting.md验证或测试失败时——按引擎类型诊断错误
assets/pmd-ruleset-template.xmlPMD XML 骨架,包含供 create-pmd-rule 脚本使用的占位符
examples/regex-examples.md解决社区反馈问题的 6 个真实正则表达式规则
examples/xpath-examples.md6 个用于 Apex 的真实 XPath 规则,包含 AST 上下文和逐步创建说明
examples/metadata-xml-examples.md6 个真实元数据 XML 规则索引(权限、描述、API 版本、流)
examples/metadata-xml-example-permissions.md元数据示例:ModifyAllData/ViewAllData、配置文件中的字段权限
examples/metadata-xml-example-fields-api.md元数据示例:自定义字段描述、最低 API 版本
examples/metadata-xml-example-flows.md元数据示例:流自动布局、流故障处理程序

评论

支持 Markdown