ESLint function-paren-newline 规则详解:强制函数括号内换行一致性
ESLint function-paren-newline 规则详解强制函数括号内换行一致性【免费下载链接】eslintFind and fix problems in your JavaScript code.项目地址: https://gitcode.com/GitHub_Trending/es/eslintfunction-paren-newline 是 ESLint 内置布局layout类规则用于在函数形参或实参的括号内部强制执行一致、统一的换行风格——它同时覆盖函数声明、函数表达式、箭头函数、函数调用、new表达式以及动态import()这六类语法节点。读完本文你将掌握该规则全部 5 种字符串选项与minItems对象选项的语义差异、每种选项下正确与错误代码的判定标准、底层源码的判定算法以及它在当前仓库中被弃用的背景与迁移路径。规则简介与适用场景许多风格指南要求或禁止在函数括号内部出现换行function-paren-newline正是为这类需求而生它检查函数形参parameters和调用实参arguments两侧括号内侧的换行情况并强制整个括号对保持一致的书写风格。从 源码定义 可以看到该规则type为layout属于纯排版类规则不影响代码语义fixable: whitespace意味着绝大多数问题都可以通过--fix自动修复recommended: false不包含在 ESLint 的推荐配置中需要用户显式开启。规则实际检查的 AST 节点类型见 getParenTokens 与监听器实现包括节点类型覆盖场景FunctionDeclaration函数声明如function foo(a, b) {}FunctionExpression函数表达式如var f function(a, b) {}ArrowFunctionExpression箭头函数如(a, b) {}CallExpression普通函数调用如foo(a, b)NewExpressionnew表达式如new Foo(a, b)ImportExpression动态导入import(source)对于没有括号的箭头函数如foo {}以及没有实参的new Foo规则会直接跳过源码中通过getParenTokens返回null处理见 lib/rules/function-paren-newline.js#L251-L332。选项详解字符串与对象两种形态该规则只有一个选项可以是字符串也可以是对象对应源码 schema 定义。字符串选项取值为枚举always、never、multiline、multiline-arguments、consistent对象选项则形如{ minItems: value }。选项类型行为alwaysstring所有函数括号内部都必须有换行neverstring所有函数括号内部都禁止换行multilinestring默认只要形参/实参之间存在换行括号内就要求换行否则禁止换行multiline-argumentsstring行为类似multiline但允许只有一个形参/实参时括号内不换行consistentstring要求每一对括号两侧(后与)前换行状态一致一侧有换行另一侧也必须一致{ minItems: value }object形参/实参数量达到value时要求括号内换行否则禁止换行选项如何映射为源码中的阈值理解选项内部机制有助于理解边界行为。在 create 函数 中规则把选项归一化为一个minItems阈值const rawOption context.options[0] || multiline; if (typeof rawOption object) { minItems rawOption.minItems; } else if (rawOption always) { minItems 0; // 数量 0 恒成立 ⇒ 永远要求换行 } else if (rawOption never) { minItems Infinity; // 数量 Infinity 恒不成立 ⇒ 永远禁止换行 } else { minItems null; // multiline / multiline-arguments / consistent 走专用分支 }也就是说always等价于{ minItems: 0 }never等价于{ minItems: Infinity }而multiline、multiline-arguments、consistent三个选项则由shouldHaveNewlines中的专用逻辑处理见 lib/rules/function-paren-newline.js#L116-L132multiline/multiline-arguments只要相邻两个形参/实参不在同一行element.loc.end.line ! elements[index 1].loc.start.line就要求括号内换行multiline-arguments的额外分支当elements.length 1只有一个参数时括号内是否换行完全跟随左括号当前的状态hasLeftNewline因此单个参数时两种风格都合法consistent括号内是否换行直接取hasLeftNewline左括号后是否已有换行即把右侧与左侧对齐。配置示例{ rules: { function-paren-newline: [error, never] } }{ rules: { function-paren-newline: [error, { minItems: 3 }] } }对象选项的 schema 还声明了约束minItems必须是非负整数type: integer, minimum: 0且不允许出现额外属性additionalProperties: false否则会触发配置校验错误见 lib/rules/function-paren-newline.js#L65-L74。选项 always所有括号内强制换行开启always后只要函数声明、表达式、箭头函数或调用出现在括号中(之后与)之前都必须有换行。不正确的代码always/* eslint function-paren-newline: [error, always] */ function foo(bar, baz) {} var qux function(bar, baz) {}; var qux (bar, baz) {}; foo(bar, baz);正确的代码always/* eslint function-paren-newline: [error, always] */ function foo( bar, baz ) {} var qux function( bar, baz ) {}; var qux ( bar, baz ) {}; foo( bar, baz );注意在always下括号内的形参之间不需要换行如bar, baz写在同一行是允许的规则只约束左右括号的内侧。这对应源码中validateParens只检查(后与)前的换行、而参数间的换行仅在multiline-arguments下才由validateArguments额外检查见 lib/rules/function-paren-newline.js#L140-L241。选项 never所有括号内禁止换行开启never后函数括号内侧出现任何换行都会报错。不正确的代码never/* eslint function-paren-newline: [error, never] */ function foo( bar, baz ) {} var qux function( bar, baz ) {}; var qux ( bar, baz ) {}; foo( bar, baz );正确的代码never/* eslint function-paren-newline: [error, never] */ function foo(bar, baz) {} function qux(bar, baz) {} var foobar function(bar, baz) {}; var foobar (bar, baz) {}; foo(bar, baz); foo(bar, baz);一个值得注意的细节在never下function qux(bar,\n baz) {}是合法的——规则只检查括号内侧(与第一个形参之间、最后一个形参与)之间没有换行参数之间是否换行并不属于never的管辖范围只有在multiline-arguments选项下参数间换行才会被检查。默认选项 multiline跟随参数是否跨行multiline是该规则的默认选项context.options[0] || multiline核心思想是保持代码原有的多行/单行意图只要任意两个形参/实参之间存在换行就要求括号内部也换行如果所有参数都在同一行则禁止括号内换行。不正确的代码默认multiline/* eslint function-paren-newline: [error, multiline] */ function foo(bar, baz ) {} var qux function( bar, baz ) {}; var qux ( bar, baz) {}; foo(bar, baz); foo( function() { return baz; } );最后一条foo(\n function() {...}\n)之所以不正确是因为单个实参内部的函数体虽然是多行的但规则统计的是形参/实参元素之间的换行相邻元素的loc.end.line与loc.start.line单个实参不构成参数之间有换行因此此时括号内侧不应换行。正确的代码默认multiline/* eslint function-paren-newline: [error, multiline] */ function foo(bar, baz) {} var foobar function( bar, baz ) {}; var foobar (bar, baz) {}; foo(bar, baz, qux); foo( bar, baz, qux ); foo(function() { return baz; });注意foo(function() {...})在这里是正确的参数只有一项且与其他参数没有之间换行因此括号内不换行也是合规的。选项 consistent括号两侧换行状态必须一致consistent关注的是每一对括号自身的对称性如果(后有换行而)前没有或相反就报告错误。它不像multiline那样关心参数是否跨行只看左右括号的内侧状态是否一致。不正确的代码consistent/* eslint function-paren-newline: [error, consistent] */ function foo(bar, baz ) {} var qux function(bar, baz ) {}; var qux ( bar, baz) {}; foo( bar, baz); foo( function() { return baz; });正确的代码consistent/* eslint function-paren-newline: [error, consistent] */ function foo(bar, baz) {} var qux function(bar, baz) {}; var qux ( bar, baz ) {}; foo( bar, baz ); foo( function() { return baz; } );可以看到在consistent下function foo(bar,\n baz)是合法的左侧(后无换行、右侧)前也无换行两侧一致而foo(\n bar, baz)同样合法两侧都有换行。判断依据正是源码中的return hasLeftNewline;——以左括号的状态为准对齐右括号lib/rules/function-paren-newline.js#L128-L130。选项 multiline-argumentsmultiline 的灵活变体multiline-arguments在multiline的基础上放宽了单个参数的场景当括号内只有一个形参/实参时无论括号内是否换行都被允许此时跟随左括号当前状态即可当存在多个参数且参数间存在换行时要求括号内换行。不正确的代码multiline-arguments/* eslint function-paren-newline: [error, multiline-arguments] */ function foo(bar, baz ) {} var foobar function(bar, baz ) {}; var foobar ( bar, baz) {}; foo( bar, baz); foo( bar, qux, baz );最后一条foo(\n bar, qux,\n baz\n)是不正确的因为参数之间存在换行bar, qux与baz分行此时规则要求参数之间也要换行——这正是multiline-arguments独有的validateArguments检查它会遍历相邻参数对若参数间无换行则报告expectedBetween错误见 lib/rules/function-paren-newline.js#L218-L241。正确的代码multiline-arguments/* eslint function-paren-newline: [error, multiline-arguments] */ function foo( bar, baz ) {} var qux function(bar, baz) {}; var qux ( bar ) {}; foo( function() { return baz; } );注意var qux (\n bar\n) {}是正确的只有一个形参时括号内换行是被允许的对应源码中elements.length 1时返回hasLeftNewline的分支lib/rules/function-paren-newline.js#L117-L119。这也是它与默认multiline最直观的区别默认模式下单个参数多行书写如foo(\n function() {...}\n)会被判错而multiline-arguments不会。对象选项 { minItems: value }按参数数量决定换行当选项为对象{ minItems: value }时规则按形参/实参的数量决定是否需要括号内换行数量达到value时要求换行否则禁止换行。该选项适合参数多了再展开、参数少就单行的团队规范。以{ minItems: 3 }为例参数数量 ≥ 3 时才展开换行不正确的代码/* eslint function-paren-newline: [error, { minItems: 3 }] */ function foo( bar, baz ) {} function foobar(bar, baz, qux) {} var barbaz function( bar, baz ) {}; var barbaz ( bar, baz ) {}; foo( bar, baz );function foobar(bar, baz, qux)不正确是因为 3 个参数达到了minItems阈值必须换行其余几条则是参数不足 3 个却换行了。正确的代码/* eslint function-paren-newline: [error, { minItems: 3 }] */ function foo(bar, baz) {} var foobar function( bar, baz, qux ) {}; var foobar ( bar, baz, qux ) {}; foo(bar, baz); foo( bar, baz, qux );注意在minItems模式下达到阈值后只要求括号内侧换行参数之间仍可保持同一行如var foobar (\n bar, baz, qux\n) {}。由于always等价于{ minItems: 0 }、never等价于{ minItems: Infinity }熟悉这个对象选项之后字符串选项的内部行为也就一目了然了。自动修复与修复限制该规则标记为fixable: whitespace因此开启后运行eslint --fix可以自动修正绝大多数换行问题。规则产生的五类报告消息见 messages 定义为expectedAfter(后缺少换行修复方式是在左括号后插入\nexpectedBefore)前缺少换行修复方式是在右括号前插入\nunexpectedAfter(后出现多余换行修复方式是删除(与下一个 token 之间的空白unexpectedBefore)前出现多余换行修复方式是删除最后一个 token 与)之间的空白expectedBetween参数之间缺少换行仅multiline-arguments触发修复方式是在下一个参数前插入\n。但有一个重要的修复限制如果括号与第一个/最后一个元素之间存在注释规则会放弃自动修复返回null以避免破坏注释位置。源码中对此有明确处理——(与首个 token 之间的文本trim()后非空则跳过修复)前同理见 lib/rules/function-paren-newline.js#L159-L173 与 lib/rules/function-paren-newline.js#L187-L200。因此遇到括号与参数间夹着注释的代码需要手动调整换行。源码判定流程一览结合 lib/rules/function-paren-newline.js 的完整实现该规则对每个命中节点的处理分三步定位括号 tokengetParenTokens根据节点类型CallExpression/NewExpression取 callee 后的开括号与末尾闭括号函数类取第一个开括号与最后一个参数后的闭括号箭头函数跳过async关键字ImportExpression取首尾 token并处理无括号情况返回nulllib/rules/function-paren-newline.js#L251-L332判定期望状态shouldHaveNewlines依据选项计算括号内是否应当换行lib/rules/function-paren-newline.js#L116-L132比对并报告/修复validateParens分别检查(后与)前的实际换行状态与期望不一致时按对应 messageId 报告必要时附带修复器multiline-arguments还会额外调用validateArguments检查参数间的换行lib/rules/function-paren-newline.js#L140-L241。其中换行状态的判断基于 token 位置astUtils.isTokenOnSameLine(leftParen, tokenAfterLeftParen)为假即视为存在换行。仓库中配套的规则测试位于 tests/lib/rules/function-paren-newline.js共 1522 行覆盖了全部选项在valid/invalid两组用例下的行为包括async箭头函数、动态import()、new Foo、无括号箭头函数、模板字符串实参等边界场景是验证上述规则语义的最佳参考。弃用说明与迁移建议需要特别提醒该规则已在ESLint v8.53.0中标记为弃用deprecated计划可用至v11.0.0。弃用原因是 ESLint 团队将排版类formatting规则逐步移出核心库交由 ESLint Stylistic 社区项目维护见 lib/rules/function-paren-newline.js#L20-L41 中的弃用元数据。迁移方式若项目仍使用旧版本可继续沿用本文配置若使用 ESLint v9 并需要长期维护建议改用stylistic/eslint-plugin中同名的function-paren-newline规则选项语义保持一致配置方式如下// eslint.config.jsflat config import stylistic from stylistic/eslint-plugin; export default [ { plugins: { stylistic: stylistic }, rules: { stylistic/function-paren-newline: [error, multiline] } } ];如果你不想强制函数括号内的换行风格则不要开启本规则——尤其是当项目中既有全单行写法、又有长参数列表手动换行的混合风格时该规则反而会造成额外噪音。此时更合适的做法是保持现状或改用整体格式化工具如 Prettier统一排版。小结function-paren-newline通过一个选项覆盖了从永远换行到永远不换行的完整策略谱系always与never是两个极端multiline默认与multiline-arguments根据参数是否跨行自适应consistent强调括号两侧对称而{ minItems: N }则按参数数量决定阈值。理解其底层的minItems归一化与仅检查括号内侧的判定规则就能准确预判任何代码风格下该规则的行为在最新项目中请优先考虑迁移到stylistic/eslint-plugin以获得持续维护。【免费下载链接】eslintFind and fix problems in your JavaScript code.项目地址: https://gitcode.com/GitHub_Trending/es/eslint创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考