Любой процесс линтинга в ESLint начинается с преобразования исходного текста файла в структуру, пригодную для анализа. Исходный JavaScript-код сам по себе представляет последовательность символов, не содержащую явных сведений о синтаксической структуре. Для статического анализа требуется формальное представление — AST (Abstract Syntax Tree), или абстрактное синтаксическое дерево.
ESLint не выполняет парсинг самостоятельно. Он делегирует эту задачу
подключаемому парсеру, который превращает текст в AST. В экосистеме чаще
всего используется стандартный парсер espree, однако
архитектура позволяет подключать альтернативы, такие как
@babel/eslint-parser или
@typescript-eslint/parser.
Парсер является первым звеном цепочки анализа кода. Его задачи:
Парсер не интерпретирует код и не выполняет его. Он работает исключительно на уровне синтаксиса.
Ключевое требование к AST в ESLint — соответствие стандарту ESTree. Это соглашение описывает структуру узлов JavaScript-кода: выражения, объявления, операторы и другие конструкции.
Перед построением AST парсер выполняет лексический анализ, или токенизацию. На этом этапе исходный код разбивается на последовательность токенов — минимальных значимых единиц языка.
Пример:
const sum = a + b;
Токены:
const — ключевое словоsum — идентификатор= — оператор присваиванияa — идентификатор+ — оператор сложенияb — идентификатор; — разделитель выраженияТокены не содержат иерархии. Они лишь фиксируют линейную структуру текста.
После токенизации начинается синтаксический разбор. Парсер анализирует последовательность токенов и строит дерево, отражающее грамматику языка.
Рассмотрим тот же пример:
const sum = a + b;
AST будет иметь примерно следующую структуру:
Program
VariableDeclaration
VariableDeclarator
Identifier (sum)
BinaryEx * pression (+)
Каждый узел AST представляет конструкцию языка и содержит:
type — тип узла (например,
VariableDeclaration);start и end — позиции в исходном
коде;ESLint использует формат ESTree как базовый контракт между парсером и линтером. Это обеспечивает совместимость различных парсеров и правил.
Основные характеристики ESTree:
Например, условный оператор:
if (x > 0) {
y = 1;
}
Представляется как:
IfStatement
Стандартный ESTree не покрывает все современные расширения JavaScript. Поэтому парсеры расширяют базовую модель.
Для React-кода добавляются узлы:
Пример:
<Button disabled />
AST включает JSX-структуру, не существующую в базовом JavaScript-спецификации.
TypeScript добавляет узлы:
Пример:
let value: number = 10;
AST фиксирует тип аннотации как отдельный подузел.
Помимо AST, парсер возвращает дополнительные структуры:
ecmaVersion,
sourceType).Комментарии не входят в дерево, но сохраняются отдельно, так как
правила ESLint могут их анализировать (например,
/* eslint-disable */).
После парсинга ESLint формирует объект SourceCode, объединяющий AST и сопутствующие данные.
Он содержит:
Эта структура используется правилами при анализе.
После построения AST начинается его обход. ESLint использует модель visitor pattern, где каждое правило подписывается на интересующие типы узлов.
Пример логики:
VariableDeclaration вызывается
обработчик;Таким образом, AST становится основой для декларативного анализа.
Исходный код:
function add(a, b) {
return a + b;
}
Этапы обработки:
Токенизация:
Построение AST:
FunctionDeclaration
Identifier (add)
params: [a, b]
body: BlockStatement
ReturnStatement
Обогащение SourceCode:
AST является центральным элементом всей системы ESLint. Без него невозможны:
Каждое правило ESLint оперирует не текстом, а структурированными узлами, что делает анализ точным и предсказуемым.
Несмотря на мощность, парсинг имеет ограничения:
Тем не менее архитектура ESLint допускает гибкую замену парсера без изменения логики правил.
AST, используемый ESLint, совпадает по концепции с деревьями в других инструментах:
Общая модель позволяет различным инструментам взаимодействовать через единое представление структуры кода.