Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2e9a648d08 | ||
|
|
83712cb1a6 | ||
|
|
30b56d5ae9 | ||
|
|
adaa95ebb8 |
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "yjs",
|
"name": "yjs",
|
||||||
"version": "13.6.0",
|
"version": "13.6.1",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "yjs",
|
"name": "yjs",
|
||||||
"version": "13.6.0",
|
"version": "13.6.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"lib0": "^0.2.74"
|
"lib0": "^0.2.74"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "yjs",
|
"name": "yjs",
|
||||||
"version": "13.6.0",
|
"version": "13.6.1",
|
||||||
"description": "Shared Editing Library",
|
"description": "Shared Editing Library",
|
||||||
"main": "./dist/yjs.cjs",
|
"main": "./dist/yjs.cjs",
|
||||||
"module": "./dist/yjs.mjs",
|
"module": "./dist/yjs.mjs",
|
||||||
|
|||||||
@@ -206,9 +206,11 @@ export class YMap extends AbstractType {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds or updates an element with a specified key and value.
|
* Adds or updates an element with a specified key and value.
|
||||||
|
* @template {MapType} VAL
|
||||||
*
|
*
|
||||||
* @param {string} key The key of the element to add to this YMap
|
* @param {string} key The key of the element to add to this YMap
|
||||||
* @param {MapType} value The value of the element to add
|
* @param {VAL} value The value of the element to add
|
||||||
|
* @return {VAL}
|
||||||
*/
|
*/
|
||||||
set (key, value) {
|
set (key, value) {
|
||||||
if (this.doc !== null) {
|
if (this.doc !== null) {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import * as object from 'lib0/object'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
YXmlFragment,
|
YXmlFragment,
|
||||||
@@ -12,12 +13,18 @@ import {
|
|||||||
YXmlText, ContentType, AbstractType, UpdateDecoderV1, UpdateDecoderV2, UpdateEncoderV1, UpdateEncoderV2, Doc, Item // eslint-disable-line
|
YXmlText, ContentType, AbstractType, UpdateDecoderV1, UpdateDecoderV2, UpdateEncoderV1, UpdateEncoderV2, Doc, Item // eslint-disable-line
|
||||||
} from '../internals.js'
|
} from '../internals.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object|number|null|Array<any>|string|Uint8Array|AbstractType<any>} ValueTypes
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An YXmlElement imitates the behavior of a
|
* An YXmlElement imitates the behavior of a
|
||||||
* {@link https://developer.mozilla.org/en-US/docs/Web/API/Element|Dom Element}.
|
* {@link https://developer.mozilla.org/en-US/docs/Web/API/Element|Dom Element}.
|
||||||
*
|
*
|
||||||
* * An YXmlElement has attributes (key value pairs)
|
* * An YXmlElement has attributes (key value pairs)
|
||||||
* * An YXmlElement has childElements that must inherit from YXmlElement
|
* * An YXmlElement has childElements that must inherit from YXmlElement
|
||||||
|
*
|
||||||
|
* @template {{ [key: string]: ValueTypes }} [KV={ [key: string]: string }]
|
||||||
*/
|
*/
|
||||||
export class YXmlElement extends YXmlFragment {
|
export class YXmlElement extends YXmlFragment {
|
||||||
constructor (nodeName = 'UNDEFINED') {
|
constructor (nodeName = 'UNDEFINED') {
|
||||||
@@ -73,14 +80,19 @@ export class YXmlElement extends YXmlFragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {YXmlElement}
|
* @return {YXmlElement<KV>}
|
||||||
*/
|
*/
|
||||||
clone () {
|
clone () {
|
||||||
|
/**
|
||||||
|
* @type {YXmlElement<KV>}
|
||||||
|
*/
|
||||||
const el = new YXmlElement(this.nodeName)
|
const el = new YXmlElement(this.nodeName)
|
||||||
const attrs = this.getAttributes()
|
const attrs = this.getAttributes()
|
||||||
for (const key in attrs) {
|
object.forEach(attrs, (value, key) => {
|
||||||
el.setAttribute(key, attrs[key])
|
if (typeof value === 'string') {
|
||||||
}
|
el.setAttribute(key, value)
|
||||||
|
}
|
||||||
|
})
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
el.insert(0, this.toArray().map(item => item instanceof AbstractType ? item.clone() : item))
|
el.insert(0, this.toArray().map(item => item instanceof AbstractType ? item.clone() : item))
|
||||||
return el
|
return el
|
||||||
@@ -116,7 +128,7 @@ export class YXmlElement extends YXmlFragment {
|
|||||||
/**
|
/**
|
||||||
* Removes an attribute from this YXmlElement.
|
* Removes an attribute from this YXmlElement.
|
||||||
*
|
*
|
||||||
* @param {String} attributeName The attribute name that is to be removed.
|
* @param {string} attributeName The attribute name that is to be removed.
|
||||||
*
|
*
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
@@ -133,8 +145,10 @@ export class YXmlElement extends YXmlFragment {
|
|||||||
/**
|
/**
|
||||||
* Sets or updates an attribute.
|
* Sets or updates an attribute.
|
||||||
*
|
*
|
||||||
* @param {String} attributeName The attribute name that is to be set.
|
* @template {keyof KV & string} KEY
|
||||||
* @param {String} attributeValue The attribute value that is to be set.
|
*
|
||||||
|
* @param {KEY} attributeName The attribute name that is to be set.
|
||||||
|
* @param {KV[KEY]} attributeValue The attribute value that is to be set.
|
||||||
*
|
*
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
@@ -151,9 +165,11 @@ export class YXmlElement extends YXmlFragment {
|
|||||||
/**
|
/**
|
||||||
* Returns an attribute value that belongs to the attribute name.
|
* Returns an attribute value that belongs to the attribute name.
|
||||||
*
|
*
|
||||||
* @param {String} attributeName The attribute name that identifies the
|
* @template {keyof KV & string} KEY
|
||||||
|
*
|
||||||
|
* @param {KEY} attributeName The attribute name that identifies the
|
||||||
* queried value.
|
* queried value.
|
||||||
* @return {String} The queried attribute value.
|
* @return {KV[KEY]|undefined} The queried attribute value.
|
||||||
*
|
*
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
@@ -164,7 +180,7 @@ export class YXmlElement extends YXmlFragment {
|
|||||||
/**
|
/**
|
||||||
* Returns whether an attribute exists
|
* Returns whether an attribute exists
|
||||||
*
|
*
|
||||||
* @param {String} attributeName The attribute name to check for existence.
|
* @param {string} attributeName The attribute name to check for existence.
|
||||||
* @return {boolean} whether the attribute exists.
|
* @return {boolean} whether the attribute exists.
|
||||||
*
|
*
|
||||||
* @public
|
* @public
|
||||||
@@ -176,12 +192,12 @@ export class YXmlElement extends YXmlFragment {
|
|||||||
/**
|
/**
|
||||||
* Returns all attribute name/value pairs in a JSON Object.
|
* Returns all attribute name/value pairs in a JSON Object.
|
||||||
*
|
*
|
||||||
* @return {Object<string, any>} A JSON Object that describes the attributes.
|
* @return {{ [Key in Extract<keyof KV,string>]?: KV[Key]}} A JSON Object that describes the attributes.
|
||||||
*
|
*
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
getAttributes () {
|
getAttributes () {
|
||||||
return typeMapGetAll(this)
|
return /** @type {any} */ (typeMapGetAll(this))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -203,7 +219,10 @@ export class YXmlElement extends YXmlFragment {
|
|||||||
const dom = _document.createElement(this.nodeName)
|
const dom = _document.createElement(this.nodeName)
|
||||||
const attrs = this.getAttributes()
|
const attrs = this.getAttributes()
|
||||||
for (const key in attrs) {
|
for (const key in attrs) {
|
||||||
dom.setAttribute(key, attrs[key])
|
const value = attrs[key]
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
dom.setAttribute(key, value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
typeListForEach(this, yxml => {
|
typeListForEach(this, yxml => {
|
||||||
dom.appendChild(yxml.toDOM(_document, hooks, binding))
|
dom.appendChild(yxml.toDOM(_document, hooks, binding))
|
||||||
|
|||||||
@@ -153,6 +153,14 @@ export const splitSnapshotAffectedStructs = (transaction, snapshot) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @example
|
||||||
|
* const ydoc = new Y.Doc({ gc: false })
|
||||||
|
* ydoc.getText().insert(0, 'world!')
|
||||||
|
* const snapshot = Y.snapshot(ydoc)
|
||||||
|
* ydoc.getText().insert(0, 'hello ')
|
||||||
|
* const restored = Y.createDocFromSnapshot(ydoc, snapshot)
|
||||||
|
* assert(restored.getText().toString() === 'world!')
|
||||||
|
*
|
||||||
* @param {Doc} originDoc
|
* @param {Doc} originDoc
|
||||||
* @param {Snapshot} snapshot
|
* @param {Snapshot} snapshot
|
||||||
* @param {Doc} [newDoc] Optionally, you may define the Yjs document that receives the data from originDoc
|
* @param {Doc} [newDoc] Optionally, you may define the Yjs document that receives the data from originDoc
|
||||||
@@ -161,7 +169,7 @@ export const splitSnapshotAffectedStructs = (transaction, snapshot) => {
|
|||||||
export const createDocFromSnapshot = (originDoc, snapshot, newDoc = new Doc()) => {
|
export const createDocFromSnapshot = (originDoc, snapshot, newDoc = new Doc()) => {
|
||||||
if (originDoc.gc) {
|
if (originDoc.gc) {
|
||||||
// we should not try to restore a GC-ed document, because some of the restored items might have their content deleted
|
// we should not try to restore a GC-ed document, because some of the restored items might have their content deleted
|
||||||
throw new Error('originDoc must not be garbage collected')
|
throw new Error('Garbage-collection must be disabled in `originDoc`!')
|
||||||
}
|
}
|
||||||
const { sv, ds } = snapshot
|
const { sv, ds } = snapshot
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,18 @@ import * as Y from '../src/index.js'
|
|||||||
import * as t from 'lib0/testing'
|
import * as t from 'lib0/testing'
|
||||||
import { init } from './testHelper.js'
|
import { init } from './testHelper.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {t.TestCase} tc
|
||||||
|
*/
|
||||||
|
export const testBasic = tc => {
|
||||||
|
const ydoc = new Y.Doc({ gc: false })
|
||||||
|
ydoc.getText().insert(0, 'world!')
|
||||||
|
const snapshot = Y.snapshot(ydoc)
|
||||||
|
ydoc.getText().insert(0, 'hello ')
|
||||||
|
const restored = Y.createDocFromSnapshot(ydoc, snapshot)
|
||||||
|
t.assert(restored.getText().toString() === 'world!')
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {t.TestCase} tc
|
* @param {t.TestCase} tc
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -3,6 +3,33 @@ import * as Y from '../src/index.js'
|
|||||||
|
|
||||||
import * as t from 'lib0/testing'
|
import * as t from 'lib0/testing'
|
||||||
|
|
||||||
|
export const testCustomTypings = () => {
|
||||||
|
const ydoc = new Y.Doc()
|
||||||
|
const ymap = ydoc.getMap()
|
||||||
|
/**
|
||||||
|
* @type {Y.XmlElement<{ num: number, str: string, [k:string]: object|number|string }>}
|
||||||
|
*/
|
||||||
|
const yxml = ymap.set('yxml', new Y.XmlElement('test'))
|
||||||
|
/**
|
||||||
|
* @type {number|undefined}
|
||||||
|
*/
|
||||||
|
const num = yxml.getAttribute('num')
|
||||||
|
/**
|
||||||
|
* @type {string|undefined}
|
||||||
|
*/
|
||||||
|
const str = yxml.getAttribute('str')
|
||||||
|
/**
|
||||||
|
* @type {object|number|string|undefined}
|
||||||
|
*/
|
||||||
|
const dtrn = yxml.getAttribute('dtrn')
|
||||||
|
const attrs = yxml.getAttributes()
|
||||||
|
/**
|
||||||
|
* @type {object|number|string|undefined}
|
||||||
|
*/
|
||||||
|
const any = attrs.shouldBeAny
|
||||||
|
console.log({ num, str, dtrn, attrs, any })
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {t.TestCase} tc
|
* @param {t.TestCase} tc
|
||||||
*/
|
*/
|
||||||
@@ -92,9 +119,9 @@ export const testTreewalker = tc => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {t.TestCase} tc
|
* @param {t.TestCase} _tc
|
||||||
*/
|
*/
|
||||||
export const testYtextAttributes = tc => {
|
export const testYtextAttributes = _tc => {
|
||||||
const ydoc = new Y.Doc()
|
const ydoc = new Y.Doc()
|
||||||
const ytext = /** @type {Y.XmlText} */ (ydoc.get('', Y.XmlText))
|
const ytext = /** @type {Y.XmlText} */ (ydoc.get('', Y.XmlText))
|
||||||
ytext.observe(event => {
|
ytext.observe(event => {
|
||||||
@@ -106,9 +133,9 @@ export const testYtextAttributes = tc => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {t.TestCase} tc
|
* @param {t.TestCase} _tc
|
||||||
*/
|
*/
|
||||||
export const testSiblings = tc => {
|
export const testSiblings = _tc => {
|
||||||
const ydoc = new Y.Doc()
|
const ydoc = new Y.Doc()
|
||||||
const yxml = ydoc.getXmlFragment()
|
const yxml = ydoc.getXmlFragment()
|
||||||
const first = new Y.XmlText()
|
const first = new Y.XmlText()
|
||||||
@@ -122,9 +149,9 @@ export const testSiblings = tc => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {t.TestCase} tc
|
* @param {t.TestCase} _tc
|
||||||
*/
|
*/
|
||||||
export const testInsertafter = tc => {
|
export const testInsertafter = _tc => {
|
||||||
const ydoc = new Y.Doc()
|
const ydoc = new Y.Doc()
|
||||||
const yxml = ydoc.getXmlFragment()
|
const yxml = ydoc.getXmlFragment()
|
||||||
const first = new Y.XmlText()
|
const first = new Y.XmlText()
|
||||||
@@ -152,9 +179,9 @@ export const testInsertafter = tc => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {t.TestCase} tc
|
* @param {t.TestCase} _tc
|
||||||
*/
|
*/
|
||||||
export const testClone = tc => {
|
export const testClone = _tc => {
|
||||||
const ydoc = new Y.Doc()
|
const ydoc = new Y.Doc()
|
||||||
const yxml = ydoc.getXmlFragment()
|
const yxml = ydoc.getXmlFragment()
|
||||||
const first = new Y.XmlText('text')
|
const first = new Y.XmlText('text')
|
||||||
@@ -170,9 +197,9 @@ export const testClone = tc => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {t.TestCase} tc
|
* @param {t.TestCase} _tc
|
||||||
*/
|
*/
|
||||||
export const testFormattingBug = tc => {
|
export const testFormattingBug = _tc => {
|
||||||
const ydoc = new Y.Doc()
|
const ydoc = new Y.Doc()
|
||||||
const yxml = /** @type {Y.XmlText} */ (ydoc.get('', Y.XmlText))
|
const yxml = /** @type {Y.XmlText} */ (ydoc.get('', Y.XmlText))
|
||||||
const delta = [
|
const delta = [
|
||||||
|
|||||||
Reference in New Issue
Block a user