news 2026/9/12 17:35:36

ESLint 规则 `semi-spacing` 全解:分号前后空格的强制与禁止

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ESLint 规则 `semi-spacing` 全解:分号前后空格的强制与禁止

ESLint 规则semi-spacing全解:分号前后空格的强制与禁止

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

ESLint 的semi-spacing规则(docs/src/rules/semi-spacing.md)专门用于统一分号(;)前后的空格风格,避免var a = "b" ;这类前后缀空格混乱、以及var c = "d";var e = "f";这类缺少分隔空格的写法,从而提升代码的可读性与一致性。读完本文你将掌握该规则的完整配置参数(before/after)、默认行为、与semicomma-spacing等相邻规则的职责划分,以及其底层实现原理和可自动修复(--fix)能力。

规则概览

JavaScript 语法允许在分号前后放置多余空格,例如:

var a = "b" ; var c = "d";var e = "f";

第一行的分号前多了一个空格,第二行两个语句之间的分号后缺少空格。semi-spacing规则的目标就是在分号两侧强制执行一致的空格风格:禁止表达式中的分号前出现空格,并按配置约束分号后的空格。

从源码 lib/rules/semi-spacing.js 的meta定义可以看出,该规则属于layout(排版布局)类型,且声明为fixable: "whitespace",意味着它产生的全部报告都能被 ESLint 的--fix自动修复。同时,该规则被纳入recommendedrecommended: false),需要你在配置中显式开启。

注意:该规则已在 ESLint v8.53.0 中被标记为已废弃(deprecated),可用至 v11.0.0。核心团队正在将格式化类规则移出 ESLint 核心,交由 ESLint Stylistic 项目(@stylistic/eslint-plugin中的semi-spacing规则)继续维护,详见源码中的 deprecated 元数据。如果项目从旧版本迁移,这条规则的行为与配置方式保持不变。

规则细节与检查范围

规则的检查核心逻辑位于checkSemicolonSpacing(lib/rules/semi-spacing.js),它只对真正是分号的 token(通过astUtils.isSemicolonToken判断,见 lib/rules/utils/ast-utils.js)进行两项判定:

  1. 分号前是否有空格hasLeadingSpace),结合配置决定是报告"多余空格"还是"缺失空格";
  2. 分号后是否有空格hasTrailingSpace),同样结合配置决定报告方向。

具体的报告消息(messageId)有四种,均定义在 lib/rules/semi-spacing.js:

messageId文案触发场景
unexpectedWhitespaceBeforeUnexpected whitespace before semicolon.配置禁止分号前空格,却出现了空格
unexpectedWhitespaceAfterUnexpected whitespace after semicolon.配置禁止分号后空格,却出现了空格
missingWhitespaceBeforeMissing whitespace before semicolon.配置要求分号前空格,却缺失
missingWhitespaceAfterMissing whitespace after semicolon.配置要求分号后空格,却缺失

规则不检查的三种情况

原文档明确了该规则不会检查以下三种场景,这些边界在源码中都有对应的守卫条件:

  1. 分号是行首第一个 token 时,不检查分号后的空格(对应源码中的isFirstTokenInCurrentLine判断,lib/rules/semi-spacing.js)。例如下一行的;foo();这种用于防御 ASI 问题的写法不会被干涉。

  2. 分号紧跟左括号({时,不检查分号前的空格;分号紧跟右括号)}时,不检查分号后的空格。这部分间距分别由space-in-parensblock-spacing负责(对应源码中的isBeforeClosingParen判断,lib/rules/semi-spacing.js)。例如if (true) {;}中的分号紧贴{}semi-spacing会主动让位。

  3. 空条件的 for 循环for(;;)中的分号间距不检查。测试用例"for (;;) {}"在默认配置下是合法的(tests/lib/rules/semi-spacing.js)。

检查覆盖的语句类型

从规则底部的return对象(lib/rules/semi-spacing.js)可以看出,checkNode会检查所有"最后一个 token 是分号"的语句,包括:

  • VariableDeclaration(变量声明)
  • ExpressionStatement(表达式语句)
  • BreakStatement/ContinueStatementbreak/continue
  • DebuggerStatementdebugger
  • DoWhileStatementdo...while
  • ReturnStatementreturn
  • ThrowStatementthrow
  • ImportDeclaration/ExportNamedDeclaration/ExportAllDeclaration/ExportDefaultDeclaration(ES Module 导入导出)
  • PropertyDefinition(类字段,ES2022,见测试 tests/lib/rules/semi-spacing.js)

