Вики: внешняя ссылка не теряет края текста и не выводится адресом без вложения (#135, ревью I-1, M-1)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Andrey Epifancev 2026-10-27 19:00:49 +04:00
parent 952398bd9a
commit 90b03ed701
3 changed files with 30 additions and 1 deletions

View File

@ -124,3 +124,15 @@ T8.2: `request_fetch` отвечает `ready` по полю `state`, а `GET
различая «новый/идущий». Цена ошибки — ответ PATCH называет уже идущий пакет. различая «новый/идущий». Цена ошибки — ответ PATCH называет уже идущий пакет.
- 2026-10-27 — T6.1: картинка-другое-вложение внутри ссылки на вложение выводится своей ссылкой перед ссылкой - 2026-10-27 — T6.1: картинка-другое-вложение внутри ссылки на вложение выводится своей ссылкой перед ссылкой
внешнего вложения. Цена ошибки — порядок двух ссылок в строке. внешнего вложения. Цена ошибки — порядок двух ссылок в строке.
- 2026-10-27 — R-1: в шапку плана добавлена строка «Ветка» — хук require-plan ищет имя ветки в плане. Цена ошибки —
нет (на поведение не влияет).
- 2026-10-27 — R-2: в MCP `sync` с ожиданием ошибка команды тоже выводится одной строкой (`_line`) — это тот же текст
Eva, что «ошибка синхронизации» решения 8. Цена ошибки — нет.
- 2026-10-27 — R-3: хранилище картинок живёт внутри `useWikiDownload` (третий параметр `attachments`, геттер `image`);
`components` в `PageView` пересоздаётся при смене карты, как и при смене `status`. Решение 10 допускало оба
прочтения; выбрано прежнее поведение `status`: состояние `busy`/`error` живёт в хуке и перемонтированием не
сбрасывается (тест). Цена ошибки — перемонтирование ссылок и картинок страницы при смене состояния другого вложения
(возможное мигание, потеря фокуса; финальное ревью M-3, deferred).
- 2026-10-27 — R-4: картинка выводится над кнопкой-ссылкой сохранения — по сценарию «Скачать картинку». Цена ошибки — нет.
- 2026-10-27 — R-5: у внешней ссылки края текста сохраняются, адрес вместо пустого текста — только при вынесенном
вложении (финальное ревью I-1, M-1). Цена ошибки — нет: прежнее поведение для ссылок без вложений.

View File

@ -119,7 +119,12 @@ class _Converter(MarkdownConverter):
if _unsafe(href): if _unsafe(href):
return text # исполняемая или внутренняя ссылка автора: остаётся только текст return text # исполняемая или внутренняя ссылка автора: остаётся только текст
el["href"] = _href(href) el["href"] = _href(href)
return marks + sep + super().convert_a(el, _tail(rest.strip()) or _label(href), parent_tags) # края текста возвращаются как были: markdownify сам выносит их за ссылку, иначе слова склеиваются (ревью I-1);
# адрес вместо пустого текста — только если из ссылки вынесено вложение (M-1)
core = rest.strip()
lead, trail = rest[:len(rest) - len(rest.lstrip())], rest[len(rest.rstrip()):]
label = lead + _tail(core) + trail if core else (_label(href) if marks else rest)
return marks + sep + super().convert_a(el, label, parent_tags)
def _strip_private(soup) -> None: def _strip_private(soup) -> None:

View File

@ -335,3 +335,15 @@ def test_trailing_backslash_in_page_link_text():
def test_trailing_backslash_in_external_link_text(): def test_trailing_backslash_in_external_link_text():
md, _ = convert.to_markdown('<p><a href="http://ex.com/">путь C:\\</a></p>', [], []) md, _ = convert.to_markdown('<p><a href="http://ex.com/">путь C:\\</a></p>', [], [])
assert md == "[путь C:\\\\](http://ex.com/)\n" assert md == "[путь C:\\\\](http://ex.com/)\n"
def test_external_link_keeps_edge_spaces():
"""Финальное ревью I-1: пробелы на краях текста внешней ссылки выносятся наружу, слова не склеиваются."""
md, _ = convert.to_markdown('<p>слово<a href="http://ex.com/"> док </a>дальше</p>', [], [])
assert md == "слово [док](http://ex.com/) дальше\n"
def test_empty_external_link_dropped():
"""Финальное ревью M-1: пустая внешняя ссылка без вложения внутри не выводится адресом."""
md, _ = convert.to_markdown('<p>a<a href="#top"></a>b<a href="http://x"><img src="static/i.png"></a>c</p>', [], [])
assert md == "abc\n"