Markdown-парсер и рендерер на чистом OneScript. Без зависимостей от Markdig или другой нативной библиотеки — реализация работает в любой среде, где есть OneScript.
Поддерживается ядро CommonMark 0.31.2 и набор расширений GitHub-Flavored Markdown (tables, tasklists, strikethrough, autolinks).
Из хаба opm:
opm install oscript-mdИз исходников (например, склонированный репозиторий):
opm install --local
opm build .После установки библиотека доступна в любом скрипте через стандартное:
#Использовать "oscript-md"#Использовать "oscript-md"
HTML = Markdown.ВHTML("# Привет, мир!");
// → "<h1>Привет, мир!</h1>" + Символы.ПСЧетыре функции фасада Markdown.*:
| Функция | Что возвращает | Когда полезна |
|---|---|---|
Markdown.ВHTML(текст[, настройки]) |
HTML-строку | Рендеринг в веб/email/preview |
Markdown.Разобрать(текст[, настройки]) |
MarkdownДокумент (AST) |
Программная обработка содержимого |
Markdown.ВJSON(текст[, настройки]) |
JSON-сериализация AST | Snapshot-тесты, интеграции, отладка |
Markdown.ВТекст(текст[, настройки]) |
plain text без разметки | Telegram, email, логи, changelog |
#Использовать "oscript-md"
Исходник =
"# Заголовок" + Символы.ПС +
"" + Символы.ПС +
"Параграф с **жирным** и *курсивом*." + Символы.ПС +
"" + Символы.ПС +
"- пункт списка" + Символы.ПС +
"- ещё пункт";
Сообщить(Markdown.ВHTML(Исходник));
// <h1>Заголовок</h1>
// <p>Параграф с <strong>жирным</strong> и <em>курсивом</em>.</p>
// <ul>
// <li>пункт списка</li>
// <li>ещё пункт</li>
// </ul>Документ = Markdown.Разобрать("# Привет" + Символы.ПС + Символы.ПС + "Параграф");
Сообщить(Документ.Дети.Количество()); // 2
Сообщить(Документ.Дети[0].ТипУзла()); // heading
Сообщить(Документ.Дети[0].Уровень); // 1
Сообщить(Документ.Дети[1].ТипУзла()); // paragraphAST-узлы доступны напрямую — можно собирать документы программно:
Документ = Новый MarkdownДокумент();
Заголовок = Новый MarkdownЗаголовок(2);
Заголовок.Добавить(Новый MarkdownТекст("Сгенерировано"));
Документ.Добавить(Заголовок);
Рендерер = Новый MarkdownHTMLРендерер();
HTML = Рендерер.Отрендерить(Документ); // <h2>Сгенерировано</h2>JSON = Markdown.ВJSON("# Hi");
// {"type":"document","children":[
// {"type":"heading","level":1,"children":[
// {"type":"text","value":"Hi"}
// ]}
// ]}Текст = Markdown.ВТекст("# Заголовок" + Символы.ПС + Символы.ПС + "Параграф *с курсивом*");
// "Заголовок\n\nПараграф с курсивом"// Чистый CommonMark без расширений.
Настройки = Markdown.НастройкиCommonMark();
// CommonMark + tables + tasklists + strikethrough + autolinks.
Настройки = Markdown.НастройкиGitHubLike();
// CommonMark + по умолчанию ничего, но безопасный режим включён.
Настройки = Markdown.НастройкиПоУмолчанию();
HTML = Markdown.ВHTML(Текст, Настройки);Доступные пресеты: commonmark (он же minimal), default, github-like,
documentation, zero.
Настройки = Новый MarkdownНастройки("commonmark");
Настройки.Расширения.Включить("tables");
Настройки.Расширения.Включить("strikethrough");
HTML = Markdown.ВHTML(Текст, Настройки);МД =
"| Колонка 1 | Колонка 2 |" + Символы.ПС +
"|-----------|:---------:|" + Символы.ПС +
"| A | B |" + Символы.ПС +
"| C | D |";
HTML = Markdown.ВHTML(МД, Markdown.НастройкиGitHubLike());
// <table>
// <thead><tr><th>Колонка 1</th><th align="center">Колонка 2</th></tr></thead>
// <tbody>
// <tr><td>A</td><td align="center">B</td></tr>
// <tr><td>C</td><td align="center">D</td></tr>
// </tbody>
// </table>МД =
"- [x] выполнено" + Символы.ПС +
"- [ ] в работе";
HTML = Markdown.ВHTML(МД, Markdown.НастройкиGitHubLike());
// <ul>
// <li><input type="checkbox" checked disabled /> выполнено</li>
// <li><input type="checkbox" disabled /> в работе</li>
// </ul>По умолчанию БезопасныйРежим = Истина: raw HTML экранируется, опасные
конструкции не пройдут в выход.
HTML = Markdown.ВHTML("<script>alert(1)</script>");
// "<script>alert(1)</script>"Чтобы разрешить raw HTML (например, для доверенного содержимого):
Настройки = Markdown.НастройкиПоУмолчанию();
Настройки.БезопасныйРежим = Ложь;
Настройки.РазрешитьRawHTML = Истина;Расширения регистрируют свои компоненты в MarkdownРеестрКомпонентов через
метод Зарегистрировать(Реестр). Полная схема — в исходниках расширений
src/extensions/Классы/ (tables / tasklists /
strikethrough / autolinks).
| Возможность | Статус | Примечание |
|---|---|---|
ATX-заголовки (#, ##, …) |
✅ | |
Setext-заголовки (===, --- под текстом) |
✅ | |
| Параграфы | ✅ | |
Тематические линии (---, ***, ___) |
✅ | |
| Indented code blocks (4 пробела) | ✅ | |
Fenced code blocks (```, ~~~) |
✅ | С info-string и language-* классом |
| HTML-блоки | ✅ | |
Блок-цитаты (>) |
✅ | |
Маркированные списки (-, *, +) |
✅ | |
| Нумерованные списки | ✅ | |
| Вложенные списки | ✅ | |
| Reference link definitions | ✅ |
| Возможность | Статус | Примечание |
|---|---|---|
Жирный (**, __) |
✅ | |
Курсив (*, _) |
✅ | |
Inline code (`) |
✅ | |
Ссылки [text](url "title") |
✅ | |
Reference-ссылки [text][ref] |
✅ | |
Изображения  |
✅ | |
Автоссылки <https://…>, <mail@…> |
✅ | |
| Raw inline HTML | ✅ | Экранируется в безопасном режиме |
Backslash escapes (\*, \[, …) |
✅ | |
HTML-сущности (&, *, *) |
✅ | |
Hard line break (\ или 2+ пробела + \n) |
✅ | |
| Soft line break | ✅ |
| Расширение | Статус | Имя в MarkdownНаборРасширений |
|---|---|---|
Таблицы (pipe tables, alignment :---:) |
✅ | tables |
Списки задач (- [ ], - [x]) |
✅ | tasklists |
Зачёркивание (~~текст~~) |
✅ | strikethrough |
Расширенные автоссылки (www., https:// без <>) |
✅ | autolinks |
| Рендерер | Назначение |
|---|---|
MarkdownHTMLРендерер |
CommonMark-совместимый HTML |
MarkdownJSONРендерер |
JSON-сериализация AST |
MarkdownТекстовыйРендерер |
Plain text без разметки |
| Возможность | Статус | Примечание |
|---|---|---|
| Экранирование HTML в тексте | ✅ | |
| Безопасный режим (raw HTML → escape) | ✅ | По умолчанию включён |
| URL %-encoding по CommonMark | ✅ | |
| Heading id / якоря | ⏳ | Пресет documentation зарезервирован |
| Frontmatter (YAML/TOML) | ⏳ | Пресет documentation зарезервирован |
| TOC | ⏳ | Пресет documentation зарезервирован |
| Markdown normalizer | ⏳ | |
Санитайзер опасных URL (javascript: и т. п.) |
⏳ | Сейчас только %-encoding, политики нет |
CommonMark 0.31.2 conformance: 646 / 652 примеров проходят, 6 помечены
как xfail (см. раздел «Известные ограничения CommonMark» ниже).
Шесть примеров официальной CommonMark 0.31.2 conformance suite сейчас
помечены &Выключен и не падают CI. Все случаи касаются тонкостей
container-модели (CM §4.7) и относятся к одной из трёх групп.
Расширение табов на границе контейнера (список, цитата) рассчитано не до конца — нужна полноценная обработка префикса строки контейнера на смешанных tab/space отступах.
| # | Что не работает |
|---|---|
| 5 | Tab внутри элемента списка — расширение таба на границе контейнера |
| 6 | Tab внутри цитаты — расширение через границу маркера > |
| 7 | Tab внутри элемента списка — расчёт отступа при двойном табе |
| # | Что не работает |
|---|---|
| 93 | Setext-подчёркивание в строке ленивого продолжения цитаты. CM запрещает создавать setext-заголовок из lazy continuation line, у нас он создаётся |
| # | Что не работает |
|---|---|
| 236 | Цитата + indented code block: CM считает внешнее indented-содержимое отдельным блоком, наш парсер цитат захватывает его через lazy continuation |
| 237 | Fenced code внутри цитаты без закрывающего ограждения: закрывающий fence тоже должен нести префикс >; без него ограждение остаётся открытым до конца цитаты |
Скрипт-генератор тестов хранит этот список внутри
tools/sync-commonmark.py (константа SKIP_LIST).
При исправлении соответствующего бага в парсере нужно убрать номер из
константы и перегенерировать сьюты.
tasks/*.os дёргают oneunit как CLI, поэтому он должен быть в PATH —
ставим его глобально. asserts и 1commands подтянутся как локальные
dev-зависимости из packagedef.
opm install oneunit # test-runner глобально (нужен в PATH)
opm install --local --dev # asserts, 1commands → ./oscript_modules
oscript tasks/test.os # все тесты + JUnit-отчёты в build/reports/
oscript tasks/test_unit.os # только юнит-тесты
oscript tasks/test_commonmark.os # только CommonMark conformanceCommonMark-сьюты автогенерируются из официальной спецификации. Список
xfail-примеров хранится в самом скрипте (SKIP_LIST в начале файла):
python tools/sync-commonmark.py 0.31.2Подробнее об устройстве — в paln.md.
MIT © 2026 Egor Ivanov