此外ForStatement有专门的处理器,只检查for头部inittest之后、非末尾处的分号(lib/rules/semi-spacing.js)。

配置选项

规则接受一个对象参数,包含两个布尔键:

选项键类型默认值含义
beforebooleanfalsetrue强制分号前有空格;为false禁止分号前空格
afterbooleantruetrue强制分号后有空格;为false禁止分号后空格

其中after选项只在分号不在行末时生效(即分号后面同一行还有别的 token)。默认配置为{"before": false, "after": true},即"分号前禁空格、分号后要空格"。

在配置文件中开启该规则的完整写法:

{ "rules": { "semi-spacing": ["error", { "before": false, "after": true }] } }

如果省略选项对象,等价于使用默认值{ "before": false, "after": true },源码中create函数的初始化逻辑正是如此(lib/rules/semi-spacing.js)。

同时,schema 定义 声明了additionalProperties: false,即不接受任何未知键,传入{ "before": false, "after": true, "foo": 1 }这类配置会直接触发配置校验错误。

默认选项{"before": false, "after": true}

这是默认选项,也是最贴近社区主流风格(配合semi规则的"语句末必须加分号")的组合:禁止分号前空格,强制分号后空格

不正确的代码示例:

/*eslint semi-spacing: "error"*/ var foo ; var foo;var bar; throw new Error("error") ; while (a) { break ; } for (i = 0 ; i < 10 ; i++) {} for (i = 0;i < 10;i++) {}

这些例子分别触发了"分号前多余空格"(var foo ;throw ... ;break ;、for 头部)和"分号后缺失空格"(var foo;var bar;for (i = 0;i < 10;i++) {})。

正确的代码示例:

/*eslint semi-spacing: "error"*/ var foo; var foo; var bar; throw new Error("error"); while (a) { break; } for (i = 0; i < 10; i++) {} for (;;) {} if (true) {;} ;foo();

注意后三行属于前面提到的豁免场景:for(;;)空条件不检查;{;}中的分号紧贴括号由block-spacing负责;行首的;foo();属于 ASI 防御写法,分号后不强制空格。

反向选项{"before": true, "after": false}

该选项要求分号前必须有空格,分号后禁止空格。这是一种比较少见的风格,通常与"语句不以分号收尾"或semi: ["error", "never"]搭配使用(分号仅用于分割同一行的语句)。

不正确的代码示例:

/*eslint semi-spacing: ["error", { "before": true, "after": false }]*/ var foo; var foo ; var bar; throw new Error("error"); while (a) { break; } for (i = 0;i < 10;i++) {} for (i = 0; i < 10; i++) {}

正确的代码示例:

/*eslint semi-spacing: ["error", { "before": true, "after": false }]*/ var foo ; var foo ;var bar ; throw new Error("error") ; while (a) {break ;} for (i = 0 ;i < 10 ;i++) {}

对比两组例子可以直观看出:before: truevar foo;变成错误、var foo ;才是正确;after: falsevar foo ; var bar;中的分号后空格成为错误,正确的写法是var foo ;var bar ;

自动修复与源码实现原理

由于规则声明了fixable: "whitespace",所有报告都可以通过--fix自动修复。修复逻辑直接内嵌在checkSemicolonSpacingfix回调中(lib/rules/semi-spacing.js):

  • 移除分号前的多余空格:fixer.removeRange([tokenBefore.range[1], token.range[0]])
  • 在分号前插入一个空格:fixer.insertTextBefore(token, " ")
  • 移除分号后的多余空格:fixer.removeRange([token.range[1], tokenAfter.range[0]])
  • 在分号后插入一个空格:fixer.insertTextAfter(token, " ")

报告位置也有讲究:分号前的问题,报告区间覆盖"分号前一个 token 的结尾到分号开头"的空白区域;分号后的问题同理(lib/rules/semi-spacing.js)。

