diff --git a/src/types/AbstractType.js b/src/types/AbstractType.js index bce269c6..36c9b4a0 100644 --- a/src/types/AbstractType.js +++ b/src/types/AbstractType.js @@ -233,7 +233,7 @@ export const updateMarkerChanges = (searchMarker, index, len) => { /** * Accumulate all (list) children of a type and return them as an Array. * - * @param {AbstractType} t + * @param {import('../utils/types.js').YType} t * @return {Array} */ export const getTypeChildren = t => { @@ -272,7 +272,7 @@ export const callTypeObservers = (type, transaction, event) => { /** * Abstract Yjs Type class * @template {delta.Delta} [EventDelta=delta.Delta] - * @template {YType_} [Self=any] + * @template {AbstractType} [Self=any] */ export class AbstractType { constructor () { @@ -442,18 +442,19 @@ export class AbstractType { * @param {import('../utils/IdSet.js').IdSet?} [opts.itemsToRender] * @param {boolean} [opts.retainInserts] - if true, retain rendered inserts with attributions * @param {boolean} [opts.retainDeletes] - if true, retain rendered+attributed deletes only - * @param {Set?} [opts.renderAttrs] - if true, retain rendered+attributed deletes only + * @param {Set?} [opts.renderAttrs] - set of attrs to render. if null, render all attributes * @param {boolean} [opts.renderChildren] - if true, retain rendered+attributed deletes only + * @param {import('../utils/IdSet.js').IdSet?} [opts.deletedItems] - used for computing prevItem in attributes * @return {EventDelta} The Delta representation of this type. * * @public */ - getContent (am = noAttributionsManager, { itemsToRender = null, retainInserts = false, retainDeletes = false, renderAttrs = null, renderChildren = true } = {}) { + getContent (am = noAttributionsManager, { itemsToRender = null, retainInserts = false, retainDeletes = false, renderAttrs = null, renderChildren = true, deletedItems = null } = {}) { /** * @type {EventDelta} */ const d = /** @type {any} */ (delta.create()) - typeMapGetDelta(d, /** @type {any} */ (this), renderAttrs, am) + typeMapGetDelta(d, /** @type {any} */ (this), renderAttrs, am, deletedItems, itemsToRender) if (renderChildren) { /** * @type {delta.FormattingAttributes} @@ -625,7 +626,7 @@ export class AbstractType { * @type {import('../utils/AttributionManager.js').Attribution} */ const formattingAttribution = object.assign({}, d.usedAttribution) - const changedAttributedAttributes = /** @type {{ [key: string]: Array }} */ (formattingAttribution.attributes = object.assign({}, formattingAttribution.attributes ?? {})) + const changedAttributedAttributes = /** @type {{ [key: string]: Array }} */ (formattingAttribution.format = object.assign({}, formattingAttribution.format ?? {})) if (attribution == null || equalAttrs(previousUnattributedAttributes[key], currentAttributes[key] ?? null)) { // an unattributed formatting attribute was found or an attributed formatting // attribute was found that resets to the previous status @@ -635,13 +636,13 @@ export class AbstractType { const by = changedAttributedAttributes[key] = (changedAttributedAttributes[key]?.slice() ?? []) by.push(...((c.deleted ? attribution.delete : attribution.insert) ?? [])) const attributedAt = (c.deleted ? attribution.deletedAt : attribution.insertedAt) - if (attributedAt) formattingAttribution.attributedAt = attributedAt + if (attributedAt) formattingAttribution.formatAt = attributedAt } if (object.isEmpty(changedAttributedAttributes)) { d.useAttribution(null) } else if (attribution != null) { const attributedAt = (c.deleted ? attribution.deletedAt : attribution.insertedAt) - if (attributedAt != null) formattingAttribution.attributedAt = attributedAt + if (attributedAt != null) formattingAttribution.formatAt = attributedAt d.useAttribution(formattingAttribution) } } @@ -651,7 +652,7 @@ export class AbstractType { } } } - return d + return /** @type {any} */ (d.done()) } /** @@ -678,7 +679,7 @@ export class AbstractType { op.value = op.value.getContentDeep(am) } }) - return /** @type {any} */ (d) + return /** @type {any} */ (d.done()) } } @@ -768,47 +769,6 @@ export const typeListToArray = type => { return cs } -/** - * @todo this can be removed as this can be replaced by a generic function - * Render the difference to another ydoc (which can be empty) and highlight the differences with - * attributions. - * - * Note that deleted content that was not deleted in prevYdoc is rendered as an insertion with the - * attribution `{ isDeleted: true, .. }`. - * - * @template {delta.Delta} TypeDelta - * @param {TypeDelta} d - * @param {import('../utils/types.js').YType} type - * @param {import('../internals.js').AbstractAttributionManager} am - * - * @private - * @function - */ -export const typeListGetContent = (d, type, am) => { - type.doc ?? warnPrematureAccess() - /** - * @type {Array>} - */ - const cs = [] - for (let item = type._start; item !== null; cs.length = 0) { - // populate cs - for (; item !== null && cs.length < 50; item = item.right) { - am.readContent(cs, item.id.client, item.id.clock, item.deleted, item.content, 1) - } - for (let i = 0; i < cs.length; i++) { - const c = cs[i] - const attribution = createAttributionFromAttributionItems(c.attrs, c.deleted) - if (c.content.isCountable()) { - if (c.render || attribution != null) { - d.insert(c.content.getContent(), null, attribution) - } else if (!c.deleted) { - d.retain(c.content.getLength()) - } - } - } - } -} - /** * @param {AbstractType} type * @param {Snapshot} snapshot @@ -1270,13 +1230,13 @@ export const typeMapGetAll = (parent) => { * @param {YType_} parent * @param {Set?} attrsToRender * @param {import('../internals.js').AbstractAttributionManager} am + * @param {import('../utils/IdSet.js').IdSet?} [deletedItems] + * @param {import('../utils/IdSet.js').IdSet?} [itemsToRender] * * @private * @function */ -export const typeMapGetDelta = (d, parent, attrsToRender, am) => { - parent.doc ?? warnPrematureAccess() - +export const typeMapGetDelta = (d, parent, attrsToRender, am, deletedItems, itemsToRender) => { /** * @param {Item} item * @param {string} key @@ -1291,28 +1251,17 @@ export const typeMapGetDelta = (d, parent, attrsToRender, am) => { const c = array.last(content.getContent()) const attribution = createAttributionFromAttributionItems(attrs, deleted) if (deleted) { - d.unset(key, attribution, c) - } else { - /** - * @type {Array>} - */ - let cs = [] - for (let prevItem = item.left; prevItem != null; prevItem = prevItem.left) { - /** - * @type {Array>} - */ - const tmpcs = [] - am.readContent(tmpcs, prevItem.id.client, prevItem.id.clock, prevItem.deleted, prevItem.content, 1) - cs = tmpcs.concat(cs) - if (cs.length === 0 || cs[0].attrs == null) { - cs.splice(0, cs.findIndex(c => c.attrs != null)) - break - } - if (cs.length > 0) { - cs.length = 1 - } + if (itemsToRender == null || itemsToRender.hasId(item.lastId)) { + d.unset(key, attribution, c) } - const prevValue = cs.length > 0 ? array.last(cs[0].content.getContent()) : undefined + } else { + // find prev content + let prevContentItem = item + // this algorithm is problematic. should check all previous content using am.readcontent + for (; prevContentItem.left !== null && deletedItems?.hasId(prevContentItem.left.lastId); prevContentItem = prevContentItem.left) { + // nop + } + const prevValue = (prevContentItem !== item && itemsToRender?.hasId(prevContentItem.lastId)) ? array.last(prevContentItem.content.getContent()) : undefined d.set(key, c, attribution, prevValue) } } diff --git a/src/types/YArray.js b/src/types/YArray.js index 23642c3b..af4e7b7b 100644 --- a/src/types/YArray.js +++ b/src/types/YArray.js @@ -17,7 +17,6 @@ import { callTypeObservers, transact, warnPrematureAccess, - typeListGetContent, typeListSlice, noAttributionsManager, AbstractAttributionManager, ArraySearchMarker, UpdateDecoderV1, UpdateDecoderV2, UpdateEncoderV1, UpdateEncoderV2, Doc, Transaction, Item // eslint-disable-line @@ -108,7 +107,7 @@ export class YArray extends AbstractType { */ _callObserver (transaction, parentSubs) { super._callObserver(transaction, parentSubs) - callTypeObservers(this, transaction, new YEvent(this, transaction, null)) + callTypeObservers(this, transaction, new YEvent(this, transaction, parentSubs)) } /** @@ -214,24 +213,6 @@ export class YArray extends AbstractType { return super.getContentDeep(am) } - /** - * Render the difference to another ydoc (which can be empty) and highlight the differences with - * attributions. - * - * Note that deleted content that was not deleted in prevYdoc is rendered as an insertion with the - * attribution `{ isDeleted: true, .. }`. - * - * @param {AbstractAttributionManager} am - * @return {delta.ArrayDelta} The Delta representation of this type. - * - * @public - */ - getContent (am = noAttributionsManager) { - const d = this.change - typeListGetContent(d, this, am) - return d - } - /** * Returns a portion of this YArray into a JavaScript Array selected * from start to end (end not included). diff --git a/src/types/YText.js b/src/types/YText.js index 19fd305d..bb7fcbf3 100644 --- a/src/types/YText.js +++ b/src/types/YText.js @@ -758,9 +758,11 @@ export class YText extends AbstractType { transact(this.doc, transaction => { const currPos = new ItemTextListPosition(null, this._start, 0, new Map(), am) for (const op of d.children) { - if (delta.$insertOp.check(op)) { - if (op.insert.length > 0 || typeof op.insert !== 'string') { - insertText(transaction, this, currPos, op.insert, op.format || {}) + if (delta.$textOp.check(op)) { + insertText(transaction, this, currPos, op.insert, op.format || {}) + } else if (delta.$insertOp.check(op)) { + for (let i = 0; i < op.insert.length; i++) { + insertText(transaction, this, currPos, op.insert[i], op.format || {}) } } else if (delta.$retainOp.check(op)) { currPos.formatText(transaction, this, op.retain, op.format || {}) diff --git a/src/utils/AttributionManager.js b/src/utils/AttributionManager.js index 745bc841..3bfb4278 100644 --- a/src/utils/AttributionManager.js +++ b/src/utils/AttributionManager.js @@ -38,8 +38,8 @@ export const attributionJsonSchema = s.$object({ insertedAt: s.$number.optional, delete: s.$array(s.$string).optional, deletedAt: s.$number.optional, - attributes: s.$record(s.$string, s.$array(s.$string)).optional, - attributedAt: s.$number.optional + format: s.$record(s.$string, s.$array(s.$string)).optional, + formatAt: s.$number.optional }) /** diff --git a/src/utils/YEvent.js b/src/utils/YEvent.js index 082944dd..181d4cfd 100644 --- a/src/utils/YEvent.js +++ b/src/utils/YEvent.js @@ -41,10 +41,6 @@ export class YEvent { * @type {Transaction} */ this.transaction = transaction - /** - * @type {Object|null} - */ - this._changes = null /** * @type {null | Map} */ @@ -183,7 +179,7 @@ export class YEvent { */ getDelta (am = noAttributionsManager) { const itemsToRender = mergeIdSets([diffIdSet(this.transaction.insertSet, this.transaction.deleteSet), diffIdSet(this.transaction.deleteSet, this.transaction.insertSet)]) - return /** @type {any} */ (this.target.getContent(am, { itemsToRender, retainDeletes: true, renderAttrs: this.keysChanged, renderChildren: this.childListChanged })) + return /** @type {any} */ (this.target.getContent(am, { itemsToRender, retainDeletes: true, renderAttrs: this.keysChanged, renderChildren: this.childListChanged, deletedItems: this.transaction.deleteSet })) } /** diff --git a/src/utils/types.js b/src/utils/types.js index a0414078..f18a546a 100644 --- a/src/utils/types.js +++ b/src/utils/types.js @@ -1,15 +1,4 @@ -/** - * @typedef {Object|Array|number|null|string|Uint8Array|BigInt - * |import('../index.js').Array - * |import('../index.js').Map - * |import('../index.js').Text - * |import('../index.js').XmlElement - * |import('../index.js').XmlFragment - * |import('../index.js').XmlText - * |import('../index.js').XmlHook} YValue - */ - /** * @typedef {import('../types/YArray.js').YArray * | import('../types/YMap.js').YMap @@ -17,15 +6,17 @@ * | import('../types/YXmlFragment.js').YXmlFragment * | import('../types/YXmlElement.js').YXmlElement * | import('../types/YXmlHook.js').YXmlHook - * | import('../types/YXmlText.js').YXmlText} YType + * | import('../types/YXmlText.js').YXmlText} YValueType */ /** - * @typedef {typeof import('../types/YArray.js').YArray - * | typeof import('../types/YMap.js').YMap - * | typeof import('../types/YText.js').YText - * | typeof import('../types/YXmlFragment.js').YXmlFragment - * | typeof import('../types/YXmlElement.js').YXmlElement - * | typeof import('../types/YXmlHook.js').YXmlHook - * | typeof import('../types/YXmlText.js').YXmlText} YTypeConstructors + * @typedef {Object|Array|number|null|string|Uint8Array|BigInt|YValueType} YValue + */ + +/** + * @typedef {import('../types/AbstractType.js').AbstractType} YType + */ + +/** + * @typedef {typeof import('../types/AbstractType.js').AbstractType} YTypeConstructors */ diff --git a/test.html b/test.html index 282340e9..c1dc0dfa 100644 --- a/test.html +++ b/test.html @@ -35,6 +35,7 @@ "lib0/conditions": "./node_modules/lib0/conditions.js", "lib0/crypto/jwt": "./node_modules/lib0/crypto/jwt.js", "lib0/crypto/aes-gcm": "./node_modules/lib0/crypto/aes-gcm.js", + "lib0/delta": "./node_modules/lib0/delta/d2.js", "lib0/crypto/ecdsa": "./node_modules/lib0/crypto/ecdsa.js", "lib0/crypto/rsa-oaep": "./node_modules/lib0/crypto/rsa-oaep.js", "lib0/hash/rabin": "./node_modules/lib0/hash/rabin.js", @@ -201,6 +202,7 @@ "lib0/conditions": "./node_modules/lib0/conditions.js", "lib0/crypto/jwt": "./node_modules/lib0/crypto/jwt.js", "lib0/crypto/aes-gcm": "./node_modules/lib0/crypto/aes-gcm.js", + "lib0/delta": "./node_modules/lib0/delta/d2.js", "lib0/crypto/ecdsa": "./node_modules/lib0/crypto/ecdsa.js", "lib0/crypto/rsa-oaep": "./node_modules/lib0/crypto/rsa-oaep.js", "lib0/hash/rabin": "./node_modules/lib0/hash/rabin.js", diff --git a/tests/doc.tests.js b/tests/doc.tests.js index 1387a43c..0381a00f 100644 --- a/tests/doc.tests.js +++ b/tests/doc.tests.js @@ -29,7 +29,7 @@ export const testFindTypeInOtherDoc = _tc => { const ydocClone = new Y.Doc() Y.applyUpdate(ydocClone, Y.encodeStateAsUpdate(ydoc)) /** - * @template {Y.AbstractType} Type + * @template {import('../src/utils/types.js').YType} Type * @param {Type} ytype * @param {Y.Doc} otherYdoc * @return {Type} @@ -47,7 +47,7 @@ export const testFindTypeInOtherDoc = _tc => { if (rootKey == null) { throw new Error('type does not exist in other ydoc') } - return /** @type {Type} */ (otherYdoc.get(rootKey, /** @type {typeof Y.AbstractType} */ (ytype.constructor))) + return /** @type {Type} */ (otherYdoc.get(rootKey, /** @type {import('../src/utils/types.js').YTypeConstructors} */ (ytype.constructor))) } else { /** * If it is a sub type, we use the item id to find the history type. diff --git a/tests/testHelper.js b/tests/testHelper.js index 3a55a553..ad11f012 100644 --- a/tests/testHelper.js +++ b/tests/testHelper.js @@ -7,6 +7,8 @@ import * as object from 'lib0/object' import * as map from 'lib0/map' import * as Y from '../src/index.js' import * as math from 'lib0/math' +import * as list from 'lib0/list' +import * as delta from 'lib0/delta' import { createIdSet, createIdMap, addToIdSet, encodeIdMap } from '../src/internals.js' @@ -484,7 +486,7 @@ export const compare = users => { t.compare(userArrayValues[i], userArrayValues[i + 1]) t.compare(userMapValues[i], userMapValues[i + 1]) t.compare(userXmlValues[i], userXmlValues[i + 1]) - t.compare(userTextValues[i].ops.map(/** @param {any} a */ a => typeof a.insert === 'string' ? a.insert : ' ').join('').length, users[i].getText('text').length) + t.compare(list.toArray(userTextValues[i].children).map(a => delta.$textOp.check(a) ? a.insert : ' ').join('').length, users[i].getText('text').length) t.compare(userTextValues[i], userTextValues[i + 1], '', (_constructor, a, b) => { if (a instanceof Y.AbstractType) { t.compare(a.toJSON(), b.toJSON()) diff --git a/tests/undo-redo.tests.js b/tests/undo-redo.tests.js index 88812af1..4bfd4906 100644 --- a/tests/undo-redo.tests.js +++ b/tests/undo-redo.tests.js @@ -1,7 +1,7 @@ import * as Y from '../src/index.js' import { init } from './testHelper.js' // eslint-disable-line import * as t from 'lib0/testing' -import * as delta from '../src/utils/Delta.js' +import * as delta from 'lib0/delta' export const testInconsistentFormat = () => { /** @@ -11,7 +11,7 @@ export const testInconsistentFormat = () => { const content = /** @type {Y.XmlText} */ (ydoc.get('text', Y.XmlText)) content.format(0, 6, { bold: null }) content.format(6, 4, { type: 'text' }) - t.compare(content.getContent(), delta.createTextDelta().insert('Merge Test', { type: 'text' }).insert(' After', { type: 'text', italic: true })) + t.compare(content.getContent(), delta.create().insert('Merge Test', { type: 'text' }).insert(' After', { type: 'text', italic: true })) } const initializeYDoc = () => { const yDoc = new Y.Doc({ gc: false }) @@ -85,11 +85,11 @@ export const testUndoText = tc => { t.assert(text0.toString() === 'bcxyz') // test marks text0.format(1, 3, { bold: true }) - t.compare(text0.getContent(), delta.fromJSON([{ insert: 'b' }, { insert: 'cxy', attributes: { bold: true } }, { insert: 'z' }])) + t.compare(text0.getContent(), delta.create().insert('b').insert('cxy', { bold: true }).insert('z')) undoManager.undo() - t.compare(text0.getContent(), delta.fromJSON([{ insert: 'bcxyz' }])) + t.compare(text0.getContent(), delta.create().insert('bcxyz')) undoManager.redo() - t.compare(text0.getContent(), delta.fromJSON([{ insert: 'b' }, { insert: 'cxy', attributes: { bold: true } }, { insert: 'z' }])) + t.compare(text0.getContent(), delta.create().insert('b').insert('cxy', { bold: true }).insert('z')) } /** @@ -677,14 +677,10 @@ export const testUndoDeleteTextFormat = _tc => { undoManager.undo() Y.applyUpdate(doc2, Y.encodeStateAsUpdate(doc)) - const expect = delta.fromJSON([ - { insert: 'Attack ships ' }, - { - insert: 'on fire', - attributes: { bold: true } - }, - { insert: ' off the shoulder of Orion.' } - ]) + const expect = delta.create() + .insert('Attack ships ') + .insert('on fire', { bold: true }) + .insert(' off the shoulder of Orion.') t.compare(text.getContent(), expect) t.compare(text2.getContent(), expect) } diff --git a/tests/updates.tests.js b/tests/updates.tests.js index f68c1978..1e16f514 100644 --- a/tests/updates.tests.js +++ b/tests/updates.tests.js @@ -5,6 +5,7 @@ import { readStructSet, readIdSet, UpdateDecoderV2, UpdateEncoderV2, writeIdSet import * as encoding from 'lib0/encoding' import * as decoding from 'lib0/decoding' import * as object from 'lib0/object' +import * as delta from 'lib0/delta' /** * @typedef {Object} Enc @@ -126,7 +127,7 @@ export const testKeyEncoding = tc => { const update = Y.encodeStateAsUpdateV2(users[0]) Y.applyUpdateV2(users[1], update) - t.compare(text1.getContent().toJSON(), [{ insert: 'c', attributes: { italic: true } }, { insert: 'b' }, { insert: 'a', attributes: { italic: true } }]) + t.compare(text1.getContent().toJSON().children, [{ insert: 'c', format: { italic: true } }, { insert: 'b' }, { insert: 'a', format: { italic: true } }]) compare(users) } @@ -207,7 +208,7 @@ const checkUpdateCases = (ydoc, updates, enc, hasDeletes) => { } const meta = enc.parseUpdateMeta(mergedUpdates) - meta.from.forEach((clock, client) => t.assert(clock === 0)) + meta.from.forEach((clock, _client) => t.assert(clock === 0)) meta.to.forEach((clock, client) => { const structs = /** @type {Array} */ (merged.store.clients.get(client)) const lastStruct = structs[structs.length - 1] @@ -237,10 +238,10 @@ export const testMergeUpdates1 = _tc => { } /** - * @param {t.TestCase} tc + * @param {t.TestCase} _tc */ -export const testMergeUpdates2 = tc => { - encoders.forEach((enc, i) => { +export const testMergeUpdates2 = _tc => { + encoders.forEach((enc, _i) => { t.info(`Using encoder: ${enc.description}`) const ydoc = new Y.Doc({ gc: false }) const updates = /** @type {Array} */ ([]) @@ -257,23 +258,23 @@ export const testMergeUpdates2 = tc => { } /** - * @param {t.TestCase} tc + * @param {t.TestCase} _tc */ -export const testMergePendingUpdates = tc => { +export const testMergePendingUpdates = _tc => { const yDoc = new Y.Doc() /** * @type {Array} */ const serverUpdates = [] - yDoc.on('update', (update, origin, c) => { + yDoc.on('update', (update, _origin, _c) => { serverUpdates.splice(serverUpdates.length, 0, update) }) const yText = yDoc.getText('textBlock') - yText.applyDelta([{ insert: 'r' }]) - yText.applyDelta([{ insert: 'o' }]) - yText.applyDelta([{ insert: 'n' }]) - yText.applyDelta([{ insert: 'e' }]) - yText.applyDelta([{ insert: 'n' }]) + yText.applyDelta(delta.create().insert('r')) + yText.applyDelta(delta.create().insert('o')) + yText.applyDelta(delta.create().insert('n')) + yText.applyDelta(delta.create().insert('e')) + yText.applyDelta(delta.create().insert('n')) const yDoc1 = new Y.Doc() Y.applyUpdate(yDoc1, serverUpdates[0]) @@ -297,8 +298,7 @@ export const testMergePendingUpdates = tc => { const yDoc5 = new Y.Doc() Y.applyUpdate(yDoc5, update4) Y.applyUpdate(yDoc5, serverUpdates[4]) - // @ts-ignore - const _update5 = Y.encodeStateAsUpdate(yDoc5) // eslint-disable-line + Y.encodeStateAsUpdate(yDoc5) const yText5 = yDoc5.getText('textBlock') t.compareStrings(yText5.toString(), 'nenor') @@ -313,7 +313,7 @@ export const testObfuscateUpdates = _tc => { const ymap = ydoc.getMap('map') const yarray = ydoc.getArray('array') // test ytext - ytext.applyDelta([{ insert: 'text', attributes: { bold: true } }, { insert: { href: 'supersecreturl' } }]) + ytext.applyDelta(delta.create().insert('text', { bold: true }).insert([{ href: 'supersecreturl' }])) // test ymap ymap.set('key', 'secret1') ymap.set('key', 'secret2') @@ -330,13 +330,14 @@ export const testObfuscateUpdates = _tc => { const omap = odoc.getMap('map') const oarray = odoc.getArray('array') // test ytext - const delta = /** @type {Array} */ (otext.getContent().toJSON()) - t.assert(delta.length === 2) - t.assert(delta[0].insert !== 'text' && delta[0].insert.length === 4) - t.assert(object.length(delta[0].attributes) === 1) - t.assert(!object.hasProperty(delta[0].attributes, 'bold')) - t.assert(object.length(delta[1]) === 1) - t.assert(object.hasProperty(delta[1], 'insert')) + const d = /** @type {any} */ (otext.getContent().toJSON().children) + t.assert(d.length === 2) + const q = d[0] + t.assert(d[0].insert !== 'text' && d[0].insert.length === 4) + t.assert(object.length(d[0].format) === 1) + t.assert(!object.hasProperty(d[0].format, 'bold')) + t.assert(object.length(d[1]) === 1) + t.assert(object.hasProperty(d[1], 'insert')) // test ymap t.assert(omap.size === 1) t.assert(!omap.has('key')) diff --git a/tests/y-array.tests.js b/tests/y-array.tests.js index 7a31f632..aec28521 100644 --- a/tests/y-array.tests.js +++ b/tests/y-array.tests.js @@ -4,7 +4,7 @@ import * as t from 'lib0/testing' import * as prng from 'lib0/prng' import * as math from 'lib0/math' import * as env from 'lib0/environment' -import * as delta from '../src/utils/Delta.js' +import * as delta from 'lib0/delta' const isDevMode = env.getVariable('node_env') === 'development' @@ -384,24 +384,22 @@ export const testObservedeepIndexes = _tc => { export const testChangeEvent = tc => { const { array0, users } = init(tc, { users: 2 }) /** - * @type {any} + * @type {delta.Delta} */ - let changes = null + let d = delta.create() array0.observe(e => { - changes = e.changes + d = e.delta }) const newArr = new Y.Array() array0.insert(0, [newArr, 4, 'dtrn']) - t.assert(changes !== null && changes.added.size === 2 && changes.deleted.size === 0) - t.compare(changes.delta, [{ insert: [newArr, 4, 'dtrn'] }]) - changes = null + t.assert(d !== null && d.children.len === 1) + t.compare(d.toJSON().children, [{ insert: [newArr, 4, 'dtrn'] }]) array0.delete(0, 2) - t.assert(changes !== null && changes.added.size === 0 && changes.deleted.size === 2) - t.compare(changes.delta, [{ delete: 2 }]) - changes = null + t.assert(d !== null && d.children.len === 1) + t.compare(d.toJSON().children, [{ delete: 2 }]) array0.insert(1, [0.1]) - t.assert(changes !== null && changes.added.size === 1 && changes.deleted.size === 0) - t.compare(changes.delta, [{ retain: 1 }, { insert: [0.1] }]) + t.assert(d !== null && d.children.len === 2) + t.compare(d.toJSON().children, [{ retain: 1 }, { insert: [0.1] }]) compare(users) } @@ -531,7 +529,7 @@ export const testAttributedContent = _tc => { yarray.delete(0, 1) yarray.insert(1, [42]) }) - const expectedContent = delta.createArrayDelta().insert([1], null, { delete: [] }).insert([2]).insert([42], null, { insert: [] }) + const expectedContent = delta.create().insert([1], null, { delete: [] }).insert([2]).insert([42], null, { insert: [] }) const attributedContent = yarray.getContent(attributionManager) console.log(attributedContent.toJSON()) t.assert(attributedContent.equals(expectedContent)) diff --git a/tests/y-map.tests.js b/tests/y-map.tests.js index db89f575..c86155af 100644 --- a/tests/y-map.tests.js +++ b/tests/y-map.tests.js @@ -4,11 +4,12 @@ import { compareIDs, noAttributionsManager, TwosetAttributionManager, - createIdMapFromIdSet, - mapDeltaJsonSchema + createIdMapFromIdSet } from '../src/internals.js' import * as t from 'lib0/testing' import * as prng from 'lib0/prng' +import * as delta from 'lib0/delta' +import * as s from 'lib0/schema' /** * @param {t.TestCase} _tc @@ -490,45 +491,41 @@ export const testThrowsDeleteEventsOnClear = tc => { export const testChangeEvent = tc => { const { map0, users } = init(tc, { users: 2 }) /** - * @type {any} + * @type {delta.Delta?} */ - let changes = null - /** - * @type {any} - */ - let keyChange = null + let changes = delta.create() map0.observe(e => { - changes = e.changes + changes = e.delta }) map0.set('a', 1) - keyChange = changes.keys.get('a') - t.assert(changes !== null && keyChange.action === 'add' && keyChange.oldValue === undefined) + let keyChange = changes.attrs.get('a') + t.assert(delta.$insertOpWith(s.$number).check(keyChange) && keyChange.prevValue === undefined) map0.set('a', 2) - keyChange = changes.keys.get('a') - t.assert(changes !== null && keyChange.action === 'update' && keyChange.oldValue === 1) + keyChange = changes.attrs.get('a') + t.assert(delta.$insertOpWith(s.$number).check(keyChange) && keyChange.prevValue === 1) users[0].transact(() => { map0.set('a', 3) map0.set('a', 4) }) - keyChange = changes.keys.get('a') - t.assert(changes !== null && keyChange.action === 'update' && keyChange.oldValue === 2) + keyChange = changes.attrs.get('a') + t.assert(delta.$insertOpWith(s.$number).check(keyChange) && keyChange.prevValue === 2) users[0].transact(() => { map0.set('b', 1) map0.set('b', 2) }) - keyChange = changes.keys.get('b') - t.assert(changes !== null && keyChange.action === 'add' && keyChange.oldValue === undefined) + keyChange = changes.attrs.get('b') + t.assert(delta.$insertOpWith(s.$number).check(keyChange) && keyChange.prevValue === undefined) users[0].transact(() => { map0.set('c', 1) map0.delete('c') }) - t.assert(changes !== null && changes.keys.size === 0) + t.assert(changes !== null && changes.attrs.size === 0) users[0].transact(() => { map0.set('d', 1) map0.set('d', 2) }) - keyChange = changes.keys.get('d') - t.assert(changes !== null && keyChange.action === 'add' && keyChange.oldValue === undefined) + keyChange = changes.attrs.get('d') + t.assert(delta.$insertOpWith(s.$number).check(keyChange) && keyChange.prevValue === undefined) compare(users) } @@ -631,24 +628,24 @@ export const testAttributedContent = _tc => { }) t.group('initial value', () => { ymap.set('test', 42) - const expectedContent = mapDeltaJsonSchema.ensure({ test: { type: 'insert', prevValue: undefined, value: 42, attribution: { insert: [] } } }) + const expectedContent = { test: delta.$deltaMapChangeJson.expect({ type: 'insert', value: 42, attribution: { insert: [] } }) } const attributedContent = ymap.getContent(attributionManager) console.log(attributedContent.toJSON()) - t.compare(expectedContent, attributedContent.toJSON()) + t.compare(expectedContent, attributedContent.toJSON().attrs) }) t.group('overwrite value', () => { ymap.set('test', 'fourtytwo') - const expectedContent = mapDeltaJsonSchema.ensure({ test: { type: 'insert', prevValue: 42, value: 'fourtytwo', attribution: { insert: [] } } }) + const expectedContent = { test: delta.$deltaMapChangeJson.expect({ type: 'insert', prevValue: 42, value: 'fourtytwo', attribution: { insert: [] } }) } const attributedContent = ymap.getContent(attributionManager) console.log(attributedContent) - t.compare(expectedContent, attributedContent.toJSON()) + t.compare(expectedContent, attributedContent.toJSON().attrs) }) t.group('delete value', () => { ymap.delete('test') - const expectedContent = mapDeltaJsonSchema.ensure({ test: { type: 'delete', prevValue: 'fourtytwo', attribution: { delete: [] } } }) + const expectedContent = { test: delta.$deltaMapChangeJson.expect({ type: 'delete', prevValue: 'fourtytwo', attribution: { delete: [] } }) } const attributedContent = ymap.getContent(attributionManager) - console.log(attributedContent) - t.compare(expectedContent, attributedContent.toJSON()) + console.log(attributedContent.toJSON()) + t.compare(expectedContent, attributedContent.toJSON().attrs) }) } diff --git a/tests/y-text.tests.js b/tests/y-text.tests.js index c78b0494..8e5fa34a 100644 --- a/tests/y-text.tests.js +++ b/tests/y-text.tests.js @@ -3,6 +3,7 @@ import * as t from 'lib0/testing' import * as prng from 'lib0/prng' import * as math from 'lib0/math' import * as delta from 'lib0/delta' +import * as list from 'lib0/list' import { createIdMapFromIdSet, noAttributionsManager, TwosetAttributionManager, createAttributionManagerFromSnapshots } from 'yjs/internals' const { init, compare } = Y @@ -15,10 +16,7 @@ const { init, compare } = Y export const testDeltaBug = _tc => { const initialDelta = delta.create() .insert('\n', { - attributes: { - 'block-id': 'block-28eea923-9cbb-4b6f-a950-cf7fd82bc087' - }, - insert: '\n' + 'block-id': 'block-28eea923-9cbb-4b6f-a950-cf7fd82bc087' }) .insert('\n\n\n', { 'table-col': { @@ -157,17 +155,17 @@ export const testDeltaBug = _tc => { const addingSpace = delta.create().retain(13).insert(' ') ytext.applyDelta(addingSpace) const addingList = delta.create().retain(12).delete(2).retain(1, { - // Clear table line attribute - 'table-cell-line': null, - // Add list attribute in place of table-cell-line - list: { - rowspan: '1', - colspan: '1', - row: 'row-pflz90', - cell: 'cell-20b0j9', - list: 'bullet' - } - }) + // Clear table line attribute + 'table-cell-line': null, + // Add list attribute in place of table-cell-line + list: { + rowspan: '1', + colspan: '1', + row: 'row-pflz90', + cell: 'cell-20b0j9', + list: 'bullet' + } + }) ytext.applyDelta(addingList) const result = ytext.getContent() const expectedResult = delta.text() @@ -308,1227 +306,918 @@ export const testDeltaBug = _tc => { * @param {t.TestCase} _tc */ export const testDeltaBug2 = _tc => { - const initialContent = [ - { insert: "Thomas' section" }, - { - insert: '\n', - attributes: { 'block-id': 'block-61ae80ac-a469-4eae-bac9-3b6a2c380118' } - }, - { - insert: '\n', - attributes: { 'block-id': 'block-d265d93f-1cc7-40ee-bb58-8270fca2619f' } - }, - { insert: '123' }, - { - insert: '\n', - attributes: { - 'block-id': 'block-592a7bee-76a3-4e28-9c25-7a84344f8813', - list: { list: 'toggled', 'toggle-id': 'list-66xfft' } + const initialContent = delta.create() + .insert("Thomas' section") + .insert('\n', { 'block-id': 'block-61ae80ac-a469-4eae-bac9-3b6a2c380118' }) + .insert('\n', { 'block-id': 'block-d265d93f-1cc7-40ee-bb58-8270fca2619f' }) + .insert('123') + .insert('\n', { + 'block-id': 'block-592a7bee-76a3-4e28-9c25-7a84344f8813', + list: { list: 'toggled', 'toggle-id': 'list-66xfft' } + }) + .insert('456') + .insert('\n', { + indent: 1, + 'block-id': 'block-3ee2bd70-b97f-45b2-9115-f1e8910235b1', + list: { list: 'toggled', 'toggle-id': 'list-6vh0t0' } + }) + .insert('789') + .insert('\n', { + indent: 1, + 'block-id': 'block-78150cf3-9bb5-4dea-a6f5-0ce1d2a98b9c', + list: { list: 'toggled', 'toggle-id': 'list-7jr0l2' } + }) + .insert('901') + .insert('\n', { + indent: 1, + 'block-id': 'block-13c6416f-f522-41d5-9fd4-ce4eb1cde5ba', + list: { list: 'toggled', 'toggle-id': 'list-7uk8qu' } + }) + .insert([{ + slash_command: { + id: 'doc_94zq-2436', + sessionId: 'nkwc70p2j', + replace: '/' } - }, - { insert: '456' }, - { - insert: '\n', - attributes: { - indent: 1, - 'block-id': 'block-3ee2bd70-b97f-45b2-9115-f1e8910235b1', - list: { list: 'toggled', 'toggle-id': 'list-6vh0t0' } - } - }, - { insert: '789' }, - { - insert: '\n', - attributes: { - indent: 1, - 'block-id': 'block-78150cf3-9bb5-4dea-a6f5-0ce1d2a98b9c', - list: { list: 'toggled', 'toggle-id': 'list-7jr0l2' } - } - }, - { insert: '901' }, - { - insert: '\n', - attributes: { - indent: 1, - 'block-id': 'block-13c6416f-f522-41d5-9fd4-ce4eb1cde5ba', - list: { list: 'toggled', 'toggle-id': 'list-7uk8qu' } - } - }, - { - insert: { - slash_command: { - id: 'doc_94zq-2436', - sessionId: 'nkwc70p2j', - replace: '/' - } - } - }, - { - insert: '\n', - attributes: { 'block-id': 'block-8a1d2bb6-23c2-4bcf-af3c-3919ffea1697' } - }, - { insert: '\n\n\n', attributes: { 'table-col': { width: '150' } } }, - { - insert: '\n', - attributes: { - 'block-id': 'block-84ec3ea4-da6a-4e03-b430-0e5f432936a9', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-blmd4s', - cell: 'cell-m0u5za' - }, + }]) + .insert('\n', { 'block-id': 'block-8a1d2bb6-23c2-4bcf-af3c-3919ffea1697' }) + .insert('\n\n\n', { 'table-col': { width: '150' } }) + .insert('\n', { + 'block-id': 'block-84ec3ea4-da6a-4e03-b430-0e5f432936a9', + 'table-cell-line': { + rowspan: '1', + colspan: '1', row: 'row-blmd4s', - cell: 'cell-m0u5za', + cell: 'cell-m0u5za' + }, + row: 'row-blmd4s', + cell: 'cell-m0u5za', + rowspan: '1', + colspan: '1' + } + ) + .insert('\n', { + 'block-id': 'block-83144ca8-aace-401e-8aa5-c05928a8ccf0', + 'table-cell-line': { rowspan: '1', - colspan: '1' - } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-83144ca8-aace-401e-8aa5-c05928a8ccf0', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-blmd4s', - cell: 'cell-1v8s8t' - }, + colspan: '1', row: 'row-blmd4s', - cell: 'cell-1v8s8t', + cell: 'cell-1v8s8t' + }, + row: 'row-blmd4s', + cell: 'cell-1v8s8t', + rowspan: '1', + colspan: '1' + }) + .insert('\n', { + 'block-id': 'block-9a493387-d27f-4b58-b2f7-731dfafda32a', + 'table-cell-line': { rowspan: '1', - colspan: '1' - } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-9a493387-d27f-4b58-b2f7-731dfafda32a', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-blmd4s', - cell: 'cell-126947' - }, + colspan: '1', row: 'row-blmd4s', - cell: 'cell-126947', + cell: 'cell-126947' + }, + row: 'row-blmd4s', + cell: 'cell-126947', + rowspan: '1', + colspan: '1' + }) + .insert('\n', { + 'block-id': 'block-3484f86e-ae42-440f-8de6-857f0d8011ea', + 'table-cell-line': { rowspan: '1', - colspan: '1' - } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-3484f86e-ae42-440f-8de6-857f0d8011ea', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-hmmljo', - cell: 'cell-wvutl9' - }, + colspan: '1', row: 'row-hmmljo', - cell: 'cell-wvutl9', + cell: 'cell-wvutl9' + }, + row: 'row-hmmljo', + cell: 'cell-wvutl9', + rowspan: '1', + colspan: '1' + }) + .insert('\n', { + 'block-id': 'block-d4e0b741-9dea-47a5-85e1-4ded0efbc89d', + 'table-cell-line': { rowspan: '1', - colspan: '1' - } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-d4e0b741-9dea-47a5-85e1-4ded0efbc89d', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-hmmljo', - cell: 'cell-nkablr' - }, + colspan: '1', row: 'row-hmmljo', - cell: 'cell-nkablr', + cell: 'cell-nkablr' + }, + row: 'row-hmmljo', + cell: 'cell-nkablr', + rowspan: '1', + colspan: '1' + }) + .insert('\n', { + 'block-id': 'block-352f0d5a-d1b9-422f-b136-4bacefd00b1a', + 'table-cell-line': { rowspan: '1', - colspan: '1' - } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-352f0d5a-d1b9-422f-b136-4bacefd00b1a', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-hmmljo', - cell: 'cell-n8xtd0' - }, + colspan: '1', row: 'row-hmmljo', - cell: 'cell-n8xtd0', + cell: 'cell-n8xtd0' + }, + row: 'row-hmmljo', + cell: 'cell-n8xtd0', + rowspan: '1', + colspan: '1' + }) + .insert('\n', { + 'block-id': 'block-95823e57-f29c-44cf-a69d-2b4494b7144b', + 'table-cell-line': { rowspan: '1', - colspan: '1' - } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-95823e57-f29c-44cf-a69d-2b4494b7144b', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-ev4xwq', - cell: 'cell-ua9bvu' - }, + colspan: '1', row: 'row-ev4xwq', - cell: 'cell-ua9bvu', + cell: 'cell-ua9bvu' + }, + row: 'row-ev4xwq', + cell: 'cell-ua9bvu', + rowspan: '1', + colspan: '1' + }) + .insert('\n', { + 'block-id': 'block-cde5c027-15d3-4780-9e76-1e1a9d97a8e8', + 'table-cell-line': { rowspan: '1', - colspan: '1' - } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-cde5c027-15d3-4780-9e76-1e1a9d97a8e8', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-ev4xwq', - cell: 'cell-7bwuvk' - }, + colspan: '1', row: 'row-ev4xwq', - cell: 'cell-7bwuvk', + cell: 'cell-7bwuvk' + }, + row: 'row-ev4xwq', + cell: 'cell-7bwuvk', + rowspan: '1', + colspan: '1' + }) + .insert('\n', { + 'block-id': 'block-11a23ed4-b04d-4e45-8065-8120889cd4a4', + 'table-cell-line': { rowspan: '1', - colspan: '1' - } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-11a23ed4-b04d-4e45-8065-8120889cd4a4', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-ev4xwq', - cell: 'cell-aouka5' - }, + colspan: '1', row: 'row-ev4xwq', - cell: 'cell-aouka5', - rowspan: '1', - colspan: '1' + cell: 'cell-aouka5' + }, + row: 'row-ev4xwq', + cell: 'cell-aouka5', + rowspan: '1', + colspan: '1' + }) + .insert('\n', { 'block-id': 'block-15b4483c-da98-4ded-91d3-c3d6ebc82582' }) + .insert([{ divider: true }]) + .insert('\n', { 'block-id': 'block-68552c8e-b57b-4f4a-9f36-6cc1ef6b3461' }) + .insert('jklasjdf') + .insert('\n', { + 'block-id': 'block-c8b2df7d-8ec5-4dd4-81f1-8d8efc40b1b4', + list: { list: 'toggled', 'toggle-id': 'list-9ss39s' } + }) + .insert('asdf') + .insert('\n', { + 'block-id': 'block-4f252ceb-14da-49ae-8cbd-69a701d18e2a', + list: { list: 'toggled', 'toggle-id': 'list-uvo013' } + }) + .insert('adg') + .insert('\n', { + 'block-id': 'block-ccb9b72e-b94d-45a0-aae4-9b0a1961c533', + list: { list: 'toggled', 'toggle-id': 'list-k53iwe' } + }) + .insert('asdfasdfasdf') + .insert('\n', { + 'block-id': 'block-ccb9b72e-b94d-45a0-aae4-9b0a1961c533', + list: { list: 'none' }, + indent: 1 + }) + .insert('asdf') + .insert('\n', [{ + 'block-id': 'block-f406f76d-f338-4261-abe7-5c9131f7f1ad', + list: { list: 'toggled', 'toggle-id': 'list-en86ur' } + }]) + .insert('\n', { 'block-id': 'block-be18141c-9b6b-434e-8fd0-2c214437d560' }) + .insert('\n', { 'block-id': 'block-36922db3-4af5-48a1-9ea4-0788b3b5d7cf' }) + .insert([{ table_content: true }]) + .insert(' ') + .insert([{ + slash_command: { + id: 'doc_94zq-2436', + sessionId: 'hiyrt6fny', + replace: '/' } - }, - { - insert: '\n', - attributes: { 'block-id': 'block-15b4483c-da98-4ded-91d3-c3d6ebc82582' } - }, - { insert: { divider: true } }, - { - insert: '\n', - attributes: { 'block-id': 'block-68552c8e-b57b-4f4a-9f36-6cc1ef6b3461' } - }, - { insert: 'jklasjdf' }, - { - insert: '\n', - attributes: { - 'block-id': 'block-c8b2df7d-8ec5-4dd4-81f1-8d8efc40b1b4', - list: { list: 'toggled', 'toggle-id': 'list-9ss39s' } - } - }, - { insert: 'asdf' }, - { - insert: '\n', - attributes: { - 'block-id': 'block-4f252ceb-14da-49ae-8cbd-69a701d18e2a', - list: { list: 'toggled', 'toggle-id': 'list-uvo013' } - } - }, - { insert: 'adg' }, - { - insert: '\n', - attributes: { - 'block-id': 'block-ccb9b72e-b94d-45a0-aae4-9b0a1961c533', - list: { list: 'toggled', 'toggle-id': 'list-k53iwe' } - } - }, - { insert: 'asdfasdfasdf' }, - { - insert: '\n', - attributes: { - 'block-id': 'block-ccb9b72e-b94d-45a0-aae4-9b0a1961c533', - list: { list: 'none' }, - indent: 1 - } - }, - { insert: 'asdf' }, - { - insert: '\n', - attributes: { - 'block-id': 'block-f406f76d-f338-4261-abe7-5c9131f7f1ad', - list: { list: 'toggled', 'toggle-id': 'list-en86ur' } - } - }, - { - insert: '\n', - attributes: { 'block-id': 'block-be18141c-9b6b-434e-8fd0-2c214437d560' } - }, - { - insert: '\n', - attributes: { 'block-id': 'block-36922db3-4af5-48a1-9ea4-0788b3b5d7cf' } - }, - { insert: { table_content: true } }, - { insert: ' ' }, - { - insert: { - slash_command: { - id: 'doc_94zq-2436', - sessionId: 'hiyrt6fny', - replace: '/' - } - } - }, - { - insert: '\n', - attributes: { 'block-id': 'block-9d6566a1-be55-4e20-999a-b990bc15e143' } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-4b545085-114d-4d07-844c-789710ec3aab', - layout: + }]) + .insert('\n', { 'block-id': 'block-9d6566a1-be55-4e20-999a-b990bc15e143' }) + .insert('\n', { + 'block-id': 'block-4b545085-114d-4d07-844c-789710ec3aab', + layout: '12d887e1-d1a2-4814-a1a3-0c904e950b46_1185cd29-ef1b-45d5-8fda-51a70b704e64', - 'layout-width': '0.25' - } - }, - { - insert: '\n', - attributes: { - - 'block-id': 'block-4d3f2321-33d1-470e-9b7c-d5a683570148', - layout: + 'layout-width': '0.25' + }) + .insert('\n', { + 'block-id': 'block-4d3f2321-33d1-470e-9b7c-d5a683570148', + layout: '12d887e1-d1a2-4814-a1a3-0c904e950b46_75523ea3-c67f-4f5f-a85f-ac7c8fc0a992', - 'layout-width': '0.5' - } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-4c7ae1e6-758e-470f-8d7c-ae0325e4ee8a', - layout: + 'layout-width': '0.5' + }) + .insert('\n', { + 'block-id': 'block-4c7ae1e6-758e-470f-8d7c-ae0325e4ee8a', + layout: '12d887e1-d1a2-4814-a1a3-0c904e950b46_54c740ef-fd7b-48c6-85aa-c14e1bfc9297', - 'layout-width': '0.25' - } - }, - { - insert: '\n', - attributes: { 'block-id': 'block-2d6ff0f4-ff00-42b7-a8e2-b816463d8fb5' } - }, - { insert: { divider: true } }, - { - insert: '\n', - attributes: { 'table-col': { width: '150' } } - }, - { insert: '\n', attributes: { 'table-col': { width: '154' } } }, - { - insert: '\n', - attributes: { 'table-col': { width: '150' } } - }, - - { - insert: '\n', - attributes: { - 'block-id': 'block-38545d56-224b-464c-b779-51fcec24dbbf', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-q0qfck', - cell: 'cell-hmapv4' - }, + 'layout-width': '0.25' + }) + .insert('\n', { 'block-id': 'block-2d6ff0f4-ff00-42b7-a8e2-b816463d8fb5' }) + .insert([{ divider: true }]) + .insert('\n', { 'table-col': { width: '150' } }) + .insert('\n', { 'table-col': { width: '154' } }) + .insert('\n', { 'table-col': { width: '150' } }) + .insert('\n', { + 'block-id': 'block-38545d56-224b-464c-b779-51fcec24dbbf', + 'table-cell-line': { + rowspan: '1', + colspan: '1', row: 'row-q0qfck', - cell: 'cell-hmapv4', + cell: 'cell-hmapv4' + }, + row: 'row-q0qfck', + cell: 'cell-hmapv4', + rowspan: '1', + colspan: '1' + }) + .insert('\n', { + 'block-id': 'block-d413a094-5f52-4fd4-a4aa-00774f6fdb44', + 'table-cell-line': { rowspan: '1', - colspan: '1' - } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-d413a094-5f52-4fd4-a4aa-00774f6fdb44', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-q0qfck', - cell: 'cell-c0czb2' - }, + colspan: '1', row: 'row-q0qfck', - cell: 'cell-c0czb2', + cell: 'cell-c0czb2' + }, + row: 'row-q0qfck', + cell: 'cell-c0czb2', + rowspan: '1', + colspan: '1' + }) + .insert('\n', { + 'block-id': 'block-ff855cbc-8871-4e0a-9ba7-de0c1c2aa585', + 'table-cell-line': { rowspan: '1', - colspan: '1' - } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-ff855cbc-8871-4e0a-9ba7-de0c1c2aa585', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-q0qfck', - cell: 'cell-hcpqmm' - }, + colspan: '1', row: 'row-q0qfck', - cell: 'cell-hcpqmm', + cell: 'cell-hcpqmm' + }, + row: 'row-q0qfck', + cell: 'cell-hcpqmm', + rowspan: '1', + colspan: '1' + }) + .insert('\n', { + 'block-id': 'block-4841e6ee-fef8-4473-bf04-f5ba62db17f0', + 'table-cell-line': { rowspan: '1', - colspan: '1' - } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-4841e6ee-fef8-4473-bf04-f5ba62db17f0', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-etopyl', - cell: 'cell-0io73v' - }, + colspan: '1', row: 'row-etopyl', - cell: 'cell-0io73v', + cell: 'cell-0io73v' + }, + row: 'row-etopyl', + cell: 'cell-0io73v', + rowspan: '1', + colspan: '1' + }) + .insert('\n', { + 'block-id': 'block-adeec631-d4fe-4f38-9d5e-e67ba068bd24', + 'table-cell-line': { rowspan: '1', - colspan: '1' - } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-adeec631-d4fe-4f38-9d5e-e67ba068bd24', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-etopyl', - cell: 'cell-gt2waa' - }, + colspan: '1', row: 'row-etopyl', - cell: 'cell-gt2waa', + cell: 'cell-gt2waa' + }, + row: 'row-etopyl', + cell: 'cell-gt2waa', + rowspan: '1', + colspan: '1' + }) + .insert('\n', { + 'block-id': 'block-d38a7308-c858-4ce0-b1f3-0f9092384961', + 'table-cell-line': { rowspan: '1', - colspan: '1' - } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-d38a7308-c858-4ce0-b1f3-0f9092384961', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-etopyl', - cell: 'cell-os9ksy' - }, + colspan: '1', row: 'row-etopyl', - cell: 'cell-os9ksy', - rowspan: '1', - colspan: '1' - } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-a9df6568-1838-40d1-9d16-3c073b6ce169', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-0jwjg3', - cell: 'cell-hbx9ri' - }, - row: 'row-0jwjg3', - cell: 'cell-hbx9ri', - rowspan: '1', - colspan: '1' - } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-e26a0cf2-fe62-44a5-a4ca-8678a56d62f1', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-0jwjg3', - cell: 'cell-yg5m2w' - }, - row: 'row-0jwjg3', - cell: 'cell-yg5m2w', - rowspan: '1', - colspan: '1' - } - }, - { insert: 'a' }, - { - insert: '\n', - attributes: { - 'block-id': 'block-bfbc5ac2-7417-44b9-9aa5-8e36e4095627', - list: { - rowspan: '1', - colspan: '1', - row: 'row-0jwjg3', - cell: 'cell-1azhl2', - list: 'ordered' - }, + cell: 'cell-os9ksy' + }, + row: 'row-etopyl', + cell: 'cell-os9ksy', + rowspan: '1', + colspan: '1' + }) + .insert('\n', { + 'block-id': 'block-a9df6568-1838-40d1-9d16-3c073b6ce169', + 'table-cell-line': { rowspan: '1', colspan: '1', row: 'row-0jwjg3', - cell: 'cell-1azhl2' - } - }, - { insert: 'b' }, - { - insert: '\n', - attributes: { - 'block-id': 'block-f011c089-6389-47c0-8396-7477a29aa56f', - list: { - rowspan: '1', - colspan: '1', - row: 'row-0jwjg3', - cell: 'cell-1azhl2', - list: 'ordered' - }, + cell: 'cell-hbx9ri' + }, + row: 'row-0jwjg3', + cell: 'cell-hbx9ri', + rowspan: '1', + colspan: '1' + }) + .insert('\n', { + 'block-id': 'block-e26a0cf2-fe62-44a5-a4ca-8678a56d62f1', + 'table-cell-line': { rowspan: '1', colspan: '1', row: 'row-0jwjg3', - cell: 'cell-1azhl2' - } - }, - { insert: 'c' }, - { - insert: '\n', - attributes: { - 'block-id': 'block-4497788d-1e02-4fd5-a80a-48b61a6185cb', - list: { - rowspan: '1', - colspan: '1', - row: 'row-0jwjg3', - cell: 'cell-1azhl2', - list: 'ordered' - }, + cell: 'cell-yg5m2w' + }, + row: 'row-0jwjg3', + cell: 'cell-yg5m2w', + rowspan: '1', + colspan: '1' + }) + .insert('a') + .insert('\n', { + 'block-id': 'block-bfbc5ac2-7417-44b9-9aa5-8e36e4095627', + list: { rowspan: '1', colspan: '1', row: 'row-0jwjg3', - cell: 'cell-1azhl2' - } - }, - { insert: 'd' }, - { - insert: '\n', - attributes: { - 'block-id': 'block-5d73a2c7-f98b-47c7-a3f5-0d8527962b02', - list: { - rowspan: '1', - colspan: '1', - row: 'row-0jwjg3', - cell: 'cell-1azhl2', - list: 'ordered' - }, + cell: 'cell-1azhl2', + list: 'ordered' + }, + rowspan: '1', + colspan: '1', + row: 'row-0jwjg3', + cell: 'cell-1azhl2' + }) + .insert('b') + .insert('\n', { + 'block-id': 'block-f011c089-6389-47c0-8396-7477a29aa56f', + list: { rowspan: '1', colspan: '1', row: 'row-0jwjg3', - cell: 'cell-1azhl2' - } - }, - { insert: 'e' }, - { - insert: '\n', - attributes: { - 'block-id': 'block-bfda76ee-ffdd-45db-a22e-a6707e11cf68', - list: { - rowspan: '1', - colspan: '1', - row: 'row-0jwjg3', - cell: 'cell-1azhl2', - list: 'ordered' - }, + cell: 'cell-1azhl2', + list: 'ordered' + }, + rowspan: '1', + colspan: '1', + row: 'row-0jwjg3', + cell: 'cell-1azhl2' + }) + .insert('c') + .insert('\n', { + 'block-id': 'block-4497788d-1e02-4fd5-a80a-48b61a6185cb', + list: { rowspan: '1', colspan: '1', row: 'row-0jwjg3', - cell: 'cell-1azhl2' - } - }, - { insert: 'd' }, - { - insert: '\n', - attributes: { - 'block-id': 'block-35242e64-a69d-4cdb-bd85-2a93766bfab4', - list: { - rowspan: '1', - colspan: '1', - row: 'row-0jwjg3', - cell: 'cell-1azhl2', - list: 'ordered' - }, + cell: 'cell-1azhl2', + list: 'ordered' + }, + rowspan: '1', + colspan: '1', + row: 'row-0jwjg3', + cell: 'cell-1azhl2' + }) + .insert('d') + .insert('\n', { + 'block-id': 'block-5d73a2c7-f98b-47c7-a3f5-0d8527962b02', + list: { rowspan: '1', colspan: '1', row: 'row-0jwjg3', - cell: 'cell-1azhl2' - } - }, - { insert: 'f' }, - { - insert: '\n', - attributes: { - 'block-id': 'block-8baa22c8-491b-4f1b-9502-44179d5ae744', - list: { - rowspan: '1', - colspan: '1', - row: 'row-0jwjg3', - cell: 'cell-1azhl2', - list: 'ordered' - }, + cell: 'cell-1azhl2', + list: 'ordered' + }, + rowspan: '1', + colspan: '1', + row: 'row-0jwjg3', + cell: 'cell-1azhl2' + }) + .insert('e') + .insert('\n', { + 'block-id': 'block-bfda76ee-ffdd-45db-a22e-a6707e11cf68', + list: { rowspan: '1', colspan: '1', row: 'row-0jwjg3', - cell: 'cell-1azhl2' + cell: 'cell-1azhl2', + list: 'ordered' + }, + rowspan: '1', + colspan: '1', + row: 'row-0jwjg3', + cell: 'cell-1azhl2' + }) + .insert('d') + .insert('\n', { + 'block-id': 'block-35242e64-a69d-4cdb-bd85-2a93766bfab4', + list: { + rowspan: '1', + colspan: '1', + row: 'row-0jwjg3', + cell: 'cell-1azhl2', + list: 'ordered' + }, + rowspan: '1', + colspan: '1', + row: 'row-0jwjg3', + cell: 'cell-1azhl2' + }) + .insert('f') + .insert('\n', { + 'block-id': 'block-8baa22c8-491b-4f1b-9502-44179d5ae744', + list: { + rowspan: '1', + colspan: '1', + row: 'row-0jwjg3', + cell: 'cell-1azhl2', + list: 'ordered' + }, + rowspan: '1', + colspan: '1', + row: 'row-0jwjg3', + cell: 'cell-1azhl2' + }) + .insert('\n', { 'block-id': 'block-7fa64af0-6974-4205-8cee-529f8bd46852' }) + .insert([{ divider: true }]) + .insert("Brandon's Section") + .insert('\n', { + header: 2, + 'block-id': 'block-cf49462c-2370-48ff-969d-576cb32c39a1' + }) + .insert('\n', { 'block-id': 'block-30ef8361-0dd6-4eee-b4eb-c9012d0e9070' }) + .insert([{ + slash_command: { + id: 'doc_94zq-2436', + sessionId: 'x9x08o916', + replace: '/' } - }, - { - insert: '\n', - attributes: { 'block-id': 'block-7fa64af0-6974-4205-8cee-529f8bd46852' } - }, - { insert: { divider: true } }, - { insert: "Brandon's Section" }, - { - insert: '\n', - attributes: { - header: 2, - 'block-id': 'block-cf49462c-2370-48ff-969d-576cb32c39a1' - } - }, - { - insert: '\n', - attributes: { 'block-id': 'block-30ef8361-0dd6-4eee-b4eb-c9012d0e9070' } - }, - { - insert: { - slash_command: { - id: 'doc_94zq-2436', - sessionId: 'x9x08o916', - replace: '/' - } - } - }, - { - insert: '\n', - attributes: { 'block-id': 'block-166ed856-cf8c-486a-9365-f499b21d91b3' } - }, - { insert: { divider: true } }, - { - insert: '\n', - attributes: { + }]) + .insert('\n', { 'block-id': 'block-166ed856-cf8c-486a-9365-f499b21d91b3' }) + .insert([{ divider: true }]) + .insert('\n', { + row: 'row-kssn15', + rowspan: '1', + colspan: '1', + 'block-id': 'block-e8079594-4559-4259-98bb-da5280e2a692', + 'table-cell-line': { + rowspan: '1', + colspan: '1', row: 'row-kssn15', - rowspan: '1', - colspan: '1', - 'block-id': 'block-e8079594-4559-4259-98bb-da5280e2a692', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-kssn15', - cell: 'cell-qxbksf' - }, cell: 'cell-qxbksf' - } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-70132663-14cc-4701-b5c5-eb99e875e2bd', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-kssn15', - cell: 'cell-lsohbx' - }, - cell: 'cell-lsohbx', + }, + cell: 'cell-qxbksf' + }) + .insert('\n', { + 'block-id': 'block-70132663-14cc-4701-b5c5-eb99e875e2bd', + 'table-cell-line': { + rowspan: '1', + colspan: '1', row: 'row-kssn15', + cell: 'cell-lsohbx' + }, + cell: 'cell-lsohbx', + row: 'row-kssn15', + rowspan: '1', + colspan: '1' + }) + .insert('\n', { + 'block-id': 'block-47a3899c-e3c5-4a7a-a8c4-46e0ae73a4fa', + 'table-cell-line': { rowspan: '1', - colspan: '1' - } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-47a3899c-e3c5-4a7a-a8c4-46e0ae73a4fa', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-kssn15', - cell: 'cell-hner9k' - }, - cell: 'cell-hner9k', + colspan: '1', row: 'row-kssn15', + cell: 'cell-hner9k' + }, + cell: 'cell-hner9k', + row: 'row-kssn15', + rowspan: '1', + colspan: '1' + }) + .insert('\n', { + 'block-id': 'block-0f9e650a-7841-412e-b4f2-5571b6d352c2', + 'table-cell-line': { rowspan: '1', - colspan: '1' - } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-0f9e650a-7841-412e-b4f2-5571b6d352c2', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-juxwc0', - cell: 'cell-ei4yqp' - }, - cell: 'cell-ei4yqp', + colspan: '1', row: 'row-juxwc0', + cell: 'cell-ei4yqp' + }, + cell: 'cell-ei4yqp', + row: 'row-juxwc0', + rowspan: '1', + colspan: '1' + }) + .insert('\n', { + 'block-id': 'block-53a158a9-8c82-4c82-9d4e-f5298257ca43', + 'table-cell-line': { rowspan: '1', - colspan: '1' - } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-53a158a9-8c82-4c82-9d4e-f5298257ca43', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-juxwc0', - cell: 'cell-25pf5x' - }, - cell: 'cell-25pf5x', + colspan: '1', row: 'row-juxwc0', + cell: 'cell-25pf5x' + }, + cell: 'cell-25pf5x', + row: 'row-juxwc0', + rowspan: '1', + colspan: '1' + }) + .insert('\n', { + 'block-id': 'block-da8ba35e-ce6e-4518-8605-c51d781eb07a', + 'table-cell-line': { rowspan: '1', - colspan: '1' - } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-da8ba35e-ce6e-4518-8605-c51d781eb07a', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-juxwc0', - cell: 'cell-m8reor' - }, - cell: 'cell-m8reor', + colspan: '1', row: 'row-juxwc0', + cell: 'cell-m8reor' + }, + cell: 'cell-m8reor', + row: 'row-juxwc0', + rowspan: '1', + colspan: '1' + }) + .insert('\n', { + 'block-id': 'block-2dce37c7-2978-4127-bed0-9549781babcb', + 'table-cell-line': { rowspan: '1', - colspan: '1' - } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-2dce37c7-2978-4127-bed0-9549781babcb', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-ot4wy5', - cell: 'cell-dinh0i' - }, - cell: 'cell-dinh0i', + colspan: '1', row: 'row-ot4wy5', + cell: 'cell-dinh0i' + }, + cell: 'cell-dinh0i', + row: 'row-ot4wy5', + rowspan: '1', + colspan: '1' + }) + .insert('\n', { + 'block-id': 'block-7b593f8c-4ea3-44b4-8ad9-4a0abffe759b', + 'table-cell-line': { rowspan: '1', - colspan: '1' - } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-7b593f8c-4ea3-44b4-8ad9-4a0abffe759b', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-ot4wy5', - cell: 'cell-d115b2' - }, - cell: 'cell-d115b2', + colspan: '1', row: 'row-ot4wy5', + cell: 'cell-d115b2' + }, + cell: 'cell-d115b2', + row: 'row-ot4wy5', + rowspan: '1', + colspan: '1' + }) + .insert('\n', { + 'block-id': 'block-272c28e6-2bde-4477-9d99-ce35b3045895', + 'table-cell-line': { rowspan: '1', - colspan: '1' - } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-272c28e6-2bde-4477-9d99-ce35b3045895', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-ot4wy5', - cell: 'cell-fuapvo' - }, - cell: 'cell-fuapvo', + colspan: '1', row: 'row-ot4wy5', + cell: 'cell-fuapvo' + }, + cell: 'cell-fuapvo', + row: 'row-ot4wy5', + rowspan: '1', + colspan: '1' + }) + .insert('\n', { 'block-id': 'block-fbf23cab-1ce9-4ede-9953-f2f8250004cf' }) + .insert('\n', { 'block-id': 'block-c3fbb8c9-495c-40b0-b0dd-f6e33dd64b1b' }) + .insert('\n', { 'block-id': 'block-3417ad09-92a3-4a43-b5db-6dbcb0f16db4' }) + .insert('\n', { 'block-id': 'block-b9eacdce-4ba3-4e66-8b69-3eace5656057' }) + .insert('Dan Gornstein') + .insert('\n', { + 'block-id': 'block-d7c6ae0d-a17c-433e-85fd-5efc52b587fb', + header: 1 + }) + .insert('\n', { 'block-id': 'block-814521bd-0e14-4fbf-b332-799c6452a624' }) + .insert('aaa') + .insert('\n', { + 'block-id': 'block-6aaf4dcf-dc21-45c6-b723-afb25fe0f498', + list: { list: 'toggled', 'toggle-id': 'list-idl93b' } + }) + .insert('bb') + .insert('\n', { + indent: 1, + 'block-id': 'block-3dd75392-fa50-4bfb-ba6b-3b7d6bd3f1a1', + list: { list: 'toggled', 'toggle-id': 'list-mrq7j2' } + }) + .insert('ccc') + .insert('\n', { + 'block-id': 'block-2528578b-ecda-4f74-9fd7-8741d72dc8b3', + indent: 2, + list: { list: 'toggled', 'toggle-id': 'list-liu7dl' } + }) + .insert('\n', { 'block-id': 'block-18bf68c3-9ef3-4874-929c-9b6bb1a00325' }) + .insert('\n', { 'table-col': { width: '150' } }) + .insert('\n', { 'table-col': { width: '150' } }) + .insert('\n', { 'table-col': { width: '150' } }) + .insert('\n', { + 'block-id': 'block-d44e74b4-b37f-48e0-b319-6327a6295a57', + 'table-cell-line': { rowspan: '1', - colspan: '1' - } - }, - { - insert: '\n', - attributes: { 'block-id': 'block-fbf23cab-1ce9-4ede-9953-f2f8250004cf' } - }, - { - insert: '\n', - attributes: { 'block-id': 'block-c3fbb8c9-495c-40b0-b0dd-f6e33dd64b1b' } - }, - { - insert: '\n', - attributes: { 'block-id': 'block-3417ad09-92a3-4a43-b5db-6dbcb0f16db4' } - }, - { - insert: '\n', - attributes: { 'block-id': 'block-b9eacdce-4ba3-4e66-8b69-3eace5656057' } - }, - { insert: 'Dan Gornstein' }, - { - insert: '\n', - attributes: { - 'block-id': 'block-d7c6ae0d-a17c-433e-85fd-5efc52b587fb', - header: 1 - } - }, - { - insert: '\n', - attributes: { 'block-id': 'block-814521bd-0e14-4fbf-b332-799c6452a624' } - }, - { insert: 'aaa' }, - { - insert: '\n', - attributes: { - 'block-id': 'block-6aaf4dcf-dc21-45c6-b723-afb25fe0f498', - list: { list: 'toggled', 'toggle-id': 'list-idl93b' } - } - }, - { insert: 'bb' }, - { - insert: '\n', - attributes: { - indent: 1, - 'block-id': 'block-3dd75392-fa50-4bfb-ba6b-3b7d6bd3f1a1', - list: { list: 'toggled', 'toggle-id': 'list-mrq7j2' } - } - }, - { insert: 'ccc' }, - { - insert: '\n', - attributes: { - 'block-id': 'block-2528578b-ecda-4f74-9fd7-8741d72dc8b3', - indent: 2, - list: { list: 'toggled', 'toggle-id': 'list-liu7dl' } - } - }, - { - insert: '\n', - attributes: { 'block-id': 'block-18bf68c3-9ef3-4874-929c-9b6bb1a00325' } - }, - { - insert: '\n', - attributes: { 'table-col': { width: '150' } } - }, - { insert: '\n', attributes: { 'table-col': { width: '150' } } }, - { - insert: '\n', - attributes: { 'table-col': { width: '150' } } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-d44e74b4-b37f-48e0-b319-6327a6295a57', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-si1nah', - cell: 'cell-cpybie' - }, + colspan: '1', + row: 'row-si1nah', + cell: 'cell-cpybie' + }, + row: 'row-si1nah', + cell: 'cell-cpybie', + rowspan: '1', + colspan: '1' + }) + .insert('aaa') + .insert('\n', { + 'block-id': 'block-3e545ee9-0c9a-42d7-a4d0-833edb8087f3', + list: { + rowspan: '1', + colspan: '1', row: 'row-si1nah', cell: 'cell-cpybie', - rowspan: '1', - colspan: '1' - } - }, - { insert: 'aaa' }, - { - insert: '\n', - attributes: { - 'block-id': 'block-3e545ee9-0c9a-42d7-a4d0-833edb8087f3', - list: { - rowspan: '1', - colspan: '1', - row: 'row-si1nah', - cell: 'cell-cpybie', - list: 'toggled', - 'toggle-id': 'list-kjl2ik' - }, + list: 'toggled', + 'toggle-id': 'list-kjl2ik' + }, + rowspan: '1', + colspan: '1', + row: 'row-si1nah', + cell: 'cell-cpybie' + }) + .insert('bb') + .insert('\n', { + indent: 1, + 'block-id': 'block-5f1225ad-370f-46ab-8f1e-18b277b5095f', + list: { rowspan: '1', colspan: '1', row: 'row-si1nah', - cell: 'cell-cpybie' - } - }, - { insert: 'bb' }, - { - insert: '\n', - attributes: { - indent: 1, - 'block-id': 'block-5f1225ad-370f-46ab-8f1e-18b277b5095f', - list: { - rowspan: '1', - colspan: '1', - row: 'row-si1nah', - cell: 'cell-cpybie', - list: 'toggled', - 'toggle-id': 'list-eei1x5' - }, - rowspan: '1', - colspan: '1', - row: 'row-si1nah', - cell: 'cell-cpybie' - } - }, - { insert: 'ccc' }, - { - insert: '\n', - attributes: { - indent: 2, - 'block-id': 'block-a77fdc11-ad24-431b-9ca2-09e32db94ac2', - list: { - rowspan: '1', - colspan: '1', - row: 'row-si1nah', - cell: 'cell-cpybie', - list: 'toggled', - 'toggle-id': 'list-30us3c' - }, - rowspan: '1', - colspan: '1', - row: 'row-si1nah', - cell: 'cell-cpybie' - } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-d44e74b4-b37f-48e0-b319-6327a6295a57', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-si1nah', - cell: 'cell-cpybie' - }, - row: 'row-si1nah', cell: 'cell-cpybie', + list: 'toggled', + 'toggle-id': 'list-eei1x5' + }, + rowspan: '1', + colspan: '1', + row: 'row-si1nah', + cell: 'cell-cpybie' + }) + .insert('ccc') + .insert('\n', { + indent: 2, + 'block-id': 'block-a77fdc11-ad24-431b-9ca2-09e32db94ac2', + list: { rowspan: '1', - colspan: '1' - } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-2c274c8a-757d-4892-8db8-1a7999f7ab51', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-si1nah', - cell: 'cell-al1z64' - }, + colspan: '1', row: 'row-si1nah', - cell: 'cell-al1z64', + cell: 'cell-cpybie', + list: 'toggled', + 'toggle-id': 'list-30us3c' + }, + rowspan: '1', + colspan: '1', + row: 'row-si1nah', + cell: 'cell-cpybie' + }) + .insert('\n', { + 'block-id': 'block-d44e74b4-b37f-48e0-b319-6327a6295a57', + 'table-cell-line': { rowspan: '1', - colspan: '1' - } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-85931afe-1879-471c-bb4b-89e7bd517fe9', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-si1nah', - cell: 'cell-q186pb' - }, + colspan: '1', row: 'row-si1nah', - cell: 'cell-q186pb', + cell: 'cell-cpybie' + }, + row: 'row-si1nah', + cell: 'cell-cpybie', + rowspan: '1', + colspan: '1' + }) + .insert('\n', { + 'block-id': 'block-2c274c8a-757d-4892-8db8-1a7999f7ab51', + 'table-cell-line': { rowspan: '1', - colspan: '1' - } - }, - { insert: 'asdfasdfasdf' }, - { - insert: '\n', - attributes: { - 'block-id': 'block-6e0522e8-c1eb-4c07-98df-2b07c533a139', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-7x2d1o', - cell: 'cell-6eid2t' - }, + colspan: '1', + row: 'row-si1nah', + cell: 'cell-al1z64' + }, + row: 'row-si1nah', + cell: 'cell-al1z64', + rowspan: '1', + colspan: '1' + }) + .insert('\n', { + 'block-id': 'block-85931afe-1879-471c-bb4b-89e7bd517fe9', + 'table-cell-line': { + rowspan: '1', + colspan: '1', + row: 'row-si1nah', + cell: 'cell-q186pb' + }, + row: 'row-si1nah', + cell: 'cell-q186pb', + rowspan: '1', + colspan: '1' + }) + .insert('asdfasdfasdf') + .insert('\n', { + 'block-id': 'block-6e0522e8-c1eb-4c07-98df-2b07c533a139', + 'table-cell-line': { + rowspan: '1', + colspan: '1', row: 'row-7x2d1o', - cell: 'cell-6eid2t', + cell: 'cell-6eid2t' + }, + row: 'row-7x2d1o', + cell: 'cell-6eid2t', + rowspan: '1', + colspan: '1' + }) + .insert('\n', { + 'block-id': 'block-4b3d0bd0-9175-45e9-955c-e8164f4b5376', + row: 'row-7x2d1o', + cell: 'cell-m1alad', + rowspan: '1', + colspan: '1', + list: { rowspan: '1', - colspan: '1' - } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-4b3d0bd0-9175-45e9-955c-e8164f4b5376', + colspan: '1', row: 'row-7x2d1o', cell: 'cell-m1alad', + list: 'ordered' + } + }) + .insert('asdfasdfasdf') + .insert('\n', { + 'block-id': 'block-08610089-cb05-4366-bb1e-a0787d5b11bf', + 'table-cell-line': { rowspan: '1', colspan: '1', - list: { - rowspan: '1', - colspan: '1', - row: 'row-7x2d1o', - cell: 'cell-m1alad', - list: 'ordered' - } - } - }, - { insert: 'asdfasdfasdf' }, - { - insert: '\n', - attributes: { - 'block-id': 'block-08610089-cb05-4366-bb1e-a0787d5b11bf', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-7x2d1o', - cell: 'cell-dm1l2p' - }, row: 'row-7x2d1o', - cell: 'cell-dm1l2p', + cell: 'cell-dm1l2p' + }, + row: 'row-7x2d1o', + cell: 'cell-dm1l2p', + rowspan: '1', + colspan: '1' + }) + .insert('\n', { + 'block-id': 'block-c22b5125-8df3-432f-bd55-5ff456e41b4e', + 'table-cell-line': { rowspan: '1', - colspan: '1' - } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-c22b5125-8df3-432f-bd55-5ff456e41b4e', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-o0ujua', - cell: 'cell-82g0ca' - }, + colspan: '1', row: 'row-o0ujua', - cell: 'cell-82g0ca', + cell: 'cell-82g0ca' + }, + row: 'row-o0ujua', + cell: 'cell-82g0ca', + rowspan: '1', + colspan: '1' + }) + .insert('\n', { + 'block-id': 'block-7c6320e4-acaf-4ab4-8355-c9b00408c9c1', + 'table-cell-line': { rowspan: '1', - colspan: '1' - } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-7c6320e4-acaf-4ab4-8355-c9b00408c9c1', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-o0ujua', - cell: 'cell-wv6ozp' - }, + colspan: '1', row: 'row-o0ujua', - cell: 'cell-wv6ozp', + cell: 'cell-wv6ozp' + }, + row: 'row-o0ujua', + cell: 'cell-wv6ozp', + rowspan: '1', + colspan: '1' + }) + .insert('\n', { + 'block-id': 'block-d1bb7bed-e69e-4807-8d20-2d28fef8d08f', + 'table-cell-line': { rowspan: '1', - colspan: '1' - } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-d1bb7bed-e69e-4807-8d20-2d28fef8d08f', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-o0ujua', - cell: 'cell-ldt53x' - }, + colspan: '1', row: 'row-o0ujua', - cell: 'cell-ldt53x', + cell: 'cell-ldt53x' + }, + row: 'row-o0ujua', + cell: 'cell-ldt53x', + rowspan: '1', + colspan: '1' + }) + .insert('\n', { 'block-id': 'block-28f28cb8-51a2-4156-acf9-2380e1349745' }) + .insert([{ divider: true }]) + .insert('\n', { 'block-id': 'block-a1193252-c0c8-47fe-b9f6-32c8b01a1619' }) + .insert('\n', { 'table-col': { width: '150' } }) + .insert('\n\n', { 'table-col': { width: '150' } }) + .insert('/This is a test.') + .insert('\n', { + 'block-id': 'block-14188df0-a63f-4317-9a6d-91b96a7ac9fe', + 'table-cell-line': { rowspan: '1', - colspan: '1' - } - }, - { - insert: '\n', - attributes: { 'block-id': 'block-28f28cb8-51a2-4156-acf9-2380e1349745' } - }, - { insert: { divider: true } }, - { - insert: '\n', - attributes: { 'block-id': 'block-a1193252-c0c8-47fe-b9f6-32c8b01a1619' } - }, - { insert: '\n', attributes: { 'table-col': { width: '150' } } }, - { - insert: '\n\n', - attributes: { 'table-col': { width: '150' } } - }, - { insert: '/This is a test.' }, - { - insert: '\n', - attributes: { - 'block-id': 'block-14188df0-a63f-4317-9a6d-91b96a7ac9fe', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-5ixdvv', - cell: 'cell-9tgyed' - }, + colspan: '1', row: 'row-5ixdvv', - cell: 'cell-9tgyed', + cell: 'cell-9tgyed' + }, + row: 'row-5ixdvv', + cell: 'cell-9tgyed', + rowspan: '1', + colspan: '1' + }) + .insert('\n', { + 'block-id': 'block-7e5ba2af-9903-457d-adf4-2a79be81d823', + 'table-cell-line': { rowspan: '1', - colspan: '1' - } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-7e5ba2af-9903-457d-adf4-2a79be81d823', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-5ixdvv', - cell: 'cell-xc56e9' - }, + colspan: '1', row: 'row-5ixdvv', - cell: 'cell-xc56e9', + cell: 'cell-xc56e9' + }, + row: 'row-5ixdvv', + cell: 'cell-xc56e9', + rowspan: '1', + colspan: '1' + }) + .insert('\n', { + 'block-id': 'block-eb6cad93-caf7-4848-8adf-415255139268', + 'table-cell-line': { rowspan: '1', - colspan: '1' - } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-eb6cad93-caf7-4848-8adf-415255139268', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-5ixdvv', - cell: 'cell-xrze3u' - }, + colspan: '1', row: 'row-5ixdvv', - cell: 'cell-xrze3u', + cell: 'cell-xrze3u' + }, + row: 'row-5ixdvv', + cell: 'cell-xrze3u', + rowspan: '1', + colspan: '1' + }) + .insert('\n', { + 'block-id': 'block-5bb547a2-6f71-4624-80c7-d0e1318c81a2', + 'table-cell-line': { rowspan: '1', - colspan: '1' - } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-5bb547a2-6f71-4624-80c7-d0e1318c81a2', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-xbzv98', - cell: 'cell-lie0ng' - }, + colspan: '1', row: 'row-xbzv98', - cell: 'cell-lie0ng', + cell: 'cell-lie0ng' + }, + row: 'row-xbzv98', + cell: 'cell-lie0ng', + rowspan: '1', + colspan: '1' + }) + .insert('\n', { + 'block-id': 'block-b506de0d-efb6-4bd7-ba8e-2186cc57903e', + 'table-cell-line': { rowspan: '1', - colspan: '1' - } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-b506de0d-efb6-4bd7-ba8e-2186cc57903e', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-xbzv98', - cell: 'cell-s9sow1' - }, + colspan: '1', row: 'row-xbzv98', - cell: 'cell-s9sow1', + cell: 'cell-s9sow1' + }, + row: 'row-xbzv98', + cell: 'cell-s9sow1', + rowspan: '1', + colspan: '1' + }) + .insert('\n', { + 'block-id': 'block-42d2ad20-5521-40e3-a88d-fe6906176e61', + 'table-cell-line': { rowspan: '1', - colspan: '1' - } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-42d2ad20-5521-40e3-a88d-fe6906176e61', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-xbzv98', - cell: 'cell-nodtcj' - }, + colspan: '1', row: 'row-xbzv98', - cell: 'cell-nodtcj', + cell: 'cell-nodtcj' + }, + row: 'row-xbzv98', + cell: 'cell-nodtcj', + rowspan: '1', + colspan: '1' + }) + .insert('\n', { + 'block-id': 'block-7d3e4216-3f68-4dd6-bc77-4a9fad4ba008', + 'table-cell-line': { rowspan: '1', - colspan: '1' - } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-7d3e4216-3f68-4dd6-bc77-4a9fad4ba008', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-5bqfil', - cell: 'cell-c8c0f3' - }, + colspan: '1', row: 'row-5bqfil', - cell: 'cell-c8c0f3', + cell: 'cell-c8c0f3' + }, + row: 'row-5bqfil', + cell: 'cell-c8c0f3', + rowspan: '1', + colspan: '1' + }) + .insert('\n', { + 'block-id': 'block-6671f221-551e-47fb-9b7d-9043b6b12cdc', + 'table-cell-line': { rowspan: '1', - colspan: '1' - } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-6671f221-551e-47fb-9b7d-9043b6b12cdc', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-5bqfil', - cell: 'cell-jvxxif' - }, + colspan: '1', row: 'row-5bqfil', - cell: 'cell-jvxxif', + cell: 'cell-jvxxif' + }, + row: 'row-5bqfil', + cell: 'cell-jvxxif', + rowspan: '1', + colspan: '1' + }) + .insert('\n', { + 'block-id': 'block-51e3161b-0437-4fe3-ac4f-129a93a93fc3', + 'table-cell-line': { rowspan: '1', - colspan: '1' - } - }, - { - insert: '\n', - attributes: { - 'block-id': 'block-51e3161b-0437-4fe3-ac4f-129a93a93fc3', - 'table-cell-line': { - rowspan: '1', - colspan: '1', - row: 'row-5bqfil', - cell: 'cell-rmjpze' - }, + colspan: '1', row: 'row-5bqfil', - cell: 'cell-rmjpze', - rowspan: '1', - colspan: '1' - } - }, - { - insert: '\n', - attributes: { 'block-id': 'block-21099df0-afb2-4cd3-834d-bb37800eb06a' } - } - ] + cell: 'cell-rmjpze' + }, + row: 'row-5bqfil', + cell: 'cell-rmjpze', + rowspan: '1', + colspan: '1' + }) + .insert('\n', { 'block-id': 'block-21099df0-afb2-4cd3-834d-bb37800eb06a' }) const ydoc = new Y.Doc() const ytext = ydoc.getText('id') ytext.applyDelta(initialContent) - const changeEvent = [ - { retain: 90 }, - { delete: 4 }, - { - retain: 1, - attributes: { - layout: null, - 'layout-width': null, - 'block-id': 'block-9d6566a1-be55-4e20-999a-b990bc15e143' - } - } - ] + const changeEvent = delta.create().retain(90).delete(4).retain(1, { + layout: null, + 'layout-width': null, + 'block-id': 'block-9d6566a1-be55-4e20-999a-b990bc15e143' + }) ytext.applyDelta(changeEvent) - const delta = ytext.getContent() - t.compare(delta.ops[40].toJSON(), { + const d = ytext.getContent() + t.compare(list.toArray(d.children)[40].toJSON(), { insert: '\n', - attributes: { + format: { 'block-id': 'block-9d6566a1-be55-4e20-999a-b990bc15e143' } }) @@ -1552,12 +1241,12 @@ export const testDeltaAfterConcurrentFormatting = tc => { */ const deltas = [] text1.observe(event => { - if (event.delta.ops.length > 0) { + if (event.delta.children.len > 0) { deltas.push(event.delta.toJSON()) } }) testConnector.flushAllMessages() - t.compare(deltas, [[{ retain: 2, attributes: { bold: true } }, { retain: 1 }, { retain: 1, attributes: { bold: null } }]]) + t.compare(deltas, [[{ retain: 2, format: { bold: true } }, { retain: 1 }, { retain: 1, format: { bold: null } }]]) } /** @@ -1576,21 +1265,21 @@ export const testBasicInsertAndDelete = tc => { text0.insert(0, 'abc') t.assert(text0.toString() === 'abc', 'Basic insert works') - t.compare(eventDelta, delta.createTextDelta().insert('abc')) + t.compare(eventDelta, delta.create().insert('abc')) text0.delete(0, 1) t.assert(text0.toString() === 'bc', 'Basic delete works (position 0)') - t.compare(eventDelta, delta.createTextDelta().delete(1)) + t.compare(eventDelta, delta.create().delete(1)) text0.delete(1, 1) t.assert(text0.toString() === 'b', 'Basic delete works (position 1)') - t.compare(eventDelta, delta.createTextDelta().retain(1).delete(1)) + t.compare(eventDelta, delta.create().retain(1).delete(1)) users[0].transact(() => { text0.insert(0, '1') text0.delete(0, 1) }) - t.compare(eventDelta, delta.createTextDelta()) + t.compare(eventDelta, delta.create()) compare(users) } @@ -1606,30 +1295,30 @@ export const testBasicFormat = tc => { }) text0.insert(0, 'abc', { bold: true }) t.assert(text0.toString() === 'abc', 'Basic insert with attributes works') - t.compare(text0.getContent(), delta.createTextDelta().insert('abc', { bold: true }).done()) - t.compare(eventDelta, delta.createTextDelta().insert('abc', { bold: true })) + t.compare(text0.getContent(), delta.create().insert('abc', { bold: true })) + t.compare(eventDelta, delta.create().insert('abc', { bold: true })) text0.delete(0, 1) t.assert(text0.toString() === 'bc', 'Basic delete on formatted works (position 0)') - t.compare(text0.getContent(), delta.createTextDelta().insert('bc', { bold: true })) - t.compare(eventDelta, delta.createTextDelta().delete(1)) + t.compare(text0.getContent(), delta.create().insert('bc', { bold: true })) + t.compare(eventDelta, delta.create().delete(1)) text0.delete(1, 1) t.assert(text0.toString() === 'b', 'Basic delete works (position 1)') - t.compare(text0.getContent(), delta.createTextDelta().insert('b', { bold: true })) - t.compare(eventDelta, delta.createTextDelta().retain(1).delete(1)) + t.compare(text0.getContent(), delta.create().insert('b', { bold: true })) + t.compare(eventDelta, delta.create().retain(1).delete(1)) text0.insert(0, 'z', { bold: true }) t.assert(text0.toString() === 'zb') - t.compare(text0.getContent(), delta.createTextDelta().insert('zb', { bold: true })) - t.compare(eventDelta, delta.createTextDelta().insert('z', { bold: true })) + t.compare(text0.getContent(), delta.create().insert('zb', { bold: true })) + t.compare(eventDelta, delta.create().insert('z', { bold: true })) // @ts-ignore t.assert(text0._start.right.right.right.content.str === 'b', 'Does not insert duplicate attribute marker') text0.insert(0, 'y') t.assert(text0.toString() === 'yzb') - t.compare(text0.getContent(), delta.createTextDelta().insert('y').insert('zb', { bold: true })) - t.compare(eventDelta, delta.createTextDelta().insert('y')) + t.compare(text0.getContent(), delta.create().insert('y').insert('zb', { bold: true })) + t.compare(eventDelta, delta.create().insert('y')) text0.format(0, 2, { bold: null }) t.assert(text0.toString() === 'yzb') - t.compare(text0.getContent(), delta.createTextDelta().insert('yz').insert('b', { bold: true })) - t.compare(eventDelta, delta.createTextDelta().retain(1).retain(1, { bold: null })) + t.compare(text0.getContent(), delta.create().insert('yz').insert('b', { bold: true })) + t.compare(eventDelta, delta.create().retain(1).retain(1, { bold: null })) compare(users) } @@ -1638,19 +1327,19 @@ export const testBasicFormat = tc => { */ export const testFalsyFormats = tc => { const { users, text0 } = init(tc, { users: 2 }) - let delta + let delta = text0.getContent().toJSON().children text0.observe(event => { - delta = event.delta.toJSON() + delta = event.delta.toJSON().children }) text0.insert(0, 'abcde', { falsy: false }) - t.compare(text0.getContent().toJSON(), [{ insert: 'abcde', attributes: { falsy: false } }]) - t.compare(delta, [{ insert: 'abcde', attributes: { falsy: false } }]) + t.compare(text0.getContent().toJSON().children, [{ insert: 'abcde', format: { falsy: false } }]) + t.compare(delta, [{ insert: 'abcde', format: { falsy: false } }]) text0.format(1, 3, { falsy: true }) - t.compare(text0.getContent().toJSON(), [{ insert: 'a', attributes: { falsy: false } }, { insert: 'bcd', attributes: { falsy: true } }, { insert: 'e', attributes: { falsy: false } }]) - t.compare(delta, [{ retain: 1 }, { retain: 3, attributes: { falsy: true } }]) + t.compare(text0.getContent().toJSON().children, [{ insert: 'a', format: { falsy: false } }, { insert: 'bcd', format: { falsy: true } }, { insert: 'e', format: { falsy: false } }]) + t.compare(delta, [{ retain: 1 }, { retain: 3, format: { falsy: true } }]) text0.format(2, 1, { falsy: false }) - t.compare(text0.getContent().toJSON(), [{ insert: 'a', attributes: { falsy: false } }, { insert: 'b', attributes: { falsy: true } }, { insert: 'c', attributes: { falsy: false } }, { insert: 'd', attributes: { falsy: true } }, { insert: 'e', attributes: { falsy: false } }]) - t.compare(delta, [{ retain: 2 }, { retain: 1, attributes: { falsy: false } }]) + t.compare(text0.getContent().toJSON().children, [{ insert: 'a', format: { falsy: false } }, { insert: 'b', format: { falsy: true } }, { insert: 'c', format: { falsy: false } }, { insert: 'd', format: { falsy: true } }, { insert: 'e', format: { falsy: false } }]) + t.compare(delta, [{ retain: 2 }, { retain: 1, format: { falsy: false } }]) compare(users) } @@ -1661,19 +1350,19 @@ export const testMultilineFormat = _tc => { const ydoc = new Y.Doc() const testText = ydoc.getText('test') testText.insert(0, 'Test\nMulti-line\nFormatting') - testText.applyDelta([ - { retain: 4, attributes: { bold: true } }, - { retain: 1 }, // newline character - { retain: 10, attributes: { bold: true } }, - { retain: 1 }, // newline character - { retain: 10, attributes: { bold: true } } - ]) - t.compare(testText.getContent().toJSON(), [ - { insert: 'Test', attributes: { bold: true } }, + const tt = delta.create() + .retain(4, { bold: true }) + .retain(1) // newline character + .retain(10, { bold: true }) + .retain(1) // newline character + .retain(10, { bold: true }) + testText.applyDelta(tt) + t.compare(testText.getContent().toJSON().children, [ + { insert: 'Test', format: { bold: true } }, { insert: '\n' }, - { insert: 'Multi-line', attributes: { bold: true } }, + { insert: 'Multi-line', format: { bold: true } }, { insert: '\n' }, - { insert: 'Formatting', attributes: { bold: true } } + { insert: 'Formatting', format: { bold: true } } ]) } @@ -1683,17 +1372,17 @@ export const testMultilineFormat = _tc => { export const testNotMergeEmptyLinesFormat = _tc => { const ydoc = new Y.Doc() const testText = ydoc.getText('test') - testText.applyDelta([ + testText.applyDelta(delta.create() + .insert('Text') + .insert('\n', { title: true }) + .insert('\nText') + .insert('\n', { title: true }) + ) + t.compare(testText.getContent().toJSON().children, [ { insert: 'Text' }, - { insert: '\n', attributes: { title: true } }, + { insert: '\n', format: { title: true } }, { insert: '\nText' }, - { insert: '\n', attributes: { title: true } } - ]) - t.compare(testText.getContent().toJSON(), [ - { insert: 'Text' }, - { insert: '\n', attributes: { title: true } }, - { insert: '\nText' }, - { insert: '\n', attributes: { title: true } } + { insert: '\n', format: { title: true } } ]) } @@ -1703,19 +1392,19 @@ export const testNotMergeEmptyLinesFormat = _tc => { export const testPreserveAttributesThroughDelete = _tc => { const ydoc = new Y.Doc() const testText = ydoc.getText('test') - testText.applyDelta([ + testText.applyDelta(delta.create() + .insert('Text') + .insert('\n', { title: true }) + .insert('\n') + ) + testText.applyDelta(delta.create() + .retain(4) + .delete(1) + .retain(1, { title: true }) + ) + t.compare(testText.getContent().toJSON().children, [ { insert: 'Text' }, - { insert: '\n', attributes: { title: true } }, - { insert: '\n' } - ]) - testText.applyDelta([ - { retain: 4 }, - { delete: 1 }, - { retain: 1, attributes: { title: true } } - ]) - t.compare(testText.getContent().toJSON(), [ - { insert: 'Text' }, - { insert: '\n', attributes: { title: true } } + { insert: '\n', format: { title: true } } ]) } @@ -1724,11 +1413,9 @@ export const testPreserveAttributesThroughDelete = _tc => { */ export const testGetDeltaWithEmbeds = tc => { const { text0 } = init(tc, { users: 1 }) - text0.applyDelta([{ - insert: { linebreak: 's' } - }]) - t.compare(text0.getContent().toJSON(), [{ - insert: { linebreak: 's' } + text0.applyDelta(delta.create().insert([{ linebreak: 's' }])) + t.compare(text0.getContent().toJSON().children, [{ + insert: [{ linebreak: 's' }] }]) } @@ -1737,21 +1424,21 @@ export const testGetDeltaWithEmbeds = tc => { */ export const testTypesAsEmbed = tc => { const { text0, text1, testConnector } = init(tc, { users: 2 }) - text0.applyDelta([{ - insert: new Y.Map([['key', 'val']]) - }]) - t.compare(/** @type {delta.InsertEmbedOp} */ (text0.getContent().ops[0]).insert.toJSON(), { key: 'val' }) + text0.applyDelta(delta.create() + .insert([new Y.Map([['key', 'val']])]) + ) + t.compare(/** @type {any} */ (text0).getContentDeep().toJSON().children[0]?.insert, { key: 'val' }) let firedEvent = false text1.observe(event => { const d = event.delta - t.assert(d.ops.length === 1) - t.compare(d.ops.map(x => /** @type {any} */ (x).insert.toJSON()), [{ key: 'val' }]) + t.assert(d.children.len === 1) + t.compare(list.toArray(d.children).map(x => /** @type {any} */ (x).insert.toJSON()), [{ key: 'val' }]) firedEvent = true }) testConnector.flushAllMessages() - const delta = text1.getContent().toJSON() - t.assert(delta.length === 1) - t.compare(/** @type {any} */ (delta[0]).insert.toJSON(), { key: 'val' }) + const dd = text1.getContent().toJSON().children + t.assert(dd?.length === 1) + t.compare(/** @type {any} */ (dd?.[0]).insert.toJSON(), { key: 'val' }) t.assert(firedEvent, 'fired the event observer containing a Type-Embed') } @@ -1762,32 +1449,24 @@ export const testSnapshot = tc => { const { text0 } = init(tc, { users: 1 }) const doc0 = /** @type {Y.Doc} */ (text0.doc) doc0.gc = false - text0.applyDelta([{ - insert: 'abcd' - }]) + text0.applyDelta(delta.create().insert('abcd')) const snapshot1 = Y.snapshot(doc0) - text0.applyDelta([{ - retain: 1 - }, { - insert: 'x' - }, { - delete: 1 - }]) + text0.applyDelta(delta.create() + .retain(1) + .insert('x') + .delete(1)) const snapshot2 = Y.snapshot(doc0) - text0.applyDelta([{ - retain: 2 - }, { - delete: 3 - }, { - insert: 'x' - }, { - delete: 1 - }]) + text0.applyDelta(delta.create() + .retain(2) + .delete(3) + .insert('x') + .delete(1) + ) const state1 = text0.getContent(createAttributionManagerFromSnapshots(snapshot1)) - t.compare(state1.toJSON(), [{ insert: 'abcd' }]) + t.compare(state1.toJSON().children, [{ insert: 'abcd' }]) const state2 = text0.getContent(createAttributionManagerFromSnapshots(snapshot2)) - t.compare(state2.toJSON(), [{ insert: 'axcd' }]) - const state2Diff = text0.getContent(createAttributionManagerFromSnapshots(snapshot1, snapshot2)).toJSON() + t.compare(state2.toJSON().children, [{ insert: 'axcd' }]) + const state2Diff = text0.getContent(createAttributionManagerFromSnapshots(snapshot1, snapshot2)).toJSON().children const expected = [{ insert: 'a' }, { insert: 'x', attribution: { insert: [] } }, { insert: 'b', attribution: { delete: [] } }, { insert: 'cd' }] t.compare(state2Diff, expected) } @@ -1799,17 +1478,16 @@ export const testSnapshotDeleteAfter = tc => { const { text0 } = init(tc, { users: 1 }) const doc0 = /** @type {Y.Doc} */ (text0.doc) doc0.gc = false - text0.applyDelta([{ - insert: 'abcd' - }]) + text0.applyDelta(delta.create() + .insert('abcd') + ) const snapshot1 = Y.snapshot(doc0) - text0.applyDelta([{ - retain: 4 - }, { - insert: 'e' - }]) + text0.applyDelta(delta.create() + .retain(4) + .insert('e') + ) const state1 = text0.getContent(createAttributionManagerFromSnapshots(snapshot1)) - t.compare(state1, delta.createTextDelta().insert('abcd')) + t.compare(state1, delta.create().insert('abcd')) } /** @@ -1828,8 +1506,8 @@ export const testToDeltaEmbedAttributes = tc => { const { text0 } = init(tc, { users: 1 }) text0.insert(0, 'ab', { bold: true }) text0.insertEmbed(1, { image: 'imageSrc.png' }, { width: 100 }) - const delta0 = text0.getContent().toJSON() - t.compare(delta0, [{ insert: 'a', attributes: { bold: true } }, { insert: { image: 'imageSrc.png' }, attributes: { width: 100 } }, { insert: 'b', attributes: { bold: true } }]) + const delta0 = text0.getContent().toJSON().children + t.compare(delta0, [{ insert: 'a', format: { bold: true } }, { insert: [{ image: 'imageSrc.png' }], format: { width: 100 } }, { insert: 'b', format: { bold: true } }]) } /** @@ -1839,8 +1517,8 @@ export const testToDeltaEmbedNoAttributes = tc => { const { text0 } = init(tc, { users: 1 }) text0.insert(0, 'ab', { bold: true }) text0.insertEmbed(1, { image: 'imageSrc.png' }) - const delta0 = text0.getContent().toJSON() - t.compare(delta0, [{ insert: 'a', attributes: { bold: true } }, { insert: { image: 'imageSrc.png' } }, { insert: 'b', attributes: { bold: true } }], 'toDelta does not set attributes key when no attributes are present') + const delta0 = text0.getContent().toJSON().children + t.compare(delta0, [{ insert: 'a', format: { bold: true } }, { insert: [{ image: 'imageSrc.png' }] }, { insert: 'b', format: { bold: true } }], 'toDelta does not set attributes key when no attributes are present') } /** @@ -1880,7 +1558,7 @@ export const testFormattingDeltaUnnecessaryAttributeChange = tc => { }) testConnector.flushAllMessages() /** - * @type {Array>} + * @type {Array>} */ const deltas = [] text0.observe(event => { @@ -1891,10 +1569,10 @@ export const testFormattingDeltaUnnecessaryAttributeChange = tc => { }) text1.format(0, 1, { LIST_STYLES: 'number' }) testConnector.flushAllMessages() - const filteredDeltas = deltas.filter(d => d.ops.length > 0) + const filteredDeltas = deltas.filter(d => d.children.len > 0) t.assert(filteredDeltas.length === 2) - t.compare(filteredDeltas[0].toJSON(), [ - { retain: 1, attributes: { LIST_STYLES: 'number' } } + t.compare(filteredDeltas[0].toJSON().children, [ + { retain: 1, format: { LIST_STYLES: 'number' } } ]) t.compare(filteredDeltas[0], filteredDeltas[1]) } @@ -2143,11 +1821,11 @@ export const testFormattingBug = async _tc => { Y.applyUpdate(ydoc2, Y.encodeStateAsUpdate(ydoc1)) const text2 = ydoc2.getText() const expectedResult = [ - { insert: '\n', attributes: { url: 'http://example.com' } }, - { insert: '\n', attributes: { url: 'http://docs.yjs.dev' } }, - { insert: '\n', attributes: { url: 'http://example.com' } } + { insert: '\n', format: { url: 'http://example.com' } }, + { insert: '\n', format: { url: 'http://docs.yjs.dev' } }, + { insert: '\n', format: { url: 'http://example.com' } } ] - t.compare(text1.getContent().toJSON(), expectedResult) + t.compare(text1.getContent().toJSON().children, expectedResult) t.compare(text1.getContent().toJSON(), text2.getContent().toJSON()) console.log(text1.getContent().toJSON()) } @@ -2174,11 +1852,11 @@ export const testDeleteFormatting = _tc => { const expected = [ { insert: 'Attack ships ' }, - { insert: 'on ', attributes: { bold: true } }, + { insert: 'on ', format: { bold: true } }, { insert: 'fire off the shoulder of Orion.' } ] - t.compare(text.getContent().toJSON(), expected) - t.compare(text2.getContent().toJSON(), expected) + t.compare(text.getContent().toJSON().children, expected) + t.compare(text2.getContent().toJSON().children, expected) } /** @@ -2195,15 +1873,15 @@ export const testAttributedContent = _tc => { attributionManager = new TwosetAttributionManager(createIdMapFromIdSet(tr.insertSet, []), createIdMapFromIdSet(tr.deleteSet, [])) }) t.group('insert / delete / format', () => { - ytext.applyDelta([{ retain: 4, attributes: { italic: true } }, { retain: 2 }, { delete: 5 }, { insert: 'attributions' }]) - const expectedContent = delta.createTextDelta().insert('Hell', { italic: true }, { attributes: { italic: [] } }).insert('o ').insert('World', {}, { delete: [] }).insert('attributions', {}, { insert: [] }).insert('!') + ytext.applyDelta(delta.create().retain(4, { italic: true }).retain(2).delete(5).insert('attributions')) + const expectedContent = delta.create().insert('Hell', { italic: true }, { format: { italic: [] } }).insert('o ').insert('World', {}, { delete: [] }).insert('attributions', {}, { insert: [] }).insert('!') const attributedContent = ytext.getContent(attributionManager) console.log(attributedContent.toJSON()) t.assert(attributedContent.equals(expectedContent)) }) t.group('unformat', () => { - ytext.applyDelta([{ retain: 5, attributes: { italic: null } }]) - const expectedContent = delta.createTextDelta().insert('Hell', null, { attributes: { italic: [] } }).insert('o attributions!') + ytext.applyDelta(delta.create().retain(5, { italic: null })) + const expectedContent = delta.create().insert('Hell', null, { format: { italic: [] } }).insert('o attributions!') const attributedContent = ytext.getContent(attributionManager) console.log(attributedContent.toJSON()) t.assert(attributedContent.equals(expectedContent)) @@ -2221,7 +1899,7 @@ export const testAttributedDiffing = _tc => { ydoc.clientID = 1 Y.applyUpdate(ydoc, Y.encodeStateAsUpdate(ydocVersion0)) const ytext = ydoc.getText() - ytext.applyDelta([{ retain: 4, attributes: { italic: true } }, { retain: 2 }, { delete: 5 }, { insert: 'attributions' }]) + ytext.applyDelta(delta.create().retain(4, { italic: true }).retain(2).delete(5).insert('attributions')) // this represents to all insertions of ydoc const insertionSet = Y.createInsertionSetFromStructStore(ydoc.store, false) const deleteSet = Y.createDeleteSetFromStructStore(ydoc.store) @@ -2237,7 +1915,7 @@ export const testAttributedDiffing = _tc => { // we render the attributed content with the attributionManager const attributedContent = ytext.getContent(attributionManager) console.log(JSON.stringify(attributedContent.toJSON(), null, 2)) - const expectedContent = delta.createTextDelta().insert('Hell', { italic: true }, { attributes: { italic: ['Bob'] } }).insert('o ').insert('World', {}, { delete: ['Bob'] }).insert('attributions', {}, { insert: ['Bob'] }).insert('!') + 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)) console.log(Y.encodeIdMap(attributedInsertions).length) } @@ -2414,12 +2092,9 @@ const qChanges = [ const ytext = y.getText('text') const insertPos = prng.int32(gen, 0, ytext.toString().length) const text = charCounter++ + prng.word(gen) - const ops = [] - if (insertPos > 0) { - ops.push({ retain: insertPos }) - } - ops.push({ insert: text }, { insert: '\n', format: { 'code-block': true } }) - ytext.applyDelta(ops) + const d = delta.create() + d.retain(insertPos).insert(text).insert('\n', { 'code-block': true }) + ytext.applyDelta(d) }, /** * @param {Y.Doc} y @@ -2429,32 +2104,29 @@ const qChanges = [ const ytext = y.getText('text') const contentLen = ytext.toString().length let currentPos = math.max(0, prng.int32(gen, 0, contentLen - 1)) - /** - * @type {Array} - */ - const ops = currentPos > 0 ? [{ retain: currentPos }] : [] + const d = delta.create().retain(currentPos) // create max 3 ops for (let i = 0; i < 7 && currentPos < contentLen; i++) { prng.oneOf(gen, [ () => { // format const retain = math.min(prng.int32(gen, 0, contentLen - currentPos), 5) const format = prng.oneOf(gen, marks) - ops.push({ retain, attributes: format }) + d.retain(retain, format) currentPos += retain }, () => { // insert const attrs = prng.oneOf(gen, marksChoices) const text = prng.word(gen, 1, 3) - ops.push({ insert: text, attributes: attrs }) + d.insert(text, attrs) }, () => { // delete const delLen = math.min(prng.int32(gen, 0, contentLen - currentPos), 10) - ops.push({ delete: delLen }) + d.delete(delLen) currentPos += delLen } ])() } - ytext.applyDelta(ops) + ytext.applyDelta(d) } ] @@ -2463,20 +2135,9 @@ const qChanges = [ */ const checkResult = result => { for (let i = 1; i < result.testObjects.length; i++) { - /** - * @param {any} d - */ - const typeToObject = d => d.insert instanceof Y.AbstractType ? d.insert.toJSON() : d - t.info('length of text = ' + result.users[i - 1].getText('text').length) - t.measureTime('original toDelta perf', () => { - result.users[i - 1].getText('text').getContent().toJSON().map(typeToObject) - }) - t.measureTime('getContent(attributionManager) performance)', () => { - result.users[i - 1].getText('text').getContent() - }) - const p1 = result.users[i - 1].getText('text').getContent().toJSON().map(typeToObject) - const p2 = result.users[i].getText('text').getContent().toJSON().map(typeToObject) + const p1 = result.users[i - 1].getText('text').getContentDeep().children + const p2 = result.users[i].getText('text').getContentDeep().children t.compare(p1, p2) } // Uncomment this to find formatting-cleanup issues diff --git a/tsconfig.json b/tsconfig.json index 71beb314..e69f7652 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -20,5 +20,5 @@ } }, "include": ["./src/**/*.js", "./tests/**/*.js"], - "exclude": ["../lib0/**"] + "exclude": ["./node_modules/**/*"] }