Skip to content

Segate-ekb/oscript-md

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

21 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

oscript-md

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

Примеры использования

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РеестрКомпонентов через метод Зарегистрировать(Реестр). Полная схема — в исходниках расширений 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
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

Шесть примеров официальной 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.

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 conformance

CommonMark-сьюты автогенерируются из официальной спецификации. Список xfail-примеров хранится в самом скрипте (SKIP_LIST в начале файла):

python tools/sync-commonmark.py 0.31.2

Подробнее об устройстве — в paln.md.

Лицензия

MIT © 2026 Egor Ivanov

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors