Uncaught RangeError: Position 14 out of range

Here i made a codesandbox showing the bug (demo).

I have this InputRule, which detect matches to the ‘SUI-x’ string.

I need each time there is a match to delete the whole ‘SUI-x’ to replace it later by another custom node.

I think what i’m passing to the tr.deleteRange() as parameters is correct : the range to delete is between the current selection / cursor pos and newFrom = pos - (detectedMatchLength + 3);

new InputRule(/(?:SUI-)(.*[a-zA-Z0-9]+)/, function(state, match, start, end) {
      const { view } = useProseMirrorComp;
      const detectedMatch = match[1];
      const detectedMatchLength = detectedMatch.length;
      const { selection, doc } = state;
      let { tr } = state;
      const { $from } = selection;
      const { pos } = $from;

      const newFrom = pos - (detectedMatchLength + 3);
      tr.deleteRange(newFrom, pos); // this causes the console error..

      view.updateState(state.apply(tr));
    });

But i’m getting this error:

     Uncaught RangeError: Position 14 out of range
     at Function.resolve (index.js:936)
     at Function.resolveCached (index.js:959)
     at Node.resolve (index.js:1228)
     at run (index.js:75)
     at Plugin.handleTextInput (index.js:55)
     at eval (index.js:2699)
     at EditorView.someProp (index.js:4849)
     at readDOMChange (index.js:2699)
     at DOMObserver.eval [as handleDOMChange] (index.js:3286)
     at DOMObserver.flush (index.js:3200)

I also tried to update the text node instead using tr.deleteRange():

new InputRule(/(?:SUI-)(.*[a-zA-Z0-9]+)/, function(state, match, start, end) {
      const { view } = useProseMirrorComp;
      const detectedMatch = match[1];
      const detectedMatchLength = detectedMatch.length;
      const { selection, doc } = state;
      let { tr } = state;
      const { $from } = selection;
      const { pos } = $from;
      const prevNode = doc.nodeAt(pos - 1);
      const prevNodePos = findNodePosition(doc, prevNode);
      const prevNodeText = prevNode.text;
      prevNode.text = prevNodeText.slice(0, prevNodeText.length - (detectedMatchLength + 4));
      view.updateState(state.apply(tr));
    });

But i also got this error too:

    Uncaught Error: Invalid position 8
    at NodeViewDesc.domFromPos (index.js:858)
    at NodeViewDesc.setSelection (index.js:946)
    at NodeViewDesc.setSelection (index.js:942)
    at selectionToDOM (index.js:2069)
    at EditorView.updateStateInner (index.js:4791)
    at EditorView.updateState (index.js:4730)
    at InputRule.rules [as handler] (BookEditor.js?da7b:332)
    at run (index.js:81)
    at Plugin.handleTextInput (index.js:55)
    at eval (index.js:2699)

Please help

Try using start and end instead of computing the extent. The match is against the changed text, with the content that’s being typed included, whereas the document still doesn’t actually have the typed character yet.

prevNode.text = prevNodeText.slice(0, prevNodeText.length - (detectedMatchLength + 4));

As the docs repeat again and again, nodes are immutable, so doing something like this is definitely never going to work.

Thanks for the answer, I wouldn’t try to change the immutable node property if the tr.deleteRange() worked for me :upside_down_face:

Well now finally i understood the real issue, I’m modifiying the document’s content with tr.deleteRange() before the content would finish its update after typing the character…

I actually had this same situation in another rule before and i just made a workaround by calling tr.deleteRange() inside a timer which triggers after 50ms.

Is there a more clean way to detect the right moment when the document finish its update inside the rule body itself to proceed ?

Oh no, that’s terrible. As I suggested, use the positions passed to your function.

I couldn’t find any good expression for the parameters passed to the tr.deleteRange() based on them which avoid getting the error. Because callling tr.deleteRange() on the state while it didn’t finish its update after typing the last character will place the last character out of the document absolute range