From 6671071213fe1d27c4a0b343c262f2981fe9355a Mon Sep 17 00:00:00 2001 From: Kevin Jahns Date: Mon, 21 Apr 2025 02:00:14 +0200 Subject: [PATCH] first test case for attributions --- src/utils/Delta.js | 41 +++++++++++++++++++++++++++++++++++++++++ src/utils/IdMap.js | 26 ++++++++++++++++++++++++++ tests/y-text.tests.js | 19 +++++++++++++++++++ 3 files changed, 86 insertions(+) diff --git a/src/utils/Delta.js b/src/utils/Delta.js index c1c5b525..175b047c 100644 --- a/src/utils/Delta.js +++ b/src/utils/Delta.js @@ -1,4 +1,5 @@ import * as object from 'lib0/object' +import * as fun from 'lib0/function' /** * @typedef {InsertOp|RetainOp|DeleteOp} DeltaOp @@ -71,6 +72,46 @@ export class Delta { this.ops = [] } + /** + * @param {Delta} d + * @return {boolean} + */ + equals (d) { + return this.ops.length === d.ops.length && this.ops.every((op, i) => { + const dop = d.ops[i] + if (op.constructor !== dop.constructor) return false + switch (op.constructor) { + case DeleteOp: { + if (/** @type {DeleteOp} */ (op).delete !== /** @type {DeleteOp} */ (dop).delete) { + return false + } + break + } + case InsertOp: { + if ( + !fun.equalityDeep(/** @type {InsertOp} */ (op).insert, /** @type {InsertOp} */ (dop).insert) + || !fun.equalityDeep(/** @type {InsertOp} */ (op).attributes, /** @type {InsertOp} */ (dop).attributes) + || !fun.equalityDeep(/** @type {InsertOp} */ (op).attribution, /** @type {InsertOp} */ (dop).attribution) + ) { + return false + } + break + } + case RetainOp: { + if ( + /** @type {RetainOp} */ (op).retain !== /** @type {RetainOp} */ (dop).retain + || !fun.equalityDeep(/** @type {RetainOp} */ (op).attributes, /** @type {RetainOp} */ (dop).attributes) + || !fun.equalityDeep(/** @type {RetainOp} */ (op).attribution, /** @type {RetainOp} */ (dop).attribution) + ) { + return false + } + break + } + } + return true + }) + } + toJSON () { return { ops: this.ops.map(o => o.toJSON()) } } diff --git a/src/utils/IdMap.js b/src/utils/IdMap.js index 522fb81a..820f3fa1 100644 --- a/src/utils/IdMap.js +++ b/src/utils/IdMap.js @@ -267,6 +267,32 @@ export const mergeIdMaps = ams => { return merged } +/** + * @param {IdSet} idset + * @param {Array>} attrs + */ +export const createIdMapFromIdSet = (idset, attrs) => { + const idmap = createIdMap() + // map attrs to idmap + attrs = _ensureAttrs(idmap, attrs) + // filter out duplicates + /** + * @type {Array>} + */ + const checkedAttrs = [] + attrs.forEach(attr => { + if (!idmapAttrsHas(checkedAttrs, attr)) { + checkedAttrs.push(attr) + } + }) + idset.clients.forEach((ranges, client) => { + const attrRanges = new AttrRanges(ranges.getIds().map(range => new AttrRange(range.clock, range.len, checkedAttrs))) + attrRanges.sorted = true // is sorted because idset is sorted + idmap.clients.set(client, attrRanges) + }) + return idmap +} + /** * @template Attrs */ diff --git a/tests/y-text.tests.js b/tests/y-text.tests.js index 4b9c6d2e..37c47799 100644 --- a/tests/y-text.tests.js +++ b/tests/y-text.tests.js @@ -2,6 +2,8 @@ import * as Y from './testHelper.js' import * as t from 'lib0/testing' import * as prng from 'lib0/prng' import * as math from 'lib0/math' +import * as delta from '../src/utils/Delta.js' +import { createIdMapFromIdSet, noAttributionsManager, TwosetAttributionManager } from 'yjs/internals' const { init, compare } = Y @@ -2299,6 +2301,23 @@ export const testDeleteFormatting = _tc => { t.compare(text2.toDelta(), expected) } +/** + * @param {t.TestCase} tc + */ +export const testAttributedContent = tc => { + const ydoc = new Y.Doc() + const ytext = ydoc.getText() + ytext.insert(0, 'Hello World!') + let am = noAttributionsManager + ydoc.on('afterTransaction', tr => { + am = new TwosetAttributionManager(createIdMapFromIdSet(tr.insertSet, []), createIdMapFromIdSet(tr.deleteSet, [])) + }) + ytext.applyDelta([{ retain: 6 }, { delete: 5 }, { insert: 'attributions' }]) + const attributedContent = ytext.getContent(am) + t.assert(attributedContent.equals(delta.create().retain(6).insert('World', {}, { type: 'delete' }).insert('attributions', {}, { type: 'insert' }))) + debugger +} + // RANDOM TESTS let charCounter = 0