Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
f77ad95
[lexical-markdown] Bug Fix: Treat Unicode punctuation and symbols as …
haripetrov-stack Oct 22, 2026
5debdb3
Merge upstream main into PR 9430
claude Oct 30, 2026
7c01137
[lexical-markdown] Bug Fix: Keep exported markers flanking beside pun…
claude Oct 30, 2026
2e36232
[lexical-markdown] Bug Fix: Decide export flanking from the emitted m…
claude Oct 30, 2026
3ce37b6
[lexical-markdown] Bug Fix: Keep export markers out of band while dec…
claude Oct 30, 2026
9fcef26
[lexical-markdown] Bug Fix: Re-decide a marker run when a reference c…
claude Oct 30, 2026
d3cca13
[lexical-markdown] Bug Fix: Place export tags by CommonMark whitespac…
claude Oct 30, 2026
84fed4a
[lexical-markdown] Bug Fix: Share the flanking rule between import an…
claude Oct 30, 2026
892eb70
[lexical-markdown] Bug Fix: Keep export tags inside JavaScript whites…
claude Oct 30, 2026
77e11a2
[lexical-markdown] Bug Fix: Write no reference that only trades one l…
claude Oct 30, 2026
b5ae663
[lexical-markdown] Refactor: Simplify the reference decision's bookke…
claude Oct 30, 2026
112522e
[lexical-markdown] Bug Fix: Leave control characters and noncharacter…
claude Oct 30, 2026
00533af
[lexical-markdown] Bug Fix: Write no reference inside a bare URL, hos…
claude Oct 30, 2026
04177c9
[lexical-markdown] Refactor: Cut the export overhead of deciding refe…
claude Oct 30, 2026
a30ec8f
[lexical-markdown] Bug Fix: Look for autolinks at the edge of the tex…
claude Oct 30, 2026
bab3485
[lexical-markdown] Bug Fix: See escaped underscores in autolinks and …
claude Oct 30, 2026
7675fe4
[lexical-markdown] Refactor: Remember each link check and share the d…
claude Oct 30, 2026
7cc4a60
[lexical-markdown] Bug Fix: Keep mailto and xmpp links whole and skip…
claude Oct 30, 2026
1931552
[lexical-markdown] Bug Fix: Apply emphasis that closes before a code …
claude Oct 30, 2026
8ae7624
[lexical-markdown] Bug Fix: Keep code spans ahead of links when empha…
claude Oct 30, 2026
5000f5e
[lexical-markdown] Bug Fix: Recognize more bare URLs at the edge of e…
claude Oct 30, 2026
6a4d7e3
[lexical-markdown] Refactor: Tidy the reference decision and code-spa…
claude Oct 30, 2026
25d9b10
[lexical-markdown] Bug Fix: Find bare URLs that run on through format…
claude Oct 30, 2026
75e72d0
[lexical-markdown] Refactor: State code-span precedence once and corr…
claude Oct 30, 2026
1dd3e81
[lexical-markdown] Bug Fix: Leave inline link targets out of the bare…
claude Oct 30, 2026
5a5dcfb
[lexical-markdown] Refactor: Classify a delimiter's neighbours once a…
claude Oct 30, 2026
07ab071
[lexical-markdown] Refactor: Skip code spans in one forward pass when…
claude Oct 30, 2026
5a6562d
[lexical-markdown] Documentation Update: Say the backslash change app…
claude Oct 30, 2026
af73d88
[lexical-markdown] Bug Fix: Keep an unescaped tag character in text o…
claude Oct 30, 2026
d8dc6f3
[lexical-markdown] Bug Fix: Apply the bare URL rule to tag characters…
claude Oct 30, 2026
07b26df
[lexical-markdown] Bug Fix: Apply emphasis ahead of a code span only …
claude Oct 30, 2026
13358b9
[lexical-markdown] Bug Fix: Read delimiter runs at a split edge with …
claude Oct 30, 2026
e6db0a1
[lexical-markdown] Bug Fix: Let an earlier link go before a code span…
claude Oct 30, 2026
6b0f826
[lexical-markdown] Bug Fix: Apply a code span before a later link again
claude Oct 30, 2026
19427db
[lexical-markdown] Bug Fix: Leave a backslash inside a bare URL raw
claude Oct 30, 2026
38aa12a
[lexical-markdown] Refactor: Give a code span's content no outside co…
claude Oct 30, 2026
d8bfb1e
[lexical-markdown] Bug Fix: Measure a cut delimiter run whole for the…
claude Oct 30, 2026
f46f447
[lexical-markdown] Refactor: Join raw output as one space when findin…
claude Oct 30, 2026
063395e
[lexical-markdown] Bug Fix: Leave an escaped delimiter out of a cut r…
claude Oct 30, 2026
d63f19f
[lexical-markdown] Bug Fix: Keep non-ASCII characters inside a bare U…
claude Oct 30, 2026
8a734d2
[lexical-markdown] Bug Fix: Restore the remaining-length rule of 3 an…
claude Oct 30, 2026
454bf81
[lexical-markdown] Bug Fix: Follow the CJK-friendly amendment for emp…
claude Oct 30, 2026
49ef33c
[lexical-markdown] Chore: Revert the CJK-friendly import amendment
claude Oct 30, 2026
474fe56
[lexical-markdown] Bug Fix: Choose export references that micromark r…
claude Oct 30, 2026
fd53c90
Merge branch 'upstream-main' into claude/project-thread-ejj4vn
claude Oct 30, 2026
99522b7
[lexical-markdown] Bug Fix: Start a link at the `[` its label really …
claude Oct 30, 2026
8692fa7
[lexical-markdown] Bug Fix: Keep a bare URL's guard running through a…
claude Oct 30, 2026
520f910
[lexical-markdown] Bug Fix: Import the text after each match in a loo…
claude Oct 30, 2026
21af6a9
[lexical-markdown] Documentation Update: Name the link and code span …
claude Oct 30, 2026
253eff3
[lexical-markdown] Bug Fix: Read runs beside other markers as microma…
claude Oct 31, 2026
9077162
[lexical-markdown] Bug Fix: Read runs beside other markers as CommonM…
claude Oct 31, 2026
095b617
[lexical-markdown] Bug Fix: Restore main's import order, find links o…
claude Oct 31, 2026
52c4375
[lexical-markdown] Bug Fix: Write no reference that starts an autolin…
claude Oct 31, 2026
3436ba9
[lexical-markdown] Bug Fix: Rescan after a transformer edits the next…
claude Oct 31, 2026
2c79985
[lexical-markdown] Bug Fix: Treat a scheme as a URL only with a host …
claude Oct 31, 2026
8a5047a
[lexical-markdown] Documentation Update: Fence the escaped-backtick e…
claude Oct 31, 2026
6be2852
[lexical-markdown] Bug Fix: Keep formatting beside a bare URL by spoi…
claude Oct 31, 2026
13595d0
[lexical-markdown] Bug Fix: Keep emails whole for micromark, guard a …
claude Oct 31, 2026
297cf86
[lexical-markdown] Bug Fix: Search a line for a link a bounded number…
claude Oct 31, 2026
ca8d028
[lexical-markdown] Bug Fix: Write no reference for an email's `@` aft…
claude Oct 31, 2026
1e4366e
Merge upstream main into claude/project-thread-ejj4vn
claude Oct 31, 2026
57d2d27
[lexical-markdown] Documentation Update: Leave the link-opener change…
claude Oct 31, 2026
4399a01
[lexical-markdown] Bug Fix: Read the text beside a text match as besi…
claude Oct 31, 2026
fa68d1a
Merge branch 'main' into markdown-unicode-punctuation
etrepum Nov 1, 2026
3824c39
[lexical-markdown] Bug Fix: Read a run after a text match the same wh…
claude Nov 1, 2026
5567204
[lexical-markdown] Bug Fix: Read a run after a text match the same wh…
claude Nov 1, 2026
7e499d6
[lexical-markdown] Bug Fix: Give a text match found earlier in the li…
claude Nov 1, 2026
286353c
[lexical-markdown] Bug Fix: Read a highlight inside a format as a lin…
claude Nov 1, 2026
c40210e
Merge 3824c39 into claude/project-thread-ejj4vn
claude Nov 1, 2026
f6e79e6
[lexical-markdown] Bug Fix: Pair a run after a link only before the n…
claude Nov 2, 2026
5369550
[lexical-markdown] Refactor: Classify a character for flanking withou…
claude Nov 2, 2026
205ed4e
[lexical-markdown] Refactor: Write the export's references and the li…
claude Nov 2, 2026
12f3bb0
[lexical-markdown] Bug Fix: Skip the bare-URL scan of an export where…
claude Nov 2, 2026
8f7a57d
[lexical-markdown] Bug Fix: Escape the backslashes before a marker in…
claude Nov 2, 2026
e99f8f3
[lexical-markdown] Bug Fix: Read the run after a text match beside a …
claude Nov 2, 2026
7184aaa
Merge branch 'main' into markdown-unicode-punctuation
etrepum Nov 3, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .changeset/markdown-unicode-punctuation-flanking.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
'@lexical/markdown': patch
---

