首页 / 资讯中心 / 文章详情

PMD 文档规则引用标签({% rule %})的用法规范与自动化校验机制

PMD 文档规则引用标签({% rule %})的用法规范与自动化校验机制 ★ FEATURED ARTICLE
静态分析代码质量【免费下载链接】pmdAn extensible multilanguage static code analyzer.项目地址https://gitcode.com/gh_mirrors/pm/pmd点击查看免费下载导读PMD 的官方文档由 Jekyll 与 Markdown 构建其中规则文档页面如java/design、java/codestyle由pmd-doc子模块从各语言模块的 XML category 文件自动生成。为了让规则文档之间可以互相引用例如废弃规则的说明中指向替代规则PMD 提供了一套自定义 Liquid 标签{% rule %}并在构建期通过RuleTagChecker自动校验标签的引用是否有效。本文将基于仓库中ruletagchecker测试样例文档系统讲解{% rule %}标签的语法规范、常见错误模式、底层实现原理及其与 Maven/Jekyll 构建流程的集成方式。读完本文你将能正确编写规则引用、理解并复现构建期的死引用检查机制。一、{% rule %} 标签规则文档间的交叉引用机制PMD 的文档分为两类一类是手工编写的页面存放在 docs/pages 下结构对应侧边栏另一类是从各语言模块的categoryXML 文件自动生成的规则文档页面。规则文档页面按pmd_rules_语言_分类.html的永久链接permalink组织例如pmd_rules_java_design.html。当一条规则的描述需要指向另一条规则时例如标记为废弃的规则提示读者改用替代规则直接写死 HTML 链接既难维护又易失效因此 PMD 引入了自定义 Liquid 标签{% rule %}其实现位于 docs/_plugins/rule_tag.rb标签在渲染时把规则引用解析为语言、分类、规则名三段若当前页面本身是某个规则分类页permalink 形如pmd_rules_语言_分类.html则省略的语言、分类段会自动从页面推断最终渲染为一个 Markdown 链接规则名锚点指向目标规则页面的标题。此外还有一个{% deleted_rule %}变体标签用于渲染已删除规则的占位链接以(deleted)后缀标记同样注册在 rule_tag.rb 中。[!NOTE] 手工文档中使用{% rule %}的示例可参考 docs/pages/pmd/devdocs/contributing/writing_documentation.md其中列出了该标签的渲染效果对照表。二、标签语法与引用格式{% rule %}标签的核心语法是{% rule 语言/分类/规则名 %}规则引用由三段构成语言language、分类category、规则名rule name。对应 rule_tag.rb 中的解析正则/(?:(?:(\w)/)?(\w)/)?(\w)/由此可以归纳出三种合法的引用形式引用形式示例说明全限定引用{% rule java/bestpractices/AvoidPrintStackTrace %}语言、分类、规则名全部写出任何页面可用全限定引用无引号{% rule java/bestpractices/AvoidPrintStackTrace %}引号可省略语义相同同分类简写引用{% rule OtherRule %}仅写规则名语言与分类从当前页面推断简写引用是规则文档内部交叉引用的便利手段当某条规则的描述需要引用同一分类下的另一条规则时可以直接写{% rule 规则名 %}例如废弃规则的通知可以这样指向替代规则。引号在三种形式中都可以自由省略但必须成对出现详见下文错误模式。语言与分类的自动推断当标签内省略语言或分类段时插件会从当前页面的 permalink 推断。在 rule_tag.rb 中通过正则/pmd_rules_(\w)_(\w)\.html/匹配context[page.permalink]把捕获的语言与分类填入缺失的字段若最终仍缺失语言或分类例如在非规则分类页上使用简写引用插件会直接fail报错拒绝渲染。对于发布说明release notes的生成场景插件还支持通过is_release_notes_processor上下文开关为链接加上基于site.pmd.version的绝对 URL 前缀使发布说明中的链接指向对应版本号的文档快照。三、错误用法全景测试样例文档中的 12 种情况仓库中的 design.md 是RuleTagChecker的测试输入样例它刻意收录了规则引用标签的各类正确与错误写法是理解标签校验规则的活教材。逐一拆解如下3.1 正确的引用不应产生问题{% rule java/bestpractices/AvoidPrintStackTrace %} {% rule java/bestpractices/AvoidPrintStackTrace %}这两行分别以带引号、不带引号的形式全限定引用同仓库测试数据中存在的规则AvoidPrintStackTrace定义于 bestpractices.md检查器对它们不应报任何问题。同分类简写引用的两种合法写法同样被文档覆盖{% rule OtherRule %} !-- 正确无引号简写 -- {% rule OtherRule %} !-- 正确带引号简写 --注意测试数据中design.md所在分类java/design本身并没有名为OtherRule的规则因此这两行实际会被判定为规则不存在——这恰好演示了语法正确 ≠ 引用有效的区分语法上它们是合法标签但目标规则缺失仍会被报告。3.2 标签未正确闭合缺少 %}{% rule java/bestpractices/AvoidPrintStackTrace %)上例以右括号)代替了%}标签并未真正闭合。这类错误对应检查器输出的提示Rule tag for java/bestpractices/AvoidPrintStackTrace is not closed properly检查器在匹配到{% rule ...后会紧接检查行尾是否出现了%}若不存在则判定为未闭合。design.md第 25 行还专门构造了一个特殊场景——标签文本恰好结束在行末{% rule OtherRule该行是历史上曾触发StringIndexOutOfBoundsException的边界输入测试文件用注释明确标注了这一点用于验证检查器对越界访问的防护源码中通过pos 1 line.length()的判断在访问字符前先做长度检查见下文。3.3 引号不配对{% rule java/bestpractices/OtherRule %} {% rule java/bestpractices/OtherRule %} {% rule OtherRule %} {% rule OtherRule %}这四种写法的引号要么只有左引号、要么只有右引号属于missing quote错误检查器输出如下提示Rule tag for java/bestpractices/OtherRule has a missing quote Rule tag for java/bestpractices/OtherRule has a missing quote引号校验的规则是引号必须同时出现或同时缺席不能只出现一边。3.4 引用不存在的分类{% rule java/notexistingcategory/AvoidPrintStackTrace %}java/notexistingcategory这个分类并不存在测试数据中只有bestpractices、codestyle、design三个分类。检查器将尝试定位pmd/rules/java/notexistingcategory.md这一文档页面文件不存在时规则集视为空集从而报告Rule java/notexistingcategory/AvoidPrintStackTrace is not found3.5 引用不存在的规则{% rule java/bestpractices/NotExistingRule %} {% rule java/codestyle/NotExistingRule %}分类存在但规则名拼写错误或规则已被移除时目标页面虽然存在其##标题列表中却不包含被引用的规则名于是报告Rule java/bestpractices/NotExistingRule is not foundcodestyle.md测试页面还演示了简写形式引用不存在规则的等价场景codestyle.md{% rule NotExistingRule %} {% rule NotExistingRule %}四、RuleTagChecker构建期的自动校验器{% rule %}标签的引用是否有效由 RuleTagChecker.java 在文档构建期统一校验。该类的检查流程分四步4.1 逐文件扫描 Markdown 页面check()使用Files.walkFileTree递归遍历docs/pages目录下所有以.md结尾的文件RuleTagChecker.java对每个文件逐行调用checkFile。4.2 从文件路径推断语言与分类对于路径符合.../rules/语言/分类.md模式的文档页面检查器通过命名捕获组正则从文件名中提取语言与分类RuleTagChecker.java作为简写引用解析时的上下文。4.3 正则提取标签并做三类校验对每一行用RULE_TAG正则\{%\s*rule\s(?[^%\}\s]?)\s*提取规则引用RuleTagChecker.java随后依次执行三项检查RuleTagChecker.java闭合检查标签匹配结束后若pos 1 line.length()或行内紧邻的字符不是%}报告 not closed properly。这里的长度判断正是对行末截断场景即测试文档第 25 行的防御避免charAt越界引号配对检查引用以引号开头却未以引号结尾或相反报告 has a missing quote存在性检查调用ruleReferenceTargetExists验证引用目标是否真实存在。4.4 规则存在性的验证方式ruleReferenceTargetExistsRuleTagChecker.java先将引用解析为全限定形式匹配?(语言)/(分类)/(规则名)?的直接取三段匹配?(规则名)?的简写引用则用当前页面的语言与分类补全。随后定位目标文档docs/pages/pmd/rules/语言/分类.md从缓存rulesCache或文件中读取其全部##开头的标题作为规则名集合RuleTagChecker.java最后判断规则名是否存在于集合中。这解释了测试文档中分类不存在规则不存在两类错误的判定逻辑分类页面缺失时集合为空任何引用都判为不存在。[!TIP] 检查器是可以独立运行的命令行工具RuleTagChecker.main接受一个项目基目录参数RuleTagChecker.java发现任何问题都会打印到标准错误并抛出AssertionError使构建失败从而把死引用拦截在文档发布之前。五、测试驱动测试样例如何锁定检查行为校验器的预期行为由 RuleTagCheckerTest.java 用 Hamcrest 断言严格锁定。测试以src/test/resources/ruletagchecker为根目录运行check()将结果排序后与 13 条期望问题逐一比对例如pmd/rules/java/codestyle.md: 8: Rule NotExistingRule is not found pmd/rules/java/design.md: 9: Rule tag for java/bestpractices/AvoidPrintStackTrace is not closed properly pmd/rules/java/design.md:12: Rule java/notexistingcategory/AvoidPrintStackTrace is not found pmd/rules/java/design.md:16: Rule tag for java/bestpractices/OtherRule has a missing quote pmd/rules/java/design.md:25: Rule tag for OtherRule is not closed properly该断言列表与design.md、codestyle.md中的每一行测试输入一一对应构成了一组覆盖语法错误、引号错误、引用目标缺失、行末截断边界的回归测试矩阵。任何对RuleTagChecker检查逻辑的改动若改变了任一问题的判定结果测试都会立刻失败。测试数据目录ruletagchecker/docs/pages/pmd/rules/java/下共三个文件bestpractices.md、codestyle.md、design.md分别扮演被引用目标错误引用示例页错误引用示例页的角色这种将测试夹具fixture按规则分类组织的方式也便于后续扩展新的检查场景。六、与构建流程的集成6.1 Maven verify 阶段自动执行在 pmd-doc/pom.xml 的generate-rule-docsprofile 中exec-maven-plugin绑定了三个java执行项全部在verify阶段运行execution id主类职责generate-rule-docsGenerateRuleDocsCmd从 XML category 生成规则文档页面check-dead-linksDeadLinksChecker检查站内死链接check-rule-tagsRuleTagChecker校验{% rule %}标签引用也就是说运行如下命令即可在打包过程中同步完成规则文档生成与标签校验./mvnw package -Pgenerate-rule-docs -pl pmd-doc若文档中存在任何无效的{% rule %}引用verify阶段会直接失败阻止携带错误文档的构建产物产生。6.2 Jekyll 构建前的前置校验规则文档页面属于构建时生成的内容在全新的克隆仓库中并不存在。为避免 Jekyll 在缺少规则文档的情况下产出不完整站点docs/_plugins/hooks/check_rule_docs.rb 在:after_init钩子中扫描各语言模块的categoryXML 文件核对每个语言/分类对应的生成页面是否存在且不早于 XML 文件的修改时间缺失或过期即中止构建并提示先执行上述 Maven 命令可通过设置环境变量PMD_DOC_IGNORE_MISSING_RULE_DOC跳过此校验。该钩子中的categories_exceptions列表如html/design.md、scala/design.md等排除了不含规则、不生成文档的分类。两条机制共同保证了规则文档页面存在且其中的规则引用有效才允许发布。七、实践建议如何正确使用规则引用结合文档编写规范writing_documentation.md与校验器实现为规则作者和文档维护者总结如下要点规则描述改在 XML 里写规则文档页面由pmd-语言/src/main/resources/category/语言/下的 XML category 文件生成修改规则说明应直接编辑 XML 中rule的description可使用 CDATA 包裹 Markdown而不是修改生成后的 Markdown 页面跨分类引用用全限定形式{% rule java/bestpractices/AvoidPrintStackTrace %}写法在任何页面都有效是规则描述中引用他处规则的推荐方式同分类引用可用简写{% rule OtherRule %}仅适用于规则分类页内部且目标规则必须真实存在于该分类页面引号要么成对、要么省略xxx或xxx这类残缺引号会触发 missing quote 错误不要漏掉%}标签必须以%}正确闭合误写为%)等字符会被判定为 not closed properly发布前跑一遍校验本地执行./mvnw package -Pgenerate-rule-docs -pl pmd-doc让verify阶段的RuleTagChecker与DeadLinksChecker帮你提前拦截全部无效引用。结语{% rule %}标签是 PMD 文档体系中连接规则描述与规则文档页面的纽带。从 rule_tag.rb 的渲染实现到 RuleTagChecker.java 的构建期校验再到ruletagchecker测试样例与 RuleTagCheckerTest.java 的断言锁定整个机制形成了书写 → 渲染 → 校验 → 发布的完整闭环。理解这套机制既能帮助你在编写 PMD 规则文档时避免踩坑也能为其他 Jekyll/Liquid 文档体系设计标签 自动校验的工程质量方案提供参考。赞分享静态分析代码质量【免费下载链接】pmdAn extensible multilanguage static code analyzer.项目地址https://gitcode.com/gh_mirrors/pm/pmd点击查看免费下载相关推荐GrowthBook Mintlify 文档编写规范MDX Frontmatter YAML 引号规则与 CI 强制校验GrowthBook Mintlify 文档编写规范MDX Frontmatter YAML 引号规则与 CI 强制校验 GrowthBook 的官方文档以后端前端数据分析数据可视化Matterbridge与智能家居集成打造无缝连接的智能生活体验Matterbridge与智能家居集成打造无缝连接的智能生活体验 Matterbridge作为一款强大的智能家居桥接工具能够轻松连接不同品牌和协议的智能设备GameDevMind 文档命名规范全解编号体系、目录结构、标签字段与自动化校验GameDevMind 文档命名规范全解编号体系、目录结构、标签字段与自动化校验 本文以 GameDevMind最全面的游戏开发技术图谱仓库中的《文档命名文档教程知识库游戏开发创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
阅读完成 · 觉得有帮助?
咨询建站