隱藏在 Eslint 的 fix 功能中的可以用來面試的算法題

2022-01-30 神光的編程秘籍

我們知道 eslint 支持 fix,當添加了 --fix 參數部分 rule 可以自動修復問題。

有沒有想過,這種功能是怎麼實現的?babel 也能轉換代碼,它和 eslint 生成代碼的原理一樣麼?

babel

babel 分為 parse、transform、generate 3 步。

在 transform 階段轉換完 AST 代碼之後,在 generate 階段會遞歸列印 AST 成目標代碼。

generate 的原理就是遞歸根據每個 AST 的信息拼接字符串:

所以我們在插件裡面改動了 AST,最終的代碼也會改。

eslint

eslint 的 rule 可以對 AST 進行檢查,然後通過 context.report 報錯,還可以指定如何修復:

自定義 rule 格式如下:

module.exports = {
     meta: {
         fixable: true
     },
     create(context) {
         return {
            // 指定 AST 的類型
            ObjectExpression(node) {
                // 一系列檢查
                context.report({
                    node,
                    message: 'xxx 有錯誤',
                    loc: node.loc,
                    *fix(fixer) {
                        yield fixer.replaceTextRange([rangeStart,rangeEnd], '替換的文本');
                    }
                });
             }
         };
     }
 };

其中 fix 選項就是用於問題自動修復的,通過 fixer 的 api。

fixer 有這些 api 可用:

insertTextAfter(nodeOrToken, text);
insertTextAfterRange(range, text);
insertTextBefore(nodeOrToken, text);
insertTextBeforeRange(range, text);

remove(nodeOrToken);
removeRange(range);

replaceText(nodeOrToken, text);
replaceTextRange(range, text);

特別容易記,就是增、刪、改 3類,增分為在前面插入和在後面插入,每一類都支持基於 token 來修改 text 或者基於 range(下標範圍)。

AST 中每個節點都保留了 range 的信息,也就是在原始碼的下標是從哪到哪,這樣就可以根據 range 來修改代碼,或者根據 AST 查到 range 再去修改代碼。

那知道了對什麼 range 做什麼操作之後,是怎麼自動修改代碼的呢?

下面是 eslint 中 fix 代碼的源碼:

// 源碼
const originalText = sourceCode.text;
// 第一個 range 的開始
const start = fixes[0].range[0];
// 最後一個 range 的結束
const end = fixes[fixes.length - 1].range[1];
// 替換的文本
let text = "";
let lastPos = Number.MIN_SAFE_INTEGER;

for (const fix of fixes) {
    if (fix.range[0] >= 0) {
        // 截取 range 的左邊的字符串,從當前 range 和 上一個 range 的右邊位置取大的
        text += originalText.slice(Math.max(0, start, lastPos), fix.range[0]);
    }
    // 拼接上修復的文本
    text += fix.text;
    // range 右邊的位置
    lastPos = fix.range[1];
}
// 用拼接的字符串替換 range 內的字符串
text += originalText.slice(Math.max(0, start, lastPos), end);

其中比較有意思的一個點是當兩端 range 有交集的時候:

每一個 fix 都是對一個線段(range)內文本的修復,當有交集的時候怎麼處理,這其實可以作為一個算法題來考核候選人了。

從左到右應用 fix,然後記錄當前的 rangeRight,應用下一段的時候就取 rangeLeft 和上一個 rangeRight 的最大值作為 rangeLeft。

把這個問題抽象出來之後還是一個比較有意思的算法題,我覺得用來面試比較不錯,而且有真實的應用場景。

聊回正題,fix 功能的實現就是對每段 range 修改的文本進行拼接,然後替換源碼字符串就可以了。

總結

babel 和 eslint 都可以修改代碼,babel 是操作了 AST,列印代碼的時候就會生成不同的代碼,而 eslint 則是一部分 rule 支持自動 fix,當開啟了 --fix 的時候就會自動修復。

babel 生成代碼的原理是遞歸列印 AST,拼接字符串,所以改了 AST,生成的代碼就改了。

eslint 修復代碼的邏輯是對某段 range 的文本做替換,之後拼接,這個與 AST 無關,所以 eslint 的 fix 功能是可選的。

比較有意思的是 eslint 的多個 rule 返回的對多段range 的修改如何應用到對代碼修改上,當有交集的時候怎麼辦,我覺得這個問題可以作為算法題來考查面試者了。

