版本

自訂規則教學

本教學涵蓋如何為 ESLint 建立自訂規則,並透過外掛程式發布它。

您可以建立自訂規則來驗證您的程式碼是否符合特定期望,並決定在不符合期望時該怎麼做。外掛程式封裝了自訂規則和其他設定,讓您可以輕鬆地在不同的專案中分享和重複使用它們。

若要深入瞭解自訂規則和外掛程式,請參閱以下文件

為何建立自訂規則?

如果 ESLint 的內建規則和社群發布的自訂規則無法滿足您的需求,請建立自訂規則。您可以建立自訂規則來強制執行貴公司或專案的最佳實務、防止特定錯誤再次發生,或確保符合樣式指南。

在建立並非特定於您的公司或專案的自訂規則之前,值得在網路上搜尋看看是否有人發布了外掛程式,其中包含可以解決您的用例的自訂規則。該規則很有可能已經存在。

先決條件

在開始之前,請確保您的開發環境中已安裝以下項目

本教學也假設您對 ESLint 和 ESLint 規則有基本的了解。

自訂規則

本教學中的自訂規則要求所有名為 fooconst 變數都必須被賦予字串字面值 "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。在對應的欄位中新增以下內容

  1. "name":套件的唯一名稱。npm 上沒有其他套件可以具有相同的名稱。
  2. "main":外掛程式檔案的相對路徑。依照此範例,路徑為 "eslint-plugin-example.js"
  3. "description":套件的描述,可在 npm 上檢視。
  4. "peerDependencies":新增 "eslint": ">=9.0.0" 作為同層級依賴項。任何大於或等於該版本的版本都是使用外掛程式所必需的。將 eslint 宣告為同層級依賴項要求使用者將套件與外掛程式分開新增至專案。
  5. "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!
}

摘要

在本教學中,您建立了一個自訂規則,該規則要求所有名為 fooconst 變數都必須被賦予字串 "bar",並建議將賦予 const foo 的任何其他值替換為 "bar"。您也已將該規則新增至外掛程式,並在 npm 上發布了該外掛程式。

透過這樣做,您學習了以下實務,您可以將其應用於建立其他自訂規則和外掛程式

  1. 建立自訂 ESLint 規則
  2. 測試自訂規則
  3. 將規則捆綁到外掛程式中
  4. 發布外掛程式
  5. 從外掛程式中使用規則

檢視教學程式碼

您可以在這裡檢視本教學的註解原始碼。

變更語言