[refactor][converter][client] Вставка markdown в редакторе через @docmost/prosemirror-markdown (browser-entry пакета) + удаление editor-ext md-слоя #347

Open
opened 2026-07-04 19:56:19 +03:00 by agent_vscode · 0 comments
Collaborator

Контекст

Продолжение #345 (шаги 1–2: серверный экспорт/импорт переводятся на канонический пакет). Этот issue — третий, технически нетривиальный шаг: клиентская вставка markdown (apps/client/src/features/editor/extensions/markdown-clipboard.ts) сейчас конвертирует через md-слой editor-ext (marked) и не знает канона (^[…], <!--img {…}-->, <!--subpages--> и т.д. при вставке не распознаются).

Выполняется ПОСЛЕ #345: к тому моменту paste — последний потребитель packages/editor-ext/src/lib/markdown/, и по завершении слой удаляется целиком.

Почему это отдельная работа (сложность)

  1. Пакет Node-only по парсингу: цепочка md→PM в @docmost/prosemirror-markdown — marked → HTML → DOM-парсинг на jsdom → generateJSON по схеме. jsdom в браузерный бандл нельзя (размер, среда). Нужен browser-entry: нативный DOMParser в браузере / jsdom на сервере — через exports-conditions или инжектируемый DOM-парсер. Обязателен контроль, что jsdom не утекает в клиентский бандл транзитивно (проверка сборки и размера бандла — в acceptance).
  2. Вставка — это фрагмент в позицию курсора, а не конвертация документа: снять doc-обёртку, inline-vs-block по контексту курсора, эвристика «это markdown или просто текст». Вся эта логика уже есть в markdown-clipboard.ts и сохраняется — заменяется только вызов конвертации. Регрессии живут именно в этом шве.
  3. Paste — самый частый интерактивный путь редактора: поверх юнит-тестов обязателен ручной QA-проход (вставка из VSCode/Obsidian/GitHub, вставка внутрь списка/таблицы/callout, вставка plain-текста с md-подобной пунктуацией — не должна внезапно конвертироваться).

План

  • Browser-entry пакета: DOM-стадия через DOMParser в браузере (exports-condition или инжект), jsdom остаётся только в node-пути; тесты обоих путей.
  • Проверка бандла клиента: jsdom отсутствует, размер не деградировал (зафиксировать до/после).
  • markdown-clipboard.ts: конвертация через пакет; fragment-insertion логика и эвристики — без изменений.
  • Юнит-тесты вставки на канон-формах: ^[…], <!--img {…}-->, > [!type], $…$, ==…==, standalone-комментарии; плюс негативные (plain-текст с $5, ==, [^1] — не корёжится).
  • Ручной QA-проход по paste-сценариям (список выше), отчёт со скриншотами/выводом.
  • Финал: удалить packages/editor-ext/src/lib/markdown/ целиком (+ тесты слоя), grep на осиротевшие импорты (htmlToMarkdown, markdownToHtml, *.marked, turndown, зависимость turndown из package.json editor-ext). После этого рукописных md-реализаций в проекте ноль.

