@loro-extended/change 0.9.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +9 -4
- package/dist/index.js +215 -187
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/conversion.test.ts +72 -72
- package/src/conversion.ts +5 -5
- package/src/overlay-recursion.test.ts +325 -0
- package/src/overlay.ts +45 -8
- package/src/typed-refs/base.ts +10 -0
- package/src/typed-refs/counter.ts +2 -2
- package/src/typed-refs/doc.ts +17 -24
- package/src/typed-refs/list-base.ts +42 -18
- package/src/typed-refs/map.ts +38 -65
- package/src/typed-refs/movable-list.ts +2 -2
- package/src/typed-refs/record.test.ts +9 -9
- package/src/typed-refs/record.ts +56 -69
- package/src/typed-refs/text.ts +6 -6
- package/src/typed-refs/tree.ts +3 -3
- package/src/typed-refs/utils.ts +93 -8
package/src/typed-refs/map.ts
CHANGED
|
@@ -1,13 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
LoroCounter,
|
|
4
|
-
LoroList,
|
|
5
|
-
LoroMap,
|
|
6
|
-
LoroMovableList,
|
|
7
|
-
LoroText,
|
|
8
|
-
LoroTree,
|
|
9
|
-
type Value,
|
|
10
|
-
} from "loro-crdt"
|
|
1
|
+
import type { Container, LoroMap, Value } from "loro-crdt"
|
|
2
|
+
import { mergeValue } from "../overlay.js"
|
|
11
3
|
import type {
|
|
12
4
|
ContainerOrValueShape,
|
|
13
5
|
ContainerShape,
|
|
@@ -16,17 +8,14 @@ import type {
|
|
|
16
8
|
} from "../shape.js"
|
|
17
9
|
import { isContainerShape, isValueShape } from "../utils/type-guards.js"
|
|
18
10
|
import { TypedRef, type TypedRefParams } from "./base.js"
|
|
19
|
-
import {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
text: LoroText,
|
|
28
|
-
tree: LoroTree,
|
|
29
|
-
} as const
|
|
11
|
+
import {
|
|
12
|
+
absorbCachedPlainValues,
|
|
13
|
+
assignPlainValueToTypedRef,
|
|
14
|
+
containerConstructor,
|
|
15
|
+
createContainerTypedRef,
|
|
16
|
+
serializeRefToJSON,
|
|
17
|
+
unwrapReadonlyPrimitive,
|
|
18
|
+
} from "./utils.js"
|
|
30
19
|
|
|
31
20
|
// Map typed ref
|
|
32
21
|
export class MapRef<
|
|
@@ -48,16 +37,7 @@ export class MapRef<
|
|
|
48
37
|
}
|
|
49
38
|
|
|
50
39
|
absorbPlainValues() {
|
|
51
|
-
|
|
52
|
-
if (node instanceof TypedRef) {
|
|
53
|
-
// Contains a TypedRef, not a plain Value: keep recursing
|
|
54
|
-
node.absorbPlainValues()
|
|
55
|
-
continue
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Plain value!
|
|
59
|
-
this.container.set(key, node)
|
|
60
|
-
}
|
|
40
|
+
absorbCachedPlainValues(this.propertyCache, () => this.container)
|
|
61
41
|
}
|
|
62
42
|
|
|
63
43
|
getTypedRefParams<S extends ContainerShape>(
|
|
@@ -77,37 +57,37 @@ export class MapRef<
|
|
|
77
57
|
}
|
|
78
58
|
}
|
|
79
59
|
|
|
80
|
-
|
|
60
|
+
getOrCreateRef<Shape extends ContainerShape | ValueShape>(
|
|
81
61
|
key: string,
|
|
82
62
|
shape: Shape,
|
|
83
63
|
): any {
|
|
84
|
-
let
|
|
85
|
-
if (!
|
|
64
|
+
let ref = this.propertyCache.get(key)
|
|
65
|
+
if (!ref) {
|
|
86
66
|
if (isContainerShape(shape)) {
|
|
87
|
-
|
|
88
|
-
// We cache container
|
|
89
|
-
this.propertyCache.set(key,
|
|
67
|
+
ref = createContainerTypedRef(this.getTypedRefParams(key, shape))
|
|
68
|
+
// We cache container refs even in readonly mode because they are just handles
|
|
69
|
+
this.propertyCache.set(key, ref)
|
|
90
70
|
} else {
|
|
91
71
|
// For value shapes, first try to get the value from the container
|
|
92
72
|
const containerValue = this.container.get(key)
|
|
93
73
|
if (containerValue !== undefined) {
|
|
94
|
-
|
|
74
|
+
ref = containerValue as Value
|
|
95
75
|
} else {
|
|
96
76
|
// Only fall back to placeholder if the container doesn't have the value
|
|
97
77
|
const placeholder = (this.placeholder as any)?.[key]
|
|
98
78
|
if (placeholder === undefined) {
|
|
99
79
|
throw new Error("placeholder required")
|
|
100
80
|
}
|
|
101
|
-
|
|
81
|
+
ref = placeholder as Value
|
|
102
82
|
}
|
|
103
83
|
|
|
104
84
|
// In readonly mode, we DO NOT cache primitive values.
|
|
105
85
|
// This ensures we always get the latest value from the CRDT on next access.
|
|
106
86
|
if (!this.readonly) {
|
|
107
|
-
this.propertyCache.set(key,
|
|
87
|
+
this.propertyCache.set(key, ref)
|
|
108
88
|
}
|
|
109
89
|
}
|
|
110
|
-
if (
|
|
90
|
+
if (ref === undefined) throw new Error("no container made")
|
|
111
91
|
}
|
|
112
92
|
|
|
113
93
|
if (this.readonly && isContainerShape(shape)) {
|
|
@@ -118,32 +98,27 @@ export class MapRef<
|
|
|
118
98
|
return (this.placeholder as any)?.[key]
|
|
119
99
|
}
|
|
120
100
|
|
|
121
|
-
|
|
122
|
-
return (node as any).value
|
|
123
|
-
}
|
|
124
|
-
if (shape._type === "text") {
|
|
125
|
-
return (node as any).toString()
|
|
126
|
-
}
|
|
101
|
+
return unwrapReadonlyPrimitive(ref as TypedRef<any>, shape)
|
|
127
102
|
}
|
|
128
103
|
|
|
129
|
-
return
|
|
104
|
+
return ref as Shape extends ContainerShape ? TypedRef<Shape> : Value
|
|
130
105
|
}
|
|
131
106
|
|
|
132
107
|
private createLazyProperties(): void {
|
|
133
108
|
for (const key in this.shape.shapes) {
|
|
134
109
|
const shape = this.shape.shapes[key]
|
|
135
110
|
Object.defineProperty(this, key, {
|
|
136
|
-
get: () => this.
|
|
111
|
+
get: () => this.getOrCreateRef(key, shape),
|
|
137
112
|
set: value => {
|
|
138
|
-
|
|
113
|
+
this.assertMutable()
|
|
139
114
|
if (isValueShape(shape)) {
|
|
140
115
|
this.container.set(key, value)
|
|
141
116
|
this.propertyCache.set(key, value)
|
|
142
117
|
} else {
|
|
143
118
|
if (value && typeof value === "object") {
|
|
144
|
-
const
|
|
119
|
+
const ref = this.getOrCreateRef(key, shape)
|
|
145
120
|
|
|
146
|
-
if (assignPlainValueToTypedRef(
|
|
121
|
+
if (assignPlainValueToTypedRef(ref as TypedRef<any>, value)) {
|
|
147
122
|
return
|
|
148
123
|
}
|
|
149
124
|
}
|
|
@@ -158,35 +133,33 @@ export class MapRef<
|
|
|
158
133
|
}
|
|
159
134
|
|
|
160
135
|
toJSON(): any {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
} else {
|
|
167
|
-
result[key] = value
|
|
168
|
-
}
|
|
136
|
+
// Fast path: readonly mode
|
|
137
|
+
if (this.readonly) {
|
|
138
|
+
const nativeJson = this.container.toJSON() as Value
|
|
139
|
+
// Overlay placeholders for missing properties
|
|
140
|
+
return mergeValue(this.shape, nativeJson, this.placeholder as Value)
|
|
169
141
|
}
|
|
170
|
-
|
|
142
|
+
|
|
143
|
+
return serializeRefToJSON(this as any, Object.keys(this.shape.shapes))
|
|
171
144
|
}
|
|
172
145
|
|
|
173
|
-
//
|
|
146
|
+
// TODO(duane): return correct type here
|
|
174
147
|
get(key: string): any {
|
|
175
148
|
return this.container.get(key)
|
|
176
149
|
}
|
|
177
150
|
|
|
178
151
|
set(key: string, value: Value): void {
|
|
179
|
-
|
|
152
|
+
this.assertMutable()
|
|
180
153
|
this.container.set(key, value)
|
|
181
154
|
}
|
|
182
155
|
|
|
183
156
|
setContainer<C extends Container>(key: string, container: C): C {
|
|
184
|
-
|
|
157
|
+
this.assertMutable()
|
|
185
158
|
return this.container.setContainer(key, container)
|
|
186
159
|
}
|
|
187
160
|
|
|
188
161
|
delete(key: string): void {
|
|
189
|
-
|
|
162
|
+
this.assertMutable()
|
|
190
163
|
this.container.delete(key)
|
|
191
164
|
}
|
|
192
165
|
|
|
@@ -20,12 +20,12 @@ export class MovableListRef<
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
move(from: number, to: number): void {
|
|
23
|
-
|
|
23
|
+
this.assertMutable()
|
|
24
24
|
this.container.move(from, to)
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
set(index: number, item: Exclude<Item, Container>) {
|
|
28
|
-
|
|
28
|
+
this.assertMutable()
|
|
29
29
|
return this.container.set(index, item)
|
|
30
30
|
}
|
|
31
31
|
}
|
|
@@ -11,8 +11,8 @@ describe("Record Types", () => {
|
|
|
11
11
|
const doc = new TypedDoc(schema)
|
|
12
12
|
|
|
13
13
|
doc.change(draft => {
|
|
14
|
-
draft.scores.
|
|
15
|
-
draft.scores.
|
|
14
|
+
draft.scores.getOrCreateRef("alice").increment(10)
|
|
15
|
+
draft.scores.getOrCreateRef("bob").increment(5)
|
|
16
16
|
})
|
|
17
17
|
|
|
18
18
|
expect(doc.toJSON().scores).toEqual({
|
|
@@ -21,7 +21,7 @@ describe("Record Types", () => {
|
|
|
21
21
|
})
|
|
22
22
|
|
|
23
23
|
doc.change(draft => {
|
|
24
|
-
draft.scores.
|
|
24
|
+
draft.scores.getOrCreateRef("alice").increment(5)
|
|
25
25
|
draft.scores.delete("bob")
|
|
26
26
|
})
|
|
27
27
|
|
|
@@ -38,8 +38,8 @@ describe("Record Types", () => {
|
|
|
38
38
|
const doc = new TypedDoc(schema)
|
|
39
39
|
|
|
40
40
|
doc.change(draft => {
|
|
41
|
-
draft.notes.
|
|
42
|
-
draft.notes.
|
|
41
|
+
draft.notes.getOrCreateRef("todo").insert(0, "Buy milk")
|
|
42
|
+
draft.notes.getOrCreateRef("reminders").insert(0, "Call mom")
|
|
43
43
|
})
|
|
44
44
|
|
|
45
45
|
expect(doc.toJSON().notes).toEqual({
|
|
@@ -56,11 +56,11 @@ describe("Record Types", () => {
|
|
|
56
56
|
const doc = new TypedDoc(schema)
|
|
57
57
|
|
|
58
58
|
doc.change(draft => {
|
|
59
|
-
const groupA = draft.groups.
|
|
59
|
+
const groupA = draft.groups.getOrCreateRef("groupA")
|
|
60
60
|
groupA.push("alice")
|
|
61
61
|
groupA.push("bob")
|
|
62
62
|
|
|
63
|
-
const groupB = draft.groups.
|
|
63
|
+
const groupB = draft.groups.getOrCreateRef("groupB")
|
|
64
64
|
groupB.push("charlie")
|
|
65
65
|
})
|
|
66
66
|
|
|
@@ -170,11 +170,11 @@ describe("Record Types", () => {
|
|
|
170
170
|
const doc = new TypedDoc(schema)
|
|
171
171
|
|
|
172
172
|
doc.change(draft => {
|
|
173
|
-
const alice = draft.users.
|
|
173
|
+
const alice = draft.users.getOrCreateRef("u1")
|
|
174
174
|
alice.name = "Alice"
|
|
175
175
|
alice.age = 30
|
|
176
176
|
|
|
177
|
-
const bob = draft.users.
|
|
177
|
+
const bob = draft.users.getOrCreateRef("u2")
|
|
178
178
|
bob.name = "Bob"
|
|
179
179
|
bob.age = 25
|
|
180
180
|
})
|
package/src/typed-refs/record.ts
CHANGED
|
@@ -1,40 +1,29 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type Container,
|
|
3
|
-
LoroCounter,
|
|
4
|
-
LoroList,
|
|
5
|
-
LoroMap,
|
|
6
|
-
LoroMovableList,
|
|
7
|
-
LoroText,
|
|
8
|
-
LoroTree,
|
|
9
|
-
type Value,
|
|
10
|
-
} from "loro-crdt"
|
|
1
|
+
import type { Container, LoroMap, Value } from "loro-crdt"
|
|
11
2
|
import { deriveShapePlaceholder } from "../derive-placeholder.js"
|
|
3
|
+
import { mergeValue } from "../overlay.js"
|
|
12
4
|
import type {
|
|
13
5
|
ContainerOrValueShape,
|
|
14
6
|
ContainerShape,
|
|
15
7
|
RecordContainerShape,
|
|
16
8
|
} from "../shape.js"
|
|
17
|
-
import type { Infer,
|
|
9
|
+
import type { Infer, InferMutableType } from "../types.js"
|
|
18
10
|
import { isContainerShape, isValueShape } from "../utils/type-guards.js"
|
|
19
11
|
import { TypedRef, type TypedRefParams } from "./base.js"
|
|
20
|
-
import {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
text: LoroText,
|
|
29
|
-
tree: LoroTree,
|
|
30
|
-
} as const
|
|
12
|
+
import {
|
|
13
|
+
absorbCachedPlainValues,
|
|
14
|
+
assignPlainValueToTypedRef,
|
|
15
|
+
containerConstructor,
|
|
16
|
+
createContainerTypedRef,
|
|
17
|
+
serializeRefToJSON,
|
|
18
|
+
unwrapReadonlyPrimitive,
|
|
19
|
+
} from "./utils.js"
|
|
31
20
|
|
|
32
21
|
// Record typed ref
|
|
33
22
|
export class RecordRef<
|
|
34
23
|
NestedShape extends ContainerOrValueShape,
|
|
35
24
|
> extends TypedRef<any> {
|
|
36
25
|
[key: string]: Infer<NestedShape> | any
|
|
37
|
-
private
|
|
26
|
+
private refCache = new Map<string, TypedRef<ContainerShape> | Value>()
|
|
38
27
|
|
|
39
28
|
protected get shape(): RecordContainerShape<NestedShape> {
|
|
40
29
|
return super.shape as RecordContainerShape<NestedShape>
|
|
@@ -45,16 +34,7 @@ export class RecordRef<
|
|
|
45
34
|
}
|
|
46
35
|
|
|
47
36
|
absorbPlainValues() {
|
|
48
|
-
|
|
49
|
-
if (node instanceof TypedRef) {
|
|
50
|
-
// Contains a TypedRef, not a plain Value: keep recursing
|
|
51
|
-
node.absorbPlainValues()
|
|
52
|
-
continue
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Plain value!
|
|
56
|
-
this.container.set(key, node)
|
|
57
|
-
}
|
|
37
|
+
absorbCachedPlainValues(this.refCache, () => this.container)
|
|
58
38
|
}
|
|
59
39
|
|
|
60
40
|
getTypedRefParams<S extends ContainerShape>(
|
|
@@ -82,7 +62,7 @@ export class RecordRef<
|
|
|
82
62
|
}
|
|
83
63
|
}
|
|
84
64
|
|
|
85
|
-
|
|
65
|
+
getOrCreateRef(key: string): any {
|
|
86
66
|
// For readonly mode with container shapes, check if the key exists first
|
|
87
67
|
// This allows optional chaining (?.) to work correctly for non-existent keys
|
|
88
68
|
// Similar to how ListRefBase.getMutableItem() handles non-existent indices
|
|
@@ -93,67 +73,64 @@ export class RecordRef<
|
|
|
93
73
|
}
|
|
94
74
|
}
|
|
95
75
|
|
|
96
|
-
let
|
|
97
|
-
if (!
|
|
76
|
+
let ref = this.refCache.get(key)
|
|
77
|
+
if (!ref) {
|
|
98
78
|
const shape = this.shape.shape
|
|
99
79
|
if (isContainerShape(shape)) {
|
|
100
|
-
|
|
80
|
+
ref = createContainerTypedRef(
|
|
101
81
|
this.getTypedRefParams(key, shape as ContainerShape),
|
|
102
82
|
)
|
|
103
|
-
// Cache container
|
|
104
|
-
this.
|
|
83
|
+
// Cache container refs
|
|
84
|
+
this.refCache.set(key, ref)
|
|
105
85
|
} else {
|
|
106
86
|
// For value shapes, first try to get the value from the container
|
|
107
87
|
const containerValue = this.container.get(key)
|
|
108
88
|
if (containerValue !== undefined) {
|
|
109
|
-
|
|
89
|
+
ref = containerValue as Value
|
|
110
90
|
} else {
|
|
111
91
|
// Only fall back to placeholder if the container doesn't have the value
|
|
112
92
|
const placeholder = (this.placeholder as any)?.[key]
|
|
113
93
|
if (placeholder === undefined) {
|
|
114
94
|
// If it's a value type and not in container or placeholder,
|
|
115
95
|
// fallback to the default value from the shape
|
|
116
|
-
|
|
96
|
+
ref = (shape as any)._plain
|
|
117
97
|
} else {
|
|
118
|
-
|
|
98
|
+
ref = placeholder as Value
|
|
119
99
|
}
|
|
120
100
|
}
|
|
121
101
|
// Only cache primitive values if NOT readonly
|
|
122
|
-
if (
|
|
123
|
-
this.
|
|
102
|
+
if (ref !== undefined && !this.readonly) {
|
|
103
|
+
this.refCache.set(key, ref)
|
|
124
104
|
}
|
|
125
105
|
}
|
|
126
106
|
}
|
|
127
107
|
|
|
128
108
|
if (this.readonly && isContainerShape(this.shape.shape)) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
if (shape._type === "text") {
|
|
134
|
-
return (node as any).toString()
|
|
135
|
-
}
|
|
109
|
+
return unwrapReadonlyPrimitive(
|
|
110
|
+
ref as TypedRef<any>,
|
|
111
|
+
this.shape.shape as ContainerShape,
|
|
112
|
+
)
|
|
136
113
|
}
|
|
137
114
|
|
|
138
|
-
return
|
|
115
|
+
return ref as any
|
|
139
116
|
}
|
|
140
117
|
|
|
141
|
-
get(key: string):
|
|
142
|
-
return this.
|
|
118
|
+
get(key: string): InferMutableType<NestedShape> {
|
|
119
|
+
return this.getOrCreateRef(key)
|
|
143
120
|
}
|
|
144
121
|
|
|
145
122
|
set(key: string, value: any): void {
|
|
146
|
-
|
|
123
|
+
this.assertMutable()
|
|
147
124
|
if (isValueShape(this.shape.shape)) {
|
|
148
125
|
this.container.set(key, value)
|
|
149
|
-
this.
|
|
126
|
+
this.refCache.set(key, value)
|
|
150
127
|
} else {
|
|
151
128
|
// For containers, we can't set them directly usually.
|
|
152
129
|
// But if the user passes a plain object that matches the shape, maybe we should convert it?
|
|
153
130
|
if (value && typeof value === "object") {
|
|
154
|
-
const
|
|
131
|
+
const ref = this.getOrCreateRef(key)
|
|
155
132
|
|
|
156
|
-
if (assignPlainValueToTypedRef(
|
|
133
|
+
if (assignPlainValueToTypedRef(ref, value)) {
|
|
157
134
|
return
|
|
158
135
|
}
|
|
159
136
|
}
|
|
@@ -165,14 +142,14 @@ export class RecordRef<
|
|
|
165
142
|
}
|
|
166
143
|
|
|
167
144
|
setContainer<C extends Container>(key: string, container: C): C {
|
|
168
|
-
|
|
145
|
+
this.assertMutable()
|
|
169
146
|
return this.container.setContainer(key, container)
|
|
170
147
|
}
|
|
171
148
|
|
|
172
149
|
delete(key: string): void {
|
|
173
|
-
|
|
150
|
+
this.assertMutable()
|
|
174
151
|
this.container.delete(key)
|
|
175
|
-
this.
|
|
152
|
+
this.refCache.delete(key)
|
|
176
153
|
}
|
|
177
154
|
|
|
178
155
|
has(key: string): boolean {
|
|
@@ -192,15 +169,25 @@ export class RecordRef<
|
|
|
192
169
|
}
|
|
193
170
|
|
|
194
171
|
toJSON(): Record<string, any> {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
172
|
+
// Fast path: readonly mode
|
|
173
|
+
if (this.readonly) {
|
|
174
|
+
const nativeJson = this.container.toJSON() as Record<string, any>
|
|
175
|
+
// For records, we need to overlay placeholders for each entry's nested shape
|
|
176
|
+
const result: Record<string, any> = {}
|
|
177
|
+
for (const key of Object.keys(nativeJson)) {
|
|
178
|
+
// For records, the placeholder is always {}, so we need to derive
|
|
179
|
+
// the placeholder for the nested shape on the fly
|
|
180
|
+
const nestedPlaceholderValue = deriveShapePlaceholder(this.shape.shape)
|
|
181
|
+
|
|
182
|
+
result[key] = mergeValue(
|
|
183
|
+
this.shape.shape,
|
|
184
|
+
nativeJson[key],
|
|
185
|
+
nestedPlaceholderValue as Value,
|
|
186
|
+
)
|
|
202
187
|
}
|
|
188
|
+
return result
|
|
203
189
|
}
|
|
204
|
-
|
|
190
|
+
|
|
191
|
+
return serializeRefToJSON(this, this.keys())
|
|
205
192
|
}
|
|
206
193
|
}
|
package/src/typed-refs/text.ts
CHANGED
|
@@ -9,12 +9,12 @@ export class TextRef extends TypedRef<TextContainerShape> {
|
|
|
9
9
|
|
|
10
10
|
// Text methods
|
|
11
11
|
insert(index: number, content: string): void {
|
|
12
|
-
|
|
12
|
+
this.assertMutable()
|
|
13
13
|
this.container.insert(index, content)
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
delete(index: number, len: number): void {
|
|
17
|
-
|
|
17
|
+
this.assertMutable()
|
|
18
18
|
this.container.delete(index, len)
|
|
19
19
|
}
|
|
20
20
|
|
|
@@ -27,17 +27,17 @@ export class TextRef extends TypedRef<TextContainerShape> {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
update(text: string): void {
|
|
30
|
-
|
|
30
|
+
this.assertMutable()
|
|
31
31
|
this.container.update(text)
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
mark(range: { start: number; end: number }, key: string, value: any): void {
|
|
35
|
-
|
|
35
|
+
this.assertMutable()
|
|
36
36
|
this.container.mark(range, key, value)
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
unmark(range: { start: number; end: number }, key: string): void {
|
|
40
|
-
|
|
40
|
+
this.assertMutable()
|
|
41
41
|
this.container.unmark(range, key)
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -46,7 +46,7 @@ export class TextRef extends TypedRef<TextContainerShape> {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
applyDelta(delta: any[]): void {
|
|
49
|
-
|
|
49
|
+
this.assertMutable()
|
|
50
50
|
this.container.applyDelta(delta)
|
|
51
51
|
}
|
|
52
52
|
|
package/src/typed-refs/tree.ts
CHANGED
|
@@ -8,17 +8,17 @@ export class TreeRef<T extends TreeContainerShape> extends TypedRef<T> {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
createNode(parent?: any, index?: number): any {
|
|
11
|
-
|
|
11
|
+
this.assertMutable()
|
|
12
12
|
return this.container.createNode(parent, index)
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
move(target: any, parent?: any, index?: number): void {
|
|
16
|
-
|
|
16
|
+
this.assertMutable()
|
|
17
17
|
this.container.move(target, parent, index)
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
delete(target: any): void {
|
|
21
|
-
|
|
21
|
+
this.assertMutable()
|
|
22
22
|
this.container.delete(target)
|
|
23
23
|
}
|
|
24
24
|
|