[Bug]: On 53.x, CRLF paragraph and blockquote text serializes with a lone `\r` and an extra hard break (fixed on `next` by #5152, not released)

Aperta
#5,323 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 1 giorno

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
3/5
Tempo stimato
1-2 giorni
Idoneità per principianti
70/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
typescript
Ambito
backend

Direzione di ricerca

Start with packages/markdown/src/lib/rules/defaultRules.ts:162-182 and the three reproduction inputs in the issue; compare the current line splitting with the paragraph handling described for PR #5152. Run the supplied bun reproduction and check serializeMd output for CRLF paragraph and blockquote text against the LF case. Done when CRLF output matches LF output and LF output stays unchanged.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

Bug type

Regression (worked before, now fails)

Browser surface

No

Owner surface

Plate framework or plugin

Summary

On @platejs/markdown 53.x, paragraph and blockquote text with CRLF line endings serializes with a lone \r followed by a hard break (\). PR #5152 fixes this on next, but it is not in any 53.x release.

Public reproduction URL

https://gist.github.com/venmakli/97e3b7778ead568b96ac990fa3f760ee

Steps to reproduce
  1. Download the reproduction (package.json and repro.ts).
  2. Run bun install && bun repro.ts.
  3. line one\r\nline two serializes to line one\r\\\nline two, and > q1\r\n> q2 to > q1\r> \\\n> q2. The LF input serializes to line one\\\nline two.
Expected behavior

The CRLF input serializes like its LF version, which repro.ts prints next to it: line one\ + LF + line two, without a lone \r. On 53.1.5 the CRLF input did not produce a lone \r or an extra \ (see "Regression range").

Actual behavior

On @platejs/markdown 53.3.18 (output of repro.ts):

"line one\r\nline two\r\n"
  value:     [{"children":[{"text":"line one\r\nline two"}],"type":"p"}]
  serialize: "line one\r\\\nline two\n"
"> q1\r\n> q2\r\n"
  value:     [{"children":[{"children":[{"text":"q1\r\nq2"}],"type":"p"}],"type":"blockquote"}]
  serialize: "> q1\r> \\\n> q2\n"
"line one\nline two\n"
  value:     [{"children":[{"text":"line one\nline two"}],"type":"p"}]
  serialize: "line one\\\nline two\n"

The output keeps a lone \r, which CommonMark reads as a line ending of its own. The blockquote output gets an extra > \ line. A second deserialize → serialize round trip keeps both.

Acceptance criteria
  • On the 53.x line, serializeMd output for CRLF paragraph and blockquote text has no lone \r and equals the output for the LF version of the same input.
  • Output for LF input is unchanged.

Question for maintainers: will #5152 (or its paragraph-text part) be backported to 53.x, or will the fix ship only with v54?

Regression range
last-known-good: "@platejs/markdown 53.1.5 (published 2026-06-14), with platejs 53.1.2"
first-known-bad: "@platejs/markdown 53.2.2 (published 2026-06-17), with platejs 53.2.1; still present in 53.3.18 and on main (170d73db6, 2026-10-23)"
evidence: >
  Same script on both versions. 53.1.5: "line one\r\nline two\r\n" -> "line one\r\nline two\n" and "> q1\r\n> q2\r\n" -> "> q1\r\n> q2\n"
  (no lone CR, no hard break). 53.2.2: "line one\r\\\nline two\n" and "> q1\r> \\\n> q2\n".
  53.2.2 is the first release after PR #5026 (commit b99cebe3d "fix markdown text leaf line breaks", merged into main 2026-06-17T09:18Z).
  It added normalizeParagraphLineBreaks, which splits text with text.split('\n')
  (v53.3.18 packages/markdown/src/lib/rules/defaultRules.ts:169); the 53.1.5 dist has no normalizeParagraphLineBreaks.
  PR #5152 (merged into next 2026-10-08T22:42Z) splits paragraph text with /\r?\n/ in encodeMarkdownParagraph
  (next: packages/platejs/src/markdown/lib/internal/markdownIntrinsics.ts). 53.3.18 (2026-10-18) was released from main
  without it; main's defaultRules.ts is identical to v53.3.18.
Reproducibility

Always

Plate / Plite / React versions
plate: "@platejs/markdown 53.3.18, platejs 53.3.18 (mdast-util-from-markdown 2.1.0, mdast-util-to-markdown 2.2.1)"
plite: not used
plite-react: not used
react: not used
Operating system

macOS 15 (Darwin 24.6.0)

Install method

bun 1.4.4: bun install && bun repro.ts

Framework / app setup

Headless createSlateEditor with MarkdownPlugin only, no React.

Affected packages or entry points

@platejs/markdown: editor.api.markdown.serialize / serializeMd (p rule via normalizeParagraphLineBreaks, blockquote), with values from deserializeMd for CRLF input.

Minimal code or config excerpt
import { MarkdownPlugin } from '@platejs/markdown';
import { createSlateEditor } from 'platejs';

const editor = createSlateEditor({ plugins: [MarkdownPlugin] });

for (const input of ['line one\r\nline two\r\n', '> q1\r\n> q2\r\n', 'line one\nline two\n']) {
  const value = editor.api.markdown.deserialize(input);
  editor.tf.setValue(value);
  console.log(JSON.stringify(input));
  console.log('  value:    ', JSON.stringify(value));
  console.log('  serialize:', JSON.stringify(editor.api.markdown.serialize()));
}
Logs, screenshots, and evidence
# @platejs/markdown 53.1.5 + platejs 53.1.2
"line one\r\nline two\r\n" serialize: "line one\r\nline two\n"
"> q1\r\n> q2\r\n"         serialize: "> q1\r\n> q2\n"
"line one\nline two\n"     serialize: "line one\nline two\n"

# @platejs/markdown 53.2.2 + platejs 53.2.1
"line one\r\nline two\r\n" serialize: "line one\r\\\nline two\n"
"> q1\r\n> q2\r\n"         serialize: "> q1\r> \\\n> q2\n"
"line one\nline two\n"     serialize: "line one\\\nline two\n"

# mdast from mdast-util-from-markdown 2.1.0: the text value keeps CRLF
[["text","line one\r\nline two"]]
Maintainer Codex context
route: N/A (headless)
local command: bun install && bun repro.ts
fixture/data: the three inputs in repro.ts
rule location: >
  v53.3.18 and main (170d73db6): packages/markdown/src/lib/rules/defaultRules.ts:162-182 (normalizeParagraphLineBreaks,
  split at :169, from b99cebe3d / PR #5026). next: packages/platejs/src/markdown/lib/internal/markdownIntrinsics.ts
  (encodeMarkdownParagraph, split(/\r?\n/), PR #5152).
known blocker: none
Impact and severity
  • Affected: @platejs/markdown 53.2.2 – 53.3.18 users who serialize values deserialized from CRLF Markdown with line breaks inside paragraphs or blockquotes. Observed on CRLF input bytes; the OS running the code does not matter.
  • Severity: data risk. The written Markdown gets a lone \r and a hard break that the source did not have.
  • Frequency: always for CRLF input with a line break inside a paragraph or blockquote.
  • Consequence: the serialized file renders differently from the source, and each line break inside a paragraph changes in diffs.
Additional information

Last known good: @platejs/markdown 53.1.5. First known bad: @platejs/markdown 53.2.2. Changing the LF soft break to \ is the intended effect of #5026 and is not reported here. Code-block lines under CRLF are a separate report.

Lingua principale
TypeScript
Stelle
16.6k
Fork
993
Merge medio
15h 55m
PR unite (30g)
63

Preparare l'ambiente

Questo progetto non fornisce container di sviluppo, Dockerfile né guida per i contributori, quindi l'ambiente è a tuo carico: parti dal suo README e consulta la nostra guida al primo contributo per i passaggi generali.

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di udecode/plate

Tutte le issue di udecode/plate

Issue simili

Altre issue su TypeScript

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.