HAST (Hypertext Abstract Syntax Tree) представляет собой абстрактное дерево, описывающее структуру HTML-документа на уровне синтаксиса, независимо от текстового представления. В экосистеме JavaScript HAST активно используется вместе с библиотекой Rehype, позволяя работать с HTML как с объектной моделью и преобразовывать её обратно в строку.
Для преобразования HAST в HTML применяются два ключевых пакета:
rehype-stringify – основной модуль для
сериализации HAST.unified – движок обработки AST,
позволяющий строить цепочки обработки.Простейший пример сериализации выглядит следующим образом:
import { unified } from 'unified';
import rehypeStringify from 'rehype-stringify';
const hast = {
type: 'root',
children: [
{
type: 'element',
tagName: 'p',
properties: {},
children: [
{ type: 'text', value: 'Пример текста в параграфе.' }
]
}
]
};
const html = unified()
.use(rehypeStringify)
.stringify(hast);
console.log(html); // <p>Пример текста в параграфе.</p>
Ключевые моменты:
type: 'root' обязательно для корневого узла HAST.children содержит элементы типа element
или text.rehypeStringify превращает AST обратно в HTML.Библиотека rehype-stringify поддерживает множество опций:
allowDangerousHtml – разрешает вставку
необработанного HTML из HAST, предотвращая экранирование.closeSelfClosing – контролирует формат
самозакрывающихся тегов (<img /> или
<img>).entities – настраивает обработку
HTML-сущностей (&, < и
т.д.).Пример с кастомными настройками:
const html = unified()
.use(rehypeStringify, { allowDangerousHtml: true, closeSelfClosing: false })
.stringify(hast);
HAST может описывать многоуровневые структуры с вложенными элементами, атрибутами и комментариями. Важные моменты:
Атрибуты передаются через поле properties.
Комментарии и инструкции можно включать через типы
comment и doctype.
Для обработки стилей и классов используются объекты в
properties:
{
type: 'element',
tagName: 'div',
properties: { className: ['container'], id: 'main' },
children: []
}Пример сериализации сложного дерева:
const complexHast = {
type: 'root',
children: [
{ type: 'doctype', name: 'html' },
{
type: 'element',
tagName: 'html',
properties: {},
children: [
{
type: 'element',
tagName: 'head',
properties: {},
children: [
{ type: 'element', tagName: 'title', properties: {}, children: [{ type: 'text', value: 'Документ' }] }
]
},
{
type: 'element',
tagName: 'body',
properties: {},
children: [
{
type: 'element',
tagName: 'h1',
properties: {},
children: [{ type: 'text', value: 'Заголовок уровня 1' }]
},
{
type: 'element',
tagName: 'p',
properties: { className: ['lead'] },
children: [{ type: 'text', value: 'Абзац с классом lead.' }]
}
]
}
]
}
]
};
После сериализации rehype-stringify создаст корректный
HTML с учётом всех атрибутов, тегов и структуры.
text узлов может ускорить сериализацию.hast-util-to-html:
альтернативный инструмент для конвертации HAST в строку, предлагающий
тонкую настройку вывода и меньший вес, чем полный
rehype.Пример использования hast-util-to-html:
import { toHtml } from 'hast-util-to-html';
const htmlString = toHtml(hast, { allowDangerousHtml: true });
HAST может содержать небезопасные фрагменты. Чтобы предотвратить XSS:
sanitize перед сериализацией.rehype-sanitize вместе с
rehype-stringify.allowDangerousHtml только проверенными
блоками.Пример цепочки:
import rehypeSanitize from 'rehype-sanitize';
const safeHtml = unified()
.use(rehypeSanitize)
.use(rehypeStringify)
.stringify(hast);
HAST часто получается из MDAST (Markdown AST) через
remark-rehype:
import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkRehype from 'remark-rehype';
import rehypeStringify from 'rehype-stringify';
const markdown = '# Заголовок\n\nТекст абзаца.';
const html = unified()
.use(remarkParse)
.use(remarkRehype)
.use(rehypeStringify)
.processSync(markdown)
.toString();
Здесь remark-rehype конвертирует Markdown AST в HAST, а
rehype-stringify сериализует его в HTML строку. Такой
подход позволяет полностью контролировать процесс преобразования от
Markdown до HTML, включая обработку атрибутов, классов и вложенных
элементов.
stringify.rehype-stringify для точного соответствия
требованиям HTML.