相關焦點

  • Eslint 的實現原理,其實挺簡單
    LinterLinter 是 eslint 最核心的類了,它提供了這幾個 api:verify // 檢查verifyAndFix // 檢查並修復getSourceCode // 獲取 ASTdefineParser // 定義 ParserdefineRule // 定義 RulegetRules // 獲取所有的
  • 一文徹底讀懂ESLint
    >}這裡有一個--fix後綴,是ESLint提供自動修復基礎錯誤的功能,我們運行lint:fix後發現有一些報錯信息消失了,代碼也改變了;不過它只能修復一些基礎的不影響代碼邏輯的錯誤,比如代碼末尾加上分號、表達式的空格等等。
  • 為什麼 Eslint 可以檢查和修復格式問題,而 Babel 不可以?
    Eslint 可以檢查出代碼中的錯誤和一些格式問題,並能自動修復,它的實現原理就是基於 AST (抽象語法樹)。通過 Parser 把源碼解析成 AST 對象樹,源碼字符串中的各種信息就被保存到了這個對象樹裡,然後遍歷 AST,對每一部分做檢查就能實現 Lint 的功能,而自動 fix 的功能則是基於字符串替換實現的,指定某一段 range,替換成另一段文本即可。
  • 給 eslint 寫一個插件
    linter 是一種代碼靜態分析工具,它可以幫你找到代碼中可能存在的錯誤與 bug,也能找出代碼風格的問題,不過因為只是靜態分析,對 js 這種動態類型的語言所能做的就比較有限了,畢竟在 js 中,變量的類型如果不執行就不容易知道,有些錯誤就不那麼容易被找出來,雖然如此,能做的檢查還是很多了。
  • 深入對比 eslint 插件 和 babel 插件的異同點
    我們從中能總結出 babel 插件的特點:插件的形式是函數返回一個對象,對象的 visitor 屬性聲明對什麼節點做什麼處理visitor 函數可以通過 path 的 api 來對 ast 增刪改eslint 插件eslint 插件也會對代碼進行 parse,查找要檢查的 AST,之後進行檢查和報錯,但不一定會修復代碼,只有指定了 fix 才會進行修復。
  • 在Typescript項目中,如何優雅的使用ESLint和Prettier
    prettier/@typescript-eslint:使得@typescript-eslint中的樣式規範失效,遵循prettier中的樣式規範plugin:prettier/recommended:使用prettier中的樣式規範,且如果使得ESLint會檢測prettier的格式問題,同樣將格式問題以error的形式拋出四、在VSCode中集成ESLint配置
  • 使用ESLint+Prettier來統一前端代碼風格
    {  "plugins": ["prettier"],  "rules": {    "prettier/prettier": "error"  }}藉助ESLint的autofix功能,在保存代碼的時候,自動將拋出error的地方進行fix。
  • 我是如何在公司項目中使用ESLint來提升代碼質量的
    next安裝時必須指定標籤:npm i eslint@next --save-dev這句命令從 npm 倉庫安裝了 ESLint CLI,如果想嘗試下新功能的童鞋可以安裝搗鼓一番。為什麼我們要在項目中使用ESLintESLint可以校驗我們寫的代碼,給代碼定義一個規範,項目裡的代碼必須按照這個規範寫。
  • 領略 Eslint 代碼檢查的四種姿勢
    概念言簡意賅,需要注意的是,概念中說到 eslint 是一個插件化的檢查工具,其意思是指 eslint 的設計是把檢查工具和檢查規則之間解耦了。也就是說,在安裝好 eslint 的開發依賴之後,我們還可以並且需要選擇安裝一個我們中意的檢查規則。
  • 代碼規範之-理解ESLint、Prettier、EditorConfig
    與Java等程式語言不同,JavaScript作為弱類型的動態語言,因為缺少編譯階段,有些本可以在編譯過程中發現的錯誤,只能等到運行時才發現,這給我們調試和提前發現隱藏問題增加了一些難度,而 Lint 工具相當於為js增加了編譯過程,在代碼部署運行前進行靜態分析,找到出錯的地方和不規範的代碼。
  • 面試經驗分享之數據結構、算法題
    刷了好幾遍,不過一些轉發評論者覺得, IT 公司面試中的算法考察沒有價值,一來工作裡用不太上,二來把程式設計師素質考察搞成了應試教育,他們認為更重要的是應聘者的工程能力。若干年前, Google、微軟的面試題讓大家眼前一亮,覺得能選拔出個性十足的聰明人來,不過隨著大家對這類題目的適應,可能選拔出來的人也在趨同,至少很多人都會 在面試前用心準備,據報導 Google 最近也是放棄了這類面試題目。沒有什麼一勞永逸、一成不變的考查方式,畢竟面試是人和人之間的動態「較量」。不要貪戀算法的奇技淫巧,也不要因為題目篩選力度的衰減而否定考察初衷。
  • 求職FLAG必須掌握哪些算法和面試技巧?附「FB最新算法面試題」
    這部分是面試中最難的,因為編程不僅是在高壓環境下進行,而且是以一種不熟悉的方式,比如白板手寫進行的,而且會有時間限制。所以要想通過編程問題面試,一定要提前多刷幾遍lintcode上的算法題。在這道題中,面試官想看到,你是否能對自己的編程過程有一個清晰的思路以及你的組織語言能力。如果說不出來,可能會讓面試官認為你在工作工程中是無序的、沒有計劃的。tips:不要局限自己的想法。這道題是用來測試你的知識面、你是否能清晰的表達自己的想法以及你的視野是否狹隘的。
  • JavaScript中的算法(附10道面試常見算法題解決方法和思路)
    一個算法通常上需要可擴展的。隨著輸入size的增加,函數將如何執行? 是否應該有某種緩存機制嗎? 通常上,需要犧牲內存優化(空間)來換取性能提升(時間)。為了使問題更加具體,畫圖表!當解決方案的具體結構開始出現時,偽代碼就可以開始了。為了給面試官留下深刻印象,請提前尋找重構和重用代碼的機會。
  • clearfix 清除浮動進化史
    但是我發現大型網站中 居然還在使用這種清楚浮動的方法。有興趣的同學可以上他們首頁搜索一下他們的.blank0這個樣式名稱。因此有很多大神就研究出了 clearfix 清除浮動的方法,直接解決了上面的缺陷,不需要增加空標籤,直接在有浮動的外層加上這個樣式就可以了,這也是我們今天要討論的clearfix進化史。
  • 程式設計師面試題,200億個數字找中位數,不給分桶算法,怎麼辦?
    海量數據裡面如何尋找一堆數字的中位數,是一道非常常見的面試題。據稱,這個題目是騰訊前首席技術執行官Tony推崇的一個面試題,被加入的騰訊的面試題題庫。今天我們就來討論下這個題目,有一個存放著200億個數字的文件,存放著32位整型,可能會有重複的數字,現在想從這堆數字中找到他們的中位數。注意,這個題目是只能用單機解決,並且內存只有512M。我們也簡單介紹一下。假如內存足夠,我們當然希望在內存裡面開一個數組或者一個字典Map,用來保存每一個數字與其出現次數的。
  • TOP 48 算法和編程面試題,牛逼啊!
    你在申請這些工作時,肯定很想知道面試官會問到哪些問題。在本文中,作者會分享一些常見的編程面試問題,這些問題來自於針對不同經驗層次的程式設計師的面試——從應屆畢業生到具有一兩年經驗的程式設計師。編程面試題通常包含數據結構和基於算法的問題,以及一些邏輯問題,例如:如何在不使用臨時變量的情況下交換兩個整數?為了清晰,編程面試題需要劃分為不同主題。
  • ESLint進階指南
    然後通過 AST selectors找到靜態代碼中的內容,再根據rule的規則去判斷這一段js是否符合eslint的規範。,在該選擇器中,我們可以獲取對應選中的內容,隨後我們可以針對選中的內容作一定的判斷,看是否滿足我們的規則,如果不滿足,可用 context.report()拋出問題,ESLint 會利用我們的配置對拋出的內容做不同的展示。
  • 【第1495期】 ESLint 工作原理探討
    我在一個項目中嘗試了 ESLint ,輸入 eslint init 後按照提示最終選擇了非常出名的 airbnb 的代碼風格,結果整個項目幾乎所有文件都被標紅,嘗試使用 —fix 卻無法全部修復,內心十分沮喪。現在想想,那時候的我對 ESLint 的認知是不完整的,在那時候的我看來 ESLint 就是輔助我們保持代碼風格一致的工具,airbnb 的 js 風格備受大家推崇。
  • 九章算法班 | 秋招改版,2019最新面試題講解
    ➤➤ IT求職必修90%以上的人都會選修《九章算法班》,即使是已經刷題幾百道的人,也常常在這門課中感受到「醍醐灌頂」。原因很簡單,主講老師刷過的題,超過2000道,所總結的「套路」和「模板」不是刷幾百道的人可以得出的。
  • 百度、阿里、騰訊、京東等面試算法題
    這是無量測試之道的第180篇原創今天給大家分享的是字符串相關的算法面試題。