eslint-plugin-sonarjs — плагин ESLint, реализующий набор правил статического анализа, основанных на подходах SonarSource к выявлению потенциальных багов, проблем с читаемостью и «кодовых запахов». Основная цель инструмента — находить неочевидные ошибки логики, избыточные конструкции и потенциально опасные паттерны до выполнения кода.
Плагин ориентирован не на стиль форматирования (как eslint:recommended или prettier), а на качество архитектуры и поведенческую корректность кода. Он дополняет базовые правила ESLint более глубоким анализом потока выполнения и структуры условий.
ESLint работает как расширяемая система правил, где каждый плагин добавляет собственные проверки AST (Abstract Syntax Tree). eslint-plugin-sonarjs подключается на уровне правил и анализирует дерево синтаксиса JavaScript/TypeScript-кода, выявляя:
В отличие от линтеров, ориентированных на формат, данный плагин анализирует семантические свойства кода.
Плагин устанавливается как обычная зависимость проекта:
npm install eslint-plugin-sonarjs --save-dev
После установки он подключается в конфигурации ESLint:
{
"plugins": ["sonarjs"],
"extends": ["plugin:sonarjs/recommended"]
}
Рекомендуемая конфигурация включает набор правил, подобранных для выявления наиболее распространённых проблем качества кода.
Каждое правило анализирует AST и строит упрощённую модель логики. Например:
Основная идея — выявление мест, где разработчик вынужден «держать слишком много контекста в голове».
Одно из ключевых правил — оценка когнитивной сложности функции. Оно отличается от цикломатической сложности тем, что учитывает не только ветвления, но и восприятие человеком.
Пример функции с высокой сложностью:
function processOrder(order) {
if (order) {
if (order.items) {
for (let i = 0; i < order.items.length; i++) {
if (order.items[i].active) {
if (order.items[i].price > 100) {
console.log("expensive");
} else {
console.log("normal");
}
}
}
}
}
}
Проблема заключается в глубокой вложенности и множестве условий, которые усложняют понимание потока выполнения.
Правило стимулирует:
Правило выявляет повторяющиеся или перекрывающиеся условия в цепочках if/else.
Пример проблемного кода:
if (status === "loading") {
fetchData();
} else if (status === "loading") {
showSpinner();
}
Вторая ветка никогда не будет выполнена. Такие ошибки часто возникают при рефакторинге или копировании блоков кода.
Выявляет сравнения, где обе стороны выражения одинаковы или логически эквивалентны.
if (user.id === user.id) {
// всегда true
}
Подобные конструкции обычно являются следствием ошибок логики или незавершённого рефакторинга.
Плагин фиксирует функции и блоки, которые не выполняют полезной работы.
function handleClick() {}
Или:
if (items.length === 0) {
}
Такие конструкции могут указывать на недописанную логику или пропущенные требования.
Плагин обнаруживает избыточные логические выражения.
Пример:
if (isValid === true) {
submit();
}
Более корректный вариант:
if (isValid) {
submit();
}
Правило выявляет инвертированные проверки, усложняющие чтение.
if (!isActive === false) {
run();
}
Такой код ухудшает понимание и часто является результатом неправильного рефакторинга.
Плагин активно рекомендует использовать ранние возвраты вместо глубокой вложенности:
Проблемный вариант:
function validate(user) {
if (user) {
if (user.isActive) {
if (user.hasAccess) {
return true;
}
}
}
return false;
}
Более читаемая структура:
function validate(user) {
if (!user) return false;
if (!user.isActive) return false;
if (!user.hasAccess) return false;
return true;
}
Правило анализирует ветвления, где выполняется одинаковый код.
if (isAdmin) {
logAccess();
} else {
logAccess();
}
Такой код не несёт различий между ветками и может быть упрощён.
Выявляет блоки try/catch, которые не добавляют обработки ошибок.
try {
execute();
} catch (e) {
throw e;
}
Такой код фактически не изменяет поведение программы и только усложняет структуру.
Плагин анализирует:
Пример:
if (score > 90) {
grade = "A";
} else if (score > 80) {
grade = "B";
} else if (score > 70) {
grade = "C";
} else if (score > 85) {
grade = "D";
}
Последнее условие никогда не выполнится, так как перекрывается предыдущим диапазоном.
Конфигурация может быть детализирована:
{
"plugins": ["sonarjs"],
"rules": {
"sonarjs/cognitive-complexity": ["warn", 15],
"sonarjs/no-duplicated-conditions": "error",
"sonarjs/no-identical-expressions": "error",
"sonarjs/no-empty-function": "warn"
}
}
Возможность тонкой настройки позволяет адаптировать строгие проверки под реальные ограничения проекта.
Как и в ESLint, можно отключать правила локально:
// eslint-disable-next-line sonarjs/cognitive-complexity
function complexFunction() {
// допустимая сложность
}
Или для отдельных блоков:
/* eslint sonarjs/no-duplicated-conditions: "off" */
Использование плагина приводит к системным изменениям в стиле кодирования:
Код начинает строиться вокруг принципа «минимальной когнитивной нагрузки», что особенно важно в крупных кодовых базах.
Несмотря на глубину, анализ имеет ограничения:
Поэтому результаты следует рассматривать как рекомендации по улучшению структуры, а не как абсолютные ошибки.