Эта история изначально была опубликована здесь.

Эта статья основана на ESLint v8.28.0.

ESLint — это инструмент линтинга по умолчанию в экосистеме JavaScript/TypeScript. ESLint постоянно запускает набор правил для обнаружения проблем и, в зависимости от правила, позволяет автоматически исправить проблему. Эти правила можно импортировать из других проектов или расширить в соответствии с вашими потребностями. В какой-то момент у вас может возникнуть случай, который не покрывается одним из уже существующих плагинов ESLint, тогда вам придется написать свой собственный плагин.

Эта статья о том, как вы можете написать свой собственный плагин для ESLint. Прежде чем начать, ознакомьтесь с кратким обзором — что такое линтинг.

Написание пользовательского правила ESLint

Чтобы использовать пользовательское правило в ESLint, вам нужно написать подключаемый модуль ESLint. Прежде чем приступить к написанию собственного плагина, проверьте уже существующие здесь. ESLint предлагает гибкую архитектуру для плагинов и полностью подключается. Парсер и правила являются подключаемыми, это означает, что вы можете настроить их под свои нужды. Если вы хотите использовать TypeScript или JavaScript или использовать различные плагины для именования функций и т. д. Возможности безграничны.

Прежде чем приступить к написанию пользовательского правила, мы должны понять, как работает ESLint и как мы можем проверить, работает ли правило. Любой линтер, TSLint или ESLint — это, по сути, базовый статический анализатор кода, он проверяет ваш исходный код на программные и стилистические ошибки (неправильный отступ, имена переменных и т. д.). ESLint использует AST (абстрактное синтаксическое дерево) для оценки шаблонов в коде. AST (Abstract Syntax Tree) используется для описания определенного синтаксического шаблона в вашем коде, см. пример AST ниже.

Итак, по сути, нам нужно найти узел нашего кода, который мы хотим проверить в AST, и вернуть его в ESLint. Следовательно, у нас есть план.

Три шага для создания пользовательского правила ESLint

  1. Создайте определение правила в проводнике AST
  2. Создать модуль с пользовательским правилом
  3. Импортировать пользовательский модуль в ESLint

1. Создайте пользовательское правило в проводнике AST

В демонстрационных целях мы напишем простое правило. Мы хотим запретить переменную с именем pizza, isPizza или любой другой комбинацией.

Открываем вкладку браузера и переходим в АСТ. Теперь нам нужно настроить парсер и преобразователь. В зависимости от конфигурации вашего проекта ESLint вам необходимо выбрать парсер, например @typescript-eslint/parser, если вы используете typescript и используете этот парсер. Используйте параметр ESLint v8 в transform, так как мы не хотим использовать TypeScript в нашем правиле ESLint. Теперь у вас будет четыре окна вместо двух.

Верхний левый — это код для анализа, верхний правый — абстрактное синтаксическое дерево, нижний левый — определение вашего правила, а нижний правый — вывод правила.

Теперь давайте изучим AST, чтобы найти name: "pizza". Это свойство мы хотим проверить. Давайте консоль зарегистрируем это.

Скопируйте код в левом нижнем углу определения правила и откройте консоль инструментов разработчика. Результат должен быть пицца.

module.exports = {
  create(context) {
    return {
      Identifier(node) {
        console.log(node.name);
      },
    };
  },
};

Теперь нам просто нужно проверить, является ли имя пиццей.

module.exports = {
  create(context) {
    return {
      Identifier(node) {
        if (node.name.toLowerCase() === 'pizza') {
          console.log(
            `Nope, the variable name '${node.name}' is reserved`,
          );
        } else {
          console.log(`'${node.name}' is an amazing variable name`);
        }
      },
    };
  },
};

Теперь давайте добавим больше тестовых случаев, чтобы проверить правильность нашего кода. Скопируйте и вставьте код в верхнее левое окно.

const pizza = 'yummy';
const isPizza = true;
const pizzaSize = 'large';

Вывод в консоли должен быть ... is an amazing variable name для isPizza и pizzaSize. Отлично. Мы определили шаблон, который нарушает наше пользовательское правило.

Чтобы сообщить о нарушении правила, мы должны использовать context.report(), см. ESLint docs. Он публикует предупреждение или ошибку в зависимости от используемой конфигурации. Объект, принятый context.report(), имеет обязательное свойство message, которое содержит сообщение, о котором будет сообщено.

