В ESLint система автоматических исправлений основана на способности
правил изменять исходный код через API fix, возвращая
объект с диапазоном замены и новым текстом. Каждое правило может быть
помечено как поддерживающее автофиксы через свойство
meta.fixable, принимающее значения code или
whitespace.
module.exports = {
meta: {
fixable: "code",
},
create(context) {
return {
Identifier(node) {
if (node.name === "foo") {
context.report({
node,
message: "Не использовать foo",
fix(fixer) {
return fixer.replaceText(node, "bar");
},
});
}
},
};
},
};
Наличие fix не гарантирует корректность преобразования
во всех контекстах, поэтому различают безопасные и потенциально
небезопасные исправления.
Безопасное исправление — трансформация кода, при которой сохраняется семантика программы независимо от контекста выполнения. Такие фиксы не зависят от побочных эффектов и структуры окружающего кода.
1. Форматирование и пробельные символы
Изменения, затрагивающие только внешний вид кода:
// было
const a=1
// стало
const a = 1;
Подобные исправления обычно относятся к
meta.fixable = "whitespace" или реализуются через
eslint --fix совместно с правилами стиля.
2. Простые замены токенов без изменения логики
// было
if (a == 0) {}
// стало
if (a === 0) {}
Такие фиксы считаются безопасными, если не происходит преобразования типов или логики сравнения.
3. Удаление избыточных конструкций
// было
if (flag === true) {}
// стало
if (flag) {}
Безопасность зависит от точного анализа выражения: правило должно учитывать truthy/falsy значения.
4. Упрощение синтаксиса
// было
const obj = {
a: a,
};
// стало
const obj = {
a,
};
Такие изменения не влияют на поведение программы.
Небезопасные исправления изменяют поведение программы или её
результат при определённых условиях. ESLint не помечает такие изменения
как fixable без осторожной реализации, однако логика правил
может приводить к потенциально опасным трансформациям.
// потенциально опасно
a == null → a === null
Проблема заключается в том, что == null также покрывает
undefined, а строгое сравнение меняет поведение:
a == null // true для null и undefined
a === null // true только для null
// было
if (!a || !b) {}
// попытка "оптимизации"
if (!(a && b)) {}
С точки зрения логики выражения эквивалентны, но при наличии побочных эффектов в геттерах результат может отличаться.
// правило может удалить вызов
getValue();
Если функция вызывает побочные эффекты, удаление нарушает поведение программы. Без статического анализа side effects подобные фиксы считаются небезопасными.
// было
a() + b()
// стало (теоретическая оптимизация)
b() + a()
Несмотря на математическую эквивалентность сложения, порядок вызова функций критичен из-за побочных эффектов.
Механизм исправлений базируется на объекте fixer,
предоставляемом контекстом правила.
fixer.replaceText(node, text)fixer.remove(node)fixer.insertTextBefore(node, text)fixer.insertTextAfter(node, text)fixer.replaceTextRange(range, text)Каждое исправление работает через диапазоны символов исходного файла, что требует точного учета токенизации.
Если несколько правил предлагают изменения в одном участке кода, ESLint выполняет объединение фикс-патчей. Конфликты возникают при пересечении диапазонов.
const a=1
const b=2
Два правила могут одновременно:
При конфликте фикс может быть частично применён или отклонён полностью.
--fix и режимы примененияeslint file.js --fix
Применяет все доступные фиксы, помеченные как безопасные.
eslint file.js --fix-type problem
eslint file.js --fix-type suggestion
eslint file.js --fix-type layout
problem — исправления потенциальных ошибокsuggestion — улучшения стиля и читаемостиlayout — форматированиеeslint file.js --fix-dry-run
Позволяет оценить изменения без модификации файлов.
Безопасность фикса зависит не от ESLint как инструмента, а от реализации конкретного правила.
1. Контекст AST-узлов
Чем глубже анализ структуры, тем выше вероятность корректного исправления.
2. Отсутствие побочных эффектов
Правила должны учитывать:
3. Детектирование типов
Использование TypeScript-информации (через
@typescript-eslint) повышает точность фиксов.
// правило: no-unused-vars
let x;
// фикс
// удаление x
Удаление переменной безопасно при отсутствии ссылок.
// было
const result = fn(a++, b++);
// потенциальный фикс (опасен)
const result = fn(a, b);
Изменение инкрементов нарушает порядок и значение состояния.
meta.fixable и его рольmeta: {
fixable: "code"
}
или
meta: {
fixable: "whitespace"
}
code — изменения логики, синтаксиса, структурыwhitespace — только форматированиеПравила без этого свойства не могут предоставлять автофиксы.
Некоторые фиксы зависят от контекста.
// было
if (value == 1)
// фикс
if (Number(value) === 1)
Корректность зависит от предполагаемого типа value. При
строковых значениях поведение может измениться.
// было
const s = "text";
// стало
const s = 'text';
Безопасно только при отсутствии экранированных символов.
Автофиксы интегрируются в:
Однако чрезмерное доверие автоматическим исправлениям без понимания
их семантики приводит к скрытым ошибкам, особенно при правилах с
fix в логике AST-трансформаций.