如何編寫你的第一個ESLint插件(翻譯)

翻譯自 《How To Write Your First ESLint Plugin》
推薦理由:言簡意駭,是我入門ESLint的啟蒙文章??

本文是ESLint插件(Plugins)的簡單介紹指南,包括它們是如何工作的,如何配置、編寫和如何使用一個插件的。

什么是ESLint插件

它是ESLint的一個外部拓展,強制執(zhí)行一些規(guī)則(rules),不是寫在ESLint核心(core)里的。舉個例子,大家都比較熟悉的插件eslint-plugin-babel支持了ESLint核心中沒有的實驗性功能和linter(改進代碼的工具)。??插件通常存儲為單獨的NPM模塊,它導出rule對象,其中key是規(guī)則名稱,value是另一個具有強制執(zhí)行規(guī)則方法的對象:??

module.exports = {
    rules: {
        "rule-name": {
            create: function (context) {
                // rule implementation ...
            }
        }
    }
};

為什么你需要關心自己去寫一個?

NPM已現(xiàn)存有非常多的插件,找到你需要的插件的概率會很高。但是在某些情況下,你可能需要針對你的代碼庫制定非常具體的規(guī)則。
最近,我們的開發(fā)團隊決定強制執(zhí)行關于異步函數(shù)的命名規(guī)范。這意味著,如果某個函數(shù)返回一個promise或有一個async聲明前綴,那么這個函數(shù)命名必須有一個固定Async后綴:function someFunctionAsync()。
讓我們以此為例,編寫一個可以警告函數(shù)命名錯誤的ESLint插件,

創(chuàng)建一個插件

在本教程中,我們將創(chuàng)建一個本地插件包并在簡單的node應用中使用。項目結(jié)構(gòu)如下所示:

plugin-tutorial 
│
└───my-eslint-rules
│   │   package.json
│   │   index.js
│   
└───node-app
    │   package.json
    │   index.js

首先創(chuàng)建主文件夾 mkdir plugin-tutorial && cd plugin-tutorial

配置插件包

每一個有效的插件都應該滿足以下條件:

  • 單獨的NPM包
  • 遵循eslint-plugin-<plugin-name>的命名格式
  • 導出rules對象
  1. 創(chuàng)建插件項目(plugin package): mkdir my-eslint-rules && cd my-eslint-rules && npm init --yes
  2. package.json中為其命名: { "name": "eslint-plugin-my-eslint-rules" }
  3. 創(chuàng)建index.js入口文件并導出自定義規(guī)則rules對象,暫命名為async-func-name
module.exports = {
  rules: {
    "async-func-name": {
      create: function (context) {
        return { /* ...rule methods */ }
      }
    }
  }
};

編寫rule規(guī)則對象

為了構(gòu)建和測試規(guī)則,我們將使用一個工具AST explorer
AST代表抽象語法樹或者語法書,它是源代碼的抽象語法結(jié)構(gòu)的樹狀表現(xiàn)形式。 [注1]

將AST Explorer的解析器(parser)設置為eslint-babel和轉(zhuǎn)換器(transformer)設置為ESLint v4。

現(xiàn)在在資源管理器中可以看到四個窗口:

  • 左上角的窗口將用于編寫源代碼(source code)
  • 右上角的窗口是源代碼的資源管理器。將鼠標懸停在表達式上時,你可以看到代碼中突出顯示的部分
  • 左下角就是我們要調(diào)試編輯的規(guī)則代碼
  • 右下角是規(guī)則后的輸出,與源代碼同步更新運行
https://astexplorer.net/

規(guī)則函數(shù)會接受一個參數(shù)為context的對象,該對象包含了關于規(guī)則上下文相關的附加功能和信息。

主要方法是context.report(),
你將使用的主要方法是 context.report(),它用來發(fā)布警告或錯誤(取決于你所使用的配置)。該方法只接收一個參數(shù),是個對象,包含以下屬性:message,node, loc, data, fix [注2]
最簡單的示例是只使用 nodemessage

context.report({
    node: node,
    message: "Async function name must end in 'Async'"
});

該規(guī)則必須返回一個對象,其中包含ESLint再遍歷源代碼語法樹時調(diào)用的visitor節(jié)點的方法。
在我們的示例中,有一個方法FunctionDeclaration,它接受一個node對象參數(shù),該節(jié)點對象包含了函數(shù)信息,例如type(類型)、name(名稱)、body(主體)、locations(每個值的位置)。

要檢查函數(shù)名稱是否具有Async后綴,我們需要訪問名稱,該名稱位于FunctionDeclaration節(jié)點的id對象中:node.id.name

所以規(guī)則的主要邏輯應該是檢查函數(shù)是否有async屬性,如果不包含Async后綴,則調(diào)用context.report()方法。

應用規(guī)則后,AST explorer輸出警告消息:

rule function

在資源管理器中編寫規(guī)則并確保它捕獲到正確的規(guī)則條件后,將邏輯代碼復制到插件包的index.js中,即完成插件:

module.exports = {
  rules: {
    "async-func-name": {
      create: function (context) {
        return {
          FunctionDeclaration(node) {
            if (node.async && !/Async$/.test(node.id.name)) {
              context.report({
                node,
                message: "Async function name must end in 'Async'"
              });
            }
          }
        }
      }
    }
  }
};

將插件應用到項目中

首先,項目需要這樣配置:

  • plugin-tutorial執(zhí)行命令mkdir node-app && cd node-app && npm init --yes && touch index.js,并將AST explorer中的實例代碼加入到index.js中:
async function myFunction() {
    return "";
}
  • 安裝ESLint依賴npm i eslint --save-dev
  • 安裝剛剛創(chuàng)建的插件:npm i ../my-eslint-rules --save-dev
  • 通過創(chuàng)建配置文件.eslintrc告訴應用程序需要使用到的ESLint規(guī)則與插件
{
  "parserOptions": {
    "ecmaVersion": 2018
  },
  "rules": {
    "my-eslint-rules/async-func-name": "warn"
  },
  "plugins": ["my-eslint-rules"]
}
  • 在項目應用程序文件夾中打開終端并運行ESLint命令:./node_modules/.bin/eslint index.js

差不多就是這樣。如何您為異步函數(shù)設置了錯誤的名稱,您應該在終端中運行它后看到ESLint警告。

在項目中使用插件的重要部分是.eslintrc配置文件。插件的命名規(guī)則應該遵循"<plugin-name>/<rule-name>": [warn/error]。插件名稱應添加到數(shù)組plugins字段中。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容