[fix] Follow CommonMark's Unicode punctuation and whitespace when deciding whether `*`, `_`, `~~` and `==` markers open or close formatting

Markdown import and the typing shortcuts now count every character in the Unicode punctuation (P) and symbol (S) categories as punctuation, so an en dash, a curly quote, a currency sign or a symbol such as ✓ or 😀 next to a marker no longer reads as a letter, and `See –**[here](https://example.com)**` imports as a bold link. On import, the backslash, which was missing from its ASCII list, counts too. Whitespace is the Zs category plus tab, line feed, form feed and carriage return, so U+000B, U+2028, U+2029 and U+FEFF no longer count as whitespace beside a marker, on import or for the typing shortcuts.

Import also applies emphasis that closes before a later code span ahead of that span, as in `` **a.**x**`c`** ``, so its markers no longer split apart and stay as literal text. A link or other text match that ends before a code span is applied ahead of it, so `[a](b) and [`c`](d)` keeps both links, and one no longer takes part of any code span in the text, not only the first. A delimiter run that an earlier match cuts through now reads as it did in the whole text instead of as one at the edge of a line, so `*)**a*` keeps its literal asterisks. An escaped backtick right before more backticks no longer keeps the rest of that run from opening a code span, so ```x\``bb`x``` imports with code `bb`, as CommonMark reads it. Long lines import faster, since their code spans, emphasis, links and the matches of other text-match transformers whose patterns do not look behind are found once per line rather than again after each match.

