62 lines
1.6 KiB
JavaScript
62 lines
1.6 KiB
JavaScript
|
|
/**
|
|
* @module utils
|
|
*/
|
|
|
|
import * as ID from '../utils/ID.js'
|
|
import { ItemJSON } from '../structs/ItemJSON.js'
|
|
import { ItemString } from '../structs/ItemString.js'
|
|
|
|
/**
|
|
* Try to merge all items in os with their successors.
|
|
*
|
|
* Some transformations (like delete) fragment items.
|
|
* Item(c: 'ab') + Delete(1,1) + Delete(0, 1) -> Item(c: 'a',deleted);Item(c: 'b',deleted)
|
|
*
|
|
* This functions merges the fragmented nodes together:
|
|
* Item(c: 'a',deleted);Item(c: 'b',deleted) -> Item(c: 'ab', deleted)
|
|
*
|
|
* TODO: The Tree implementation does not support deletions in-spot.
|
|
* This is why all deletions must be performed after the traversal.
|
|
*
|
|
*/
|
|
export const defragmentItemContent = y => {
|
|
const os = y.os
|
|
if (os.length < 2) {
|
|
return
|
|
}
|
|
let deletes = []
|
|
let node = os.findSmallestNode()
|
|
let next = node.next()
|
|
while (next !== null) {
|
|
let a = node.val
|
|
let b = next.val
|
|
if (
|
|
(a instanceof ItemJSON || a instanceof ItemString) &&
|
|
a.constructor === b.constructor &&
|
|
a._deleted === b._deleted &&
|
|
a._right === b &&
|
|
(ID.createID(a._id.user, a._id.clock + a._length)).equals(b._id)
|
|
) {
|
|
a._right = b._right
|
|
if (a instanceof ItemJSON) {
|
|
a._content = a._content.concat(b._content)
|
|
} else if (a instanceof ItemString) {
|
|
a._content += b._content
|
|
}
|
|
// delete b later
|
|
deletes.push(b._id)
|
|
// do not iterate node!
|
|
// !(node = next)
|
|
} else {
|
|
// not able to merge node, get next node
|
|
node = next
|
|
}
|
|
// update next
|
|
next = next.next()
|
|
}
|
|
for (let i = deletes.length - 1; i >= 0; i--) {
|
|
os.delete(deletes[i])
|
|
}
|
|
}
|