StateCore, StateBlock, StateInline

Библиотека Markdown-it предоставляет мощную систему для обработки и анализа Markdown-текста. Основой этой системы являются три ключевых класса состояния: StateCore, StateBlock и StateInline. Они управляют процессом токенизации и рендеринга текста на разных уровнях, обеспечивая гибкую и расширяемую архитектуру парсера.


StateCore

StateCore — это центральный объект состояния, который используется при выполнении цепочки core rules. Основная задача StateCore — управлять списком токенов и обеспечивать возможность их изменения на глобальном уровне после первичной обработки документа.

Основные свойства:

  • src — исходный Markdown-текст.
  • env — объект окружения, который может хранить любые данные, необходимые для обработки.
  • tokens — массив токенов, который формируется на этапе парсинга и модифицируется core rules.
  • inlineMode — логический флаг, указывающий, находится ли обработка в контексте inline-уровня.

Методы и функционал:

  • push(token) — добавляет токен в массив tokens.
  • walkTokens(fn) — обходит все токены и применяет функцию fn к каждому.
  • getTokens() — возвращает массив токенов для внешнего использования.

Пример использования:

const md = require('markdown-it')();
md.core.ruler.push('example_core_rule', function(state) {
  state.tokens.push(new state.Token('custom_token', '', 0));
});

В этом примере создается core rule, которая добавляет пользовательский токен в конце массива.


StateBlock

StateBlock управляет обработкой блоков Markdown: заголовков, параграфов, списков, цитат, кодовых блоков. Он используется парсером для построения иерархии блоков и генерации соответствующих токенов.

Основные свойства:

  • src — исходный текст для блока.
  • bMarks — массив индексов начала каждой строки блока.
  • eMarks — массив индексов конца каждой строки блока.
  • tShift — массив отступов строк.
  • blkIndent — текущий уровень отступа блока.
  • lineMax — индекс последней строки документа.
  • line — текущая строка для обработки.
  • tokens — массив токенов, которые генерируются для блока.

Ключевые методы:

  • skipEmptyLines() — пропускает пустые строки и обновляет индекс текущей строки.
  • getLines(begin, end, indent, keepLastLF) — возвращает массив строк блока с учетом отступов.
  • push(type, tag, nesting) — создает и добавляет новый токен блока.
  • tokenize(state, startLine, endLine) — основной метод для создания токенов из блока текста.

Пример обработки блока кода:

function fenceBlock(state, startLine, endLine, silent) {
  const pos = state.bMarks[startLine] + state.tShift[startLine];
  const max = state.eMarks[startLine];
  const lineText = state.src.slice(pos, max);
  
  if (!lineText.startsWith('```')) return false;

  if (!silent) {
    const token = state.push('fence', 'code', 0);
    token.content = state.getLines(startLine + 1, endLine, 0, true);
  }
  state.line = endLine;
  return true;
}

Этот пример показывает, как StateBlock управляет извлечением строк блока и генерацией токена fence.


StateInline

StateInline отвечает за обработку inline-содержимого внутри блоков. Это могут быть жирный текст, ссылки, эмодзи, изображения и другие inline-элементы. Он работает на уровне текста внутри блоков и преобразует их в токены, которые затем рендерятся в HTML.

Основные свойства:

  • src — текст, который нужно разобрать на inline-токены.
  • pos — текущая позиция парсера внутри строки.
  • posMax — конечная позиция для обработки.
  • env — объект окружения для inline-уровня.
  • tokens — массив сгенерированных inline-токенов.

Ключевые методы:

  • push(type, tag, nesting) — добавляет новый inline-токен.
  • scanDelims(state, pos) — проверяет наличие символов-разделителей (например, * для жирного текста) и возвращает информацию о допустимых открывающих и закрывающих позициях.
  • tokenize(state) — основной метод для рекурсивного разбиения текста на inline-токены.

Пример обработки выделенного текста:

function strongRule(state, silent) {
  const start = state.pos;
  if (state.src[start] !== '*' || state.src[start + 1] !== '*') return false;

  if (!silent) {
    const token = state.push('strong_open', 'strong', 1);
    state.pos += 2;
    token = state.push('text', '', 0);
    token.content = 'выделенный текст';
    state.push('strong_close', 'strong', -1);
  }
  state.pos += 2;
  return true;
}

Этот пример демонстрирует, как StateInline управляет распознаванием и генерацией токенов для жирного текста.


Взаимодействие StateCore, StateBlock и StateInline

  1. StateCore управляет глобальным списком токенов и запускает core rules.
  2. StateBlock формирует токены блоков и передает текст для inline-обработки.
  3. StateInline анализирует строки блоков, создавая токены для inline-содержимого.

Последовательность работы выглядит следующим образом:

  1. Исходный текст передается в StateCore.
  2. StateCore запускает block parser, который создает StateBlock для каждого блока.
  3. StateBlock вызывает StateInline для обработки inline-содержимого внутри блоков.
  4. Все токены собираются обратно в StateCore.tokens для последующего рендеринга или модификации.

Эта система обеспечивает мощный и гибкий механизм обработки Markdown. Понимание структуры StateCore, StateBlock и StateInline позволяет создавать собственные правила, расширения и плагины для Markdown-it, полностью контролируя процесс парсинга на любом уровне.