Implement experimental new encoder 🚀
This commit is contained in:
		
							parent
							
								
									e31e968f0d
								
							
						
					
					
						commit
						6c2cf0f769
					
				
							
								
								
									
										12
									
								
								.jsdoc.json
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								.jsdoc.json
									
									
									
									
									
								
							@ -17,10 +17,13 @@
 | 
			
		||||
    "useCollapsibles": true,
 | 
			
		||||
    "collapse": true,
 | 
			
		||||
    "resources": {
 | 
			
		||||
      "yjs.dev": "Yjs website"
 | 
			
		||||
      "yjs.dev": "Website",
 | 
			
		||||
      "docs.yjs.dev": "Docs",
 | 
			
		||||
      "discuss.yjs.dev": "Forum",
 | 
			
		||||
      "https://gitter.im/Yjs/community": "Chat"
 | 
			
		||||
    },
 | 
			
		||||
    "logo": {
 | 
			
		||||
      "url": "https://user-images.githubusercontent.com/5553757/48975307-61efb100-f06d-11e8-9177-ee895e5916e5.png",
 | 
			
		||||
      "url": "https://yjs.dev/images/logo/yjs-512x512.png",
 | 
			
		||||
      "width": "162px",
 | 
			
		||||
      "height": "162px",
 | 
			
		||||
      "link": "/"
 | 
			
		||||
@ -35,7 +38,7 @@
 | 
			
		||||
    ],
 | 
			
		||||
    "default": {
 | 
			
		||||
      "staticFiles": {
 | 
			
		||||
          "include": ["examples/"]
 | 
			
		||||
          "include": []
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
@ -44,7 +47,6 @@
 | 
			
		||||
    "encoding": "utf8",
 | 
			
		||||
    "private": false,
 | 
			
		||||
    "recurse": true,
 | 
			
		||||
    "template": "./node_modules/tui-jsdoc-template",
 | 
			
		||||
    "tutorials": "./examples"
 | 
			
		||||
    "template": "./node_modules/tui-jsdoc-template"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -958,5 +958,6 @@ Yjs and all related projects are [**MIT licensed**](./LICENSE).
 | 
			
		||||
Yjs is based on my research as a student at the [RWTH
 | 
			
		||||
i5](http://dbis.rwth-aachen.de/). Now I am working on Yjs in my spare time.
 | 
			
		||||
 | 
			
		||||
Fund this project by donating on [Patreon](https://www.patreon.com/dmonad) or
 | 
			
		||||
hiring [me](https://github.com/dmonad) for professional support.
 | 
			
		||||
Fund this project by donating on [GitHub Sponsors](https://github.com/sponsors/dmonad)
 | 
			
		||||
or hiring [me](https://github.com/dmonad) as a contractor for your collaborative
 | 
			
		||||
app.
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										40
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										40
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@ -1429,9 +1429,9 @@
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "isomorphic.js": {
 | 
			
		||||
      "version": "0.1.3",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/isomorphic.js/-/isomorphic.js-0.1.3.tgz",
 | 
			
		||||
      "integrity": "sha512-pabBRLDwYefSsNS+qCazJ97o7P5xDTrNoxSYFTM09JlZTxPrOEPGKekwqUy3/Np4C4PHnVUXHYsZPOix0jELsA=="
 | 
			
		||||
      "version": "0.1.4",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/isomorphic.js/-/isomorphic.js-0.1.4.tgz",
 | 
			
		||||
      "integrity": "sha512-t9zbgkjE7f9f2M6OSW49YEq0lUrSdAllBbWFUZoeck/rnnFae6UlhmDtXWs48VJY3ZpryCoZsRiAiKD44hPIGQ=="
 | 
			
		||||
    },
 | 
			
		||||
    "js-tokens": {
 | 
			
		||||
      "version": "4.0.0",
 | 
			
		||||
@ -1548,9 +1548,9 @@
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "lib0": {
 | 
			
		||||
      "version": "0.2.29",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.29.tgz",
 | 
			
		||||
      "integrity": "sha512-bcQqmh3bUDVXwZrAJnekTpNk0uaShRg1bHMK7uzBIDFAWWdMXXCUtQXO/d/XsIxCiskgHTqF4jiQmDdoPCMVIw==",
 | 
			
		||||
      "version": "0.2.32",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.32.tgz",
 | 
			
		||||
      "integrity": "sha512-cHHKhHTojtvFSsthTk+CKuD17jMHIxuZxYpTzXj9TeQLPNoGNDPl6ax+J6eFETVe3ZvPMh3V0nGfJgGo6QgSvA==",
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "isomorphic.js": "^0.1.3"
 | 
			
		||||
      }
 | 
			
		||||
@ -1716,18 +1716,18 @@
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "markdownlint": {
 | 
			
		||||
      "version": "0.20.3",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.20.3.tgz",
 | 
			
		||||
      "integrity": "sha512-J93s59tGvSFvAPWVUtEgxqPI0CHayTx1Z8poj1/4UJAquHGPIruWRMurkRldiNbgBiaQ4OOt15rHZbFfU6u05A==",
 | 
			
		||||
      "version": "0.20.4",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.20.4.tgz",
 | 
			
		||||
      "integrity": "sha512-jpfaPgjT0OpeBbemjYNZbzGG3hCLcAIvrm/pEY3+q/szDScG6ZonDacqySVRJAv9glbo8y4wBPJ0wgW17+9GGA==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "markdown-it": "10.0.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "markdownlint-cli": {
 | 
			
		||||
      "version": "0.23.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/markdownlint-cli/-/markdownlint-cli-0.23.1.tgz",
 | 
			
		||||
      "integrity": "sha512-UARWuPILksAcVLTosUv1F1tLognNYQ/qjLRIgWwQAYqdl3QQrTPurU/X9Z2jrdAJYlOim868QsufxjYJpH0K7Q==",
 | 
			
		||||
      "version": "0.23.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/markdownlint-cli/-/markdownlint-cli-0.23.2.tgz",
 | 
			
		||||
      "integrity": "sha512-OSl5OZ8xzGN6z355cqRkiq67zPi3reJimklaF72p0554q85Dng5ToOjjSB9tDKZebSt85jX8cp+ruoQlPqOsPA==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "commander": "~2.9.0",
 | 
			
		||||
@ -1739,8 +1739,8 @@
 | 
			
		||||
        "jsonc-parser": "~2.2.0",
 | 
			
		||||
        "lodash.differencewith": "~4.5.0",
 | 
			
		||||
        "lodash.flatten": "~4.4.0",
 | 
			
		||||
        "markdownlint": "~0.20.3",
 | 
			
		||||
        "markdownlint-rule-helpers": "~0.10.0",
 | 
			
		||||
        "markdownlint": "~0.20.4",
 | 
			
		||||
        "markdownlint-rule-helpers": "~0.11.0",
 | 
			
		||||
        "minimatch": "~3.0.4",
 | 
			
		||||
        "minimist": "~1.2.5",
 | 
			
		||||
        "rc": "~1.2.7"
 | 
			
		||||
@ -1770,9 +1770,9 @@
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "markdownlint-rule-helpers": {
 | 
			
		||||
      "version": "0.10.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/markdownlint-rule-helpers/-/markdownlint-rule-helpers-0.10.0.tgz",
 | 
			
		||||
      "integrity": "sha512-0e8VUTjNdQwS7hTyNan9oOLsy4a7KEsXo3fxKMDRFRk6Jn+pLB3iKZ3mj/m6ECrlOUCxPYYmgOmmyk3bSdbIvw==",
 | 
			
		||||
      "version": "0.11.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/markdownlint-rule-helpers/-/markdownlint-rule-helpers-0.11.0.tgz",
 | 
			
		||||
      "integrity": "sha512-PhGii9dOiDJDXxiRMpK8N0FM9powprvRPsXALgkjlSPTwLh6ymH+iF3iUe3nq8KGu26tclFBlLL5xAGy/zb7FA==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "marked": {
 | 
			
		||||
@ -2786,9 +2786,9 @@
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "typescript": {
 | 
			
		||||
      "version": "3.9.3",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.3.tgz",
 | 
			
		||||
      "integrity": "sha512-D/wqnB2xzNFIcoBG9FG8cXRDjiqSTbG2wd8DMZeQyJlP1vfTkIxH4GKveWaEBYySKIg+USu+E+EDIR47SqnaMQ==",
 | 
			
		||||
      "version": "3.9.6",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.6.tgz",
 | 
			
		||||
      "integrity": "sha512-Pspx3oKAPJtjNwE92YS05HQoY7z2SFyOpHo9MqJor3BXAGNaPUs83CuVp9VISFkSjyRfiTpmKuAYGJB7S7hOxw==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "uc.micro": {
 | 
			
		||||
 | 
			
		||||
@ -18,7 +18,7 @@
 | 
			
		||||
    "lint": "markdownlint README.md && standard && tsc",
 | 
			
		||||
    "docs": "rm -rf docs; jsdoc --configure ./.jsdoc.json --verbose --readme ./README.md --package ./package.json || true",
 | 
			
		||||
    "serve-docs": "npm run docs && http-server ./docs/",
 | 
			
		||||
    "preversion": "npm run lint && PRODUCTION=1 npm run dist && npm run docs && node ./dist/tests.cjs --repitition-time 1000",
 | 
			
		||||
    "preversion": "npm run lint && PRODUCTION=1 npm run dist && npm run docs && node ./dist/tests.cjs --repitition-time 1000 && test -e dist/src/index.d.ts && test -e dist/yjs.cjs && test -e dist/yjs.cjs",
 | 
			
		||||
    "debug": "concurrently 'http-server -o test.html' 'npm run watch'",
 | 
			
		||||
    "trace-deopt": "clear && rollup -c  && node --trace-deopt dist/test.cjs",
 | 
			
		||||
    "trace-opt": "clear && rollup -c  && node --trace-opt dist/test.cjs"
 | 
			
		||||
@ -60,7 +60,7 @@
 | 
			
		||||
  },
 | 
			
		||||
  "homepage": "https://yjs.dev",
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "lib0": "^0.2.29"
 | 
			
		||||
    "lib0": "^0.2.32"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "@rollup/plugin-commonjs": "^11.1.0",
 | 
			
		||||
@ -68,12 +68,12 @@
 | 
			
		||||
    "concurrently": "^3.6.1",
 | 
			
		||||
    "http-server": "^0.12.3",
 | 
			
		||||
    "jsdoc": "^3.6.4",
 | 
			
		||||
    "markdownlint-cli": "^0.23.1",
 | 
			
		||||
    "markdownlint-cli": "^0.23.2",
 | 
			
		||||
    "rollup": "^1.32.1",
 | 
			
		||||
    "rollup-cli": "^1.0.9",
 | 
			
		||||
    "standard": "^14.3.4",
 | 
			
		||||
    "tui-jsdoc-template": "^1.2.2",
 | 
			
		||||
    "typescript": "^3.9.3",
 | 
			
		||||
    "typescript": "^3.9.6",
 | 
			
		||||
    "y-protocols": "^0.2.3"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -48,12 +48,18 @@ export {
 | 
			
		||||
  typeMapGetSnapshot,
 | 
			
		||||
  iterateDeletedStructs,
 | 
			
		||||
  applyUpdate,
 | 
			
		||||
  applyUpdateV2,
 | 
			
		||||
  readUpdate,
 | 
			
		||||
  readUpdateV2,
 | 
			
		||||
  encodeStateAsUpdate,
 | 
			
		||||
  encodeStateAsUpdateV2,
 | 
			
		||||
  encodeStateVector,
 | 
			
		||||
  encodeStateVectorV2,
 | 
			
		||||
  UndoManager,
 | 
			
		||||
  decodeSnapshot,
 | 
			
		||||
  encodeSnapshot,
 | 
			
		||||
  decodeSnapshotV2,
 | 
			
		||||
  encodeSnapshotV2,
 | 
			
		||||
  isDeleted,
 | 
			
		||||
  isParentOf,
 | 
			
		||||
  equalSnapshots,
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,8 @@
 | 
			
		||||
 | 
			
		||||
export * from './utils/DeleteSet.js'
 | 
			
		||||
export * from './utils/Doc.js'
 | 
			
		||||
export * from './utils/UpdateDecoder.js'
 | 
			
		||||
export * from './utils/UpdateEncoder.js'
 | 
			
		||||
export * from './utils/encoding.js'
 | 
			
		||||
export * from './utils/EventHandler.js'
 | 
			
		||||
export * from './utils/ID.js'
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,8 @@
 | 
			
		||||
 | 
			
		||||
import {
 | 
			
		||||
  StructStore, ID, Transaction // eslint-disable-line
 | 
			
		||||
  AbstractUpdateEncoder, ID, Transaction // eslint-disable-line
 | 
			
		||||
} from '../internals.js'
 | 
			
		||||
 | 
			
		||||
import * as encoding from 'lib0/encoding.js' // eslint-disable-line
 | 
			
		||||
import * as error from 'lib0/error.js'
 | 
			
		||||
 | 
			
		||||
export class AbstractStruct {
 | 
			
		||||
@ -35,7 +34,7 @@ export class AbstractStruct {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {encoding.Encoder} encoder The encoder to write data to.
 | 
			
		||||
   * @param {AbstractUpdateEncoder} encoder The encoder to write data to.
 | 
			
		||||
   * @param {number} offset
 | 
			
		||||
   * @param {number} encodingRef
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,7 @@
 | 
			
		||||
import {
 | 
			
		||||
  Transaction, Item, StructStore // eslint-disable-line
 | 
			
		||||
  AbstractUpdateDecoder, AbstractUpdateEncoder, Transaction, Item, StructStore // eslint-disable-line
 | 
			
		||||
} from '../internals.js'
 | 
			
		||||
 | 
			
		||||
import * as encoding from 'lib0/encoding.js'
 | 
			
		||||
import * as decoding from 'lib0/decoding.js'
 | 
			
		||||
 | 
			
		||||
export class ContentAny {
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {Array<any>} arr
 | 
			
		||||
@ -77,15 +74,15 @@ export class ContentAny {
 | 
			
		||||
   */
 | 
			
		||||
  gc (store) {}
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {encoding.Encoder} encoder
 | 
			
		||||
   * @param {AbstractUpdateEncoder} encoder
 | 
			
		||||
   * @param {number} offset
 | 
			
		||||
   */
 | 
			
		||||
  write (encoder, offset) {
 | 
			
		||||
    const len = this.arr.length
 | 
			
		||||
    encoding.writeVarUint(encoder, len - offset)
 | 
			
		||||
    encoder.writeLen(len - offset)
 | 
			
		||||
    for (let i = offset; i < len; i++) {
 | 
			
		||||
      const c = this.arr[i]
 | 
			
		||||
      encoding.writeAny(encoder, c)
 | 
			
		||||
      encoder.writeAny(c)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -98,14 +95,14 @@ export class ContentAny {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {decoding.Decoder} decoder
 | 
			
		||||
 * @param {AbstractUpdateDecoder} decoder
 | 
			
		||||
 * @return {ContentAny}
 | 
			
		||||
 */
 | 
			
		||||
export const readContentAny = decoder => {
 | 
			
		||||
  const len = decoding.readVarUint(decoder)
 | 
			
		||||
  const len = decoder.readLen()
 | 
			
		||||
  const cs = []
 | 
			
		||||
  for (let i = 0; i < len; i++) {
 | 
			
		||||
    cs.push(decoding.readAny(decoder))
 | 
			
		||||
    cs.push(decoder.readAny())
 | 
			
		||||
  }
 | 
			
		||||
  return new ContentAny(cs)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,7 @@
 | 
			
		||||
import {
 | 
			
		||||
  StructStore, Item, Transaction // eslint-disable-line
 | 
			
		||||
  AbstractUpdateDecoder, AbstractUpdateEncoder, StructStore, Item, Transaction // eslint-disable-line
 | 
			
		||||
} from '../internals.js'
 | 
			
		||||
 | 
			
		||||
import * as encoding from 'lib0/encoding.js'
 | 
			
		||||
import * as decoding from 'lib0/decoding.js'
 | 
			
		||||
import * as buffer from 'lib0/buffer.js'
 | 
			
		||||
import * as error from 'lib0/error.js'
 | 
			
		||||
 | 
			
		||||
export class ContentBinary {
 | 
			
		||||
@ -73,11 +70,11 @@ export class ContentBinary {
 | 
			
		||||
   */
 | 
			
		||||
  gc (store) {}
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {encoding.Encoder} encoder
 | 
			
		||||
   * @param {AbstractUpdateEncoder} encoder
 | 
			
		||||
   * @param {number} offset
 | 
			
		||||
   */
 | 
			
		||||
  write (encoder, offset) {
 | 
			
		||||
    encoding.writeVarUint8Array(encoder, this.content)
 | 
			
		||||
    encoder.writeBuf(this.content)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
@ -89,7 +86,7 @@ export class ContentBinary {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {decoding.Decoder} decoder
 | 
			
		||||
 * @param {AbstractUpdateDecoder} decoder
 | 
			
		||||
 * @return {ContentBinary}
 | 
			
		||||
 */
 | 
			
		||||
export const readContentBinary = decoder => new ContentBinary(buffer.copyUint8Array(decoding.readVarUint8Array(decoder)))
 | 
			
		||||
export const readContentBinary = decoder => new ContentBinary(decoder.readBuf())
 | 
			
		||||
 | 
			
		||||
@ -1,12 +1,9 @@
 | 
			
		||||
 | 
			
		||||
import {
 | 
			
		||||
  addToDeleteSet,
 | 
			
		||||
  StructStore, Item, Transaction // eslint-disable-line
 | 
			
		||||
  AbstractUpdateDecoder, AbstractUpdateEncoder, StructStore, Item, Transaction // eslint-disable-line
 | 
			
		||||
} from '../internals.js'
 | 
			
		||||
 | 
			
		||||
import * as encoding from 'lib0/encoding.js'
 | 
			
		||||
import * as decoding from 'lib0/decoding.js'
 | 
			
		||||
 | 
			
		||||
export class ContentDeleted {
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {number} len
 | 
			
		||||
@ -67,7 +64,7 @@ export class ContentDeleted {
 | 
			
		||||
   * @param {Item} item
 | 
			
		||||
   */
 | 
			
		||||
  integrate (transaction, item) {
 | 
			
		||||
    addToDeleteSet(transaction.deleteSet, item.id, this.len)
 | 
			
		||||
    addToDeleteSet(transaction.deleteSet, item.id.client, item.id.clock, this.len)
 | 
			
		||||
    item.markDeleted()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -80,11 +77,11 @@ export class ContentDeleted {
 | 
			
		||||
   */
 | 
			
		||||
  gc (store) {}
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {encoding.Encoder} encoder
 | 
			
		||||
   * @param {AbstractUpdateEncoder} encoder
 | 
			
		||||
   * @param {number} offset
 | 
			
		||||
   */
 | 
			
		||||
  write (encoder, offset) {
 | 
			
		||||
    encoding.writeVarUint(encoder, this.len - offset)
 | 
			
		||||
    encoder.writeLen(this.len - offset)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
@ -98,7 +95,7 @@ export class ContentDeleted {
 | 
			
		||||
/**
 | 
			
		||||
 * @private
 | 
			
		||||
 *
 | 
			
		||||
 * @param {decoding.Decoder} decoder
 | 
			
		||||
 * @param {AbstractUpdateDecoder} decoder
 | 
			
		||||
 * @return {ContentDeleted}
 | 
			
		||||
 */
 | 
			
		||||
export const readContentDeleted = decoder => new ContentDeleted(decoding.readVarUint(decoder))
 | 
			
		||||
export const readContentDeleted = decoder => new ContentDeleted(decoder.readLen())
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,8 @@
 | 
			
		||||
 | 
			
		||||
import {
 | 
			
		||||
  StructStore, Item, Transaction // eslint-disable-line
 | 
			
		||||
  AbstractUpdateDecoder, AbstractUpdateEncoder, StructStore, Item, Transaction // eslint-disable-line
 | 
			
		||||
} from '../internals.js'
 | 
			
		||||
 | 
			
		||||
import * as encoding from 'lib0/encoding.js'
 | 
			
		||||
import * as decoding from 'lib0/decoding.js'
 | 
			
		||||
import * as error from 'lib0/error.js'
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@ -76,11 +74,11 @@ export class ContentEmbed {
 | 
			
		||||
   */
 | 
			
		||||
  gc (store) {}
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {encoding.Encoder} encoder
 | 
			
		||||
   * @param {AbstractUpdateEncoder} encoder
 | 
			
		||||
   * @param {number} offset
 | 
			
		||||
   */
 | 
			
		||||
  write (encoder, offset) {
 | 
			
		||||
    encoding.writeVarString(encoder, JSON.stringify(this.embed))
 | 
			
		||||
    encoder.writeJSON(this.embed)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
@ -94,7 +92,7 @@ export class ContentEmbed {
 | 
			
		||||
/**
 | 
			
		||||
 * @private
 | 
			
		||||
 *
 | 
			
		||||
 * @param {decoding.Decoder} decoder
 | 
			
		||||
 * @param {AbstractUpdateDecoder} decoder
 | 
			
		||||
 * @return {ContentEmbed}
 | 
			
		||||
 */
 | 
			
		||||
export const readContentEmbed = decoder => new ContentEmbed(JSON.parse(decoding.readVarString(decoder)))
 | 
			
		||||
export const readContentEmbed = decoder => new ContentEmbed(decoder.readJSON())
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,8 @@
 | 
			
		||||
 | 
			
		||||
import {
 | 
			
		||||
  Item, StructStore, Transaction // eslint-disable-line
 | 
			
		||||
  AbstractUpdateDecoder, AbstractUpdateEncoder, Item, StructStore, Transaction // eslint-disable-line
 | 
			
		||||
} from '../internals.js'
 | 
			
		||||
 | 
			
		||||
import * as encoding from 'lib0/encoding.js'
 | 
			
		||||
import * as decoding from 'lib0/decoding.js'
 | 
			
		||||
import * as error from 'lib0/error.js'
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@ -78,12 +76,12 @@ export class ContentFormat {
 | 
			
		||||
   */
 | 
			
		||||
  gc (store) {}
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {encoding.Encoder} encoder
 | 
			
		||||
   * @param {AbstractUpdateEncoder} encoder
 | 
			
		||||
   * @param {number} offset
 | 
			
		||||
   */
 | 
			
		||||
  write (encoder, offset) {
 | 
			
		||||
    encoding.writeVarString(encoder, this.key)
 | 
			
		||||
    encoding.writeVarString(encoder, JSON.stringify(this.value))
 | 
			
		||||
    encoder.writeKey(this.key)
 | 
			
		||||
    encoder.writeJSON(this.value)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
@ -95,7 +93,7 @@ export class ContentFormat {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {decoding.Decoder} decoder
 | 
			
		||||
 * @param {AbstractUpdateDecoder} decoder
 | 
			
		||||
 * @return {ContentFormat}
 | 
			
		||||
 */
 | 
			
		||||
export const readContentFormat = decoder => new ContentFormat(decoding.readVarString(decoder), JSON.parse(decoding.readVarString(decoder)))
 | 
			
		||||
export const readContentFormat = decoder => new ContentFormat(decoder.readString(), decoder.readJSON())
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,7 @@
 | 
			
		||||
import {
 | 
			
		||||
  Transaction, Item, StructStore // eslint-disable-line
 | 
			
		||||
  AbstractUpdateDecoder, AbstractUpdateEncoder, Transaction, Item, StructStore // eslint-disable-line
 | 
			
		||||
} from '../internals.js'
 | 
			
		||||
 | 
			
		||||
import * as encoding from 'lib0/encoding.js'
 | 
			
		||||
import * as decoding from 'lib0/decoding.js'
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @private
 | 
			
		||||
 */
 | 
			
		||||
@ -80,15 +77,15 @@ export class ContentJSON {
 | 
			
		||||
   */
 | 
			
		||||
  gc (store) {}
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {encoding.Encoder} encoder
 | 
			
		||||
   * @param {AbstractUpdateEncoder} encoder
 | 
			
		||||
   * @param {number} offset
 | 
			
		||||
   */
 | 
			
		||||
  write (encoder, offset) {
 | 
			
		||||
    const len = this.arr.length
 | 
			
		||||
    encoding.writeVarUint(encoder, len - offset)
 | 
			
		||||
    encoder.writeLen(len - offset)
 | 
			
		||||
    for (let i = offset; i < len; i++) {
 | 
			
		||||
      const c = this.arr[i]
 | 
			
		||||
      encoding.writeVarString(encoder, c === undefined ? 'undefined' : JSON.stringify(c))
 | 
			
		||||
      encoder.writeString(c === undefined ? 'undefined' : JSON.stringify(c))
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -103,14 +100,14 @@ export class ContentJSON {
 | 
			
		||||
/**
 | 
			
		||||
 * @private
 | 
			
		||||
 *
 | 
			
		||||
 * @param {decoding.Decoder} decoder
 | 
			
		||||
 * @param {AbstractUpdateDecoder} decoder
 | 
			
		||||
 * @return {ContentJSON}
 | 
			
		||||
 */
 | 
			
		||||
export const readContentJSON = decoder => {
 | 
			
		||||
  const len = decoding.readVarUint(decoder)
 | 
			
		||||
  const len = decoder.readLen()
 | 
			
		||||
  const cs = []
 | 
			
		||||
  for (let i = 0; i < len; i++) {
 | 
			
		||||
    const c = decoding.readVarString(decoder)
 | 
			
		||||
    const c = decoder.readString()
 | 
			
		||||
    if (c === 'undefined') {
 | 
			
		||||
      cs.push(undefined)
 | 
			
		||||
    } else {
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,7 @@
 | 
			
		||||
import {
 | 
			
		||||
  Transaction, Item, StructStore // eslint-disable-line
 | 
			
		||||
  AbstractUpdateDecoder, AbstractUpdateEncoder, Transaction, Item, StructStore // eslint-disable-line
 | 
			
		||||
} from '../internals.js'
 | 
			
		||||
 | 
			
		||||
import * as encoding from 'lib0/encoding.js'
 | 
			
		||||
import * as decoding from 'lib0/decoding.js'
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @private
 | 
			
		||||
 */
 | 
			
		||||
@ -80,11 +77,11 @@ export class ContentString {
 | 
			
		||||
   */
 | 
			
		||||
  gc (store) {}
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {encoding.Encoder} encoder
 | 
			
		||||
   * @param {AbstractUpdateEncoder} encoder
 | 
			
		||||
   * @param {number} offset
 | 
			
		||||
   */
 | 
			
		||||
  write (encoder, offset) {
 | 
			
		||||
    encoding.writeVarString(encoder, offset === 0 ? this.str : this.str.slice(offset))
 | 
			
		||||
    encoder.writeString(offset === 0 ? this.str : this.str.slice(offset))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
@ -98,7 +95,7 @@ export class ContentString {
 | 
			
		||||
/**
 | 
			
		||||
 * @private
 | 
			
		||||
 *
 | 
			
		||||
 * @param {decoding.Decoder} decoder
 | 
			
		||||
 * @param {AbstractUpdateDecoder} decoder
 | 
			
		||||
 * @return {ContentString}
 | 
			
		||||
 */
 | 
			
		||||
export const readContentString = decoder => new ContentString(decoding.readVarString(decoder))
 | 
			
		||||
export const readContentString = decoder => new ContentString(decoder.readString())
 | 
			
		||||
 | 
			
		||||
@ -7,15 +7,13 @@ import {
 | 
			
		||||
  readYXmlFragment,
 | 
			
		||||
  readYXmlHook,
 | 
			
		||||
  readYXmlText,
 | 
			
		||||
  ID, StructStore, Transaction, Item, YEvent, AbstractType // eslint-disable-line
 | 
			
		||||
  AbstractUpdateDecoder, AbstractUpdateEncoder, StructStore, Transaction, Item, YEvent, AbstractType // eslint-disable-line
 | 
			
		||||
} from '../internals.js'
 | 
			
		||||
 | 
			
		||||
import * as encoding from 'lib0/encoding.js' // eslint-disable-line
 | 
			
		||||
import * as decoding from 'lib0/decoding.js'
 | 
			
		||||
import * as error from 'lib0/error.js'
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @type {Array<function(decoding.Decoder):AbstractType<any>>}
 | 
			
		||||
 * @type {Array<function(AbstractUpdateDecoder):AbstractType<any>>}
 | 
			
		||||
 * @private
 | 
			
		||||
 */
 | 
			
		||||
export const typeRefs = [
 | 
			
		||||
@ -150,7 +148,7 @@ export class ContentType {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {encoding.Encoder} encoder
 | 
			
		||||
   * @param {AbstractUpdateEncoder} encoder
 | 
			
		||||
   * @param {number} offset
 | 
			
		||||
   */
 | 
			
		||||
  write (encoder, offset) {
 | 
			
		||||
@ -168,7 +166,7 @@ export class ContentType {
 | 
			
		||||
/**
 | 
			
		||||
 * @private
 | 
			
		||||
 *
 | 
			
		||||
 * @param {decoding.Decoder} decoder
 | 
			
		||||
 * @param {AbstractUpdateDecoder} decoder
 | 
			
		||||
 * @return {ContentType}
 | 
			
		||||
 */
 | 
			
		||||
export const readContentType = decoder => new ContentType(typeRefs[decoding.readVarUint(decoder)](decoder))
 | 
			
		||||
export const readContentType = decoder => new ContentType(typeRefs[decoder.readTypeRef()](decoder))
 | 
			
		||||
 | 
			
		||||
@ -2,11 +2,9 @@
 | 
			
		||||
import {
 | 
			
		||||
  AbstractStruct,
 | 
			
		||||
  addStruct,
 | 
			
		||||
  StructStore, Transaction, ID // eslint-disable-line
 | 
			
		||||
  AbstractUpdateEncoder, StructStore, Transaction, ID // eslint-disable-line
 | 
			
		||||
} from '../internals.js'
 | 
			
		||||
 | 
			
		||||
import * as encoding from 'lib0/encoding.js'
 | 
			
		||||
 | 
			
		||||
export const structGCRefNumber = 0
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@ -41,12 +39,12 @@ export class GC extends AbstractStruct {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {encoding.Encoder} encoder
 | 
			
		||||
   * @param {AbstractUpdateEncoder} encoder
 | 
			
		||||
   * @param {number} offset
 | 
			
		||||
   */
 | 
			
		||||
  write (encoder, offset) {
 | 
			
		||||
    encoding.writeUint8(encoder, structGCRefNumber)
 | 
			
		||||
    encoding.writeVarUint(encoder, this.length - offset)
 | 
			
		||||
    encoder.writeInfo(structGCRefNumber)
 | 
			
		||||
    encoder.writeLen(this.length - offset)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,5 @@
 | 
			
		||||
 | 
			
		||||
import {
 | 
			
		||||
  readID,
 | 
			
		||||
  writeID,
 | 
			
		||||
  GC,
 | 
			
		||||
  getState,
 | 
			
		||||
  AbstractStruct,
 | 
			
		||||
@ -23,12 +21,10 @@ import {
 | 
			
		||||
  readContentFormat,
 | 
			
		||||
  readContentType,
 | 
			
		||||
  addChangedTypeToTransaction,
 | 
			
		||||
  Doc, ContentType, ContentDeleted, StructStore, ID, AbstractType, Transaction // eslint-disable-line
 | 
			
		||||
  AbstractUpdateDecoder, AbstractUpdateEncoder, ContentType, ContentDeleted, StructStore, ID, AbstractType, Transaction // eslint-disable-line
 | 
			
		||||
} from '../internals.js'
 | 
			
		||||
 | 
			
		||||
import * as error from 'lib0/error.js'
 | 
			
		||||
import * as encoding from 'lib0/encoding.js'
 | 
			
		||||
import * as decoding from 'lib0/decoding.js'
 | 
			
		||||
import * as maplib from 'lib0/map.js'
 | 
			
		||||
import * as set from 'lib0/set.js'
 | 
			
		||||
import * as binary from 'lib0/binary.js'
 | 
			
		||||
@ -574,7 +570,7 @@ export class Item extends AbstractStruct {
 | 
			
		||||
        parent._length -= this.length
 | 
			
		||||
      }
 | 
			
		||||
      this.markDeleted()
 | 
			
		||||
      addToDeleteSet(transaction.deleteSet, this.id, this.length)
 | 
			
		||||
      addToDeleteSet(transaction.deleteSet, this.id.client, this.id.clock, this.length)
 | 
			
		||||
      maplib.setIfUndefined(transaction.changed, parent, set.create).add(this.parentSub)
 | 
			
		||||
      this.content.delete(transaction)
 | 
			
		||||
    }
 | 
			
		||||
@ -602,7 +598,7 @@ export class Item extends AbstractStruct {
 | 
			
		||||
   *
 | 
			
		||||
   * This is called when this Item is sent to a remote peer.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {encoding.Encoder} encoder The encoder to write data to.
 | 
			
		||||
   * @param {AbstractUpdateEncoder} encoder The encoder to write data to.
 | 
			
		||||
   * @param {number} offset
 | 
			
		||||
   */
 | 
			
		||||
  write (encoder, offset) {
 | 
			
		||||
@ -613,12 +609,12 @@ export class Item extends AbstractStruct {
 | 
			
		||||
      (origin === null ? 0 : binary.BIT8) | // origin is defined
 | 
			
		||||
      (rightOrigin === null ? 0 : binary.BIT7) | // right origin is defined
 | 
			
		||||
      (parentSub === null ? 0 : binary.BIT6) // parentSub is non-null
 | 
			
		||||
    encoding.writeUint8(encoder, info)
 | 
			
		||||
    encoder.writeInfo(info)
 | 
			
		||||
    if (origin !== null) {
 | 
			
		||||
      writeID(encoder, origin)
 | 
			
		||||
      encoder.writeLeftID(origin)
 | 
			
		||||
    }
 | 
			
		||||
    if (rightOrigin !== null) {
 | 
			
		||||
      writeID(encoder, rightOrigin)
 | 
			
		||||
      encoder.writeRightID(rightOrigin)
 | 
			
		||||
    }
 | 
			
		||||
    if (origin === null && rightOrigin === null) {
 | 
			
		||||
      const parent = /** @type {AbstractType<any>} */ (this.parent)
 | 
			
		||||
@ -627,14 +623,14 @@ export class Item extends AbstractStruct {
 | 
			
		||||
        // parent type on y._map
 | 
			
		||||
        // find the correct key
 | 
			
		||||
        const ykey = findRootTypeKey(parent)
 | 
			
		||||
        encoding.writeVarUint(encoder, 1) // write parentYKey
 | 
			
		||||
        encoding.writeVarString(encoder, ykey)
 | 
			
		||||
        encoder.writeParentInfo(true) // write parentYKey
 | 
			
		||||
        encoder.writeString(ykey)
 | 
			
		||||
      } else {
 | 
			
		||||
        encoding.writeVarUint(encoder, 0) // write parent id
 | 
			
		||||
        writeID(encoder, parentItem.id)
 | 
			
		||||
        encoder.writeParentInfo(false) // write parent id
 | 
			
		||||
        encoder.writeLeftID(parentItem.id)
 | 
			
		||||
      }
 | 
			
		||||
      if (parentSub !== null) {
 | 
			
		||||
        encoding.writeVarString(encoder, parentSub)
 | 
			
		||||
        encoder.writeString(parentSub)
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    this.content.write(encoder, offset)
 | 
			
		||||
@ -642,15 +638,15 @@ export class Item extends AbstractStruct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {decoding.Decoder} decoder
 | 
			
		||||
 * @param {AbstractUpdateDecoder} decoder
 | 
			
		||||
 * @param {number} info
 | 
			
		||||
 */
 | 
			
		||||
const readItemContent = (decoder, info) => contentRefs[info & binary.BITS5](decoder)
 | 
			
		||||
export const readItemContent = (decoder, info) => contentRefs[info & binary.BITS5](decoder)
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A lookup map for reading Item content.
 | 
			
		||||
 *
 | 
			
		||||
 * @type {Array<function(decoding.Decoder):AbstractContent>}
 | 
			
		||||
 * @type {Array<function(AbstractUpdateDecoder):AbstractContent>}
 | 
			
		||||
 */
 | 
			
		||||
export const contentRefs = [
 | 
			
		||||
  () => { throw error.unexpectedCase() }, // GC is not ItemContent
 | 
			
		||||
@ -741,7 +737,7 @@ export class AbstractContent {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {encoding.Encoder} encoder
 | 
			
		||||
   * @param {AbstractUpdateEncoder} encoder
 | 
			
		||||
   * @param {number} offset
 | 
			
		||||
   */
 | 
			
		||||
  write (encoder, offset) {
 | 
			
		||||
@ -755,38 +751,3 @@ export class AbstractContent {
 | 
			
		||||
    throw error.methodUnimplemented()
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {decoding.Decoder} decoder
 | 
			
		||||
 * @param {ID} id
 | 
			
		||||
 * @param {number} info
 | 
			
		||||
 * @param {Doc} doc
 | 
			
		||||
 */
 | 
			
		||||
export const readItem = (decoder, id, info, doc) => {
 | 
			
		||||
  /**
 | 
			
		||||
   * The item that was originally to the left of this item.
 | 
			
		||||
   * @type {ID | null}
 | 
			
		||||
   */
 | 
			
		||||
  const origin = (info & binary.BIT8) === binary.BIT8 ? readID(decoder) : null
 | 
			
		||||
  /**
 | 
			
		||||
   * The item that was originally to the right of this item.
 | 
			
		||||
   * @type {ID | null}
 | 
			
		||||
   */
 | 
			
		||||
  const rightOrigin = (info & binary.BIT7) === binary.BIT7 ? readID(decoder) : null
 | 
			
		||||
  const canCopyParentInfo = (info & (binary.BIT7 | binary.BIT8)) === 0
 | 
			
		||||
  const hasParentYKey = canCopyParentInfo ? decoding.readVarUint(decoder) === 1 : false
 | 
			
		||||
  /**
 | 
			
		||||
   * If parent = null and neither left nor right are defined, then we know that `parent` is child of `y`
 | 
			
		||||
   * and we read the next string as parentYKey.
 | 
			
		||||
   * It indicates how we store/retrieve parent from `y.share`
 | 
			
		||||
   * @type {string|null}
 | 
			
		||||
   */
 | 
			
		||||
  const parentYKey = canCopyParentInfo && hasParentYKey ? decoding.readVarString(decoder) : null
 | 
			
		||||
 | 
			
		||||
  return new Item(
 | 
			
		||||
    id, null, origin, null, rightOrigin,
 | 
			
		||||
    canCopyParentInfo && !hasParentYKey ? readID(decoder) : (parentYKey ? doc.get(parentYKey) : null), // parent
 | 
			
		||||
    canCopyParentInfo && (info & binary.BIT6) === binary.BIT6 ? decoding.readVarString(decoder) : null, // parentSub
 | 
			
		||||
    /** @type {AbstractContent} */ (readItemContent(decoder, info)) // item content
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -11,13 +11,12 @@ import {
 | 
			
		||||
  ContentAny,
 | 
			
		||||
  ContentBinary,
 | 
			
		||||
  getItemCleanStart,
 | 
			
		||||
  ID, Doc, Snapshot, Transaction, EventHandler, YEvent, Item, // eslint-disable-line
 | 
			
		||||
  AbstractUpdateEncoder, Doc, Snapshot, Transaction, EventHandler, YEvent, Item, // eslint-disable-line
 | 
			
		||||
} from '../internals.js'
 | 
			
		||||
 | 
			
		||||
import * as map from 'lib0/map.js'
 | 
			
		||||
import * as iterator from 'lib0/iterator.js'
 | 
			
		||||
import * as error from 'lib0/error.js'
 | 
			
		||||
import * as encoding from 'lib0/encoding.js' // eslint-disable-line
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Accumulate all (list) children of a type and return them as an Array.
 | 
			
		||||
@ -116,7 +115,7 @@ export class AbstractType {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {encoding.Encoder} encoder
 | 
			
		||||
   * @param {AbstractUpdateEncoder} encoder
 | 
			
		||||
   */
 | 
			
		||||
  _write (encoder) { }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -15,12 +15,9 @@ import {
 | 
			
		||||
  YArrayRefID,
 | 
			
		||||
  callTypeObservers,
 | 
			
		||||
  transact,
 | 
			
		||||
  Doc, Transaction, Item // eslint-disable-line
 | 
			
		||||
  AbstractUpdateDecoder, AbstractUpdateEncoder, Doc, Transaction, Item // eslint-disable-line
 | 
			
		||||
} from '../internals.js'
 | 
			
		||||
 | 
			
		||||
import * as decoding from 'lib0/decoding.js' // eslint-disable-line
 | 
			
		||||
import * as encoding from 'lib0/encoding.js'
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Event that describes the changes on a YArray
 | 
			
		||||
 * @template T
 | 
			
		||||
@ -204,15 +201,15 @@ export class YArray extends AbstractType {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {encoding.Encoder} encoder
 | 
			
		||||
   * @param {AbstractUpdateEncoder} encoder
 | 
			
		||||
   */
 | 
			
		||||
  _write (encoder) {
 | 
			
		||||
    encoding.writeVarUint(encoder, YArrayRefID)
 | 
			
		||||
    encoder.writeTypeRef(YArrayRefID)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {decoding.Decoder} decoder
 | 
			
		||||
 * @param {AbstractUpdateDecoder} decoder
 | 
			
		||||
 *
 | 
			
		||||
 * @private
 | 
			
		||||
 * @function
 | 
			
		||||
 | 
			
		||||
@ -14,11 +14,9 @@ import {
 | 
			
		||||
  YMapRefID,
 | 
			
		||||
  callTypeObservers,
 | 
			
		||||
  transact,
 | 
			
		||||
  Doc, Transaction, Item // eslint-disable-line
 | 
			
		||||
  AbstractUpdateDecoder, AbstractUpdateEncoder, Doc, Transaction, Item // eslint-disable-line
 | 
			
		||||
} from '../internals.js'
 | 
			
		||||
 | 
			
		||||
import * as encoding from 'lib0/encoding.js'
 | 
			
		||||
import * as decoding from 'lib0/decoding.js' // eslint-disable-line
 | 
			
		||||
import * as iterator from 'lib0/iterator.js'
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@ -229,15 +227,15 @@ export class YMap extends AbstractType {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {encoding.Encoder} encoder
 | 
			
		||||
   * @param {AbstractUpdateEncoder} encoder
 | 
			
		||||
   */
 | 
			
		||||
  _write (encoder) {
 | 
			
		||||
    encoding.writeVarUint(encoder, YMapRefID)
 | 
			
		||||
    encoder.writeTypeRef(YMapRefID)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {decoding.Decoder} decoder
 | 
			
		||||
 * @param {AbstractUpdateDecoder} decoder
 | 
			
		||||
 *
 | 
			
		||||
 * @private
 | 
			
		||||
 * @function
 | 
			
		||||
 | 
			
		||||
@ -20,11 +20,9 @@ import {
 | 
			
		||||
  splitSnapshotAffectedStructs,
 | 
			
		||||
  iterateDeletedStructs,
 | 
			
		||||
  iterateStructs,
 | 
			
		||||
  ID, Doc, Item, Snapshot, Transaction // eslint-disable-line
 | 
			
		||||
  AbstractUpdateDecoder, AbstractUpdateEncoder, ID, Doc, Item, Snapshot, Transaction // eslint-disable-line
 | 
			
		||||
} from '../internals.js'
 | 
			
		||||
 | 
			
		||||
import * as decoding from 'lib0/decoding.js' // eslint-disable-line
 | 
			
		||||
import * as encoding from 'lib0/encoding.js'
 | 
			
		||||
import * as object from 'lib0/object.js'
 | 
			
		||||
import * as map from 'lib0/map.js'
 | 
			
		||||
 | 
			
		||||
@ -1096,15 +1094,15 @@ export class YText extends AbstractType {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {encoding.Encoder} encoder
 | 
			
		||||
   * @param {AbstractUpdateEncoder} encoder
 | 
			
		||||
   */
 | 
			
		||||
  _write (encoder) {
 | 
			
		||||
    encoding.writeVarUint(encoder, YTextRefID)
 | 
			
		||||
    encoder.writeTypeRef(YTextRefID)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {decoding.Decoder} decoder
 | 
			
		||||
 * @param {AbstractUpdateDecoder} decoder
 | 
			
		||||
 * @return {YText}
 | 
			
		||||
 *
 | 
			
		||||
 * @private
 | 
			
		||||
 | 
			
		||||
@ -8,12 +8,9 @@ import {
 | 
			
		||||
  typeMapGetAll,
 | 
			
		||||
  typeListForEach,
 | 
			
		||||
  YXmlElementRefID,
 | 
			
		||||
  Snapshot, Doc, Item // eslint-disable-line
 | 
			
		||||
  AbstractUpdateDecoder, AbstractUpdateEncoder, Snapshot, Doc, Item // eslint-disable-line
 | 
			
		||||
} from '../internals.js'
 | 
			
		||||
 | 
			
		||||
import * as encoding from 'lib0/encoding.js'
 | 
			
		||||
import * as decoding from 'lib0/decoding.js'
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * An YXmlElement imitates the behavior of a
 | 
			
		||||
 * {@link https://developer.mozilla.org/en-US/docs/Web/API/Element|Dom Element}.
 | 
			
		||||
@ -181,18 +178,18 @@ export class YXmlElement extends YXmlFragment {
 | 
			
		||||
   *
 | 
			
		||||
   * This is called when this Item is sent to a remote peer.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {encoding.Encoder} encoder The encoder to write data to.
 | 
			
		||||
   * @param {AbstractUpdateEncoder} encoder The encoder to write data to.
 | 
			
		||||
   */
 | 
			
		||||
  _write (encoder) {
 | 
			
		||||
    encoding.writeVarUint(encoder, YXmlElementRefID)
 | 
			
		||||
    encoding.writeVarString(encoder, this.nodeName)
 | 
			
		||||
    encoder.writeTypeRef(YXmlElementRefID)
 | 
			
		||||
    encoder.writeKey(this.nodeName)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {decoding.Decoder} decoder
 | 
			
		||||
 * @param {AbstractUpdateDecoder} decoder
 | 
			
		||||
 * @return {YXmlElement}
 | 
			
		||||
 *
 | 
			
		||||
 * @function
 | 
			
		||||
 */
 | 
			
		||||
export const readYXmlElement = decoder => new YXmlElement(decoding.readVarString(decoder))
 | 
			
		||||
export const readYXmlElement = decoder => new YXmlElement(decoder.readKey())
 | 
			
		||||
 | 
			
		||||
@ -14,12 +14,9 @@ import {
 | 
			
		||||
  YXmlFragmentRefID,
 | 
			
		||||
  callTypeObservers,
 | 
			
		||||
  transact,
 | 
			
		||||
  Doc, ContentType, Transaction, Item, YXmlText, YXmlHook, Snapshot // eslint-disable-line
 | 
			
		||||
  AbstractUpdateDecoder, AbstractUpdateEncoder, Doc, ContentType, Transaction, Item, YXmlText, YXmlHook, Snapshot // eslint-disable-line
 | 
			
		||||
} from '../internals.js'
 | 
			
		||||
 | 
			
		||||
import * as encoding from 'lib0/encoding.js'
 | 
			
		||||
import * as decoding from 'lib0/decoding.js' // eslint-disable-line
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Define the elements to which a set of CSS queries apply.
 | 
			
		||||
 * {@link https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors|CSS_Selectors}
 | 
			
		||||
@ -325,15 +322,15 @@ export class YXmlFragment extends AbstractType {
 | 
			
		||||
   *
 | 
			
		||||
   * This is called when this Item is sent to a remote peer.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {encoding.Encoder} encoder The encoder to write data to.
 | 
			
		||||
   * @param {AbstractUpdateEncoder} encoder The encoder to write data to.
 | 
			
		||||
   */
 | 
			
		||||
  _write (encoder) {
 | 
			
		||||
    encoding.writeVarUint(encoder, YXmlFragmentRefID)
 | 
			
		||||
    encoder.writeTypeRef(YXmlFragmentRefID)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {decoding.Decoder} decoder
 | 
			
		||||
 * @param {AbstractUpdateDecoder} decoder
 | 
			
		||||
 * @return {YXmlFragment}
 | 
			
		||||
 *
 | 
			
		||||
 * @private
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,9 @@
 | 
			
		||||
 | 
			
		||||
import {
 | 
			
		||||
  YMap,
 | 
			
		||||
  YXmlHookRefID
 | 
			
		||||
  YXmlHookRefID,
 | 
			
		||||
  AbstractUpdateDecoder, AbstractUpdateEncoder // eslint-disable-line
 | 
			
		||||
} from '../internals.js'
 | 
			
		||||
import * as encoding from 'lib0/encoding.js'
 | 
			
		||||
import * as decoding from 'lib0/decoding.js'
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * You can manage binding to a custom type with YXmlHook.
 | 
			
		||||
@ -66,21 +65,20 @@ export class YXmlHook extends YMap {
 | 
			
		||||
   *
 | 
			
		||||
   * This is called when this Item is sent to a remote peer.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {encoding.Encoder} encoder The encoder to write data to.
 | 
			
		||||
   * @param {AbstractUpdateEncoder} encoder The encoder to write data to.
 | 
			
		||||
   */
 | 
			
		||||
  _write (encoder) {
 | 
			
		||||
    super._write(encoder)
 | 
			
		||||
    encoding.writeVarUint(encoder, YXmlHookRefID)
 | 
			
		||||
    encoding.writeVarString(encoder, this.hookName)
 | 
			
		||||
    encoder.writeTypeRef(YXmlHookRefID)
 | 
			
		||||
    encoder.writeKey(this.hookName)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {decoding.Decoder} decoder
 | 
			
		||||
 * @param {AbstractUpdateDecoder} decoder
 | 
			
		||||
 * @return {YXmlHook}
 | 
			
		||||
 *
 | 
			
		||||
 * @private
 | 
			
		||||
 * @function
 | 
			
		||||
 */
 | 
			
		||||
export const readYXmlHook = decoder =>
 | 
			
		||||
  new YXmlHook(decoding.readVarString(decoder))
 | 
			
		||||
  new YXmlHook(decoder.readKey())
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,9 @@
 | 
			
		||||
 | 
			
		||||
import { YText, YXmlTextRefID } from '../internals.js'
 | 
			
		||||
 | 
			
		||||
import * as encoding from 'lib0/encoding.js'
 | 
			
		||||
import * as decoding from 'lib0/decoding.js' // eslint-disable-line
 | 
			
		||||
import {
 | 
			
		||||
  YText,
 | 
			
		||||
  YXmlTextRefID,
 | 
			
		||||
  AbstractUpdateDecoder, AbstractUpdateEncoder // eslint-disable-line
 | 
			
		||||
} from '../internals.js'
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents text in a Dom Element. In the future this type will also handle
 | 
			
		||||
@ -78,15 +79,15 @@ export class YXmlText extends YText {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {encoding.Encoder} encoder
 | 
			
		||||
   * @param {AbstractUpdateEncoder} encoder
 | 
			
		||||
   */
 | 
			
		||||
  _write (encoder) {
 | 
			
		||||
    encoding.writeVarUint(encoder, YXmlTextRefID)
 | 
			
		||||
    encoder.writeTypeRef(YXmlTextRefID)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {decoding.Decoder} decoder
 | 
			
		||||
 * @param {AbstractUpdateDecoder} decoder
 | 
			
		||||
 * @return {YXmlText}
 | 
			
		||||
 *
 | 
			
		||||
 * @private
 | 
			
		||||
 | 
			
		||||
@ -3,9 +3,8 @@ import {
 | 
			
		||||
  findIndexSS,
 | 
			
		||||
  getState,
 | 
			
		||||
  splitItem,
 | 
			
		||||
  createID,
 | 
			
		||||
  iterateStructs,
 | 
			
		||||
  Item, AbstractStruct, GC, StructStore, Transaction, ID // eslint-disable-line
 | 
			
		||||
  AbstractUpdateDecoder, AbstractDSDecoder, AbstractDSEncoder, DSDecoderV2, DSEncoderV2, Item, GC, StructStore, Transaction, ID // eslint-disable-line
 | 
			
		||||
} from '../internals.js'
 | 
			
		||||
 | 
			
		||||
import * as array from 'lib0/array.js'
 | 
			
		||||
@ -163,14 +162,15 @@ export const mergeDeleteSets = dss => {
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {DeleteSet} ds
 | 
			
		||||
 * @param {ID} id
 | 
			
		||||
 * @param {number} client
 | 
			
		||||
 * @param {number} clock
 | 
			
		||||
 * @param {number} length
 | 
			
		||||
 *
 | 
			
		||||
 * @private
 | 
			
		||||
 * @function
 | 
			
		||||
 */
 | 
			
		||||
export const addToDeleteSet = (ds, id, length) => {
 | 
			
		||||
  map.setIfUndefined(ds.clients, id.client, () => []).push(new DeleteItem(id.clock, length))
 | 
			
		||||
export const addToDeleteSet = (ds, client, clock, length) => {
 | 
			
		||||
  map.setIfUndefined(ds.clients, client, () => []).push(new DeleteItem(clock, length))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const createDeleteSet = () => new DeleteSet()
 | 
			
		||||
@ -210,28 +210,29 @@ export const createDeleteSetFromStructStore = ss => {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {encoding.Encoder} encoder
 | 
			
		||||
 * @param {AbstractDSEncoder} encoder
 | 
			
		||||
 * @param {DeleteSet} ds
 | 
			
		||||
 *
 | 
			
		||||
 * @private
 | 
			
		||||
 * @function
 | 
			
		||||
 */
 | 
			
		||||
export const writeDeleteSet = (encoder, ds) => {
 | 
			
		||||
  encoding.writeVarUint(encoder, ds.clients.size)
 | 
			
		||||
  encoding.writeVarUint(encoder.restEncoder, ds.clients.size)
 | 
			
		||||
  ds.clients.forEach((dsitems, client) => {
 | 
			
		||||
    encoding.writeVarUint(encoder, client)
 | 
			
		||||
    encoder.resetDsCurVal()
 | 
			
		||||
    encoding.writeVarUint(encoder.restEncoder, client)
 | 
			
		||||
    const len = dsitems.length
 | 
			
		||||
    encoding.writeVarUint(encoder, len)
 | 
			
		||||
    encoding.writeVarUint(encoder.restEncoder, len)
 | 
			
		||||
    for (let i = 0; i < len; i++) {
 | 
			
		||||
      const item = dsitems[i]
 | 
			
		||||
      encoding.writeVarUint(encoder, item.clock)
 | 
			
		||||
      encoding.writeVarUint(encoder, item.len)
 | 
			
		||||
      encoder.writeDsClock(item.clock)
 | 
			
		||||
      encoder.writeDsLen(item.len)
 | 
			
		||||
    }
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {decoding.Decoder} decoder
 | 
			
		||||
 * @param {AbstractDSDecoder} decoder
 | 
			
		||||
 * @return {DeleteSet}
 | 
			
		||||
 *
 | 
			
		||||
 * @private
 | 
			
		||||
@ -239,19 +240,27 @@ export const writeDeleteSet = (encoder, ds) => {
 | 
			
		||||
 */
 | 
			
		||||
export const readDeleteSet = decoder => {
 | 
			
		||||
  const ds = new DeleteSet()
 | 
			
		||||
  const numClients = decoding.readVarUint(decoder)
 | 
			
		||||
  const numClients = decoding.readVarUint(decoder.restDecoder)
 | 
			
		||||
  for (let i = 0; i < numClients; i++) {
 | 
			
		||||
    const client = decoding.readVarUint(decoder)
 | 
			
		||||
    const numberOfDeletes = decoding.readVarUint(decoder)
 | 
			
		||||
    for (let i = 0; i < numberOfDeletes; i++) {
 | 
			
		||||
      addToDeleteSet(ds, createID(client, decoding.readVarUint(decoder)), decoding.readVarUint(decoder))
 | 
			
		||||
    decoder.resetDsCurVal()
 | 
			
		||||
    const client = decoding.readVarUint(decoder.restDecoder)
 | 
			
		||||
    const numberOfDeletes = decoding.readVarUint(decoder.restDecoder)
 | 
			
		||||
    if (numberOfDeletes > 0) {
 | 
			
		||||
      const dsField = map.setIfUndefined(ds.clients, client, () => [])
 | 
			
		||||
      for (let i = 0; i < numberOfDeletes; i++) {
 | 
			
		||||
        dsField.push(new DeleteItem(decoder.readDsClock(), decoder.readDsLen()))
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return ds
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {decoding.Decoder} decoder
 | 
			
		||||
 * @todo YDecoder also contains references to String and other Decoders. Would make sense to exchange YDecoder.toUint8Array for YDecoder.DsToUint8Array()..
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {AbstractDSDecoder} decoder
 | 
			
		||||
 * @param {Transaction} transaction
 | 
			
		||||
 * @param {StructStore} store
 | 
			
		||||
 *
 | 
			
		||||
@ -260,18 +269,19 @@ export const readDeleteSet = decoder => {
 | 
			
		||||
 */
 | 
			
		||||
export const readAndApplyDeleteSet = (decoder, transaction, store) => {
 | 
			
		||||
  const unappliedDS = new DeleteSet()
 | 
			
		||||
  const numClients = decoding.readVarUint(decoder)
 | 
			
		||||
  const numClients = decoding.readVarUint(decoder.restDecoder)
 | 
			
		||||
  for (let i = 0; i < numClients; i++) {
 | 
			
		||||
    const client = decoding.readVarUint(decoder)
 | 
			
		||||
    const numberOfDeletes = decoding.readVarUint(decoder)
 | 
			
		||||
    decoder.resetDsCurVal()
 | 
			
		||||
    const client = decoding.readVarUint(decoder.restDecoder)
 | 
			
		||||
    const numberOfDeletes = decoding.readVarUint(decoder.restDecoder)
 | 
			
		||||
    const structs = store.clients.get(client) || []
 | 
			
		||||
    const state = getState(store, client)
 | 
			
		||||
    for (let i = 0; i < numberOfDeletes; i++) {
 | 
			
		||||
      const clock = decoding.readVarUint(decoder)
 | 
			
		||||
      const len = decoding.readVarUint(decoder)
 | 
			
		||||
      const clock = decoder.readDsClock()
 | 
			
		||||
      const clockEnd = clock + decoder.readDsLen()
 | 
			
		||||
      if (clock < state) {
 | 
			
		||||
        if (state < clock + len) {
 | 
			
		||||
          addToDeleteSet(unappliedDS, createID(client, state), clock + len - state)
 | 
			
		||||
        if (state < clockEnd) {
 | 
			
		||||
          addToDeleteSet(unappliedDS, client, state, clockEnd - state)
 | 
			
		||||
        }
 | 
			
		||||
        let index = findIndexSS(structs, clock)
 | 
			
		||||
        /**
 | 
			
		||||
@ -288,10 +298,10 @@ export const readAndApplyDeleteSet = (decoder, transaction, store) => {
 | 
			
		||||
        while (index < structs.length) {
 | 
			
		||||
          // @ts-ignore
 | 
			
		||||
          struct = structs[index++]
 | 
			
		||||
          if (struct.id.clock < clock + len) {
 | 
			
		||||
          if (struct.id.clock < clockEnd) {
 | 
			
		||||
            if (!struct.deleted) {
 | 
			
		||||
              if (clock + len < struct.id.clock + struct.length) {
 | 
			
		||||
                structs.splice(index, 0, splitItem(transaction, struct, clock + len - struct.id.clock))
 | 
			
		||||
              if (clockEnd < struct.id.clock + struct.length) {
 | 
			
		||||
                structs.splice(index, 0, splitItem(transaction, struct, clockEnd - struct.id.clock))
 | 
			
		||||
              }
 | 
			
		||||
              struct.delete(transaction)
 | 
			
		||||
            }
 | 
			
		||||
@ -300,14 +310,14 @@ export const readAndApplyDeleteSet = (decoder, transaction, store) => {
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      } else {
 | 
			
		||||
        addToDeleteSet(unappliedDS, createID(client, clock), len)
 | 
			
		||||
        addToDeleteSet(unappliedDS, client, clock, clockEnd - clock)
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  if (unappliedDS.clients.size > 0) {
 | 
			
		||||
    // TODO: no need for encoding+decoding ds anymore
 | 
			
		||||
    const unappliedDSEncoder = encoding.createEncoder()
 | 
			
		||||
    const unappliedDSEncoder = new DSEncoderV2()
 | 
			
		||||
    writeDeleteSet(unappliedDSEncoder, unappliedDS)
 | 
			
		||||
    store.pendingDeleteReaders.push(decoding.createDecoder(encoding.toUint8Array(unappliedDSEncoder)))
 | 
			
		||||
    store.pendingDeleteReaders.push(new DSDecoderV2(decoding.createDecoder((unappliedDSEncoder.toUint8Array()))))
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -5,11 +5,11 @@ import {
 | 
			
		||||
  readDeleteSet,
 | 
			
		||||
  writeDeleteSet,
 | 
			
		||||
  createDeleteSet,
 | 
			
		||||
  ID, DeleteSet, YArrayEvent, Transaction, Doc // eslint-disable-line
 | 
			
		||||
  DSEncoderV1, DSDecoderV1, ID, DeleteSet, YArrayEvent, Transaction, Doc // eslint-disable-line
 | 
			
		||||
} from '../internals.js'
 | 
			
		||||
 | 
			
		||||
import * as decoding from 'lib0/decoding.js'
 | 
			
		||||
import * as encoding from 'lib0/encoding.js'
 | 
			
		||||
 | 
			
		||||
import { mergeDeleteSets, isDeleted } from './DeleteSet.js'
 | 
			
		||||
 | 
			
		||||
export class PermanentUserData {
 | 
			
		||||
@ -46,12 +46,12 @@ export class PermanentUserData {
 | 
			
		||||
        event.changes.added.forEach(item => {
 | 
			
		||||
          item.content.getContent().forEach(encodedDs => {
 | 
			
		||||
            if (encodedDs instanceof Uint8Array) {
 | 
			
		||||
              this.dss.set(userDescription, mergeDeleteSets([this.dss.get(userDescription) || createDeleteSet(), readDeleteSet(decoding.createDecoder(encodedDs))]))
 | 
			
		||||
              this.dss.set(userDescription, mergeDeleteSets([this.dss.get(userDescription) || createDeleteSet(), readDeleteSet(new DSDecoderV1(decoding.createDecoder(encodedDs)))]))
 | 
			
		||||
            }
 | 
			
		||||
          })
 | 
			
		||||
        })
 | 
			
		||||
      })
 | 
			
		||||
      this.dss.set(userDescription, mergeDeleteSets(ds.map(encodedDs => readDeleteSet(decoding.createDecoder(encodedDs)))))
 | 
			
		||||
      this.dss.set(userDescription, mergeDeleteSets(ds.map(encodedDs => readDeleteSet(new DSDecoderV1(encodedDs)))))
 | 
			
		||||
      ids.observe(/** @param {YArrayEvent<any>} event */ event =>
 | 
			
		||||
        event.changes.added.forEach(item => item.content.getContent().forEach(addClientId))
 | 
			
		||||
      )
 | 
			
		||||
@ -97,11 +97,11 @@ export class PermanentUserData {
 | 
			
		||||
              user.get('ids').push([clientid])
 | 
			
		||||
            }
 | 
			
		||||
          })
 | 
			
		||||
          const encoder = encoding.createEncoder()
 | 
			
		||||
          const encoder = new DSEncoderV1()
 | 
			
		||||
          const ds = this.dss.get(userDescription)
 | 
			
		||||
          if (ds) {
 | 
			
		||||
            writeDeleteSet(encoder, ds)
 | 
			
		||||
            user.get('ds').push([encoding.toUint8Array(encoder)])
 | 
			
		||||
            user.get('ds').push([encoder.toUint8Array()])
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }, 0)
 | 
			
		||||
@ -111,9 +111,9 @@ export class PermanentUserData {
 | 
			
		||||
        const yds = user.get('ds')
 | 
			
		||||
        const ds = transaction.deleteSet
 | 
			
		||||
        if (transaction.local && ds.clients.size > 0 && filter(transaction, ds)) {
 | 
			
		||||
          const encoder = encoding.createEncoder()
 | 
			
		||||
          const encoder = new DSEncoderV1()
 | 
			
		||||
          writeDeleteSet(encoder, ds)
 | 
			
		||||
          yds.push([encoding.toUint8Array(encoder)])
 | 
			
		||||
          yds.push([encoder.toUint8Array()])
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
@ -12,13 +12,13 @@ import {
 | 
			
		||||
  createDeleteSet,
 | 
			
		||||
  createID,
 | 
			
		||||
  getState,
 | 
			
		||||
  Transaction, Doc, DeleteSet, Item // eslint-disable-line
 | 
			
		||||
  AbstractDSDecoder, AbstractDSEncoder, DSEncoderV1, DSEncoderV2, DSDecoderV1, DSDecoderV2, Transaction, Doc, DeleteSet, Item // eslint-disable-line
 | 
			
		||||
} from '../internals.js'
 | 
			
		||||
 | 
			
		||||
import * as map from 'lib0/map.js'
 | 
			
		||||
import * as set from 'lib0/set.js'
 | 
			
		||||
import * as encoding from 'lib0/encoding.js'
 | 
			
		||||
import * as decoding from 'lib0/decoding.js'
 | 
			
		||||
import { DefaultDSEncoder } from './encoding.js'
 | 
			
		||||
 | 
			
		||||
export class Snapshot {
 | 
			
		||||
  /**
 | 
			
		||||
@ -74,23 +74,35 @@ export const equalSnapshots = (snap1, snap2) => {
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {Snapshot} snapshot
 | 
			
		||||
 * @param {AbstractDSEncoder} [encoder]
 | 
			
		||||
 * @return {Uint8Array}
 | 
			
		||||
 */
 | 
			
		||||
export const encodeSnapshot = snapshot => {
 | 
			
		||||
  const encoder = encoding.createEncoder()
 | 
			
		||||
export const encodeSnapshotV2 = (snapshot, encoder = new DSEncoderV2()) => {
 | 
			
		||||
  writeDeleteSet(encoder, snapshot.ds)
 | 
			
		||||
  writeStateVector(encoder, snapshot.sv)
 | 
			
		||||
  return encoding.toUint8Array(encoder)
 | 
			
		||||
  return encoder.toUint8Array()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {Snapshot} snapshot
 | 
			
		||||
 * @return {Uint8Array}
 | 
			
		||||
 */
 | 
			
		||||
export const encodeSnapshot = snapshot => encodeSnapshotV2(snapshot, new DefaultDSEncoder())
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {Uint8Array} buf
 | 
			
		||||
 * @param {AbstractDSDecoder} [decoder]
 | 
			
		||||
 * @return {Snapshot}
 | 
			
		||||
 */
 | 
			
		||||
export const decodeSnapshotV2 = (buf, decoder = new DSDecoderV2(decoding.createDecoder(buf))) => {
 | 
			
		||||
  return new Snapshot(readDeleteSet(decoder), readStateVector(decoder))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {Uint8Array} buf
 | 
			
		||||
 * @return {Snapshot}
 | 
			
		||||
 */
 | 
			
		||||
export const decodeSnapshot = buf => {
 | 
			
		||||
  const decoder = decoding.createDecoder(buf)
 | 
			
		||||
  return new Snapshot(readDeleteSet(decoder), readStateVector(decoder))
 | 
			
		||||
}
 | 
			
		||||
export const decodeSnapshot = buf => decodeSnapshotV2(buf, new DSDecoderV1(decoding.createDecoder(buf)))
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {DeleteSet} ds
 | 
			
		||||
 | 
			
		||||
@ -2,12 +2,11 @@
 | 
			
		||||
import {
 | 
			
		||||
  GC,
 | 
			
		||||
  splitItem,
 | 
			
		||||
  AbstractStruct, Transaction, ID, Item // eslint-disable-line
 | 
			
		||||
  Transaction, ID, Item, DSDecoderV2 // eslint-disable-line
 | 
			
		||||
} from '../internals.js'
 | 
			
		||||
 | 
			
		||||
import * as math from 'lib0/math.js'
 | 
			
		||||
import * as error from 'lib0/error.js'
 | 
			
		||||
import * as decoding from 'lib0/decoding.js' // eslint-disable-line
 | 
			
		||||
 | 
			
		||||
export class StructStore {
 | 
			
		||||
  constructor () {
 | 
			
		||||
@ -31,7 +30,7 @@ export class StructStore {
 | 
			
		||||
     */
 | 
			
		||||
    this.pendingStack = []
 | 
			
		||||
    /**
 | 
			
		||||
     * @type {Array<decoding.Decoder>}
 | 
			
		||||
     * @type {Array<DSDecoderV2>}
 | 
			
		||||
     */
 | 
			
		||||
    this.pendingDeleteReaders = []
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -11,15 +11,16 @@ import {
 | 
			
		||||
  Item,
 | 
			
		||||
  generateNewClientId,
 | 
			
		||||
  createID,
 | 
			
		||||
  GC, StructStore, ID, AbstractType, AbstractStruct, YEvent, Doc // eslint-disable-line
 | 
			
		||||
  AbstractUpdateEncoder, GC, StructStore, UpdateEncoderV1, AbstractType, AbstractStruct, YEvent, Doc // eslint-disable-line
 | 
			
		||||
} from '../internals.js'
 | 
			
		||||
 | 
			
		||||
import * as encoding from 'lib0/encoding.js'
 | 
			
		||||
import * as map from 'lib0/map.js'
 | 
			
		||||
import * as math from 'lib0/math.js'
 | 
			
		||||
import * as set from 'lib0/set.js'
 | 
			
		||||
import * as logging from 'lib0/logging.js'
 | 
			
		||||
import { callAll } from 'lib0/function.js'
 | 
			
		||||
import { DefaultUpdateEncoder } from './encoding.js'
 | 
			
		||||
import { UpdateEncoderV2 } from './UpdateEncoder.js'
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A transaction is created for every change on the Yjs model. It is possible
 | 
			
		||||
@ -107,17 +108,18 @@ export class Transaction {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {AbstractUpdateEncoder} encoder
 | 
			
		||||
 * @param {Transaction} transaction
 | 
			
		||||
 * @return {boolean} Whether data was written.
 | 
			
		||||
 */
 | 
			
		||||
export const computeUpdateMessageFromTransaction = transaction => {
 | 
			
		||||
export const writeUpdateMessageFromTransaction = (encoder, transaction) => {
 | 
			
		||||
  if (transaction.deleteSet.clients.size === 0 && !map.any(transaction.afterState, (clock, client) => transaction.beforeState.get(client) !== clock)) {
 | 
			
		||||
    return null
 | 
			
		||||
    return false
 | 
			
		||||
  }
 | 
			
		||||
  const encoder = encoding.createEncoder()
 | 
			
		||||
  sortAndMergeDeleteSet(transaction.deleteSet)
 | 
			
		||||
  writeStructsFromTransaction(encoder, transaction)
 | 
			
		||||
  writeDeleteSet(encoder, transaction.deleteSet)
 | 
			
		||||
  return encoder
 | 
			
		||||
  return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@ -322,9 +324,17 @@ const cleanupTransactions = (transactionCleanups, i) => {
 | 
			
		||||
      // @todo Merge all the transactions into one and provide send the data as a single update message
 | 
			
		||||
      doc.emit('afterTransactionCleanup', [transaction, doc])
 | 
			
		||||
      if (doc._observers.has('update')) {
 | 
			
		||||
        const updateMessage = computeUpdateMessageFromTransaction(transaction)
 | 
			
		||||
        if (updateMessage !== null) {
 | 
			
		||||
          doc.emit('update', [encoding.toUint8Array(updateMessage), transaction.origin, doc])
 | 
			
		||||
        const encoder = new DefaultUpdateEncoder()
 | 
			
		||||
        const hasContent = writeUpdateMessageFromTransaction(encoder, transaction)
 | 
			
		||||
        if (hasContent) {
 | 
			
		||||
          doc.emit('update', [encoder.toUint8Array(), transaction.origin, doc])
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      if (doc._observers.has('updateV2')) {
 | 
			
		||||
        const encoder = new UpdateEncoderV2()
 | 
			
		||||
        const hasContent = writeUpdateMessageFromTransaction(encoder, transaction)
 | 
			
		||||
        if (hasContent) {
 | 
			
		||||
          doc.emit('updateV2', [encoder.toUint8Array(), transaction.origin, doc])
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      if (transactionCleanups.length <= i + 1) {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										392
									
								
								src/utils/UpdateDecoder.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										392
									
								
								src/utils/UpdateDecoder.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,392 @@
 | 
			
		||||
import * as buffer from 'lib0/buffer.js'
 | 
			
		||||
import * as error from 'lib0/error.js'
 | 
			
		||||
import * as decoding from 'lib0/decoding.js'
 | 
			
		||||
import {
 | 
			
		||||
  ID, createID
 | 
			
		||||
} from '../internals.js'
 | 
			
		||||
 | 
			
		||||
export class AbstractDSDecoder {
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {decoding.Decoder} decoder
 | 
			
		||||
   */
 | 
			
		||||
  constructor (decoder) {
 | 
			
		||||
    this.restDecoder = decoder
 | 
			
		||||
    error.methodUnimplemented()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  resetDsCurVal () { }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @return {number}
 | 
			
		||||
   */
 | 
			
		||||
  readDsClock () {
 | 
			
		||||
    error.methodUnimplemented()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @return {number}
 | 
			
		||||
   */
 | 
			
		||||
  readDsLen () {
 | 
			
		||||
    error.methodUnimplemented()
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class AbstractUpdateDecoder extends AbstractDSDecoder {
 | 
			
		||||
  /**
 | 
			
		||||
   * @return {ID}
 | 
			
		||||
   */
 | 
			
		||||
  readLeftID () {
 | 
			
		||||
    error.methodUnimplemented()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @return {ID}
 | 
			
		||||
   */
 | 
			
		||||
  readRightID () {
 | 
			
		||||
    error.methodUnimplemented()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Read the next client id.
 | 
			
		||||
   * Use this in favor of readID whenever possible to reduce the number of objects created.
 | 
			
		||||
   *
 | 
			
		||||
   * @return {number}
 | 
			
		||||
   */
 | 
			
		||||
  readClient () {
 | 
			
		||||
    error.methodUnimplemented()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @return {number} info An unsigned 8-bit integer
 | 
			
		||||
   */
 | 
			
		||||
  readInfo () {
 | 
			
		||||
    error.methodUnimplemented()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @return {string}
 | 
			
		||||
   */
 | 
			
		||||
  readString () {
 | 
			
		||||
    error.methodUnimplemented()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @return {boolean} isKey
 | 
			
		||||
   */
 | 
			
		||||
  readParentInfo () {
 | 
			
		||||
    error.methodUnimplemented()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @return {number} info An unsigned 8-bit integer
 | 
			
		||||
   */
 | 
			
		||||
  readTypeRef () {
 | 
			
		||||
    error.methodUnimplemented()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Write len of a struct - well suited for Opt RLE encoder.
 | 
			
		||||
   *
 | 
			
		||||
   * @return {number} len
 | 
			
		||||
   */
 | 
			
		||||
  readLen () {
 | 
			
		||||
    error.methodUnimplemented()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @return {any}
 | 
			
		||||
   */
 | 
			
		||||
  readAny () {
 | 
			
		||||
    error.methodUnimplemented()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @return {Uint8Array}
 | 
			
		||||
   */
 | 
			
		||||
  readBuf () {
 | 
			
		||||
    error.methodUnimplemented()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Legacy implementation uses JSON parse. We use any-decoding in v2.
 | 
			
		||||
   *
 | 
			
		||||
   * @return {any}
 | 
			
		||||
   */
 | 
			
		||||
  readJSON () {
 | 
			
		||||
    error.methodUnimplemented()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @return {string}
 | 
			
		||||
   */
 | 
			
		||||
  readKey () {
 | 
			
		||||
    error.methodUnimplemented()
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class DSDecoderV1 {
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {decoding.Decoder} decoder
 | 
			
		||||
   */
 | 
			
		||||
  constructor (decoder) {
 | 
			
		||||
    this.restDecoder = decoder
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  resetDsCurVal () {
 | 
			
		||||
    // nop
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @return {number}
 | 
			
		||||
   */
 | 
			
		||||
  readDsClock () {
 | 
			
		||||
    return decoding.readVarUint(this.restDecoder)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @return {number}
 | 
			
		||||
   */
 | 
			
		||||
  readDsLen () {
 | 
			
		||||
    return decoding.readVarUint(this.restDecoder)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class UpdateDecoderV1 extends DSDecoderV1 {
 | 
			
		||||
  /**
 | 
			
		||||
   * @return {ID}
 | 
			
		||||
   */
 | 
			
		||||
  readLeftID () {
 | 
			
		||||
    return createID(decoding.readVarUint(this.restDecoder), decoding.readVarUint(this.restDecoder))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @return {ID}
 | 
			
		||||
   */
 | 
			
		||||
  readRightID () {
 | 
			
		||||
    return createID(decoding.readVarUint(this.restDecoder), decoding.readVarUint(this.restDecoder))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Read the next client id.
 | 
			
		||||
   * Use this in favor of readID whenever possible to reduce the number of objects created.
 | 
			
		||||
   */
 | 
			
		||||
  readClient () {
 | 
			
		||||
    return decoding.readVarUint(this.restDecoder)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @return {number} info An unsigned 8-bit integer
 | 
			
		||||
   */
 | 
			
		||||
  readInfo () {
 | 
			
		||||
    return decoding.readUint8(this.restDecoder)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @return {string}
 | 
			
		||||
   */
 | 
			
		||||
  readString () {
 | 
			
		||||
    return decoding.readVarString(this.restDecoder)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @return {boolean} isKey
 | 
			
		||||
   */
 | 
			
		||||
  readParentInfo () {
 | 
			
		||||
    return decoding.readVarUint(this.restDecoder) === 1
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @return {number} info An unsigned 8-bit integer
 | 
			
		||||
   */
 | 
			
		||||
  readTypeRef () {
 | 
			
		||||
    return decoding.readVarUint(this.restDecoder)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Write len of a struct - well suited for Opt RLE encoder.
 | 
			
		||||
   *
 | 
			
		||||
   * @return {number} len
 | 
			
		||||
   */
 | 
			
		||||
  readLen () {
 | 
			
		||||
    return decoding.readVarUint(this.restDecoder)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @return {any}
 | 
			
		||||
   */
 | 
			
		||||
  readAny () {
 | 
			
		||||
    return decoding.readAny(this.restDecoder)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @return {Uint8Array}
 | 
			
		||||
   */
 | 
			
		||||
  readBuf () {
 | 
			
		||||
    return buffer.copyUint8Array(decoding.readVarUint8Array(this.restDecoder))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Legacy implementation uses JSON parse. We use any-decoding in v2.
 | 
			
		||||
   *
 | 
			
		||||
   * @return {any}
 | 
			
		||||
   */
 | 
			
		||||
  readJSON () {
 | 
			
		||||
    return JSON.parse(decoding.readVarString(this.restDecoder))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @return {string}
 | 
			
		||||
   */
 | 
			
		||||
  readKey () {
 | 
			
		||||
    return decoding.readVarString(this.restDecoder)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class DSDecoderV2 {
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {decoding.Decoder} decoder
 | 
			
		||||
   */
 | 
			
		||||
  constructor (decoder) {
 | 
			
		||||
    this.dsCurrVal = 0
 | 
			
		||||
    this.restDecoder = decoder
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  resetDsCurVal () {
 | 
			
		||||
    this.dsCurrVal = 0
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  readDsClock () {
 | 
			
		||||
    this.dsCurrVal += decoding.readVarUint(this.restDecoder)
 | 
			
		||||
    return this.dsCurrVal
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  readDsLen () {
 | 
			
		||||
    const diff = decoding.readVarUint(this.restDecoder) + 1
 | 
			
		||||
    this.dsCurrVal += diff
 | 
			
		||||
    return diff
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class UpdateDecoderV2 extends DSDecoderV2 {
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {decoding.Decoder} decoder
 | 
			
		||||
   */
 | 
			
		||||
  constructor (decoder) {
 | 
			
		||||
    super(decoder)
 | 
			
		||||
    /**
 | 
			
		||||
     * List of cached keys. If the keys[id] does not exist, we read a new key
 | 
			
		||||
     * from stringEncoder and push it to keys.
 | 
			
		||||
     *
 | 
			
		||||
     * @type {Array<string>}
 | 
			
		||||
     */
 | 
			
		||||
    this.keys = []
 | 
			
		||||
    decoding.readUint8(decoder) // read feature flag - currently unused
 | 
			
		||||
    this.keyClockDecoder = new decoding.IntDiffOptRleDecoder(decoding.readVarUint8Array(decoder))
 | 
			
		||||
    this.clientDecoder = new decoding.UintOptRleDecoder(decoding.readVarUint8Array(decoder))
 | 
			
		||||
    this.leftClockDecoder = new decoding.IntDiffOptRleDecoder(decoding.readVarUint8Array(decoder))
 | 
			
		||||
    this.rightClockDecoder = new decoding.IntDiffOptRleDecoder(decoding.readVarUint8Array(decoder))
 | 
			
		||||
    this.infoDecoder = new decoding.RleDecoder(decoding.readVarUint8Array(decoder), decoding.readUint8)
 | 
			
		||||
    this.stringDecoder = new decoding.StringDecoder(decoding.readVarUint8Array(decoder))
 | 
			
		||||
    this.parentInfoDecoder = new decoding.RleDecoder(decoding.readVarUint8Array(decoder), decoding.readUint8)
 | 
			
		||||
    this.typeRefDecoder = new decoding.UintOptRleDecoder(decoding.readVarUint8Array(decoder))
 | 
			
		||||
    this.lenDecoder = new decoding.UintOptRleDecoder(decoding.readVarUint8Array(decoder))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @return {ID}
 | 
			
		||||
   */
 | 
			
		||||
  readLeftID () {
 | 
			
		||||
    return new ID(this.clientDecoder.read(), this.leftClockDecoder.read())
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @return {ID}
 | 
			
		||||
   */
 | 
			
		||||
  readRightID () {
 | 
			
		||||
    return new ID(this.clientDecoder.read(), this.rightClockDecoder.read())
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Read the next client id.
 | 
			
		||||
   * Use this in favor of readID whenever possible to reduce the number of objects created.
 | 
			
		||||
   */
 | 
			
		||||
  readClient () {
 | 
			
		||||
    return this.clientDecoder.read()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @return {number} info An unsigned 8-bit integer
 | 
			
		||||
   */
 | 
			
		||||
  readInfo () {
 | 
			
		||||
    return /** @type {number} */ (this.infoDecoder.read())
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @return {string}
 | 
			
		||||
   */
 | 
			
		||||
  readString () {
 | 
			
		||||
    return this.stringDecoder.read()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @return {boolean}
 | 
			
		||||
   */
 | 
			
		||||
  readParentInfo () {
 | 
			
		||||
    return this.parentInfoDecoder.read() === 1
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @return {number} An unsigned 8-bit integer
 | 
			
		||||
   */
 | 
			
		||||
  readTypeRef () {
 | 
			
		||||
    return this.typeRefDecoder.read()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Write len of a struct - well suited for Opt RLE encoder.
 | 
			
		||||
   *
 | 
			
		||||
   * @return {number}
 | 
			
		||||
   */
 | 
			
		||||
  readLen () {
 | 
			
		||||
    return this.lenDecoder.read()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @return {any}
 | 
			
		||||
   */
 | 
			
		||||
  readAny () {
 | 
			
		||||
    return decoding.readAny(this.restDecoder)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @return {Uint8Array}
 | 
			
		||||
   */
 | 
			
		||||
  readBuf () {
 | 
			
		||||
    return decoding.readVarUint8Array(this.restDecoder)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * This is mainly here for legacy purposes.
 | 
			
		||||
   *
 | 
			
		||||
   * Initial we incoded objects using JSON. Now we use the much faster lib0/any-encoder. This method mainly exists for legacy purposes for the v1 encoder.
 | 
			
		||||
   *
 | 
			
		||||
   * @return {any}
 | 
			
		||||
   */
 | 
			
		||||
  readJSON () {
 | 
			
		||||
    return decoding.readAny(this.restDecoder)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @return {string}
 | 
			
		||||
   */
 | 
			
		||||
  readKey () {
 | 
			
		||||
    const keyClock = this.keyClockDecoder.read()
 | 
			
		||||
    if (keyClock < this.keys.length) {
 | 
			
		||||
      return this.keys[keyClock]
 | 
			
		||||
    } else {
 | 
			
		||||
      const key = this.stringDecoder.read()
 | 
			
		||||
      this.keys.push(key)
 | 
			
		||||
      return key
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										408
									
								
								src/utils/UpdateEncoder.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										408
									
								
								src/utils/UpdateEncoder.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,408 @@
 | 
			
		||||
 | 
			
		||||
import * as error from 'lib0/error.js'
 | 
			
		||||
import * as encoding from 'lib0/encoding.js'
 | 
			
		||||
 | 
			
		||||
import {
 | 
			
		||||
  ID // eslint-disable-line
 | 
			
		||||
} from '../internals.js'
 | 
			
		||||
 | 
			
		||||
export class AbstractDSEncoder {
 | 
			
		||||
  constructor () {
 | 
			
		||||
    this.restEncoder = encoding.createEncoder()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @return {Uint8Array}
 | 
			
		||||
   */
 | 
			
		||||
  toUint8Array () {
 | 
			
		||||
    error.methodUnimplemented()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Resets the ds value to 0.
 | 
			
		||||
   * The v2 encoder uses this information to reset the initial diff value.
 | 
			
		||||
   */
 | 
			
		||||
  resetDsCurVal () { }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {number} clock
 | 
			
		||||
   */
 | 
			
		||||
  writeDsClock (clock) { }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {number} len
 | 
			
		||||
   */
 | 
			
		||||
  writeDsLen (len) { }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class AbstractUpdateEncoder extends AbstractDSEncoder {
 | 
			
		||||
  /**
 | 
			
		||||
   * @return {Uint8Array}
 | 
			
		||||
   */
 | 
			
		||||
  toUint8Array () {
 | 
			
		||||
    error.methodUnimplemented()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {ID} id
 | 
			
		||||
   */
 | 
			
		||||
  writeLeftID (id) { }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {ID} id
 | 
			
		||||
   */
 | 
			
		||||
  writeRightID (id) { }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Use writeClient and writeClock instead of writeID if possible.
 | 
			
		||||
   * @param {number} client
 | 
			
		||||
   */
 | 
			
		||||
  writeClient (client) { }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {number} info An unsigned 8-bit integer
 | 
			
		||||
   */
 | 
			
		||||
  writeInfo (info) { }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {string} s
 | 
			
		||||
   */
 | 
			
		||||
  writeString (s) { }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {boolean} isYKey
 | 
			
		||||
   */
 | 
			
		||||
  writeParentInfo (isYKey) { }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {number} info An unsigned 8-bit integer
 | 
			
		||||
   */
 | 
			
		||||
  writeTypeRef (info) { }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Write len of a struct - well suited for Opt RLE encoder.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {number} len
 | 
			
		||||
   */
 | 
			
		||||
  writeLen (len) { }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {any} any
 | 
			
		||||
   */
 | 
			
		||||
  writeAny (any) { }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {Uint8Array} buf
 | 
			
		||||
   */
 | 
			
		||||
  writeBuf (buf) { }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {any} embed
 | 
			
		||||
   */
 | 
			
		||||
  writeJSON (embed) { }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {string} key
 | 
			
		||||
   */
 | 
			
		||||
  writeKey (key) { }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class DSEncoderV1 {
 | 
			
		||||
  constructor () {
 | 
			
		||||
    this.restEncoder = new encoding.Encoder()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  toUint8Array () {
 | 
			
		||||
    return encoding.toUint8Array(this.restEncoder)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  resetDsCurVal () {
 | 
			
		||||
    // nop
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {number} clock
 | 
			
		||||
   */
 | 
			
		||||
  writeDsClock (clock) {
 | 
			
		||||
    encoding.writeVarUint(this.restEncoder, clock)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {number} len
 | 
			
		||||
   */
 | 
			
		||||
  writeDsLen (len) {
 | 
			
		||||
    encoding.writeVarUint(this.restEncoder, len)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class UpdateEncoderV1 extends DSEncoderV1 {
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {ID} id
 | 
			
		||||
   */
 | 
			
		||||
  writeLeftID (id) {
 | 
			
		||||
    encoding.writeVarUint(this.restEncoder, id.client)
 | 
			
		||||
    encoding.writeVarUint(this.restEncoder, id.clock)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {ID} id
 | 
			
		||||
   */
 | 
			
		||||
  writeRightID (id) {
 | 
			
		||||
    encoding.writeVarUint(this.restEncoder, id.client)
 | 
			
		||||
    encoding.writeVarUint(this.restEncoder, id.clock)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Use writeClient and writeClock instead of writeID if possible.
 | 
			
		||||
   * @param {number} client
 | 
			
		||||
   */
 | 
			
		||||
  writeClient (client) {
 | 
			
		||||
    encoding.writeVarUint(this.restEncoder, client)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {number} info An unsigned 8-bit integer
 | 
			
		||||
   */
 | 
			
		||||
  writeInfo (info) {
 | 
			
		||||
    encoding.writeUint8(this.restEncoder, info)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {string} s
 | 
			
		||||
   */
 | 
			
		||||
  writeString (s) {
 | 
			
		||||
    encoding.writeVarString(this.restEncoder, s)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {boolean} isYKey
 | 
			
		||||
   */
 | 
			
		||||
  writeParentInfo (isYKey) {
 | 
			
		||||
    encoding.writeVarUint(this.restEncoder, isYKey ? 1 : 0)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {number} info An unsigned 8-bit integer
 | 
			
		||||
   */
 | 
			
		||||
  writeTypeRef (info) {
 | 
			
		||||
    encoding.writeVarUint(this.restEncoder, info)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Write len of a struct - well suited for Opt RLE encoder.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {number} len
 | 
			
		||||
   */
 | 
			
		||||
  writeLen (len) {
 | 
			
		||||
    encoding.writeVarUint(this.restEncoder, len)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {any} any
 | 
			
		||||
   */
 | 
			
		||||
  writeAny (any) {
 | 
			
		||||
    encoding.writeAny(this.restEncoder, any)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {Uint8Array} buf
 | 
			
		||||
   */
 | 
			
		||||
  writeBuf (buf) {
 | 
			
		||||
    encoding.writeVarUint8Array(this.restEncoder, buf)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {any} embed
 | 
			
		||||
   */
 | 
			
		||||
  writeJSON (embed) {
 | 
			
		||||
    encoding.writeVarString(this.restEncoder, JSON.stringify(embed))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {string} key
 | 
			
		||||
   */
 | 
			
		||||
  writeKey (key) {
 | 
			
		||||
    encoding.writeVarString(this.restEncoder, key)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class DSEncoderV2 {
 | 
			
		||||
  constructor () {
 | 
			
		||||
    this.restEncoder = new encoding.Encoder() // encodes all the rest / non-optimized
 | 
			
		||||
    this.dsCurrVal = 0
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  toUint8Array () {
 | 
			
		||||
    return encoding.toUint8Array(this.restEncoder)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  resetDsCurVal () {
 | 
			
		||||
    this.dsCurrVal = 0
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {number} clock
 | 
			
		||||
   */
 | 
			
		||||
  writeDsClock (clock) {
 | 
			
		||||
    const diff = clock - this.dsCurrVal
 | 
			
		||||
    this.dsCurrVal = clock
 | 
			
		||||
    encoding.writeVarUint(this.restEncoder, diff)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {number} len
 | 
			
		||||
   */
 | 
			
		||||
  writeDsLen (len) {
 | 
			
		||||
    if (len === 0) {
 | 
			
		||||
      error.unexpectedCase()
 | 
			
		||||
    }
 | 
			
		||||
    encoding.writeVarUint(this.restEncoder, len - 1)
 | 
			
		||||
    this.dsCurrVal += len
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class UpdateEncoderV2 extends DSEncoderV2 {
 | 
			
		||||
  constructor () {
 | 
			
		||||
    super()
 | 
			
		||||
    /**
 | 
			
		||||
     * @type {Map<string,number>}
 | 
			
		||||
     */
 | 
			
		||||
    this.keyMap = new Map()
 | 
			
		||||
    /**
 | 
			
		||||
     * Refers to the next uniqe key-identifier to me used.
 | 
			
		||||
     * See writeKey method for more information.
 | 
			
		||||
     *
 | 
			
		||||
     * @type {number}
 | 
			
		||||
     */
 | 
			
		||||
    this.keyClock = 0
 | 
			
		||||
    this.keyClockEncoder = new encoding.IntDiffOptRleEncoder()
 | 
			
		||||
    this.clientEncoder = new encoding.UintOptRleEncoder()
 | 
			
		||||
    this.leftClockEncoder = new encoding.IntDiffOptRleEncoder()
 | 
			
		||||
    this.rightClockEncoder = new encoding.IntDiffOptRleEncoder()
 | 
			
		||||
    this.infoEncoder = new encoding.RleEncoder(encoding.writeUint8)
 | 
			
		||||
    this.stringEncoder = new encoding.StringEncoder()
 | 
			
		||||
    this.parentInfoEncoder = new encoding.RleEncoder(encoding.writeUint8)
 | 
			
		||||
    this.typeRefEncoder = new encoding.UintOptRleEncoder()
 | 
			
		||||
    this.lenEncoder = new encoding.UintOptRleEncoder()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  toUint8Array () {
 | 
			
		||||
    const encoder = encoding.createEncoder()
 | 
			
		||||
    encoding.writeUint8(encoder, 0) // this is a feature flag that we might use in the future
 | 
			
		||||
    encoding.writeVarUint8Array(encoder, this.keyClockEncoder.toUint8Array())
 | 
			
		||||
    encoding.writeVarUint8Array(encoder, this.clientEncoder.toUint8Array())
 | 
			
		||||
    encoding.writeVarUint8Array(encoder, this.leftClockEncoder.toUint8Array())
 | 
			
		||||
    encoding.writeVarUint8Array(encoder, this.rightClockEncoder.toUint8Array())
 | 
			
		||||
    encoding.writeVarUint8Array(encoder, encoding.toUint8Array(this.infoEncoder))
 | 
			
		||||
    encoding.writeVarUint8Array(encoder, this.stringEncoder.toUint8Array())
 | 
			
		||||
    encoding.writeVarUint8Array(encoder, encoding.toUint8Array(this.parentInfoEncoder))
 | 
			
		||||
    encoding.writeVarUint8Array(encoder, this.typeRefEncoder.toUint8Array())
 | 
			
		||||
    encoding.writeVarUint8Array(encoder, this.lenEncoder.toUint8Array())
 | 
			
		||||
    // @note The rest encoder is appended! (note the missing var)
 | 
			
		||||
    encoding.writeUint8Array(encoder, encoding.toUint8Array(this.restEncoder))
 | 
			
		||||
    return encoding.toUint8Array(encoder)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {ID} id
 | 
			
		||||
   */
 | 
			
		||||
  writeLeftID (id) {
 | 
			
		||||
    this.clientEncoder.write(id.client)
 | 
			
		||||
    this.leftClockEncoder.write(id.clock)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {ID} id
 | 
			
		||||
   */
 | 
			
		||||
  writeRightID (id) {
 | 
			
		||||
    this.clientEncoder.write(id.client)
 | 
			
		||||
    this.rightClockEncoder.write(id.clock)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {number} client
 | 
			
		||||
   */
 | 
			
		||||
  writeClient (client) {
 | 
			
		||||
    this.clientEncoder.write(client)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {number} info An unsigned 8-bit integer
 | 
			
		||||
   */
 | 
			
		||||
  writeInfo (info) {
 | 
			
		||||
    this.infoEncoder.write(info)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {string} s
 | 
			
		||||
   */
 | 
			
		||||
  writeString (s) {
 | 
			
		||||
    this.stringEncoder.write(s)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {boolean} isYKey
 | 
			
		||||
   */
 | 
			
		||||
  writeParentInfo (isYKey) {
 | 
			
		||||
    this.parentInfoEncoder.write(isYKey ? 1 : 0)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {number} info An unsigned 8-bit integer
 | 
			
		||||
   */
 | 
			
		||||
  writeTypeRef (info) {
 | 
			
		||||
    this.typeRefEncoder.write(info)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Write len of a struct - well suited for Opt RLE encoder.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {number} len
 | 
			
		||||
   */
 | 
			
		||||
  writeLen (len) {
 | 
			
		||||
    this.lenEncoder.write(len)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {any} any
 | 
			
		||||
   */
 | 
			
		||||
  writeAny (any) {
 | 
			
		||||
    encoding.writeAny(this.restEncoder, any)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @param {Uint8Array} buf
 | 
			
		||||
   */
 | 
			
		||||
  writeBuf (buf) {
 | 
			
		||||
    encoding.writeVarUint8Array(this.restEncoder, buf)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * This is mainly here for legacy purposes.
 | 
			
		||||
   *
 | 
			
		||||
   * Initial we incoded objects using JSON. Now we use the much faster lib0/any-encoder. This method mainly exists for legacy purposes for the v1 encoder.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {any} embed
 | 
			
		||||
   */
 | 
			
		||||
  writeJSON (embed) {
 | 
			
		||||
    encoding.writeAny(this.restEncoder, embed)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Property keys are often reused. For example, in y-prosemirror the key `bold` might
 | 
			
		||||
   * occur very often. For a 3d application, the key `position` might occur very often.
 | 
			
		||||
   *
 | 
			
		||||
   * We cache these keys in a Map and refer to them via a unique number.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {string} key
 | 
			
		||||
   */
 | 
			
		||||
  writeKey (key) {
 | 
			
		||||
    const clock = this.keyMap.get(key)
 | 
			
		||||
    if (clock === undefined) {
 | 
			
		||||
      this.keyClockEncoder.write(this.keyClock++)
 | 
			
		||||
      this.stringEncoder.write(key)
 | 
			
		||||
    } else {
 | 
			
		||||
      this.keyClockEncoder.write(this.keyClock++)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,7 +1,8 @@
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @module encoding
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
/*
 | 
			
		||||
 * We use the first five bits in the info flag for determining the type of the struct.
 | 
			
		||||
 *
 | 
			
		||||
 * 0: GC
 | 
			
		||||
@ -16,8 +17,6 @@
 | 
			
		||||
 | 
			
		||||
import {
 | 
			
		||||
  findIndexSS,
 | 
			
		||||
  writeID,
 | 
			
		||||
  readID,
 | 
			
		||||
  getState,
 | 
			
		||||
  createID,
 | 
			
		||||
  getStateVector,
 | 
			
		||||
@ -25,16 +24,36 @@ import {
 | 
			
		||||
  writeDeleteSet,
 | 
			
		||||
  createDeleteSetFromStructStore,
 | 
			
		||||
  transact,
 | 
			
		||||
  readItem,
 | 
			
		||||
  Doc, Transaction, GC, Item, StructStore, ID // eslint-disable-line
 | 
			
		||||
  readItemContent,
 | 
			
		||||
  UpdateDecoderV1,
 | 
			
		||||
  UpdateDecoderV2,
 | 
			
		||||
  UpdateEncoderV1,
 | 
			
		||||
  UpdateEncoderV2,
 | 
			
		||||
  DSDecoderV2,
 | 
			
		||||
  DSEncoderV2,
 | 
			
		||||
  DSDecoderV1,
 | 
			
		||||
  DSEncoderV1,
 | 
			
		||||
  AbstractDSEncoder, AbstractDSDecoder, AbstractUpdateEncoder, AbstractUpdateDecoder, AbstractContent, Doc, Transaction, GC, Item, StructStore, ID // eslint-disable-line
 | 
			
		||||
} from '../internals.js'
 | 
			
		||||
 | 
			
		||||
import * as encoding from 'lib0/encoding.js'
 | 
			
		||||
import * as decoding from 'lib0/decoding.js'
 | 
			
		||||
import * as binary from 'lib0/binary.js'
 | 
			
		||||
 | 
			
		||||
export let DefaultDSEncoder = DSEncoderV1
 | 
			
		||||
export let DefaultDSDecoder = DSDecoderV1
 | 
			
		||||
export let DefaultUpdateEncoder = UpdateEncoderV1
 | 
			
		||||
export let DefaultUpdateDecoder = UpdateDecoderV1
 | 
			
		||||
 | 
			
		||||
export const useV2Encoding = () => {
 | 
			
		||||
  DefaultDSEncoder = DSEncoderV2
 | 
			
		||||
  DefaultDSDecoder = DSDecoderV2
 | 
			
		||||
  DefaultUpdateEncoder = UpdateEncoderV2
 | 
			
		||||
  DefaultUpdateDecoder = UpdateDecoderV2
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {encoding.Encoder} encoder
 | 
			
		||||
 * @param {AbstractUpdateEncoder} encoder
 | 
			
		||||
 * @param {Array<GC|Item>} structs All structs by `client`
 | 
			
		||||
 * @param {number} client
 | 
			
		||||
 * @param {number} clock write structs starting with `ID(client,clock)`
 | 
			
		||||
@ -45,8 +64,9 @@ const writeStructs = (encoder, structs, client, clock) => {
 | 
			
		||||
  // write first id
 | 
			
		||||
  const startNewStructs = findIndexSS(structs, clock)
 | 
			
		||||
  // write # encoded structs
 | 
			
		||||
  encoding.writeVarUint(encoder, structs.length - startNewStructs)
 | 
			
		||||
  writeID(encoder, createID(client, clock))
 | 
			
		||||
  encoding.writeVarUint(encoder.restEncoder, structs.length - startNewStructs)
 | 
			
		||||
  encoder.writeClient(client)
 | 
			
		||||
  encoding.writeVarUint(encoder.restEncoder, clock)
 | 
			
		||||
  const firstStruct = structs[startNewStructs]
 | 
			
		||||
  // write first struct with an offset
 | 
			
		||||
  firstStruct.write(encoder, clock - firstStruct.id.clock)
 | 
			
		||||
@ -56,7 +76,7 @@ const writeStructs = (encoder, structs, client, clock) => {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {encoding.Encoder} encoder
 | 
			
		||||
 * @param {AbstractUpdateEncoder} encoder
 | 
			
		||||
 * @param {StructStore} store
 | 
			
		||||
 * @param {Map<number,number>} _sm
 | 
			
		||||
 *
 | 
			
		||||
@ -78,7 +98,7 @@ export const writeClientsStructs = (encoder, store, _sm) => {
 | 
			
		||||
    }
 | 
			
		||||
  })
 | 
			
		||||
  // write # states that were updated
 | 
			
		||||
  encoding.writeVarUint(encoder, sm.size)
 | 
			
		||||
  encoding.writeVarUint(encoder.restEncoder, sm.size)
 | 
			
		||||
  // Write items with higher client ids first
 | 
			
		||||
  // This heavily improves the conflict algorithm.
 | 
			
		||||
  Array.from(sm.entries()).sort((a, b) => b[0] - a[0]).forEach(([client, clock]) => {
 | 
			
		||||
@ -88,7 +108,7 @@ export const writeClientsStructs = (encoder, store, _sm) => {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {decoding.Decoder} decoder The decoder object to read data from.
 | 
			
		||||
 * @param {AbstractUpdateDecoder} decoder The decoder object to read data from.
 | 
			
		||||
 * @param {Map<number,Array<GC|Item>>} clientRefs
 | 
			
		||||
 * @param {Doc} doc
 | 
			
		||||
 * @return {Map<number,Array<GC|Item>>}
 | 
			
		||||
@ -97,21 +117,52 @@ export const writeClientsStructs = (encoder, store, _sm) => {
 | 
			
		||||
 * @function
 | 
			
		||||
 */
 | 
			
		||||
export const readClientsStructRefs = (decoder, clientRefs, doc) => {
 | 
			
		||||
  const numOfStateUpdates = decoding.readVarUint(decoder)
 | 
			
		||||
  const numOfStateUpdates = decoding.readVarUint(decoder.restDecoder)
 | 
			
		||||
  for (let i = 0; i < numOfStateUpdates; i++) {
 | 
			
		||||
    const numberOfStructs = decoding.readVarUint(decoder)
 | 
			
		||||
    const numberOfStructs = decoding.readVarUint(decoder.restDecoder)
 | 
			
		||||
    /**
 | 
			
		||||
     * @type {Array<GC|Item>}
 | 
			
		||||
     */
 | 
			
		||||
    const refs = []
 | 
			
		||||
    let { client, clock } = readID(decoder)
 | 
			
		||||
    let info, struct
 | 
			
		||||
    const client = decoder.readClient()
 | 
			
		||||
    let clock = decoding.readVarUint(decoder.restDecoder)
 | 
			
		||||
    clientRefs.set(client, refs)
 | 
			
		||||
    for (let i = 0; i < numberOfStructs; i++) {
 | 
			
		||||
      info = decoding.readUint8(decoder)
 | 
			
		||||
      struct = (binary.BITS5 & info) === 0 ? new GC(createID(client, clock), decoding.readVarUint(decoder)) : readItem(decoder, createID(client, clock), info, doc)
 | 
			
		||||
      refs.push(struct)
 | 
			
		||||
      clock += struct.length
 | 
			
		||||
      const info = decoder.readInfo()
 | 
			
		||||
      if ((binary.BITS5 & info) !== 0) {
 | 
			
		||||
        /**
 | 
			
		||||
         * The item that was originally to the left of this item.
 | 
			
		||||
         * @type {ID | null}
 | 
			
		||||
         */
 | 
			
		||||
        const origin = (info & binary.BIT8) === binary.BIT8 ? decoder.readLeftID() : null
 | 
			
		||||
        /**
 | 
			
		||||
         * The item that was originally to the right of this item.
 | 
			
		||||
         * @type {ID | null}
 | 
			
		||||
         */
 | 
			
		||||
        const rightOrigin = (info & binary.BIT7) === binary.BIT7 ? decoder.readRightID() : null
 | 
			
		||||
        const canCopyParentInfo = (info & (binary.BIT7 | binary.BIT8)) === 0
 | 
			
		||||
        const hasParentYKey = canCopyParentInfo ? decoder.readParentInfo() : false
 | 
			
		||||
        /**
 | 
			
		||||
         * If parent = null and neither left nor right are defined, then we know that `parent` is child of `y`
 | 
			
		||||
         * and we read the next string as parentYKey.
 | 
			
		||||
         * It indicates how we store/retrieve parent from `y.share`
 | 
			
		||||
         * @type {string|null}
 | 
			
		||||
         */
 | 
			
		||||
        const parentYKey = canCopyParentInfo && hasParentYKey ? decoder.readString() : null
 | 
			
		||||
 | 
			
		||||
        const struct = new Item(
 | 
			
		||||
          createID(client, clock), null, origin, null, rightOrigin,
 | 
			
		||||
          canCopyParentInfo && !hasParentYKey ? decoder.readLeftID() : (parentYKey ? doc.get(parentYKey) : null), // parent
 | 
			
		||||
          canCopyParentInfo && (info & binary.BIT6) === binary.BIT6 ? decoder.readString() : null, // parentSub
 | 
			
		||||
          /** @type {AbstractContent} */ (readItemContent(decoder, info)) // item content
 | 
			
		||||
        )
 | 
			
		||||
        refs.push(struct)
 | 
			
		||||
        clock += struct.length
 | 
			
		||||
      } else {
 | 
			
		||||
        const len = decoder.readLen()
 | 
			
		||||
        refs.push(new GC(createID(client, clock), len))
 | 
			
		||||
        clock += len
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return clientRefs
 | 
			
		||||
@ -222,7 +273,7 @@ export const tryResumePendingDeleteReaders = (transaction, store) => {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {encoding.Encoder} encoder
 | 
			
		||||
 * @param {AbstractUpdateEncoder} encoder
 | 
			
		||||
 * @param {Transaction} transaction
 | 
			
		||||
 *
 | 
			
		||||
 * @private
 | 
			
		||||
@ -275,7 +326,7 @@ const cleanupPendingStructs = pendingClientsStructRefs => {
 | 
			
		||||
 *
 | 
			
		||||
 * This is called when data is received from a remote peer.
 | 
			
		||||
 *
 | 
			
		||||
 * @param {decoding.Decoder} decoder The decoder object to read data from.
 | 
			
		||||
 * @param {AbstractUpdateDecoder} decoder The decoder object to read data from.
 | 
			
		||||
 * @param {Transaction} transaction
 | 
			
		||||
 * @param {StructStore} store
 | 
			
		||||
 *
 | 
			
		||||
@ -299,15 +350,46 @@ export const readStructs = (decoder, transaction, store) => {
 | 
			
		||||
 * @param {decoding.Decoder} decoder
 | 
			
		||||
 * @param {Doc} ydoc
 | 
			
		||||
 * @param {any} [transactionOrigin] This will be stored on `transaction.origin` and `.on('update', (update, origin))`
 | 
			
		||||
 * @param {AbstractUpdateDecoder} [structDecoder]
 | 
			
		||||
 *
 | 
			
		||||
 * @function
 | 
			
		||||
 */
 | 
			
		||||
export const readUpdate = (decoder, ydoc, transactionOrigin) =>
 | 
			
		||||
export const readUpdateV2 = (decoder, ydoc, transactionOrigin, structDecoder = new UpdateDecoderV2(decoder)) =>
 | 
			
		||||
  transact(ydoc, transaction => {
 | 
			
		||||
    readStructs(decoder, transaction, ydoc.store)
 | 
			
		||||
    readAndApplyDeleteSet(decoder, transaction, ydoc.store)
 | 
			
		||||
    readStructs(structDecoder, transaction, ydoc.store)
 | 
			
		||||
    readAndApplyDeleteSet(structDecoder, transaction, ydoc.store)
 | 
			
		||||
  }, transactionOrigin, false)
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Read and apply a document update.
 | 
			
		||||
 *
 | 
			
		||||
 * This function has the same effect as `applyUpdate` but accepts an decoder.
 | 
			
		||||
 *
 | 
			
		||||
 * @param {decoding.Decoder} decoder
 | 
			
		||||
 * @param {Doc} ydoc
 | 
			
		||||
 * @param {any} [transactionOrigin] This will be stored on `transaction.origin` and `.on('update', (update, origin))`
 | 
			
		||||
 *
 | 
			
		||||
 * @function
 | 
			
		||||
 */
 | 
			
		||||
export const readUpdate = (decoder, ydoc, transactionOrigin) => readUpdateV2(decoder, ydoc, transactionOrigin, new DefaultUpdateDecoder(decoder))
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Apply a document update created by, for example, `y.on('update', update => ..)` or `update = encodeStateAsUpdate()`.
 | 
			
		||||
 *
 | 
			
		||||
 * This function has the same effect as `readUpdate` but accepts an Uint8Array instead of a Decoder.
 | 
			
		||||
 *
 | 
			
		||||
 * @param {Doc} ydoc
 | 
			
		||||
 * @param {Uint8Array} update
 | 
			
		||||
 * @param {any} [transactionOrigin] This will be stored on `transaction.origin` and `.on('update', (update, origin))`
 | 
			
		||||
 * @param {typeof UpdateDecoderV1 | typeof UpdateDecoderV2} [YDecoder]
 | 
			
		||||
 *
 | 
			
		||||
 * @function
 | 
			
		||||
 */
 | 
			
		||||
export const applyUpdateV2 = (ydoc, update, transactionOrigin, YDecoder = UpdateDecoderV2) => {
 | 
			
		||||
  const decoder = decoding.createDecoder(update)
 | 
			
		||||
  readUpdateV2(decoder, ydoc, transactionOrigin, new YDecoder(decoder))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Apply a document update created by, for example, `y.on('update', update => ..)` or `update = encodeStateAsUpdate()`.
 | 
			
		||||
 *
 | 
			
		||||
@ -319,14 +401,13 @@ export const readUpdate = (decoder, ydoc, transactionOrigin) =>
 | 
			
		||||
 *
 | 
			
		||||
 * @function
 | 
			
		||||
 */
 | 
			
		||||
export const applyUpdate = (ydoc, update, transactionOrigin) =>
 | 
			
		||||
  readUpdate(decoding.createDecoder(update), ydoc, transactionOrigin)
 | 
			
		||||
export const applyUpdate = (ydoc, update, transactionOrigin) => applyUpdateV2(ydoc, update, transactionOrigin, DefaultUpdateDecoder)
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Write all the document as a single update message. If you specify the state of the remote client (`targetStateVector`) it will
 | 
			
		||||
 * only write the operations that are missing.
 | 
			
		||||
 *
 | 
			
		||||
 * @param {encoding.Encoder} encoder
 | 
			
		||||
 * @param {AbstractUpdateEncoder} encoder
 | 
			
		||||
 * @param {Doc} doc
 | 
			
		||||
 * @param {Map<number,number>} [targetStateVector] The state of the target that receives the update. Leave empty to write all known structs
 | 
			
		||||
 *
 | 
			
		||||
@ -345,31 +426,45 @@ export const writeStateAsUpdate = (encoder, doc, targetStateVector = new Map())
 | 
			
		||||
 *
 | 
			
		||||
 * @param {Doc} doc
 | 
			
		||||
 * @param {Uint8Array} [encodedTargetStateVector] The state of the target that receives the update. Leave empty to write all known structs
 | 
			
		||||
 * @param {AbstractUpdateEncoder} [encoder]
 | 
			
		||||
 * @return {Uint8Array}
 | 
			
		||||
 *
 | 
			
		||||
 * @function
 | 
			
		||||
 */
 | 
			
		||||
export const encodeStateAsUpdate = (doc, encodedTargetStateVector) => {
 | 
			
		||||
  const encoder = encoding.createEncoder()
 | 
			
		||||
export const encodeStateAsUpdateV2 = (doc, encodedTargetStateVector, encoder = new UpdateEncoderV2()) => {
 | 
			
		||||
  const targetStateVector = encodedTargetStateVector == null ? new Map() : decodeStateVector(encodedTargetStateVector)
 | 
			
		||||
  writeStateAsUpdate(encoder, doc, targetStateVector)
 | 
			
		||||
  return encoding.toUint8Array(encoder)
 | 
			
		||||
  return encoder.toUint8Array()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Write all the document as a single update message that can be applied on the remote document. If you specify the state of the remote client (`targetState`) it will
 | 
			
		||||
 * only write the operations that are missing.
 | 
			
		||||
 *
 | 
			
		||||
 * Use `writeStateAsUpdate` instead if you are working with lib0/encoding.js#Encoder
 | 
			
		||||
 *
 | 
			
		||||
 * @param {Doc} doc
 | 
			
		||||
 * @param {Uint8Array} [encodedTargetStateVector] The state of the target that receives the update. Leave empty to write all known structs
 | 
			
		||||
 * @return {Uint8Array}
 | 
			
		||||
 *
 | 
			
		||||
 * @function
 | 
			
		||||
 */
 | 
			
		||||
export const encodeStateAsUpdate = (doc, encodedTargetStateVector) => encodeStateAsUpdateV2(doc, encodedTargetStateVector, new DefaultUpdateEncoder())
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Read state vector from Decoder and return as Map
 | 
			
		||||
 *
 | 
			
		||||
 * @param {decoding.Decoder} decoder
 | 
			
		||||
 * @param {AbstractDSDecoder} decoder
 | 
			
		||||
 * @return {Map<number,number>} Maps `client` to the number next expected `clock` from that client.
 | 
			
		||||
 *
 | 
			
		||||
 * @function
 | 
			
		||||
 */
 | 
			
		||||
export const readStateVector = decoder => {
 | 
			
		||||
  const ss = new Map()
 | 
			
		||||
  const ssLength = decoding.readVarUint(decoder)
 | 
			
		||||
  const ssLength = decoding.readVarUint(decoder.restDecoder)
 | 
			
		||||
  for (let i = 0; i < ssLength; i++) {
 | 
			
		||||
    const client = decoding.readVarUint(decoder)
 | 
			
		||||
    const clock = decoding.readVarUint(decoder)
 | 
			
		||||
    const client = decoding.readVarUint(decoder.restDecoder)
 | 
			
		||||
    const clock = decoding.readVarUint(decoder.restDecoder)
 | 
			
		||||
    ss.set(client, clock)
 | 
			
		||||
  }
 | 
			
		||||
  return ss
 | 
			
		||||
@ -383,28 +478,34 @@ export const readStateVector = decoder => {
 | 
			
		||||
 *
 | 
			
		||||
 * @function
 | 
			
		||||
 */
 | 
			
		||||
export const decodeStateVector = decodedState => readStateVector(decoding.createDecoder(decodedState))
 | 
			
		||||
export const decodeStateVectorV2 = decodedState => readStateVector(new DSDecoderV2(decoding.createDecoder(decodedState)))
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Write State Vector to `lib0/encoding.js#Encoder`.
 | 
			
		||||
 * Read decodedState and return State as Map.
 | 
			
		||||
 *
 | 
			
		||||
 * @param {encoding.Encoder} encoder
 | 
			
		||||
 * @param {Uint8Array} decodedState
 | 
			
		||||
 * @return {Map<number,number>} Maps `client` to the number next expected `clock` from that client.
 | 
			
		||||
 *
 | 
			
		||||
 * @function
 | 
			
		||||
 */
 | 
			
		||||
export const decodeStateVector = decodedState => readStateVector(new DefaultDSDecoder(decoding.createDecoder(decodedState)))
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {AbstractDSEncoder} encoder
 | 
			
		||||
 * @param {Map<number,number>} sv
 | 
			
		||||
 * @function
 | 
			
		||||
 */
 | 
			
		||||
export const writeStateVector = (encoder, sv) => {
 | 
			
		||||
  encoding.writeVarUint(encoder, sv.size)
 | 
			
		||||
  encoding.writeVarUint(encoder.restEncoder, sv.size)
 | 
			
		||||
  sv.forEach((clock, client) => {
 | 
			
		||||
    encoding.writeVarUint(encoder, client)
 | 
			
		||||
    encoding.writeVarUint(encoder, clock)
 | 
			
		||||
    encoding.writeVarUint(encoder.restEncoder, client) // @todo use a special client decoder that is based on mapping
 | 
			
		||||
    encoding.writeVarUint(encoder.restEncoder, clock)
 | 
			
		||||
  })
 | 
			
		||||
  return encoder
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Write State Vector to `lib0/encoding.js#Encoder`.
 | 
			
		||||
 *
 | 
			
		||||
 * @param {encoding.Encoder} encoder
 | 
			
		||||
 * @param {AbstractDSEncoder} encoder
 | 
			
		||||
 * @param {Doc} doc
 | 
			
		||||
 *
 | 
			
		||||
 * @function
 | 
			
		||||
@ -415,12 +516,22 @@ export const writeDocumentStateVector = (encoder, doc) => writeStateVector(encod
 | 
			
		||||
 * Encode State as Uint8Array.
 | 
			
		||||
 *
 | 
			
		||||
 * @param {Doc} doc
 | 
			
		||||
 * @param {AbstractDSEncoder} [encoder]
 | 
			
		||||
 * @return {Uint8Array}
 | 
			
		||||
 *
 | 
			
		||||
 * @function
 | 
			
		||||
 */
 | 
			
		||||
export const encodeStateVector = doc => {
 | 
			
		||||
  const encoder = encoding.createEncoder()
 | 
			
		||||
export const encodeStateVectorV2 = (doc, encoder = new DSEncoderV2()) => {
 | 
			
		||||
  writeDocumentStateVector(encoder, doc)
 | 
			
		||||
  return encoding.toUint8Array(encoder)
 | 
			
		||||
  return encoder.toUint8Array()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Encode State as Uint8Array.
 | 
			
		||||
 *
 | 
			
		||||
 * @param {Doc} doc
 | 
			
		||||
 * @return {Uint8Array}
 | 
			
		||||
 *
 | 
			
		||||
 * @function
 | 
			
		||||
 */
 | 
			
		||||
export const encodeStateVector = doc => encodeStateVectorV2(doc, new DefaultDSEncoder())
 | 
			
		||||
 | 
			
		||||
@ -394,21 +394,21 @@ export const applyRandomTests = (tc, mods, iterations, initTestObject) => {
 | 
			
		||||
  const result = init(tc, { users: 5 }, initTestObject)
 | 
			
		||||
  const { testConnector, users } = result
 | 
			
		||||
  for (let i = 0; i < iterations; i++) {
 | 
			
		||||
    if (prng.int31(gen, 0, 100) <= 2) {
 | 
			
		||||
    if (prng.int32(gen, 0, 100) <= 2) {
 | 
			
		||||
      // 2% chance to disconnect/reconnect a random user
 | 
			
		||||
      if (prng.bool(gen)) {
 | 
			
		||||
        testConnector.disconnectRandom()
 | 
			
		||||
      } else {
 | 
			
		||||
        testConnector.reconnectRandom()
 | 
			
		||||
      }
 | 
			
		||||
    } else if (prng.int31(gen, 0, 100) <= 1) {
 | 
			
		||||
    } else if (prng.int32(gen, 0, 100) <= 1) {
 | 
			
		||||
      // 1% chance to flush all
 | 
			
		||||
      testConnector.flushAllMessages()
 | 
			
		||||
    } else if (prng.int31(gen, 0, 100) <= 50) {
 | 
			
		||||
    } else if (prng.int32(gen, 0, 100) <= 50) {
 | 
			
		||||
      // 50% chance to flush a random message
 | 
			
		||||
      testConnector.flushRandomMessage()
 | 
			
		||||
    }
 | 
			
		||||
    const user = prng.int31(gen, 0, users.length - 1)
 | 
			
		||||
    const user = prng.int32(gen, 0, users.length - 1)
 | 
			
		||||
    const test = prng.oneOf(gen, mods)
 | 
			
		||||
    test(users[user], gen, result.testObjects[user])
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -5,6 +5,18 @@ import * as t from 'lib0/testing.js'
 | 
			
		||||
import * as prng from 'lib0/prng.js'
 | 
			
		||||
import * as math from 'lib0/math.js'
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {t.TestCase} tc
 | 
			
		||||
 */
 | 
			
		||||
export const testBasicUpdate = tc => {
 | 
			
		||||
  const doc1 = new Y.Doc()
 | 
			
		||||
  const doc2 = new Y.Doc()
 | 
			
		||||
  doc1.getArray('array').insert(0, ['hi'])
 | 
			
		||||
  const update = Y.encodeStateAsUpdate(doc1)
 | 
			
		||||
  Y.applyUpdate(doc2, update)
 | 
			
		||||
  t.compare(doc2.getArray('array').toArray(), ['hi'])
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {t.TestCase} tc
 | 
			
		||||
 */
 | 
			
		||||
@ -335,23 +347,23 @@ const arrayTransactions = [
 | 
			
		||||
    const yarray = user.getArray('array')
 | 
			
		||||
    var uniqueNumber = getUniqueNumber()
 | 
			
		||||
    var content = []
 | 
			
		||||
    var len = prng.int31(gen, 1, 4)
 | 
			
		||||
    var len = prng.int32(gen, 1, 4)
 | 
			
		||||
    for (var i = 0; i < len; i++) {
 | 
			
		||||
      content.push(uniqueNumber)
 | 
			
		||||
    }
 | 
			
		||||
    var pos = prng.int31(gen, 0, yarray.length)
 | 
			
		||||
    var pos = prng.int32(gen, 0, yarray.length)
 | 
			
		||||
    yarray.insert(pos, content)
 | 
			
		||||
  },
 | 
			
		||||
  function insertTypeArray (user, gen) {
 | 
			
		||||
    const yarray = user.getArray('array')
 | 
			
		||||
    var pos = prng.int31(gen, 0, yarray.length)
 | 
			
		||||
    var pos = prng.int32(gen, 0, yarray.length)
 | 
			
		||||
    yarray.insert(pos, [new Y.Array()])
 | 
			
		||||
    var array2 = yarray.get(pos)
 | 
			
		||||
    array2.insert(0, [1, 2, 3, 4])
 | 
			
		||||
  },
 | 
			
		||||
  function insertTypeMap (user, gen) {
 | 
			
		||||
    const yarray = user.getArray('array')
 | 
			
		||||
    var pos = prng.int31(gen, 0, yarray.length)
 | 
			
		||||
    var pos = prng.int32(gen, 0, yarray.length)
 | 
			
		||||
    yarray.insert(pos, [new Y.Map()])
 | 
			
		||||
    var map = yarray.get(pos)
 | 
			
		||||
    map.set('someprop', 42)
 | 
			
		||||
@ -362,13 +374,13 @@ const arrayTransactions = [
 | 
			
		||||
    const yarray = user.getArray('array')
 | 
			
		||||
    var length = yarray.length
 | 
			
		||||
    if (length > 0) {
 | 
			
		||||
      var somePos = prng.int31(gen, 0, length - 1)
 | 
			
		||||
      var delLength = prng.int31(gen, 1, math.min(2, length - somePos))
 | 
			
		||||
      var somePos = prng.int32(gen, 0, length - 1)
 | 
			
		||||
      var delLength = prng.int32(gen, 1, math.min(2, length - somePos))
 | 
			
		||||
      if (prng.bool(gen)) {
 | 
			
		||||
        var type = yarray.get(somePos)
 | 
			
		||||
        if (type.length > 0) {
 | 
			
		||||
          somePos = prng.int31(gen, 0, type.length - 1)
 | 
			
		||||
          delLength = prng.int31(gen, 0, math.min(2, type.length - somePos))
 | 
			
		||||
          somePos = prng.int32(gen, 0, type.length - 1)
 | 
			
		||||
          delLength = prng.int32(gen, 0, math.min(2, type.length - somePos))
 | 
			
		||||
          type.delete(somePos, delLength)
 | 
			
		||||
        }
 | 
			
		||||
      } else {
 | 
			
		||||
 | 
			
		||||
@ -215,7 +215,7 @@ const tryGc = () => {
 | 
			
		||||
 * @param {t.TestCase} tc
 | 
			
		||||
 */
 | 
			
		||||
export const testLargeFragmentedDocument = tc => {
 | 
			
		||||
  const itemsToInsert = 2000000
 | 
			
		||||
  const itemsToInsert = 1000000
 | 
			
		||||
  let update = /** @type {any} */ (null)
 | 
			
		||||
  ;(() => {
 | 
			
		||||
    const doc1 = new Y.Doc()
 | 
			
		||||
@ -230,14 +230,15 @@ export const testLargeFragmentedDocument = tc => {
 | 
			
		||||
    })
 | 
			
		||||
    tryGc()
 | 
			
		||||
    t.measureTime('time to encode document', () => {
 | 
			
		||||
      update = Y.encodeStateAsUpdate(doc1)
 | 
			
		||||
      update = Y.encodeStateAsUpdateV2(doc1)
 | 
			
		||||
    })
 | 
			
		||||
    t.describe('Document size:', update.byteLength)
 | 
			
		||||
  })()
 | 
			
		||||
  ;(() => {
 | 
			
		||||
    const doc2 = new Y.Doc()
 | 
			
		||||
    tryGc()
 | 
			
		||||
    t.measureTime(`time to apply ${itemsToInsert} updates`, () => {
 | 
			
		||||
      Y.applyUpdate(doc2, update)
 | 
			
		||||
      Y.applyUpdateV2(doc2, update)
 | 
			
		||||
    })
 | 
			
		||||
  })()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user