Fix deleteText removing all inline children from a block#158
Conversation
The empty-inline cleanup loop in deleteText used a snapshot array to guard against removing the last inline, but never updated the array after each removal. With 2+ empty inlines the stale length check allowed all of them to be deleted, leaving the block with zero inline children and causing "unacceptable path" errors on subsequent edits. Apply the same splice pattern already used in applyStyle so the guard tracks the actual count. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
📝 WalkthroughWalkthroughUpdated the Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/frontend/tests/app/docs/yorkie-doc-store.test.ts (1)
494-546: Good regression test — covers the exact production failure shape.The test faithfully reproduces the scenario (block with 2 empty inlines after split-fragment state) and asserts both the tree invariant (exactly 1 inline child) and that
getDocument()still round-trips cleanly — which was the symptom path that ultimately raisedYorkieError: unacceptable path.One small optional refinement: consider also asserting the inline has
text === ''after delete, so a future regression that accidentally preserved the wrong inline (e.g. left'X'behind) would be caught too. Not a blocker.Optional additional assertion
assert.equal(result.blocks[1].inlines.length, 1); + assert.equal(result.blocks[1].inlines[0].text, ''); });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/frontend/tests/app/docs/yorkie-doc-store.test.ts` around lines 494 - 546, Add an extra assertion after the deleteText step to verify the remaining inline's text is empty: locate the test "should keep at least one inline when deleting all text from a block with multiple empty inlines" and after computing inlinesAfter (from blockAfter.children) assert that inlinesAfter[0].text === '' (or the equivalent property used by your model) before calling store.getDocument(); this will ensure the preserved inline contains an empty string rather than leftover content from the deleted text (references: makeBlock, store.splitBlock, doc.update, store.insertText, store.deleteText, store.getDocument).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@packages/frontend/tests/app/docs/yorkie-doc-store.test.ts`:
- Around line 494-546: Add an extra assertion after the deleteText step to
verify the remaining inline's text is empty: locate the test "should keep at
least one inline when deleting all text from a block with multiple empty
inlines" and after computing inlinesAfter (from blockAfter.children) assert that
inlinesAfter[0].text === '' (or the equivalent property used by your model)
before calling store.getDocument(); this will ensure the preserved inline
contains an empty string rather than leftover content from the deleted text
(references: makeBlock, store.splitBlock, doc.update, store.insertText,
store.deleteText, store.getDocument).
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 39ce5981-15fe-44ea-b4d3-47e28661e76e
📒 Files selected for processing (2)
packages/frontend/src/app/docs/yorkie-doc-store.tspackages/frontend/tests/app/docs/yorkie-doc-store.test.ts
Verification: verify:selfResult: ✅ PASS in 116.7s
Verification: verify:integrationResult: ✅ PASS |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Summary
deleteTextcleanup loop that allowed removing all inline children from a block, leaving it in an invalid stateinlinessnapshot array was never updated after each removal, so thelengthguard always checked the original countsplicepattern already used inapplyStyleto keep the array in sync with the treeRoot Cause
When a block has 2+ empty inlines after text deletion, the cleanup loop removes them one by one. The guard
if (inlines.length <= 1) breakchecked the snapshot array length, which never decreased. With 2 empty inlines, both were removed, leaving the block with zero inline children. SubsequenteditByPathcalls on that block triggeredYorkieError: unacceptable path.Confirmed by replaying all 451 changes from the production document (
server_seq=630).Test plan
pnpm verify:fastpasses (200 tests, 0 failures)pnpm verify:selfpasses (full build + tests)🤖 Generated with Claude Code
Summary by CodeRabbit
Bug Fixes
Tests