P2.1 · ProseMirror ↔ Markdown converter with unit tests
Why this is a separate ticket
Linear stores issue descriptions as ProseMirror JSON, not markdown. The API accepts markdown on write, but reads return ProseMirror. The conversion is the single highest-risk piece of the whole product.
What
Module src/convert/ with two entry points:
proseMirrorToMarkdown(doc: PMNode): stringmarkdownToProseMirror(md: string): PMNode
Nodes to support
- Headings h1–h6
- Paragraphs
- Bold, italic, strikethrough, inline code
- Code blocks with language hint
- Ordered and unordered lists, including nested lists (main gotcha)
- Links
- Linear user mentions (
@user→mentionnode with userId) - Issue references (
KAI-12→ Linear renders as a link) - Images / attachments
- Blockquotes
- Horizontal rules
Technical approach
- Use
prosemirror-markdownas a starting point but override the schema to match Linear's (which differs slightly from commonmark). - Inspect Linear's schema by pulling a rich issue via the API and logging the returned ProseMirror structure.
Acceptance criteria
- 25+ fixture files: each is a ProseMirror JSON doc. Test:
markdownToProseMirror(proseMirrorToMarkdown(fixture)) === fixturestructurally (with a deep-equal ignoring whitespace-only differences). - Lossless roundtrip on 95%+ of fixtures. Document the 5% known-lossy cases in a
LIMITATIONS.md. - Handles nested list depth ≥ 3.
- Updated
- 2026-04-22