Конфликты между правилами в ESLint возникают тогда, когда одновременно активируются несколько источников проверок, задающих несовместимые требования к одному и тому же фрагменту кода. На практике это проявляется в виде противоречивых сообщений линтера, где одно правило требует одного поведения, а другое — противоположного. Подобные ситуации особенно характерны для сложных конфигураций, использующих несколько наборов правил, сторонние плагины и наследование конфигураций.
Основной источник конфликтов — многослойность конфигурации ESLint.
Конфигурация формируется из нескольких уровней: базовые настройки
проекта, подключаемые пресеты (extends), плагины, локальные
переопределения (rules), а также файловые исключения и
специальные правила для отдельных директорий.
Каждый уровень может переопределять или дополнять предыдущий. В
результате одно и то же правило может быть определено несколько раз с
различными значениями. Например, базовый конфиг может запрещать
использование console, в то время как конфиг для разработки
допускает его использование.
Дополнительный источник противоречий — взаимодействие правил форматирования и правил качества кода. ESLint изначально не является инструментом форматирования, но на практике часто используется совместно с форматирующими наборами правил, что создаёт пересечения.
Наиболее очевидный тип конфликтов возникает, когда одно и то же правило задано с разными уровнями строгости:
offwarnerrorПри объединении конфигураций применяется последнее определение правила. Это означает, что порядок подключения конфигов становится критически важным. Например, если базовая конфигурация включает:
"no-console": "error"
а более специфичная конфигурация переопределяет:
"no-console": "off"
итоговое поведение полностью отключает правило, даже если базовая конфигурация считалась более строгой.
Разные плагины могут вводить собственные правила, регулирующие одинаковые аспекты кода, но с разной логикой. Например, один плагин может требовать строгого выравнивания скобок, а другой — ориентироваться на иные стилистические принципы.
Особенно часто такие конфликты возникают между:
eslint:recommendedeslint-plugin-import,
eslint-plugin-unicorn)@typescript-eslint/*)Типичный пример — конфликт между правилами базового ESLint и
TypeScript-расширений. Некоторые правила базового набора становятся
неприменимыми в TypeScript-контексте и должны быть отключены в пользу
аналогов из @typescript-eslint.
Наиболее распространённый класс проблем связан с пересечением ESLint и инструментов форматирования, таких как Prettier. ESLint может проверять отступы, кавычки, пробелы и переносы строк, в то время как Prettier автоматически форматирует код по собственным правилам.
Например, правило:
"indent": ["error", 2]
может конфликтовать с Prettier, который форматирует отступы по собственному алгоритму. В результате одна система исправляет код, а другая снова помечает его как ошибочный.
В подобных конфигурациях ESLint и Prettier фактически конкурируют за контроль над одним и тем же аспектом синтаксиса, что приводит к постоянным циклам исправлений.
В классической системе ESLint (legacy config) порядок разрешения
конфигураций определяется следующим образом: сначала загружаются базовые
конфигурации, затем расширения (extends), после чего
применяются локальные настройки проекта.
Каждый последующий уровень переопределяет предыдущий. Это означает, что:
При этом важно, что объединение объектов конфигурации не является глубоким слиянием для всех типов данных. Для правил ESLint применяется перезапись значений, а не их объединение.
В новой системе flat config, используемой в современных версиях ESLint, конфигурация представляется как массив объектов. Порядок этих объектов напрямую определяет приоритет: более поздние элементы перекрывают предыдущие.
export default [
baseConfig,
pluginConfig,
projectConfig
]
Конфликты в этой модели становятся более предсказуемыми, но при этом усиливается зависимость результата от порядка следования конфигураций.
В flat config также становится более прозрачным взаимодействие между различными источниками правил, однако повышается риск неявного переопределения при добавлении новых слоёв конфигурации в середину массива.
При использовании TypeScript через
@typescript-eslint/parser возникает специфический класс
конфликтов. Базовые правила ESLint часто не учитывают особенности
типизированного кода, из-за чего:
any или типов интерфейсов
дублируются разными плагинамиТипичный конфликт:
no-unused-vars (ESLint core)@typescript-eslint/no-unused-varsОдновременное включение обоих правил приводит к дублированию сообщений и несовместимым результатам анализа. Обычно базовое правило отключается в пользу TypeScript-версии.
Семантические правила отвечают за корректность кода, тогда как стилевые — за его внешний вид. Конфликт возникает, когда изменение внешнего вида влияет на интерпретацию семантики правил.
Например:
no-restricted-syntax)brace-style,
curly)В сложных конфигурациях одно правило может изменять структуру кода таким образом, что другое начинает считать его ошибочным.
ESLint позволяет разрешать конфликты локально через комментарии:
/* eslint-disable no-console */
console.log("debug");
или точечно:
// eslint-disable-next-line no-unused-vars
const temp = 1;
Подобные конструкции фактически создают локальное исключение из глобальной системы правил. При большом количестве таких отключений конфигурация теряет предсказуемость, поскольку фактическое поведение линтера начинает расходиться с глобальными настройками.
Механизм overrides позволяет задавать разные наборы
правил для разных типов файлов. Это один из ключевых инструментов
управления конфликтами в проектах с разнородным кодом.
"overrides": [
{
"files": ["*.ts"],
"rules": {
"@typescript-eslint/no-explicit-any": "error"
}
},
{
"files": ["*.test.js"],
"rules": {
"no-unused-expressions": "off"
}
}
]
Конфликты могут возникать, если файл попадает под несколько
пересекающихся шаблонов. В таких случаях применяется порядок следования
overrides: более поздние правила имеют приоритет над
предыдущими.
Конфигурация ESLint может собираться из:
eslint.config.js или
.eslintrceslint-config-*)eslint-plugin-*)CLI-аргументы имеют наивысший приоритет и могут полностью
переопределять поведение конфигурации. Например, передача флага
--rule способна изменить результат анализа независимо от
всех остальных слоёв.
Сложные конфликты чаще всего возникают при накоплении правил без общей архитектуры конфигурации. На уровне проектирования конфигурации важным фактором становится разделение ответственности:
Конфигурации с чётким разделением слоёв демонстрируют более стабильное поведение, поскольку количество перекрывающихся правил снижается, а приоритеты становятся предсказуемыми.
Не все конфликты проявляются напрямую. Некоторые из них выражаются косвенно:
--fix)Подобные эффекты возникают, когда разные правила воздействуют на один и тот же участок AST (абстрактного синтаксического дерева), но применяют разные стратегии исправления.
Хотя ESLint не гарантирует последовательное выполнение всех правил в строгом порядке, результат может зависеть от того, какие правила имеют возможность применить автофикс первыми. В случае пересекающихся фиксов итоговое состояние кода может отличаться от ожидаемого, если несколько правил изменяют одну и ту же строку.
Особенно это заметно в сочетании правил:
При пересечении таких правил возникает ситуация, при которой один автофикс отменяет другой, создавая циклические изменения при повторном запуске линтера.
По мере роста проекта увеличивается количество конфигурационных источников и плагинов, что экспоненциально повышает вероятность конфликтов. Особенно критично это проявляется в монорепозиториях, где разные пакеты могут использовать разные стандарты кодирования.
В таких условиях конфигурация ESLint фактически становится системой правил с множеством перекрывающихся областей, где ключевым фактором становится строгая иерархия приоритетов и минимизация дублирующих правил.