From 4bbfd90ee0749fa038a500e043021d19bbb43916 Mon Sep 17 00:00:00 2001 From: hedi-ghodhbane Date: Mon, 23 Mar 2026 10:54:04 +0100 Subject: [PATCH 1/3] fix: restore depth guard in getParentBlockInfo to prevent RangeError PR #2126 removed the depth guard that prevented calling `$pos.before(0)` on the top-level document node. When pressing Delete at the end of the last block, `$pos.depth` is 1, so `depth` becomes 0, and `$pos.before(0)` throws "RangeError: There is no position before the top-level node". This restores the guard by returning undefined when depth < 1, before the `.before()` call. Fixes #2584 --- .../blockManipulation/commands/mergeBlocks/mergeBlocks.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/core/src/api/blockManipulation/commands/mergeBlocks/mergeBlocks.ts b/packages/core/src/api/blockManipulation/commands/mergeBlocks/mergeBlocks.ts index 2e9a58d70f..ce1a9455db 100644 --- a/packages/core/src/api/blockManipulation/commands/mergeBlocks/mergeBlocks.ts +++ b/packages/core/src/api/blockManipulation/commands/mergeBlocks/mergeBlocks.ts @@ -16,6 +16,11 @@ export const getParentBlockInfo = ( ): BlockInfo | undefined => { const $pos = doc.resolve(beforePos); const depth = $pos.depth - 1; + + if (depth < 1) { + return undefined; + } + const parentBeforePos = $pos.before(depth); const parentNode = doc.resolve(parentBeforePos).nodeAfter; From 41bd6683bf4885b336b34805a759f17736703eda Mon Sep 17 00:00:00 2001 From: hedi-ghodhbane Date: Mon, 23 Mar 2026 15:59:15 +0100 Subject: [PATCH 2/3] test: add unit test for getParentBlockInfo depth guard Verifies that getParentBlockInfo returns undefined when called on a top-level block (depth < 1), preventing the RangeError that was thrown by $pos.before(0). Co-Authored-By: Claude Opus 4.6 (1M context) --- .../commands/mergeBlocks/mergeBlocks.test.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/core/src/api/blockManipulation/commands/mergeBlocks/mergeBlocks.test.ts b/packages/core/src/api/blockManipulation/commands/mergeBlocks/mergeBlocks.test.ts index 57ec776d3a..437d7ad098 100644 --- a/packages/core/src/api/blockManipulation/commands/mergeBlocks/mergeBlocks.test.ts +++ b/packages/core/src/api/blockManipulation/commands/mergeBlocks/mergeBlocks.test.ts @@ -2,7 +2,7 @@ import { describe, expect, it } from "vitest"; import { getBlockInfoFromTransaction } from "../../../getBlockInfoFromPos.js"; import { setupTestEnv } from "../../setupTestEnv.js"; -import { mergeBlocksCommand } from "./mergeBlocks.js"; +import { getParentBlockInfo, mergeBlocksCommand } from "./mergeBlocks.js"; const getEditor = setupTestEnv(); @@ -77,6 +77,16 @@ describe("Test mergeBlocks", () => { expect(anchorIsAtOldFirstBlockEndPos).toBeTruthy(); }); + it("getParentBlockInfo returns undefined for top-level block", () => { + getEditor().setTextCursorPosition("paragraph-0"); + + const beforePos = getPosBeforeSelectedBlock(); + const doc = getEditor()._tiptapEditor.state.doc; + const result = getParentBlockInfo(doc, beforePos); + + expect(result).toBeUndefined(); + }); + // We expect a no-op for each of the remaining tests as merging should only // happen for blocks which both have inline content. We also expect // `mergeBlocks` to return false as TipTap commands should do that instead of From 55be6bd623f846bbfa225a298bbc0a35c766da33 Mon Sep 17 00:00:00 2001 From: hedi-ghodhbane Date: Tue, 24 Mar 2026 09:42:46 +0100 Subject: [PATCH 3/3] test: assert resolved position depth triggers the guard Verify that the resolved position's depth is < 1 before calling getParentBlockInfo, ensuring we exercise the top-level branch. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../commands/mergeBlocks/mergeBlocks.test.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/core/src/api/blockManipulation/commands/mergeBlocks/mergeBlocks.test.ts b/packages/core/src/api/blockManipulation/commands/mergeBlocks/mergeBlocks.test.ts index 437d7ad098..654fbfdeba 100644 --- a/packages/core/src/api/blockManipulation/commands/mergeBlocks/mergeBlocks.test.ts +++ b/packages/core/src/api/blockManipulation/commands/mergeBlocks/mergeBlocks.test.ts @@ -82,6 +82,10 @@ describe("Test mergeBlocks", () => { const beforePos = getPosBeforeSelectedBlock(); const doc = getEditor()._tiptapEditor.state.doc; + const $pos = doc.resolve(beforePos); + + expect($pos.depth - 1).toBeLessThan(1); + const result = getParentBlockInfo(doc, beforePos); expect(result).toBeUndefined();