rename concept AttributionManager => Renderer

definitely a breaking change to all users of the current attribution api
This commit is contained in:
Kevin Jahns
2026-06-16 21:29:45 +02:00
parent b2fd836017
commit e53a6a0227
16 changed files with 218 additions and 215 deletions

View File

@@ -20,9 +20,9 @@ export const testRelativePositions = _tc => {
const v1 = Y.cloneDoc(ydoc)
ytext.delete(1, 6)
ytext.insert(1, 'x')
const am = Y.createAttributionManagerFromDiff(v1, ydoc)
const rel = Y.createRelativePositionFromTypeIndex(ytext, 9, 1, am) // pos after "hello wo"
const abs1 = Y.createAbsolutePositionFromRelativePosition(rel, ydoc, true, am)
const renderer = Y.createDiffRenderer(v1, ydoc)
const rel = Y.createRelativePositionFromTypeIndex(ytext, 9, 1, renderer) // pos after "hello wo"
const abs1 = Y.createAbsolutePositionFromRelativePosition(rel, ydoc, true, renderer)
const abs2 = Y.createAbsolutePositionFromRelativePosition(rel, ydoc, true)
t.assert(abs1?.index === 9)
t.assert(abs2?.index === 3)
@@ -39,16 +39,16 @@ export const testAttributedEvents = _tc => {
ydoc.transact(() => {
ytext.delete(6, 5)
})
const am = Y.createAttributionManagerFromDiff(v1, ydoc)
const c1 = ytext.toDelta(am)
const renderer = Y.createDiffRenderer(v1, ydoc)
const c1 = ytext.toDelta({ renderer })
t.compare(c1, delta.create().insert('hello ').insert('world', null, { delete: [] }).done())
let calledObserver = false
ytext.observe(event => {
const d = event.getDelta(am)
const d = event.getDelta({ renderer })
t.compare(d, delta.create().retain(11).insert('!', null, { insert: [] }).done())
calledObserver = true
})
ytext.applyDelta(delta.create().retain(11).insert('!').done(), am)
ytext.applyDelta(delta.create().retain(11).insert('!').done(), { renderer })
t.assert(calledObserver)
}
@@ -63,10 +63,10 @@ export const testInsertionsMindingAttributedContent = _tc => {
ydoc.transact(() => {
ytext.delete(6, 5)
})
const am = Y.createAttributionManagerFromDiff(v1, ydoc)
const c1 = ytext.toDelta(am)
const renderer = Y.createDiffRenderer(v1, ydoc)
const c1 = ytext.toDelta({ renderer })
t.compare(c1, delta.create().insert('hello ').insert('world', null, { delete: [] }).done())
ytext.applyDelta(delta.create().retain(11).insert('content').done(), am)
ytext.applyDelta(delta.create().retain(11).insert('content').done(), { renderer })
t.assert(ytext.toString() === 'hello content')
}
@@ -81,10 +81,10 @@ export const testInsertionsIntoAttributedContent = _tc => {
ydoc.transact(() => {
ytext.insert(6, 'word')
})
const am = Y.createAttributionManagerFromDiff(v1, ydoc)
const c1 = ytext.toDelta(am)
const renderer = Y.createDiffRenderer(v1, ydoc)
const c1 = ytext.toDelta({ renderer })
t.compare(c1, delta.create().insert('hello ').insert('word', null, { insert: [] }).done())
ytext.applyDelta(delta.create().retain(9).insert('l').done(), am)
ytext.applyDelta(delta.create().retain(9).insert('l').done(), { renderer })
t.assert(ytext.toString() === 'hello world')
}
@@ -151,21 +151,21 @@ export const testAttributionSession1 = tc => {
text0.insert(0, 'a')
text1.insert(0, 'b')
testConnector.flushAllMessages()
const d1 = text0.toDelta(Y.createAttributionManagerFromDiff(v1, users[0], { attrs: globalAttributions }))
const d1 = text0.toDelta({ renderer: Y.createDiffRenderer(v1, users[0], { attrs: globalAttributions }) })
t.compare(d1, delta.create().insert('a', null, { insert: ['0'] }).insert('b', null, { insert: ['1'] }).done())
const v2 = Y.cloneDoc(users[0])
text0.delete(1, 1)
text1.insert(2, 'c')
testConnector.flushAllMessages()
const d2 = text0.toDelta(Y.createAttributionManagerFromDiff(v2, users[0], { attrs: globalAttributions }))
const d2 = text0.toDelta({ renderer: Y.createDiffRenderer(v2, users[0], { attrs: globalAttributions }) })
t.compare(d2, delta.create().insert('a').insert('b', null, { delete: ['0'] }).insert('c', null, { insert: ['1'] }).done())
const onlyUser0ChangesAttributed = {
inserts: Y.filterIdMap(globalAttributions.inserts, attrs => attrs.some(attr => attr.name === 'insert' && attr.val === '0')),
deletes: Y.filterIdMap(globalAttributions.deletes, attrs => attrs.some(attr => attr.name === 'delete' && attr.val === '0'))
}
const amUser0 = new Y.TwosetAttributionManager(onlyUser0ChangesAttributed.inserts, onlyUser0ChangesAttributed.deletes)
const d3 = text0.toDelta(amUser0)
const rendererUser0 = new Y.TwosetRenderer(onlyUser0ChangesAttributed.inserts, onlyUser0ChangesAttributed.deletes)
const d3 = text0.toDelta({ renderer: rendererUser0 })
t.compare(d3, delta.create().insert('a', null, { insert: ['0'] }).insert('b', null, { delete: ['0'] }).insert('c').done())
Y.undoContentIds(users[0], Y.createContentIdsFromContentMap(onlyUser0ChangesAttributed))
@@ -179,10 +179,10 @@ export const testAttributionEvent = () => {
// <p>hi</p>
ytype.applyDelta(delta.create().insert([delta.create('p').insert('hi').done()]).done())
const ydocBase = Y.cloneDoc(ydoc)
const am = Y.createAttributionManagerFromDiff(ydocBase, ydoc)
const renderer = Y.createDiffRenderer(ydocBase, ydoc)
let called = false
ytype.observeDeep(event => {
const change = event.getDelta(am)
const change = event.getDelta({ renderer })
const expectedChange = delta.create().modify(delta.create('p').retain(2, null, { delete: [] }), null, { delete: [] }).done()
t.compare(
change,
@@ -201,12 +201,12 @@ export const testAttributionChange = () => {
const ytype = ydoc.get()
ytype.applyDelta(delta.create().insert('hi').done())
const ydocClone = Y.cloneDoc(ydoc)
const am = Y.createAttributionManagerFromDiff(ydocClone, ydoc)
const renderer = Y.createDiffRenderer(ydocClone, ydoc)
ytype.applyDelta(delta.create().retain(2).insert('!').done())
let calledHandler = false
am.on('change', changes => {
renderer.on('change', changes => {
calledHandler = true
const changeUpdate = ytype.toDelta(am, { deep: true, itemsToRender: changes, retainInserts: true, retainDeletes: true })
const changeUpdate = ytype.toDelta({ renderer, deep: true, itemsToRender: changes, retainInserts: true, retainDeletes: true })
const expectedUpdate = delta.create().retain(2).retain(1, null, {})
t.compare(changeUpdate, expectedUpdate)
console.log(changeUpdate.toJSON())

View File

@@ -168,14 +168,14 @@ export const testAttributions = _tc => {
const ytype = ydoc.get('txt')
// delete " world" and insert exclamation mark "!".
ytype.applyDelta(delta.create().retain(5).delete(6).insert('!').done())
const am = Y.createAttributionManagerFromDiff(ydocV1, ydoc)
const renderer = Y.createDiffRenderer(ydocV1, ydoc)
// get the attributed differences
const attributedContent = ytype.toDelta(am)
const attributedContent = ytype.toDelta({ renderer })
console.log('attributed content', attributedContent.toJSON())
t.assert(attributedContent.equals(delta.create().insert('hello').insert(' world', null, { delete: [] }).insert('!', null, { insert: [] }).done()))
// for editor bindings, it is also necessary to observe changes and get the attributed changes
ytype.observe(event => {
const attributedChange = event.getDelta(am)
const attributedChange = event.getDelta({ renderer })
console.log('the attributed change', attributedChange.toJSON())
t.assert(attributedChange.done().equals(delta.create().retain(11).insert('!', null, { insert: [] }).done()))
const unattributedChange = event.delta
@@ -191,7 +191,7 @@ export const testAttributions = _tc => {
* UNattributed: 'world!'
*/
// Apply a change to the attributed content
ytype.applyDelta(delta.create().retain(11).insert('!').done(), am)
ytype.applyDelta(delta.create().retain(11).insert('!').done(), { renderer })
// // Equivalent to applying a change to the UNattributed content:
// ytype.applyDelta(delta.create().retain(5).insert('!'))
}

View File

@@ -467,11 +467,11 @@ export const testAttributedContent = _tc => {
*/
const yarray = ydoc.get()
yarray.insert(0, [1, 2])
let attributionManager = Y.noAttributionsManager
let renderer = Y.baseRenderer
ydoc.on('afterTransaction', tr => {
// attributionManager = new TwosetAttributionManager(createIdMapFromIdSet(tr.insertSet, [new Y.Attribution('insertAt', 42), new Y.Attribution('insert', 'kevin')]), createIdMapFromIdSet(tr.deleteSet, [new Y.Attribution('delete', 'kevin')]))
attributionManager = new Y.TwosetAttributionManager(Y.createIdMapFromIdSet(tr.insertSet, []), Y.createIdMapFromIdSet(tr.deleteSet, []))
// renderer = new TwosetRenderer(createIdMapFromIdSet(tr.insertSet, [new Y.Attribution('insertAt', 42), new Y.Attribution('insert', 'kevin')]), createIdMapFromIdSet(tr.deleteSet, [new Y.Attribution('delete', 'kevin')]))
renderer = new Y.TwosetRenderer(Y.createIdMapFromIdSet(tr.insertSet, []), Y.createIdMapFromIdSet(tr.deleteSet, []))
})
t.group('insert / delete', () => {
ydoc.transact(() => {
@@ -479,7 +479,7 @@ export const testAttributedContent = _tc => {
yarray.insert(1, [42])
})
const expectedContent = delta.create().insert([1], null, { delete: [] }).insert([2]).insert([42], null, { insert: [] })
const attributedContent = yarray.toDelta(attributionManager)
const attributedContent = yarray.toDelta({ renderer })
console.log(attributedContent.toJSON())
t.assert(attributedContent.equals(expectedContent))
})

View File

@@ -1,6 +1,6 @@
import * as Y from '../src/index.js'
import { init, compare, applyRandomTests, Doc } from './testHelper.js' // eslint-disable-line
import { noAttributionsManager, TwosetAttributionManager } from '../src/utils/AttributionManager.js'
import { baseRenderer, TwosetRenderer } from '../src/utils/Renderer.js'
import { createIdMapFromIdSet } from '../src/utils/ids.js'
import * as t from 'lib0/testing'
import * as prng from 'lib0/prng'
@@ -550,35 +550,35 @@ export const testYmapEventHasCorrectValueWhenSettingAPrimitiveFromOtherUser = tc
export const testAttributedContent = _tc => {
const ydoc = new Y.Doc({ gc: false })
const ymap = ydoc.get()
let attributionManager = noAttributionsManager
let renderer = baseRenderer
ydoc.on('afterTransaction', tr => {
// attributionManager = new TwosetAttributionManager(createIdMapFromIdSet(tr.insertSet, [new Y.Attribution('insertAt', 42), new Y.Attribution('insert', 'kevin')]), createIdMapFromIdSet(tr.deleteSet, [new Y.Attribution('delete', 'kevin')]))
attributionManager = new TwosetAttributionManager(createIdMapFromIdSet(tr.insertSet, []), createIdMapFromIdSet(tr.deleteSet, []))
// renderer = new TwosetRenderer(createIdMapFromIdSet(tr.insertSet, [new Y.Attribution('insertAt', 42), new Y.Attribution('insert', 'kevin')]), createIdMapFromIdSet(tr.deleteSet, [new Y.Attribution('delete', 'kevin')]))
renderer = new TwosetRenderer(createIdMapFromIdSet(tr.insertSet, []), createIdMapFromIdSet(tr.deleteSet, []))
})
t.group('initial value', () => {
ymap.setAttr('test', 42)
const expectedContent = { test: delta.$deltaMapChangeJson.expect({ type: 'insert', value: 42, attribution: { insert: [] } }) }
const attributedContent = ymap.toDelta(attributionManager)
const attributedContent = ymap.toDelta({ renderer })
console.log(attributedContent.toJSON())
t.compare(expectedContent, attributedContent.toJSON().attrs)
})
t.group('overwrite value', () => {
ymap.setAttr('test', 'fourtytwo')
const expectedContent = { test: delta.$deltaMapChangeJson.expect({ type: 'insert', value: 'fourtytwo', attribution: { insert: [] } }) }
const attributedContent = ymap.toDelta(attributionManager)
const attributedContent = ymap.toDelta({ renderer })
console.log(attributedContent)
t.compare(expectedContent, attributedContent.toJSON().attrs)
})
t.group('delete value', () => {
ymap.deleteAttr('test')
// Snapshot-mode `toDelta(am)` (no `itemsToRender` opt) must not emit
// Snapshot-mode `toDelta(renderer)` (no `itemsToRender` opt) must not emit
// `DeleteAttrOp`. An attribute deleted under attribution is still
// observable in the rendered state with its prior value and a `delete`
// attribution marker - symmetric with how soft-deleted content children
// surface as `InsertOp` with `{ delete: [] }` rather than `DeleteOp`.
const expectedContent = { test: delta.$deltaMapChangeJson.expect({ type: 'insert', value: 'fourtytwo', attribution: { delete: [] } }) }
const attributedContent = ymap.toDelta(attributionManager)
const attributedContent = ymap.toDelta({ renderer })
console.log(attributedContent.toJSON())
t.compare(expectedContent, attributedContent.toJSON().attrs)
})

View File

@@ -4,7 +4,7 @@ import * as prng from 'lib0/prng'
import * as math from 'lib0/math'
import * as delta from 'lib0/delta'
import { createIdMapFromIdSet } from '../src/utils/ids.js'
import { noAttributionsManager, TwosetAttributionManager, createAttributionManagerFromSnapshots } from '../src/utils/AttributionManager.js'
import { baseRenderer, TwosetRenderer, createSnapshotRenderer } from '../src/utils/Renderer.js'
const { init, compare } = Y
@@ -1476,11 +1476,11 @@ export const testSnapshot = tc => {
.insert('x')
.delete(1)
)
const state1 = text0.toDelta(createAttributionManagerFromSnapshots(snapshot1))
const state1 = text0.toDelta({ renderer: createSnapshotRenderer(snapshot1) })
t.compare(state1, delta.create().insert('abcd').done())
const state2 = text0.toDelta(createAttributionManagerFromSnapshots(snapshot2))
const state2 = text0.toDelta({ renderer: createSnapshotRenderer(snapshot2) })
t.compare(state2, delta.create().insert('axcd').done())
const state2Diff = text0.toDelta(createAttributionManagerFromSnapshots(snapshot1, snapshot2))
const state2Diff = text0.toDelta({ renderer: createSnapshotRenderer(snapshot1, snapshot2) })
t.compare(
state2Diff,
delta.create()
@@ -1509,7 +1509,7 @@ export const testSnapshotDeleteAfter = tc => {
.insert('e')
.done()
)
const state1 = text0.toDelta(createAttributionManagerFromSnapshots(snapshot1))
const state1 = text0.toDelta({ renderer: createSnapshotRenderer(snapshot1) })
t.compare(state1, delta.create().insert('abcd').done())
}
@@ -1900,23 +1900,23 @@ export const testAttributedContent = _tc => {
const ydoc = new Y.Doc({ gc: false })
const ytext = ydoc.get()
ytext.insert(0, 'Hello World!')
let attributionManager = noAttributionsManager
let renderer = baseRenderer
ydoc.on('afterTransaction', tr => {
// attributionManager = new TwosetAttributionManager(createIdMapFromIdSet(tr.insertSet, [new Y.Attribution('insertAt', 42), new Y.Attribution('insert', 'kevin')]), createIdMapFromIdSet(tr.deleteSet, [new Y.Attribution('delete', 'kevin')]))
attributionManager = new TwosetAttributionManager(createIdMapFromIdSet(tr.insertSet, []), createIdMapFromIdSet(tr.deleteSet, []))
// renderer = new TwosetRenderer(createIdMapFromIdSet(tr.insertSet, [new Y.Attribution('insertAt', 42), new Y.Attribution('insert', 'kevin')]), createIdMapFromIdSet(tr.deleteSet, [new Y.Attribution('delete', 'kevin')]))
renderer = new TwosetRenderer(createIdMapFromIdSet(tr.insertSet, []), createIdMapFromIdSet(tr.deleteSet, []))
})
t.group('insert / delete / format', () => {
ytext.applyDelta(delta.create().retain(4, { italic: true }).retain(2).delete(5).insert('attributions').done())
const expectedContent = delta.create().insert('Hell', { italic: true }, { format: { italic: [] } }).insert('o ').insert('World', {}, { delete: [] }).insert('attributions', {}, { insert: [] }).insert('!')
const attributedContent = ytext.toDelta(attributionManager)
const attributedContent = ytext.toDelta({ renderer })
console.log(attributedContent.toJSON())
t.assert(attributedContent.equals(expectedContent))
})
t.group('unformat', () => {
ytext.applyDelta(delta.create().retain(5, { italic: null }))
const expectedContent = delta.create().insert('Hell', null, { format: { italic: [] } }).insert('o attributions!')
const attributedContent = ytext.toDelta(attributionManager)
const attributedContent = ytext.toDelta({ renderer })
console.log(attributedContent.toJSON())
t.assert(attributedContent.equals(expectedContent))
})
@@ -1944,10 +1944,10 @@ export const testAttributedDiffing = _tc => {
const attributedInsertions = createIdMapFromIdSet(insertionSetDiff, [Y.createContentAttribute('insert', 'Bob')])
const attributedDeletions = createIdMapFromIdSet(deleteSetDiff, [Y.createContentAttribute('delete', 'Bob')])
// now we can define an attribution manager that maps these changes to output. One of the
// implementations is the TwosetAttributionManager
const attributionManager = new TwosetAttributionManager(attributedInsertions, attributedDeletions)
// we render the attributed content with the attributionManager
const attributedContent = ytext.toDelta(attributionManager)
// implementations is the TwosetRenderer
const renderer = new TwosetRenderer(attributedInsertions, attributedDeletions)
// we render the attributed content with the renderer
const attributedContent = ytext.toDelta({ renderer })
console.log(JSON.stringify(attributedContent.toJSON(), null, 2))
const expectedContent = delta.create().insert('Hell', { italic: true }, { format: { italic: ['Bob'] } }).insert('o ').insert('World', {}, { delete: ['Bob'] }).insert('attributions', {}, { insert: ['Bob'] }).insert('!')
t.assert(attributedContent.equals(expectedContent))
@@ -2187,7 +2187,7 @@ const checkResult = result => {
*
* @param {t.TestCase} tc
*/
export const testAttributionManagerDefaultPerformance = tc => {
export const testRendererDefaultPerformance = tc => {
const N = 10000
const MaxDeletionLength = 5 // 25% chance of deletion
const MaxInsertionLength = 5
@@ -2212,7 +2212,7 @@ export const testAttributionManagerDefaultPerformance = tc => {
ytext.toString()
}
})
t.measureTime(`toDelta(attributionManager) performance <executed ${M} times>`, () => {
t.measureTime(`toDelta(renderer) performance <executed ${M} times>`, () => {
for (let i = 0; i < M; i++) {
ytext.toDelta()
}

View File

@@ -139,10 +139,10 @@ export const testFragmentAttributedContent = _tc => {
const elem3 = Y.Type.from(delta.create().insert('world'))
yfragment.insert(0, [elem1, elem2])
ydoc.get().insert(0, [yfragment])
let attributionManager = Y.noAttributionsManager
let renderer = Y.baseRenderer
ydoc.on('afterTransaction', tr => {
// attributionManager = new TwosetAttributionManager(createIdMapFromIdSet(tr.insertSet, [new Y.Attribution('insertAt', 42), new Y.Attribution('insert', 'kevin')]), createIdMapFromIdSet(tr.deleteSet, [new Y.Attribution('delete', 'kevin')]))
attributionManager = new Y.TwosetAttributionManager(Y.createIdMapFromIdSet(tr.insertSet, []), Y.createIdMapFromIdSet(tr.deleteSet, []))
// renderer = new TwosetRenderer(createIdMapFromIdSet(tr.insertSet, [new Y.Attribution('insertAt', 42), new Y.Attribution('insert', 'kevin')]), createIdMapFromIdSet(tr.deleteSet, [new Y.Attribution('delete', 'kevin')]))
renderer = new Y.TwosetRenderer(Y.createIdMapFromIdSet(tr.insertSet, []), Y.createIdMapFromIdSet(tr.deleteSet, []))
})
t.group('insert / delete', () => {
ydoc.transact(() => {
@@ -150,10 +150,10 @@ export const testFragmentAttributedContent = _tc => {
yfragment.insert(1, [elem3])
})
const expectedContent = delta.create().insert([elem1], null, { delete: [] }).insert([elem2]).insert([elem3], null, { insert: [] })
const attributedContent = yfragment.toDelta(attributionManager)
const attributedContent = yfragment.toDelta({ renderer })
console.log(attributedContent.toJSON())
t.assert(attributedContent.equals(expectedContent))
t.compare(elem1.toDelta(attributionManager).toJSON(), delta.create().insert('hello', null, { delete: [] }).toJSON())
t.compare(elem1.toDelta({ renderer }).toJSON(), delta.create().insert('hello', null, { delete: [] }).toJSON())
})
}
@@ -167,10 +167,10 @@ export const testElementAttributedContent = _tc => {
const elem2 = delta.create('span').done()
const elem3 = delta.create().insert('world').done()
yelement.insert(0, [elem1, elem2])
let attributionManager = Y.noAttributionsManager
let renderer = Y.baseRenderer
ydoc.on('afterTransaction', tr => {
// attributionManager = new TwosetAttributionManager(createIdMapFromIdSet(tr.insertSet, [new Y.Attribution('insertAt', 42), new Y.Attribution('insert', 'kevin')]), createIdMapFromIdSet(tr.deleteSet, [new Y.Attribution('delete', 'kevin')]))
attributionManager = new Y.TwosetAttributionManager(Y.createIdMapFromIdSet(tr.insertSet, []), Y.createIdMapFromIdSet(tr.deleteSet, []))
// renderer = new TwosetRenderer(createIdMapFromIdSet(tr.insertSet, [new Y.Attribution('insertAt', 42), new Y.Attribution('insert', 'kevin')]), createIdMapFromIdSet(tr.deleteSet, [new Y.Attribution('delete', 'kevin')]))
renderer = new Y.TwosetRenderer(Y.createIdMapFromIdSet(tr.insertSet, []), Y.createIdMapFromIdSet(tr.deleteSet, []))
})
t.group('insert / delete', () => {
ydoc.transact(() => {
@@ -183,7 +183,7 @@ export const testElementAttributedContent = _tc => {
.insert([elem2])
.insert([delta.create().insert('world', null, { insert: [] })], null, { insert: [] })
.setAttr('key', '42', { insert: [] })
const attributedContent = yelement.toDeltaDeep(attributionManager)
const attributedContent = yelement.toDeltaDeep({ renderer })
console.log('retrieved content', attributedContent.toJSON())
t.assert(attributedContent.equals(expectedContent))
t.compare(attributedContent.toJSON().attrs, { key: { type: 'insert', value: '42', attribution: { insert: [] } } })
@@ -206,9 +206,9 @@ export const testElementAttributedContentViaDiffer = _tc => {
yelement.insert(1, [elem3])
yelement.setAttr('key', '42')
})
const attributionManager = Y.createAttributionManagerFromDiff(ydocV1, ydoc)
const renderer = Y.createDiffRenderer(ydocV1, ydoc)
const expectedContent = delta.create().insert([delta.create().insert('hello')], null, { delete: [] }).insert([elem2.toDeltaDeep()]).insert([delta.create().insert('world', null, { insert: [] })], null, { insert: [] }).setAttr('key', '42', { insert: [] })
const attributedContent = yelement.toDeltaDeep(attributionManager)
const attributedContent = yelement.toDeltaDeep({ renderer })
console.log('children', attributedContent.toJSON().children)
console.log('attributes', attributedContent.toJSON().attrs)
t.compare(attributedContent.toJSON(), expectedContent.toJSON())
@@ -226,7 +226,7 @@ export const testElementAttributedContentViaDiffer = _tc => {
delta.create().insert('world', null, { insert: [] })
], null, { insert: [] })
.setAttr('key', '42', { insert: [] })
const attributedContent = yelement.toDeltaDeep(attributionManager)
const attributedContent = yelement.toDeltaDeep({ renderer })
console.log('children', JSON.stringify(attributedContent.toJSON().children, null, 2))
console.log('cs expec', JSON.stringify(expectedContent.toJSON(), null, 2))
console.log('attributes', attributedContent.toJSON().attrs)
@@ -238,7 +238,7 @@ export const testElementAttributedContentViaDiffer = _tc => {
elem3.insert(0, 'big')
})
t.group('test getContentDeep after some more updates', () => {
t.info('expecting diffingAttributionManager to auto update itself')
t.info('expecting DiffRenderer to auto update itself')
const expectedContent = delta.create()
.insert(
[delta.create().insert('hello')],
@@ -250,7 +250,7 @@ export const testElementAttributedContentViaDiffer = _tc => {
delta.create().insert('bigworld', null, { insert: [] })
], null, { insert: [] })
.setAttr('key', '42', { insert: [] })
const attributedContent = yelement.toDeltaDeep(attributionManager)
const attributedContent = yelement.toDeltaDeep({ renderer })
console.log('children', JSON.stringify(attributedContent.toJSON().children, null, 2))
console.log('cs expec', JSON.stringify(expectedContent.toJSON(), null, 2))
console.log('attributes', attributedContent.toJSON().attrs)
@@ -260,11 +260,11 @@ export const testElementAttributedContentViaDiffer = _tc => {
})
Y.applyUpdate(ydocV1, Y.encodeStateAsUpdate(ydoc))
t.group('test getContentDeep both docs synced', () => {
t.info('expecting diffingAttributionManager to auto update itself')
t.info('expecting DiffRenderer to auto update itself')
const expectedContent = delta.create().insert([delta.create('span')]).insert([
delta.create().insert('bigworld')
]).setAttr('key', '42')
const attributedContent = yelement.toDeltaDeep(attributionManager)
const attributedContent = yelement.toDeltaDeep({ renderer })
console.log('children', JSON.stringify(attributedContent.toJSON().children, null, 2))
console.log('cs expec', JSON.stringify(expectedContent.toJSON(), null, 2))
console.log('attributes', attributedContent.toJSON().attrs)
@@ -277,7 +277,7 @@ export const testElementAttributedContentViaDiffer = _tc => {
/**
* @param {t.TestCase} _tc
*/
export const testAttributionManagerSimpleExample = _tc => {
export const testRendererSimpleExample = _tc => {
const ydoc = new Y.Doc()
ydoc.clientID = 0
// create some initial content
@@ -295,7 +295,7 @@ export const testAttributionManagerSimpleExample = _tc => {
ytext.delete(11, 8)
ytext.insert(11, '!')
// highlight the changes
console.log(JSON.stringify(ydocFork.get().toDeltaDeep(Y.createAttributionManagerFromDiff(ydoc, ydocFork)), null, 2))
console.log(JSON.stringify(ydocFork.get().toDeltaDeep({ renderer: Y.createDiffRenderer(ydoc, ydocFork) }), null, 2))
/* =>
{
"children": {
@@ -390,7 +390,7 @@ const collectForbiddenOps = (d, forbidden, path = '$', acc = []) => {
/**
* Reproduces the y-prosemirror issue #247 contract violation at the @y/y
* level: `ytype.toDeltaDeep(am)` is supposed to surface soft-deleted content
* level: `ytype.toDeltaDeep({ renderer })` is supposed to surface soft-deleted content
* as positive ops (`SetAttrOp` / `InsertOp`) carrying attribution metadata,
* never as `DeleteAttrOp` / `DeleteOp`. Today, when a parent YXmlElement is
* itself soft-deleted under attribution, `typeMapGetDelta` (ytype.js:1928)
@@ -398,7 +398,7 @@ const collectForbiddenOps = (d, forbidden, path = '$', acc = []) => {
* cascaded child setAttr / content items - which downstream consumers
* (lib0/delta `diff`, y-prosemirror's PM mapper) cannot handle.
*
* Expected after fix: walking the delta returned by `parent.toDeltaDeep(am)`
* Expected after fix: walking the delta returned by `parent.toDeltaDeep({ renderer })`
* finds zero `DeleteAttrOp` entries in any `attrs` map and zero `DeleteOp`
* entries in any `children` list, at every nesting level.
*
@@ -424,8 +424,8 @@ export const testToDeltaDeepEmitsNoDeleteOpsForSoftDeletedParent = _tc => {
parent.delete(0, 1)
})
const am = Y.createAttributionManagerFromDiff(ydocV1, ydoc)
const rendered = parent.toDeltaDeep(am)
const renderer = Y.createDiffRenderer(ydocV1, ydoc)
const rendered = parent.toDeltaDeep({ renderer })
// The cascade should surface as positive ops with attribution, not as
// delete ops. Find any DeleteAttrOp / DeleteOp anywhere in the tree.
@@ -439,7 +439,7 @@ export const testToDeltaDeepEmitsNoDeleteOpsForSoftDeletedParent = _tc => {
}
t.assert(
offenders.length === 0,
`toDeltaDeep(am) emitted ${offenders.length} forbidden delete op(s) for a soft-deleted parent (issue #247 / y-prosemirror)`
`toDeltaDeep(renderer) emitted ${offenders.length} forbidden delete op(s) for a soft-deleted parent (issue #247 / y-prosemirror)`
)
}
@@ -460,8 +460,8 @@ export const testToDeltaDeepRendersExplicitDeleteAttrAsSetAttrWithAttribution =
ydoc.transact(() => {
ydoc.get('p').deleteAttr('id')
})
const am = Y.createAttributionManagerFromDiff(ydocV1, ydoc)
const rendered = ydoc.get('p').toDeltaDeep(am)
const renderer = Y.createDiffRenderer(ydocV1, ydoc)
const rendered = ydoc.get('p').toDeltaDeep({ renderer })
const offenders = collectForbiddenOps(rendered, ['DeleteAttrOp', 'DeleteOp'])
t.assert(offenders.length === 0, 'no DeleteAttrOp / DeleteOp from explicit deleteAttr under diff AM')