Сериализация дерева MDAST (Markdown Abstract Syntax Tree) в Markdown — это процесс преобразования внутреннего представления документа обратно в текстовый формат Markdown. Это важный этап при работе с библиотеками Remark и Rehype, так как позволяет модифицировать дерево и сохранять результат в читаемом виде.
MDAST представляет документ как иерархическое дерево, где каждый узел имеет тип и набор свойств. Основные типы узлов:
root — корень дерева, содержит массив дочерних
узлов.paragraph — параграф, содержит текстовые узлы
(text), а также встроенные элементы (emphasis,
strong).heading — заголовок с уровнем (depth от 1
до 6).list и listItem — списки и элементы
списков.link и image — ссылки и изображения с
атрибутами url, title и т. д.code — блоки кода с возможностью указания языка
(lang).inlineCode — встроенный код внутри текста.Каждый узел может содержать дополнительные свойства, например
children для вложенных элементов. Понимание структуры
дерева критично для правильной сериализации.
remark-stringifyОсновной инструмент для обратной сериализации MDAST в Markdown — это
пакет remark-stringify, который
интегрируется с unified:
import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkStringify from 'remark-stringify';
const processor = unified()
.use(remarkParse)
.use(remarkStringify);
const markdown = `
# Заголовок
Пример **жирного текста** и *курсива*.
`;
const tree = processor.parse(markdown);
const output = processor.stringify(tree);
console.log(output);
В этом примере processor.stringify(tree) преобразует
MDAST обратно в Markdown с сохранением форматирования.
remark-stringifyremark-stringify предоставляет множество опций для
контроля формата выходного Markdown:
bullet — символ для маркеров
ненумерованных списков (*, -,
+).fence — символы для блоков кода
(``` или ~~~).incrementListMarker — автоматически
увеличивать нумерацию списков (true /
false).listItemIndent — тип отступа для
элементов списка (tab или 1/2
пробела).tightDefinitions — управляет
плотностью списка определений.emphasis и
strong — символы для выделения текста
(* или _).Пример настройки:
const processor = unified()
.use(remarkParse)
.use(remarkStringify, {
bullet: '-',
fence: '`',
listItemIndent: '1',
emphasis: '_',
strong: '*',
});
Проблемы с пробелами и отступами: Markdown
чувствителен к пробелам перед списками, заголовками и блоками кода.
remark-stringify старается сохранять исходные отступы, но
при ручной модификации дерева может потребоваться дополнительная
настройка параметров.
Обработка вложенных элементов: Вложенные списки,
цитаты и комбинированные элементы (emphasis внутри
link) требуют точного порядка обхода дерева.
remark-stringify автоматически обрабатывает вложенность, но
при добавлении нестандартных типов узлов нужно реализовать кастомные
сериализаторы.
Поддержка HTML внутри Markdown: Узлы типа
html сохраняются без изменений, что позволяет оставлять
встроенные HTML-блоки. Однако при манипуляции с деревом важно не
потерять эти узлы.
remark-stringify позволяет определять кастомные методы
для сериализации нестандартных узлов через опцию handlers.
Пример:
import { visit } from 'unist-util-visit';
const customProcessor = unified()
.use(remarkParse)
.use(remarkStringify, {
handlers: {
customNode(node) {
return `> ${node.value}\n`;
}
}
});
const tree = {
type: 'root',
children: [
{ type: 'customNode', value: 'Это пользовательский блок' }
]
};
const output = customProcessor.stringify(tree);
console.log(output);
Этот подход позволяет сериализовать любые нестандартные узлы в желаемый Markdown-формат.
Для случаев, когда необходимо преобразовывать Markdown → HTML → Markdown, часто используется цепочка Remark → Rehype → Remark. Основные шаги:
remark-parse.remark-rehype.rehype-remark.remark-stringify.Такой подход полезен для обработки HTML-специфичных узлов и сохранения расширенной разметки при обратной сериализации.
console.log(JSON.stringify(tree, null, 2)).handlers для нестандартных узлов,
чтобы избежать потери информации при сериализации.Сочетание MDAST, remark-stringify и, при необходимости, Rehype позволяет создавать мощные инструменты для анализа, модификации и генерации Markdown-документов с высокой точностью форматирования.