测试文件 tests/lib/rules/semi-spacing.js 中的大量用例同时验证了code(原始代码)与output(修复后代码),例如:

  • "var a = 'b' ;""var a = 'b';"(移除分号前两个空格);
  • "var a = 'b';c = 'd';""var a = 'b'; c = 'd';"(补上分号后缺失的空格);
  • "for(a ; ; );""for(a;; );"before: false, after: false组合下同时移除两个空格);
  • "do {} while (true); foo""do {} while (true) ;foo"before: true, after: false下先补后删)。

这些测试还覆盖了字符串内的分号不被误判("var a = 'b ; c';"合法)、跨行变量声明、IIFE、正则字面量后分号、debugger、类字段等边界场景(tests/lib/rules/semi-spacing.js)。

与相邻规则的职责划分

semi-spacing只是分号处理体系中的一环,原文档 frontmatter 声明的相关规则(related_rules)明确了各自的边界:

规则职责与 semi-spacing 的关系
semi决定是否必须/禁止写分号搭配使用:semi: ["error", "always"]保证分号存在,semi-spacing保证分号两侧空格
no-extra-semi移除多余的分号分号本体重复/多余的问题归它管;semi-spacing只关注空格。测试中"foo; ;;;;;;;;;"之所以合法,正是因为多余分号由no-extra-semi清理
comma-spacing控制逗号前后空格对标分号场景,语义几乎一致
block-spacing控制代码块花括号{ }内部空格负责{;}这类紧贴花括号的分号两侧空格
space-in-parens控制圆括号( )内部空格负责(;;)这类紧贴圆括号的分号两侧空格

用一句话概括:semi-spacing只管分号两侧的空格,凡是分号紧贴括号或处于行首/行末的边界情形,都由上述相邻规则接管

历史沿革:合并自no-space-before-semi

从 conf/rule-type-list.json 的移除规则清单可以看到,旧版规则no-space-before-semi(禁止分号前空格)已被移除,其功能合并进semi-spacing

{ "removed": "no-space-before-semi", "replacedBy": [{ "rule": { "name": "semi-spacing" } }] }

因此在配置中看到遗留的no-space-before-semi时,应当迁移为semi-spacingbefore: false配置。

何时关闭该规则

如果你不关心分号前后空格的一致性——例如团队已经统一使用格式化工具(Prettier 等)管理空白、或刻意使用无分号风格且不在意行内分割——可以直接关闭该规则。另外需要重申:由于该规则已被标记为废弃(见 lib/rules/semi-spacing.js),新项目更建议直接使用 ESLint Stylistic 的semi-spacing规则,其选项与行为完全一致,迁移成本为零。

参考资源

  • 规则文档:docs/src/rules/semi-spacing.md
  • 规则实现:lib/rules/semi-spacing.js
  • 单元测试(含全部自动修复用例):tests/lib/rules/semi-spacing.js
  • 相关规则文档:docs/src/rules/semi.md、docs/src/rules/no-extra-semi.md、docs/src/rules/comma-spacing.md、docs/src/rules/block-spacing.md、docs/src/rules/space-in-parens.md
  • 移除规则对照表:conf/rule-type-list.json

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

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

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

棋盘格相机标定实战:从内参矩阵到畸变校正的关键细节

简介&#xff1a;相机内参标定是计算机视觉的基础环节&#xff0c;直接影响图像畸变校正与三维测量精度。这份练习包面向需要快速上手单目相机标定的学生、研究者或开发者&#xff0c;定位明确&#xff1a;通过棋盘格图像与Python脚本&#xff0c;解决相机焦距、主点坐标及畸变…

作者头像 李华
网站建设 2026/9/12 17:28:53

如何按官方最佳实践对 Envoy 做基准测试并避免常见测量错误

如何按官方最佳实践对 Envoy 做基准测试并避免常见测量错误 【免费下载链接】envoy Cloud-native high-performance edge/middle/service proxy 项目地址: https://gitcode.com/GitHub_Trending/en/envoy 如果你需要量化 Envoy 在你自己环境中的 QPS、延迟或资源开销&am…

作者头像 李华
网站建设 2026/9/12 17:26:43

告别装软件踩坑:awesome-macOS 帮你一次配齐 macOS 效率工具

告别装软件踩坑&#xff1a;awesome-macOS 帮你一次配齐 macOS 效率工具 【免费下载链接】awesome-macOS  A curated list of awesome applications, softwares, tools and shiny things for macOS. 项目地址: https://gitcode.com/GitHub_Trending/aw/awesome-macOS …

作者头像 李华