Markdown
Текст страниц пишется на Markdown. Движок преобразует Markdown в BEMTree — ту же модель данных, из которой собирает вёрстку страницы и обёртку документа HTML.
Markdown разбирает связка remark/unified: сначала micromark сканирует текст, затем remark строит mdast — типизированное дерево Markdown. Почему не markdown-it, объясняет решение о движке Markdown.
Что поддерживает ядро
Ядро поддерживает CommonMark, а также возможности GFM: таблицы, зачёркивание ~~текст~~, списки задач (- [x]) и автоматические ссылки. Оно также разбирает директивы :::name для markdown-расширений. Мост mdast → BEMJSON преобразует разобранные узлы в BEMTree.
Иерархические якоря
Движок назначает заголовкам идентификаторы по правилу иерархических якорей. Если раздел вложен, идентификатор составной:
# Шины → id="шины"
## Зимние → id="шины-зимние"
### Шипованные → id="шины-зимние-шипованные"
Кириллица сохраняется в идентификаторах — без транслитерации и без кодирования. Нумерованный префикс (1. , 1.2. ) убирается из видимого заголовка и якоря; косую черту заменяет дефис. Точки в остальном тексте сохраняются: # Версия 2.4.3. получает якорь версия-2.4.3.. Ссылаться на якорь можно прямо кириллицей.
Собственный идентификатор задают суффиксом {#id} в обычном тексте в конце заголовка, например # **Title** {#custom}. Суффикс удаляется из видимого текста; внутри кода, ссылки или выделения он остаётся обычным содержимым.
Перекрёстные ссылки
Авторы пишут обычные ссылки в Markdown на файлы .md:
См. [модель данных](../how/bemjson.ru.md).
Движок преобразует путь в адрес по карте md2url, построенной из карты сайта. Можно сослаться и на якорь другого документа:
См. [шипы](../free/tyres.md#шины-зимние-шипованные).
Движок превращает якорь в итоговый иерархический идентификатор целевой страницы. Ссылка на отсутствующий документ .md прерывает сборку. Неизвестные фрагменты сохраняются: шаблон страницы может добавлять собственные идентификаторы. Автору не нужно знать итоговый адрес — достаточно пути к файлу.
Изображения
Ссылка на изображение в Markdown — логический адрес. По общему для Markdown и CSS файлу image-mapping.json движок находит хэшированный адрес семейства изображения. Подготовленные варианты AVIF/WebP копирует стадия изображений, а формат выбирает сервер. Подробнее — изображения в результате сборки.
 → <img class=article__image src=/_ia1b2c3d4e5f6a7b8 alt="Подпись">
Автор указывает одну ссылку, сервер отдаёт подходящий формат.
Типографика
Типографика русского текста — это markdown-расширение: до сборки HTML оно проходит по дереву Markdown и не даёт тире отрываться от слова — ставит неразрывный пробел перед длинным тире и обычный после. Узлы кода расширение не трогает.
Поскольку это расширение, а не часть ядра, англоязычному сайту оно не нужно — его просто не подключают.
Конструкции markdown-разметки — расширения
Галерея, сетка, выноска и видео в ядро не входят. Ядро не знает конкретных конструкций :::gallery или :::callout. Их добавляют markdown-расширения: обработчик преобразует конструкцию в узлы BEMJSON нужного блока.
:::gallery
 
:::
Здесь :::gallery — синтаксис markdown-расширения. Без расширения движок убирает оболочку директивы и обрабатывает Markdown внутри неё как обычно. См. каталог markdown-расширений.
Встроенный HTML
Встроенный HTML из Markdown (например, <span> в тексте) сохраняется как raw: сериализатор не экранирует и не минимизирует его. Парсер не очищает HTML и не проверяет структуру документа. При этом отдельный проход переписывает логические пути в img src по карте изображений. Передавайте только доверенный HTML.
Карта изображений меняет значения настоящих атрибутов img src, с кавычками или без них. Текст, похожий на изображение, внутри атрибутов, комментариев, скриптов, стилей и элементов с буквальным содержимым сохраняется.
Пробелы разобранного текста возле встроенного HTML и ссылок сохраняются: в Hello <em>world</em> остаётся разделяющий пробел, а в x[link](/target) новый пробел не добавляется. Типографика остаётся опциональной.
Программный вызов
При сборке ссылки и пути к изображениям отсчитываются от каталога текущего файла Markdown внутри корня контента. Имя корневого каталога на разрешение путей не влияет. При самостоятельном вызове createMarkdown передайте в sourceFile путь к файлу относительно корня контента; при необходимости сохраните inputPath для диагностики и существующих интеграций.
import { createMarkdown } from 'nuckty';
const { tree } = createMarkdown({
sourceFile: 'guide/start.md',
inputPath: './content/guide/start.md',
md2url: { 'index.md': '/' },
imageMapping: { 'images/logo.png': '_i1234567890123456' },
}).render('[Home](../index.md) ');