Форматтер в ESLint представляет собой отдельный модуль, отвечающий за преобразование результатов проверки кода в удобное текстовое или структурированное представление. Архитектура ESLint изначально разделяет процесс анализа и процесс вывода, что позволяет гибко менять формат представления без изменения логики линтинга.
После выполнения анализа ESLint формирует массив сообщений о проблемах. Каждое сообщение содержит:
Форматтер получает этот массив и преобразует его в строку или другой формат вывода (JSON, HTML, таблицы и т.д.).
Ключевой принцип: форматтер не влияет на процесс проверки кода, он работает только с результатом.
Пользовательский форматтер в ESLint — это JavaScript-модуль, который экспортирует функцию.
Базовый контракт:
module.exports = function (results) {
return "строка вывода";
};
Параметр results — массив объектов результатов
проверки.
Структура одного результата:
{
filePath: "src/index.js",
messages: [
{
ruleId: "no-console",
severity: 2,
message: "Unexpected console statement",
line: 10,
column: 5,
endLine: 10,
endColumn: 12
}
],
errorCount: 1,
warningCount: 0,
fixableErrorCount: 0,
fixableWarningCount: 0
}
ESLint позволяет указать путь к кастомному форматтеру через CLI:
eslint . --format ./formatters/simple-formatter.js
Также возможно использование через Node API:
const eslint = require("eslint");
const cli = new eslint.CLIEngine({
formatter: "./formatters/simple-formatter.js"
});
Минимальный форматтер может просто перечислять ошибки:
module.exports = function (results) {
let output = "";
results.forEach(result => {
if (result.messages.length === 0) return;
output += `\n${result.filePath}\n`;
result.messages.forEach(msg => {
output += ` ${msg.line}:${msg.column} ${msg.message} (${msg.ruleId})\n`;
});
});
return output;
};
Такой форматтер повторяет базовую идею стандартного вывода, но позволяет полностью контролировать структуру.
Сообщения имеют поле severity:
1 — предупреждение (warning)2 — ошибка (error)Это позволяет разделять вывод:
const isError = msg.severity === 2;
output += isError ? "ERROR: " : "WARN: ";
output += `${msg.message}\n`;
Разделение уровней полезно для построения цветных терминальных интерфейсов или интеграции с CI.
Форматтер может анализировать весь массив результатов и формировать сводку:
module.exports = function (results) {
let totalErrors = 0;
let totalWarnings = 0;
results.forEach(file => {
totalErrors += file.errorCount;
totalWarnings += file.warningCount;
});
return `
Errors: ${totalErrors}
Warnings: ${totalWarnings}
`;
};
Такая агрегация используется для построения отчётов уровня проекта.
Расширенные форматтеры часто группируют сообщения по правилам или файлам:
const grouped = {};
results.forEach(result => {
result.messages.forEach(msg => {
if (!grouped[msg.ruleId]) {
grouped[msg.ruleId] = [];
}
grouped[msg.ruleId].push({
file: result.filePath,
line: msg.line,
message: msg.message
});
});
});
Вывод по группам помогает анализировать частые нарушения правил.
Форматтер может возвращать структурированные данные:
module.exports = function (results) {
return JSON.stringify(results, null, 2);
};
Такой подход используется для интеграции с внешними системами анализа кода, где ESLint выступает как источник данных.
Форматтер может генерировать HTML-отчёты:
module.exports = function (results) {
let html = `<html><body><h1>ESLint Report</h1>`;
results.forEach(result => {
html += `<h2>${result.filePath}</h2><ul>`;
result.messages.forEach(msg => {
html += `<li>${msg.line}:${msg.column} - ${msg.message}</li>`;
});
html += `</ul>`;
});
html += `</body></html>`;
return html;
};
Подобный формат используется для визуализации качества кода в браузере.
В форматтерах допустимо использование сторонних пакетов, например:
Пример с цветами:
const chalk = require("chalk");
module.exports = function (results) {
let output = "";
results.forEach(result => {
result.messages.forEach(msg => {
if (msg.severity === 2) {
output += chalk.red(msg.message) + "\n";
} else {
output += chalk.yellow(msg.message) + "\n";
}
});
});
return output;
};
При отсутствии ошибок форматтер обязан корректно обрабатывать пустой массив:
if (results.length === 0) {
return "No linting issues found";
}
Это важно для CI-систем, где отсутствие вывода может интерпретироваться как ошибка.
Несмотря на синхронную природу API, форматтер может имитировать потоковую обработку данных:
Такой подход необходим при работе с большими проектами, содержащими тысячи файлов.
Форматтеры ESLint имеют ряд особенностей:
Эти ограничения обеспечивают предсказуемость и стабильность поведения.
Форматтеры часто адаптируются под системы непрерывной интеграции:
Пример форматтера для CI-логов:
module.exports = function (results) {
let output = "";
results.forEach(result => {
result.messages.forEach(msg => {
output += `${result.filePath}:${msg.line}:${msg.column} `;
output += `${msg.severity === 2 ? "error" : "warn"} `;
output += `${msg.message}\n`;
});
});
return output;
};
Такой формат легко парсится внешними системами.
Форматтер может быть построен как система плагинов:
const formatters = [
require("./parts/header"),
require("./parts/body"),
require("./parts/footer")
];
module.exports = function (results) {
return formatters.map(fn => fn(results)).join("\n");
};
Это позволяет разделять ответственность и упрощать поддержку сложных отчётов.
Часто требуется нормализация путей:
const path = require("path");
const normalized = path.relative(process.cwd(), result.filePath);
Это делает вывод независимым от окружения выполнения.
Хотя основная задача форматтера — представление данных, он фактически становится инструментом аналитики:
За счёт этого форматтеры часто используются в связке с метриками качества и отчётами разработческих команд.