Files
twenty/packages
Sonarly Claude Code 9407ab91cf fix(twenty-front): guard convertTextToTag against stale editor state in multi-item field editor
https://sonarly.com/issue/33779?type=bug

The workflow email editor's multi-recipient field crashes with RangeError when `convertTextToTag` runs inside a `setTimeout` callback with a stale text length, computing a negative `from` position for ProseMirror's `deleteRange`.

Fix: Changed `convertTextToTag` to read the text before cursor from the editor's current state at execution time, instead of accepting a pre-captured `text` parameter from the caller's closure.

**What changed:**

1. **`convertTextToTag` signature**: Changed from `(editor: Editor, text: string)` to `(editor: Editor)`. The function now calls `getTextBeforeCursor(editor)` internally to get the current text before cursor, ensuring it always operates on the editor's actual state rather than a stale closure value.

2. **Safety guard**: Added `if (deleteFrom < 0) return false` check before calling `deleteRange`, as defense-in-depth against any remaining edge case where position arithmetic could produce a negative value.

3. **All 4 call sites updated**:
   - `handleTextInput` setTimeout callback (line 77)
   - `handleKeyDown` setTimeout callback (line 90)
   - `onBlur` handler (line 159) — also simplified since the empty-text check is now inside `convertTextToTag`

**Why this fixes the bug:**

The original code captured `textBefore` via `getTextBeforeCursor()` at event time, then passed it to `convertTextToTag` inside a `setTimeout`. By the time the setTimeout fired, the `onBlur` handler (or another setTimeout) could have already converted that text to a tag node, shrinking the document. The function then used the stale `text.length` against the current `$from.pos`, producing `deleteFrom = small_pos - large_stale_length = negative`, which caused ProseMirror's `Node.resolve(negative)` to throw `RangeError: Position -N out of range`.

Now, `convertTextToTag` reads the current text at execution time. If a prior handler already converted the text, `getTextBeforeCursor` returns an empty string, and the function safely returns `false`.
2026-05-03 23:28:45 +00:00
..