Теперь давайте расширим код.

module.exports = {
  create(context) {
    return {
      Identifier(node) {
        if (node.name.toLowerCase() === 'pizza') {
          return context.report({
            node,
            message: 'Nope, the variable name "pizza" is reserved',
          });
        }
        return null;
      },
    };
  },
};

Вывод (внизу справа) должен быть примерно таким:

// Nope, the variable name "pizza" is reserved (at 1:7)
const pizza = 'yummy';
// ------^
// ...

Наше определение правила завершено. Кроме того, метод context.report() также имеет необязательное свойство fix, которое позволит нам определить функцию, применяющую исправление нарушения правила. Впрочем, об этом будет рассказано в другом посте в блоге. 😀

2. Создайте модуль с пользовательским правилом

Создайте проект с соответствующими папками и файлами и инициализируйте с помощью npm init -y.

mkdir eslint-custom-rules
cd eslint-custom-rules
npm init -y
touch index.js
mkdir rules
cd rules
touch pizza-reserved.js

Это понадобится нам позже, чтобы загрузить модуль или импортировать его в наш проект.

Добавьте определение правила в файл pizza-reserved.js.

module.exports = {
  create(context) {
    return {
      Identifier(node) {
        if (node.name.toLowerCase() === 'pizza') {
          return context.report({
            node,
            message: 'Nope, the variable name "pizza" is reserved',
          });
        }
        return null;
      },
    };
  },
};

Существуют ограничения на имена для создания пользовательских правил eslint. Допускаются следующие форматы, где plugin-name и scope можно настроить:

  • eslint-плагин-plugin-name
  • @scope/eslint-plugin-plugin-name
  • @scope/eslint-плагин

В этом примере мы выбираем eslint-plugin-pizza-reserved для модуля npm.

Мы должны обновить package.json в нашем файле index.js с именем eslint-plugin-pizza-reserved.

Package.json должен выглядеть так:

{
  "name": "eslint-plugin-pizza-reserved",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

Теперь мы обновляем наши файлы index.js, чтобы экспортировать правила.

module.exports = {
  rules: {
    'pizza-reserved': require('./rules/pizza-reserved'),
  },
};

Теперь у нас есть работающее пользовательское правило eslint. Теперь мы можем опубликовать его в npm или использовать только локально в нашем проекте.

3. Импортируйте пользовательский модуль в ESLint

Импорт пользовательского правила в вашу конфигурацию ESLint зависит от того, опубликовали ли вы правило или хотите использовать его локально.

Если вы используете правило ESLint локально в своем проекте, вы можете просто расширить свой package.json devDependencies с помощью "<plugin-name>": "file:path/to/entrypoint".

Структура папок в этом примере:

.
├── eslint-custom-rules     # Custom ESLint rules
|   ├── rules
|   |   └── pizza-reserved.js
|   └── index.js
|
└── my-project               # Project folder, where we want to use custom rules
    ├── src                  # Source files
    ├── test                 # Automated tests
    ├── .eslintrc.js         # Automated tests
    ├── ...                  # Automated tests
    └── README.md

Следовательно, используйте "eslint-plugin-custom-rules": "file:eslint-custom-rules", чтобы добавить свой собственный плагин eslint в package.json, и запустите npm i, чтобы установить его.

Последним шагом будет расширение конфигурации ESLint.

module.exports = {
  plugins: [
    'custom-rules',
    // other plugins
  ],
  rules: {
    // other configs
    'custom-rules/pizza-reserved': 'warn',
  },
};

Вот и все. Вы написали пользовательское правило ESLint. Поздравляем.

TL;DR

  • Чтобы создать собственное правило ESLint, вам необходимо создать собственный подключаемый модуль ESLint.
  • Сначала вы должны определить определение правила с помощью проводника AST.
  • Затем вам нужно создать модуль NPM с пользовательским правилом
  • Наконец, вам нужно установить пользовательский модуль в свой проект и добавить его в конфигурацию ESLint.

Спасибо за внимание. Если у вас есть вопросы, используйте функцию комментариев или отправьте мне сообщение @mariokandut . Если вы хотите узнать больше о typescript, ознакомьтесь с этими Учебными пособиями по Typescript.

Рекомендации (и большое спасибо): ESLint, Darragh ORiordan, Carrie Reid-Knox, MEWS — Дарья