ESLint no-warning-comments 规则详解:用注释规范拦截 TODO、FIXME 与 XXX
【免费下载链接】eslintFind and fix problems in your JavaScript code.项目地址: https://gitcode.com/GitHub_Trending/es/eslint
本篇技术指南以 ESLint 内置规则no-warning-comments为核心,讲解如何通过配置terms、location、decoration三个选项,在代码评审与发布前自动拦截注释中遗留的 TODO、FIXME、XXX 等警示性词汇,并结合仓库源码与测试用例深入剖析其匹配原理(大小写不敏感、整词匹配、装饰字符跳过等),帮助你在实际项目中快速落地这一"注释卫生"检查。
为什么需要禁用警示性注释
开发者在编写尚未完成或需要复查的代码时,常常会随手留下注释作为标记。最常见的形式如下:
// TODO: do something // FIXME: this is not a good idea这些注释的本意是提醒"这块代码还没有就绪、还需要复查",但问题在于:它们很容易被遗忘。代码进入生产环境时,这些 TODO/FIXME 往往仍然残留在源码中,既不美观,也容易掩盖真正的问题。no-warning-comments规则的作用,就是把这些警示性词汇当作"定时炸弹"来排查——只要注释中出现了配置的词汇,ESLint 就立即报告错误,促使开发者在代码达到生产就绪状态前,要么修复代码、要么删除注释。
该规则在 lib/rules/no-warning-comments.js 中实现,其规则类型为suggestion(建议型规则),默认不包含在 recommended 配置中,需要显式开启(见 docs/src/_data/rules.json)。
Rule Details:规则如何工作
简单来说,这条规则会检查源码中的全部注释,凡是注释内容中包含配置项里指定的任一词汇(term),就会产生一条违规报告。它遍历注释节点的方式非常直接——在Program()节点事件中取出所有注释,过滤掉 Shebang 后逐一检查:
Program() { const comments = sourceCode.getAllComments(); comments .filter(token => token.type !== "Shebang") .forEach(checkComment); }其中checkComment会调用commentContainsWarningTerm对注释内容逐一进行正则测试,命中的每个词汇都会触发一条报告,消息模板为:
Unexpected '{{matchedTerm}}' comment: '{{comment}}'.一个值得注意的细节是:规则会豁免 ESLint 自身的指令注释(如/* eslint no-warning-comments: "error" */)。源码中通过astUtils.isDirectiveComment(node)与/\bno-warning-comments\b/u正则双重判断,只有当注释本身就是配置本规则的指令时才跳过,否则即使是/* eslint one-var: 2 */这类其他规则指令,只要其内容命中了配置的词汇(例如将eslint或one加入 terms),依然会被报告(参见 tests/lib/rules/no-warning-comments.js 中的对应测试)。isDirectiveComment的实现位于 lib/rules/utils/ast-utils.js。
Options:三个配置项详解
该规则接受一个对象字面量配置,共三个选项:
| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
terms | string[] | ["todo", "fixme", "xxx"] | 要匹配的警示词汇列表 |
location | string | "start" | 匹配位置,可选"start"(注释起始处)或"anywhere"(注释任意位置) |
decoration | string[] | [] | 当location为"start"时,注释起始处会被忽略的装饰字符 |
terms:自定义警示词汇
terms是可选的词汇数组,默认值为["todo", "fixme", "xxx"]。匹配规则有两条关键约束:
- 大小写不敏感:
fix既能匹配FIX,也能匹配fIxMe这类混合大小写写法。测试用例中专门验证了// any fIxMe、/* any FIXME */均会命中(见 tests/lib/rules/no-warning-comments.js); - 整词匹配(word boundary):
fix可以匹配FIX,但不会匹配fixing或affix这类包含该词作为子串的单词。
词汇还支持由多个单词组成,例如配置"really bad idea"就可以匹配包含这一整句的注释。
location:匹配位置
location默认值为"start",即只检查注释的起始位置。这里的"起始"指的是跳过空白、换行以及decoration中指定的字符之后的第一处内容。另一个可选值是"anywhere",此时会在注释的任意位置查找词汇。
decoration:起始装饰字符
decoration默认为[],仅在location: "start"时生效。许多开发者喜欢用连续的星号、斜杠等字符美化注释(如/***** TODO ... *****/或 JSDoc 风格的多行注释/** ... */),这些"装饰性"字符如果不忽略,会干扰start位置对词汇的识别。配置decoration后,注释起始处的任意空白序列与这些字符都会被跳过。当location为"anywhere"时,此选项会被忽略。
默认配置下的代码示例
以下代码演示了默认配置{ "terms": ["todo", "fixme", "xxx"], "location": "start" }的行为。
不正确的代码示例(应当被报告):
/*eslint no-warning-comments: "error"*/ /* FIXME */ function callback(err, results) { if (err) { console.error(err); return; } // TODO }上面的多行注释以FIXME开头、行注释以TODO开头,两处都会命中默认词汇,因此都被判为错误。
正确的代码示例(应当通过检查):
/*eslint no-warning-comments: "error"*/ function callback(err, results) { if (err) { console.error(err); return; } // NOT READY FOR PRIME TIME // but too bad, it is not a predefined warning term }这里NOT READY FOR PRIME TIME并不在默认的terms列表中,且默认location: "start"模式下,位于注释中段的内容本来也不会被检查,因此代码通过检查。
组合 terms 与 location:匹配任意位置
将terms与location: "anywhere"组合,可以做到在注释全文中查找警示词汇,适合对注释质量要求更严格的团队。
不正确的代码示例,配置为{ "terms": ["todo", "fixme", "any other term"], "location": "anywhere" }:
/*eslint no-warning-comments: ["error", { "terms": ["todo", "fixme", "any other term"], "location": "anywhere" }]*/ // TODO: this // todo: this too // Even this: TODO /* * The same goes for this TODO comment * Or a fixme * as well as any other term */// TODO: this与// todo: this too中的词汇位于注释开头,// Even this: TODO中的词汇位于注释末尾,多行块注释中的TODO、fixme、any other term分布在正文各处——由于anywhere模式会在任意位置查找,以上全部会被报告。
正确的代码示例,同样的配置:
/*eslint no-warning-comments: ["error", { "terms": ["todo", "fixme", "any other term"], "location": "anywhere" }]*/ // This is to do // even not any other term // any other terminal /* * The same goes for block comments * with any other interesting term * or fix me this */这里的关键在于整词匹配的边界行为:
to do中间有空格,不是一个完整词,不会命中todo;any other term中间的空格序列被正则压缩处理(源码中以/\s+/u折叠空白),但term与any other之间被空白隔开,并非连续的any other term,因此不命中;any other terminal中any other后面紧跟terminal而不是term,整词边界使term无法命中;fix me this中fix与me被空格分隔,不是fixme;- 注意:
location: "anywhere"模式下decoration选项会被忽略。
Decoration Characters:处理装饰字符
当location为默认的"start"时,decoration可以指定一组在注释起始处被忽略的字符。
不正确的代码示例,配置为{ "decoration": ["*"] }:
/*eslint no-warning-comments: ["error", { "decoration": ["*"] }]*/ //***** todo decorative asterisks are ignored *****// /** * TODO new lines and asterisks are also ignored in block comments. */第一条注释虽然以//*****开头,但星号作为装饰字符被忽略,后面的todo依然会被定位到注释"起始处";第二条块注释起始处的换行、星号同样被跳过,TODO仍然命中。
不正确的代码示例,配置为{ "decoration": ["/", "*"] }:
/*eslint no-warning-comments: ["error", { "decoration": ["/", "*"] }]*/ ////// TODO decorative slashes and whitespace are ignored ////// //***** todo decorative asterisks are also ignored *****// /** * TODO new lines are also ignored in block comments. */当同时把/与*加入decoration后,//////这类斜杠装饰、*****这类星号装饰以及换行都会被忽略,注释"起始"处的词汇照样命中。
正确的代码示例,配置为{ "decoration": ["/", "*"] }:
/*eslint no-warning-comments: ["error", { "decoration": ["/", "*"] }]*/ //!TODO preceded by non-decoration character /** *!TODO preceded by non-decoration character in a block comment */!不在decoration列表中,也不是空白字符,因此它无法被跳过,导致TODO不再位于"起始处",两条注释都不会被报告。这正是decoration机制的边界所在:起始处只能被空白与显式声明的装饰字符跳过。
源码级原理:正则如何生成
为了深入理解上述行为,我们来看规则核心的convertToRegExp函数(见 lib/rules/no-warning-comments.js)。每个配置的词汇都会被转成一个正则:
location: "start"时,前缀为^[\s<decoration字符>]*,即允许起始处出现任意空白与装饰字符,然后紧跟转义后的词汇本体;location: "anywhere"时,若词汇以单词字符开头,则前缀为\b(词边界);若以单词字符结尾,则后缀为\b;- 正则标志固定为
iu——i提供大小写不敏感,u提供 Unicode 大小写折叠,这正是fIxMe、FIX都能被识别的原因; - 词汇中的正则特殊字符会先经
escape-string-regexp转义,因此把[litera|$]、[aeiou]这类含特殊字符的字符串当作词汇也完全安全(测试见 tests/lib/rules/no-warning-comments.js 与 tests/lib/rules/no-warning-comments.js)。
例如默认配置下TODO的匹配正则形如/^[\s]*todo\b/iu;配置decoration: ["*"]后则变为/^[\s\*]*todo\b/iu。
另外,报告消息中的注释内容有一个 40 字符的展示上限(源码常量CHAR_LIMIT = 40):报告时会按空白分词拼接注释文本,超过 40 个字符的部分用...省略。这在超长或含多行内容的注释上体现得很明显,例如测试中// TODO: something really longer than 40 characters的报告内容被截断为"TODO: something really longer than 40...",超长 URL 注释甚至直接显示为"..."(见 tests/lib/rules/no-warning-comments.js)。
如何开启该规则
由于该规则不在eslint:recommended中,需要手动在配置文件里开启。在 flat config(新版 ESLint 默认)中:
// eslint.config.js export default [ { rules: { "no-warning-comments": "error", // 自定义配置示例 "no-warning-comments": ["error", { "terms": ["todo", "fixme", "xxx", "hack"], "location": "start", "decoration": ["*", "/"] }] } } ];在旧的 eslintrc 风格配置中:
{ "rules": { "no-warning-comments": ["error", { "terms": ["todo", "fixme", "xxx"], "location": "anywhere" }] } }严重级别同样支持"warn"与"error"。该规则的schema校验(见 lib/rules/no-warning-comments.js)还约束了:location只能是"start"或"anywhere";decoration中每个字符必须是单个非空白字符(pattern: "^\\S$")、至少 1 项且不能重复。需要特别注意的是,由于decoration的minItems: 1约束,传空数组[]会被判定为配置非法,不配置该选项时应直接省略。
When Not To Use It:何时不该用
no-warning-comments并非放之四海而皆准,文档明确给出了两类"不适用"场景:
- 历史包袱过重的大型代码库:如果代码库在开发时没有"禁止使用警示词汇"的约定,历史遗留的 TODO/FIXME 可能多达数百条。此时一次性开启会产生海量警告/错误,如果你没有时间全部修复,反而会掩盖其他更有价值的警告,或让人对警告"脱敏"、不再关注。
- 词汇本身过于常用:同理,不要把注释语言里高频出现的词汇配置进
terms。例如中文注释里常见的"待办""问题"等泛化词,或与业务领域强相关、必然反复出现的词,配置进去只会导致噪音。
建议的落地方式是从"warn"级别开始,配合location: "start"与保守的terms列表逐步推行,待存量注释清理完毕后再升级为"error"。
小结
no-warning-comments用一套极其轻量的正则机制,把"注释卫生"纳入自动化检查管线:默认拦截todo/fixme/xxx,支持大小写不敏感与整词匹配,支持在start/anywhere两种位置检查,并可用decoration优雅处理各种装饰性注释风格。配合源码中 lib/rules/no-warning-comments.js 的正则生成逻辑与 tests/lib/rules/no-warning-comments.js 中 600 余行的完整测试用例,你可以精准预测它对任何注释的判定结果,将其作为代码评审前的一道自动防线。
【免费下载链接】eslintFind and fix problems in your JavaScript code.项目地址: https://gitcode.com/GitHub_Trending/es/eslint
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考