Repository navigation
Conversation
| if (this.out.endsWith(' ')) { | ||
| let end = this.out.length; | ||
| while (/[ \t]/.test(this.out.charAt(end - 1))) --end; | ||
| this.out = this.out.slice(0, end); |
There was a problem hiding this comment.
AI-generated
"Generated" means mostly the model, "Edited" means mostly me.
[P1] Keep the previous block's output when handling soft_break
When a paragraph starts with soft_break, the previous block has not been closed by flushClose() yet, so this code trims that block's trailing spaces. renderTopLevelContent() then caches the new block as this.out.slice(outBefore.length) with the old length and drops the beginning of its output.
Reproduced with DefaultSpecsPreset:
const first = p('x ');
const second = p(sb(), 'yz');
serializer.serialize(doc(first, second)); // "x\n\n\nyz"
serializer.serialize(doc(first, second, p('new paragraph')));
// "x \n\nnew paragraph": the text "yz" is lostWith two trailing spaces, p('x '), the second serialization returns x \ny, which parses as a single paragraph with a hard_break.
The base version keeps yz. Trimming should be limited to the current block; please add a test that serializes twice with reused nodes.
| if (keepLinkedWhitespace) { | ||
| marks = marks.filter(mark => this.getMark(mark.type.name).expelEnclosingWhitespace) | ||
| .concat(marks.filter(mark => !this.getMark(mark.type.name).expelEnclosingWhitespace)); |
There was a problem hiding this comment.
AI-generated
"Generated" means mostly the model, "Edited" means mostly me.
[P2] Take the preceding character into account when moving formatting outside a link
The reordering produces an invalid opening delimiter when a letter precedes the link. With DefaultSpecsPreset, doc(p('A', a(em('B ')))) now serializes to A*[B ](foo)*: after parsing, B loses emphasis and both asterisks become literal text. The base version outputs A[*B*](foo) and keeps the emphasis. strong and strike behave the same way.
Before moving delimiters outside the link, check that they remain valid at the new position; please add a case with a link directly after plain text.
| if (node?.type.name === 'soft_break') { | ||
| leading = leading.replace(/[ \t]+$/, ''); | ||
| if (this.out.endsWith(' ')) { |
There was a problem hiding this comment.
AI-generated
"Generated" means mostly the model, "Edited" means mostly me.
[P2] Keep spaces inside a link that is being closed
This trimming runs before active marks are closed and removes link content: a document parsed from [x ](foo)\ny serializes back as [x](foo)\ny. The base version keeps both spaces. They cannot produce a hard break, since ](foo) is written before the newline.
Trimming should take closing delimiters into account; please add a round-trip check for a link with two trailing spaces before a soft break.
There was a problem hiding this comment.
AI-generated
"Generated" means mostly the model, "Edited" means mostly me.
Changes requested: repeated serialization can drop a whole paragraph. Loss of link formatting and removal of spaces inside links are also confirmed. Reproductions are in the three inline comments.
There was a problem hiding this comment.
Hey - I've found 1 issue
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="packages/editor/src/core/markdown/MarkdownSerializer.ts" line_range="492-495" />
<code_context>
+
+ if (node?.type.name === 'soft_break') {
+ leading = leading.replace(/[ \t]+$/, '');
+ if (this.out.endsWith(' ')) {
+ let end = this.out.length;
+ while (/[ \t]/.test(this.out.charAt(end - 1))) --end;
+ this.out = this.out.slice(0, end);
+ }
+ }
</code_context>
<issue_to_address>
**Soft break deletes preceding block output**
When a block ends in spaces and the next block starts with a soft break, the soft-break handler trims `this.out` across the top-level block boundary. `renderTopLevelContent` then slices the current block’s cache entry from the old output length, so it omits the beginning of that block; a later serialization with the same preceding block type reuses the truncated output.
Limit soft-break trimming to spaces emitted within the current inline block, rather than trimming the shared output buffer across block boundaries.
</issue_to_address>| if (this.out.endsWith(' ')) { | ||
| let end = this.out.length; | ||
| while (/[ \t]/.test(this.out.charAt(end - 1))) --end; | ||
| this.out = this.out.slice(0, end); |
There was a problem hiding this comment.
🟡 Medium · Soft break deletes preceding block output
When a block ends in spaces and the next block starts with a soft break, the soft-break handler trims this.out across the top-level block boundary. renderTopLevelContent then slices the current block’s cache entry from the old output length, so it omits the beginning of that block; a later serialization with the same preceding block type reuses the truncated output.
Limit soft-break trimming to spaces emitted within the current inline block, rather than trimming the shared output buffer across block boundaries.
Prompt for AI agents
In `packages/editor/src/core/markdown/MarkdownSerializer.ts` at lines 492-495:
**Soft break deletes preceding block output**
When a block ends in spaces and the next block starts with a soft break, the soft-break handler trims `this.out` across the top-level block boundary. `renderTopLevelContent` then slices the current block’s cache entry from the old output length, so it omits the beginning of that block; a later serialization with the same preceding block type reuses the truncated output.
Limit soft-break trimming to spaces emitted within the current inline block, rather than trimming the shared output buffer across block boundaries.|
AI review, revision Tests
Architecture
Other
No findings: PR title, description, packages and scripts. This comment is from AI and may contain inaccuracies. |
Summary
Fix text loss and broken formatting when the serializer handles multiline text, spaces, and line breaks. This continues the whitespace work from #1388.
Tests and remaining scope
Integration tests cover text and formatting after serialization and parsing, link targets, images, and cached heading output without changes to the source document. Fixed cases are converted from expected-failure tests to regular tests.
Expected-failure tests remain for known code-space, code/link, and Unicode delimiter problems, including the deferred multiline code/link cases. This PR does not resolve all serializer boundary issues.
Summary by Sourcery
Preserve multiline text and formatting boundaries across Markdown serialization and parsing.
Bug Fixes:
Enhancements:
Tests: