Встраивание ESLint в собственные приложения

ESLint предоставляет не только CLI-инструмент для проверки кода, но и полноценное программное API, позволяющее интегрировать процесс статического анализа непосредственно в собственные приложения, сборочные пайплайны, редакторы кода и серверные среды. Такой подход используется в системах, где требуется динамическая проверка пользовательского или генерируемого JavaScript-кода, а также в инструментах разработки, расширяющих стандартные возможности линтинга.

Встраивание ESLint обычно опирается на модуль eslint, который предоставляет класс ESLint — основной программный интерфейс для анализа файлов, применения конфигураций и получения результатов проверки.


Установка и базовая подготовка окружения

Для интеграции в приложение ESLint устанавливается как зависимость уровня разработки:

npm install eslint

или

yarn add eslint

После установки становится доступен программный API:

import { ESLint } from "eslint";

или в CommonJS:

const { ESLint } = require("eslint");

Современные версии ESLint ориентированы на flat-config архитектуру, но поддерживают и традиционные конфигурации через .eslintrc.


Программный запуск линтера

Ключевой сценарий встраивания — запуск анализа файлов напрямую из кода приложения:

import { ESLint } from "eslint";

const eslint = new ESLint({
  cwd: process.cwd(),
  overrideConfigFile: true,
});

const results = await eslint.lintFiles(["src/**/*.js"]);

Метод lintFiles принимает пути или glob-шаблоны и возвращает массив результатов, содержащих информацию о нарушениях правил.

Каждый результат включает:

  • путь к файлу
  • массив сообщений об ошибках и предупреждениях
  • метаданные о производительности и применённых правилах

Обработка результатов анализа

Результаты линтинга представляют собой структурированные объекты:

for (const result of results) {
  console.log(result.filePath);

  for (const message of result.messages) {
    console.log(message.ruleId, message.message, message.line);
  }
}

Сообщения содержат:

  • ruleId — идентификатор правила
  • message — текст нарушения
  • line, column — позиция в файле
  • severity — уровень критичности

На основе этих данных можно строить пользовательские интерфейсы, отчёты или блокировать выполнение кода.


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

Встраиваемые системы часто работают не с файлами, а с кодом в памяти. Для этого применяется метод lintText:

const eslint = new ESLint();

const code = `
function test() {
  var x = 1
}
`;

const results = await eslint.lintText(code, {
  filePath: "virtual.js",
});

Передача filePath важна для корректного применения правил, зависящих от расширений и конфигураций проекта.


Кастомная конфигурация при встраивании

ESLint позволяет задавать конфигурацию прямо в конструкторе:

const eslint = new ESLint({
  overrideConfig: {
    rules: {
      semi: ["error", "always"],
      "no-unused-vars": "warn",
    },
    env: {
      browser: true,
      node: true,
    },
  },
});

Такой подход используется в приложениях, где конфигурация формируется динамически, например:

  • онлайн-редакторы кода
  • обучающие платформы
  • sandbox-окружения
  • IDE-плагины

Интеграция с пользовательскими правилами

Встраивание ESLint особенно эффективно при использовании кастомных правил. Они подключаются через rulePaths или plugins.

const eslint = new ESLint({
  overrideConfig: {
    plugins: ["custom-rules"],
    rules: {
      "custom-rules/no-console-log": "error",
    },
  },
});

Для загрузки локальных правил:

const eslint = new ESLint({
  rulePaths: ["./eslint-rules"],
});

Каждое правило представляет собой модуль с AST-логикой, работающий через ESTree-структуру.


Работа с flat config внутри приложений

Flat config представляет собой массив конфигурационных объектов:

const eslint = new ESLint({
  overrideConfigFile: true,
});

или прямое задание:

const eslint = new ESLint({
  overrideConfig: [
    {
      files: ["**/*.js"],
      rules: {
        eqeqeq: "error",
      },
    },
  ],
});

Flat config особенно полезен при создании многоуровневых систем анализа, где разные модули требуют разных политик линтинга.


Потоковая обработка больших кодовых баз

При работе с крупными проектами важна оптимизация. ESLint поддерживает кеширование:

const eslint = new ESLint({
  cache: true,
  cacheLocation: ".eslintcache",
});

Кеш уменьшает повторную обработку неизменённых файлов и ускоряет интеграцию в сборочные системы.

Также возможно параллельное выполнение через разделение наборов файлов:

await Promise.all([
  eslint.lintFiles(["src/**/*.js"]),
  eslint.lintFiles(["tests/**/*.js"]),
]);

Встраивание в сборочные системы

ESLint часто интегрируется в инструменты сборки.

Webpack

Используется eslint-webpack-plugin:

const ESLintPlugin = require("eslint-webpack-plugin");

module.exports = {
  plugins: [new ESLintPlugin()],
};

Vite

import eslint from "vite-plugin-eslint";

export default {
  plugins: [eslint()],
};

В таких сценариях ESLint становится частью pipeline трансформации кода, выполняясь на этапе разработки или сборки.


Серверная интеграция и динамический анализ

На серверной стороне ESLint применяется для анализа пользовательского кода:

import { ESLint } from "eslint";

const eslint = new ESLint({
  useEslintrc: false,
  overrideConfig: {
    rules: {
      "no-eval": "error",
    },
  },
});

export async function analyze(code) {
  const result = await eslint.lintText(code);
  return result[0].messages;
}

Такие решения используются в:

  • песочницах выполнения JavaScript
  • образовательных системах
  • платформах код-ревью
  • генераторах кода

Обработка и форматирование отчётов

ESLint поддерживает форматирование результатов через ESLint.getFormatter:

const eslint = new ESLint();
const results = await eslint.lintFiles(["src"]);

const formatter = await eslint.loadFormatter("stylish");
const output = formatter.format(results);

console.log(output);

Также возможны JSON-форматы для интеграции с аналитическими системами:

const eslint = new ESLint({
  overrideConfig: {},
});

const results = await eslint.lintFiles(["src"]);
const json = JSON.stringify(results);

Интеграция с пользовательскими интерфейсами

При встраивании ESLint в UI-приложения результаты часто преобразуются в структуры, удобные для визуализации:

function transform(results) {
  return results.flatMap((file) =>
    file.messages.map((msg) => ({
      file: file.filePath,
      rule: msg.ruleId,
      severity: msg.severity,
      position: `${msg.line}:${msg.column}`,
    }))
  );
}

Такая трансформация используется в редакторах кода и web IDE.


Динамическое обновление конфигурации

Встраиваемые системы часто требуют изменения правил без перезапуска процесса:

let eslint = new ESLint(baseConfig);

export function updateConfig(newConfig) {
  eslint = new ESLint({
    overrideConfig: newConfig,
  });
}

Это позволяет реализовывать:

  • пользовательские профили линтинга
  • политики организации
  • адаптивные правила в зависимости от контекста проекта

Ограничения и особенности выполнения

При встраивании ESLint важно учитывать:

  • высокая стоимость AST-анализа на больших кодовых базах
  • необходимость контроля памяти при массовом linting
  • влияние синхронных операций в старых плагинах
  • различия между legacy .eslintrc и flat config

Оптимизация обычно достигается за счёт:

  • кеширования
  • батчинга файлов
  • ограничения набора правил
  • предварительной фильтрации файлов

Расширение поведения через Node API

ESLint позволяет глубоко интегрироваться в Node.js-приложения:

import { ESLint } from "eslint";

const eslint = new ESLint();

export async function lintProject(files) {
  return await eslint.lintFiles(files);
}

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