draft for WeakLink API
This commit is contained in:
		
							parent
							
								
									5db1eed181
								
							
						
					
					
						commit
						c7539b028a
					
				@ -10,6 +10,7 @@ export {
 | 
				
			|||||||
  YXmlHook as XmlHook,
 | 
					  YXmlHook as XmlHook,
 | 
				
			||||||
  YXmlElement as XmlElement,
 | 
					  YXmlElement as XmlElement,
 | 
				
			||||||
  YXmlFragment as XmlFragment,
 | 
					  YXmlFragment as XmlFragment,
 | 
				
			||||||
 | 
					  WeakLink,
 | 
				
			||||||
  YXmlEvent,
 | 
					  YXmlEvent,
 | 
				
			||||||
  YMapEvent,
 | 
					  YMapEvent,
 | 
				
			||||||
  YArrayEvent,
 | 
					  YArrayEvent,
 | 
				
			||||||
 | 
				
			|||||||
@ -27,6 +27,7 @@ export * from './types/YXmlElement.js'
 | 
				
			|||||||
export * from './types/YXmlEvent.js'
 | 
					export * from './types/YXmlEvent.js'
 | 
				
			||||||
export * from './types/YXmlHook.js'
 | 
					export * from './types/YXmlHook.js'
 | 
				
			||||||
export * from './types/YXmlText.js'
 | 
					export * from './types/YXmlText.js'
 | 
				
			||||||
 | 
					export * from './types/WeakLink.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export * from './structs/AbstractStruct.js'
 | 
					export * from './structs/AbstractStruct.js'
 | 
				
			||||||
export * from './structs/GC.js'
 | 
					export * from './structs/GC.js'
 | 
				
			||||||
@ -39,5 +40,6 @@ export * from './structs/ContentJSON.js'
 | 
				
			|||||||
export * from './structs/ContentAny.js'
 | 
					export * from './structs/ContentAny.js'
 | 
				
			||||||
export * from './structs/ContentString.js'
 | 
					export * from './structs/ContentString.js'
 | 
				
			||||||
export * from './structs/ContentType.js'
 | 
					export * from './structs/ContentType.js'
 | 
				
			||||||
 | 
					export * from './structs/ContentLink.js'
 | 
				
			||||||
export * from './structs/Item.js'
 | 
					export * from './structs/Item.js'
 | 
				
			||||||
export * from './structs/Skip.js'
 | 
					export * from './structs/Skip.js'
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										99
									
								
								src/structs/ContentLink.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								src/structs/ContentLink.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,99 @@
 | 
				
			|||||||
 | 
					import {
 | 
				
			||||||
 | 
					    UpdateEncoderV1, UpdateEncoderV2, UpdateDecoderV1, UpdateDecoderV2, Transaction, Item, StructStore // eslint-disable-line
 | 
				
			||||||
 | 
					  } from '../internals.js'
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  export class ContentLink {
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @param {Item} item
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    constructor (item) {
 | 
				
			||||||
 | 
					      /**
 | 
				
			||||||
 | 
					       * @type {Item}
 | 
				
			||||||
 | 
					       */
 | 
				
			||||||
 | 
					      this.item = item
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @return {number}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    getLength () {
 | 
				
			||||||
 | 
					      return this.item.length
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @return {Array<any>}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    getContent () {
 | 
				
			||||||
 | 
					      throw new Error('not implemented')
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @return {boolean}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    isCountable () {
 | 
				
			||||||
 | 
					      return true
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @return {ContentLink}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    copy () {
 | 
				
			||||||
 | 
					      return new ContentLink(this.item)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @param {number} offset
 | 
				
			||||||
 | 
					     * @return {ContentLink}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    splice (offset) {
 | 
				
			||||||
 | 
					      throw new Error('not implemented')
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @param {ContentLink} right
 | 
				
			||||||
 | 
					     * @return {boolean}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    mergeWith (right) {
 | 
				
			||||||
 | 
					      throw new Error('not implemented')
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @param {Transaction} transaction
 | 
				
			||||||
 | 
					     * @param {Item} item
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    integrate (transaction, item) {}
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @param {Transaction} transaction
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    delete (transaction) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @param {StructStore} store
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    gc (store) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
 | 
				
			||||||
 | 
					     * @param {number} offset
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    write (encoder, offset) {
 | 
				
			||||||
 | 
					      throw new Error('not implemented')
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @return {number}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    getRef () {
 | 
				
			||||||
 | 
					      return 10
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
 | 
				
			||||||
 | 
					   * @return {ContentLink}
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  export const readContentWeakLink = decoder => {
 | 
				
			||||||
 | 
					    throw new Error('not implemented')
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
@ -18,6 +18,7 @@ import {
 | 
				
			|||||||
  readContentString,
 | 
					  readContentString,
 | 
				
			||||||
  readContentEmbed,
 | 
					  readContentEmbed,
 | 
				
			||||||
  readContentDoc,
 | 
					  readContentDoc,
 | 
				
			||||||
 | 
					  readContentWeakLink,
 | 
				
			||||||
  createID,
 | 
					  createID,
 | 
				
			||||||
  readContentFormat,
 | 
					  readContentFormat,
 | 
				
			||||||
  readContentType,
 | 
					  readContentType,
 | 
				
			||||||
@ -719,6 +720,7 @@ export const contentRefs = [
 | 
				
			|||||||
  readContentType, // 7
 | 
					  readContentType, // 7
 | 
				
			||||||
  readContentAny, // 8
 | 
					  readContentAny, // 8
 | 
				
			||||||
  readContentDoc, // 9
 | 
					  readContentDoc, // 9
 | 
				
			||||||
 | 
					  readContentWeakLink, // 10
 | 
				
			||||||
  () => { error.unexpectedCase() } // 10 - Skip is not ItemContent
 | 
					  () => { error.unexpectedCase() } // 10 - Skip is not ItemContent
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										17
									
								
								src/types/WeakLink.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/types/WeakLink.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @template T
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * Weak link to another value stored somewhere in the document.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export class WeakLink {
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Returns a reference to an underlying value existing somewhere on in the document.
 | 
				
			||||||
 | 
					     * 
 | 
				
			||||||
 | 
					     * @return {T|undefined}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    deref() {
 | 
				
			||||||
 | 
					        throw new Error('not implemented')
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -16,7 +16,8 @@ import {
 | 
				
			|||||||
  YArrayRefID,
 | 
					  YArrayRefID,
 | 
				
			||||||
  callTypeObservers,
 | 
					  callTypeObservers,
 | 
				
			||||||
  transact,
 | 
					  transact,
 | 
				
			||||||
  ArraySearchMarker, UpdateDecoderV1, UpdateDecoderV2, UpdateEncoderV1, UpdateEncoderV2, Doc, Transaction, Item // eslint-disable-line
 | 
					  ArraySearchMarker, UpdateDecoderV1, UpdateDecoderV2, UpdateEncoderV1, UpdateEncoderV2, Doc, Transaction, Item, // eslint-disable-line
 | 
				
			||||||
 | 
					  WeakLink
 | 
				
			||||||
} from '../internals.js'
 | 
					} from '../internals.js'
 | 
				
			||||||
import { typeListSlice } from './AbstractType.js'
 | 
					import { typeListSlice } from './AbstractType.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -201,6 +202,16 @@ export class YArray extends AbstractType {
 | 
				
			|||||||
    return typeListGet(this, index)
 | 
					    return typeListGet(this, index)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Returns the weak link to i-th element from a YArray.
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * @param {number} index The index of the element to return from the YArray
 | 
				
			||||||
 | 
					   * @return {WeakLink<T>}
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  link(index) {
 | 
				
			||||||
 | 
					      throw new Error('Method not implemented.')
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Transforms this YArray to a JavaScript Array.
 | 
					   * Transforms this YArray to a JavaScript Array.
 | 
				
			||||||
   *
 | 
					   *
 | 
				
			||||||
 | 
				
			|||||||
@ -14,7 +14,8 @@ import {
 | 
				
			|||||||
  YMapRefID,
 | 
					  YMapRefID,
 | 
				
			||||||
  callTypeObservers,
 | 
					  callTypeObservers,
 | 
				
			||||||
  transact,
 | 
					  transact,
 | 
				
			||||||
  UpdateDecoderV1, UpdateDecoderV2, UpdateEncoderV1, UpdateEncoderV2, Doc, Transaction, Item // eslint-disable-line
 | 
					  UpdateDecoderV1, UpdateDecoderV2, UpdateEncoderV1, UpdateEncoderV2, Doc, Transaction, Item, // eslint-disable-line
 | 
				
			||||||
 | 
					  WeakLink
 | 
				
			||||||
} from '../internals.js'
 | 
					} from '../internals.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import * as iterator from 'lib0/iterator'
 | 
					import * as iterator from 'lib0/iterator'
 | 
				
			||||||
@ -233,6 +234,16 @@ export class YMap extends AbstractType {
 | 
				
			|||||||
    return /** @type {any} */ (typeMapGet(this, key))
 | 
					    return /** @type {any} */ (typeMapGet(this, key))
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Returns a weak reference link to another element stored in the same document.
 | 
				
			||||||
 | 
					   * 
 | 
				
			||||||
 | 
					   * @param {string} key 
 | 
				
			||||||
 | 
					   * @return {WeakLink<MapType>|undefined}
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  link(key) {
 | 
				
			||||||
 | 
					    throw new Error('Method not implemented.')
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Returns a boolean indicating whether the specified key exists or not.
 | 
					   * Returns a boolean indicating whether the specified key exists or not.
 | 
				
			||||||
   *
 | 
					   *
 | 
				
			||||||
 | 
				
			|||||||
@ -11,6 +11,7 @@ import * as doc from './doc.tests.js'
 | 
				
			|||||||
import * as snapshot from './snapshot.tests.js'
 | 
					import * as snapshot from './snapshot.tests.js'
 | 
				
			||||||
import * as updates from './updates.tests.js'
 | 
					import * as updates from './updates.tests.js'
 | 
				
			||||||
import * as relativePositions from './relativePositions.tests.js'
 | 
					import * as relativePositions from './relativePositions.tests.js'
 | 
				
			||||||
 | 
					import * as weakLinks from './weakLinks.tests.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { runTests } from 'lib0/testing'
 | 
					import { runTests } from 'lib0/testing'
 | 
				
			||||||
import { isBrowser, isNode } from 'lib0/environment'
 | 
					import { isBrowser, isNode } from 'lib0/environment'
 | 
				
			||||||
@ -20,7 +21,7 @@ if (isBrowser) {
 | 
				
			|||||||
  log.createVConsole(document.body)
 | 
					  log.createVConsole(document.body)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
runTests({
 | 
					runTests({
 | 
				
			||||||
  doc, map, array, text, xml, encoding, undoredo, compatibility, snapshot, updates, relativePositions
 | 
					  doc, map, array, text, xml, encoding, undoredo, compatibility, snapshot, updates, relativePositions, weakLinks
 | 
				
			||||||
}).then(success => {
 | 
					}).then(success => {
 | 
				
			||||||
  /* istanbul ignore next */
 | 
					  /* istanbul ignore next */
 | 
				
			||||||
  if (isNode) {
 | 
					  if (isNode) {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										176
									
								
								tests/weakLinks.tests.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										176
									
								
								tests/weakLinks.tests.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,176 @@
 | 
				
			|||||||
 | 
					import * as Y from '../src/index.js'
 | 
				
			||||||
 | 
					import * as t from 'lib0/testing'
 | 
				
			||||||
 | 
					import { init, compare } from './testHelper.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @param {t.TestCase} tc
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export const testBasic = tc => {
 | 
				
			||||||
 | 
					  const doc = new Y.Doc()
 | 
				
			||||||
 | 
					  const map = doc.getMap('map')
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  const nested = new Y.Map()
 | 
				
			||||||
 | 
					  nested.set('a1', 'hello')
 | 
				
			||||||
 | 
					  map.set('a', nested)
 | 
				
			||||||
 | 
					  const link = nested.link('a')
 | 
				
			||||||
 | 
					  map.set('b', link)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const nested2 = map.get('b')
 | 
				
			||||||
 | 
					  t.compare(nested2.toJSON(), nested.toJSON())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @param {t.TestCase} tc
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export const testUpdate = tc => {
 | 
				
			||||||
 | 
					  const { testConnector, users, map0, map1 } = init(tc, { users: 2 })
 | 
				
			||||||
 | 
					  map0.set('a', new Y.Map([['a1', 'hello']]))
 | 
				
			||||||
 | 
					  const link0 = /** @type {Y.WeakLink<Y.Map<any>>} */ (map0.link('a'))
 | 
				
			||||||
 | 
					  map0.set('b', link0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  testConnector.flushAllMessages()
 | 
				
			||||||
 | 
					  const link1 = /** @type {Y.WeakLink<Y.Map<any>>} */ (map1.get('b'))
 | 
				
			||||||
 | 
					  let l1 = /** @type {Y.Map<any>} */ (link1.deref())
 | 
				
			||||||
 | 
					  let l0 = /** @type {Y.Map<any>} */ (link0.deref())
 | 
				
			||||||
 | 
					  t.compare(l1.get('a1'), l0.get('a1'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  map1.get('a').set('a2', 'world')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  testConnector.flushAllMessages()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  l1 = /** @type {Y.Map<any>} */ (link1.deref())
 | 
				
			||||||
 | 
					  l0 = /** @type {Y.Map<any>} */ (link0.deref())
 | 
				
			||||||
 | 
					  t.compare(l1.get('a2'), l0.get('a2'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  compare(users)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @param {t.TestCase} tc
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export const testDeleteWeakLink = tc => {
 | 
				
			||||||
 | 
					  const { testConnector, users, map0, map1 } = init(tc, { users: 2 })
 | 
				
			||||||
 | 
					  map0.set('a', new Y.Map([['a1', 'hello']]))
 | 
				
			||||||
 | 
					  const link0 = /** @type {Y.WeakLink<Y.Map<any>>} */ (map0.link('a'))
 | 
				
			||||||
 | 
					  map0.set('b', link0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  testConnector.flushAllMessages()
 | 
				
			||||||
 | 
					  const link1 = /** @type {Y.WeakLink<Y.Map>} */ map1.get('b')
 | 
				
			||||||
 | 
					  const l0 = /** @type {Y.Map<any>} */ (link0.deref())
 | 
				
			||||||
 | 
					  t.compare(link1.ref.get('a1'), l0.get('a1'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  map1.delete('b') // delete links
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  testConnector.flushAllMessages()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // since links have been deleted, they no longer refer to any content
 | 
				
			||||||
 | 
					  t.compare(link0.deref(), undefined)
 | 
				
			||||||
 | 
					  t.compare(link1.deref(), undefined)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  compare(users)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @param {t.TestCase} tc
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export const testDeleteSource = tc => {
 | 
				
			||||||
 | 
					  const { testConnector, users, map0, map1 } = init(tc, { users: 2 })
 | 
				
			||||||
 | 
					  map0.set('a', new Y.Map([['a1', 'hello']]))
 | 
				
			||||||
 | 
					  const link0 = /** @type {Y.WeakLink<Y.Map<any>>} */ (map0.link('a'))
 | 
				
			||||||
 | 
					  map0.set('b', link0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  testConnector.flushAllMessages()
 | 
				
			||||||
 | 
					  const link1 = /** @type {Y.WeakLink<Y.Map<any>>} */ (map1.get('b'))
 | 
				
			||||||
 | 
					  let l1 = /** @type {Y.Map<any>} */ (link1.deref())
 | 
				
			||||||
 | 
					  let l0 = /** @type {Y.Map<any>} */ (link0.deref())
 | 
				
			||||||
 | 
					  t.compare(l1.get('a1'), l0.get('a1'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  map1.delete('a') // delete source of the link
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  testConnector.flushAllMessages()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // since source have been deleted, links no longer refer to any content
 | 
				
			||||||
 | 
					  t.compare(link0.deref(), undefined)
 | 
				
			||||||
 | 
					  t.compare(link1.deref(), undefined)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  compare(users)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @param {t.TestCase} tc
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export const testObserve = tc => {
 | 
				
			||||||
 | 
					  const doc = new Y.Doc()
 | 
				
			||||||
 | 
					  const map = doc.getMap('map')
 | 
				
			||||||
 | 
					  const array = doc.getArray('array')
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * @type {Array<any>}
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  let delta
 | 
				
			||||||
 | 
					  array.observe((e) => delta = e.changes.delta)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  map.set('key', 'value1')
 | 
				
			||||||
 | 
					  const link = map.link('key')
 | 
				
			||||||
 | 
					  array.insert(0, [link])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  delta = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  map.set('key', 'value2')
 | 
				
			||||||
 | 
					  t.compare(delta, [{ delete: 1 }, { insert: 'value2' }])
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @param {t.TestCase} tc
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export const testDeepObserve = tc => {
 | 
				
			||||||
 | 
					  const doc = new Y.Doc()
 | 
				
			||||||
 | 
					  const map = doc.getMap('map')
 | 
				
			||||||
 | 
					  const array = doc.getArray('array')
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * @type {Array<any>}
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  let events
 | 
				
			||||||
 | 
					  array.observeDeep((e) => events = e)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const nested = new Y.Map([['key', 'value']])
 | 
				
			||||||
 | 
					  map.set('key', nested)
 | 
				
			||||||
 | 
					  const link = map.link('key')
 | 
				
			||||||
 | 
					  array.insert(0, [link])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  events = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  nested.set('key', 'value2')
 | 
				
			||||||
 | 
					  for (let i = 0; i < events.length; i++) {
 | 
				
			||||||
 | 
					    let e = events[i]
 | 
				
			||||||
 | 
					    throw new Error('todo')
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @param {t.TestCase} tc
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export const testObserveRecursive = tc => {
 | 
				
			||||||
 | 
					  const doc = new Y.Doc()
 | 
				
			||||||
 | 
					  const map = doc.getMap('map')
 | 
				
			||||||
 | 
					  const array = doc.getArray('array')
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * @type {any}
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  let arrayChanges
 | 
				
			||||||
 | 
					  array.observe((e) => arrayChanges = e.changes)
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * @type {any}
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  let mapChanges
 | 
				
			||||||
 | 
					  map.observe((e) => mapChanges = e.changes)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Y.transact(doc, () => {
 | 
				
			||||||
 | 
					    map.set('key', 'map-value')
 | 
				
			||||||
 | 
					    array.insert(0, [map.link('key')])
 | 
				
			||||||
 | 
					    map.set('key2', array.link(0))
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					  t.compare(arrayChanges.delta, [{ insert: 'map-value' }])
 | 
				
			||||||
 | 
					  t.compare(mapChanges.keys.get('key2'), [{ action: 'insert', oldValue: 'map-value' }])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  t.compare(map.get('key2').deref().deref(), 'map-value')
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user