news 2026/9/11 23:59:01

ESLint lines-around-comment 规则详解:强制注释前后空行以提升代码可读性

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ESLint lines-around-comment 规则详解:强制注释前后空行以提升代码可读性

ESLint lines-around-comment 规则详解:强制注释前后空行以提升代码可读性

【免费下载链接】eslintFind and fix problems in your JavaScript code.项目地址: https://gitcode.com/GitHub_Trending/es/eslint

lines-around-comment是 ESLint 内置的布局(layout)类规则,用于强制在块注释(/* */)与行注释(//)的前后保留空行,使注释与代码在视觉上清晰分层。本文以 规则文档 为核心,结合 规则源码 与 规则测试,系统讲解该规则的全部 15 个可配置项、默认值、判定逻辑与源码实现,帮助你精确控制注释周围的空行格式。

Rule Details:规则做了什么

许多团队风格指南要求在注释前后保留空行,本规则的目标正是让注释更易读、提升代码可读性。具体来说,规则要求:

  • 在块注释(/* ... */)和/或行注释(// ...之前或之后保留空行;
  • beforeBlockCommentafterBlockComment分别控制块注释前后的空行,beforeLineCommentafterLineComment分别控制行注释前后的空行,两类注释互不影响,可按需单独启用;
  • 不检查与代码同行出现的注释(如foo(); // 行尾注释),也不要求文件开头或结尾出现空行。

从源码看,规则在Program节点上遍历sourceCode.getAllComments()获取的所有注释 token,并按token.type分流处理:lib/rules/lines-around-comment.js#L546-L579 中,"Line"类型走beforeLineComment/afterLineComment逻辑,"Block"类型走beforeBlockComment/afterBlockComment逻辑,"Shebang"类型(即#!注释)则仅在启用afterHashbangComment时处理。

Options:完整的可配置项

本规则接受一个对象选项,下表汇总了所有参数、默认值与作用(与源码 schema 定义 完全一致):

选项类型默认值说明
beforeBlockCommentbooleantrue要求块注释前有空行
afterBlockCommentbooleanfalse要求块注释后有空行
beforeLineCommentbooleanfalse要求行注释前有空行
afterLineCommentbooleanfalse要求行注释后有空行
allowBlockStartbooleanfalse允许注释出现在块语句、函数体、类、switch 语句及类静态块(static block)的起始位置
allowBlockEndbooleanfalse允许注释出现在上述块结构(块语句、函数体、类、switch、类静态块)的结尾位置
allowObjectStartbooleanfalse允许注释出现在对象字面量(含解构模式)的起始位置
allowObjectEndbooleanfalse允许注释出现在对象字面量(含解构模式)的结尾位置
allowArrayStartbooleanfalse允许注释出现在数组字面量(含解构模式)的起始位置
allowArrayEndbooleanfalse允许注释出现在数组字面量(含解构模式)的结尾位置
allowClassStartbooleanfalse允许注释出现在类的起始位置(未设置时沿用allowBlockStart的行为)
allowClassEndbooleanfalse允许注释出现在类的结尾位置(未设置时沿用allowBlockEnd的行为)
ignorePatternstring自定义被规则忽略的注释正则模式
applyDefaultIgnorePatternsbooleantrue是否应用默认忽略模式
afterHashbangCommentbooleanfalse要求 hashbang 注释(#!...)后有空行

注意:beforeBlockComment的默认值true是通过源码显式兜底实现的——lib/rules/lines-around-comment.js#L164-L167 中,当该项为undefined时会被赋值为true;其余三个before*/after*开关默认关闭。allowClassStartallowClassEnd比较特殊:schema 中未声明默认值,其生效逻辑与allowBlockStart/allowBlockEnd联动(详见下文"类边界判定")。

配置示例(eslint.config.js的 rules 字段):

export default [ { rules: { "lines-around-comment": ["error", { beforeBlockComment: true, afterBlockComment: true, beforeLineComment: true, afterLineComment: false, allowBlockStart: true, allowObjectStart: true, applyDefaultIgnorePatterns: false, ignorePattern: "pragma", afterHashbangComment: true }] } } ];

该规则的报告消息只有两种(源码 messages 定义):Expected line before comment.(注释前缺少空行)与Expected line after comment.(注释后缺少空行)。

beforeBlockComment:块注释前必须空行

默认{ "beforeBlockComment": true }下,不正确的代码——块注释紧跟在上一条语句之后:

/*eslint lines-around-comment: ["error", { "beforeBlockComment": true }]*/ var night = "long"; /* what a great and wonderful day */ var day = "great"

正确的代码——块注释前保留一个空行:

/*eslint lines-around-comment: ["error", { "beforeBlockComment": true }]*/ var night = "long"; /* what a great and wonderful day */ var day = "great"

afterBlockComment:块注释后必须空行

启用{ "afterBlockComment": true }后,不正确的代码——块注释之后直接跟代码:

/*eslint lines-around-comment: ["error", { "afterBlockComment": true }]*/ var night = "long"; /* what a great and wonderful day */ var day = "great"

正确的代码——块注释前后都有空行:

/*eslint lines-around-comment: ["error", { "afterBlockComment": true }]*/ var night = "long"; /* what a great and wonderful day */ var day = "great"

beforeLineComment:行注释前必须空行

启用{ "beforeLineComment": true }后,不正确的代码:

/*eslint lines-around-comment: ["error", { "beforeLineComment": true }]*/ var night = "long"; // what a great and wonderful day var day = "great"

正确的代码:

/*eslint lines-around-comment: ["error", { "beforeLineComment": true }]*/ var night = "long"; // what a great and wonderful day var day = "great"

afterLineComment:行注释后必须空行

启用{ "afterLineComment": true }后,不正确的代码:

/*eslint lines-around-comment: ["error", { "afterLineComment": true }]*/ var night = "long"; // what a great and wonderful day var day = "great"

正确的代码:

/*eslint lines-around-comment: ["error", { "afterLineComment": true }]*/ var night = "long"; // what a great and wonderful day var day = "great"

allowBlockStart / allowBlockEnd:块结构边界的注释放行

当同时启用beforeLineComment/afterLineCommentbeforeBlockComment/afterBlockComment时,处于"块的开头或结尾"的注释往往不需要额外的空行(空行已由花括号分隔)。allowBlockStartallowBlockEnd正是为此设计,覆盖的函数体、if块、class体、switch语句与类静态块(static { })。

{ "beforeLineComment": true, "allowBlockStart": true }正确的代码:

/*eslint lines-around-comment: ["error", { "beforeLineComment": true, "allowBlockStart": true }]*/ function foo(){ // what a great and wonderful day var day = "great" return day; } if (bar) { // what a great and wonderful day foo(); } class C { // what a great and wonderful day method() { // what a great and wonderful day foo(); } static { // what a great and wonderful day foo(); } }

{ "beforeBlockComment": true, "allowBlockStart": true }正确的代码(含switch):

/*eslint lines-around-comment: ["error", { "beforeBlockComment": true, "allowBlockStart": true }]*/ function foo(){ /* what a great and wonderful day */ var day = "great" return day; } if (bar) { /* what a great and wonderful day */ foo(); } class C { /* what a great and wonderful day */ method() { /* what a great and wonderful day */ foo(); } static { /* what a great and wonderful day */ foo(); } } switch (foo) { /* what a great and wonderful day */ case 1: bar(); break; }

{ "afterLineComment": true, "allowBlockEnd": true }正确的代码:

/*eslint lines-around-comment: ["error", { "afterLineComment": true, "allowBlockEnd": true }]*/ function foo(){ var day = "great" return day; // what a great and wonderful day } if (bar) { foo(); // what a great and wonderful day } class C { method() { foo(); // what a great and wonderful day } static { foo(); // what a great and wonderful day } // what a great and wonderful day }

{ "afterBlockComment": true, "allowBlockEnd": true }正确的代码(含switch):

/*eslint lines-around-comment: ["error", { "afterBlockComment": true, "allowBlockEnd": true }]*/ function foo(){ var day = "great" return day; /* what a great and wonderful day */ } if (bar) { foo(); /* what a great and wonderful day */ } class C { method() { foo(); /* what a great and wonderful day */ } static { foo(); /* what a great and wonderful day */ } /* what a great and wonderful day */ } switch (foo) { case 1: bar(); break; /* what a great and wonderful day */ }

源码:块边界的判定方式

allowBlockStart/allowBlockEnd的判定由 isCommentAtBlockStart 与 isCommentAtBlockEnd 完成,二者分别委托isCommentAtParentStart/isCommentAtParentEnd,覆盖ClassBodyBlockStatementStaticBlockSwitchCaseSwitchStatement五种父节点类型:

  • 块起始:注释所在行与父节点"起始 token"所在行相差 1(token.loc.start.line - parentStartNodeOrToken.loc.start.line === 1)才判定为块开头;
  • 块结尾:父节点结束行与注释结束行相差 1(parent.loc.end.line - token.loc.end.line === 1)才判定为块结尾。

对于StaticBlockSwitchStatement有特殊处理:getParentNodeOfToken 中,StaticBlock只把花括号内的注释视为静态块的一部分(static\n// comment\n{ }中花括号外的注释返回null);SwitchStatement的起始 token 取判别表达式之后的左花括号,因此注释必须出现在switch (x) {的左花括号之后才算块开头。测试用例 tests/lib/rules/lines-around-comment.js#L2776-L2814 专门验证了"位于switch判别式括号内的注释不会被allowBlockStart放行"这一边界行为。

allowClassStart / allowClassEnd:类边界的精细控制

allowClassStartallowClassEnd单独控制类体ClassBody)的起始与结尾,且优先级高于块开关:当显式设为false时,会覆盖allowBlockStart/allowBlockEnd对类体的放行(见源码 checkForEmptyLine 中blockStartAllowed/blockEndAllowed的组合条件)。

{ "beforeLineComment": true, "allowClassStart": false }不正确的代码:

/*eslint lines-around-comment: ["error", { "beforeLineComment": true, "allowClassStart": false }]*/ class foo { // what a great and wonderful day day() {} };

{ "beforeLineComment": true, "allowClassStart": false }正确的代码:

/*eslint lines-around-comment: ["error", { "beforeLineComment": true, "allowClassStart": false }]*/ class foo { // what a great and wonderful day day() {} };

{ "beforeLineComment": true, "allowClassStart": true }正确的代码:

/*eslint lines-around-comment: ["error", { "beforeLineComment": true, "allowClassStart": true }]*/ class foo { // what a great and wonderful day day() {} };

同样,块注释下{ "beforeBlockComment": true, "allowClassStart": false }不正确

/*eslint lines-around-comment: ["error", { "beforeBlockComment": true, "allowClassStart": false }]*/ class foo { /* what a great and wonderful day */ day() {} };

{ "beforeBlockComment": true, "allowClassStart": false }正确

/*eslint lines-around-comment: ["error", { "beforeBlockComment": true, "allowClassStart": false }]*/ class foo { /* what a great and wonderful day */ day() {} };

{ "beforeBlockComment": true, "allowClassStart": true }正确

/*eslint lines-around-comment: ["error", { "beforeBlockComment": true, "allowClassStart": true }]*/ class foo { /* what a great and wonderful day */ day() {} };

{ "afterLineComment": true, "allowClassEnd": true }正确的代码:

/*eslint lines-around-comment: ["error", { "afterLineComment": true, "allowClassEnd": true }]*/ class foo { day() {} // what a great and wonderful day };

{ "afterBlockComment": true, "allowClassEnd": true }正确的代码:

/*eslint lines-around-comment: ["error", { "afterBlockComment": true, "allowClassEnd": true }]*/ class foo { day() {} /* what a great and wonderful day */ };

allowObjectStart / allowObjectEnd:对象字面量边界

对象相关的放行同时覆盖对象字面量ObjectExpression与对象解构模式ObjectPattern(见 isCommentAtObjectStart 与 isCommentAtObjectEnd),因此对象解构const { ... } = ...中的注释同样受控。

{ "beforeLineComment": true, "allowObjectStart": true }正确的代码:

/*eslint lines-around-comment: ["error", { "beforeLineComment": true, "allowObjectStart": true }]*/ var foo = { // what a great and wonderful day day: "great" }; const { // what a great and wonderful day foo: someDay } = {foo: "great"}; const { // what a great and wonderful day day } = {day: "great"};

{ "beforeBlockComment": true, "allowObjectStart": true }正确的代码:

/*eslint lines-around-comment: ["error", { "beforeBlockComment": true, "allowObjectStart": true }]*/ var foo = { /* what a great and wonderful day */ day: "great" }; const { /* what a great and wonderful day */ foo: someDay } = {foo: "great"}; const { /* what a great and wonderful day */ day } = {day: "great"};

{ "afterLineComment": true, "allowObjectEnd": true }正确的代码:

/*eslint lines-around-comment: ["error", { "afterLineComment": true, "allowObjectEnd": true }]*/ var foo = { day: "great" // what a great and wonderful day }; const { foo: someDay // what a great and wonderful day } = {foo: "great"}; const { day // what a great and wonderful day } = {day: "great"};

{ "afterBlockComment": true, "allowObjectEnd": true }正确的代码:

/*eslint lines-around-comment: ["error", { "afterBlockComment": true, "allowObjectEnd": true }]*/ var foo = { day: "great" /* what a great and wonderful day */ }; const { foo: someDay /* what a great and wonderful day */ } = {foo: "great"}; const { day /* what a great and wonderful day */ } = {day: "great"};

allowArrayStart / allowArrayEnd:数组字面量边界

数组相关放行同时覆盖数组字面量ArrayExpression与数组解构模式ArrayPattern(见 isCommentAtArrayStart 与 isCommentAtArrayEnd)。

{ "beforeLineComment": true, "allowArrayStart": true }正确的代码:

/*eslint lines-around-comment: ["error", { "beforeLineComment": true, "allowArrayStart": true }]*/ var day = [ // what a great and wonderful day "great", "wonderful" ]; const [ // what a great and wonderful day someDay ] = ["great", "not great"];

{ "beforeBlockComment": true, "allowArrayStart": true }正确的代码:

/*eslint lines-around-comment: ["error", { "beforeBlockComment": true, "allowArrayStart": true }]*/ var day = [ /* what a great and wonderful day */ "great", "wonderful" ]; const [ /* what a great and wonderful day */ someDay ] = ["great", "not great"];

{ "afterLineComment": true, "allowArrayEnd": true }正确的代码:

/*eslint lines-around-comment: ["error", { "afterLineComment": true, "allowArrayEnd": true }]*/ var day = [ "great", "wonderful" // what a great and wonderful day ]; const [ someDay // what a great and wonderful day ] = ["great", "not great"];

{ "afterBlockComment": true, "allowArrayEnd": true }正确的代码:

/*eslint lines-around-comment: ["error", { "afterBlockComment": true, "allowArrayEnd": true }]*/ var day = [ "great", "wonderful" /* what a great and wonderful day */ ]; const [ someDay /* what a great and wonderful day */ ] = ["great", "not great"];

ignorePattern:自定义忽略模式

默认情况下,规则会忽略以eslintjshintjslintistanbulglobalexportedjscs开头的注释。这些关键词的底层正则定义在 lib/rules/utils/ast-utils.js#L45-L46 的COMMENTS_IGNORE_PATTERN

const COMMENTS_IGNORE_PATTERN = /^\s*(?:eslint|jshint\s+|jslint\s+|istanbul\s+|globals?\s+|exported\s+|jscs)/u;

注意其中eslintjscs不带空白限定(\s+),即注释内容以这两个词开头即被忽略;而jshintjslintistanbulglobal(s)exported后要求紧跟空白。因此默认配置下,以下代码全部正确(测试见 tests/lib/rules/lines-around-comment.js#L1196-L1203):

foo(); /* jshint mentioned in this comment */ bar();

/* fallthrough */这类不在默认模式中的注释不会被忽略,仍会触发报告(测试 tests/lib/rules/lines-around-comment.js#L2765-L2775)。

如需在默认模式之外额外忽略更多注释,可将ignorePattern设置为一个字符串模式,该字符串会被直接传入RegExp构造函数(new RegExp(ignorePattern, "u"),见源码 lib/rules/lines-around-comment.js#L160),因此可以使用正则语法并默认启用u(Unicode)标志。

{ "ignorePattern": "pragma" }正确的代码:

/*eslint lines-around-comment: ["error", { "ignorePattern": "pragma" }] */ foo(); /* jshint mentioned in this comment */ bar(); foo(); /* a valid comment using pragma in it */

{ "ignorePattern": "pragma" }不正确的代码:

/*eslint lines-around-comment: ["error", { "ignorePattern": "pragma" }] */ 1 + 1; /* something else */

源码 checkForEmptyLine 的匹配顺序是:先测applyDefaultIgnorePatterns && defaultIgnoreRegExp.test(token.value),再测ignorePattern && customIgnoreRegExp.test(token.value),二者任一命中即直接返回、不报告。

applyDefaultIgnorePatterns:关闭默认忽略模式

默认忽略模式始终生效,即使你同时提供了ignorePattern。如果希望完全放弃默认模式、只保留自定义模式,请将applyDefaultIgnorePatterns设为false。源码实现见 lib/rules/lines-around-comment.js#L161-L162:options.applyDefaultIgnorePatterns !== false,即只有显式传false才会关闭。

{ "ignorePattern": "pragma", applyDefaultIgnorePatterns: false }正确的代码:

/*eslint lines-around-comment: ["error", { "ignorePattern": "pragma", applyDefaultIgnorePatterns: false }] */ foo(); /* a valid comment using pragma in it */

{ "applyDefaultIgnorePatterns": false }不正确的代码——默认模式被关闭后,jshint注释不再被忽略:

/*eslint lines-around-comment: ["error", { "applyDefaultIgnorePatterns": false }] */ foo(); /* jshint mentioned in comment */

测试 tests/lib/rules/lines-around-comment.js#L2664-L2762 逐一验证了关闭默认模式后eslintjshintjslintistanbulglobalglobalsexportedjscs全部不再豁免,均会报告before错误。

afterHashbangComment:hashbang 注释后的空行

#!开头的 hashbang 注释(shebang)在 Node.js 可执行脚本中用于指定解释器。启用afterHashbangComment: true后,规则要求 hashbang 注释之后必须紧跟一个空行。源码中 hashbang 只检查after方向、before恒为false(lib/rules/lines-around-comment.js#L569-L576)。

不正确的代码:

#!foo var day = "great" /*eslint lines-around-comment: ["error", { "afterHashbangComment": true }] */

正确的代码:

#!foo var day = "great" /*eslint lines-around-comment: ["error", { "afterHashbangComment": true }] */

测试用例 tests/lib/rules/lines-around-comment.js#L2816-L2826 验证了#!foo\nvar a = 1;会报告after错误并自动修复为#!foo\n\nvar a = 1;

源码实现:规则的核心判定流程

理解规则内部逻辑有助于预测各种边界输入的行为,其核心流程集中在 checkForEmptyLine:

  1. 忽略检查:先检查默认忽略模式与自定义ignorePattern,命中即跳过;
  2. 文件边界豁免prevLineNum < 1(注释在首行)时取消before检查,nextLineNum >= numLines(注释在末行)时取消after检查;
  3. 行内注释豁免:通过 codeAroundComment 向前后查找非注释 token,若任一 token 与注释在同一行(借助astUtils.isTokenOnSameLine),则视为行内注释直接跳过——这就是文档中"不检查与代码同行注释"的底层实现;
  4. 异常放行组合:将blockStartAllowedclassStartAllowedobjectStartAllowedarrayStartAllowed合并为exceptionStartAllowedend同理),任一命中即跳过对应的before/after检查;其中allowClassStart: false/allowClassEnd: false否决allowBlockStart/allowBlockEnd对类体的放行;
  5. 空行判定:基于sourceCode.lines与注释行号构建commentAndEmptyLines集合(见 getEmptyLineNums 与 getCommentLineNums),用注释上一行/下一行的行号是否在该集合中判断是否已有空行或相邻注释;
  6. 自动修复:规则声明fixable: "whitespace"(lib/rules/lines-around-comment.js#L88),缺少前空行时在注释行首插入\nfixer.insertTextBeforeRange),缺少后空行时在注释 token 后插入\nfixer.insertTextAfter),因此eslint --fix可以自动补齐空行。

内联注释与连续注释的处理

  • 行尾内联注释foo() // An inline comment不会被检查。测试 tests/lib/rules/lines-around-comment.js#L70-L78 中,即使同时开启afterLineCommentbeforeLineComment,行内注释也不会触发错误;
  • 连续的注释行:相邻注释彼此之间不要求空行。测试 tests/lib/rules/lines-around-comment.js#L44-L46 显示// line\n// line两行连排时,同时开启前后空行检查依然合法——因为注释行号本身加入了commentAndEmptyLines集合,且源码 lib/rules/lines-around-comment.js#L505-L509 对"前一个 token 是同行的注释"也做了豁免。

与相关规则的配合

lines-around-comment与两个相邻的格式规则共同构成注释/块排版体系:

  • space-before-blocks:要求块({)前有空格,控制的是块与语句之间的空白;
  • spaced-comment:要求注释内容以空格开始(如// comment而非//comment),控制的是注释符号内部的格式。

三者分别管住"块前空格、注释符号内空格、注释周围空行",通常一起启用以形成统一的注释排版风格。lines-around-comment的规则类型为layout(布局类),在 规则元信息 中标明recommended: false,即不随eslint:recommended自动启用,需要团队按需显式配置。

与 JSX/注释指令的注意事项

规则基于sourceCode.getAllComments()遍历所有注释 token,因此同样会处理 JSX 中的注释。另外,eslint开头的注释(如/* eslint-disable */)默认被COMMENTS_IGNORE_PATTERN忽略,不会因缺少空行被报告——这保证了关闭/启用规则的指令注释不会反过来触发本规则的错误。

When Not To Use It:何时关闭该规则

很多开发者偏爱紧凑的代码风格,并不介意注释紧贴着代码出现。如果你属于这类风格,或者你的代码库普遍使用行内注释、/* jshint ... */这类工具注释,并且不希望因此引入大量空行,那么本规则并不适合你——可以直接关闭("lines-around-comment": "off"),改用团队统一的注释规范或交给格式化工具处理。

补充说明:规则的维护状态

从源码 meta.deprecated 可以看到,本规则自ESLint v8.53.0起被标记为弃用(deprecated):ESLint 官方决定将格式化类规则移出核心库,计划保留至 v11.0.0;后续维护由@stylistic/eslint-plugin中的同名lines-around-comment规则接管(迁移指南见 ESLint Stylistic 项目)。因此新项目若需要该规则,建议直接使用 Stylistic 插件的对应规则;在使用当前 ESLint 版本(v11 之前)时,本规则依然可用,但要注意它不会再有新功能演进。

【免费下载链接】eslintFind and fix problems in your JavaScript code.项目地址: https://gitcode.com/GitHub_Trending/es/eslint

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/11 23:58:55

WordPress数据可视化插件定制开发全指南

1. WordPress数据可视化插件定制开发的市场需求在当今数据驱动的商业环境中&#xff0c;企业越来越需要将复杂数据以直观方式呈现给决策者和终端用户。WordPress作为全球最流行的内容管理系统&#xff0c;其插件生态系统为数据可视化需求提供了丰富的解决方案。但标准化的插件往…

作者头像 李华
网站建设 2026/9/11 23:56:12

多模态融合五种策略原理与PyTorch实现

简介&#xff1a;本资源是一份面向高校学生与初学者的多模态情感分析课程设计项目&#xff0c;聚焦期末大作业场景&#xff0c;解决文本与图像双模态数据协同建模的情感倾向识别问题。压缩包共47个文件&#xff0c;含17个核心Python源码&#xff08;如main.py、Trainer.py、多种…

作者头像 李华
网站建设 2026/9/11 23:55:02

HyperFrames 如何登录 HeyGen 账号并用 auth status 验证凭据配置

HyperFrames 如何登录 HeyGen 账号并用 auth status 验证凭据配置 【免费下载链接】hyperframes Write HTML. Render video. Built for agents. 项目地址: https://gitcode.com/GitHub_Trending/hy/hyperframes HyperFrames 在本地创建和渲染视频不需要任何账号&#xf…

作者头像 李华