Стабилизация, итерация 8: конвертер — block-escape, атрибутный contract-тест, дедуп зеркал (один PR, 7 коммитов) #493

Open
opened 2026-07-11 02:05:33 +03:00 by agent_vscode · 0 comments
Collaborator

Один PR. Зависимостей от других итераций нет. Связано с #347 (клиентские markdown-пути — отдельная работа, там же browser-entry). Координаты — develop@363f20ab.

Коммит 1 — fix(converter): block-escape параграфа — незакрытый класс потерь данных

packages/prosemirror-markdown/src/markdown-converter.ts:414-430: строка параграфа, начинающаяся с #/-/>/1./|/фенса/---, на round-trip превращается в другой блок или теряет текст. Класс известен и ОБХОДИТСЯ, а не чинится: генератор property-тестов сознательно не выдаёт такие строки (text-arbitraries.ts), bridge вставляет ZWSP-хак (gitmost-recording.ts:292-296) — workaround расползается по потребителям.
Правка: экранировать блочные триггеры в начале каждой строки параграфа при сериализации (\\#, \\-, \\>, 1\\. — стандартный приём CommonMark-сериализаторов). Затем: удалить ZWSP-хак, снять самоцензуру в text-arbitraries — генеративный suite сам докажет закрытие класса. Пины на каждый триггер.

Коммит 2 — test(converter): атрибутный contract-тест схем

schema-editor-ext-contract.test.ts:19-25 сравнивает только ИМЕНА нод — дрейф атрибутов (класс, породивший потерю subpages.recursive) CI не ловит. Правка: сравнивать spec.attrs (имена + дефолты) каждой ноды/марки обеих схем (~30 строк).

Коммит 3 — fix(converter): warnings вместо тихой потери

markdown-converter.ts:520-596: незнакомые марки/ноды теряются молча. Default-ветка → накапливать warnings (паттерн footnoteWarnings уже есть) и отдавать наружу; в git-sync и тестах — strict-режим (warning = ошибка).

Коммит 4 — refactor(converter): normalizeForeignMarkdown → в пакет

Нормализация GFM-сносок [^id]/front-matter живёт только в apps/server → MCP updatePageMarkdown тот же ввод обрабатывает иначе, чем серверный импорт. Перенести в @docmost/prosemirror-markdown, вызывать в markdownToProseMirrorCanonical.

Коммит 5 — refactor(converter): дедуп зеркал footnote/stripInlineMarkdown/glyph

footnote-canonicalize.ts ×2 (+1255-строчный корпус-зеркало), text-normalize.ts:95 ×2, glyph-карты ×2. Перенести canonicalizeFootnotes и stripInlineMarkdown в канонический пакет; editor-ext и mcp импортируют; корпус остаётся один.

Коммит 6 — fix(mcp): resolved-якоря переживают полный write

Read-путь прячет resolved-спаны (#337), write-путь (updatePageMarkdown) верит markdown агента дословно → full-write стирает resolved-марки. Правка: пере-прививать resolved-марки из старого дока на совпадающие текстовые диапазоны (механика анкоринга уже есть в comment-anchor). Альтернатива «отдавать resolved-спаны в get_page» отвергнута — ломает чистоту read-пути.

Коммит 7 — refactor(import): унификация путей импорта .md

file-import-task.service.ts:477-480: zip-путь идёт через PM→HTML→PM-хоп, API-путь — прямой (import.service.ts:148). Унифицировать на прямой («architecture B» уже помечена в коде как план).

Один PR. Зависимостей от других итераций нет. Связано с #347 (клиентские markdown-пути — отдельная работа, там же browser-entry). Координаты — develop@363f20ab. ### Коммит 1 — fix(converter): block-escape параграфа — незакрытый класс потерь данных `packages/prosemirror-markdown/src/markdown-converter.ts:414-430`: строка параграфа, начинающаяся с `#`/`-`/`>`/`1.`/`|`/фенса/`---`, на round-trip превращается в другой блок или теряет текст. Класс известен и ОБХОДИТСЯ, а не чинится: генератор property-тестов сознательно не выдаёт такие строки (`text-arbitraries.ts`), bridge вставляет ZWSP-хак (`gitmost-recording.ts:292-296`) — workaround расползается по потребителям. Правка: экранировать блочные триггеры в начале каждой строки параграфа при сериализации (`\\#`, `\\-`, `\\>`, `1\\.` — стандартный приём CommonMark-сериализаторов). Затем: удалить ZWSP-хак, снять самоцензуру в text-arbitraries — генеративный suite сам докажет закрытие класса. Пины на каждый триггер. ### Коммит 2 — test(converter): атрибутный contract-тест схем `schema-editor-ext-contract.test.ts:19-25` сравнивает только ИМЕНА нод — дрейф атрибутов (класс, породивший потерю `subpages.recursive`) CI не ловит. Правка: сравнивать `spec.attrs` (имена + дефолты) каждой ноды/марки обеих схем (~30 строк). ### Коммит 3 — fix(converter): warnings вместо тихой потери `markdown-converter.ts:520-596`: незнакомые марки/ноды теряются молча. Default-ветка → накапливать warnings (паттерн `footnoteWarnings` уже есть) и отдавать наружу; в git-sync и тестах — strict-режим (warning = ошибка). ### Коммит 4 — refactor(converter): normalizeForeignMarkdown → в пакет Нормализация GFM-сносок `[^id]`/front-matter живёт только в apps/server → MCP `updatePageMarkdown` тот же ввод обрабатывает иначе, чем серверный импорт. Перенести в `@docmost/prosemirror-markdown`, вызывать в `markdownToProseMirrorCanonical`. ### Коммит 5 — refactor(converter): дедуп зеркал footnote/stripInlineMarkdown/glyph `footnote-canonicalize.ts` ×2 (+1255-строчный корпус-зеркало), `text-normalize.ts:95` ×2, glyph-карты ×2. Перенести canonicalizeFootnotes и stripInlineMarkdown в канонический пакет; editor-ext и mcp импортируют; корпус остаётся один. ### Коммит 6 — fix(mcp): resolved-якоря переживают полный write Read-путь прячет resolved-спаны (#337), write-путь (`updatePageMarkdown`) верит markdown агента дословно → full-write стирает resolved-марки. Правка: пере-прививать resolved-марки из старого дока на совпадающие текстовые диапазоны (механика анкоринга уже есть в comment-anchor). Альтернатива «отдавать resolved-спаны в get_page» отвергнута — ломает чистоту read-пути. ### Коммит 7 — refactor(import): унификация путей импорта .md `file-import-task.service.ts:477-480`: zip-путь идёт через PM→HTML→PM-хоп, API-путь — прямой (`import.service.ts:148`). Унифицировать на прямой («architecture B» уже помечена в коде как план).
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: vvzvlad/gitmost#493