ESLint array-bracket-newline 规则详解:掌控数组方括号内换行排版
【免费下载链接】eslintFind and fix problems in your JavaScript code.项目地址: https://gitcode.com/GitHub_Trending/es/eslint
本篇技术指南围绕 ESLint 核心仓库中的array-bracket-newline规则展开,该规则用于强制(或禁止)在数组方括号[之后与]之前添加换行符,是团队统一数组字面量与解构赋值排版风格的关键 layout 类规则。读完本文,你将完整掌握其字符串选项("always"/"never"/"consistent")与对象选项(multiline/minItems)的全部语义、默认值、判定逻辑与自动修复行为,并能够结合源码理解其底层实现。
规则概览
许多风格指南会要求或禁止在数组方括号内部出现换行。array-bracket-newline规则正是为此而生:它强制在开方括号之后与闭方括号之前执行换行策略。
- 规则类型:
layout(排版布局类),在 lib/rules/array-bracket-newline.js 中声明; - 可自动修复:
fixable: "whitespace",即所有报错均可通过eslint --fix自动修正; - 适用节点:同时作用于
ArrayExpression(数组字面量)与ArrayPattern(ES6 解构赋值模式),见 lib/rules/array-bracket-newline.js; - 默认行为:未配置任何选项时,等价于
{ "multiline": true },即"元素或元素之间出现换行时,括号内也需要换行"; - 关联规则:
array-bracket-spacing(控制方括号内部空格),两者常配合使用,详见 docs/src/rules/array-bracket-spacing.md。
注意:该规则自 ESLintv8.53.0起被标记为废弃(deprecated),原因与理由见下文"当前仓库中的废弃状态"一节。
选项详解
本规则接受字符串选项或对象选项两种形式。
字符串选项
| 选项 | 含义 |
|---|---|
"always" | 要求方括号内部必须有换行 |
"never" | 禁止方括号内部出现换行 |
"consistent" | 要求每一对方括号的换行使用保持一致:若一对括号中某一侧有换行而另一侧没有,则报错 |
对象选项
对象选项采用"任一条件满足则要求换行,否则禁止换行"的组合逻辑:
| 属性 | 默认值 | 含义 |
|---|---|---|
multiline | true | 若元素内部或元素之间存在换行,则要求括号内换行;设为false时该条件禁用 |
minItems | null | 当元素数量达到给定整数时要求括号内换行;设为0时行为与"always"相同;设为null(默认)时该条件禁用 |
字符串选项实战
always
配置方式:/*eslint array-bracket-newline: ["error", "always"]*/
不正确的代码:
/*eslint array-bracket-newline: ["error", "always"]*/ const a = []; const b = [1]; const c = [1, 2]; const d = [1, 2]; const e = [function foo() { dosomething(); }];正确的代码:
/*eslint array-bracket-newline: ["error", "always"]*/ const a = [ ]; const b = [ 1 ]; const c = [ 1, 2 ]; const d = [ 1, 2 ]; const e = [ function foo() { dosomething(); } ];可以看到,"always"强制每个数组(包括空数组[])都在[之后和]之前换行。测试用例 tests/lib/rules/array-bracket-newline.js 验证了var foo = [[1,2]]与var foo = []在"always"下会自动修复为逐层换行的形式。
never
配置方式:/*eslint array-bracket-newline: ["error", "never"]*/
不正确的代码:
/*eslint array-bracket-newline: ["error", "never"]*/ const a = [ ]; const b = [ 1 ]; const c = [ 1, 2 ]; const d = [ 1, 2 ]; const e = [ function foo() { dosomething(); } ];正确的代码:
/*eslint array-bracket-newline: ["error", "never"]*/ const a = []; const b = [1]; const c = [1, 2]; const d = [1, 2]; const e = [function foo() { dosomething(); }];"never"与"always"完全相反:括号必须紧贴元素(元素内部自身换行不受限制,例如[function foo() {\n...\n}]中的函数体换行是允许的,只要[与函数开头、函数结尾与]在同一行即可)。
consistent
配置方式:/*eslint array-bracket-newline: ["error", "consistent"]*/
不正确的代码(括号两侧换行不一致):
/*eslint array-bracket-newline: ["error", "consistent"]*/ const a = [1 ]; const b = [ 1]; const c = [function foo() { dosomething(); } ] const d = [ function foo() { dosomething(); }]正确的代码:
/*eslint array-bracket-newline: ["error", "consistent"]*/ const a = []; const b = [ ]; const c = [1]; const d = [ 1 ]; const e = [function foo() { dosomething(); }]; const f = [ function foo() { dosomething(); } ];"consistent"的核心思想是"开括号后换行,则闭括号前也必须换行":左侧[之后有换行而右侧]之前没有(或反之)即为违规。测试 tests/lib/rules/array-bracket-newline.js 覆盖了空数组、单元素数组以及嵌套数组等多种形态。
对象选项实战
multiline
配置方式:/*eslint array-bracket-newline: ["error", { "multiline": true }]*/(这也是规则的默认行为)
不正确的代码:
/*eslint array-bracket-newline: ["error", { "multiline": true }]*/ const a = [ ]; const b = [ 1 ]; const c = [ 1, 2 ]; const d = [1, 2]; const e = [function foo() { dosomething(); }];正确的代码:
/*eslint array-bracket-newline: ["error", { "multiline": true }]*/ const a = []; const b = [1]; const c = [1, 2]; const d = [ 1, 2 ]; const e = [ function foo() { dosomething(); } ];注意这里的微妙之处:{ "multiline": true }只要求当数组内容本身跨行(即首尾元素之间不在同一行)时,括号才需要换行。因此:
[1, 2]单行数组 → 不要求换行,正确;[\n1\n]单元素数组虽然内容只有一行,但括号换行了而内容没有跨行,反而被判定为不正确——因为"元素之间没有换行,括号却换行了",此时规则要求移除多余换行;[\n1,\n2\n]内容跨行 → 必须换行,正确。
也就是说,multiline: true检查的是"换行是否必要":内容未跨行时,多余的括号换行会被报错并自动移除。这一点从源码的判定条件可以清楚看出(见下文实现解析)。
minItems
配置方式:/*eslint array-bracket-newline: ["error", { "minItems": 2 }]*/
不正确的代码:
/*eslint array-bracket-newline: ["error", { "minItems": 2 }]*/ const a = [ ]; const b = [ 1 ]; const c = [1, 2]; const d = [1, 2]; const e = [ function foo() { dosomething(); } ];正确的代码:
/*eslint array-bracket-newline: ["error", { "minItems": 2 }]*/ const a = []; const b = [1]; const c = [ 1, 2 ]; const d = [ 1, 2 ]; const e = [function foo() { dosomething(); }];minItems: 2的含义是:元素数量达到 2 个及以上时要求括号内换行,少于 2 个时禁止括号内换行。因此:
[]与[1](元素数量 < 2)→ 必须单行书写;[1, 2]、[1,\n2](元素数量 ≥ 2)→ 必须写成[\n1, 2\n]或[\n1,\n2\n]形式;[function foo() {...}]虽然元素只有 1 个,但元素数量未达阈值,括号必须贴紧(函数体内部换行不受影响)。
multiline 与 minItems 组合
配置方式:/*eslint array-bracket-newline: ["error", { "multiline": true, "minItems": 2 }]*/
不正确的代码:
/*eslint array-bracket-newline: ["error", { "multiline": true, "minItems": 2 }]*/ const a = [ ]; const b = [ 1 ]; const c = [1, 2]; const d = [1, 2]; const e = [function foo() { dosomething(); }];正确的代码:
/*eslint array-bracket-newline: ["error", { "multiline": true, "minItems": 2 }]*/ const a = []; const b = [1]; const c = [ 1, 2 ]; const d = [ 1, 2 ]; const e = [ function foo() { dosomething(); } ];组合使用时采用"或"逻辑:multiline条件或minItems条件任一满足即要求换行。因此示例中的e虽只有 1 个元素,但因函数体跨行使multiline条件成立,括号必须换行。
默认行为(未配置选项)
不写选项时,规则等价于{ "multiline": true }。其源码归一化逻辑位于 lib/rules/array-bracket-newline.js:当option为空时,multiline = true、minItems = Number.POSITIVE_INFINITY(即minItems条件永远不触发)。测试 tests/lib/rules/array-bracket-newline.js 的 valid 用例验证了默认情况下[]、[1]、[1, 2]均为合法,而[\n1, 2\n]这类内容跨行的写法必须保持括号换行。
源码级实现解析
选项归一化:字符串如何映射为对象
normalizeOptionValue函数(lib/rules/array-bracket-newline.js)将各种选项形态统一归一化为{ consistent, multiline, minItems }三要素:
| 传入选项 | consistent | multiline | minItems |
|---|---|---|---|
| (未传) | false | true | Infinity |
"always" | false | false | 0 |
"never" | false | false | Infinity |
"consistent" | true | false | Infinity |
{ minItems: 0 } | false | false | 0 |
{ multiline: true }等对象 | false | Boolean(option.multiline) | option.minItems \|\| Infinity |
关键设计:
"always"与{ minItems: 0 }殊途同归——minItems归零意味着"元素数量 ≥ 0 恒成立",即永远要求换行;"never"与"consistent"都将minItems设为Infinity(阈值永不可达),两者差异仅在于consistent标志位;option.minItems || Number.POSITIVE_INFINITY这一写法使得minItems: null也会落到Infinity,与文档所述默认值一致。
判定逻辑:什么时候需要换行
核心判定在check函数(lib/rules/array-bracket-newline.js)中完成,needsLinebreaks为真时要求括号换行,为假时禁止换行:
const needsLinebreaks = elements.length >= options.minItems || (options.multiline && elements.length > 0 && firstIncComment.loc.start.line !== lastIncComment.loc.end.line) || (elements.length === 0 && firstIncComment.type === "Block" && firstIncComment.loc.start.line !== lastIncComment.loc.end.line && firstIncComment === lastIncComment) || (options.consistent && openBracket.loc.end.line !== first.loc.start.line);四个条件逐一解读:
- 元素数量达到
minItems阈值; multiline: true且元素数 > 0 且首尾 token(含注释)跨行——这是默认模式的核心判定;- 空数组但包含跨行的块注释(如
[/* \n多行注释\n */]),此时视为"内容跨行",要求括号换行; consistent模式下开括号行尾与首个 token 行首不在同一行——即"开括号后换行了,则闭括号前也必须换行"。
实现中特意区分了"判断是否多行"与"判断是否需要换行"所用的 token 集合:注释被计入多行判定,但换行必要性判定只基于真实 token。源码注释中的示例说明这一设计允许以下写法(在[后紧跟行注释再换行):
var arr = [ // eslint-disable-line foo 'a' ]自动修复:插入与删除换行
四条报告路径对应四个messageId,全部支持自动修复(lib/rules/array-bracket-newline.js):
| messageId | 触发场景 | 修复动作 |
|---|---|---|
unexpectedOpeningLinebreak | [之后不应有换行 | fixer.removeRange删除[与下一 token 之间空白 |
unexpectedClosingLinebreak | ]之前不应有换行 | fixer.removeRange删除上一 token 与]之间空白 |
missingOpeningLinebreak | [之后缺少换行 | fixer.insertTextAfter(token, "\n")插入换行 |
missingClosingLinebreak | ]之前缺少换行 | fixer.insertTextBefore(token, "\n")插入换行 |
值得注意的边界处理:在删除换行时,如果紧邻的 token 是注释(通过astUtils.isCommentToken判断,见 lib/rules/utils/ast-utils.js),修复函数会返回null放弃修复——这是为了避免删除注释与其所属代码之间的换行导致注释错位。测试 tests/lib/rules/array-bracket-newline.js 中对嵌套数组的 autofix 输出(如var foo = [[2,\n3]]→var foo = [\n[\n2,\n3\n]\n])精确验证了每一层括号的修复结果。
覆盖 ArrayPattern:解构赋值同样受控
check同时挂载在ArrayPattern与ArrayExpression上,因此解构赋值同样适用本规则:
/*eslint array-bracket-newline: ["error", "always"]*/ // 正确 var [ a, b ] = foo;测试文件在 tests/lib/rules/array-bracket-newline.js 中为ArrayPattern场景(需ecmaVersion: 6)逐一验证了默认、"always"、"consistent"、{ multiline: true }等选项。
与 array-bracket-spacing 配合使用
array-bracket-newline的关联规则array-bracket-spacing(见 docs/src/rules/array-bracket-spacing.md)控制的是空格而非换行,两者互补:
array-bracket-newline:控制[后与]前是否换行;array-bracket-spacing:控制[后与]前是否留空格。
一个常见的组合是"允许换行但不允许空格"——array-bracket-spacing: ["error", "never"]的默认内置例外就允许括号内换行(这是常见书写模式),而换行的具体策略交给array-bracket-newline裁决。例如:
// array-bracket-spacing: ["error", "never"] + array-bracket-newline: ["error", "multiline"] var arr = [ 'foo', 'bar' ]; // 正确:无多余空格,内容跨行故括号换行何时不使用此规则
如果你不关心数组方括号前后是否换行,或者项目已经采用 Prettier 等格式化工具统一排版,可以关闭本规则。文档原话为:"If you don't want to enforce line breaks after opening and before closing array brackets, don't enable this rule."
兼容性
该规则的前身来自 JSCS 的 validateNewlineAfterArrayElements 检查项,ESLint 将其纳入核心规则集并扩展出"always"/"never"/"consistent"及对象选项等更丰富的配置形态。
当前仓库中的废弃状态
从源码元数据看,该规则自ESLint v8.53.0起被标记为废弃(lib/rules/array-bracket-newline.js),废弃原因是"格式化类规则正在移出 ESLint 核心",并计划在 v11.0.0 之前从核心移除。官方建议的迁移路径是使用 ESLint Stylistic 项目维护的@stylistic/eslint-plugin插件,其中的array-bracket-newline规则提供了同名替代实现。因此在现有新代码库中,更推荐直接采用@stylistic/eslint-plugin的对应规则来管理数组括号换行风格。
参考路径
- 规则文档:docs/src/rules/array-bracket-newline.md
- 规则实现:lib/rules/array-bracket-newline.js
- 规则测试:tests/lib/rules/array-bracket-newline.js
- 辅助工具:lib/rules/utils/ast-utils.js
- 关联规则文档:docs/src/rules/array-bracket-spacing.md
【免费下载链接】eslintFind and fix problems in your JavaScript code.项目地址: https://gitcode.com/GitHub_Trending/es/eslint
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考