add test case for custom AttributionsRenderer usecase

This commit is contained in:
Kevin Jahns
2026-07-15 16:18:07 +02:00
parent 486d5677d9
commit ca98fead1f
3 changed files with 39 additions and 4 deletions

View File

@@ -43,9 +43,13 @@ export const createContentIdsFromContentMap = contentMap => createContentIds(
/** /**
* @param {import('./Doc.js').Doc} ydoc * @param {import('./Doc.js').Doc} ydoc
* @param {boolean} insertsContainDeletes - whether the returned `inserts` set includes content that
* the doc has already deleted. `true` yields a full structural snapshot (every inserted id);
* `false` yields only the doc's currently-visible content (`inserts deletes`), which is what you
* want when the snapshot defines what should render.
*/ */
export const createContentIdsFromDoc = ydoc => createContentIds( export const createContentIdsFromDoc = (ydoc, insertsContainDeletes) => createContentIds(
createInsertSetFromStructStore(ydoc.store, false), createInsertSetFromStructStore(ydoc.store, !insertsContainDeletes),
createDeleteSetFromStructStore(ydoc.store) createDeleteSetFromStructStore(ydoc.store)
) )
@@ -54,7 +58,7 @@ export const createContentIdsFromDoc = ydoc => createContentIds(
* @param {import('./Doc.js').Doc} ydocNext * @param {import('./Doc.js').Doc} ydocNext
*/ */
export const createContentIdsFromDocDiff = (ydocPrev, ydocNext) => export const createContentIdsFromDocDiff = (ydocPrev, ydocNext) =>
excludeContentIds(createContentIdsFromDoc(ydocPrev), createContentIdsFromDoc(ydocNext)) excludeContentIds(createContentIdsFromDoc(ydocPrev, true), createContentIdsFromDoc(ydocNext, true))
/** /**
* @param {ContentIds} content * @param {ContentIds} content

View File

@@ -2170,3 +2170,34 @@ export const testRdtBaseFormatClearInsideSuggestionDeletedParagraphCacheDrift =
} }
t.assert(cached.equals(fresh), 'maintained .delta must equal a fresh deep render after a base format clear inside a suggestion-deleted paragraph') t.assert(cached.equals(fresh), 'maintained .delta must equal a fresh deep render after a base format clear inside a suggestion-deleted paragraph')
} }
/**
*
*
* @param {t.TestCase} _tc
*/
export const testAttributionRendererActiveChangesInDiff = _tc => {
const ydoc = new Y.Doc({ gc: false })
const ytext = ydoc.get()
ytext.insert(0, 'hella')
const state1 = Y.createContentIdsFromDoc(ydoc, true)
ytext.applyDelta(delta.create().retain(4).delete(1).insert('o!').done())
const state2 = Y.createContentIdsFromDoc(ydoc, true)
ytext.applyDelta(delta.create().retain(5).delete(1).insert(' world').done())
// state3 captures the *visible* content (`insertsContainDeletes: false` → inserts already exclude
// deletes). Using it both as the intersection target and as `renderedContent` means: a change that
// was inserted-then-deleted by state3 (the '!' at clock 6) is no longer an active insert and drops
// out, and state3's deletions (the 'a' at clock 4) aren't "restored" so they keep their delete
// attribution instead of re-rendering as inserts.
const state3 = Y.createContentIdsFromDoc(ydoc, false)
ytext.applyDelta(delta.create().delete(11).insert('42').done())
// render the active changes that happened between state 1 and 2 within state 3.
const attrs = Y.createContentMapFromContentIds(Y.intersectContentIds(Y.excludeContentIds(state2, state1), state3), [], [])
const renderer = Y.createAttributionsRenderer(attrs, { renderedContent: state3.inserts })
const attrDelta = ytext.toDelta({ renderer })
console.log(attrDelta.toJSON())
t.compare(attrDelta, delta.create().insert('hell').insert('a', null, { delete: [] }).insert('o', null, { insert: [] }).insert(' world').done())
}

View File

@@ -396,7 +396,7 @@ export const testObfuscateUpdates = _tc => {
export const testIntersectDoc = () => { export const testIntersectDoc = () => {
const ydoc = new Y.Doc() const ydoc = new Y.Doc()
ydoc.get().setAttr('k', 1) ydoc.get().setAttr('k', 1)
const c1 = Y.createContentIdsFromDoc(ydoc) const c1 = Y.createContentIdsFromDoc(ydoc, true)
ydoc.get().setAttr('k', 2) ydoc.get().setAttr('k', 2)
const v1 = Y.intersectUpdateWithContentIds(Y.encodeStateAsUpdate(ydoc), c1) const v1 = Y.intersectUpdateWithContentIds(Y.encodeStateAsUpdate(ydoc), c1)