翻譯自 《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對象
- 創(chuàng)建插件項目(plugin package):
mkdir my-eslint-rules && cd my-eslint-rules && npm init --yes - 在
package.json中為其命名:{ "name": "eslint-plugin-my-eslint-rules" } - 創(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ī)則后的輸出,與源代碼同步更新運行

規(guī)則函數(shù)會接受一個參數(shù)為context的對象,該對象包含了關于規(guī)則上下文相關的附加功能和信息。
主要方法是context.report(),
你將使用的主要方法是 context.report(),它用來發(fā)布警告或錯誤(取決于你所使用的配置)。該方法只接收一個參數(shù),是個對象,包含以下屬性:message,node, loc, data, fix [注2]
最簡單的示例是只使用 node 和 message:
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輸出警告消息:

在資源管理器中編寫規(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字段中。