
ESLint 的 semi-style 規則精確約束分號位置的布局規范指南【免費下載鏈接】eslintFind and fix problems in your JavaScript code.項目地址: https://gitcode.com/GitHub_Trending/es/eslint本指南圍繞 ESLint 核心規則semi-style分號樣式展開它用于強制分號出現在語句的行尾或行首指定位置是維護 JavaScript 無分號semicolon-less代碼風格一致性的關鍵工具。讀完本文你將掌握semi-style的兩種選項last與first的配置方法、其底層實現原理、for循環頭與類靜態塊等特殊場景的處理邏輯以及該規則當前在 ESLint 中的棄用狀態與遷移路徑。規則概覽為什么要指定分號位置通常情況下分號位于行的末尾foo(); bar();但在無分號風格semicolon-less style的代碼中開發者會把分號放在行的開頭作為前一條語句的安全延續標記從而避免 ASI自動分號插入帶來的歧義foo() ;[1, 2, 3].forEach(bar)semi-style規則的作用就是檢查分號周圍的行終止符換行符強制分號出現在你配置的位置。它關注的是分號位于行首還是行尾而非是否寫分號——后者由semi規則負責。因此semi-style通常與semi配合使用semi決定分號的有無semi-style決定分號的方位。該規則在 ESLint 官方分類中屬于layout布局類規則默認不推薦啟用recommended: false支持--fix自動修復fixable: whitespace。其元數據可在 lib/rules/semi-style.js 中查看type: layout影響代碼排版而非邏輯正確性schema: [{ enum: [last, first] }]唯一合法選項值只有last與firstfixable: whitespace表示修復屬于空白類變更不會改變語義報錯信息expectedSemiColon文本為Expected this semicolon to be at {{pos}}.其中{{pos}}會被替換為 the end of the previous line 或 the beginning of the next line。配置選項規則接受一個字符串選項默認值為last。在 flat config 或 eslintrc 配置文件中寫法如下{ semi-style: [error, last] }兩種選項的語義選項含義說明last默認強制分號位于語句末尾上一行行尾符合常規書寫習慣first強制分號位于語句開頭下一行行首適用于無分號風格代碼重要特例即使使用first選項for循環頭for(a;b;c){}中的分號也必須放在行尾。這是由源碼中的ForStatement處理器硬性規定的詳見下文源碼實現章節因為for頭部的兩個分號在語法上必須分隔三個表達式無法采用行首分號的寫法。從源碼看選項的讀取邏輯為const option context.options[0] || last;lib/rules/semi-style.js即未提供選項時自動回退到last。用法示例選項last默認不正確的代碼示例/*eslint semi-style: [error, last]*/ foo() ;[1, 2, 3].forEach(bar) for ( var i 0 ; i 10 ; i ) { foo() } class C { static { foo() ;bar() } }以上代碼中分號被放在了行首違反了last要求。其中for循環頭的分號位于行首; i 10、; i類靜態塊內;bar()的行首分號同樣違規。正確的代碼示例/*eslint semi-style: [error, last]*/ foo(); [1, 2, 3].forEach(bar) for ( var i 0; i 10; i ) { foo() } class C { static { foo(); bar() } }注意第二行[1, 2, 3].forEach(bar)末尾沒有分號也能通過檢查——semi-style只約束已存在的分號的位置不要求必須寫分號。選項first不正確的代碼示例/*eslint semi-style: [error, first]*/ foo(); [1, 2, 3].forEach(bar) for ( var i 0 ; i 10 ; i ) { foo() } class C { static { foo(); bar() } }在此配置下foo();行尾的分號違規應移到下一行行首但for循環頭即使使用first分號依然必須留在行尾此處; i 10放在行首屬于另一類違規見下文源碼說明——實際上該示例同時觸發了對for頭分號的last檢查類靜態塊中foo();的行尾分號同樣違規。正確的代碼示例/*eslint semi-style: [error, first]*/ foo() ;[1, 2, 3].forEach(bar) for ( var i 0; i 10; i ) { foo() } class C { static { foo() ;bar() } }在first模式下只有for循環頭的兩個分號保持在行尾var i 0;、i 10;普通語句的分號均位于行首。源碼實現規則是如何工作的semi-style的實現位于 lib/rules/semi-style.js核心邏輯可以拆解為三個部分。1. 監聽哪些節點規則通過一個 CSS 選擇器字符串SELECTOR批量監聽 13 種語句節點類型lib/rules/semi-style.jsBreakStatement, ContinueStatement, DebuggerStatement, DoWhileStatement, ExportAllDeclaration, ExportDefaultDeclaration, ExportNamedDeclaration, ExpressionStatement, ImportDeclaration, ReturnStatement, ThrowStatement, VariableDeclaration, PropertyDefinition這些節點覆蓋了幾乎所有的以分號結尾的語句類型包括import/export聲明、return/throw、變量聲明以及 ES2022 的類字段PropertyDefinition。2. 檢查單個分號 tokencheck(semiToken, expected)函數lib/rules/semi-style.js是核心檢查器取分號前后的兩個 token判斷分號與前一個 tokenprevIsSameLine、與后一個 tokennextIsSameLine是否在同一行若expected last且分號與前一個 token 不在同一行或expected first且分號與后一個 token 不在同一行則上報錯誤行內判斷復用 lib/rules/utils/ast-utils.js 中的isTokenOnSameLine工具函數分號識別使用isSemicolonToken。自動修復邏輯修復器會先檢查分號前后 token 之間是否存在注釋sourceCode.commentsExistBetween若存在注釋則拒絕修復返回null避免破壞注釋否則將分號與其前/后 token 之間的整個區間替換為;\nlast模式或\n;first模式。這正是測試中foo\n;bar被修復為foo;\nbar的底層原因。3. 兩個特殊處理塊尾節點與 for 循環頭塊尾節點豁免isLastChild函數lib/rules/semi-style.js負責判斷節點是否為父塊的最后一條語句。當選項為first且節點是塊內最后一條語句時規則直接跳過——因為塊的}后面已經緊跟換行行首分號無從談起。該函數識別以下情況IfStatement的consequent且存在alternate即else分支之前DoWhileStatement的循環體while關鍵字之前BlockStatement、StaticBlock、Program、ClassBody的body最后一項、SwitchCase的consequent最后一項即}之前。for 循環頭固定為lastForStatement處理器lib/rules/semi-style.js獨立于選項設置無論配置為last還是first都強制要求for頭部的兩個分號位于行尾。這正是文檔中即使使用first選項for循環頭的分號也應位于行尾這一規則在實現層的落實。邊界情況與測試佐證規則的測試集位于 tests/lib/rules/semi-style.js共覆蓋 741 行測試用例值得關注幾類邊界行為空語句與連續分號;、;foo;bar;baz;在兩種選項下都視為合法說明規則允許獨立分號語句的存在。do...while與if...elsedo foo; while (a)中foo;的行尾分號在first模式下合法因為位于while關鍵字之前屬于isLastChild豁免if (a) foo; else bar同理。注釋阻止自動修復測試中foo\n;/**/bar、foo;\n/**/bar的output均為null即規則會報告錯誤但拒絕提供修復驗證了分號與注釋相鄰時不修復的保護機制。類靜態塊與類字段ES2022 語法的類字段PropertyDefinition和類靜態塊StaticBlock均被納入檢查范圍測試覆蓋了class C { static { foo\n; } }修復為class C { static { foo;\n} }等場景。for頭多行換行for(a\n;b;c)d在兩種選項下都會被修復為for(a;\nb;c)d確認for頭分號始終以last標準檢查。與相關規則的協同semi-style的 frontmatter 聲明了三個相關規則見 docs/src/rules/semi-style.mdno-extra-semi禁止多余分號防止;;;之類的冗余寫法semi控制是否要求分號always/never及單行塊等細節選項semi-spacing約束分號與相鄰 token 之間的空白字符。實踐中推薦的組合semi決定分號有無semi-style決定分號方位行尾/行首semi-spacing決定分號兩側是否留空格三個規則各司其職、互不重疊。棄用狀態與遷移指引需要特別說明的是semi-style已在 ESLintv8.53.0起被標記為棄用計劃可用至v11.0.0隨后將從 ESLint 核心中移除。原因正如源碼元數據lib/rules/semi-style.js所寫格式類規則正在從 ESLint 核心移出交由其繼任者 ESLint Stylistic 項目維護。官方給出的替換方案是stylistic/eslint-plugin中的同名規則semi-style。因此如果項目使用的是 ESLint v8.53.0 及以上版本建議新項目直接使用stylistic/eslint-plugin中的對應規則或在舊項目升級時同步遷移避免規則在 v11.0.0 被移除后失效。若仍需在 ESLint 核心中使用該規則的文檔即本文所講解的 docs/src/rules/semi-style.md其配置與行為不因棄用而改變。何時不使用此規則如果你不關心分號位于行首還是行尾即不想收到關于分號位置的通知那么可以安全地關閉禁用此規則。在 flat config 中{ rules: { semi-style: off, }, }特別地對于無分號風格的代碼庫如果團隊統一遵循ASI 由換行符自然處理的約定且不愿采用行首分號的防御性寫法semi-style同樣不是必需品只有當你明確要求分號必須錨定在行尾last或行首first時才值得啟用。【免費下載鏈接】eslintFind and fix problems in your JavaScript code.項目地址: https://gitcode.com/GitHub_Trending/es/eslint創作聲明:本文部分內容由AI輔助生成(AIGC),僅供參考