OpenHub
OpenHub
Войти

oscript-mdпакет

с апстрима
автор: Egor Ivanovскачиваний: 7

Пакет лежит в основном пуле хаба: короткой формы достаточно, если хаб прописан сервером пакетов в 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>");
// "&lt;script&gt;alert(1)&lt;/script&gt;"

Чтобы разрешить 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]
Изображения ![alt](url)
Автоссылки <https://…>, <mail@…>
Raw inline HTML Экранируется в безопасном режиме
Backslash escapes (\*, \[, …)
HTML-сущности (&amp;, &#42;, &#x2A;)
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