不能只用正则匹配HTML标签,因为HTML不是正则友好型语言,嵌套结构、属性顺序、换行、注释、自闭合标签及模板字符串等会导致正则失效,而AST能准确解析语义结构并支持上下文感知的规则校验。

为什么不能只用正则匹配 HTML 标签
HTML 不是正则友好型语言,嵌套、属性顺序、换行、注释、自闭合标签等都会让 pattern 失效。比如 <img src="x" alt=""> 和 <img\n alt=""\n src="x"> 在 AST 层面结构一致,但正则很难稳定覆盖。更麻烦的是,<div><p></p></div> 这类嵌套结构,正则根本无法判断闭合层级是否匹配。
实际踩坑场景包括:
- 误报:把合法的 JSX 或模板字符串(如
`<div class="${cls}">`)当成真实 HTML 检查 - 漏报:忽略
<input type="hidden">中缺失name属性的问题,因为正则没解析属性树 - 维护成本高:每新增一种写法(如 Pug、Vue SFC 中的 HTML 片段),就得补一堆正则变体
如何用 AST 定义一条“必须带 aria-label 的 icon 按钮”规则
关键不是写个匹配 <button> 的表达式,而是识别语义节点及其上下文。以主流 HTML 解析器(如 parse5 或 htmlparser2)输出的 AST 为例,这条规则需同时满足:
-
node.type === 'tag'且node.tagName === 'button' -
node.children中存在一个img或svg子节点(即图标) -
node.attribs中不含aria-label,且未通过title或其他 ARIA 属性间接提供文本替代
示例伪代码逻辑:
立即学习“前端免费学习笔记(深入)”;
function checkButtonWithIcon(ast) {
const violations = [];
traverse(ast, (node) => {
if (node.type === 'tag' && node.tagName === 'button') {
const hasIcon = node.children.some(c =>
c.type === 'tag' && ['img', 'svg'].includes(c.tagName)
);
const hasAriaLabel = node.attribs?.['aria-label'];
if (hasIcon && !hasAriaLabel) {
violations.push({ line: node.sourceCodeLocation?.startLine, message: 'icon button missing aria-label' });
}
}
});
return violations;
}
团队规则怎么避免“越写越重”
AST 规则容易陷入两个极端:要么太细(每种组件都单独写一条),要么太泛(一条规则覆盖所有交互元素)。真正可持续的做法是分层抽象:
- 基础层:复用通用 AST 节点断言,如
hasAttribute(node, 'aria-label')、isSelfClosingTag(node) - 业务层:组合基础断言,定义语义单元,如
isIconButton(node)、isFormInput(node) - 策略层:按团队规范绑定行为,如 “所有
isIconButton必须hasAriaLabel”,而非硬编码 tag 名
这样当设计系统升级图标按钮组件时,只需调整 isIconButton 的判定逻辑,所有依赖它的规则自动生效,不用逐条改。
CI 中跑 HTML AST 规则要注意什么
HTML AST 解析比 JS/TS 慢得多,尤其含大量内联脚本或模板字符串时。常见问题包括:
- 超时:默认 30s 超时可能不够,建议为 HTML 检查单独设
timeout: 120s - 内存溢出:解析未压缩的 HTML 文件(如构建产物中的
index.html)易 OOM,应限定检查范围为src/**/*.html或components/**/*.{html,tsx} - 误判框架模板:Vue/Svelte 的
<template>或 React 的 JSX 不该走 HTML AST 流程,需在入口过滤掉非纯 HTML 文件
推荐做法:用 glob 显式声明检查路径,配合 ignore 排除 node_modules/、dist/ 和框架专属目录(如 **/*.vue)。
最常被忽略的一点是:HTML AST 规则的错误定位精度严重依赖解析器是否保留源码位置信息。如果用的 parse5 没开启 sourceCodeLocationInfo: true,所有 line 字段都是 undefined,CI 报告就只剩“某文件有违规”,开发体验大打折扣。



















