ueberdosis/tiptap

@tiptap/markdown: serialize emits empty delimiter runs for a whitespace-only marked text node

Aperta

#8212 aperta il 18 ago 2026

 (2 commenti) (0 reazioni) (0 assegnatari)TypeScript (1979 fork)batch import
area: markdowncomplexity: easygood first issueimpact: low

Metriche repository

Star
 (23.454 stelle)
Metriche merge PR
 (Metriche PR in attesa)

Descrizione

Affected Packages

@tiptap/markdown

Tiptap Version

3.30.1

Browser Used

Not browser-specific — server-side serialization on Node 20.12.2

What happened?

MarkdownManager.serialize() emits empty delimiter runs when a text node is whitespace-only but carries a delimiter mark.

import { getSchema } from '@tiptap/core'
import { StarterKit } from '@tiptap/starter-kit'
import { MarkdownManager } from '@tiptap/markdown'

const mm = new MarkdownManager({ extensions: [StarterKit] })

mm.serialize({
  type: 'doc',
  content: [{
    type: 'paragraph',
    content: [
      { type: 'text', text: 'a' },
      { type: 'text', text: ' ', marks: [{ type: 'bold' }] },
      { type: 'text', text: 'b' },
    ],
  }],
})

Output, by mark type:

bold   ->  "a**** b"
italic ->  "a** b"
code   ->  "a`` b"

**** is not emphasis in CommonMark, so it renders as four literal asterisks. Same for the italic and code forms.

This node shape shows up when someone bolds only a space, or when a document transform splits a text node so one part is whitespace only.

Expected Behavior

a b — just the whitespace, with no delimiters, since there is no text to emphasise.

The neighbouring case already works this way. A mark whose range includes surrounding whitespace has that whitespace expelled outside the delimiters, so 'Label: ' in bold correctly serializes to **Label:** . The whitespace-only input looks like the same rule reaching the point where trimming leaves nothing to wrap.

Additional Context (Optional)

Low severity for us: we measured 0 occurrences across our production documents, so it is latent rather than active, and we guard against it locally.

Reporting it because it is the same class as the trailing-space emphasis case (**Label: **text, which CommonMark will not close) that we were originally investigating — so a fix here may want to cover both.

Guida contributor