Compare commits

...

8 Commits

Author SHA1 Message Date
Kevin Jahns
1337d38ada 13.0.0-95 2019-08-09 01:18:15 +02:00
Kevin Jahns
f5c66e41cb audit 2019-08-09 01:16:40 +02:00
Kevin Jahns
0e7da017fe Use lib0/any-encoding instead of JSON 2019-08-09 01:15:46 +02:00
Kevin Jahns
36203af88e should not rely on all deconstructing features because not all parsers support it 2019-06-29 14:47:34 +02:00
Kevin Jahns
dd2b8bc6c7 13.0.0-94 2019-06-25 11:57:50 +02:00
Kevin Jahns
463065ac21 UndoManager: keep item before item is deleted (fixes some edge cases of followRedo) 2019-06-25 11:56:41 +02:00
Kevin Jahns
d064e6e96e UndoManager accepts an array of types as scope. Implements #156 2019-06-25 02:26:18 +02:00
Kevin Jahns
b1ed2df208 proper TOC links 2019-06-25 00:10:12 +02:00
11 changed files with 228 additions and 104 deletions

View File

@@ -25,10 +25,10 @@ suited for even large documents.
* [Getting Started](#Getting-Started)
* [API](#API)
* [Shared Types](#Shared-Types)
* [Y.Doc](#Y.Doc)
* [Y.Doc](#YDoc)
* [Document Updates](#Document-Updates)
* [Relative Positions](#Relative-Positions)
* [Y.UndoManager](#Y.UndoManager)
* [Y.UndoManager](#YUndoManager)
* [Miscellaneous](#Miscellaneous)
* [Typescript Declarations](#Typescript-Declarations)
* [Yjs CRDT Algorithm](#Yjs-CRDT-Algorithm)
@@ -661,9 +661,9 @@ ytext.toString() // => 'abc'
```
<dl>
<b><code>constructor(type:Y.AbstractType,
<b><code>constructor(scope:Y.AbstractType|Array&lt;Y.AbstractType&gt;,
[trackedTransactionOrigins:Set&lt;any&gt;, [{captureTimeout: number}]])</code></b>
<dd></dd>
<dd>Accepts either single type as scope or an array of types.</dd>
<b><code>undo()</code></b>
<dd></dd>
<b><code>redo()</code></b>

123
package-lock.json generated
View File

@@ -1,13 +1,13 @@
{
"name": "yjs",
"version": "13.0.0-93",
"version": "13.0.0-95",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@babel/parser": {
"version": "7.4.5",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.4.5.tgz",
"integrity": "sha512-9mUqkL1FF5T7f0WDFfAoDdiMVPWsdD1gZYzSnaXsxUCUqzuch/8of9G3VUSNiZmMBoRxT3neyVsqeiL/ZPcjew==",
"version": "7.5.5",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.5.5.tgz",
"integrity": "sha512-E5BN68cqR7dhKan1SfqgPGhQ178bkVKpXTPEXnFJBrEt8/DKRZlybmy+IgYLTeN7tp1R5Ccmbm2rBk17sHYU3g==",
"dev": true
},
"@types/estree": {
@@ -431,12 +431,12 @@
"dev": true
},
"catharsis": {
"version": "0.8.10",
"resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.8.10.tgz",
"integrity": "sha512-l2OUaz/3PU3MZylspVFJvwHCVfWyvcduPq4lv3AzZ2pJzZCo7kNKFNyatwujD7XgvGkNAE/Jhhbh2uARNwNkfw==",
"version": "0.8.11",
"resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.8.11.tgz",
"integrity": "sha512-a+xUyMV7hD1BrDQA/3iPV7oc+6W26BgVJO05PGEoatMyIuPScQKsde6i3YorWX1qs+AZjnJ18NqdKoCtKiNh1g==",
"dev": true,
"requires": {
"lodash": "^4.17.11"
"lodash": "^4.17.14"
}
},
"chalk": {
@@ -2514,22 +2514,22 @@
}
},
"jsdoc": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.6.2.tgz",
"integrity": "sha512-S2vzg99C5+gb7FWlrK4TVdyzVPGGkdvpDkCEJH1JABi2PKzPeLu5/zZffcJUifgWUJqXWl41Hoc+MmuM2GukIg==",
"version": "3.6.3",
"resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.6.3.tgz",
"integrity": "sha512-Yf1ZKA3r9nvtMWHO1kEuMZTlHOF8uoQ0vyo5eH7SQy5YeIiHM+B0DgKnn+X6y6KDYZcF7G2SPkKF+JORCXWE/A==",
"dev": true,
"requires": {
"@babel/parser": "^7.4.4",
"bluebird": "^3.5.4",
"catharsis": "^0.8.10",
"catharsis": "^0.8.11",
"escape-string-regexp": "^2.0.0",
"js2xmlparser": "^4.0.0",
"klaw": "^3.0.0",
"markdown-it": "^8.4.2",
"markdown-it-anchor": "^5.0.2",
"marked": "^0.6.2",
"marked": "^0.7.0",
"mkdirp": "^0.5.1",
"requizzle": "^0.2.2",
"requizzle": "^0.2.3",
"strip-json-comments": "^3.0.1",
"taffydb": "2.6.2",
"underscore": "~1.9.1"
@@ -2596,14 +2596,14 @@
}
},
"lib0": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/lib0/-/lib0-0.0.5.tgz",
"integrity": "sha512-3ElV6/t5Lv0Eczlnh/05q+Uq3RxQ/Q0zdN6LVtaUERQIDDZsP/CUXEGLsV8KZTgZwVFNCPGXNWYE+3WTOo+SHw=="
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/lib0/-/lib0-0.0.6.tgz",
"integrity": "sha512-drb8LcwZu2rAmTsXN0d3hFtZVbPE5ZUrsWf307Boc/v7IrmLq3lM5+OOMY672EysHTWeXo/OH54wRHyD6eFXXw=="
},
"linkify-it": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.1.0.tgz",
"integrity": "sha512-4REs8/062kV2DSHxNfq5183zrqXMl7WP0WzABH9IeJI+NLm429FgE1PDecltYfnOoFDFlZGh2T8PfZn0r+GTRg==",
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz",
"integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==",
"dev": true,
"requires": {
"uc.micro": "^1.0.1"
@@ -2653,9 +2653,9 @@
}
},
"lodash": {
"version": "4.17.11",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
"version": "4.17.15",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
"dev": true
},
"lodash.assignin": {
@@ -2701,9 +2701,9 @@
"dev": true
},
"lodash.merge": {
"version": "4.6.1",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.1.tgz",
"integrity": "sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ==",
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
"dev": true
},
"lodash.pick": {
@@ -2784,15 +2784,15 @@
}
},
"markdown-it-anchor": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-5.1.0.tgz",
"integrity": "sha512-wJOmyXzDUxI8iuowEsaQAKMQBButhSw8j64SpgcaL75QZYC/OSZV66Fnr50lfMLYNGtV0rJdw2fmLwXCT6T+bw==",
"version": "5.2.4",
"resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-5.2.4.tgz",
"integrity": "sha512-n8zCGjxA3T+Mx1pG8HEgbJbkB8JFUuRkeTZQuIM8iPY6oQ8sWOPRZJDFC9a/pNg2QkHEjjGkhBEl/RSyzaDZ3A==",
"dev": true
},
"marked": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/marked/-/marked-0.6.2.tgz",
"integrity": "sha512-LqxwVH3P/rqKX4EKGz7+c2G9r98WeM/SW34ybhgNGhUQNKtf1GmmSkJ6cDGJ/t6tiyae49qRkpyTw2B9HOrgUA==",
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/marked/-/marked-0.7.0.tgz",
"integrity": "sha512-c+yYdCZJQrsRjTPhUx7VKkApw9bwDkNbHUKo1ovgcfDjb2kc8rLuRbIFyXL5WOEUwzSSKo3IXpph2K6DqB/KZg==",
"dev": true
},
"mdurl": {
@@ -2865,9 +2865,9 @@
"dev": true
},
"mixin-deep": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz",
"integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==",
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
"integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
"dev": true,
"requires": {
"for-in": "^1.0.2",
@@ -3437,12 +3437,12 @@
}
},
"requizzle": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.2.tgz",
"integrity": "sha512-oJ6y7JcUJkblRGhMByGNcszeLgU0qDxNKFCiUZR1XyzHyVsev+Mxb1tyygxLd1ORsKee1SA5BInFdUwY64GE/A==",
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.3.tgz",
"integrity": "sha512-YanoyJjykPxGHii0fZP0uUPEXpvqfBDxWV7s6GKAiiOsiqhX6vHNyW3Qzdmqp/iq/ExbhaGbVrjB4ruEVSM4GQ==",
"dev": true,
"requires": {
"lodash": "^4.17.11"
"lodash": "^4.17.14"
}
},
"resolve": {
@@ -3648,9 +3648,9 @@
}
},
"set-value": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz",
"integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==",
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
"integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
"dev": true,
"requires": {
"extend-shallow": "^2.0.1",
@@ -4176,38 +4176,15 @@
"dev": true
},
"union-value": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz",
"integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=",
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
"integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
"dev": true,
"requires": {
"arr-union": "^3.1.0",
"get-value": "^2.0.6",
"is-extendable": "^0.1.1",
"set-value": "^0.4.3"
},
"dependencies": {
"extend-shallow": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
"dev": true,
"requires": {
"is-extendable": "^0.1.0"
}
},
"set-value": {
"version": "0.4.3",
"resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz",
"integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=",
"dev": true,
"requires": {
"extend-shallow": "^2.0.1",
"is-extendable": "^0.1.1",
"is-plain-object": "^2.0.1",
"to-object-path": "^0.3.0"
}
}
"set-value": "^2.0.1"
}
},
"uniq": {
@@ -4385,6 +4362,14 @@
"dev": true,
"requires": {
"lib0": "0.0.5"
},
"dependencies": {
"lib0": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/lib0/-/lib0-0.0.5.tgz",
"integrity": "sha512-3ElV6/t5Lv0Eczlnh/05q+Uq3RxQ/Q0zdN6LVtaUERQIDDZsP/CUXEGLsV8KZTgZwVFNCPGXNWYE+3WTOo+SHw==",
"dev": true
}
}
},
"yallist": {

View File

@@ -1,6 +1,6 @@
{
"name": "yjs",
"version": "13.0.0-93",
"version": "13.0.0-95",
"description": "Shared Editing Library",
"main": "./dist/yjs.js",
"module": "./dist/yjs.mjs",
@@ -51,11 +51,11 @@
},
"homepage": "http://y-js.org",
"dependencies": {
"lib0": "0.0.5"
"lib0": "0.0.6"
},
"devDependencies": {
"concurrently": "^3.6.1",
"jsdoc": "^3.6.2",
"jsdoc": "^3.6.3",
"live-server": "^1.2.1",
"rollup": "^1.11.3",
"rollup-cli": "^1.0.9",

View File

@@ -21,6 +21,7 @@ export {
ContentEmbed,
ContentFormat,
ContentJSON,
ContentAny,
ContentString,
ContentType,
AbstractType,

View File

@@ -27,6 +27,7 @@ export * from './structs/ContentDeleted.js'
export * from './structs/ContentEmbed.js'
export * from './structs/ContentFormat.js'
export * from './structs/ContentJSON.js'
export * from './structs/ContentAny.js'
export * from './structs/ContentString.js'
export * from './structs/ContentType.js'
export * from './structs/Item.js'

108
src/structs/ContentAny.js Normal file
View File

@@ -0,0 +1,108 @@
import {
Transaction, Item, StructStore // eslint-disable-line
} from '../internals.js'
import * as encoding from 'lib0/encoding.js'
import * as decoding from 'lib0/decoding.js'
/**
* @private
*/
export class ContentAny {
/**
* @param {Array<any>} arr
*/
constructor (arr) {
/**
* @type {Array<any>}
*/
this.arr = arr
}
/**
* @return {number}
*/
getLength () {
return this.arr.length
}
/**
* @return {Array<any>}
*/
getContent () {
return this.arr
}
/**
* @return {boolean}
*/
isCountable () {
return true
}
/**
* @return {ContentAny}
*/
copy () {
return new ContentAny(this.arr)
}
/**
* @param {number} offset
* @return {ContentAny}
*/
splice (offset) {
const right = new ContentAny(this.arr.slice(offset))
this.arr = this.arr.slice(0, offset)
return right
}
/**
* @param {ContentAny} right
* @return {boolean}
*/
mergeWith (right) {
this.arr = this.arr.concat(right.arr)
return true
}
/**
* @param {Transaction} transaction
* @param {Item} item
*/
integrate (transaction, item) {}
/**
* @param {Transaction} transaction
*/
delete (transaction) {}
/**
* @param {StructStore} store
*/
gc (store) {}
/**
* @param {encoding.Encoder} encoder
* @param {number} offset
*/
write (encoder, offset) {
const len = this.arr.length
encoding.writeVarUint(encoder, len - offset)
for (let i = offset; i < len; i++) {
const c = this.arr[i]
encoding.writeAny(encoder, c)
}
}
/**
* @return {number}
*/
getRef () {
return 8
}
}
/**
* @private
*
* @param {decoding.Decoder} decoder
* @return {ContentAny}
*/
export const readContentAny = decoder => {
const len = decoding.readVarUint(decoder)
const cs = []
for (let i = 0; i < len; i++) {
cs.push(decoding.readAny(decoder))
}
return new ContentAny(cs)
}

View File

@@ -18,6 +18,7 @@ import {
readContentDeleted,
readContentBinary,
readContentJSON,
readContentAny,
readContentString,
readContentEmbed,
readContentFormat,
@@ -561,7 +562,8 @@ export const contentRefs = [
readContentString,
readContentEmbed,
readContentFormat,
readContentType
readContentType,
readContentAny
]
/**

View File

@@ -7,7 +7,7 @@ import {
nextID,
isVisible,
ContentType,
ContentJSON,
ContentAny,
ContentBinary,
createID,
getItemCleanStart,
@@ -374,7 +374,7 @@ export const typeListInsertGenericsAfter = (transaction, parent, referenceItem,
let jsonContent = []
const packJsonContent = () => {
if (jsonContent.length > 0) {
left = new Item(nextID(transaction), left, left === null ? null : left.lastId, right, right === null ? null : right.id, parent, null, new ContentJSON(jsonContent))
left = new Item(nextID(transaction), left, left === null ? null : left.lastId, right, right === null ? null : right.id, parent, null, new ContentAny(jsonContent))
left.integrate(transaction)
jsonContent = []
}
@@ -503,7 +503,7 @@ export const typeMapSet = (transaction, parent, key, value) => {
const left = parent._map.get(key) || null
let content
if (value == null) {
content = new ContentJSON([value])
content = new ContentAny([value])
} else {
switch (value.constructor) {
case Number:
@@ -511,7 +511,7 @@ export const typeMapSet = (transaction, parent, key, value) => {
case Boolean:
case Array:
case String:
content = new ContentJSON([value])
content = new ContentAny([value])
break
case Uint8Array:
content = new ContentBinary(value)

View File

@@ -9,7 +9,7 @@ import {
createID,
followRedone,
getItemCleanStart,
Doc, Item, GC, DeleteSet, AbstractType // eslint-disable-line
Transaction, Doc, Item, GC, DeleteSet, AbstractType // eslint-disable-line
} from '../internals.js'
import * as time from 'lib0/time.js'
@@ -45,7 +45,7 @@ const popStackItem = (undoManager, stack, eventType) => {
*/
let result = null
const doc = undoManager.doc
const type = undoManager.type
const scope = undoManager.scope
transact(doc, transaction => {
while (stack.length > 0 && result === null) {
const store = doc.store
@@ -53,7 +53,7 @@ const popStackItem = (undoManager, stack, eventType) => {
const itemsToRedo = new Set()
let performedChange = false
iterateDeletedStructs(transaction, stackItem.ds, store, struct => {
if (struct instanceof Item && isParentOf(type, struct)) {
if (struct instanceof Item && scope.some(type => isParentOf(type, struct))) {
itemsToRedo.add(struct)
}
})
@@ -62,17 +62,18 @@ const popStackItem = (undoManager, stack, eventType) => {
})
const structs = /** @type {Array<GC|Item>} */ (store.clients.get(doc.clientID))
iterateStructs(transaction, structs, stackItem.start, stackItem.len, struct => {
if (struct instanceof Item && struct.redone !== null) {
let { item, diff } = followRedone(store, struct.id)
if (diff > 0) {
item = getItemCleanStart(transaction, store, struct.id)
if (struct instanceof Item && !struct.deleted && scope.some(type => isParentOf(type, /** @type {Item} */ (struct)))) {
if (struct.redone !== null) {
let { item, diff } = followRedone(store, struct.id)
if (diff > 0) {
item = getItemCleanStart(transaction, store, createID(item.id.client, item.id.clock + diff))
}
if (item.length > stackItem.len) {
getItemCleanStart(transaction, store, createID(item.id.client, item.id.clock + stackItem.len))
}
struct = item
}
if (item.length > stackItem.len) {
getItemCleanStart(transaction, store, createID(item.id.client, item.id.clock + stackItem.len))
}
struct = item
}
if (!struct.deleted && isParentOf(type, /** @type {Item} */ (struct))) {
keepItem(struct)
struct.delete(transaction)
performedChange = true
}
@@ -97,13 +98,16 @@ const popStackItem = (undoManager, stack, eventType) => {
*/
export class UndoManager extends Observable {
/**
* @param {AbstractType<any>} type
* @param {AbstractType<any>|Array<AbstractType<any>>} typeScope Accepts either a single type, or an array of types
* @param {Set<any>} [trackedTransactionOrigins=new Set([null])]
* @param {object} [options={captureTimeout=500}]
*/
constructor (type, trackedTransactionOrigins = new Set([null]), { captureTimeout = 500 } = {}) {
constructor (typeScope, trackedTransactionOrigins = new Set([null]), { captureTimeout } = {}) {
if (captureTimeout == null) {
captureTimeout = 500
}
super()
this.type = type
this.scope = typeScope instanceof Array ? typeScope : [typeScope]
trackedTransactionOrigins.add(this)
this.trackedTransactionOrigins = trackedTransactionOrigins
/**
@@ -121,11 +125,11 @@ export class UndoManager extends Observable {
*/
this.undoing = false
this.redoing = false
this.doc = /** @type {Doc} */ (type.doc)
this.doc = /** @type {Doc} */ (this.scope[0].doc)
this.lastChange = 0
type.observeDeep((events, transaction) => {
this.doc.on('afterTransaction', /** @param {Transaction} transaction */ transaction => {
// Only track certain transactions
if (!this.trackedTransactionOrigins.has(transaction.origin) && (!transaction.origin || !this.trackedTransactionOrigins.has(transaction.origin.constructor))) {
if (!this.scope.some(type => transaction.changedParentTypes.has(type)) || (!this.trackedTransactionOrigins.has(transaction.origin) && (!transaction.origin || !this.trackedTransactionOrigins.has(transaction.origin.constructor)))) {
return
}
const undoing = this.undoing
@@ -154,7 +158,7 @@ export class UndoManager extends Observable {
}
// make sure that deleted structs are not gc'd
iterateDeletedStructs(transaction, transaction.deleteSet, transaction.doc.store, /** @param {Item|GC} item */ item => {
if (item instanceof Item && isParentOf(type, item)) {
if (item instanceof Item && this.scope.some(type => isParentOf(type, item))) {
keepItem(item)
}
})

View File

@@ -8,19 +8,21 @@ import {
readContentJSON,
readContentEmbed,
readContentType,
readContentFormat
readContentFormat,
readContentAny
} from '../src/internals.js'
/**
* @param {t.TestCase} tc
*/
export const testStructReferences = tc => {
t.assert(contentRefs.length === 8)
t.assert(contentRefs.length === 9)
t.assert(contentRefs[1] === readContentDeleted)
t.assert(contentRefs[2] === readContentJSON)
t.assert(contentRefs[2] === readContentJSON) // TODO: deprecate content json?
t.assert(contentRefs[3] === readContentBinary)
t.assert(contentRefs[4] === readContentString)
t.assert(contentRefs[5] === readContentEmbed)
t.assert(contentRefs[6] === readContentFormat)
t.assert(contentRefs[7] === readContentType)
t.assert(contentRefs[8] === readContentAny)
}

View File

@@ -180,3 +180,24 @@ export const testTrackClass = tc => {
undoManager.undo()
t.assert(text0.toString() === '')
}
/**
* @param {t.TestCase} tc
*/
export const testTypeScope = tc => {
const { array0 } = init(tc, { users: 3 })
// only track origins that are numbers
const text0 = new Y.Text()
const text1 = new Y.Text()
array0.insert(0, [text0, text1])
const undoManager = new UndoManager(text0)
const undoManagerBoth = new UndoManager([text0, text1])
text1.insert(0, 'abc')
t.assert(undoManager.undoStack.length === 0)
t.assert(undoManagerBoth.undoStack.length === 1)
t.assert(text1.toString() === 'abc')
undoManager.undo()
t.assert(text1.toString() === 'abc')
undoManagerBoth.undo()
t.assert(text1.toString() === '')
}