Export of formatting that starts or ends with punctuation right beside a letter, such as plain `foo` then bold `“bar”`, now writes that letter as a numeric character reference (`foo**“bar”**baz`), so that the formatting survives a round trip through a CommonMark reader. Those references are chosen so that micromark-based readers such as `@lexical/mdast`, which read an emoji or another character outside the Basic Multilingual Plane as a letter, format it the same way, so plain `😀` then bold `“b”` exports as `😀**“b”**`. Characters that are neither punctuation nor whitespace count as letters here, including the variation selector that ends an emoji such as ❤️. A raw backslash that ends text right before a marker or such a reference (text exported with `shouldPreserveNewLines`, or decorator text) now goes out as `\`, so that it does not escape it. With `shouldPreserveNewLines`, backslashes right before a `*`, `_`, `` ` `` or `~` of the text are escaped too, so that they no longer cancel that character's escape. A bare URL, `www.` host or email that GFM readers would link, and that would hold such a reference or take in the markers or code span after it, now has a character of its prefix written as a reference too, so that no reader links it and the formatting and text come through: bold `www.x.co` then `a` exports as `**www.x.co**a`, and plain `see https://x.com/a` then bold `“x”` as `see https://x.com/a**“x”**`, where a GFM reader used to take the markers into the link. `@lexical/mdast` still links the decoded text.

Verify: Markdown with a marker between a letter and Unicode punctuation, such as `**“bar”**baz`, `**你好。**世界` or `**注意:**请先登录`, now imports with literal asterisks, as CommonMark readers show it, where it used to import as bold. The same goes for formatting that starts or ends with an escaped ASCII character right beside a letter, such as `a**\_x**`, since the backslash is punctuation. Lexical exported these shapes for such formatting before, so check stored Markdown that has them. Exported Markdown for such formatting, and for formatting beside a bare URL, now holds the character references described above, so check export snapshots too.
12 changes: 12 additions & 0 deletions packages/lexical-markdown/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,18 @@ reference definition or a check list item, so text such as `[1]` and `array[0]`
exports as typed. Escaped brackets and guarded `<`/`&` use numeric references so
escaping does not change adjacent emphasis flanking.

Import follows CommonMark's Unicode punctuation and whitespace when deciding
whether `*`, `_`, `~~` and `==` open or close formatting. When formatted text
starts or ends with punctuation right beside a letter, export writes that
letter as a numeric reference (`fo&#111;**“bar”**`) so that the markers still
open and close, for micromark-based readers such as `@lexical/mdast` too. This
holds with `shouldPreserveNewLines` as well, where a raw backslash right before
such a marker or reference goes out as `&#92;`. Where a bare URL, `www.` host
or email that GFM readers would link holds such a reference, or would take in
the markers or code span after it, export writes a character of its prefix as
a reference too (`www&#46;x.co*a*b`), so that no reader links it and the
formatting comes through.

There're three types of transformers:

- **Element transformer** handles top level elements (lists, headings, quotes, tables or code blocks)
Expand Down
Loading
Loading