reimplemented WeakLink as an AbstractType
This commit is contained in:
parent
6f9db68f9a
commit
e50db9e123
@ -40,6 +40,5 @@ export * from './structs/ContentJSON.js'
|
||||
export * from './structs/ContentAny.js'
|
||||
export * from './structs/ContentString.js'
|
||||
export * from './structs/ContentType.js'
|
||||
export * from './structs/ContentLink.js'
|
||||
export * from './structs/Item.js'
|
||||
export * from './structs/Skip.js'
|
||||
|
@ -1,183 +0,0 @@
|
||||
import { decoding, encoding, error } from 'lib0'
|
||||
import {
|
||||
UpdateEncoderV1, UpdateEncoderV2, UpdateDecoderV1, UpdateDecoderV2, Transaction, Item, StructStore, // eslint-disable-line
|
||||
YWeakLink,
|
||||
AbstractType,
|
||||
getItemCleanStart,
|
||||
createID,
|
||||
getItemCleanEnd
|
||||
} from '../internals.js'
|
||||
|
||||
export class ContentLink {
|
||||
/**
|
||||
* @param {YWeakLink<any>} link
|
||||
*/
|
||||
constructor (link) {
|
||||
this.link = link
|
||||
/**
|
||||
* @type {Item|null}
|
||||
*/
|
||||
this._item = null
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {number}
|
||||
*/
|
||||
getLength () {
|
||||
return 1
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {Array<any>}
|
||||
*/
|
||||
getContent () {
|
||||
return [this.link]
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {boolean}
|
||||
*/
|
||||
isCountable () {
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {ContentLink}
|
||||
*/
|
||||
copy () {
|
||||
return new ContentLink(this.link)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} offset
|
||||
* @return {ContentLink}
|
||||
*/
|
||||
splice (offset) {
|
||||
throw error.methodUnimplemented()
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ContentLink} right
|
||||
* @return {boolean}
|
||||
*/
|
||||
mergeWith (right) {
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Transaction} transaction
|
||||
* @param {Item} item
|
||||
*/
|
||||
integrate (transaction, item) {
|
||||
let sourceItem = this.link.item !== null ? this.link.item : getItemCleanStart(transaction, this.link.id)
|
||||
if (sourceItem.constructor === Item && sourceItem.parentSub !== null) {
|
||||
// for maps, advance to most recent item
|
||||
while (sourceItem.right !== null) {
|
||||
sourceItem = sourceItem.right
|
||||
}
|
||||
}
|
||||
if (!sourceItem.deleted && sourceItem.length > 1) {
|
||||
sourceItem = getItemCleanEnd(transaction, transaction.doc.store, createID(sourceItem.id.client, sourceItem.id.clock + 1))
|
||||
}
|
||||
this.link.item = sourceItem
|
||||
this._item = item
|
||||
if (!sourceItem.deleted) {
|
||||
const src = /** @type {Item} */ (sourceItem)
|
||||
if (src.linkedBy === null) {
|
||||
src.linkedBy = new Set()
|
||||
}
|
||||
src.linkedBy.add(item)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Transaction} transaction
|
||||
*/
|
||||
delete (transaction) {
|
||||
if (this._item !== null && this.link !== null && this.link.item !== null && !this.link.item.deleted) {
|
||||
const item = /** @type {Item} */ (this.link.item)
|
||||
if (item.linkedBy !== null) {
|
||||
item.linkedBy.delete(this._item)
|
||||
}
|
||||
this.link.item = null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {StructStore} store
|
||||
*/
|
||||
gc (store) {}
|
||||
|
||||
/**
|
||||
* @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
|
||||
* @param {number} offset
|
||||
*/
|
||||
write (encoder, offset) {
|
||||
const flags = 0 // flags that could be used in the future
|
||||
encoding.writeUint8(encoder.restEncoder, flags)
|
||||
encoder.writeLeftID(this.link.id)
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {number}
|
||||
*/
|
||||
getRef () {
|
||||
return 11
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
|
||||
* @return {ContentLink}
|
||||
*/
|
||||
export const readContentWeakLink = decoder => {
|
||||
const flags = decoding.readUint8(decoder.restDecoder)
|
||||
const id = decoder.readLeftID()
|
||||
return new ContentLink(new YWeakLink(id, null))
|
||||
}
|
||||
|
||||
const lengthExceeded = error.create('Length exceeded!')
|
||||
|
||||
/**
|
||||
* Returns a {WeakLink} to an YArray element at given index.
|
||||
*
|
||||
* @param {Transaction} transaction
|
||||
* @param {AbstractType<any>} parent
|
||||
* @param {number} index
|
||||
* @return {YWeakLink<any>}
|
||||
*/
|
||||
export const arrayWeakLink = (transaction, parent, index) => {
|
||||
let item = parent._start
|
||||
for (; item !== null; item = item.right) {
|
||||
if (!item.deleted && item.countable) {
|
||||
if (index < item.length) {
|
||||
if (index > 0) {
|
||||
item = getItemCleanStart(transaction, createID(item.id.client, item.id.clock + index))
|
||||
}
|
||||
if (item.length > 1) {
|
||||
item = getItemCleanEnd(transaction, transaction.doc.store, createID(item.id.client, item.id.clock + 1))
|
||||
}
|
||||
return new YWeakLink(item.id, item)
|
||||
}
|
||||
index -= item.length
|
||||
}
|
||||
}
|
||||
|
||||
throw lengthExceeded
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {WeakLink} to an YMap element at given key.
|
||||
*
|
||||
* @param {AbstractType<any>} parent
|
||||
* @param {string} key
|
||||
* @return {YWeakLink<any>|undefined}
|
||||
*/
|
||||
export const mapWeakLink = (parent, key) => {
|
||||
const item = parent._map.get(key)
|
||||
if (item !== undefined) {
|
||||
return new YWeakLink(item.id, item)
|
||||
} else {
|
||||
return undefined
|
||||
}
|
||||
}
|
@ -7,7 +7,8 @@ import {
|
||||
readYXmlFragment,
|
||||
readYXmlHook,
|
||||
readYXmlText,
|
||||
UpdateDecoderV1, UpdateDecoderV2, UpdateEncoderV1, UpdateEncoderV2, StructStore, Transaction, Item, YEvent, AbstractType // eslint-disable-line
|
||||
UpdateDecoderV1, UpdateDecoderV2, UpdateEncoderV1, UpdateEncoderV2, StructStore, Transaction, Item, YEvent, AbstractType, // eslint-disable-line
|
||||
readYWeakLink
|
||||
} from '../internals.js'
|
||||
|
||||
import * as error from 'lib0/error'
|
||||
@ -23,7 +24,8 @@ export const typeRefs = [
|
||||
readYXmlElement,
|
||||
readYXmlFragment,
|
||||
readYXmlHook,
|
||||
readYXmlText
|
||||
readYXmlText,
|
||||
readYWeakLink
|
||||
]
|
||||
|
||||
export const YArrayRefID = 0
|
||||
@ -33,6 +35,7 @@ export const YXmlElementRefID = 3
|
||||
export const YXmlFragmentRefID = 4
|
||||
export const YXmlHookRefID = 5
|
||||
export const YXmlTextRefID = 6
|
||||
export const YWeakLinkRefID = 7
|
||||
|
||||
/**
|
||||
* @private
|
||||
@ -104,6 +107,7 @@ export class ContentType {
|
||||
* @param {Transaction} transaction
|
||||
*/
|
||||
delete (transaction) {
|
||||
this.type._delete(transaction) // call custom destructor on AbstractType
|
||||
let item = this.type._start
|
||||
while (item !== null) {
|
||||
if (!item.deleted) {
|
||||
|
@ -18,15 +18,13 @@ import {
|
||||
readContentString,
|
||||
readContentEmbed,
|
||||
readContentDoc,
|
||||
readContentWeakLink,
|
||||
createID,
|
||||
readContentFormat,
|
||||
readContentType,
|
||||
addChangedTypeToTransaction,
|
||||
isDeleted,
|
||||
StackItem, DeleteSet, UpdateDecoderV1, UpdateDecoderV2, UpdateEncoderV1, UpdateEncoderV2, ContentType, ContentDeleted, StructStore, ID, AbstractType, Transaction, // eslint-disable-line
|
||||
YWeakLink,
|
||||
ContentLink
|
||||
YWeakLink
|
||||
} from '../internals.js'
|
||||
|
||||
import * as error from 'lib0/error'
|
||||
@ -302,7 +300,7 @@ export class Item extends AbstractStruct {
|
||||
* If this item was referenced by other weak links, here we keep the references
|
||||
* to these weak refs.
|
||||
*
|
||||
* @type {Set<Item> | null}
|
||||
* @type {Set<YWeakLink<any>> | null}
|
||||
*/
|
||||
this.linkedBy = null
|
||||
/**
|
||||
@ -386,10 +384,10 @@ export class Item extends AbstractStruct {
|
||||
if (this.parent && this.parent.constructor === ID && this.id.client !== this.parent.client && this.parent.clock >= getState(store, this.parent.client)) {
|
||||
return this.parent.client
|
||||
}
|
||||
if (this.content.constructor === ContentLink) {
|
||||
const content = /** @type {ContentLink} */ (this.content)
|
||||
if (content.link.id.client !== this.id.client) {
|
||||
return content.link.id.client
|
||||
if (this.content.constructor === ContentType && /** @type {ContentType} */ (this.content).type.constructor === YWeakLink) {
|
||||
const content = /** @type {any} */ (this.content).type
|
||||
if (content._id.client !== this.id.client) {
|
||||
return content._id.client
|
||||
}
|
||||
}
|
||||
|
||||
@ -540,7 +538,7 @@ export class Item extends AbstractStruct {
|
||||
addChangedTypeToTransaction(transaction, /** @type {AbstractType<any>} */ (this.parent), this.parentSub)
|
||||
if (this.linkedBy !== null) {
|
||||
for (let link of this.linkedBy) {
|
||||
addChangedTypeToTransaction(transaction, /** @type {AbstractType<any>} */ (link.parent), link.parentSub)
|
||||
addChangedTypeToTransaction(transaction, link, this.parentSub)
|
||||
}
|
||||
}
|
||||
if ((/** @type {AbstractType<any>} */ (this.parent)._item !== null && /** @type {AbstractType<any>} */ (this.parent)._item.deleted) || (this.parentSub !== null && this.right !== null)) {
|
||||
@ -647,7 +645,12 @@ export class Item extends AbstractStruct {
|
||||
addToDeleteSet(transaction.deleteSet, this.id.client, this.id.clock, this.length)
|
||||
addChangedTypeToTransaction(transaction, parent, this.parentSub)
|
||||
this.content.delete(transaction)
|
||||
this.linkedBy = null
|
||||
if (this.linkedBy !== null) {
|
||||
for (let link of this.linkedBy) {
|
||||
addChangedTypeToTransaction(transaction, link, this.parentSub)
|
||||
}
|
||||
this.linkedBy = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -744,8 +747,7 @@ export const contentRefs = [
|
||||
readContentType, // 7
|
||||
readContentAny, // 8
|
||||
readContentDoc, // 9
|
||||
() => { error.unexpectedCase() }, // 10 - Skip is not ItemContent
|
||||
readContentWeakLink // 11
|
||||
() => { error.unexpectedCase() } // 10 - Skip is not ItemContent
|
||||
]
|
||||
|
||||
/**
|
||||
|
@ -11,7 +11,7 @@ import {
|
||||
ContentAny,
|
||||
ContentBinary,
|
||||
getItemCleanStart,
|
||||
ContentDoc, YText, YArray, UpdateEncoderV1, UpdateEncoderV2, Doc, Snapshot, Transaction, EventHandler, YEvent, Item, YWeakLink, ContentLink, // eslint-disable-line
|
||||
ContentDoc, YText, YArray, UpdateEncoderV1, UpdateEncoderV2, Doc, Snapshot, Transaction, EventHandler, YEvent, Item, YWeakLink, // eslint-disable-line
|
||||
} from '../internals.js'
|
||||
|
||||
import * as map from 'lib0/map'
|
||||
@ -309,6 +309,11 @@ export class AbstractType {
|
||||
this._item = item
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Transaction} transaction
|
||||
*/
|
||||
_delete (transaction) { }
|
||||
|
||||
/**
|
||||
* @return {AbstractType<EventType>}
|
||||
*/
|
||||
@ -669,10 +674,6 @@ export const typeListInsertGenericsAfter = (transaction, parent, referenceItem,
|
||||
left = new Item(createID(ownClientId, getState(store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, new ContentDoc(/** @type {Doc} */ (c)))
|
||||
left.integrate(transaction, 0)
|
||||
break
|
||||
case YWeakLink:
|
||||
left = new Item(createID(ownClientId, getState(store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, new ContentLink(/** @type {YWeakLink<any>} */ (c)))
|
||||
left.integrate(transaction, 0)
|
||||
break
|
||||
default:
|
||||
if (c instanceof AbstractType) {
|
||||
left = new Item(createID(ownClientId, getState(store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, new ContentType(c))
|
||||
@ -855,9 +856,6 @@ export const typeMapSet = (transaction, parent, key, value) => {
|
||||
case Doc:
|
||||
content = new ContentDoc(/** @type {Doc} */ (value))
|
||||
break
|
||||
case YWeakLink:
|
||||
content = new ContentLink(/** @type {YWeakLink<any>} */ (value))
|
||||
break;
|
||||
default:
|
||||
if (value instanceof AbstractType) {
|
||||
content = new ContentType(value)
|
||||
|
@ -1,4 +1,13 @@
|
||||
import { AbstractType, GC, ID, Item, Transaction, YEvent } from "yjs"
|
||||
import { decoding, encoding, error } from "lib0"
|
||||
import {
|
||||
YEvent, Transaction, ID, GC, AbstractType, UpdateDecoderV1, UpdateDecoderV2, UpdateEncoderV1, UpdateEncoderV2, Doc, Item,
|
||||
transact,
|
||||
getItemCleanEnd,
|
||||
createID,
|
||||
getItemCleanStart,
|
||||
callTypeObservers,
|
||||
YWeakLinkRefID
|
||||
} from "../internals.js"
|
||||
|
||||
/**
|
||||
* @template T extends AbstractType<any>
|
||||
@ -9,27 +18,27 @@ export class YWeakLinkEvent extends YEvent {
|
||||
/**
|
||||
* @param {YWeakLink<T>} ylink The YWeakLink to which this event was propagated to.
|
||||
* @param {Transaction} transaction
|
||||
* @param {YEvent<any>} source Source event that has been propagated to ylink.
|
||||
*/
|
||||
constructor (ylink, transaction, source) {
|
||||
constructor (ylink, transaction) {
|
||||
super(ylink, transaction)
|
||||
this.source = source
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @extends AbstractType<YWeakLinkEvent<T>>
|
||||
*
|
||||
* Weak link to another value stored somewhere in the document.
|
||||
*/
|
||||
export class YWeakLink {
|
||||
export class YWeakLink extends AbstractType {
|
||||
/**
|
||||
* @param {ID} id
|
||||
* @param {Item|GC|null} item
|
||||
*/
|
||||
constructor(id, item) {
|
||||
this.id = id
|
||||
this.item = item
|
||||
super()
|
||||
this._id = id
|
||||
this._linkedItem = item
|
||||
}
|
||||
|
||||
/**
|
||||
@ -38,14 +47,14 @@ export class YWeakLink {
|
||||
* @return {T|undefined}
|
||||
*/
|
||||
deref() {
|
||||
if (this.item !== null && this.item.constructor === Item) {
|
||||
let item = this.item
|
||||
if (this._linkedItem !== null && this._linkedItem.constructor === Item) {
|
||||
let item = this._linkedItem
|
||||
if (item.parentSub !== null) {
|
||||
// for map types go to the most recent one
|
||||
while (item.right !== null) {
|
||||
item = item.right
|
||||
}
|
||||
this.item = item
|
||||
this._linkedItem = item
|
||||
}
|
||||
if (!item.deleted) {
|
||||
return item.content.getContent()[0]
|
||||
@ -53,4 +62,155 @@ export class YWeakLink {
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Integrate this type into the Yjs instance.
|
||||
*
|
||||
* * Save this struct in the os
|
||||
* * This type is sent to other client
|
||||
* * Observer functions are fired
|
||||
*
|
||||
* @param {Doc} y The Yjs instance
|
||||
* @param {Item|null} item
|
||||
*/
|
||||
_integrate (y, item) {
|
||||
super._integrate(y, item)
|
||||
if (item !== null) {
|
||||
transact(y, (transaction) => {
|
||||
let sourceItem = this._linkedItem !== null ? this._linkedItem : getItemCleanStart(transaction, this._id)
|
||||
if (sourceItem.constructor === Item && sourceItem.parentSub !== null) {
|
||||
// for maps, advance to most recent item
|
||||
while (sourceItem.right !== null) {
|
||||
sourceItem = sourceItem.right
|
||||
}
|
||||
}
|
||||
if (!sourceItem.deleted && sourceItem.length > 1) {
|
||||
sourceItem = getItemCleanEnd(transaction, transaction.doc.store, createID(sourceItem.id.client, sourceItem.id.clock + 1))
|
||||
}
|
||||
this._linkedItem = sourceItem
|
||||
if (!sourceItem.deleted) {
|
||||
const src = /** @type {Item} */ (sourceItem)
|
||||
if (src.linkedBy === null) {
|
||||
src.linkedBy = new Set()
|
||||
}
|
||||
src.linkedBy.add(this)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Transaction} transaction
|
||||
*/
|
||||
_delete (transaction) {
|
||||
if (this._item !== null && this._linkedItem !== null && !this._linkedItem.deleted) {
|
||||
const item = /** @type {Item} */ (this._linkedItem)
|
||||
if (item.linkedBy !== null) {
|
||||
item.linkedBy.delete(this)
|
||||
}
|
||||
this._linkedItem = null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {YWeakLink<T>}
|
||||
*/
|
||||
_copy () {
|
||||
return new YWeakLink(this._id, this._linkedItem)
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {YWeakLink<T>}
|
||||
*/
|
||||
clone () {
|
||||
return new YWeakLink(this._id, this._linkedItem)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates YWeakLinkEvent and calls observers.
|
||||
*
|
||||
* @param {Transaction} transaction
|
||||
* @param {Set<null|string>} parentSubs Keys changed on this type. `null` if list was modified.
|
||||
*/
|
||||
_callObserver (transaction, parentSubs) {
|
||||
super._callObserver(transaction, parentSubs)
|
||||
callTypeObservers(this, transaction, new YWeakLinkEvent(this, transaction))
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
|
||||
*/
|
||||
_write (encoder) {
|
||||
encoder.writeTypeRef(YWeakLinkRefID)
|
||||
const flags = 0 // flags that could be used in the future
|
||||
encoding.writeUint8(encoder.restEncoder, flags)
|
||||
encoder.writeLeftID(this._id)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
|
||||
* @return {YWeakLink<any>}
|
||||
*/
|
||||
export const readYWeakLink = decoder => {
|
||||
const flags = decoding.readUint8(decoder.restDecoder)
|
||||
const id = decoder.readLeftID()
|
||||
return new YWeakLink(id, null)
|
||||
}
|
||||
|
||||
const lengthExceeded = error.create('Length exceeded!')
|
||||
|
||||
/**
|
||||
* Returns a {WeakLink} to an YArray element at given index.
|
||||
*
|
||||
* @param {Transaction} transaction
|
||||
* @param {AbstractType<any>} parent
|
||||
* @param {number} index
|
||||
* @return {YWeakLink<any>}
|
||||
*/
|
||||
export const arrayWeakLink = (transaction, parent, index) => {
|
||||
let item = parent._start
|
||||
for (; item !== null; item = item.right) {
|
||||
if (!item.deleted && item.countable) {
|
||||
if (index < item.length) {
|
||||
if (index > 0) {
|
||||
item = getItemCleanStart(transaction, createID(item.id.client, item.id.clock + index))
|
||||
}
|
||||
if (item.length > 1) {
|
||||
item = getItemCleanEnd(transaction, transaction.doc.store, createID(item.id.client, item.id.clock))
|
||||
}
|
||||
const link = new YWeakLink(item.id, item)
|
||||
if (item.linkedBy === null) {
|
||||
item.linkedBy = new Set()
|
||||
}
|
||||
item.linkedBy.add(link)
|
||||
return link
|
||||
}
|
||||
index -= item.length
|
||||
}
|
||||
}
|
||||
|
||||
throw lengthExceeded
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {WeakLink} to an YMap element at given key.
|
||||
*
|
||||
* @param {AbstractType<any>} parent
|
||||
* @param {string} key
|
||||
* @return {YWeakLink<any>|undefined}
|
||||
*/
|
||||
export const mapWeakLink = (parent, key) => {
|
||||
const item = parent._map.get(key)
|
||||
if (item !== undefined) {
|
||||
const link = new YWeakLink(item.id, item)
|
||||
if (item.linkedBy === null) {
|
||||
item.linkedBy = new Set()
|
||||
}
|
||||
item.linkedBy.add(link)
|
||||
return link
|
||||
} else {
|
||||
return undefined
|
||||
}
|
||||
}
|
@ -118,55 +118,69 @@ export const testDeleteSource = tc => {
|
||||
/**
|
||||
* @param {t.TestCase} tc
|
||||
*/
|
||||
export const testObserveMapLinkArrayRemove = tc => {
|
||||
const doc = new Y.Doc()
|
||||
const map = doc.getMap('map')
|
||||
const array = doc.getArray('array')
|
||||
|
||||
array.insert(0, [1])
|
||||
const link = array.link(0)
|
||||
map.set('key', link)
|
||||
export const testObserveMapUpdate = tc => {
|
||||
const { testConnector, users, map0, map1 } = init(tc, { users: 2 })
|
||||
map0.set('a', 'value')
|
||||
const link0 = /** @type {Y.WeakLink<String>} */ (map0.link('a'))
|
||||
/**
|
||||
* @type {any}
|
||||
*/
|
||||
let keys = null
|
||||
map.observe((e) => {
|
||||
console.log('map received event', e)
|
||||
keys = e.keys
|
||||
})
|
||||
let target0
|
||||
link0.observe((e) => target0 = e.target)
|
||||
map0.set('b', link0)
|
||||
|
||||
array.delete(0)
|
||||
testConnector.flushAllMessages()
|
||||
|
||||
t.compare(keys.get('key'), { action:'delete', oldValue: 1, newValue: null })
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {t.TestCase} tc
|
||||
*/
|
||||
export const testObserveMapLinkMapUpdate = tc => {
|
||||
const doc = new Y.Doc()
|
||||
const map1 = doc.getMap('map1')
|
||||
const map2 = doc.getMap('map2')
|
||||
let link1 = /** @type {Y.WeakLink<String>} */ (map1.get('b'))
|
||||
t.compare(link1.deref(), 'value')
|
||||
/**
|
||||
* @type {Map<string, { action: 'add' | 'update' | 'delete', oldValue: any, newValue: any }>}
|
||||
* @type {any}
|
||||
*/
|
||||
let keys
|
||||
map1.observe((e) => keys = e.keys)
|
||||
let target1
|
||||
link1.observe((e) => target1 = e.target)
|
||||
|
||||
map2.set('key', 'value1')
|
||||
const link = map2.link('key')
|
||||
map1.set('other-key', link)
|
||||
map0.set('a', 'value2')
|
||||
t.compare(target0.deref(), 'value2')
|
||||
|
||||
keys = /** @type {any} */ (null)
|
||||
map2.set('key', 'value2')
|
||||
|
||||
t.compare(keys.get('key'), { action:'update', oldValue: 'value1', newValue: 'value2' })
|
||||
testConnector.flushAllMessages()
|
||||
t.compare(target1.deref(), 'value2')
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {t.TestCase} tc
|
||||
*/
|
||||
export const testObserveMapLinkMapRemove = tc => {
|
||||
export const testObserveMapDelete = tc => {
|
||||
const { testConnector, users, map0, map1 } = init(tc, { users: 2 })
|
||||
map0.set('a', 'value')
|
||||
const link0 = /** @type {Y.WeakLink<String>} */ (map0.link('a'))
|
||||
/**
|
||||
* @type {any}
|
||||
*/
|
||||
let target0
|
||||
link0.observe((e) => target0 = e.target)
|
||||
map0.set('b', link0)
|
||||
|
||||
testConnector.flushAllMessages()
|
||||
|
||||
let link1 = /** @type {Y.WeakLink<String>} */ (map1.get('b'))
|
||||
t.compare(link1.deref(), 'value')
|
||||
/**
|
||||
* @type {any}
|
||||
*/
|
||||
let target1
|
||||
link1.observe((e) => target1 = e.target)
|
||||
|
||||
map0.delete('a')
|
||||
t.compare(target0.deref(), undefined)
|
||||
|
||||
testConnector.flushAllMessages()
|
||||
t.compare(target1.deref(), undefined)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {t.TestCase} tc
|
||||
*/
|
||||
const testObserveMapLinkMapRemove = tc => {
|
||||
const doc = new Y.Doc()
|
||||
const map1 = doc.getMap('map1')
|
||||
const map2 = doc.getMap('map2')
|
||||
@ -189,7 +203,7 @@ export const testObserveMapLinkMapRemove = tc => {
|
||||
/**
|
||||
* @param {t.TestCase} tc
|
||||
*/
|
||||
export const testObserveArrayLinkMapRemove = tc => {
|
||||
const testObserveArrayLinkMapRemove = tc => {
|
||||
const doc = new Y.Doc()
|
||||
const array = doc.getArray('array')
|
||||
const map = doc.getMap('map')
|
||||
@ -212,7 +226,7 @@ export const testObserveArrayLinkMapRemove = tc => {
|
||||
/**
|
||||
* @param {t.TestCase} tc
|
||||
*/
|
||||
export const testObserveArrayLinkMapUpdate = tc => {
|
||||
const testObserveArrayLinkMapUpdate = tc => {
|
||||
const doc = new Y.Doc()
|
||||
const array = doc.getArray('array')
|
||||
const map = doc.getMap('map')
|
||||
@ -235,7 +249,7 @@ export const testObserveArrayLinkMapUpdate = tc => {
|
||||
/**
|
||||
* @param {t.TestCase} tc
|
||||
*/
|
||||
export const testObserveTransitive = tc => {
|
||||
const testObserveTransitive = tc => {
|
||||
// test observers in a face of linked chains of values
|
||||
const doc = new Y.Doc()
|
||||
const map1 = doc.getMap('map1')
|
||||
@ -262,7 +276,7 @@ export const testObserveTransitive = tc => {
|
||||
/**
|
||||
* @param {t.TestCase} tc
|
||||
*/
|
||||
export const testDeepObserveMap = tc => {
|
||||
const testDeepObserveMap = tc => {
|
||||
// test observers in a face of linked chains of values
|
||||
const doc = new Y.Doc()
|
||||
const map = doc.getMap('map')
|
||||
@ -297,7 +311,7 @@ export const testDeepObserveMap = tc => {
|
||||
/**
|
||||
* @param {t.TestCase} tc
|
||||
*/
|
||||
export const testDeepObserveArray = tc => {
|
||||
const testDeepObserveArray = tc => {
|
||||
// test observers in a face of linked chains of values
|
||||
const doc = new Y.Doc()
|
||||
const map = doc.getMap('map')
|
||||
@ -332,7 +346,7 @@ export const testDeepObserveArray = tc => {
|
||||
/**
|
||||
* @param {t.TestCase} tc
|
||||
*/
|
||||
export const testDeepObserveRecursive = tc => {
|
||||
const testDeepObserveRecursive = tc => {
|
||||
// test observers in a face of linked chains of values
|
||||
const doc = new Y.Doc()
|
||||
const root = doc.getArray('array')
|
||||
|
Loading…
x
Reference in New Issue
Block a user