feat: lint headers and validate anchor links in markdown files
Задачи
- Написать линтер заголовков файлов Markdown, который проверяет их на наличие якорей формата
{: #anchor } - Написать валидатор якорей в относительных ссылках файлов Markdown
Реализация — в виде хуков или плагина MkDocs.
Решение
Нововведения
- Линтер
lint_headers.py:- проверяет заголовки в файлах
.mdна наличие якорей формата{: #anchor } - создает индекс якорей
anchor_index
- проверяет заголовки в файлах
- Валидатор
validate_anchor_links.py:- валидирует относительные ссылки на якори в файлах
.mdс помощью индекса якорейanchor_index
- валидирует относительные ссылки на якори в файлах
Принцип работы линтера lint_headers.py
- Хук выполняется в событии
on_pre_buildэтапаbuild, чтобы командаmkdocs serve -sобрабатывала записи хука со статусомWARNING - Генератор
os.walk()возвращает пути к файлам.mdв папкеdocs - В индексе
anchor_index— типdict[str, set]— создается запись, соответствующая файлу.md - Из каждого файла
.mdудаляется закомментированный текст — заключен в<!--и--> - В оставшемся тексте построчно парсятся заголовки:
- первый заголовок пропускается
- в следующих заголовках проверяется наличие якоря формата
{: #anchor }— символ:и пробелы с обеих сторон обязательны - якорь нужного формата добавляется в индекс
anchor_index - при отсутствии в заголовке якоря нужного формата в лог MkDocs выводится запись со статусом
DEBUG
- Индекс
anchor_indexзаписывается в файлanchor.yml
Принцип работы валидатора validate_anchor_links.py
- Хук выполняется в событии
on_pre_buildэтапаbuild, чтобы командаmkdocs serve -sобрабатывала записи хука со статусомWARNING - Генератор
os.walk()возвращает пути к файлам.mdв папкеdocs - Из файла
anchor.ymlчитается индексanchor_index - Из каждого файла
.mdудаляется закомментированный текст — заключен в<!--и--> - В оставшемся тексте парсятся ссылки:
- ищутся ссылки
linkв формате[text](full_path) - если у ссылки
linkесть якорь, т. е.full_path == path#anchor, и нет подстрокиhttps://, из нее извлекается путьpathи в ней валидируется якорьanchor - при обнаружении невалидного якоря в лог MkDocs выводится запись со статусом
DEBUG
- ищутся ссылки
Примеры записей в логе
lint_headers.py
DEBUG - lint_headers: INVALID or MISSING anchor @ docs/reference/api.md -> ### pico.wait_ddl_finalize
validate_anchor_links.py
DEBUG - validate_anchor_links: BROKEN link @ docs/reference/api.md -> [Vclock](../overview/glossary.md#vclock-vector-clock)
Поиск решения
Поиск решения
Первая итерация
Написан хук lint_anchors.py.
Принцип работы:
- Хук выполняется в событии
on_configв начале этапаbuild, чтобы командаmkdocs serve -sобрабатывала записи хука со статусомWARNING - Генератор
os.walk()возвращает пути к файлам Markdown в папкеdocs - Из каждого файла Markdown читается список строк
data - Нулевой элемент списка
dataудаляется — подразумевается, что это самый первый заголовок, которому не нужен якорь - В списке
dataсчитается количество заголовковheadersи якорейanchors. Закомментированные заголовки не учитываются - Регулярное выражение для поиска якорей
\{:\s#[\w.-]*\s\}соответствует формату{: #anchor } - Если якорей меньше, чем заголовков, в лог MkDocs выводится запись со статусом
WARNING. Пример:
WARNING - lint_anchors: Number of missing anchors in docs/reference/api.md >>> 4
Доработать:
- Нужно исключать не первую строку файла Markdown, а первый заголовок — файл может начинаться с блока метаданных
- Плагин
attr-listдопускает следующие форматы якорей:{:#anchor },{: #anchor},{ #anchor },{#anchor },{#anchor}. Возможно, следует добавить эти форматы в линтер. Источник:
The colon after the opening brace is optional, but is supported to maintain consistency with other implementations.
<...>
In addition, the spaces after the opening brace and before the closing brace are optional. They are recommended as they improve readability, but they are not required.
See:
- https://www.mkdocs.org/dev-guide/plugins/#events
- https://www.mkdocs.org/dev-guide/plugins/#on_config
- https://docs.python.org/3/library/os.html#os.walk
- https://python-markdown.github.io/extensions/attr_list/
- Лог MkDocs при запуске сервера в строгом режиме
Refer:
Вторая итерация
Изменения:
- Из проверки исключается первый найденный заголовок — ранее исключалась первая строка файла Markdown
- В результате работы хука создается словарь
anchors_dictс записями в формате{document: anchors_set}, где:-
document(str) — путь к файлу Markdown -
anchors_set(set) — множество якорей заголовков из файла Markdown
-
Третья итерация
Изменения:
- В хук
lint_anchors.pyдобавлена функцияwrite_dict(), которая записывает словарь —dict— в файл - Переименование
lint_anchors.py->lint_headers.py
Четвертая итерация
Изменения:
- Написан хук
validate_anchor_links.py
Коммиты
- chore: move filter_plugin_records.py to hooks
- feat: lint attr-list anchors in markdown files
- rename: lint_anchors.py -> lint_headers.py
- feat: validate anchor links in markdown files
- refactor: reorganize lint_headers.py and validate_anchor_links.py code
Close #147 (closed)
Саморевью
-
Контент отображается корректно -
Ссылки в контенте работоспособны и корректны
Edited by Artur Sabirov