ESLint анализирует исходный код JavaScript через многоуровневую модель представления программы. После этапа парсинга формируется абстрактное синтаксическое дерево (AST), однако для большинства правил одного AST недостаточно. Более низкоуровневое представление — токены — позволяет работать с исходным кодом с точностью до лексических единиц.
Токен представляет собой минимальный значимый элемент исходного текста: идентификатор, ключевое слово, оператор, литерал, пунктуационный символ. В отличие от узлов AST, токены сохраняют полную информацию о исходной структуре кода, включая форматирование и синтаксические детали, которые обычно теряются на уровне дерева.
Внутри ESLint доступ к токенам осуществляется через объект
SourceCode, который инкапсулирует результаты парсинга.
Ключевой интерфейс:
sourceCode.tokensAndCommentssourceCode.tokenssourceCode.commentsНа практике основная работа ведётся через sourceCode,
получаемый из контекста правила:
create(context) {
const sourceCode = context.getSourceCode();
}
Токены доступны как упорядоченный массив, отражающий последовательность исходного текста.
Каждый токен содержит минимальный набор полей:
type — тип токена (Identifier, Keyword, Punctuator,
Numeric, String и др.)value — текстовое значениеrange — позиция в исходном коде (индексы символов)loc — координаты (строка и столбец)Пример логической структуры:
{
"type": "Identifier",
"value": "console",
"range": [10, 18],
"loc": {
"start": { "line": 2, "column": 4 },
"end": { "line": 2, "column": 12 }
}
}
Точность позиционирования позволяет выполнять анализ форматирования, пробелов и синтаксических конструкций, не представленных в AST.
Основные методы для навигации по токенам:
getTokenBefore(nodeOrToken, options)getTokenAfter(nodeOrToken, options)Используются для анализа контекста вокруг узла AST или другого токена.
Пример:
const tokenBefore = sourceCode.getTokenBefore(node);
const tokenAfter = sourceCode.getTokenAfter(node);
Эти методы учитывают пробелы и комментарии в зависимости от параметров.
getFirstToken(node)getLastToken(node)getFirstTokenBetween(nodeA, nodeB)getLastTokenBetween(nodeA, nodeB)Позволяют точно определить границы синтаксической конструкции.
Пример:
const first = sourceCode.getFirstToken(node);
const last = sourceCode.getLastToken(node);
AST ориентирован на структуру программы, токены — на её текстовое представление.
Пример:
const x = 1 + 2;
AST может представить это как:
VariableDeclaration
VariableDeclarator
Токены же будут включать:
Эта разница критична при создании правил, связанных с форматированием, пробелами и стилем.
Каждый токен имеет range, что позволяет вычислять точные
фрагменты исходного кода.
Пример вычисления подстроки:
const [start, end] = token.range;
const text = sourceCode.text.slice(start, end);
Это используется в правилах, которые модифицируют код или проверяют его формат.
loc дополняет информацию координатами:
Это особенно важно для генерации диагностических сообщений.
Метод getTokensBetween позволяет извлекать
последовательности токенов между двумя узлами AST.
const tokens = sourceCode.getTokensBetween(nodeA, nodeB);
Используется для анализа выражений, операторов и разделителей.
Применения:
Методы getTokens и getTokensBetween
поддерживают фильтрацию:
sourceCode.getTokens(node, { includeComments: false });
Дополнительные параметры позволяют учитывать:
Это важно при создании точных правил, зависящих от синтаксического контекста.
Комментарии в ESLint рассматриваются как отдельный тип токенов, но часто обрабатываются совместно.
Типы комментариев:
//)/* */)Доступ:
const comments = sourceCode.getAllComments();
или через:
sourceCode.comments
Комментарии используются для:
Токены можно сравнивать по позиции или значению.
Пример сравнения:
if (token1.range[0] < token2.range[0]) {
// token1 расположен раньше
}
Также возможно сравнение по типу и значению:
if (token.type === "Punctuator" && token.value === ";") {
}
ESLint фиксеры используют токены для точного редактирования текста.
Пример:
fix(fixer) {
const sourceCode = context.getSourceCode();
const token = sourceCode.getFirstToken(node);
return fixer.replaceText(token, "newValue");
}
Манипуляции на уровне токенов позволяют:
Одной из частых проблем является использование AST вместо токенов там, где требуется точность форматирования.
Ошибки включают:
node.range вместо токенов для
форматированияТакже важно учитывать, что токены могут включать синтетические элементы, добавленные парсером.
Работа с токенами обычно быстрее, чем глубокий обход AST, однако частые вызовы навигационных методов могут создавать накладные расходы.
Оптимизационные подходы:
getSourceCode()getTokenBefore/AfterТокены становятся ключевым инструментом при создании правил, связанных с:
Именно на уровне токенов реализуются правила, аналогичные: