oscript-mdпакет
Пакет лежит в основном пуле хаба: короткой формы достаточно, если хаб прописан сервером пакетов в opm.cfg.
opm install oscript-mdУстановка на opm младше 1.7.0
Легаси-флоу. Клиент младше 1.7.0 адрес пула в аргументе не разбирает: пул сначала прописывают сервером пакетов, и только потом ставят через него. На 1.7.0 и новее этот раздел не нужен — хватает команды из шапки страницы.
Добавьте пул сервером пакетов в opm.cfg. Порт продублирован в «Сервер»: у opm push поле «Порт» не читается.
{
"СервераПакетов": [
{
"Имя": "default",
"Сервер": "https://hub.1cdevelopers.ru",
"Порт": 443,
"ПутьНаСервере": "/api/v1/pools/default/download/",
"РесурсПубликацииПакетов": "/api/v1/pools/default/push",
"Приоритет": 1
}
]
}И ставьте пакет, указывая сервер:
opm install -m default oscript-mdОписание
oscript-md
Markdown-парсер и рендерер на чистом OneScript. Без зависимостей от Markdig или другой нативной библиотеки — реализация работает в любой среде, где есть OneScript.
Поддерживается ядро CommonMark 0.31.2 и набор расширений
GitHub-Flavored Markdown (tables, tasklists, strikethrough, autolinks).
Недоверенный Markdown рендерится сразу в безопасный HTML —
Markdown.ВБезопасныйHTML, см. «Недоверенный Markdown».
Установка
Из хаба opm:
opm install oscript-md
Единственная зависимость времени выполнения —
html-sanitizer: её зовёт
Markdown.ВБезопасныйHTML. Разбор и рендеринг Markdown сторонних библиотек
не требуют.
Из исходников (например, склонированный репозиторий):
opm install --local
opm build .
После установки библиотека доступна в любом скрипте через стандартное:
#Использовать "oscript-md"
Быстрый старт
#Использовать "oscript-md"
HTML = Markdown.ВHTML("# Привет, мир!");
// → "<h1>Привет, мир!</h1>" + Символы.ПС
Функции фасада Markdown.*:
| Функция | Что возвращает | Когда полезна |
|---|---|---|
Markdown.ВHTML(текст[, настройки]) |
HTML-строку | Рендеринг своего Markdown в веб/email/preview |
Markdown.ВБезопасныйHTML(текст[, настройки[, allowlist]]) |
санитизированный HTML | Рендеринг чужого Markdown: README, комментарии, ввод пользователя |
Markdown.Разобрать(текст[, настройки]) |
MarkdownДокумент (AST) |
Программная обработка содержимого |
Markdown.ВJSON(текст[, настройки]) |
JSON-сериализация AST | Snapshot-тесты, интеграции, отладка |
Markdown.ВТекст(текст[, настройки]) |
plain text без разметки | Telegram, email, логи, changelog |
Примеры использования
HTML-рендеринг
#Использовать "oscript-md"
Исходник =
"# Заголовок" + Символы.ПС +
"" + Символы.ПС +
"Параграф с **жирным** и *курсивом*." + Символы.ПС +
"" + Символы.ПС +
"- пункт списка" + Символы.ПС +
"- ещё пункт";
Сообщить(Markdown.ВHTML(Исходник));
// <h1>Заголовок</h1>
// <p>Параграф с <strong>жирным</strong> и <em>курсивом</em>.</p>
// <ul>
// <li>пункт списка</li>
// <li>ещё пункт</li>
// </ul>
Работа с AST
Документ = Markdown.Разобрать("# Привет" + Символы.ПС + Символы.ПС + "Параграф");
Сообщить(Документ.Дети.Количество()); // 2
Сообщить(Документ.Дети[0].ТипУзла()); // heading
Сообщить(Документ.Дети[0].Уровень); // 1
Сообщить(Документ.Дети[1].ТипУзла()); // paragraph
AST-узлы доступны напрямую — можно собирать документы программно:
Документ = Новый MarkdownДокумент();
Заголовок = Новый MarkdownЗаголовок(2);
Заголовок.Добавить(Новый MarkdownТекст("Сгенерировано"));
Документ.Добавить(Заголовок);
Рендерер = Новый MarkdownHTMLРендерер();
HTML = Рендерер.Отрендерить(Документ); // <h2>Сгенерировано</h2>
JSON-сериализация AST
JSON = Markdown.ВJSON("# Hi");
// {"type":"document","children":[
// {"type":"heading","level":1,"children":[
// {"type":"text","value":"Hi"}
// ]}
// ]}
Plain text
Текст = 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(Текст, Настройки);
GFM-таблицы
МД =
"| Колонка 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>
Списки задач (tasklists)
МД =
"- [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
Безопасный режим экранирует сырой HTML из исходника, но не проверяет то, что
собирает сам рендерер: ссылку [зло](javascript:alert(1)) он честно превратит в
<a href="javascript:alert(1)">. Поэтому для текста, который написал не вы —
README чужого пакета, комментарий, поле формы — нужен второй рубеж: санитизация
готового HTML по принципу allowlist.
Её выполняет библиотека html-sanitizer — свой санитайзер oscript-md не пишет. Фасад лишь склеивает рендер и очистку:
#Использовать "oscript-md"
HTML = Markdown.ВБезопасныйHTML(ТекстREADME); // рендер + очистка
HTML = Markdown.ОчиститьHTML(НедоверенныйHTML); // очистка готового HTML
| Функция | Назначение |
|---|---|
Markdown.ВБезопасныйHTML(текст[, настройки[, allowlist]]) |
разобрать Markdown, отрендерить и санитизировать |
Markdown.ОчиститьHTML(HTML[, allowlist]) |
санитизировать готовый HTML |
Markdown.НастройкиСанитизацииПоУмолчанию() |
профиль allowlist под вывод рендерера (новый объект на каждый вызов) |
Что остаётся в выходе по умолчанию: абзацы, заголовки, списки, strong/em,
code/pre с классом language-*, цитаты, таблицы с align, details/summary,
a с href/title и img с src/alt/title. Схемы URL — http, https,
mailto плюс относительные адреса; внешние ссылки получают rel="nofollow noopener".
Профиль покрывает и вывод GFM-расширений: del зачёркивания и input с type,
checked, disabled — чекбокс списка задач. Полное описание профиля, гарантий
и ограничений (гомоглифы в доменах, data:-картинки) — в README html-sanitizer.
Свой allowlist собирается средствами html-sanitizer и передаётся третьим параметром; за основу удобно брать профиль библиотеки — тогда GFM останется на месте:
Настройки = Markdown.НастройкиСанитизацииПоУмолчанию()
.ЗапретитьТег("img")
.РазрешитьПротокол("ftp");
HTML = Markdown.ВБезопасныйHTML(Текст, Markdown.НастройкиGitHubLike(), Настройки);
Свои расширения
Расширения регистрируют свои компоненты в MarkdownРеестрКомпонентов через
метод Зарегистрировать(Реестр). Полная схема — в исходниках расширений
src/extensions/Классы/ (tables / tasklists /
strikethrough / autolinks).
Реализованные возможности
Блочный уровень (CommonMark)
| Возможность | Статус | Примечание |
|---|---|---|
ATX-заголовки (#, ##, …) |
✅ | |
Setext-заголовки (===, --- под текстом) |
✅ | |
| Параграфы | ✅ | |
Тематические линии (---, ***, ___) |
✅ | |
| Indented code blocks (4 пробела) | ✅ | |
Fenced code blocks (```, ~~~) |
✅ | С info-string и language-* классом |
| HTML-блоки | ✅ | |
Блок-цитаты (>) |
✅ | |
Маркированные списки (-, *, +) |
✅ | |
| Нумерованные списки | ✅ | |
| Вложенные списки | ✅ | |
| Reference link definitions | ✅ |
Inline-уровень (CommonMark)
| Возможность | Статус | Примечание |
|---|---|---|
Жирный (**, __) |
✅ | |
Курсив (*, _) |
✅ | |
Inline code (`) |
✅ | |
Ссылки [text](url "title") |
✅ | |
Reference-ссылки [text][ref] |
✅ | |
Изображения  |
✅ | |
Автоссылки <https://…>, <mail@…> |
✅ | |
| Raw inline HTML | ✅ | Экранируется в безопасном режиме |
Backslash escapes (\*, \[, …) |
✅ | |
HTML-сущности (&, *, *) |
✅ | |
Hard line break (\ или 2+ пробела + \n) |
✅ | |
| Soft line break | ✅ |
Расширения (GFM)
| Расширение | Статус | Имя в 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 | ✅ | |
| Санитизация недоверенного вывода | ✅ | Markdown.ВБезопасныйHTML поверх html-sanitizer |
Санитайзер опасных URL (javascript: и т. п.) |
✅ | Allowlist схем в html-sanitizer; сам рендерер по-прежнему только %-encoding |
| Heading id / якоря | ⏳ | Пресет documentation зарезервирован |
| Frontmatter (YAML/TOML) | ⏳ | Пресет documentation зарезервирован |
| TOC | ⏳ | Пресет documentation зарезервирован |
| Markdown normalizer | ⏳ |
CommonMark 0.31.2 conformance: 646 / 652 примеров проходят, 6 помечены
как xfail (см. раздел «Известные ограничения CommonMark» ниже).
Известные ограничения CommonMark
Шесть примеров официальной CommonMark 0.31.2 conformance suite сейчас
помечены &Выключен и не падают CI. Все случаи касаются тонкостей
container-модели (CM §4.7) и относятся к одной из трёх групп.
Табуляция в контейнерных блоках (CM §2.2)
Расширение табов на границе контейнера (список, цитата) рассчитано не до конца — нужна полноценная обработка префикса строки контейнера на смешанных tab/space отступах.
| # | Что не работает |
|---|---|
| 5 | Tab внутри элемента списка — расширение таба на границе контейнера |
| 6 | Tab внутри цитаты — расширение через границу маркера > |
| 7 | Tab внутри элемента списка — расчёт отступа при двойном табе |
Setext-заголовок в lazy continuation
| # | Что не работает |
|---|---|
| 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, html-sanitizer — как обычная зависимость.
opm install oneunit # test-runner глобально (нужен в PATH)
opm install --local --dev # asserts, 1commands, html-sanitizer → ./oscript_modules
oscript tasks/test.os # все тесты + JUnit-отчёты в build/reports/
oscript tasks/test_unit.os # только юнит-тесты
oscript tasks/test_commonmark.os # только CommonMark conformance
CommonMark-сьюты автогенерируются из официальной спецификации. Список
xfail-примеров хранится в самом скрипте (SKIP_LIST в начале файла):
python tools/sync-commonmark.py 0.31.2
Подробнее об устройстве — в paln.md.
Лицензия
MIT © 2026 Egor Ivanov