Работа с токенами

ESLint анализирует исходный код JavaScript через многоуровневую модель представления программы. После этапа парсинга формируется абстрактное синтаксическое дерево (AST), однако для большинства правил одного AST недостаточно. Более низкоуровневое представление — токены — позволяет работать с исходным кодом с точностью до лексических единиц.

Токен представляет собой минимальный значимый элемент исходного текста: идентификатор, ключевое слово, оператор, литерал, пунктуационный символ. В отличие от узлов AST, токены сохраняют полную информацию о исходной структуре кода, включая форматирование и синтаксические детали, которые обычно теряются на уровне дерева.

Модель токенов в SourceCode

Внутри ESLint доступ к токенам осуществляется через объект SourceCode, который инкапсулирует результаты парсинга.

Ключевой интерфейс:

  • sourceCode.tokensAndComments
  • sourceCode.tokens
  • sourceCode.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.

Доступ к токенам через SourceCode API

Основные методы для навигации по токенам:

Получение соседних токенов

  • 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: различие уровней анализа

AST ориентирован на структуру программы, токены — на её текстовое представление.

Пример:

const x = 1 + 2;

AST может представить это как:

  • VariableDeclaration

    • VariableDeclarator

      • Identifier
      • BinaryExpression

Токены же будут включать:

  • const
  • x
  • =
  • 1
  • 2
  • ;

Эта разница критична при создании правил, связанных с форматированием, пробелами и стилем.

Работа с диапазонами и позициями

Каждый токен имеет 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 рассматриваются как отдельный тип токенов, но часто обрабатываются совместно.

Типы комментариев:

  • Line comment (//)
  • Block comment (/* */)

Доступ:

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
  • использование диапазонов вместо повторного поиска токенов
  • избегание вложенных циклов по токенам при больших файлах

Роль токенов в разработке правил

Токены становятся ключевым инструментом при создании правил, связанных с:

  • стилем кода
  • пробелами и форматированием
  • операторной структурой
  • синтаксическими ограничениями, не выраженными в AST

Именно на уровне токенов реализуются правила, аналогичные:

  • контроль пробелов вокруг операторов
  • проверка наличия точек с запятой
  • анализ переносов строк
  • проверка расположения скобок