From 2c0daeb0711042cc8f41f8c7010025516acff933 Mon Sep 17 00:00:00 2001 From: Kevin Jahns Date: Tue, 21 Nov 2023 12:24:21 +0100 Subject: [PATCH] implement snapshot API for yxml.getAttributes. implements #543 --- src/index.js | 1 + src/types/AbstractType.js | 28 ++++++++++++++++++++++++++++ src/types/YXmlElement.js | 8 +++++--- tests/snapshot.tests.js | 15 +++++++++++++++ 4 files changed, 49 insertions(+), 3 deletions(-) diff --git a/src/index.js b/src/index.js index be7ca25e..ae96b747 100644 --- a/src/index.js +++ b/src/index.js @@ -52,6 +52,7 @@ export { getItem, typeListToArraySnapshot, typeMapGetSnapshot, + typeMapGetAllSnapshot, createDocFromSnapshot, iterateDeletedStructs, applyUpdate, diff --git a/src/types/AbstractType.js b/src/types/AbstractType.js index 3163b8da..8aef5dc4 100644 --- a/src/types/AbstractType.js +++ b/src/types/AbstractType.js @@ -925,6 +925,34 @@ export const typeMapGetSnapshot = (parent, key, snapshot) => { return v !== null && isVisible(v, snapshot) ? v.content.getContent()[v.length - 1] : undefined } +/** + * @param {AbstractType} parent + * @param {Snapshot} snapshot + * @return {Object|number|null|Array|string|Uint8Array|AbstractType|undefined>} + * + * @private + * @function + */ +export const typeMapGetAllSnapshot = (parent, snapshot) => { + /** + * @type {Object} + */ + const res = {} + parent._map.forEach((value, key) => { + /** + * @type {Item|null} + */ + let v = value + while (v !== null && (!snapshot.sv.has(v.id.client) || v.id.clock >= (snapshot.sv.get(v.id.client) || 0))) { + v = v.left + } + if (v !== null && isVisible(v, snapshot)) { + res[key] = v.content.getContent()[v.length - 1] + } + }) + return res +} + /** * @param {Map} map * @return {IterableIterator>} diff --git a/src/types/YXmlElement.js b/src/types/YXmlElement.js index 92088cdd..7b18be69 100644 --- a/src/types/YXmlElement.js +++ b/src/types/YXmlElement.js @@ -8,9 +8,10 @@ import { typeMapSet, typeMapGet, typeMapGetAll, + typeMapGetAllSnapshot, typeListForEach, YXmlElementRefID, - YXmlText, ContentType, AbstractType, UpdateDecoderV1, UpdateDecoderV2, UpdateEncoderV1, UpdateEncoderV2, Doc, Item // eslint-disable-line + Snapshot, YXmlText, ContentType, AbstractType, UpdateDecoderV1, UpdateDecoderV2, UpdateEncoderV1, UpdateEncoderV2, Doc, Item // eslint-disable-line } from '../internals.js' /** @@ -192,12 +193,13 @@ export class YXmlElement extends YXmlFragment { /** * Returns all attribute name/value pairs in a JSON Object. * + * @param {Snapshot} [snapshot] * @return {{ [Key in Extract]?: KV[Key]}} A JSON Object that describes the attributes. * * @public */ - getAttributes () { - return /** @type {any} */ (typeMapGetAll(this)) + getAttributes (snapshot) { + return /** @type {any} */ (snapshot ? typeMapGetAllSnapshot(this, snapshot) : typeMapGetAll(this)) } /** diff --git a/tests/snapshot.tests.js b/tests/snapshot.tests.js index d72e7ba7..4f3ecd47 100644 --- a/tests/snapshot.tests.js +++ b/tests/snapshot.tests.js @@ -14,6 +14,21 @@ export const testBasic = _tc => { t.assert(restored.getText().toString() === 'world!') } +/** + * @param {t.TestCase} _tc + */ +export const testBasicXmlAttributes = _tc => { + const ydoc = new Y.Doc({ gc: false }) + const yxml = ydoc.getMap().set('el', new Y.XmlElement('div')) + const snapshot1 = Y.snapshot(ydoc) + yxml.setAttribute('a', '1') + const snapshot2 = Y.snapshot(ydoc) + yxml.setAttribute('a', '2') + t.compare(yxml.getAttributes(), { a: '2' }) + t.compare(yxml.getAttributes(snapshot2), { a: '1' }) + t.compare(yxml.getAttributes(snapshot1), {}) +} + /** * @param {t.TestCase} _tc */