Floating Promise Anti-Pattern & Premature Caret in Multi-Block Paste

Open Beginner friendly
#3,032 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
78/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
typescript
Domain
frontend

Research direction

Start in src/components/modules/paste.ts around lines 251–261 and trace insertBlock, BlockManager.currentBlock, and Caret.setToBlock. Exercise multi-block paste with a custom or asynchronously initialized tool, then verify that all blocks are inserted and the caret ends in the intended block without discarded promises.

Written by the indexing model from the issue text.

Description

bug good first issue

4. Floating Promise Anti-Pattern & Premature Caret in Multi-Block Paste

📍 Affected Locations
  • src/components/modules/paste.ts (Lines 251–261)
🔍 Deep Technical Diagnosis

In src/components/modules/paste.ts:

// src/components/modules/paste.ts: Lines 251-261
const isCurrentBlockDefault = BlockManager.currentBlock && BlockManager.currentBlock.tool.isDefault;
const needToReplaceCurrentBlock = isCurrentBlockDefault && BlockManager.currentBlock.isEmpty;

dataToInsert.map(
  async (content, i) => this.insertBlock(content, i === 0 && needToReplaceCurrentBlock)
);

if (BlockManager.currentBlock) {
  Caret.setToBlock(BlockManager.currentBlock, Caret.positions.END);
}
Flaws:
  1. Misused .map() as .forEach(): .map() allocates a new array of returned Promises that are completely discarded.
  2. Unawaited Floating Promises: The callback is marked async, meaning this.insertBlock(...) returns an unresolved Promise for each item.
  3. Premature Caret Placement: Caret.setToBlock(BlockManager.currentBlock, Caret.positions.END) executes immediately and synchronously on line 259 before the async map operations have resolved.
  4. If any custom tool initializes asynchronously during insertion or yields to the event loop, the caret focuses the wrong block or moves before blocks are even attached to the DOM.
💡 Proposed Solution & Patch
src/components/modules/paste.ts
@@ -251,9 +251,9 @@ export default class Paste extends Module {
     const isCurrentBlockDefault = BlockManager.currentBlock && BlockManager.currentBlock.tool.isDefault;
     const needToReplaceCurrentBlock = isCurrentBlockDefault && BlockManager.currentBlock.isEmpty;

-    dataToInsert.map(
-      async (content, i) => this.insertBlock(content, i === 0 && needToReplaceCurrentBlock)
-    );
+    for (let i = 0; i < dataToInsert.length; i++) {
+      this.insertBlock(dataToInsert[i], i === 0 && needToReplaceCurrentBlock);
+    }

     if (BlockManager.currentBlock) {
       Caret.setToBlock(BlockManager.currentBlock, Caret.positions.END);

Dominant language
TypeScript
Stars
32k
Forks
2.2k
Avg merge
1d 13h
Merged PRs (30d)
2

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from codex-team/editor.js

All issues in codex-team/editor.js

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.