Версионирование и совместимость

Экосистема ESLint опирается на семантическое версионирование (SemVer), где версия представляется в формате MAJOR.MINOR.PATCH. Эта модель определяет характер изменений и их влияние на совместимость.

MAJOR-версия изменяется при внесении несовместимых изменений. Такие обновления затрагивают публичные API, формат конфигураций, поведение правил или архитектуру плагинов. MINOR-версия включает обратимо совместимые улучшения: новые правила, расширения возможностей, дополнительные опции. PATCH-версия фиксирует ошибки, не изменяя поведение системы в ожидаемом контракте.

В контексте линтера важным аспектом становится не только API, но и поведение анализа кода, поскольку даже изменение диагностики может считаться потенциально разрушающим совместимость.


Модель совместимости в экосистеме линтера

Совместимость ESLint определяется сразу на нескольких уровнях:

  • совместимость ядра и конфигурации;
  • совместимость плагинов и парсеров;
  • совместимость правил и их опций;
  • совместимость среды выполнения (Node.js);
  • совместимость формата конфигурации.

Каждый уровень может независимо стать источником несовместимости при обновлении версии. Поэтому версия ESLint часто влияет не только на сам пакет, но и на всю цепочку зависимостей инструмента качества кода.


Эволюция конфигурационного формата и влияние на версии

Исторически ESLint использовал формат .eslintrc, который поддерживал JSON, YAML и JavaScript-конфигурации. Этот формат долгое время оставался стандартом, но с развитием системы возникла новая модель — flat config.

Переход на flat config в новых версиях стал одним из ключевых факторов изменения мажорной версии:

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

Изменение модели конфигурации напрямую влияет на совместимость, так как плагины и пресеты должны адаптироваться к новому формату экспорта.


Совместимость legacy-конфигурации и новой модели

В переходных версиях ESLint поддерживаются оба подхода, но с различиями в поведении:

  • legacy .eslintrc работает через каскадное объединение конфигураций;
  • flat config использует явный массив объектов конфигурации;
  • некоторые поля конфигурации переосмыслены или удалены;
  • порядок применения правил становится строго линейным.

Это приводит к ситуации, когда одинаковые конфигурации могут давать разные результаты анализа в зависимости от режима.


Совместимость плагинов и архитектура расширений

Плагины являются ключевым элементом расширения функциональности ESLint. Каждый плагин экспортирует набор правил, конфигураций и иногда парсеров.

Совместимость плагинов зависит от нескольких факторов:

  • версия API ядра ESLint;
  • структура объекта rule definition;
  • формат контекста выполнения правил;
  • доступные методы report и fixer;
  • поддержка flat config.

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

Особое значение имеет поле peerDependencies, которое задаёт допустимые диапазоны версий ESLint для конкретного плагина. Несовпадение этих диапазонов часто приводит к неработоспособности правил или предупреждениям пакетного менеджера.


Парсеры и их влияние на совместимость

ESLint сам по себе не парсит современный JavaScript без внешних парсеров. Для этого используются:

  • @babel/eslint-parser;
  • @typescript-eslint/parser;
  • espree (встроенный парсер).

Совместимость парсера и версии ESLint определяется:

  • форматом AST;
  • поддержкой экспериментального синтаксиса;
  • API передачи parserOptions;
  • интеграцией с flat config.

Например, изменения в структуре AST или расширение поддержки TypeScript требуют обновления парсера, даже если сам ESLint не меняет ядро.


Зависимость от Node.js и среды выполнения

Каждая мажорная версия ESLint устанавливает минимальную версию Node.js.

Эта зависимость влияет на:

  • доступность современных возможностей JavaScript;
  • использование ESM-модулей вместо CommonJS;
  • поддержку top-level await в конфигурациях;
  • производительность анализа больших проектов.

При повышении минимальной версии Node.js часто упрощается внутренняя архитектура ESLint, но одновременно нарушается обратная совместимость с устаревшими средами CI/CD.


Поведение правил и обратная совместимость диагностики

Правила ESLint представляют собой функции анализа AST с определённым контрактом. Изменения в правилах могут быть:

  • добавление новых проверок;
  • изменение severity по умолчанию;
  • удаление устаревших правил;
  • уточнение логики диагностики.

Даже при сохранении API изменение поведения правила считается потенциально ломающее совместимость, так как влияет на результаты линтинга.

Особенно чувствительны правила, связанные с:

  • семантикой JavaScript (e.g. no-implicit-coercion);
  • импортами и модулями;
  • асинхронным кодом;
  • типизацией через плагины.

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

Пресеты (shareable configs) формируют слой абстракции поверх правил. Их совместимость зависит от:

  • версии ESLint;
  • версии зависимых плагинов;
  • структуры конфигурации (legacy vs flat);
  • наличия deprecated правил.

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


Миграция между мажорными версиями

Переход между версиями ESLint обычно затрагивает несколько слоёв одновременно:

  • обновление ядра ESLint;
  • обновление плагинов;
  • изменение конфигурационного формата;
  • адаптация CI/CD пайплайнов;
  • пересмотр правил и их опций.

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


Совместимость зависимостей и управление версиями

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

  • фиксирование версии в package-lock.json или pnpm-lock.yaml;
  • ограничение диапазонов в package.json;
  • использование overrides для выравнивания плагинов;
  • разделение конфигураций по средам (dev/CI).

Особое значение имеет согласование версий между:

  • eslint;
  • eslint-config-* пакетами;
  • eslint-plugin-* пакетами;
  • парсерами и трансформерами.

Конфликты версий и типовые сценарии несовместимости

На практике несовместимость возникает в нескольких сценариях:

  • плагин требует ESLint 9, но проект использует ESLint 8;
  • конфигурация написана под flat config, но используется legacy runner;
  • парсер не поддерживает новый синтаксис ECMAScript;
  • пересечение peerDependencies приводит к установке нескольких версий ESLint;
  • устаревшие правила вызывают ошибки выполнения.

Каждый из этих сценариев приводит к либо частичной деградации анализа, либо полной невозможности запуска линтера.


Структурные изменения API и влияние на экосистему

Мажорные версии ESLint часто сопровождаются изменением внутренних API:

  • изменение структуры context объекта;
  • обновление механизма сообщений (messages API);
  • переработка механизма fixer;
  • изменение загрузки конфигураций;
  • переход на новые форматы модулей.

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


Стабилизация версий в крупных проектах

В больших кодовых базах управление совместимостью ESLint строится через:

  • централизованную конфигурацию;
  • единый набор плагинов;
  • контроль версий через CI;
  • периодическое обновление мажорных версий с фиксацией изменений;
  • изоляцию конфигураций для разных пакетов в монорепозиториях.

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