版本

自訂規則教學

本教學涵蓋如何為 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 install eslint --save-dev

並將測試指令碼新增至您的 `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

npx 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 install --save-dev eslint-plugin-example # Add your package name here

更新 `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,現在使用下載的外掛程式

npx 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

npx eslint example.js --fix

當您執行此操作時,終端機中沒有錯誤輸出,但您可以在 `example.js` 中看到套用的修正。您應該會看到以下內容

// example.js

// ... rest of file

function incorrectFoo(){
  const foo = "bar"; // Fixed!
}

總結

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

透過執行此操作,您已學習以下做法,您可以套用這些做法來建立其他自訂規則和外掛程式

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

檢視教學程式碼

您可以在這裡檢視教學的標注原始程式碼。

變更語言