Acceptance: вставка канонического md даёт те же ноды, что серверный импорт того же текста (общая фикстура с #345 шагом 2); бандл клиента без jsdom; md-слой editor-ext удалён, editor-ext остаётся только схемой/расширениями.

Guardrails (уроки #293/#333)

  1. Никакой конвертер-логики в клиенте/editor-ext — только вызовы пакета.
  2. Browser-entry — это изменение сборки workspace-пакета: проверка в CI-условиях И сборка клиента И Docker (класс блокеров #333 — «зелёное в workspace ≠ зелёное в CI/Docker»).
  3. Fixtures-first; отчёты с выводом прогонов.

Зависимости и связанные

  • Блокируется #345 (шаги 1–2): удаление слоя возможно только когда paste — последний его потребитель — переведён.
  • #293 (закрыт, #333) — консолидация; #326 — общий план. Независимо от замороженного вливания синка (#119 / шаг 6b).
  • Канон: #293 (comment)
## Контекст Продолжение #345 (шаги 1–2: серверный экспорт/импорт переводятся на канонический пакет). Этот issue — третий, технически нетривиальный шаг: **клиентская вставка markdown** (`apps/client/src/features/editor/extensions/markdown-clipboard.ts`) сейчас конвертирует через md-слой editor-ext (marked) и не знает канона (`^[…]`, `<!--img {…}-->`, `<!--subpages-->` и т.д. при вставке не распознаются). Выполняется ПОСЛЕ #345: к тому моменту paste — последний потребитель `packages/editor-ext/src/lib/markdown/`, и по завершении слой удаляется целиком. ## Почему это отдельная работа (сложность) 1. **Пакет Node-only по парсингу**: цепочка md→PM в `@docmost/prosemirror-markdown` — marked → HTML → **DOM-парсинг на jsdom** → generateJSON по схеме. jsdom в браузерный бандл нельзя (размер, среда). Нужен **browser-entry**: нативный `DOMParser` в браузере / jsdom на сервере — через exports-conditions или инжектируемый DOM-парсер. Обязателен контроль, что jsdom не утекает в клиентский бандл транзитивно (проверка сборки и размера бандла — в acceptance). 2. **Вставка — это фрагмент в позицию курсора, а не конвертация документа**: снять doc-обёртку, inline-vs-block по контексту курсора, эвристика «это markdown или просто текст». Вся эта логика уже есть в `markdown-clipboard.ts` и **сохраняется** — заменяется только вызов конвертации. Регрессии живут именно в этом шве. 3. **Paste — самый частый интерактивный путь редактора**: поверх юнит-тестов обязателен ручной QA-проход (вставка из VSCode/Obsidian/GitHub, вставка внутрь списка/таблицы/callout, вставка plain-текста с md-подобной пунктуацией — не должна внезапно конвертироваться). ## План - [ ] Browser-entry пакета: DOM-стадия через `DOMParser` в браузере (exports-condition или инжект), jsdom остаётся только в node-пути; тесты обоих путей. - [ ] Проверка бандла клиента: jsdom отсутствует, размер не деградировал (зафиксировать до/после). - [ ] `markdown-clipboard.ts`: конвертация через пакет; fragment-insertion логика и эвристики — без изменений. - [ ] Юнит-тесты вставки на канон-формах: `^[…]`, `<!--img {…}-->`, `> [!type]`, `$…$`, `==…==`, standalone-комментарии; плюс негативные (plain-текст с `$5`, `==`, `[^1]` — не корёжится). - [ ] Ручной QA-проход по paste-сценариям (список выше), отчёт со скриншотами/выводом. - [ ] **Финал: удалить `packages/editor-ext/src/lib/markdown/` целиком** (+ тесты слоя), grep на осиротевшие импорты (`htmlToMarkdown`, `markdownToHtml`, `*.marked`, turndown, зависимость turndown из package.json editor-ext). После этого рукописных md-реализаций в проекте ноль. **Acceptance**: вставка канонического md даёт те же ноды, что серверный импорт того же текста (общая фикстура с #345 шагом 2); бандл клиента без jsdom; md-слой editor-ext удалён, editor-ext остаётся только схемой/расширениями. ## Guardrails (уроки #293/#333) 1. Никакой конвертер-логики в клиенте/editor-ext — только вызовы пакета. 2. Browser-entry — это изменение сборки workspace-пакета: проверка в CI-условиях И сборка клиента И Docker (класс блокеров #333 — «зелёное в workspace ≠ зелёное в CI/Docker»). 3. Fixtures-first; отчёты с выводом прогонов. ## Зависимости и связанные - Блокируется #345 (шаги 1–2): удаление слоя возможно только когда paste — последний его потребитель — переведён. - #293 (закрыт, #333) — консолидация; #326 — общий план. Независимо от замороженного вливания синка (#119 / шаг 6b). - Канон: https://gitea.vvzvlad.xyz/vvzvlad/gitmost/issues/293#issuecomment-5076
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: vvzvlad/gitmost#347