[delta integration] fixed all tests

This commit is contained in:
Kevin Jahns
2026-01-10 13:28:41 +01:00
parent 8bd9946a95
commit bbaec17bf3
8 changed files with 38 additions and 56 deletions

View File

@@ -24,6 +24,7 @@ import {
getItemCleanStart,
intersectSets,
ContentFormat,
createAttributionItem,
StructStore, Transaction, ID, IdSet, Item, Snapshot, Doc, AbstractContent, IdMap, // eslint-disable-line
encodeStateAsUpdate
} from '../internals.js'
@@ -574,16 +575,16 @@ export class SnapshotAttributionManager extends ObservableV2 {
* @param {Object} [options] - options for the attribution manager
* @param {Array<import('./IdMap.js').AttributionItem<any>>} [options.attrs] - the attributes to apply to the diff
*/
constructor (prevSnapshot, nextSnapshot, { attrs = [] } = {}) {
constructor (prevSnapshot, nextSnapshot) {
super()
this.prevSnapshot = prevSnapshot
this.nextSnapshot = nextSnapshot
const inserts = createIdMap()
const deletes = createIdMapFromIdSet(diffIdSet(nextSnapshot.ds, prevSnapshot.ds), attrs)
const deletes = createIdMapFromIdSet(diffIdSet(nextSnapshot.ds, prevSnapshot.ds), [createAttributionItem('change', '')])
nextSnapshot.sv.forEach((clock, client) => {
const prevClock = prevSnapshot.sv.get(client) || 0
inserts.add(client, 0, prevClock, []) // content is included in prevSnapshot is rendered without attributes
inserts.add(client, prevClock, clock - prevClock, attrs) // content is rendered as "inserted"
inserts.add(client, prevClock, clock - prevClock, [createAttributionItem('change', '')]) // content is rendered as "inserted"
})
this.attrs = mergeIdMaps([diffIdMap(inserts, prevSnapshot.ds), deletes])
}
@@ -635,7 +636,5 @@ export class SnapshotAttributionManager extends ObservableV2 {
/**
* @param {Snapshot} prevSnapshot
* @param {Snapshot} nextSnapshot
* @param {Object} [options] - options for the attribution manager
* @param {Array<import('./IdMap.js').AttributionItem<any>>} [options.attrs] - the attributes to apply to the diff
*/
export const createAttributionManagerFromSnapshots = (prevSnapshot, nextSnapshot = prevSnapshot, options) => new SnapshotAttributionManager(prevSnapshot, nextSnapshot, options)
export const createAttributionManagerFromSnapshots = (prevSnapshot, nextSnapshot = prevSnapshot) => new SnapshotAttributionManager(prevSnapshot, nextSnapshot)

View File

@@ -530,22 +530,6 @@ const cleanupTransactions = (transactionCleanups, i) => {
// We need to think about the possibility that the user transforms the
// Y.Doc in the event.
if (type._dEH.l.length > 0 && (type._item === null || !type._item.deleted)) {
events = events
.filter(event =>
event.target._item === null || !event.target._item.deleted
)
events
.forEach(event => {
event.currentTarget = type
// path is relative to the current target
event._path = null
})
// sort events by path length so that top-level events are fired first.
events
.sort((event1, event2) => event1.path.length - event2.path.length)
// We don't need to check for events.length
// because we know it has at least one element
/**
* @type {YEvent<any>}
*/

View File

@@ -101,8 +101,6 @@ export class ItemTextListPosition {
* @function
*/
formatText (transaction, parent, length, attributes) {
const doc = transaction.doc
const ownClientId = doc.clientID
minimizeAttributeChanges(this, attributes)
const negatedAttributes = insertAttributes(transaction, parent, this, attributes)
// iterate until first non-format or null is found
@@ -1312,7 +1310,7 @@ export class YType {
* @type {{[K:string]:any}}
*/
const attrs = this.getAttrs()
for (let k in attrs) {
for (const k in attrs) {
const attr = attrs[k]
attrs[k] = attr instanceof YType ? attr.toJSON() : attr
}
@@ -1343,7 +1341,7 @@ export class YType {
*/
const attrs = []
this.forEachAttr((attr, key) => {
attrs.push([(key), attr.toString({ forceTag: true })])
attrs.push([(key), /** @type {any} */ (attr) instanceof YType ? attr.toString({ forceTag: true }) : JSON.stringify(attr)])
})
const attrsString = (attrs.length > 0 ? ' ' : '') + attrs.sort((a, b) => a[0].toString() < b[0].toString() ? -1 : 1).map(attr => attr[0] + '=' + attr[1]).join(' ')
/**
@@ -1561,6 +1559,8 @@ export const typeListGet = (type, index) => {
}
/**
* @todo this is a duplicate. use the unified insert function and remove this.
*
* @param {Transaction} transaction
* @param {YType} parent
* @param {Item?} referenceItem

View File

@@ -112,14 +112,16 @@ export const testToJSON = _tc => {
map2.setAttr('m2k1', 'm2v1')
t.compare(doc.toJSON(), {
array: { children: ['test1'] },
map: { attrs: {
k1: 'v1',
k2: {
attrs: {
m2k1: 'm2v1'
map: {
attrs: {
k1: 'v1',
k2: {
attrs: {
m2k1: 'm2v1'
}
}
}
}}
}
}, 'doc.toJSON has array and recursive map')
}

View File

@@ -262,7 +262,7 @@ export const testUndoArray = tc => {
t.compare(array0.toJSON().children, [{}])
undoManager.stopCapturing()
ymap.setAttr('a', 1)
t.compare(array0.toJSON().children, [{ a: 1 }])
t.compare(array0.toJSON().children, [{ attrs: { a: 1 } }])
undoManager.undo()
t.compare(array0.toJSON().children, [{}])
undoManager.undo()
@@ -270,19 +270,19 @@ export const testUndoArray = tc => {
undoManager.redo()
t.compare(array0.toJSON().children, [{}])
undoManager.redo()
t.compare(array0.toJSON().children, [{ a: 1 }])
t.compare(array0.toJSON().children, [{ attrs: { a: 1 } }])
testConnector.syncAll()
array1.get(0).setAttr('b', 2)
testConnector.syncAll()
t.compare(array0.toJSON().children, [{ a: 1, b: 2 }])
t.compare(array0.toJSON().children, [{ attrs: { a: 1, b: 2 } }])
undoManager.undo()
t.compare(array0.toJSON().children, [{ b: 2 }])
t.compare(array0.toJSON().children, [{ attrs: { b: 2 } }])
undoManager.undo()
t.compare(array0.toJSON().children, [2, 3, 4, 5, 6])
undoManager.redo()
t.compare(array0.toJSON().children, [{ b: 2 }])
t.compare(array0.toJSON().children, [{ attrs: { b: 2 } }])
undoManager.redo()
t.compare(array0.toJSON().children, [{ a: 1, b: 2 }])
t.compare(array0.toJSON().children, [{ attrs: { a: 1, b: 2 } }])
}
/**
@@ -311,7 +311,6 @@ export const testUndoXml = tc => {
t.compare(xml0.getContentDeep(), v1)
}
/**
* @param {t.TestCase} tc
*/
@@ -584,7 +583,7 @@ export const testUndoXmlBug = _tc => {
undoManager.redo()
undoManager.redo()
undoManager.redo()
t.compare(fragment.toString(), '<test-node a=180 b=50 />')
t.compare(fragment.toString(), '<test-node a="180" b="50" />')
}
/**
@@ -643,7 +642,7 @@ export const testUndoBlockBug = _tc => {
undoManager.redo() // {"text":{"blocks":{"text":"2"}}}
undoManager.redo() // {"text":{"blocks":{"text":"3"}}}
undoManager.redo() // {"text":{}}
t.compare(design.toJSON().attrs, { text: { blocks: { text: '4' } } })
t.compare(design.toJSON().attrs, { text: { attrs: { blocks: { attrs: { text: '4' } } } } })
}
/**
@@ -720,16 +719,16 @@ export const testSpecialDeletionCase = _tc => {
e.setAttr('b', '2')
fragment.insert(0, [e])
})
t.compareStrings(fragment.toString(), '<test a="1" b="2"></test>')
t.compareStrings(fragment.toString(), '<test a="1" b="2" />')
doc.transact(() => {
// change attribute "b" and delete test-node
const e = fragment.get(0)
e.setAttribute('b', '3')
e.setAttr('b', '3')
fragment.delete(0)
}, origin)
t.compareStrings(fragment.toString(), '')
undoManager.undo()
t.compareStrings(fragment.toString(), '<test a="1" b="2"></test>')
t.compareStrings(fragment.toString(), '<test a="1" b="2" />')
}
/**

View File

@@ -203,7 +203,7 @@ export const testYmapSetsYarray = tc => {
t.assert(array === map0.getAttr('Array'))
array.insert(0, [1, 2, 3])
// @ts-ignore
t.compare(map0.toJSON(), { Array: [1, 2, 3] })
t.compare(map0.toJSON().attrs, { Array: { children: [1, 2, 3] } })
compare(users)
}

View File

@@ -2096,7 +2096,7 @@ const qChanges = [
*/
(y, gen) => { // delete text
const ytext = y.get('text')
const contentLen = ytext.toString().length
const contentLen = ytext.length
const insertPos = prng.int32(gen, 0, contentLen)
const overwrite = math.min(prng.int32(gen, 0, contentLen - insertPos), 2)
ytext.delete(insertPos, overwrite)
@@ -2107,7 +2107,7 @@ const qChanges = [
*/
(y, gen) => { // format text
const ytext = y.get('text')
const contentLen = ytext.toString().length
const contentLen = ytext.length
const insertPos = prng.int32(gen, 0, contentLen)
const overwrite = math.min(prng.int32(gen, 0, contentLen - insertPos), 2)
const format = prng.oneOf(gen, marks)
@@ -2119,7 +2119,7 @@ const qChanges = [
*/
(y, gen) => { // insert codeblock
const ytext = y.get('text')
const insertPos = prng.int32(gen, 0, ytext.toString().length)
const insertPos = prng.int32(gen, 0, ytext.length)
const text = charCounter++ + prng.word(gen)
const d = delta.create()
d.retain(insertPos).insert(text).insert('\n', { 'code-block': true })
@@ -2131,7 +2131,7 @@ const qChanges = [
*/
(y, gen) => { // complex delta op
const ytext = y.get('text')
const contentLen = ytext.toString().length
const contentLen = ytext.length
let currentPos = math.max(0, prng.int32(gen, 0, contentLen - 1))
const d = delta.create().retain(currentPos)
// create max 3 ops

View File

@@ -94,14 +94,12 @@ export const testInsertafter = _tc => {
const first = new Y.Type()
const second = new Y.Type('p')
const third = new Y.Type('p')
const deepsecond1 = new Y.Type('span')
const deepsecond2 = new Y.Type()
second.insertAfter(null, [deepsecond1])
second.insertAfter(deepsecond1, [deepsecond2])
yxml.insertAfter(null, [first, second])
yxml.insertAfter(second, [third])
second.insertAfter(null, [deepsecond1])
second.insertAfter(deepsecond1, [deepsecond2])
t.assert(yxml.length === 3)
t.assert(second.get(0) === deepsecond1)
@@ -164,9 +162,9 @@ export const testElement = _tc => {
export const testFragmentAttributedContent = _tc => {
const ydoc = new Y.Doc({ gc: false })
const yfragment = new Y.Type()
const elem1 = new Y.Type('hello')
const elem1 = Y.Type.from(delta.create().insert('hello'))
const elem2 = new Y.Type()
const elem3 = new Y.Type('world')
const elem3 = Y.Type.from(delta.create().insert('world'))
yfragment.insert(0, [elem1, elem2])
ydoc.get().insert(0, [yfragment])
let attributionManager = Y.noAttributionsManager
@@ -230,7 +228,7 @@ export const testElementAttributedContentViaDiffer = _tc => {
Y.applyUpdate(ydoc, Y.encodeStateAsUpdate(ydocV1))
const yelement = ydoc.get('p')
const elem2 = yelement.get(1) // new Y.XmlElement('span')
const elem3 = new Y.Type('world')
const elem3 = Y.Type.from(delta.create().insert('world'))
ydoc.transact(() => {
yelement.delete(0, 1)
yelement.insert(1, [elem3])