How does Operational Transformation algorithm in ot.js handle conflicts between Insert and Delete?

Considering OT’s transform algorithm for an Insert operation and a Delete operation executed at the same time, on two different clients. Insert.pos is in the range [Delete.pos, Delete.pos + Delete.count - 1].

To keep both the intentions executed, we can turn the Delete operation into at most two delete operations, to keep both the insert intention and the delete intention executed. More specifically, [Delete.pos, Insert.pos - 1] and [Insert.pos + Insert.content.length, Delete.pos + Delete.count + Insert.content.length - 1].

However, it will turns an operation into two operations. Could it cause time complexity problem?


I later checked ot.js but found their behaviours different.

In Operational-Transformation/ot.js/lib/simple-text-operation.js, it just ignored the Insert operation.

if (a instanceof Insert && b instanceof Delete) {
      if (a.position <= b.position) {
        return [a, new Delete(b.count, b.position + a.str.length)];
      }
      if (a.position >= b.position + b.count) {
        return [new Insert(a.str, a.position - b.count), b];
      }
      // Here, we have to delete the inserted string of operation a.
      // That doesn't preserve the intention of operation a, but it's the only
      // thing we can do to get a valid transform function.
      return [noop, new Delete(b.count + a.str.length, b.position)];
    }

But in https://operational-transformation.github.io/ , the OT take the choice I mentioned in the top of passage (splitting the Delete operation into <=2 operations).

(You can try to remove orem ips in Alice and insert hi at pos = 5 in Bob to see effect.)

I am confused that two behaviors are different, and according to some blogs I see on the Internet, transform should be return only two operations, not two operation arrays (which means splitting is not allowed).