What's broken?
Since the custom Markdown parser landed in 0.51.0 (#2624), a link whose text equals its URL does not survive a Markdown round trip. It comes back as plain text.
The two halves disagree. formatLink in htmlToMarkdown.ts writes such a link as a bare URL, following the remark-stringify behavior from #2661. That relies on the parser autolinking it, as remark-gfm did. The new parser in markdownToHtml.ts has no autolink tokenizer, so it reads the URL back as text. It also does not recognize CommonMark autolinks (<https://example.com>), which it leaves as literal text including the angle brackets.
Still reproducible on 0.55.0. On 0.50.0 the link survives both cases.
What did you expect to happen?
tryParseMarkdownToBlocks(blocksToMarkdownLossy(blocks)) keeps the link. At minimum, the parser should accept what the serializer emits. Ideally it recognizes both CommonMark autolinks (<https://…>) and GFM autolink literals (bare https://…, www.…), which the pre-0.51 remark-gfm pipeline handled.
Steps to reproduce
import { JSDOM } from "jsdom";
const dom = new JSDOM("<!doctype html>");
globalThis.window = dom.window;
globalThis.document = dom.window.document;
globalThis.DOMParser = dom.window.DOMParser;
const { BlockNoteEditor } = await import("@blocknote/core");
const editor = BlockNoteEditor.create({
initialContent: [
{
type: "paragraph",
content: [{ type: "link", href: "https://example.com", content: "https://example.com" }],
},
],
});
const markdown = await editor.blocksToMarkdownLossy(editor.document);
console.log(JSON.stringify(markdown));
console.log(JSON.stringify((await editor.tryParseMarkdownToBlocks(markdown))[0].content));
console.log(JSON.stringify((await editor.tryParseMarkdownToBlocks("<https://example.com>"))[0].content));
0.55.0:
"https://example.com\n"
[{"type":"text","text":"https://example.com","styles":{}}]
[{"type":"text","text":"<https://example.com>","styles":{}}]
0.50.0:
"<https://example.com>\n"
[{"type":"link","href":"https://example.com","content":[{"type":"text","text":"https://example.com","styles":{}}]}]
[{"type":"link","href":"https://example.com","content":[{"type":"text","text":"https://example.com","styles":{}}]}]
Impact
We keep documents editable as Markdown and only accept an edit when the document round-trips. From 0.51 on, any document containing a URL link fails that check. Markdown written by other tools also loses its links, for example a description with Issue: https://github.com/org/repo/issues/1.
BlockNote version
0.51.0 through 0.55.0 (@blocknote/core)
Environment
Node 24, jsdom 26 (also reproduced in Chrome)
Related: #3035 covers the serializer's link format, not the parse side.
What's broken?
Since the custom Markdown parser landed in 0.51.0 (#2624), a link whose text equals its URL does not survive a Markdown round trip. It comes back as plain text.
The two halves disagree.
formatLinkinhtmlToMarkdown.tswrites such a link as a bare URL, following the remark-stringify behavior from #2661. That relies on the parser autolinking it, as remark-gfm did. The new parser inmarkdownToHtml.tshas no autolink tokenizer, so it reads the URL back as text. It also does not recognize CommonMark autolinks (<https://example.com>), which it leaves as literal text including the angle brackets.Still reproducible on 0.55.0. On 0.50.0 the link survives both cases.
What did you expect to happen?
tryParseMarkdownToBlocks(blocksToMarkdownLossy(blocks))keeps the link. At minimum, the parser should accept what the serializer emits. Ideally it recognizes both CommonMark autolinks (<https://…>) and GFM autolink literals (barehttps://…,www.…), which the pre-0.51 remark-gfm pipeline handled.Steps to reproduce
0.55.0:
0.50.0:
Impact
We keep documents editable as Markdown and only accept an edit when the document round-trips. From 0.51 on, any document containing a URL link fails that check. Markdown written by other tools also loses its links, for example a description with
Issue: https://github.com/org/repo/issues/1.BlockNote version
0.51.0 through 0.55.0 (
@blocknote/core)Environment
Node 24, jsdom 26 (also reproduced in Chrome)
Related: #3035 covers the serializer's link format, not the parse side.