Compare commits

...

10 Commits

Author SHA1 Message Date
Kevin Jahns
e90d9de5ed 13.5.22 2021-11-19 13:48:52 +01:00
Kevin Jahns
9a7250f192 fix undoing of content containing subdocs 2021-11-19 13:47:10 +01:00
Kevin Jahns
4154b12f14 handle local/remote autoload edge cases 2021-11-19 13:27:14 +01:00
Kevin Jahns
9df5016667 13.5.21 2021-11-15 14:00:04 +01:00
Kevin Jahns
1becaccdd9 bump lib0 dependency for bugfix dmonad/lib0#34 2021-11-15 13:58:22 +01:00
Kevin Jahns
ea4e9a0007 change order of logging statement for debugging 2021-11-14 13:10:52 +01:00
Kevin Jahns
a4e48d1ddf 13.5.20 2021-11-09 16:53:35 +01:00
Kevin Jahns
0a39a92b33 export testHelper 2021-11-09 16:51:54 +01:00
Kevin Jahns
bd819243eb 13.5.19 2021-11-09 16:39:58 +01:00
Kevin Jahns
2ec19defcb export testHelper esm properly 2021-11-06 15:55:59 +01:00
14 changed files with 211 additions and 86 deletions

14
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "yjs",
"version": "13.5.18",
"version": "13.5.22",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -1711,9 +1711,9 @@
}
},
"lib0": {
"version": "0.2.42",
"resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.42.tgz",
"integrity": "sha512-8BNM4MiokEKzMvSxTOC3gnCBisJH+jL67CnSnqzHv3jli3pUvGC8wz+0DQ2YvGr4wVQdb2R2uNNPw9LEpVvJ4Q==",
"version": "0.2.43",
"resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.43.tgz",
"integrity": "sha512-MJ1KLoz5p3gljIUBfdjjNuL/wlWHHK6+DrcIRhzSRLvtAu1XNdRtRGATYM51KSTI0P2nxJZFQM8rwCH6ga9KUw==",
"requires": {
"isomorphic.js": "^0.2.4"
}
@@ -2494,9 +2494,9 @@
}
},
"rollup": {
"version": "2.58.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.58.0.tgz",
"integrity": "sha512-NOXpusKnaRpbS7ZVSzcEXqxcLDOagN6iFS8p45RkoiMqPHDLwJm758UF05KlMoCRbLBTZsPOIa887gZJ1AiXvw==",
"version": "2.60.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.60.0.tgz",
"integrity": "sha512-cHdv9GWd58v58rdseC8e8XIaPUo8a9cgZpnCMMDGZFDZKEODOiPPEQFXLriWr/TjXzhPPmG5bkAztPsOARIcGQ==",
"dev": true,
"requires": {
"fsevents": "~2.3.2"

View File

@@ -1,10 +1,11 @@
{
"name": "yjs",
"version": "13.5.18",
"version": "13.5.22",
"description": "Shared Editing Library",
"main": "./dist/yjs.cjs",
"module": "./dist/yjs.mjs",
"types": "./dist/src/index.d.ts",
"type": "module",
"sideEffects": false,
"funding": {
"type": "GitHub Sponsors ❤",
@@ -31,6 +32,7 @@
},
"./src/index.js": "./src/index.js",
"./tests/testHelper.js": "./tests/testHelper.js",
"./testHelper": "./dist/testHelper.mjs",
"./package.json": "./package.json"
},
"files": [
@@ -38,6 +40,7 @@
"dist/src",
"src",
"tests/testHelper.js",
"dist/testHelper.mjs",
"sponsor-y.js"
],
"dictionaries": {
@@ -71,7 +74,7 @@
},
"homepage": "https://docs.yjs.dev",
"dependencies": {
"lib0": "^0.2.42"
"lib0": "^0.2.43"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^17.0.0",
@@ -80,7 +83,7 @@
"http-server": "^0.12.3",
"jsdoc": "^3.6.7",
"markdownlint-cli": "^0.23.2",
"rollup": "^2.58.0",
"rollup": "^2.60.0",
"standard": "^16.0.4",
"tui-jsdoc-template": "^1.2.2",
"typescript": "^4.4.4",

View File

@@ -60,6 +60,23 @@ export default [{
sourcemap: true
},
external: id => /^lib0\//.test(id)
}, {
input: './tests/testHelper.js',
output: {
name: 'Y',
file: 'dist/testHelper.mjs',
format: 'esm',
sourcemap: true
},
external: id => /^lib0\//.test(id) || id === 'yjs',
plugins: [{
resolveId (importee) {
if (importee === '../src/index.js') {
return 'yjs'
}
return null
}
}]
}, {
input: './tests/index.js',
output: {

View File

@@ -27,12 +27,13 @@ export {
ContentString,
ContentType,
AbstractType,
RelativePosition,
getTypeChildren,
createRelativePositionFromTypeIndex,
createRelativePositionFromJSON,
createAbsolutePositionFromRelativePosition,
compareRelativePositions,
AbsolutePosition,
RelativePosition,
ID,
createID,
compareIDs,
@@ -41,6 +42,7 @@ export {
createSnapshot,
createDeleteSet,
createDeleteSetFromStructStore,
cleanupYTextFormatting,
snapshot,
emptySnapshot,
findRootTypeKey,

View File

@@ -5,6 +5,12 @@ import {
import * as error from 'lib0/error'
/**
* @param {string} guid
* @param {Object<string, any>} opts
*/
const createDocFromOpts = (guid, opts) => new Doc({ guid, ...opts, shouldLoad: opts.shouldLoad || opts.autoLoad || false })
/**
* @private
*/
@@ -61,7 +67,7 @@ export class ContentDoc {
* @return {ContentDoc}
*/
copy () {
return new ContentDoc(this.doc)
return new ContentDoc(createDocFromOpts(this.doc.guid, this.opts))
}
/**
@@ -132,4 +138,4 @@ export class ContentDoc {
* @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
* @return {ContentDoc}
*/
export const readContentDoc = decoder => new ContentDoc(new Doc({ guid: decoder.readString(), ...decoder.readAny() }))
export const readContentDoc = decoder => new ContentDoc(createDocFromOpts(decoder.readString(), decoder.readAny()))

View File

@@ -28,6 +28,7 @@ export const generateNewClientId = random.uint32
* @property {string | null} [DocOpts.collectionid] Associate this document with a collection. This only plays a role if your provider has a concept of collection.
* @property {any} [DocOpts.meta] Any kind of meta information you want to associate with this document. If this is a subdocument, remote peers will store the meta information as well.
* @property {boolean} [DocOpts.autoLoad] If a subdocument, automatically load document. If this is a subdocument, remote peers will load the document as well automatically.
* @property {boolean} [DocOpts.shouldLoad] Whether the document should be synced by the provider now. This is toggled to true when you call ydoc.load()
*/
/**
@@ -38,7 +39,7 @@ export class Doc extends Observable {
/**
* @param {DocOpts} [opts] configuration
*/
constructor ({ guid = random.uuidv4(), collectionid = null, gc = true, gcFilter = () => true, meta = null, autoLoad = false } = {}) {
constructor ({ guid = random.uuidv4(), collectionid = null, gc = true, gcFilter = () => true, meta = null, autoLoad = false, shouldLoad = true } = {}) {
super()
this.gc = gc
this.gcFilter = gcFilter
@@ -67,7 +68,7 @@ export class Doc extends Observable {
* @type {Item?}
*/
this._item = null
this.shouldLoad = autoLoad
this.shouldLoad = shouldLoad
this.autoLoad = autoLoad
this.meta = meta
}
@@ -248,16 +249,12 @@ export class Doc extends Observable {
if (item !== null) {
this._item = null
const content = /** @type {ContentDoc} */ (item.content)
if (item.deleted) {
// @ts-ignore
content.doc = null
} else {
content.doc = new Doc({ guid: this.guid, ...content.opts })
content.doc._item = item
}
content.doc = new Doc({ guid: this.guid, ...content.opts, shouldLoad: false })
content.doc._item = item
transact(/** @type {any} */ (item).parent.doc, transaction => {
const doc = content.doc
if (!item.deleted) {
transaction.subdocsAdded.add(content.doc)
transaction.subdocsAdded.add(doc)
}
transaction.subdocsRemoved.add(this)
}, null, true)

View File

@@ -331,8 +331,8 @@ const cleanupTransactions = (transactionCleanups, i) => {
}
}
if (!transaction.local && transaction.afterState.get(doc.clientID) !== transaction.beforeState.get(doc.clientID)) {
doc.clientID = generateNewClientId()
logging.print(logging.ORANGE, logging.BOLD, '[yjs] ', logging.UNBOLD, logging.RED, 'Changed the client-id because another client seems to be using it.')
doc.clientID = generateNewClientId()
}
// @todo Merge all the transactions into one and provide send the data as a single update message
doc.emit('afterTransactionCleanup', [transaction, doc])

View File

@@ -601,7 +601,7 @@ export const decodeStateVector = decodedState => readStateVector(new DSDecoderV1
*/
export const writeStateVector = (encoder, sv) => {
encoding.writeVarUint(encoder.restEncoder, sv.size)
sv.forEach((clock, client) => {
Array.from(sv.entries()).sort((a, b) => b[0] - a[0]).forEach(([client, clock]) => {
encoding.writeVarUint(encoder.restEncoder, client) // @todo use a special client decoder that is based on mapping
encoding.writeVarUint(encoder.restEncoder, clock)
})

View File

@@ -88,7 +88,7 @@ export const testSubdoc = tc => {
subdocs.get('a').load()
t.compare(event, [[], [], ['a']])
subdocs.set('b', new Y.Doc({ guid: 'a' }))
subdocs.set('b', new Y.Doc({ guid: 'a', shouldLoad: false }))
t.compare(event, [['a'], [], []])
subdocs.get('b').load()
t.compare(event, [[], [], ['a']])
@@ -124,3 +124,107 @@ export const testSubdoc = tc => {
t.compare(Array.from(doc2.getSubdocGuids()), ['a', 'c'])
}
}
/**
* @param {t.TestCase} tc
*/
export const testSubdocLoadEdgeCases = tc => {
const ydoc = new Y.Doc()
const yarray = ydoc.getArray()
const subdoc1 = new Y.Doc()
/**
* @type {any}
*/
let lastEvent = null
ydoc.on('subdocs', event => {
lastEvent = event
})
yarray.insert(0, [subdoc1])
t.assert(subdoc1.shouldLoad)
t.assert(subdoc1.autoLoad === false)
t.assert(lastEvent !== null && lastEvent.loaded.has(subdoc1))
t.assert(lastEvent !== null && lastEvent.added.has(subdoc1))
// destroy and check whether lastEvent adds it again to added (it shouldn't)
subdoc1.destroy()
const subdoc2 = yarray.get(0)
t.assert(subdoc1 !== subdoc2)
t.assert(lastEvent !== null && lastEvent.added.has(subdoc2))
t.assert(lastEvent !== null && !lastEvent.loaded.has(subdoc2))
// load
subdoc2.load()
t.assert(lastEvent !== null && !lastEvent.added.has(subdoc2))
t.assert(lastEvent !== null && lastEvent.loaded.has(subdoc2))
// apply from remote
const ydoc2 = new Y.Doc()
ydoc2.on('subdocs', event => {
lastEvent = event
})
Y.applyUpdate(ydoc2, Y.encodeStateAsUpdate(ydoc))
const subdoc3 = ydoc2.getArray().get(0)
t.assert(subdoc3.shouldLoad === false)
t.assert(subdoc3.autoLoad === false)
t.assert(lastEvent !== null && lastEvent.added.has(subdoc3))
t.assert(lastEvent !== null && !lastEvent.loaded.has(subdoc3))
// load
subdoc3.load()
t.assert(subdoc3.shouldLoad)
t.assert(lastEvent !== null && !lastEvent.added.has(subdoc3))
t.assert(lastEvent !== null && lastEvent.loaded.has(subdoc3))
}
/**
* @param {t.TestCase} tc
*/
export const testSubdocLoadEdgeCasesAutoload = tc => {
const ydoc = new Y.Doc()
const yarray = ydoc.getArray()
const subdoc1 = new Y.Doc({ autoLoad: true })
/**
* @type {any}
*/
let lastEvent = null
ydoc.on('subdocs', event => {
lastEvent = event
})
yarray.insert(0, [subdoc1])
t.assert(subdoc1.shouldLoad)
t.assert(subdoc1.autoLoad)
t.assert(lastEvent !== null && lastEvent.loaded.has(subdoc1))
t.assert(lastEvent !== null && lastEvent.added.has(subdoc1))
// destroy and check whether lastEvent adds it again to added (it shouldn't)
subdoc1.destroy()
const subdoc2 = yarray.get(0)
t.assert(subdoc1 !== subdoc2)
t.assert(lastEvent !== null && lastEvent.added.has(subdoc2))
t.assert(lastEvent !== null && !lastEvent.loaded.has(subdoc2))
// load
subdoc2.load()
t.assert(lastEvent !== null && !lastEvent.added.has(subdoc2))
t.assert(lastEvent !== null && lastEvent.loaded.has(subdoc2))
// apply from remote
const ydoc2 = new Y.Doc()
ydoc2.on('subdocs', event => {
lastEvent = event
})
Y.applyUpdate(ydoc2, Y.encodeStateAsUpdate(ydoc))
const subdoc3 = ydoc2.getArray().get(0)
t.assert(subdoc1.shouldLoad)
t.assert(subdoc1.autoLoad)
t.assert(lastEvent !== null && lastEvent.added.has(subdoc3))
t.assert(lastEvent !== null && lastEvent.loaded.has(subdoc3))
}
/**
* @param {t.TestCase} tc
*/
export const testSubdocsUndo = tc => {
const ydoc = new Y.Doc()
const elems = ydoc.getXmlFragment()
const undoManager = new Y.UndoManager(elems)
const subdoc = new Y.Doc()
// @ts-ignore
elems.insert(0, [subdoc])
undoManager.undo()
undoManager.redo()
t.assert(elems.length === 1)
}

View File

@@ -1,9 +1,9 @@
import * as Y from '../src/internals'
import * as Y from '../src/index.js'
import * as t from 'lib0/testing'
/**
* @param {Y.YText} ytext
* @param {Y.Text} ytext
*/
const checkRelativePositions = ytext => {
// test if all positions are encoded and restored correctly

View File

@@ -1,17 +1,17 @@
import { createDocFromSnapshot, Doc, snapshot, YMap } from '../src/internals'
import * as Y from '../src/index.js'
import * as t from 'lib0/testing'
import { init } from './testHelper'
import { init } from './testHelper.js'
/**
* @param {t.TestCase} tc
*/
export const testBasicRestoreSnapshot = tc => {
const doc = new Doc({ gc: false })
const doc = new Y.Doc({ gc: false })
doc.getArray('array').insert(0, ['hello'])
const snap = snapshot(doc)
const snap = Y.snapshot(doc)
doc.getArray('array').insert(1, ['world'])
const docRestored = createDocFromSnapshot(doc, snap)
const docRestored = Y.createDocFromSnapshot(doc, snap)
t.compare(docRestored.getArray('array').toArray(), ['hello'])
t.compare(doc.getArray('array').toArray(), ['hello', 'world'])
@@ -21,19 +21,19 @@ export const testBasicRestoreSnapshot = tc => {
* @param {t.TestCase} tc
*/
export const testEmptyRestoreSnapshot = tc => {
const doc = new Doc({ gc: false })
const snap = snapshot(doc)
const doc = new Y.Doc({ gc: false })
const snap = Y.snapshot(doc)
snap.sv.set(9999, 0)
doc.getArray().insert(0, ['world'])
const docRestored = createDocFromSnapshot(doc, snap)
const docRestored = Y.createDocFromSnapshot(doc, snap)
t.compare(docRestored.getArray().toArray(), [])
t.compare(doc.getArray().toArray(), ['world'])
// now this snapshot reflects the latest state. It shoult still work.
const snap2 = snapshot(doc)
const docRestored2 = createDocFromSnapshot(doc, snap2)
const snap2 = Y.snapshot(doc)
const docRestored2 = Y.createDocFromSnapshot(doc, snap2)
t.compare(docRestored2.getArray().toArray(), ['world'])
}
@@ -41,15 +41,15 @@ export const testEmptyRestoreSnapshot = tc => {
* @param {t.TestCase} tc
*/
export const testRestoreSnapshotWithSubType = tc => {
const doc = new Doc({ gc: false })
doc.getArray('array').insert(0, [new YMap()])
const doc = new Y.Doc({ gc: false })
doc.getArray('array').insert(0, [new Y.Map()])
const subMap = doc.getArray('array').get(0)
subMap.set('key1', 'value1')
const snap = snapshot(doc)
const snap = Y.snapshot(doc)
subMap.set('key2', 'value2')
const docRestored = createDocFromSnapshot(doc, snap)
const docRestored = Y.createDocFromSnapshot(doc, snap)
t.compare(docRestored.getArray('array').toJSON(), [{
key1: 'value1'
@@ -64,13 +64,13 @@ export const testRestoreSnapshotWithSubType = tc => {
* @param {t.TestCase} tc
*/
export const testRestoreDeletedItem1 = tc => {
const doc = new Doc({ gc: false })
const doc = new Y.Doc({ gc: false })
doc.getArray('array').insert(0, ['item1', 'item2'])
const snap = snapshot(doc)
const snap = Y.snapshot(doc)
doc.getArray('array').delete(0)
const docRestored = createDocFromSnapshot(doc, snap)
const docRestored = Y.createDocFromSnapshot(doc, snap)
t.compare(docRestored.getArray('array').toArray(), ['item1', 'item2'])
t.compare(doc.getArray('array').toArray(), ['item2'])
@@ -80,15 +80,15 @@ export const testRestoreDeletedItem1 = tc => {
* @param {t.TestCase} tc
*/
export const testRestoreLeftItem = tc => {
const doc = new Doc({ gc: false })
const doc = new Y.Doc({ gc: false })
doc.getArray('array').insert(0, ['item1'])
doc.getMap('map').set('test', 1)
doc.getArray('array').insert(0, ['item0'])
const snap = snapshot(doc)
const snap = Y.snapshot(doc)
doc.getArray('array').delete(1)
const docRestored = createDocFromSnapshot(doc, snap)
const docRestored = Y.createDocFromSnapshot(doc, snap)
t.compare(docRestored.getArray('array').toArray(), ['item0', 'item1'])
t.compare(doc.getArray('array').toArray(), ['item0'])
@@ -98,13 +98,13 @@ export const testRestoreLeftItem = tc => {
* @param {t.TestCase} tc
*/
export const testDeletedItemsBase = tc => {
const doc = new Doc({ gc: false })
const doc = new Y.Doc({ gc: false })
doc.getArray('array').insert(0, ['item1'])
doc.getArray('array').delete(0)
const snap = snapshot(doc)
const snap = Y.snapshot(doc)
doc.getArray('array').insert(0, ['item0'])
const docRestored = createDocFromSnapshot(doc, snap)
const docRestored = Y.createDocFromSnapshot(doc, snap)
t.compare(docRestored.getArray('array').toArray(), [])
t.compare(doc.getArray('array').toArray(), ['item0'])
@@ -114,13 +114,13 @@ export const testDeletedItemsBase = tc => {
* @param {t.TestCase} tc
*/
export const testDeletedItems2 = tc => {
const doc = new Doc({ gc: false })
const doc = new Y.Doc({ gc: false })
doc.getArray('array').insert(0, ['item1', 'item2', 'item3'])
doc.getArray('array').delete(1)
const snap = snapshot(doc)
const snap = Y.snapshot(doc)
doc.getArray('array').insert(0, ['item0'])
const docRestored = createDocFromSnapshot(doc, snap)
const docRestored = Y.createDocFromSnapshot(doc, snap)
t.compare(docRestored.getArray('array').toArray(), ['item1', 'item3'])
t.compare(doc.getArray('array').toArray(), ['item0', 'item1', 'item3'])
@@ -140,11 +140,11 @@ export const testDependentChanges = tc => {
}
/**
* @type Doc
* @type {Y.Doc}
*/
const doc0 = array0.doc
/**
* @type Doc
* @type {Y.Doc}
*/
const doc1 = array1.doc
@@ -156,16 +156,16 @@ export const testDependentChanges = tc => {
array1.insert(1, ['user2item1'])
testConnector.syncAll()
const snap = snapshot(array0.doc)
const snap = Y.snapshot(array0.doc)
array0.insert(2, ['user1item2'])
testConnector.syncAll()
array1.insert(3, ['user2item2'])
testConnector.syncAll()
const docRestored0 = createDocFromSnapshot(array0.doc, snap)
const docRestored0 = Y.createDocFromSnapshot(array0.doc, snap)
t.compare(docRestored0.getArray('array').toArray(), ['user1item1', 'user2item1'])
const docRestored1 = createDocFromSnapshot(array1.doc, snap)
const docRestored1 = Y.createDocFromSnapshot(array1.doc, snap)
t.compare(docRestored1.getArray('array').toArray(), ['user1item1', 'user2item1'])
}

View File

@@ -3,10 +3,10 @@ import * as t from 'lib0/testing'
import * as prng from 'lib0/prng'
import * as encoding from 'lib0/encoding'
import * as decoding from 'lib0/decoding'
import * as syncProtocol from 'y-protocols/sync.js'
import * as syncProtocol from 'y-protocols/sync'
import * as object from 'lib0/object'
import * as Y from '../src/internals.js'
export * from '../src/internals.js'
import * as Y from '../src/index.js'
export * from '../src/index.js'
if (typeof window !== 'undefined') {
// @ts-ignore
@@ -279,7 +279,7 @@ export class TestConnector {
* @param {t.TestCase} tc
* @param {{users?:number}} conf
* @param {InitTestObjectCallback<T>} [initTestObject]
* @return {{testObjects:Array<any>,testConnector:TestConnector,users:Array<TestYInstance>,array0:Y.YArray<any>,array1:Y.YArray<any>,array2:Y.YArray<any>,map0:Y.YMap<any>,map1:Y.YMap<any>,map2:Y.YMap<any>,map3:Y.YMap<any>,text0:Y.YText,text1:Y.YText,text2:Y.YText,xml0:Y.YXmlElement,xml1:Y.YXmlElement,xml2:Y.YXmlElement}}
* @return {{testObjects:Array<any>,testConnector:TestConnector,users:Array<TestYInstance>,array0:Y.Array<any>,array1:Y.Array<any>,array2:Y.Array<any>,map0:Y.Map<any>,map1:Y.Map<any>,map2:Y.Map<any>,map3:Y.Map<any>,text0:Y.Text,text1:Y.Text,text2:Y.Text,xml0:Y.XmlElement,xml1:Y.XmlElement,xml2:Y.XmlElement}}
*/
export const init = (tc, { users = 5 } = {}, initTestObject) => {
/**
@@ -304,7 +304,7 @@ export const init = (tc, { users = 5 } = {}, initTestObject) => {
result.users.push(y)
result['array' + i] = y.getArray('array')
result['map' + i] = y.getMap('map')
result['xml' + i] = y.get('xml', Y.YXmlElement)
result['xml' + i] = y.get('xml', Y.XmlElement)
result['text' + i] = y.getText('text')
}
testConnector.syncAll()
@@ -335,7 +335,7 @@ export const compare = users => {
users.push(.../** @type {any} */(mergedDocs))
const userArrayValues = users.map(u => u.getArray('array').toJSON())
const userMapValues = users.map(u => u.getMap('map').toJSON())
const userXmlValues = users.map(u => u.get('xml', Y.YXmlElement).toString())
const userXmlValues = users.map(u => u.get('xml', Y.XmlElement).toString())
const userTextValues = users.map(u => u.getText('text').toDelta())
for (const u of users) {
t.assert(u.store.pendingDs === null)
@@ -370,7 +370,7 @@ export const compare = users => {
}
return true
})
t.compare(Y.getStateVector(users[i].store), Y.getStateVector(users[i + 1].store))
t.compare(Y.encodeStateVector(users[i]), Y.encodeStateVector(users[i + 1]))
compareDS(Y.createDeleteSetFromStructStore(users[i].store), Y.createDeleteSetFromStructStore(users[i + 1].store))
compareStructStores(users[i].store, users[i + 1].store)
}
@@ -385,8 +385,8 @@ export const compare = users => {
export const compareItemIDs = (a, b) => a === b || (a !== null && b != null && Y.compareIDs(a.id, b.id))
/**
* @param {Y.StructStore} ss1
* @param {Y.StructStore} ss2
* @param {import('../src/internals').StructStore} ss1
* @param {import('../src/internals').StructStore} ss2
*/
export const compareStructStores = (ss1, ss2) => {
t.assert(ss1.clients.size === ss2.clients.size)
@@ -428,13 +428,13 @@ export const compareStructStores = (ss1, ss2) => {
}
/**
* @param {Y.DeleteSet} ds1
* @param {Y.DeleteSet} ds2
* @param {import('../src/internals').DeleteSet} ds1
* @param {import('../src/internals').DeleteSet} ds2
*/
export const compareDS = (ds1, ds2) => {
t.assert(ds1.clients.size === ds2.clients.size)
ds1.clients.forEach((deleteItems1, client) => {
const deleteItems2 = /** @type {Array<Y.DeleteItem>} */ (ds2.clients.get(client))
const deleteItems2 = /** @type {Array<import('../src/internals').DeleteItem>} */ (ds2.clients.get(client))
t.assert(deleteItems2 !== undefined && deleteItems1.length === deleteItems2.length)
for (let i = 0; i < deleteItems1.length; i++) {
const di1 = deleteItems1[i]

View File

@@ -1,9 +1,5 @@
import { init, compare, applyRandomTests, Doc } from './testHelper.js' // eslint-disable-line
import {
UndoManager
} from '../src/internals.js'
import * as Y from '../src/index.js'
import * as t from 'lib0/testing'
@@ -12,7 +8,7 @@ import * as t from 'lib0/testing'
*/
export const testUndoText = tc => {
const { testConnector, text0, text1 } = init(tc, { users: 3 })
const undoManager = new UndoManager(text0)
const undoManager = new Y.UndoManager(text0)
// items that are added & deleted in the same transaction won't be undo
text0.insert(0, 'test')
@@ -81,7 +77,7 @@ export const testDoubleUndo = tc => {
export const testUndoMap = tc => {
const { testConnector, map0, map1 } = init(tc, { users: 2 })
map0.set('a', 0)
const undoManager = new UndoManager(map0)
const undoManager = new Y.UndoManager(map0)
map0.set('a', 1)
undoManager.undo()
t.assert(map0.get('a') === 0)
@@ -120,7 +116,7 @@ export const testUndoMap = tc => {
*/
export const testUndoArray = tc => {
const { testConnector, array0, array1 } = init(tc, { users: 3 })
const undoManager = new UndoManager(array0)
const undoManager = new Y.UndoManager(array0)
array0.insert(0, [1, 2, 3])
array1.insert(0, [4, 5, 6])
testConnector.syncAll()
@@ -171,7 +167,7 @@ export const testUndoArray = tc => {
*/
export const testUndoXml = tc => {
const { xml0 } = init(tc, { users: 3 })
const undoManager = new UndoManager(xml0)
const undoManager = new Y.UndoManager(xml0)
const child = new Y.XmlElement('p')
xml0.insert(0, [child])
const textchild = new Y.XmlText('content')
@@ -196,7 +192,7 @@ export const testUndoXml = tc => {
*/
export const testUndoEvents = tc => {
const { text0 } = init(tc, { users: 3 })
const undoManager = new UndoManager(text0)
const undoManager = new Y.UndoManager(text0)
let counter = 0
let receivedMetadata = -1
undoManager.on('stack-item-added', /** @param {any} event */ event => {
@@ -222,7 +218,7 @@ export const testUndoEvents = tc => {
export const testTrackClass = tc => {
const { users, text0 } = init(tc, { users: 3 })
// only track origins that are numbers
const undoManager = new UndoManager(text0, { trackedOrigins: new Set([Number]) })
const undoManager = new Y.UndoManager(text0, { trackedOrigins: new Set([Number]) })
users[0].transact(() => {
text0.insert(0, 'abc')
}, 42)
@@ -240,8 +236,8 @@ export const testTypeScope = tc => {
const text0 = new Y.Text()
const text1 = new Y.Text()
array0.insert(0, [text0, text1])
const undoManager = new UndoManager(text0)
const undoManagerBoth = new UndoManager([text0, text1])
const undoManager = new Y.UndoManager(text0)
const undoManagerBoth = new Y.UndoManager([text0, text1])
text1.insert(0, 'abc')
t.assert(undoManager.undoStack.length === 0)
t.assert(undoManagerBoth.undoStack.length === 1)
@@ -260,7 +256,7 @@ export const testUndoDeleteFilter = tc => {
* @type {Array<Y.Map<any>>}
*/
const array0 = /** @type {any} */ (init(tc, { users: 3 }).array0)
const undoManager = new UndoManager(array0, { deleteFilter: item => !(item instanceof Y.Item) || (item.content instanceof Y.ContentType && item.content.type._map.size === 0) })
const undoManager = new Y.UndoManager(array0, { deleteFilter: item => !(item instanceof Y.Item) || (item.content instanceof Y.ContentType && item.content.type._map.size === 0) })
const map0 = new Y.Map()
map0.set('hi', 1)
const map1 = new Y.Map()

View File

@@ -157,7 +157,7 @@ export const testGetDeltaWithEmbeds = tc => {
export const testTypesAsEmbed = tc => {
const { text0, text1, testConnector } = init(tc, { users: 2 })
text0.applyDelta([{
insert: new Y.YMap([['key', 'val']])
insert: new Y.Map([['key', 'val']])
}])
t.compare(text0.toDelta()[0].insert.toJSON(), { key: 'val' })
let firedEvent = false
@@ -714,7 +714,7 @@ const qChanges = [
if (prng.bool(gen)) {
ytext.insertEmbed(insertPos, { image: 'https://user-images.githubusercontent.com/5553757/48975307-61efb100-f06d-11e8-9177-ee895e5916e5.png' })
} else {
ytext.insertEmbed(insertPos, new Y.YMap([[prng.word(gen), prng.word(gen)]]))
ytext.insertEmbed(insertPos, new Y.Map([[prng.word(gen), prng.word(gen)]]))
}
},
/**