В экосистеме ESLint процессоры (processors) представляют собой механизм предварительной обработки и постобработки кода перед его анализом линтером. Они расширяют стандартную модель работы ESLint, позволяя применять правила не только к чистому JavaScript-файлу, но и к содержимому, извлечённому из других форматов: шаблонов, Markdown-документов, Vue-компонентов, HTML-фрагментов и любых кастомных текстовых структур.
ESLint изначально проектировался для анализа JavaScript-кода, представленного как линейный текст. Однако в реальных проектах код редко существует в изоляции: он часто встроен в многоформатные контейнеры. Процессоры решают задачу извлечения «чистого» кода из таких контейнеров и обратного сопоставления ошибок с исходным источником.
Процессор выполняет две ключевые функции:
Таким образом, процессор выступает промежуточным слоем между файловой системой и ядром анализа ESLint.
Общий цикл обработки можно представить следующим образом:
Ключевая особенность заключается в том, что ESLint не осознаёт исходный формат файла — он работает только с тем, что возвращает процессор.
Процессор в ESLint определяется как объект с двумя методами:
module.exports = {
preprocess(text, filename) {
return [text];
},
postprocess(messages, filename) {
return messages.flat();
}
};
Каждый метод имеет строго определённую ответственность.
Метод preprocess получает:
Он обязан вернуть массив строк, где каждая строка рассматривается ESLint как отдельный виртуальный файл.
Основные задачи:
Пример извлечения скриптов из HTML:
preprocess(text) {
const scripts = [];
const regex = /<script>([\s\S]*?)<\/script>/g;
let match;
while ((match = regex.exec(text)) !== null) {
scripts.push(match[1]);
}
return scripts;
}
В данном случае каждый блок <script> становится
отдельной единицей анализа.
Метод postprocess принимает:
И возвращает единый массив сообщений.
Задачи postprocess:
Пример объединения результатов:
postprocess(messages) {
return messages.reduce((acc, curr) => acc.concat(curr), []);
}
В более сложных реализациях выполняется корректировка строк и столбцов с учётом смещения внутри исходного файла.
Одной из ключевых проблем при работе с процессорами является корректное отображение ошибок на исходный файл. Так как ESLint анализирует виртуальные фрагменты, их координаты не совпадают с оригинальным документом.
Для решения используется механизм смещения:
Пример логики смещения:
postprocess(messages, filename) {
return messages.map((block, index) => {
const offset = lineOffsets[index];
return block.map(msg => ({
...msg,
line: msg.line + offset,
filename
}));
}).flat();
}
Процессоры активно используются в расширениях ESLint для различных типов файлов.
Файлы .vue содержат сразу несколько языковых секций:
<template><script><style>Процессор выделяет JavaScript-часть и передаёт её в ESLint.
В Markdown часто встречаются блоки кода:
# Документация
```js
const x = 10;
Процессор извлекает кодовые блоки и анализирует их отдельно.
#### HTML-файлы
HTML может содержать inline-скрипты, которые требуют отдельной обработки.
### Отличие процессоров от парсеров
Процессор и парсер выполняют разные задачи в архитектуре ESLint:
- **Парсер** преобразует JavaScript в AST (абстрактное синтаксическое дерево)
- **Процессор** подготавливает входной текст и управляет его сегментацией
Процессор работает до этапа парсинга и не взаимодействует с AST напрямую.
### Ограничения процессоров
Несмотря на гибкость, процессоры имеют ряд ограничений:
- невозможность изменения логики правил ESLint
- отсутствие доступа к AST
- необходимость ручного управления координатами
- усложнение отладки при большом количестве виртуальных файлов
Также неправильная реализация postprocess может привести к некорректному отображению ошибок.
### Взаимодействие с конфигурацией ESLint
Процессоры подключаются через конфигурационный файл:
```json
{
"plugins": ["html"],
"processor": "html/html"
}
Или через plugin-конфигурацию:
module.exports = {
processors: {
".html": require("./processors/html")
}
};
Это позволяет привязывать обработку к конкретным расширениям файлов.
В сложных сценариях процессоры могут быть каскадными. Один процессор подготавливает данные, другой уточняет структуру, третий выполняет финальную сегментацию. Такая архитектура используется в крупных фреймворках, где один файл содержит несколько уровней вложенности кода.
Пример:
<script>Процессоры расширяют ESLint за пределы классического JavaScript-анализа, превращая его в универсальный инструмент статического анализа текстовых структур. Они позволяют стандартизировать подход к проверке кода независимо от его контейнера и обеспечивают единый механизм обработки ошибок для разноформатных файлов.