Объект context

В архитектуре ESLint каждая пользовательская или встроенная проверка реализуется как функция правила, получающая единственный аргумент — объект context. Этот объект является центральным механизмом взаимодействия правила с анализатором кода, предоставляя доступ к метаданным, AST, сервисам парсера и API для регистрации проблем.

context формируется ESLint во время инициализации правила и остается неизменным на протяжении всего анализа файла. Он не предназначен для модификации со стороны правила и рассматривается как интерфейс только для чтения и вызова методов ESLint.


Общая структура context

Объект context можно рассматривать как контейнер из нескольких функциональных блоков:

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

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

context = {
  id,
  options,
  settings,
  parserServices,
  parserPath,
  getSourceCode,
  getFilename,
  report,
  cwd,
  sourceCode
}

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


context.id

context.id содержит строковый идентификатор правила. Он соответствует имени правила, зарегистрированного в конфигурации ESLint.

Используется для:

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

Пример:

create(context) {
  if (context.id === "no-console") {
    // специфическая логика
  }
}

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


context.options

context.options представляет собой массив параметров, переданных пользователем в конфигурации ESLint для конкретного правила.

Пример конфигурации:

{
  "no-console": ["error", { "allow": ["warn", "error"] }]
}

Внутри правила:

create(context) {
  const options = context.options[0];
  const allowed = options?.allow || [];
}

Особенности:

  • всегда массив
  • может быть пустым
  • структура элементов зависит от автора правила
  • не валидируется ESLint автоматически (ответственность на разработчике правила)

context.settings

context.settings содержит глобальные пользовательские настройки ESLint, заданные в конфигурации settings.

Пример:

{
  "settings": {
    "react": {
      "version": "detect"
    }
  }
}

Использование:

create(context) {
  const reactVersion = context.settings.react?.version;
}

Особенности:

  • общие для всех правил проекта
  • часто используется плагинами (React, Vue, import)
  • не зависит от конкретного правила
  • может отсутствовать полностью

context.getSourceCode()

Метод getSourceCode() возвращает объект SourceCode, содержащий полную информацию о текущем файле.

Это один из ключевых инструментов анализа.

const sourceCode = context.getSourceCode();

Через него доступны:

  • полный текст файла
  • токены
  • комментарии
  • методы обхода AST
  • утилиты для работы с позициями

Примеры использования:

const text = sourceCode.getText();
const comments = sourceCode.getAllComments();

context.sourceCode

В новых версиях ESLint вместо getSourceCode() часто используется прямое свойство context.sourceCode, являющееся тем же объектом SourceCode.

const sourceCode = context.sourceCode;

Различие:

  • getSourceCode() — метод (устаревающий подход)
  • sourceCode — прямой доступ

context.report()

context.report() — основной механизм генерации ошибок и предупреждений.

Сигнатура:

context.report(descriptor)

Где descriptor может включать:

  • node — AST-узел
  • message — текст ошибки
  • loc — позиция (опционально)
  • data — шаблонные данные
  • fix — функция автоматического исправления

Пример:

context.report({
  node,
  message: "Использование console запрещено"
});

С автозаменой:

context.report({
  node,
  message: "Удалите console.log",
  fix(fixer) {
    return fixer.remove(node);
  }
});

Ключевые особенности:

  • может вызываться много раз за один проход
  • не прерывает выполнение анализа
  • поддерживает автофикс через fixer

context.getFilename()

Возвращает путь к текущему анализируемому файлу.

const filename = context.getFilename();

Особенности:

  • может возвращать <input> при анализе stdin
  • полезно для исключений по путям
  • часто используется для логики игнорирования

context.cwd

Содержит текущую рабочую директорию процесса ESLint.

const root = context.cwd;

Используется для:

  • построения абсолютных путей
  • загрузки конфигурационных файлов
  • разрешения модулей

context.parserServices

parserServices предоставляется кастомными парсерами (например, TypeScript ESLint) и содержит дополнительные данные, недоступные в стандартном AST.

Пример:

const services = context.parserServices;

Возможности:

  • доступ к TypeScript Program
  • маппинг AST → TS AST
  • типовая информация

Пример проверки:

if (!context.parserServices?.program) {
  return {};
}

Особенности:

  • зависит от парсера
  • может отсутствовать полностью
  • требует проверки перед использованием

context.parserPath

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

const parser = context.parserPath;

Используется редко, обычно для:

  • отладки
  • адаптации поведения под разные парсеры

Работа context в функции правила

Любое ESLint-правило определяется через функцию create, возвращающую набор обработчиков AST.

export default {
  create(context) {
    return {
      Identifier(node) {
        context.report({
          node,
          message: "Запрещён идентификатор"
        });
      }
    };
  }
};

Модель работы:

  1. ESLint вызывает create(context)
  2. правило возвращает набор visitor-функций
  3. при обходе AST вызываются обработчики
  4. через context.report фиксируются нарушения

Согласованность context и AST

context тесно связан с AST через SourceCode. Каждый узел AST содержит:

  • type
  • loc
  • range
  • ссылки на родительские узлы

Пример анализа:

create(context) {
  return {
    Literal(node) {
      const text = context.sourceCode.getText(node);
    }
  };
}

Иммутабельность context

context не предназначен для изменения. Любые попытки модификации:

context.options = [];

не поддерживаются и могут привести к:

  • некорректному поведению ESLint
  • потере совместимости
  • ошибкам выполнения

Все данные внутри объекта считаются read-only интерфейсом.


Взаимодействие с фиксаторами

context.report поддерживает механизм автоматического исправления через fixer.

fix(fixer) {
  return fixer.replaceText(node, "newValue");
}

context обеспечивает доступ к:

  • исходному коду
  • позициям узлов
  • текстовым диапазонам

что делает возможным точечные изменения без пересборки файла.


Роль context в экосистеме ESLint

context является связующим звеном между:

  • движком анализа ESLint
  • парсерами (Babel, TypeScript и др.)
  • пользовательскими правилами
  • системой отчетности

Без него правило представляет собой изолированную функцию без доступа к среде выполнения анализа.


Расширяемость через плагины

Плагины ESLint активно используют context для расширения возможностей:

  • доступ к глобальным настройкам через settings
  • использование parserServices для типизации
  • кросс-файловый анализ через cwd и getFilename
  • унифицированный репортинг ошибок

Типовые ошибки при работе с context

Часто встречающиеся проблемы:

  • отсутствие проверки parserServices
  • предположение о структуре options
  • прямое изменение context
  • использование getSourceCode() вместо sourceCode в новых версиях
  • игнорирование случаев null/undefined в настройках

Эти ошибки приводят к нестабильности правил и снижению переносимости между проектами.


Контракт выполнения правил

context обеспечивает формальный контракт:

  • вход: AST + context
  • выход: список диагностик
  • побочный эффект: отсутствует (кроме report и fix)

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