自訂規則教學
本教學涵蓋如何為 ESLint 建立自訂規則,並透過外掛程式發布它。
您可以建立自訂規則來驗證您的程式碼是否符合特定期望,並決定在不符合期望時該怎麼做。外掛程式封裝了自訂規則和其他設定,讓您可以輕鬆地在不同的專案中分享和重複使用它們。
若要深入瞭解自訂規則和外掛程式,請參閱以下文件
為何建立自訂規則?
如果 ESLint 的內建規則和社群發布的自訂規則無法滿足您的需求,請建立自訂規則。您可以建立自訂規則來強制執行貴公司或專案的最佳實務、防止特定錯誤再次發生,或確保符合樣式指南。
在建立並非特定於您的公司或專案的自訂規則之前,值得在網路上搜尋看看是否有人發布了外掛程式,其中包含可以解決您的用例的自訂規則。該規則很有可能已經存在。
先決條件
在開始之前,請確保您的開發環境中已安裝以下項目
本教學也假設您對 ESLint 和 ESLint 規則有基本的了解。
自訂規則
本教學中的自訂規則要求所有名為 foo
的 const
變數都必須被賦予字串字面值 "bar"
。該規則定義在檔案 enforce-foo-bar.js
中。該規則也建議將賦予 const foo
的任何其他值替換為 "bar"
。
例如,假設您有以下 foo.js
檔案
// foo.js
const foo = "baz123";
使用該規則執行 ESLint 會將 "baz123"
標記為變數 foo
的不正確值。如果 ESLint 在自動修正模式下執行,則 ESLint 會修正該檔案以包含以下內容
// foo.js
const foo = "bar";
步驟 1:設定您的專案
首先,為您的自訂規則建立一個新專案。建立一個新目錄,在其中初始化一個新的 npm 專案,並為自訂規則建立一個新檔案
mkdir eslint-custom-rule-example # create directory
cd eslint-custom-rule-example # enter the directory
npm init -y # init new npm project
touch enforce-foo-bar.js # create file enforce-foo-bar.js
步驟 2:建立規則檔案的骨架
在 enforce-foo-bar.js
檔案中,為 enforce-foo-bar
自訂規則新增一些骨架。此外,新增一個包含規則基本資訊的 meta
物件。
// enforce-foo-bar.js
module.exports = {
meta: {
// TODO: add metadata
},
create(context) {
return {
// TODO: add callback function(s)
};
}
};
步驟 3:新增規則元數據
在撰寫規則之前,請將一些元數據新增至規則物件。ESLint 在執行規則時會使用此資訊。
首先匯出一個物件,其中包含一個 meta
屬性,該屬性包含規則的元數據,例如規則類型、文件和可修正性。在本例中,規則類型為「problem」,描述為「強制名為 foo
的變數只能被賦予值 ‘bar’。」,且該規則可透過修改程式碼來修正。
// enforce-foo-bar.js
module.exports = {
meta: {
type: "problem",
docs: {
description: "Enforce that a variable named `foo` can only be assigned a value of 'bar'.",
},
fixable: "code",
schema: []
},
create(context) {
return {
// TODO: add callback function(s)
};
}
};
若要深入瞭解規則元數據,請參閱規則結構。
步驟 4:新增規則訪問器方法
定義規則的 create
函式,該函式接受一個 context
物件,並傳回一個物件,其中每個語法節點類型都有一個屬性,您想要處理這些節點類型。在本例中,您想要處理 VariableDeclarator
節點。您可以選擇任何 ESTree 節點類型或選擇器。
在 VariableDeclarator
訪問器方法中,檢查節點是否表示 const
變數宣告、其名稱是否為 foo
,以及是否未被賦予字串 "bar"
。您可以透過評估傳遞給 VariableDeclaration
方法的 node
來執行此操作。
如果 const foo
宣告被賦予值 "bar"
,則規則不執行任何操作。如果 const foo
未被賦予值 "bar"
,則 context.report()
會向 ESLint 回報錯誤。錯誤報告包含有關錯誤以及如何修正它的資訊。
// enforce-foo-bar.js
module.exports = {
meta: {
type: "problem",
docs: {
description: "Enforce that a variable named `foo` can only be assigned a value of 'bar'."
},
fixable: "code",
schema: []
},
create(context) {
return {
// Performs action in the function on every variable declarator
VariableDeclarator(node) {
// Check if a `const` variable declaration
if (node.parent.kind === "const") {
// Check if variable name is `foo`
if (node.id.type === "Identifier" && node.id.name === "foo") {
// Check if value of variable is "bar"
if (node.init && node.init.type === "Literal" && node.init.value !== "bar") {
/*
* Report error to ESLint. Error message uses
* a message placeholder to include the incorrect value
* in the error message.
* Also includes a `fix(fixer)` function that replaces
* any values assigned to `const foo` with "bar".
*/
context.report({
node,
message: 'Value other than "bar" assigned to `const foo`. Unexpected value: {{ notBar }}.',
data: {
notBar: node.init.value
},
fix(fixer) {
return fixer.replaceText(node.init, '"bar"');
}
});
}
}
}
}
};
}
};
步驟 5:設定測試
撰寫完規則後,您可以測試它以確保它如預期般運作。
ESLint 提供了內建的 RuleTester
類別來測試規則。您不需要使用第三方測試函式庫來測試 ESLint 規則,但 RuleTester
可以與 Mocha 和 Jest 等工具無縫協作。
接下來,為測試建立檔案 enforce-foo-bar.test.js
touch enforce-foo-bar.test.js
您將在測試檔案中使用 eslint
套件。將其安裝為開發依賴項
npm
npm install --save-dev eslint
yarn
yarn add --dev eslint
pnpm
pnpm add --save-dev eslint
bun
bun add --dev eslint
並將測試指令碼新增至您的 package.json
檔案以執行測試
// package.json
{
// ...other configuration
"scripts": {
"test": "node enforce-foo-bar.test.js"
},
// ...other configuration
}
步驟 6:撰寫測試
若要使用 RuleTester
撰寫測試,請將該類別和您的自訂規則匯入到 enforce-foo-bar.test.js
檔案中。
RuleTester#run()
方法會針對有效和無效的測試案例測試規則。如果規則未能通過任何測試情境,此方法會擲回錯誤。RuleTester
要求至少存在一個有效和一個無效的測試情境。
// enforce-foo-bar.test.js
const {RuleTester} = require("eslint");
const fooBarRule = require("./enforce-foo-bar");
const ruleTester = new RuleTester({
// Must use at least ecmaVersion 2015 because
// that's when `const` variables were introduced.
languageOptions: { ecmaVersion: 2015 }
});
// Throws error if the tests in ruleTester.run() do not pass
ruleTester.run(
"enforce-foo-bar", // rule name
fooBarRule, // rule code
{ // checks
// 'valid' checks cases that should pass
valid: [{
code: "const foo = 'bar';",
}],
// 'invalid' checks cases that should not pass
invalid: [{
code: "const foo = 'baz';",
output: 'const foo = "bar";',
errors: 1,
}],
}
);
console.log("All tests passed!");
使用以下指令執行測試
npm test
如果測試通過,您應該會在主控台中看到以下內容
All tests passed!
步驟 7:將自訂規則捆綁到外掛程式中
現在您已撰寫了自訂規則並驗證其運作正常,您可以將其包含在外掛程式中。使用外掛程式,您可以在 npm 套件中分享該規則,以便在其他專案中使用。
為外掛程式建立檔案
touch eslint-plugin-example.js
現在撰寫外掛程式碼。外掛程式只是匯出的 JavaScript 物件。若要將規則包含在外掛程式中,請將其包含在外掛程式的 rules
物件中,該物件包含規則名稱及其原始碼的鍵值對。
若要深入瞭解如何建立外掛程式,請參閱建立外掛程式。
// eslint-plugin-example.js
const fooBarRule = require("./enforce-foo-bar");
const plugin = { rules: { "enforce-foo-bar": fooBarRule } };
module.exports = plugin;
步驟 8:在本機使用外掛程式
您可以使用本機定義的外掛程式在您的專案中執行自訂規則。若要使用本機外掛程式,請在您的 ESLint 設定檔的 plugins
屬性中指定外掛程式的路徑。
您可能想要在以下其中一種情境中使用本機定義的外掛程式
- 您想要在將外掛程式發布到 npm 之前對其進行測試。
- 您想要使用外掛程式,但不想要將其發布到 npm。
在您可以將外掛程式新增至專案之前,請使用扁平化設定檔 eslint.config.js
為您的專案建立 ESLint 設定
touch eslint.config.js
然後,將以下程式碼新增至 eslint.config.js
// eslint.config.js
"use strict";
// Import the ESLint plugin locally
const eslintPluginExample = require("./eslint-plugin-example");
module.exports = [
{
files: ["**/*.js"],
languageOptions: {
sourceType: "commonjs",
ecmaVersion: "latest",
},
// Using the eslint-plugin-example plugin defined locally
plugins: {"example": eslintPluginExample},
rules: {
"example/enforce-foo-bar": "error",
},
}
]
在您可以測試規則之前,您必須建立一個檔案來測試該規則。
建立檔案 example.js
touch example.js
將以下程式碼新增至 example.js
// example.js
function correctFooBar() {
const foo = "bar";
}
function incorrectFoo(){
const foo = "baz"; // Problem!
}
現在您可以準備好使用本機定義的外掛程式測試自訂規則。
在 example.js
上執行 ESLint
npm
npx eslint example.js
yarn
yarn dlx eslint example.js
pnpm
pnpm dlx eslint example.js
bun
bunx eslint example.js
這會在終端機中產生以下輸出
/<path-to-directory>/eslint-custom-rule-example/example.js
8:11 error Value other than "bar" assigned to `const foo`. Unexpected value: baz example/enforce-foo-bar
✖ 1 problem (1 error, 0 warnings)
1 error and 0 warnings potentially fixable with the `--fix` option.
步驟 9:發布外掛程式
若要將包含規則的外掛程式發布到 npm,您需要設定 package.json
。在對應的欄位中新增以下內容
"name"
:套件的唯一名稱。npm 上沒有其他套件可以具有相同的名稱。"main"
:外掛程式檔案的相對路徑。依照此範例,路徑為"eslint-plugin-example.js"
。"description"
:套件的描述,可在 npm 上檢視。"peerDependencies"
:新增"eslint": ">=9.0.0"
作為同層級依賴項。任何大於或等於該版本的版本都是使用外掛程式所必需的。將eslint
宣告為同層級依賴項要求使用者將套件與外掛程式分開新增至專案。"keywords"
:包含標準關鍵字["eslint", "eslintplugin", "eslint-plugin"]
,讓套件容易找到。您也可以新增任何其他可能與您的外掛程式相關的關鍵字。
外掛程式的 package.json
檔案應有的完整註解範例
// package.json
{
// Name npm package.
// Add your own package name. eslint-plugin-example is taken!
"name": "eslint-plugin-example",
"version": "1.0.0",
"description": "ESLint plugin for enforce-foo-bar rule.",
"main": "eslint-plugin-example.js", // plugin entry point
"scripts": {
"test": "node enforce-foo-bar.test.js"
},
// Add eslint>=9.0.0 as a peer dependency.
"peerDependencies": {
"eslint": ">=9.0.0"
},
// Add these standard keywords to make plugin easy to find!
"keywords": [
"eslint",
"eslintplugin",
"eslint-plugin"
],
"author": "",
"license": "ISC",
"devDependencies": {
"eslint": "^9.0.0"
}
}
若要發布套件,請執行 npm publish
並依照 CLI 提示操作。
您應該會在 npm 上看到該套件上線!
步驟 10:使用已發布的自訂規則
接下來,您可以使用已發布的外掛程式。
在您的專案中執行以下指令以下載套件
npm
# Add your package name here
npm install --save-dev eslint-plugin-example
yarn
# Add your package name here
yarn add --dev eslint-plugin-example
pnpm
# Add your package name here
pnpm add --save-dev eslint-plugin-example
bun
# Add your package name here
bun add --dev eslint-plugin-example
更新 eslint.config.js
以使用套件化的外掛程式版本
// eslint.config.js
"use strict";
// Import the plugin downloaded from npm
const eslintPluginExample = require("eslint-plugin-example");
// ... rest of configuration
現在您可以準備好測試自訂規則。
在您在步驟 8 中建立的 example.js
檔案上執行 ESLint,現在使用已下載的外掛程式
npm
npx eslint example.js
yarn
yarn dlx eslint example.js
pnpm
pnpm dlx eslint example.js
bun
bunx eslint example.js
這會在終端機中產生以下輸出
/<path-to-directory>/eslint-custom-rule-example/example.js
8:11 error Value other than "bar" assigned to `const foo`. Unexpected value: baz example/enforce-foo-bar
✖ 1 problem (1 error, 0 warnings)
1 error and 0 warnings potentially fixable with the `--fix` option.
如您在上面的訊息中所見,您實際上可以使用 --fix
旗標修正問題,將變數賦值更正為 "bar"
。
再次使用 --fix
旗標執行 ESLint
npm
npx eslint example.js --fix
yarn
yarn dlx eslint example.js --fix
pnpm
pnpm dlx eslint example.js --fix
bun
bunx eslint example.js --fix
當您執行此操作時,終端機中沒有錯誤輸出,但您可以在 example.js
中看到套用的修正。您應該會看到以下內容
// example.js
// ... rest of file
function incorrectFoo(){
const foo = "bar"; // Fixed!
}
摘要
在本教學中,您建立了一個自訂規則,該規則要求所有名為 foo
的 const
變數都必須被賦予字串 "bar"
,並建議將賦予 const foo
的任何其他值替換為 "bar"
。您也已將該規則新增至外掛程式,並在 npm 上發布了該外掛程式。
透過這樣做,您學習了以下實務,您可以將其應用於建立其他自訂規則和外掛程式
- 建立自訂 ESLint 規則
- 測試自訂規則
- 將規則捆綁到外掛程式中
- 發布外掛程式
- 從外掛程式中使用規則
檢視教學程式碼
您可以在這裡檢視本教學的註解原始碼。