eslint-plugin-unicorn 快照测试深度解析:prefer-dom-node-text-content 规则如何把.innerText改为.textContent
【免费下载链接】eslint-plugin-unicornMore than 300 powerful ESLint rules项目地址: https://gitcode.com/GitHub_Trending/es/eslint-plugin-unicorn
本篇技术指南以 eslint-plugin-unicorn 仓库中prefer-dom-node-text-content规则的 AVA 快照测试报告为主体,完整讲解该规则覆盖的 15 个违规场景、每个场景的错误定位与自动修复输出,并结合规则源码与测试用例剖析其检测原理(成员访问监听 + 解构模式监听 + 非 DOM 节点类型过滤)。读完本文,你将理解如何通过快照报告逆向读懂一条 ESLint 规则的完整行为边界,包括可选链、赋值、重命名解构、默认值与嵌套解构等边界情形。
快照报告是什么:规则行为的“逐帧录像”
test/snapshots/prefer-dom-node-text-content.js.md是一份由 AVA 测试框架自动生成的快照报告(Snapshot report),它忠实记录了test/prefer-dom-node-text-content.js中全部 15 个 invalid 用例的运行结果——包括输入代码、错误消息、定位列号以及编辑器可用的自动修复建议。真实的快照数据保存在同目录的prefer-dom-node-text-content.js.snap文件中,.md版本是其可读性更强的渲染副本。
报告头部给出了三条关键元信息:
- 被测文件:
test/prefer-dom-node-text-content.js,即规则的单测入口; - 快照本体:
prefer-dom-node-text-content.js.snap; - 生成工具:AVA(avajs.dev),ESLint 生态中常用的 Node.js 测试运行器。
每条用例在报告中以invalid(N): 代码的标题出现,随后依次展示> Input(输入源码与行号标注)和> Error 1/1(错误详情:消息文本、^定位以及Suggestion建议修复)。
规则核心:为什么必须用.textContent而不是.innerText
该规则的官方文档位于 docs/rules/prefer-dom-node-text-content.md,其宗旨是:对 DOM 节点强制使用.textContent而非.innerText。理由来自 MDN 对Node.textContent的说明:.textContent在性能上更优,且更新文本内容时行为更可预测(.innerText受 CSS 样式与排版影响,其读取结果可能因渲染状态而异)。规则同时提示,两者存在语义差异(例如.innerText会触发重排、只返回可见文本),在个别场景下不能直接等价替换。
规则元数据(见 rules/prefer-dom-node-text-content.js)显示:
type: 'suggestion':属于建议型规则,报告的问题是代码风格/可维护性问题而非确定性 bug;recommended: 'unopinionated':默认纳入unopinionated配置集(该文档标题旁的 ☑️ 标记);hasSuggestions: true:规则的修复以“编辑器建议(editor suggestions)”形式提供,需要开发者手动确认,而非自动应用;languages: ['js/js']:作用于 JavaScript 文件。
15 个违规用例全景:成员访问与解构两大阵营
快照报告完整呈现了规则能够捕获的全部 15 个违规场景。它们可以清晰地划分为两组:成员表达式(MemberExpression)访问与对象解构模式(ObjectPattern)中的属性键。
第一组:成员访问(用例 1–4)
| 用例 | 输入 | 修复建议 |
|---|---|---|
| 1 | node.innerText; | node.textContent; |
| 2 | node?.innerText; | node?.textContent; |
| 3 | node.innerText = 'foo'; | node.textContent = 'foo'; |
| 4 | innerText.innerText; | innerText.textContent; |
这组用例验证了规则对三种读取/写入形式的覆盖:
- 普通读取(用例 1):成员访问出现在表达式语句中,错误定位在
node.innerText的innerText部分(快照中以^^^^^^^^^标记,列号与属性名对齐); - 可选链读取(用例 2):
node?.innerText同样命中,修复保留?.前缀,只替换属性名; - 属性赋值(用例 3):
node.innerText = 'foo'的写入场景同样被拦截,修复后变为node.textContent = 'foo'; - 同名链式访问(用例 4):
innerText.innerText只报告内层innerText(对象上访问的属性),而不会把独立的innerText变量误判为违规——这与下方 valid 用例innerText.textContent相互印证,说明规则只关心属性访问,不关心标识符本身叫什么名字。
第二组:对象解构模式(用例 5–15)
解构场景是规则最精细的部分,快照覆盖了简写、带尾逗号、重命名、默认值、赋值模式、函数参数与嵌套解构的全部组合:
| 用例 | 输入 | 修复建议 |
|---|---|---|
| 5 | const {innerText} = node; | const {textContent: innerText} = node; |
| 6 | const {innerText,} = node; | const {textContent: innerText,} = node; |
| 7 | const {innerText: text} = node; | const {textContent: text} = node; |
| 8 | const {innerText = "default text"} = node; | const {textContent: innerText = "default text"} = node; |
| 9 | const {innerText: text = "default text"} = node; | const {textContent: text = "default text"} = node; |
| 10 | ({innerText} = node); | ({textContent: innerText} = node); |
| 11 | ({innerText: text} = node); | ({textContent: text} = node); |
| 12 | ({innerText = "default text"} = node); | ({textContent: innerText = "default text"} = node); |
| 13 | ({innerText: text = "default text"} = node); | ({textContent: text = "default text"} = node); |
| 14 | function foo({innerText}) {return innerText} | function foo({textContent: innerText}) {return innerText} |
| 15 | for (const [{innerText}] of elements); | for (const [{textContent: innerText}] of elements); |
从快照中可以提炼出修复策略的规律:
- 简写属性必须展开:
{innerText}这种简写形式无法直接改名(否则局部变量名会丢失),因此修复为{textContent: innerText}——保留原变量名,只把“来源键”改为textContent; - 已重命名的属性只换键名:
{innerText: text}修复为{textContent: text},{innerText: text = "default text"}修复为{textContent: text = "default text"},默认值"default text"原样保留; - 赋值模式同样命中:用例 10–13 展示了解构赋值语句
({innerText} = node)的四种变体,修复逻辑与变量声明一致; - 函数参数与嵌套解构不遗漏:用例 14(函数形参)和用例 15(
for...of中的嵌套数组解构[{innerText}])表明,无论解构嵌套多深、出现在什么位置,只要对象模式中的属性键是innerText,都会被规则捕获。
规则源码如何实现这些检测
两条监听路径
规则注册了两个独立的 AST 监听器(见 rules/prefer-dom-node-text-content.js):
MemberExpression监听器(第 32–54 行):负责捕获node.innerText形式的成员访问。它使用仓库自带的 AST 工具isMemberExpression精确匹配property: 'innerText'。该工具位于 rules/ast/is-member-expression.js,支持对property、computed、optional等维度做约束匹配;当只传property时,computed默认被约束为false——这正是测试中node['innerText'](字符串计算属性)和node[innerText](变量计算属性)被视为 valid 的原因。Identifier监听器(第 56–86 行):负责捕获解构模式中的innerText键。它有一组严格的父链校验条件:节点必须名为innerText、是Property的key(非计算属性)、kind为init、且外层是ObjectPattern。这条链路保证了const foo = {innerText}(普通对象字面量)、const {[innerText]: text} = node(计算键)等场景不会被误报。
非 DOM 节点的类型过滤
两条监听路径在报告错误前,都调用isKnownNonDomNode(来自 rules/utils/is-dom-node.js)做反向排除:如果能够推断出对象不是DOM 节点,就直接放行。这样避免了把接口/普通对象上的同名属性误报为违规。
is-dom-node.js基于通用类型推断引擎createTypeCheckers(见 rules/utils/type-helpers.js)构建,将CharacterData、Document、DocumentFragment、Element、HTMLElement、Node、SVGElement、Text视为 DOM 节点类型名集合,通过变量定义追踪、类型注解、导入绑定等途径推断表达式类型。prefer-dom-node-text-content.js中还额外实现了isKnownNonDomObjectPattern(第 11–26 行),专门为解构模式追查其初始化器(VariableDeclarator.init)或赋值右侧(AssignmentExpression.right)是否确认为非 DOM 节点。
建议型修复(Suggestion)
两处监听器都返回messageId: 'error'与suggest数组,其中唯一的建议项messageId: 'suggestion'提供修复函数:
- 成员访问路径直接
fixer.replaceText(node, 'textContent')(第 50 行); - 解构路径则需要区分简写与否:简写时替换为
'textContent: innerText',非简写时只替换键名(第 79–82 行)。
这与快照中每条用例末尾的Suggestion 1/1输出一一对应。
不误报的边界:valid 用例对照
快照报告只收录 invalid 用例,但 test/prefer-dom-node-text-content.js 中的 valid 列表同样关键,它划定了规则“不该管”的边界:
- 裸标识符:
innerText;、innerText = true;、innerText.textContent——innerText作为普通变量名出现时不触发; - 计算属性访问:
node[innerText];、node['innerText'];——计算成员表达式不匹配property: 'innerText'且computed: false的约束; - 数组解构:
const [innerText] = node;、[innerText] = node;——规则只针对对象解构; - 对象字面量:
const foo = {innerText}、const foo = {innerText: text}——字面量属性定义不属于对象解构模式; - TypeScript 接口场景:当
innerText是接口Value的字段时,value.innerText、const {innerText} = value、函数参数解构均不报告——这正是isKnownNonDomNode类型过滤在起作用(接口类型不在 DOM 节点类型名集合中)。
如何查看与运行这套测试
若想在本仓库中复现快照结果,可以执行:
npx ava test/prefer-dom-node-text-content.js新增或修改用例后,快照会因输出变化而失败,此时可配合 AVA 的快照更新机制重新生成.snap与.md文件(仓库文档 docs/write-tests.md 说明了规则测试的编写约定)。阅读快照时建议三份文件对照:test/prefer-dom-node-text-content.js.md(可读报告)、同目录的.snap(机器快照)与 rules/prefer-dom-node-text-content.js(规则实现),即可完整还原从输入代码到错误输出、再到修复建议的全链路行为。
小结
通过这份快照报告,我们可以得出prefer-dom-node-text-content规则的完整行为模型:它捕获 DOM 节点上的.innerText成员访问(含读取、赋值、可选链)与对象解构中的innerText键(含重命名、默认值、赋值模式、函数参数与嵌套解构),统一建议改为.textContent,同时借助类型推断机制精确排除接口、普通对象等非 DOM 场景,避免误报。这种“快照报告 + 测试用例 + 源码实现”三合一的阅读方式,同样适用于该仓库 test/snapshots 下其他 300+ 条规则的测试理解。
【免费下载链接】eslint-plugin-unicornMore than 300 powerful ESLint rules项目地址: https://gitcode.com/GitHub_Trending/es/eslint-plugin-unicorn
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考