developer-guide/markdown-and-editor/index.md

3.2 KiB

id title description tags lang
markdown-and-editor Markdown and the editor The Markdown pipeline, its constructs, and adding a construct in both packages.
markdown
editor
architecture
en

Markdown and the editor

Two packages share the job of understanding a page's content: packages/markdown turns Markdown into sanitized HTML for reading; packages/editor provides the ProseMirror schema behind the WYSIWYG editor. They have to agree, because a page can be opened in either mode at any time and must come back unchanged.

The Markdown pipeline

packages/markdown/src/:

  • parse.ts / render.ts / stringify.ts — Markdown → AST → HTML, and back to Markdown text.
  • frontmatter.ts / frontmatter-split.ts / frontmatter-metadata.ts — the YAML header every page carries.
  • alerts.ts — the > [!NOTE] / [!TIP] / [!IMPORTANT] / [!WARNING] callouts used throughout this space.
  • image-size.ts, youtube.ts — extra constructs beyond plain CommonMark.
  • slug.ts, diff.ts, version.ts — heading slugs, and support for page version comparison.

The editor

packages/editor/src/:

  • extensions.ts — assembles the ProseMirror schema.
  • nodes/alert.ts, nodes/image.ts, nodes/wiki-link.ts, nodes/youtube-embed.ts — one node per construct that needs editor support beyond stock ProseMirror.
  • from-markdown.ts / to-markdown.ts — the two directions of conversion between editor document and Markdown text.

Constructs shared by both packages

Wikilinks ([[page-id]], [[page-id|label]]) and callouts are the two constructs every page in this space uses, and both need a matching node in packages/editor (wiki-link.ts, alert.ts) so that opening a page in the WYSIWYG editor round-trips it correctly.

Adding a construct to both packages

A new Markdown construct (say, a new kind of callout, or a new inline element) needs changes in four places, in this order:

  1. packages/markdown — teach the parser to recognize the syntax and the renderer to produce sanitized HTML for it.
  2. packages/markdown — teach stringify.ts to produce the same syntax back out, so a document that was never touched in the editor is byte-for-byte stable.
  3. packages/editor — add a node (or mark) under nodes/ and wire it into extensions.ts, then extend from-markdown.ts and to-markdown.ts for the two conversion directions.
  4. Round-trip test — Markdown → editor document → Markdown must reproduce the original. This is the test that actually catches drift between the two packages; skipping it is how "reading shows X, editing shows Y" bugs get in.

Warning

If the sanitizer (used by packages/markdown's HTML output) doesn't know about the new construct's tags or attributes, it will silently strip them. This is exactly the failure mode the diagram sanitizer test guards against for .drawio.svg/.excalidraw.svg — the content attribute and wrapping text elements must survive sanitization, or diagrams lose their source and their full labels.

See extending for the same recipe phrased as a short checklist, and api for how the rendered result reaches the reader.