[refactor][converter] Серверный экспорт/импорт страниц на @docmost/prosemirror-markdown (шаги 1–2 ликвидации editor-ext md-слоя) #345
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Контекст
После #293/#333 канонический PM↔MD конвертер существует в одном экземпляре (
@docmost/prosemirror-markdown, под serializer-contract тестом), его используют mcp/ai-chat и git-sync. Но вpackages/editor-ext/src/lib/markdown/живёт вторая, независимая реализация на другом стеке (turndown HTML→MD + marked MD→HTML), и её потребители — пользовательские пути:apps/server/src/integrations/export|import→htmlToMarkdown/markdownToHtmlиз@docmost/editor-ext) — этот issue;apps/client/.../markdown-clipboard.ts) — вынесена в #347 (browser-entry пакета + удаление слоя).Чем этот слой отличается от канона (проверено по коду правил)
:::type(turndown.utils.ts:302); читает оба формата> [!type][^id]ссылочный стиль^[текст]inline— width/height/align/size/attachmentId ТЕРЯЮТСЯ; caption через<div><img data-caption>+<!--img {…}-->, lossless$…$(совпадает)$…$Следствия: (а) md из «Export page» ≠ md в vault git-sync ≠ md, который видит агент — два диалекта в одном продукте; (б) экспорт теряет layout картинок; (в) слой рукописный, контракт-тестом не покрыт, чинится руками — последний живой генератор дрейфа.
План — два шага, два отдельных PR, по порядку
Шаг 1 — серверный экспорт на пакет (первый: максимум ценности, минимум работы).
В
apps/server/src/integrations/exportзаменить цепочкуcontent → HTML → htmlToMarkdown(turndown)на прямойconvertProseMirrorToMarkdown(content)из пакета (PM JSON → MD, без HTML-промежутка). Экспортные goldens обновить осознанно, fixtures-first: канонические формы сносок/картинок/комментариев, layout картинок выживает. Пакет headless и уже копируется в Docker-образ (#333) — инфра-работы нет.Acceptance: экспортированный md байт-в-байт равен тому, что записал бы git-sync для той же страницы (общая фикстура «export == vault»).
Шаг 2 — серверный импорт на пакет + нормализатор чужого markdown.
Заменить
markdownToHtml(marked)наmarkdownToProseMirrorпакета. ВАЖНО: канон-парсер намеренно строгий ([^id]и:::не парсит — no-backward-compat), а импорт глотает чужие файлы (GitHub/Notion/старые выгрузки). Поэтому на границе импорта — тонкий текстовый pre-pass нормализации::::type→> [!type],[^id]+[^id]: def→^[…](+ по мелочи по фикстурам). Нормализатор живёт ТОЛЬКО в import-boundary сервера, НЕ в пакете — это не форк конвертера, это input-liberal/output-canonical адаптер в одном месте.Acceptance: корпус чужих md-файлов (gfm-сноски, :::‑callouts, таблицы) импортируется без литерального мусора; повторный экспорт даёт канон.
Финал этого issue: в
apps/serverне остаётся импортов md-слоя editor-ext (htmlToMarkdown/markdownToHtml) — grep чистый. Само удалениеpackages/editor-ext/src/lib/markdown/— в #347, после перевода последнего потребителя (клиентская вставка).Guardrails (уроки #293/#333)
Связанные
[refactor][converter] Перевести editor-ext markdown-слой на @docmost/prosemirror-markdown: экспорт → импорт → вставка (последний диалектный шов)to [refactor][converter] Серверный экспорт/импорт страниц на @docmost/prosemirror-markdown (шаги 1–2 ликвидации editor-ext md-слоя)