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