diff --git a/src/types/AbstractType.js b/src/types/AbstractType.js
index d8411933..1f4f04dd 100644
--- a/src/types/AbstractType.js
+++ b/src/types/AbstractType.js
@@ -571,7 +571,7 @@ export class AbstractType {
if (c.deleted ? retainDeletes : retainInserts) {
d.retain(c.content.getLength(), null, attribution ?? {})
} else if (deep && c.content.constructor === ContentType) {
- d.insert([/** @type {any} */(c.content).type.getContent(am, opts)], null, attribution)
+ d.insert([/** @type {any} */(c.content).type.getContent(am, { ...opts, renderChildren: true, renderAttrs: null })], null, attribution)
} else {
d.insert(c.content.getContent(), null, attribution)
}
@@ -579,6 +579,7 @@ export class AbstractType {
d.delete(1)
} else if (retainContent) {
if (c.content.constructor === ContentType && modified?.has(/** @type {ContentType} */ (c.content).type)) {
+ // @todo use current transaction instead
d.modify(/** @type {any} */ (c.content).type.getContent(am, opts))
} else {
d.usedAttributes = changedAttributes
diff --git a/src/types/YArray.js b/src/types/YArray.js
index 39e29fd6..eaad7db1 100644
--- a/src/types/YArray.js
+++ b/src/types/YArray.js
@@ -3,7 +3,6 @@
*/
import {
- YEvent,
AbstractType,
typeListGet,
typeListToArray,
diff --git a/src/types/YXmlFragment.js b/src/types/YXmlFragment.js
index 356f1934..be65a48f 100644
--- a/src/types/YXmlFragment.js
+++ b/src/types/YXmlFragment.js
@@ -3,7 +3,6 @@
*/
import {
- YEvent,
AbstractType,
typeListMap,
typeListForEach,
diff --git a/tests/compatibility.tests.js b/tests/compatibility.tests.js
index 98d97e92..674d6862 100644
--- a/tests/compatibility.tests.js
+++ b/tests/compatibility.tests.js
@@ -38,7 +38,7 @@ export const testMapDecodingCompatibilityV1 = _tc => {
export const testTextDecodingCompatibilityV1 = _tc => {
const oldDoc = 'BS8EAAUBBHRleHRveyJpbWFnZSI6Imh0dHBzOi8vdXNlci1pbWFnZXMuZ2l0aHVidXNlcmNvbnRlbnQuY29tLzU1NTM3NTcvNDg5NzUzMDctNjFlZmIxMDAtZjA2ZC0xMWU4LTkxNzctZWU4OTVlNTkxNmU1LnBuZyJ9RAQAATHBBAEEAAHBBAIEAAHEBAMEAAQxdXUKxQQCBANveyJpbWFnZSI6Imh0dHBzOi8vdXNlci1pbWFnZXMuZ2l0aHVidXNlcmNvbnRlbnQuY29tLzU1NTM3NTcvNDg5NzUzMDctNjFlZmIxMDAtZjA2ZC0xMWU4LTkxNzctZWU4OTVlNTkxNmU1LnBuZyJ9xQMJBAFveyJpbWFnZSI6Imh0dHBzOi8vdXNlci1pbWFnZXMuZ2l0aHVidXNlcmNvbnRlbnQuY29tLzU1NTM3NTcvNDg5NzUzMDctNjFlZmIxMDAtZjA2ZC0xMWU4LTkxNzctZWU4OTVlNTkxNmU1LnBuZyJ9xQMJBAlveyJpbWFnZSI6Imh0dHBzOi8vdXNlci1pbWFnZXMuZ2l0aHVidXNlcmNvbnRlbnQuY29tLzU1NTM3NTcvNDg5NzUzMDctNjFlZmIxMDAtZjA2ZC0xMWU4LTkxNzctZWU4OTVlNTkxNmU1LnBuZyJ9xgMBAwIGaXRhbGljBHRydWXGBAsDAgVjb2xvcgYiIzg4OCLEBAwDAgExxAQNAwIBMsEEDgMCAsYEEAMCBml0YWxpYwRudWxsxgQRAwIFY29sb3IEbnVsbMQDAQQLATHEBBMECwIyOcQEFQQLCzl6anpueXdvaHB4xAQgBAsIY25icmNhcQrBAxADEQHGAR8BIARib2xkBHRydWXGAgACAQRib2xkBG51bGzFAwkECm97ImltYWdlIjoiaHR0cHM6Ly91c2VyLWltYWdlcy5naXRodWJ1c2VyY29udGVudC5jb20vNTU1Mzc1Ny80ODk3NTMwNy02MWVmYjEwMC1mMDZkLTExZTgtOTE3Ny1lZTg5NWU1OTE2ZTUucG5nIn3GARABEQZpdGFsaWMEdHJ1ZcYELQERBWNvbG9yBiIjODg4IsYBEgETBml0YWxpYwRudWxsxgQvARMFY29sb3IEbnVsbMYCKwIsBGJvbGQEdHJ1ZcYCLQIuBGJvbGQEbnVsbMYCjAECjQEGaXRhbGlj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xgKbAQQOBml0YWxpYwR0cnVlxgKcAQQOBWNvbG9yBiIjODg4IsECaAI7AcQCCgEBFjEzMThqd3NramFiZG5kcmRsbWphZQrGA1UDVgRib2xkBHRydWXGA1cDWARib2xkBG51bGzGAEAAQQZpdGFsaWMEdHJ1ZcYCtwEAQQRib2xkBG51bGzEArgBAEESMTMyNnJwY3pucWFob3BjcnRkxgLKAQBBBml0YWxpYwRudWxsxgLLAQBBBGJvbGQEdHJ1ZRkBAMUCAgIDb3siaW1hZ2UiOiJodHRwczovL3VzZXItaW1hZ2VzLmdpdGh1YnVzZXJjb250ZW50LmNvbS81NTUzNzU3LzQ4OTc1MzA3LTYxZWZiMTAwLWYwNmQtMTFlOC05MTc3LWVlODk1ZTU5MTZlNS5wbmcifcQCCgILBzEyOTN0agrGABgAGQRib2xkBHRydWXGAA0ADgRib2xkBG51bGxEAgAHMTMwNnJ1cMQBEAIAAnVqxAESAgANaWtrY2pucmNwc2Nrd8QBHwIAAQrFBBMEFG97ImltYWdlIjoiaHR0cHM6Ly91c2VyLWltYWdlcy5naXRodWJ1c2VyY29udGVudC5jb20vNTU1Mzc1Ny80ODk3NTMwNy02MWVmYjEwMC1mMDZkLTExZTgtOTE3Ny1lZTg5NWU1OTE2ZTUucG5nIn3FAx0DBW97ImltYWdlIjoiaHR0cHM6Ly91c2VyLWltYWdlcy5naXRodWJ1c2VyY29udGVudC5jb20vNTU1Mzc1Ny80ODk3NTMwNy02MWVmYjEwMC1mMDZkLTExZTgtOTE3Ny1lZTg5NWU1OTE2ZTUucG5nIn3GAlICUwRib2xkBHRydWXGAlQCVQRib2xkBG51bGzGAnsCfAZpdGFsaWMEdHJ1ZcYBJQJ8BWNvbG9yBiIjODg4IsYBJgJ8BGJvbGQEbnVsbMQBJwJ8CjEzMTRweWNhdnXGATECfAZpdGFsaWMEbnVsbMYBMgJ8BWNvbG9yBG51bGzBATMCfAHFADEAMm97ImltYWdlIjoiaHR0cHM6Ly91c2VyLWltYWdlcy5naXRodWJ1c2VyY29udGVudC5jb20vNTU1Mzc1Ny80ODk3NTMwNy02MWVmYjEwMC1mMDZkLTExZTgtOTE3Ny1lZTg5NWU1OTE2ZTUucG5nIn3GADUANgZpdGFsaWMEdHJ1ZcEANwA4AcQAMgAzEzEzMjJybmJhb2tvcml4ZW52cArEAgUCBhcxMzIzbnVjdnhzcWx6bndsZmF2bXBjCsYDDwMQBGJvbGQEdHJ1ZR0AAMQEAwQEDTEyOTVxZnJ2bHlmYXDEAAwEBAFjxAANBAQCanbBAAwADQHEABAADQEywQARAA0ExAAVAA0DZHZmxAAYAA0BYcYCAwIEBml0YWxpYwR0cnVlwQAaAgQCxAAcAgQEMDRrdcYAIAIEBml0YWxpYwRudWxsxQQgBCFveyJpbWFnZSI6Imh0dHBzOi8vdXNlci1pbWFnZXMuZ2l0aHVidXNlcmNvbnRlbnQuY29tLzU1NTM3NTcvNDg5NzUzMDctNjFlZmIxMDAtZjA2ZC0xMWU4LTkxNzctZWU4OTVlNTkxNmU1LnBuZyJ9xQJAABZveyJpbWFnZSI6Imh0dHBzOi8vdXNlci1pbWFnZXMuZ2l0aHVidXNlcmNvbnRlbnQuY29tLzU1NTM3NTcvNDg5NzUzMDctNjFlZmIxMDAtZjA2ZC0xMWU4LTkxNzctZWU4OTVlNTkxNmU1LnBuZyJ9xAQVBBYGMTMxMWtrxAIqAisIMTMxMnFyd3TEADECKwFixAAyAisDcnhxxAA1AisBasQANgIrAXjEADcCKwZkb3ZhbwrEAgAEKwMxMzHEAEAEKwkzYXhoa3RoaHXGAnoCewRib2xkBG51bGzFAEoCe297ImltYWdlIjoiaHR0cHM6Ly91c2VyLWltYWdlcy5naXRodWJ1c2VyY29udGVudC5jb20vNTU1Mzc1Ny80ODk3NTMwNy02MWVmYjEwMC1mMDZkLTExZTgtOTE3Ny1lZTg5NWU1OTE2ZTUucG5nIn3GAEsCewRib2xkBHRydWXEAl8CYBExMzE3cGZjeWhrc3JrcGt0CsQBHwQqCzEzMTliY2Nna3AKxAKSAQKTARUxMzIwY29oYnZjcmtycGpuZ2RvYwoFBAQCAg8CKQE1AQADEAESBBsCAwsGAhIBHgJAAk8CWwJfAmQDcQJ5AaABAQIOBAILAg4CIQIoAjcCPAJEAlgCagJwAXwClwEEngEBAQI0ATcB'
// eslint-disable-next-line
- const oldVal = [{"insert":"1306rup"},{"insert":"uj","attributes":{"italic":true,"color":"#888"}},{"insert":"ikkcjnrcpsckw1319bccgkp\n"},{"insert":"\n1131","attributes":{"bold":true}},{"insert":"1326rpcznqahopcrtd","attributes":{"italic":true}},{"insert":"3axhkthhu","attributes":{"bold":true}},{"insert":"28"},{"insert":[{"image":"https://user-images.githubusercontent.com/5553757/48975307-61efb100-f06d-11e8-9177-ee895e5916e5.png"}]},{"insert":"9"},{"insert":"04ku","attributes":{"italic":true}},{"insert":"1323nucvxsqlznwlfavmpc\nu"},{"insert":"tc","attributes":{"italic":true}},{"insert":"je1318jwskjabdndrdlmjae\n1293tj\nj1292qrmf"},{"insert":[{"image":"https://user-images.githubusercontent.com/5553757/48975307-61efb100-f06d-11e8-9177-ee895e5916e5.png"}]},{"insert":"k\nuf"},{"insert":"14hs","attributes":{"italic":true}},{"insert":"13dccxdyxg"},{"insert":"zc","attributes":{"italic":true,"color":"#888"}},{"insert":"apo"},{"insert":"tn","attributes":{"bold":true}},{"insert":"r"},{"insert":[{"image":"https://user-images.githubusercontent.com/5553757/48975307-61efb100-f06d-11e8-9177-ee895e5916e5.png"}]},{"insert":"gn\n"},{"insert":"z","attributes":{"italic":true}},{"insert":"\n121"},{"insert":[{"image":"https://user-images.githubusercontent.com/5553757/48975307-61efb100-f06d-11e8-9177-ee895e5916e5.png"}]},{"insert":"291311kk9zjznywohpx"},{"insert":[{"image":"https://user-images.githubusercontent.com/5553757/48975307-61efb100-f06d-11e8-9177-ee895e5916e5.png"}]},{"insert":"cnbrcaq\n"},{"insert":"1","attributes":{"italic":true,"color":"#888"}},{"insert":"1310g"},{"insert":"ws","attributes":{"italic":true,"color":"#888"}},{"insert":"hxwych"},{"insert":"kq","attributes":{"italic":true}},{"insert":"sdru1320cohbvcrkrpjngdoc\njqic\n"},{"insert":"2","attributes":{"italic":true,"color":"#888"}},{"insert":[{"image":"https://user-images.githubusercontent.com/5553757/48975307-61efb100-f06d-11e8-9177-ee895e5916e5.png"}]},{"insert":"90n1297zm"},{"insert":"v1309zlgvjx","attributes":{"bold":true}},{"insert":[{"image":"https://user-images.githubusercontent.com/5553757/48975307-61efb100-f06d-11e8-9177-ee895e5916e5.png"}]},{"insert":"g","attributes":{"bold":true}},{"insert":"1314pycavu","attributes":{"italic":true,"color":"#888"}},{"insert":"pkzqcj"},{"insert":"sa","attributes":{"italic":true,"color":"#888"}},{"insert":"sjy\n"},{"insert":[{"image":"https://user-images.githubusercontent.com/5553757/48975307-61efb100-f06d-11e8-9177-ee895e5916e5.png"}]},{"insert":"xr\n"},{"insert":[{"image":"https://user-images.githubusercontent.com/5553757/48975307-61efb100-f06d-11e8-9177-ee895e5916e5.png"}]},{"insert":[{"image":"https://user-images.githubusercontent.com/5553757/48975307-61efb100-f06d-11e8-9177-ee895e5916e5.png"}]},{"insert":[{"image":"https://user-images.githubusercontent.com/5553757/48975307-61efb100-f06d-11e8-9177-ee895e5916e5.png"}]},{"insert":"1"},{"insert":[{"image":"https://user-images.githubusercontent.com/5553757/48975307-61efb100-f06d-11e8-9177-ee895e5916e5.png"}]},{"insert":"1295qfrvlyfap201312qrwt"},{"insert":[{"image":"https://user-images.githubusercontent.com/5553757/48975307-61efb100-f06d-11e8-9177-ee895e5916e5.png"}]},{"insert":"b1322rnbaokorixenvp\nrxq"},{"insert":"j","attributes":{"italic":true}},{"insert":"x","attributes":{"italic":true,"color":"#888"}},{"insert":"15mziwabzkrrmscvdovao\n0","attributes":{"italic":true}},{"insert":"hx","attributes":{"italic":true,"bold":true}},{"insert":"ojeetrjhxkr13031317pfcyhksrkpkt\nuhv1","attributes":{"italic":true}},{"insert":"32","attributes":{"italic":true,"color":"#888"}},{"insert":"4rorywthq1325iodbzizxhmlibvpyrxmq\n\nganln\nqne\n"},{"insert":[{"image":"https://user-images.githubusercontent.com/5553757/48975307-61efb100-f06d-11e8-9177-ee895e5916e5.png"}]},{"insert":"dvf"},{"insert":"ac","attributes":{"bold":true}},{"insert":"1302xciwa"},{"insert":"1305rl","attributes":{"bold":true}},{"insert":"08\n"},{"insert":"eyk","attributes":{"bold":true}},{"insert":"y1321apgivydqsjfsehhezukiqtt1307tvjiejlh"},{"insert":"1316zlpkmctoqomgfthbpg","attributes":{"bold":true}},{"insert":"gv"},{"insert":"lb","attributes":{"bold":true}},{"insert":"f\nhntk\njv1uu\n"},{"insert":[{"image":"https://user-images.githubusercontent.com/5553757/48975307-61efb100-f06d-11e8-9177-ee895e5916e5.png"}]}].map(x => ({ type: 'insert', ...x }))
+ const oldVal = [{"insert":"1306rup"},{"insert":"uj","format":{"italic":true,"color":"#888"}},{"insert":"ikkcjnrcpsckw1319bccgkp\n"},{"insert":"\n1131","format":{"bold":true}},{"insert":"1326rpcznqahopcrtd","format":{"italic":true}},{"insert":"3axhkthhu","format":{"bold":true}},{"insert":"28"},{"insert":[{"image":"https://user-images.githubusercontent.com/5553757/48975307-61efb100-f06d-11e8-9177-ee895e5916e5.png"}]},{"insert":"9"},{"insert":"04ku","format":{"italic":true}},{"insert":"1323nucvxsqlznwlfavmpc\nu"},{"insert":"tc","format":{"italic":true}},{"insert":"je1318jwskjabdndrdlmjae\n1293tj\nj1292qrmf"},{"insert":[{"image":"https://user-images.githubusercontent.com/5553757/48975307-61efb100-f06d-11e8-9177-ee895e5916e5.png"}]},{"insert":"k\nuf"},{"insert":"14hs","format":{"italic":true}},{"insert":"13dccxdyxg"},{"insert":"zc","format":{"italic":true,"color":"#888"}},{"insert":"apo"},{"insert":"tn","format":{"bold":true}},{"insert":"r"},{"insert":[{"image":"https://user-images.githubusercontent.com/5553757/48975307-61efb100-f06d-11e8-9177-ee895e5916e5.png"}]},{"insert":"gn\n"},{"insert":"z","format":{"italic":true}},{"insert":"\n121"},{"insert":[{"image":"https://user-images.githubusercontent.com/5553757/48975307-61efb100-f06d-11e8-9177-ee895e5916e5.png"}]},{"insert":"291311kk9zjznywohpx"},{"insert":[{"image":"https://user-images.githubusercontent.com/5553757/48975307-61efb100-f06d-11e8-9177-ee895e5916e5.png"}]},{"insert":"cnbrcaq\n"},{"insert":"1","format":{"italic":true,"color":"#888"}},{"insert":"1310g"},{"insert":"ws","format":{"italic":true,"color":"#888"}},{"insert":"hxwych"},{"insert":"kq","format":{"italic":true}},{"insert":"sdru1320cohbvcrkrpjngdoc\njqic\n"},{"insert":"2","format":{"italic":true,"color":"#888"}},{"insert":[{"image":"https://user-images.githubusercontent.com/5553757/48975307-61efb100-f06d-11e8-9177-ee895e5916e5.png"}]},{"insert":"90n1297zm"},{"insert":"v1309zlgvjx","format":{"bold":true}},{"insert":[{"image":"https://user-images.githubusercontent.com/5553757/48975307-61efb100-f06d-11e8-9177-ee895e5916e5.png"}]},{"insert":"g","format":{"bold":true}},{"insert":"1314pycavu","format":{"italic":true,"color":"#888"}},{"insert":"pkzqcj"},{"insert":"sa","format":{"italic":true,"color":"#888"}},{"insert":"sjy\n"},{"insert":[{"image":"https://user-images.githubusercontent.com/5553757/48975307-61efb100-f06d-11e8-9177-ee895e5916e5.png"}]},{"insert":"xr\n"},{"insert":[{"image":"https://user-images.githubusercontent.com/5553757/48975307-61efb100-f06d-11e8-9177-ee895e5916e5.png"},{"image":"https://user-images.githubusercontent.com/5553757/48975307-61efb100-f06d-11e8-9177-ee895e5916e5.png"}, {"image":"https://user-images.githubusercontent.com/5553757/48975307-61efb100-f06d-11e8-9177-ee895e5916e5.png"}]},{"insert":"1"},{"insert":[{"image":"https://user-images.githubusercontent.com/5553757/48975307-61efb100-f06d-11e8-9177-ee895e5916e5.png"}]},{"insert":"1295qfrvlyfap201312qrwt"},{"insert":[{"image":"https://user-images.githubusercontent.com/5553757/48975307-61efb100-f06d-11e8-9177-ee895e5916e5.png"}]},{"insert":"b1322rnbaokorixenvp\nrxq"},{"insert":"j","format":{"italic":true}},{"insert":"x","format":{"italic":true,"color":"#888"}},{"insert":"15mziwabzkrrmscvdovao\n0","format":{"italic":true}},{"insert":"hx","format":{"italic":true,"bold":true}},{"insert":"ojeetrjhxkr13031317pfcyhksrkpkt\nuhv1","format":{"italic":true}},{"insert":"32","format":{"italic":true,"color":"#888"}},{"insert":"4rorywthq1325iodbzizxhmlibvpyrxmq\n\nganln\nqne\n"},{"insert":[{"image":"https://user-images.githubusercontent.com/5553757/48975307-61efb100-f06d-11e8-9177-ee895e5916e5.png"}]},{"insert":"dvf"},{"insert":"ac","format":{"bold":true}},{"insert":"1302xciwa"},{"insert":"1305rl","format":{"bold":true}},{"insert":"08\n"},{"insert":"eyk","format":{"bold":true}},{"insert":"y1321apgivydqsjfsehhezukiqtt1307tvjiejlh"},{"insert":"1316zlpkmctoqomgfthbpg","format":{"bold":true}},{"insert":"gv"},{"insert":"lb","format":{"bold":true}},{"insert":"f\nhntk\njv1uu\n"},{"insert":[{"image":"https://user-images.githubusercontent.com/5553757/48975307-61efb100-f06d-11e8-9177-ee895e5916e5.png"}]}].map(x => ({ type: 'insert', ...x }))
const doc = new Y.Doc()
Y.applyUpdate(doc, buffer.fromBase64(oldDoc))
t.compare(doc.getText('text').getContent().toJSON().children, /** @type {any} */ (oldVal))
diff --git a/tests/delta.tests.js b/tests/delta.tests.js
index 252c56bb..7063df3a 100644
--- a/tests/delta.tests.js
+++ b/tests/delta.tests.js
@@ -1,6 +1,7 @@
import * as Y from '../src/index.js'
import * as delta from 'lib0/delta'
import * as t from 'lib0/testing'
+import * as s from 'lib0/schema'
/**
* Delta is a versatyle format enabling you to efficiently describe changes. It is part of lib0, so
@@ -20,7 +21,7 @@ import * as t from 'lib0/testing'
* The "|" describes the current cursor position.
*
* - d.retain(5) - "|hello world" => "hello| world" - jump over the next five characters
- * - d.delete(6) - "hello| world" => "hello|" - delete the next 6 characres
+ * - d.delete(6) - "hello| world" => "hello|" - delete the next 6 characres
* - d.insert('!') - "hello!|" - insert "!" at the current position
* => compact form: d.retain(5).delete(6).insert('!')
*
@@ -44,6 +45,34 @@ export const testDeltaBasics = _tc => {
t.assert(state.equals(delta.create().insert('hello!')))
}
+/**
+ * lib0 also ships a schema library that can be used to validate JSON objects and custom data types,
+ * like Yjs types.
+ *
+ * As a convention, schemas are usually prefixed with a $ sign. This clarifies the difference
+ * between a schema, and an instance of a schema.
+ *
+ * const $myobj = s.$object({ key: s.$number })
+ * let inputValue: any
+ * if ($myobj.check(inputValue)) {
+ * inputValue // is validated and of type $myobj
+ * }
+ *
+ * We can also define the expected values on a delta.
+ *
+ * @param {t.TestCase} _tc
+ */
+export const testDeltaBasicSchema = _tc => {
+ const $d = delta.$delta({ attrs: s.$object({ key: s.$string }), children: s.$number, hasText: false })
+ const d = delta.create($d)
+ // @ts-expect-error
+ d.set('key', false) // invalid change: will throw a type error
+ t.fails(() => {
+ // @ts-expect-error
+ d.apply(delta.create().set('key', false)) // invalid delta: will throw a type error
+ })
+}
+
/**
* Deltas can describe changes on attributes and children. Textual insertions are children. But we
* may also insert json-objects and other deltas as children.
@@ -71,9 +100,9 @@ export const testDeltaValues = _tc => {
} else if (delta.$deleteOp.check(childChange)) {
console.log(`delete ${childChange.delete} child items`)
} else if (delta.$insertOp.check(childChange)) {
- console.log(`insert child items:`, childChange.insert)
+ console.log('insert child items:', childChange.insert)
} else if (delta.$textOp.check(childChange)) {
- console.log(`insert textual content`, childChange.insert)
+ console.log('insert textual content', childChange.insert)
}
}
}
diff --git a/tests/undo-redo.tests.js b/tests/undo-redo.tests.js
index 3304c34c..c40c6985 100644
--- a/tests/undo-redo.tests.js
+++ b/tests/undo-redo.tests.js
@@ -11,7 +11,7 @@ export const testInconsistentFormat = () => {
const content = /** @type {Y.XmlText} */ (ydoc.get('text', Y.XmlText))
content.format(0, 6, { bold: null })
content.format(6, 4, { type: 'text' })
- t.compare(content.getContent(), delta.create().insert('Merge Test', { type: 'text' }).insert(' After', { type: 'text', italic: true }))
+ t.compare(content.getContent(), delta.create().insert('Merge Test', { type: 'text' }).insert(' After', { type: 'text', italic: true }).done())
}
const initializeYDoc = () => {
const yDoc = new Y.Doc({ gc: false })
@@ -298,17 +298,18 @@ export const testUndoXml = tc => {
t.assert(xml0.toString() === 'content
')
// format textchild and revert that change
undoManager.stopCapturing()
- textchild.format(3, 4, { bold: {} })
- t.compare(xml0.getContentDeep(), delta.create('UNDEFINED').insert([delta.text().insert('con').insert('tent', { bold: true }).done()]).done())
- t.assert(xml0.toString() === 'content
')
+ textchild.format(3, 4, { bold: true })
+ const v1 = delta.create('UNDEFINED').insert([delta.create('p').insert([delta.text().insert('con').insert('tent', { bold: true }).done()]).done()]).done()
+ const v2 = delta.create('UNDEFINED').insert([delta.create('p').insert([delta.text().insert('content').done()]).done()]).done()
+ t.compare(xml0.getContentDeep(), v1)
undoManager.undo()
- t.assert(xml0.toString() === 'content
')
+ t.compare(xml0.getContentDeep(), v2)
undoManager.redo()
- t.assert(xml0.toString() === 'content
')
+ t.compare(xml0.getContentDeep(), v1)
xml0.delete(0, 1)
- t.assert(xml0.toString() === '')
+ t.compare(xml0.getContentDeep(), delta.create('UNDEFINED'))
undoManager.undo()
- t.assert(xml0.toString() === 'content
')
+ t.compare(xml0.getContentDeep(), v1)
}
/**
diff --git a/tests/y-text.tests.js b/tests/y-text.tests.js
index f846991e..b84d67e8 100644
--- a/tests/y-text.tests.js
+++ b/tests/y-text.tests.js
@@ -1439,18 +1439,18 @@ export const testTypesAsEmbed = tc => {
text0.applyDelta(delta.create()
.insert([new Y.Map([['key', 'val']])])
)
- t.compare(/** @type {any} */ (text0).getContentDeep().toJSON().children, [{ type: 'insert', insert: [{ attrs: { key: { type: 'insert', value: 'val' } } }] }])
+ t.compare(/** @type {any} */ (text0).getContentDeep().toJSON().children, [{ type: 'insert', insert: [{ type: 'delta', attrs: { key: { type: 'insert', value: 'val' } } }] }])
let firedEvent = false
text1.observe(event => {
const d = event.deltaDeep
t.assert(d.children.len === 1)
- t.compare(d.toJSON().children?.map(x => /** @type {any} */ (x).insert), [[{ key: { type: 'insert', value: 'val' } }]])
+ t.compare(d.toJSON().children?.map(x => /** @type {any} */ (x).insert), [[{ type: 'delta', attrs: { key: { type: 'insert', value: 'val' } } }]])
firedEvent = true
})
testConnector.flushAllMessages()
- const dd = text1.getContent().toJSON().children
+ const dd = text1.getContentDeep().toJSON().children
t.assert(dd?.length === 1)
- t.compare(/** @type {any} */ (dd?.[0]).insert, { key: 'val' })
+ t.compare(/** @type {any} */ (dd?.[0]).insert[0], { type: 'delta', attrs: { key: { type: 'insert', value: 'val' } } })
t.assert(firedEvent, 'fired the event observer containing a Type-Embed')
}
diff --git a/tests/y-xml.tests.js b/tests/y-xml.tests.js
index 038f77bc..41e982a3 100644
--- a/tests/y-xml.tests.js
+++ b/tests/y-xml.tests.js
@@ -59,46 +59,6 @@ export const testHasProperty = tc => {
compare(users)
}
-/**
- * @param {t.TestCase} tc
- */
-export const testEvents = tc => {
- const { testConnector, users, xml0, xml1 } = init(tc, { users: 2 })
- /**
- * @type {any}
- */
- let event
- /**
- * @type {any}
- */
- let remoteEvent
- xml0.observe(e => {
- event = e
- })
- xml1.observe(e => {
- remoteEvent = e
- })
- xml0.setAttribute('key', 'value')
- t.assert(event.attributesChanged.has('key'), 'YXmlEvent.attributesChanged on updated key')
- testConnector.flushAllMessages()
- t.assert(remoteEvent.attributesChanged.has('key'), 'YXmlEvent.attributesChanged on updated key (remote)')
- // check attributeRemoved
- xml0.removeAttribute('key')
- t.assert(event.attributesChanged.has('key'), 'YXmlEvent.attributesChanged on removed attribute')
- testConnector.flushAllMessages()
- t.assert(remoteEvent.attributesChanged.has('key'), 'YXmlEvent.attributesChanged on removed attribute (remote)')
- xml0.insert(0, [new Y.XmlText('some text')])
- t.assert(event.childListChanged, 'YXmlEvent.childListChanged on inserted element')
- testConnector.flushAllMessages()
- t.assert(remoteEvent.childListChanged, 'YXmlEvent.childListChanged on inserted element (remote)')
- // test childRemoved
- xml0.delete(0)
- t.assert(event.childListChanged, 'YXmlEvent.childListChanged on deleted element')
- testConnector.flushAllMessages()
- t.assert(remoteEvent.childListChanged, 'YXmlEvent.childListChanged on deleted element (remote)')
- compare(users)
-}
-
/**
* @param {t.TestCase} _tc
*/
@@ -252,28 +212,31 @@ export const testElementAttributedContent = _tc => {
yelement.insert(1, [elem3])
yelement.setAttribute('key', '42')
})
- const expectedContent = delta.create().insert([elem1], null, { delete: [] }).insert([elem2]).insert([elem3], null, { insert: [] })
+ const expectedContent = delta.create('UNDEFINED').insert([elem1], null, { delete: [] }).insert([elem2]).insert([elem3], null, { insert: [] }).set('key', '42', { insert: [] })
const attributedContent = yelement.getContent(attributionManager)
console.log('children', attributedContent.toJSON())
console.log('attributes', attributedContent)
t.assert(attributedContent.equals(expectedContent))
- t.compare(attributedContent.toJSON().attrs, { key: { type: 'insert', prevValue: undefined, value: '42', attribution: { insert: [] } } })
+ t.compare(attributedContent.toJSON().attrs, { key: { type: 'insert', value: '42', attribution: { insert: [] } } })
t.group('test getContentDeep', () => {
- const expectedContent = delta.create().insert(
- [delta.text().insert('hello', null, { delete: [] })],
- null,
- { delete: [] }
- ).insert([delta.create('span')])
+ const expectedContent = delta.create('UNDEFINED')
+ .insert(
+ [delta.text().insert('hello', null, { delete: [] })],
+ null,
+ { delete: [] }
+ )
+ .insert([delta.create('span')])
.insert([
delta.text().insert('world', null, { insert: [] })
], null, { insert: [] })
+ .set('key', '42', { insert: [] })
+ .done()
const attributedContent = yelement.getContentDeep(attributionManager)
console.log('children', JSON.stringify(attributedContent.toJSON().children, null, 2))
console.log('cs expec', JSON.stringify(expectedContent.toJSON(), null, 2))
console.log('attributes', attributedContent.toJSON().attrs)
t.assert(attributedContent.equals(expectedContent))
- t.compare(attributedContent, delta.map().set('key', '42', { insert: [] }))
- t.compare(attributedContent.toJSON().attrs, { key: { type: 'insert', prevValue: undefined, value: '42', attribution: { insert: [] } } })
+ t.compare(attributedContent.toJSON().attrs, { key: { type: 'insert', value: '42', attribution: { insert: [] } } })
t.assert(attributedContent.name === 'UNDEFINED')
})
})
@@ -296,28 +259,31 @@ export const testElementAttributedContentViaDiffer = _tc => {
yelement.setAttribute('key', '42')
})
const attributionManager = Y.createAttributionManagerFromDiff(ydocV1, ydoc)
- const expectedContent = delta.create().insert([delta.create().insert('hello')], null, { delete: [] }).insert([elem2.getContentDeep()]).insert([delta.create().insert('world', null, { insert: [] })], null, { insert: [] })
+ const expectedContent = delta.create('UNDEFINED').insert([delta.create().insert('hello')], null, { delete: [] }).insert([elem2.getContentDeep()]).insert([delta.create().insert('world', null, { insert: [] })], null, { insert: [] }).set('key', '42', { insert: [] })
const attributedContent = yelement.getContentDeep(attributionManager)
console.log('children', attributedContent.toJSON().children)
console.log('attributes', attributedContent.toJSON().attrs)
t.compare(attributedContent.toJSON(), expectedContent.toJSON())
t.assert(attributedContent.equals(expectedContent))
- t.compare(attributedContent.toJSON().attrs, { key: { type: 'insert', prevValue: undefined, value: '42', attribution: { insert: [] } } })
+ t.compare(attributedContent.toJSON().attrs, { key: { type: 'insert', value: '42', attribution: { insert: [] } } })
t.group('test getContentDeep', () => {
- const expectedContent = delta.create().insert(
- [delta.create().insert('hello')],
- null,
- { delete: [] }
- ).insert([delta.create('span')])
+ const expectedContent = delta.create('UNDEFINED')
+ .insert(
+ [delta.create().insert('hello')],
+ null,
+ { delete: [] }
+ )
+ .insert([delta.create('span')])
.insert([
delta.create().insert('world', null, { insert: [] })
], null, { insert: [] })
+ .set('key', '42', { insert: [] })
const attributedContent = yelement.getContentDeep(attributionManager)
console.log('children', JSON.stringify(attributedContent.toJSON().children, null, 2))
console.log('cs expec', JSON.stringify(expectedContent.toJSON(), null, 2))
console.log('attributes', attributedContent.toJSON().attrs)
t.assert(attributedContent.equals(expectedContent))
- t.compare(attributedContent.toJSON().attrs, { key: { type: 'insert', prevValue: undefined, value: '42', attribution: { insert: [] } } })
+ t.compare(attributedContent.toJSON().attrs, { key: { type: 'insert', value: '42', attribution: { insert: [] } } })
t.assert(attributedContent.name === 'UNDEFINED')
})
ydoc.transact(() => {
@@ -325,34 +291,37 @@ export const testElementAttributedContentViaDiffer = _tc => {
})
t.group('test getContentDeep after some more updates', () => {
t.info('expecting diffingAttributionManager to auto update itself')
- const expectedContent = delta.create().insert(
- [delta.create().insert('hello')],
- null,
- { delete: [] }
- ).insert([delta.create('span')])
+ const expectedContent = delta.create('UNDEFINED')
+ .insert(
+ [delta.create().insert('hello')],
+ null,
+ { delete: [] }
+ )
+ .insert([delta.create('span')])
.insert([
delta.create().insert('bigworld', null, { insert: [] })
], null, { insert: [] })
+ .set('key', '42', { insert: [] })
const attributedContent = yelement.getContentDeep(attributionManager)
console.log('children', JSON.stringify(attributedContent.toJSON().children, null, 2))
console.log('cs expec', JSON.stringify(expectedContent.toJSON(), null, 2))
console.log('attributes', attributedContent.toJSON().attrs)
t.assert(attributedContent.equals(expectedContent))
- t.compare(attributedContent.toJSON().attrs, { key: { type: 'insert', prevValue: undefined, value: '42', attribution: { insert: [] } } })
+ t.compare(attributedContent.toJSON().attrs, { key: { type: 'insert', value: '42', attribution: { insert: [] } } })
t.assert(attributedContent.name === 'UNDEFINED')
})
Y.applyUpdate(ydocV1, Y.encodeStateAsUpdate(ydoc))
t.group('test getContentDeep both docs synced', () => {
t.info('expecting diffingAttributionManager to auto update itself')
- const expectedContent = delta.create().insert([delta.create('span')]).insert([
+ const expectedContent = delta.create('UNDEFINED').insert([delta.create('span')]).insert([
delta.create().insert('bigworld')
- ])
+ ]).set('key', '42')
const attributedContent = yelement.getContentDeep(attributionManager)
console.log('children', JSON.stringify(attributedContent.toJSON().children, null, 2))
console.log('cs expec', JSON.stringify(expectedContent.toJSON(), null, 2))
console.log('attributes', attributedContent.toJSON().attrs)
t.assert(attributedContent.equals(expectedContent))
- t.compare(attributedContent.toJSON().attrs, { key: { type: 'insert', prevValue: undefined, value: '42' } })
+ t.compare(attributedContent.toJSON().attrs, { key: { type: 'insert', value: '42' } })
t.assert(attributedContent.name === 'UNDEFINED')
})
}