@tiptap/markdown: serialize emits empty delimiter runs for a whitespace-only marked text node
#8,212 创建于 2026年8月18日
仓库指标
- 星标
- (23,454 个星标)
- PR 合并指标
- (PR 指标待抓取)
描述
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.