@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/dist/index.js
CHANGED
|
@@ -143,12 +143,21 @@ function mergeValue(shape, crdtValue, placeholderValue) {
|
|
|
143
143
|
}
|
|
144
144
|
switch (shape._type) {
|
|
145
145
|
case "text":
|
|
146
|
-
return crdtValue
|
|
146
|
+
return crdtValue !== void 0 ? crdtValue : placeholderValue ?? "";
|
|
147
147
|
case "counter":
|
|
148
|
-
return crdtValue
|
|
148
|
+
return crdtValue !== void 0 ? crdtValue : placeholderValue ?? 0;
|
|
149
149
|
case "list":
|
|
150
|
-
case "movableList":
|
|
151
|
-
|
|
150
|
+
case "movableList": {
|
|
151
|
+
if (crdtValue === void 0) {
|
|
152
|
+
return placeholderValue ?? [];
|
|
153
|
+
}
|
|
154
|
+
const crdtArray = crdtValue;
|
|
155
|
+
const itemShape = shape.shape;
|
|
156
|
+
const itemPlaceholder = deriveShapePlaceholder(itemShape);
|
|
157
|
+
return crdtArray.map(
|
|
158
|
+
(item) => mergeValue(itemShape, item, itemPlaceholder)
|
|
159
|
+
);
|
|
160
|
+
}
|
|
152
161
|
case "map": {
|
|
153
162
|
if (!isObjectValue(crdtValue) && crdtValue !== void 0) {
|
|
154
163
|
throw new Error("map crdt must be object");
|
|
@@ -171,14 +180,31 @@ function mergeValue(shape, crdtValue, placeholderValue) {
|
|
|
171
180
|
return result;
|
|
172
181
|
}
|
|
173
182
|
case "tree":
|
|
174
|
-
return crdtValue
|
|
183
|
+
return crdtValue !== void 0 ? crdtValue : placeholderValue ?? [];
|
|
184
|
+
case "record": {
|
|
185
|
+
if (!isObjectValue(crdtValue) && crdtValue !== void 0) {
|
|
186
|
+
throw new Error("record crdt must be object");
|
|
187
|
+
}
|
|
188
|
+
const crdtRecordValue = crdtValue ?? {};
|
|
189
|
+
const result = {};
|
|
190
|
+
for (const key of Object.keys(crdtRecordValue)) {
|
|
191
|
+
const nestedCrdtValue = crdtRecordValue[key];
|
|
192
|
+
const nestedPlaceholderValue = deriveShapePlaceholder(shape.shape);
|
|
193
|
+
result[key] = mergeValue(
|
|
194
|
+
shape.shape,
|
|
195
|
+
nestedCrdtValue,
|
|
196
|
+
nestedPlaceholderValue
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
return result;
|
|
200
|
+
}
|
|
175
201
|
default:
|
|
176
202
|
if (shape._type === "value" && shape.valueType === "object") {
|
|
177
203
|
const crdtObj = crdtValue ?? {};
|
|
178
204
|
const placeholderObj = placeholderValue ?? {};
|
|
179
205
|
const result = { ...placeholderObj };
|
|
180
206
|
if (typeof crdtObj !== "object" || crdtObj === null) {
|
|
181
|
-
return crdtValue
|
|
207
|
+
return crdtValue !== void 0 ? crdtValue : placeholderValue;
|
|
182
208
|
}
|
|
183
209
|
for (const [key, propShape] of Object.entries(shape.shape)) {
|
|
184
210
|
const propCrdt = crdtObj[key];
|
|
@@ -194,7 +220,7 @@ function mergeValue(shape, crdtValue, placeholderValue) {
|
|
|
194
220
|
placeholderValue
|
|
195
221
|
);
|
|
196
222
|
}
|
|
197
|
-
return crdtValue
|
|
223
|
+
return crdtValue !== void 0 ? crdtValue : placeholderValue;
|
|
198
224
|
}
|
|
199
225
|
}
|
|
200
226
|
function mergeDiscriminatedUnion(shape, crdtValue, placeholderValue) {
|
|
@@ -206,7 +232,7 @@ function mergeDiscriminatedUnion(shape, crdtValue, placeholderValue) {
|
|
|
206
232
|
}
|
|
207
233
|
const variantShape = shape.variants[discriminantValue];
|
|
208
234
|
if (!variantShape) {
|
|
209
|
-
return crdtValue
|
|
235
|
+
return crdtValue !== void 0 ? crdtValue : placeholderValue;
|
|
210
236
|
}
|
|
211
237
|
const placeholderDiscriminant = placeholderObj[shape.discriminantKey];
|
|
212
238
|
const effectivePlaceholderValue = placeholderDiscriminant === discriminantValue ? placeholderValue : void 0;
|
|
@@ -678,6 +704,15 @@ var TypedRef = class {
|
|
|
678
704
|
get readonly() {
|
|
679
705
|
return !!this._params.readonly;
|
|
680
706
|
}
|
|
707
|
+
/**
|
|
708
|
+
* Throws an error if this ref is in readonly mode.
|
|
709
|
+
* Call this at the start of any mutating method.
|
|
710
|
+
*/
|
|
711
|
+
assertMutable() {
|
|
712
|
+
if (this.readonly) {
|
|
713
|
+
throw new Error("Cannot modify readonly ref");
|
|
714
|
+
}
|
|
715
|
+
}
|
|
681
716
|
get container() {
|
|
682
717
|
if (!this._cachedContainer) {
|
|
683
718
|
const container = this._params.getContainer();
|
|
@@ -688,16 +723,26 @@ var TypedRef = class {
|
|
|
688
723
|
}
|
|
689
724
|
};
|
|
690
725
|
|
|
726
|
+
// src/typed-refs/utils.ts
|
|
727
|
+
import {
|
|
728
|
+
LoroCounter as LoroCounter2,
|
|
729
|
+
LoroList as LoroList2,
|
|
730
|
+
LoroMap as LoroMap2,
|
|
731
|
+
LoroMovableList as LoroMovableList2,
|
|
732
|
+
LoroText as LoroText2,
|
|
733
|
+
LoroTree
|
|
734
|
+
} from "loro-crdt";
|
|
735
|
+
|
|
691
736
|
// src/typed-refs/counter.ts
|
|
692
737
|
var CounterRef = class extends TypedRef {
|
|
693
738
|
absorbPlainValues() {
|
|
694
739
|
}
|
|
695
740
|
increment(value) {
|
|
696
|
-
|
|
741
|
+
this.assertMutable();
|
|
697
742
|
this.container.increment(value);
|
|
698
743
|
}
|
|
699
744
|
decrement(value) {
|
|
700
|
-
|
|
745
|
+
this.assertMutable();
|
|
701
746
|
this.container.decrement(value);
|
|
702
747
|
}
|
|
703
748
|
get value() {
|
|
@@ -732,7 +777,7 @@ function convertListInput(value, shape) {
|
|
|
732
777
|
}
|
|
733
778
|
const list = new LoroList();
|
|
734
779
|
for (const item of value) {
|
|
735
|
-
const convertedItem =
|
|
780
|
+
const convertedItem = convertInputToRef(item, shape.shape);
|
|
736
781
|
if (isContainer(convertedItem)) {
|
|
737
782
|
list.pushContainer(convertedItem);
|
|
738
783
|
} else {
|
|
@@ -747,7 +792,7 @@ function convertMovableListInput(value, shape) {
|
|
|
747
792
|
}
|
|
748
793
|
const list = new LoroMovableList();
|
|
749
794
|
for (const item of value) {
|
|
750
|
-
const convertedItem =
|
|
795
|
+
const convertedItem = convertInputToRef(item, shape.shape);
|
|
751
796
|
if (isContainer(convertedItem)) {
|
|
752
797
|
list.pushContainer(convertedItem);
|
|
753
798
|
} else {
|
|
@@ -764,7 +809,7 @@ function convertMapInput(value, shape) {
|
|
|
764
809
|
for (const [k, v] of Object.entries(value)) {
|
|
765
810
|
const nestedSchema = shape.shapes[k];
|
|
766
811
|
if (nestedSchema) {
|
|
767
|
-
const convertedValue =
|
|
812
|
+
const convertedValue = convertInputToRef(v, nestedSchema);
|
|
768
813
|
if (isContainer(convertedValue)) {
|
|
769
814
|
map.setContainer(k, convertedValue);
|
|
770
815
|
} else {
|
|
@@ -782,7 +827,7 @@ function convertRecordInput(value, shape) {
|
|
|
782
827
|
}
|
|
783
828
|
const map = new LoroMap();
|
|
784
829
|
for (const [k, v] of Object.entries(value)) {
|
|
785
|
-
const convertedValue =
|
|
830
|
+
const convertedValue = convertInputToRef(v, shape.shape);
|
|
786
831
|
if (isContainer(convertedValue)) {
|
|
787
832
|
map.setContainer(k, convertedValue);
|
|
788
833
|
} else {
|
|
@@ -791,7 +836,7 @@ function convertRecordInput(value, shape) {
|
|
|
791
836
|
}
|
|
792
837
|
return map;
|
|
793
838
|
}
|
|
794
|
-
function
|
|
839
|
+
function convertInputToRef(value, shape) {
|
|
795
840
|
switch (shape._type) {
|
|
796
841
|
case "text": {
|
|
797
842
|
if (typeof value !== "string") {
|
|
@@ -868,7 +913,7 @@ var ListRefBase = class extends TypedRef {
|
|
|
868
913
|
this.itemCache.clear();
|
|
869
914
|
}
|
|
870
915
|
insertWithConversion(index, item) {
|
|
871
|
-
const convertedItem =
|
|
916
|
+
const convertedItem = convertInputToRef(item, this.shape.shape);
|
|
872
917
|
if (isContainer(convertedItem)) {
|
|
873
918
|
this.container.insertContainer(index, convertedItem);
|
|
874
919
|
} else {
|
|
@@ -876,7 +921,7 @@ var ListRefBase = class extends TypedRef {
|
|
|
876
921
|
}
|
|
877
922
|
}
|
|
878
923
|
pushWithConversion(item) {
|
|
879
|
-
const convertedItem =
|
|
924
|
+
const convertedItem = convertInputToRef(item, this.shape.shape);
|
|
880
925
|
if (isContainer(convertedItem)) {
|
|
881
926
|
this.container.pushContainer(convertedItem);
|
|
882
927
|
} else {
|
|
@@ -949,13 +994,10 @@ var ListRefBase = class extends TypedRef {
|
|
|
949
994
|
);
|
|
950
995
|
this.itemCache.set(index, cachedItem);
|
|
951
996
|
if (this.readonly) {
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
if (shape._type === "text") {
|
|
957
|
-
return cachedItem.toString();
|
|
958
|
-
}
|
|
997
|
+
return unwrapReadonlyPrimitive(
|
|
998
|
+
cachedItem,
|
|
999
|
+
this.shape.shape
|
|
1000
|
+
);
|
|
959
1001
|
}
|
|
960
1002
|
return cachedItem;
|
|
961
1003
|
}
|
|
@@ -1033,25 +1075,25 @@ var ListRefBase = class extends TypedRef {
|
|
|
1033
1075
|
return result;
|
|
1034
1076
|
}
|
|
1035
1077
|
insert(index, item) {
|
|
1036
|
-
|
|
1078
|
+
this.assertMutable();
|
|
1037
1079
|
this.updateCacheForInsert(index);
|
|
1038
1080
|
this.insertWithConversion(index, item);
|
|
1039
1081
|
}
|
|
1040
1082
|
delete(index, len) {
|
|
1041
|
-
|
|
1083
|
+
this.assertMutable();
|
|
1042
1084
|
this.updateCacheForDelete(index, len);
|
|
1043
1085
|
this.container.delete(index, len);
|
|
1044
1086
|
}
|
|
1045
1087
|
push(item) {
|
|
1046
|
-
|
|
1088
|
+
this.assertMutable();
|
|
1047
1089
|
this.pushWithConversion(item);
|
|
1048
1090
|
}
|
|
1049
1091
|
pushContainer(container) {
|
|
1050
|
-
|
|
1092
|
+
this.assertMutable();
|
|
1051
1093
|
return this.container.pushContainer(container);
|
|
1052
1094
|
}
|
|
1053
1095
|
insertContainer(index, container) {
|
|
1054
|
-
|
|
1096
|
+
this.assertMutable();
|
|
1055
1097
|
return this.container.insertContainer(index, container);
|
|
1056
1098
|
}
|
|
1057
1099
|
get(index) {
|
|
@@ -1065,6 +1107,16 @@ var ListRefBase = class extends TypedRef {
|
|
|
1065
1107
|
return result;
|
|
1066
1108
|
}
|
|
1067
1109
|
toJSON() {
|
|
1110
|
+
if (this.readonly) {
|
|
1111
|
+
const nativeJson = this.container.toJSON();
|
|
1112
|
+
if (isContainerShape(this.shape.shape) || isValueShape(this.shape.shape) && this.shape.shape.valueType === "object") {
|
|
1113
|
+
const itemPlaceholder = deriveShapePlaceholder(this.shape.shape);
|
|
1114
|
+
return nativeJson.map(
|
|
1115
|
+
(item) => mergeValue(this.shape.shape, item, itemPlaceholder)
|
|
1116
|
+
);
|
|
1117
|
+
}
|
|
1118
|
+
return nativeJson ?? [];
|
|
1119
|
+
}
|
|
1068
1120
|
return this.toArray();
|
|
1069
1121
|
}
|
|
1070
1122
|
[Symbol.iterator]() {
|
|
@@ -1122,23 +1174,6 @@ var ListRef = class extends ListRefBase {
|
|
|
1122
1174
|
};
|
|
1123
1175
|
|
|
1124
1176
|
// src/typed-refs/map.ts
|
|
1125
|
-
import {
|
|
1126
|
-
LoroCounter as LoroCounter2,
|
|
1127
|
-
LoroList as LoroList2,
|
|
1128
|
-
LoroMap as LoroMap2,
|
|
1129
|
-
LoroMovableList as LoroMovableList2,
|
|
1130
|
-
LoroText as LoroText2,
|
|
1131
|
-
LoroTree
|
|
1132
|
-
} from "loro-crdt";
|
|
1133
|
-
var containerConstructor = {
|
|
1134
|
-
counter: LoroCounter2,
|
|
1135
|
-
list: LoroList2,
|
|
1136
|
-
map: LoroMap2,
|
|
1137
|
-
movableList: LoroMovableList2,
|
|
1138
|
-
record: LoroMap2,
|
|
1139
|
-
text: LoroText2,
|
|
1140
|
-
tree: LoroTree
|
|
1141
|
-
};
|
|
1142
1177
|
var MapRef = class extends TypedRef {
|
|
1143
1178
|
propertyCache = /* @__PURE__ */ new Map();
|
|
1144
1179
|
constructor(params) {
|
|
@@ -1152,13 +1187,7 @@ var MapRef = class extends TypedRef {
|
|
|
1152
1187
|
return super.container;
|
|
1153
1188
|
}
|
|
1154
1189
|
absorbPlainValues() {
|
|
1155
|
-
|
|
1156
|
-
if (node instanceof TypedRef) {
|
|
1157
|
-
node.absorbPlainValues();
|
|
1158
|
-
continue;
|
|
1159
|
-
}
|
|
1160
|
-
this.container.set(key, node);
|
|
1161
|
-
}
|
|
1190
|
+
absorbCachedPlainValues(this.propertyCache, () => this.container);
|
|
1162
1191
|
}
|
|
1163
1192
|
getTypedRefParams(key, shape) {
|
|
1164
1193
|
const placeholder = this.placeholder?.[key];
|
|
@@ -1170,57 +1199,52 @@ var MapRef = class extends TypedRef {
|
|
|
1170
1199
|
readonly: this.readonly
|
|
1171
1200
|
};
|
|
1172
1201
|
}
|
|
1173
|
-
|
|
1174
|
-
let
|
|
1175
|
-
if (!
|
|
1202
|
+
getOrCreateRef(key, shape) {
|
|
1203
|
+
let ref = this.propertyCache.get(key);
|
|
1204
|
+
if (!ref) {
|
|
1176
1205
|
if (isContainerShape(shape)) {
|
|
1177
|
-
|
|
1178
|
-
this.propertyCache.set(key,
|
|
1206
|
+
ref = createContainerTypedRef(this.getTypedRefParams(key, shape));
|
|
1207
|
+
this.propertyCache.set(key, ref);
|
|
1179
1208
|
} else {
|
|
1180
1209
|
const containerValue = this.container.get(key);
|
|
1181
1210
|
if (containerValue !== void 0) {
|
|
1182
|
-
|
|
1211
|
+
ref = containerValue;
|
|
1183
1212
|
} else {
|
|
1184
1213
|
const placeholder = this.placeholder?.[key];
|
|
1185
1214
|
if (placeholder === void 0) {
|
|
1186
1215
|
throw new Error("placeholder required");
|
|
1187
1216
|
}
|
|
1188
|
-
|
|
1217
|
+
ref = placeholder;
|
|
1189
1218
|
}
|
|
1190
1219
|
if (!this.readonly) {
|
|
1191
|
-
this.propertyCache.set(key,
|
|
1220
|
+
this.propertyCache.set(key, ref);
|
|
1192
1221
|
}
|
|
1193
1222
|
}
|
|
1194
|
-
if (
|
|
1223
|
+
if (ref === void 0) throw new Error("no container made");
|
|
1195
1224
|
}
|
|
1196
1225
|
if (this.readonly && isContainerShape(shape)) {
|
|
1197
1226
|
const existing = this.container.get(key);
|
|
1198
1227
|
if (existing === void 0) {
|
|
1199
1228
|
return this.placeholder?.[key];
|
|
1200
1229
|
}
|
|
1201
|
-
|
|
1202
|
-
return node.value;
|
|
1203
|
-
}
|
|
1204
|
-
if (shape._type === "text") {
|
|
1205
|
-
return node.toString();
|
|
1206
|
-
}
|
|
1230
|
+
return unwrapReadonlyPrimitive(ref, shape);
|
|
1207
1231
|
}
|
|
1208
|
-
return
|
|
1232
|
+
return ref;
|
|
1209
1233
|
}
|
|
1210
1234
|
createLazyProperties() {
|
|
1211
1235
|
for (const key in this.shape.shapes) {
|
|
1212
1236
|
const shape = this.shape.shapes[key];
|
|
1213
1237
|
Object.defineProperty(this, key, {
|
|
1214
|
-
get: () => this.
|
|
1238
|
+
get: () => this.getOrCreateRef(key, shape),
|
|
1215
1239
|
set: (value) => {
|
|
1216
|
-
|
|
1240
|
+
this.assertMutable();
|
|
1217
1241
|
if (isValueShape(shape)) {
|
|
1218
1242
|
this.container.set(key, value);
|
|
1219
1243
|
this.propertyCache.set(key, value);
|
|
1220
1244
|
} else {
|
|
1221
1245
|
if (value && typeof value === "object") {
|
|
1222
|
-
const
|
|
1223
|
-
if (assignPlainValueToTypedRef(
|
|
1246
|
+
const ref = this.getOrCreateRef(key, shape);
|
|
1247
|
+
if (assignPlainValueToTypedRef(ref, value)) {
|
|
1224
1248
|
return;
|
|
1225
1249
|
}
|
|
1226
1250
|
}
|
|
@@ -1234,31 +1258,26 @@ var MapRef = class extends TypedRef {
|
|
|
1234
1258
|
}
|
|
1235
1259
|
}
|
|
1236
1260
|
toJSON() {
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
if (value && typeof value === "object" && "toJSON" in value) {
|
|
1241
|
-
result[key] = value.toJSON();
|
|
1242
|
-
} else {
|
|
1243
|
-
result[key] = value;
|
|
1244
|
-
}
|
|
1261
|
+
if (this.readonly) {
|
|
1262
|
+
const nativeJson = this.container.toJSON();
|
|
1263
|
+
return mergeValue(this.shape, nativeJson, this.placeholder);
|
|
1245
1264
|
}
|
|
1246
|
-
return
|
|
1265
|
+
return serializeRefToJSON(this, Object.keys(this.shape.shapes));
|
|
1247
1266
|
}
|
|
1248
|
-
//
|
|
1267
|
+
// TODO(duane): return correct type here
|
|
1249
1268
|
get(key) {
|
|
1250
1269
|
return this.container.get(key);
|
|
1251
1270
|
}
|
|
1252
1271
|
set(key, value) {
|
|
1253
|
-
|
|
1272
|
+
this.assertMutable();
|
|
1254
1273
|
this.container.set(key, value);
|
|
1255
1274
|
}
|
|
1256
1275
|
setContainer(key, container) {
|
|
1257
|
-
|
|
1276
|
+
this.assertMutable();
|
|
1258
1277
|
return this.container.setContainer(key, container);
|
|
1259
1278
|
}
|
|
1260
1279
|
delete(key) {
|
|
1261
|
-
|
|
1280
|
+
this.assertMutable();
|
|
1262
1281
|
this.container.delete(key);
|
|
1263
1282
|
}
|
|
1264
1283
|
has(key) {
|
|
@@ -1284,11 +1303,11 @@ var MovableListRef = class extends ListRefBase {
|
|
|
1284
1303
|
this.container.set(index, value);
|
|
1285
1304
|
}
|
|
1286
1305
|
move(from, to) {
|
|
1287
|
-
|
|
1306
|
+
this.assertMutable();
|
|
1288
1307
|
this.container.move(from, to);
|
|
1289
1308
|
}
|
|
1290
1309
|
set(index, item) {
|
|
1291
|
-
|
|
1310
|
+
this.assertMutable();
|
|
1292
1311
|
return this.container.set(index, item);
|
|
1293
1312
|
}
|
|
1294
1313
|
};
|
|
@@ -1374,25 +1393,8 @@ var movableListProxyHandler = {
|
|
|
1374
1393
|
};
|
|
1375
1394
|
|
|
1376
1395
|
// src/typed-refs/record.ts
|
|
1377
|
-
import {
|
|
1378
|
-
LoroCounter as LoroCounter3,
|
|
1379
|
-
LoroList as LoroList3,
|
|
1380
|
-
LoroMap as LoroMap3,
|
|
1381
|
-
LoroMovableList as LoroMovableList3,
|
|
1382
|
-
LoroText as LoroText3,
|
|
1383
|
-
LoroTree as LoroTree2
|
|
1384
|
-
} from "loro-crdt";
|
|
1385
|
-
var containerConstructor2 = {
|
|
1386
|
-
counter: LoroCounter3,
|
|
1387
|
-
list: LoroList3,
|
|
1388
|
-
map: LoroMap3,
|
|
1389
|
-
movableList: LoroMovableList3,
|
|
1390
|
-
record: LoroMap3,
|
|
1391
|
-
text: LoroText3,
|
|
1392
|
-
tree: LoroTree2
|
|
1393
|
-
};
|
|
1394
1396
|
var RecordRef = class extends TypedRef {
|
|
1395
|
-
|
|
1397
|
+
refCache = /* @__PURE__ */ new Map();
|
|
1396
1398
|
get shape() {
|
|
1397
1399
|
return super.shape;
|
|
1398
1400
|
}
|
|
@@ -1400,20 +1402,14 @@ var RecordRef = class extends TypedRef {
|
|
|
1400
1402
|
return super.container;
|
|
1401
1403
|
}
|
|
1402
1404
|
absorbPlainValues() {
|
|
1403
|
-
|
|
1404
|
-
if (node instanceof TypedRef) {
|
|
1405
|
-
node.absorbPlainValues();
|
|
1406
|
-
continue;
|
|
1407
|
-
}
|
|
1408
|
-
this.container.set(key, node);
|
|
1409
|
-
}
|
|
1405
|
+
absorbCachedPlainValues(this.refCache, () => this.container);
|
|
1410
1406
|
}
|
|
1411
1407
|
getTypedRefParams(key, shape) {
|
|
1412
1408
|
let placeholder = this.placeholder?.[key];
|
|
1413
1409
|
if (placeholder === void 0) {
|
|
1414
1410
|
placeholder = deriveShapePlaceholder(shape);
|
|
1415
1411
|
}
|
|
1416
|
-
const LoroContainer =
|
|
1412
|
+
const LoroContainer = containerConstructor[shape._type];
|
|
1417
1413
|
return {
|
|
1418
1414
|
shape,
|
|
1419
1415
|
placeholder,
|
|
@@ -1421,61 +1417,58 @@ var RecordRef = class extends TypedRef {
|
|
|
1421
1417
|
readonly: this.readonly
|
|
1422
1418
|
};
|
|
1423
1419
|
}
|
|
1424
|
-
|
|
1420
|
+
getOrCreateRef(key) {
|
|
1425
1421
|
if (this.readonly && isContainerShape(this.shape.shape)) {
|
|
1426
1422
|
const existing = this.container.get(key);
|
|
1427
1423
|
if (existing === void 0) {
|
|
1428
1424
|
return void 0;
|
|
1429
1425
|
}
|
|
1430
1426
|
}
|
|
1431
|
-
let
|
|
1432
|
-
if (!
|
|
1427
|
+
let ref = this.refCache.get(key);
|
|
1428
|
+
if (!ref) {
|
|
1433
1429
|
const shape = this.shape.shape;
|
|
1434
1430
|
if (isContainerShape(shape)) {
|
|
1435
|
-
|
|
1431
|
+
ref = createContainerTypedRef(
|
|
1436
1432
|
this.getTypedRefParams(key, shape)
|
|
1437
1433
|
);
|
|
1438
|
-
this.
|
|
1434
|
+
this.refCache.set(key, ref);
|
|
1439
1435
|
} else {
|
|
1440
1436
|
const containerValue = this.container.get(key);
|
|
1441
1437
|
if (containerValue !== void 0) {
|
|
1442
|
-
|
|
1438
|
+
ref = containerValue;
|
|
1443
1439
|
} else {
|
|
1444
1440
|
const placeholder = this.placeholder?.[key];
|
|
1445
1441
|
if (placeholder === void 0) {
|
|
1446
|
-
|
|
1442
|
+
ref = shape._plain;
|
|
1447
1443
|
} else {
|
|
1448
|
-
|
|
1444
|
+
ref = placeholder;
|
|
1449
1445
|
}
|
|
1450
1446
|
}
|
|
1451
|
-
if (
|
|
1452
|
-
this.
|
|
1447
|
+
if (ref !== void 0 && !this.readonly) {
|
|
1448
|
+
this.refCache.set(key, ref);
|
|
1453
1449
|
}
|
|
1454
1450
|
}
|
|
1455
1451
|
}
|
|
1456
1452
|
if (this.readonly && isContainerShape(this.shape.shape)) {
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
if (shape._type === "text") {
|
|
1462
|
-
return node.toString();
|
|
1463
|
-
}
|
|
1453
|
+
return unwrapReadonlyPrimitive(
|
|
1454
|
+
ref,
|
|
1455
|
+
this.shape.shape
|
|
1456
|
+
);
|
|
1464
1457
|
}
|
|
1465
|
-
return
|
|
1458
|
+
return ref;
|
|
1466
1459
|
}
|
|
1467
1460
|
get(key) {
|
|
1468
|
-
return this.
|
|
1461
|
+
return this.getOrCreateRef(key);
|
|
1469
1462
|
}
|
|
1470
1463
|
set(key, value) {
|
|
1471
|
-
|
|
1464
|
+
this.assertMutable();
|
|
1472
1465
|
if (isValueShape(this.shape.shape)) {
|
|
1473
1466
|
this.container.set(key, value);
|
|
1474
|
-
this.
|
|
1467
|
+
this.refCache.set(key, value);
|
|
1475
1468
|
} else {
|
|
1476
1469
|
if (value && typeof value === "object") {
|
|
1477
|
-
const
|
|
1478
|
-
if (assignPlainValueToTypedRef(
|
|
1470
|
+
const ref = this.getOrCreateRef(key);
|
|
1471
|
+
if (assignPlainValueToTypedRef(ref, value)) {
|
|
1479
1472
|
return;
|
|
1480
1473
|
}
|
|
1481
1474
|
}
|
|
@@ -1485,13 +1478,13 @@ var RecordRef = class extends TypedRef {
|
|
|
1485
1478
|
}
|
|
1486
1479
|
}
|
|
1487
1480
|
setContainer(key, container) {
|
|
1488
|
-
|
|
1481
|
+
this.assertMutable();
|
|
1489
1482
|
return this.container.setContainer(key, container);
|
|
1490
1483
|
}
|
|
1491
1484
|
delete(key) {
|
|
1492
|
-
|
|
1485
|
+
this.assertMutable();
|
|
1493
1486
|
this.container.delete(key);
|
|
1494
|
-
this.
|
|
1487
|
+
this.refCache.delete(key);
|
|
1495
1488
|
}
|
|
1496
1489
|
has(key) {
|
|
1497
1490
|
return this.container.get(key) !== void 0;
|
|
@@ -1506,16 +1499,20 @@ var RecordRef = class extends TypedRef {
|
|
|
1506
1499
|
return this.container.size;
|
|
1507
1500
|
}
|
|
1508
1501
|
toJSON() {
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
const
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1502
|
+
if (this.readonly) {
|
|
1503
|
+
const nativeJson = this.container.toJSON();
|
|
1504
|
+
const result = {};
|
|
1505
|
+
for (const key of Object.keys(nativeJson)) {
|
|
1506
|
+
const nestedPlaceholderValue = deriveShapePlaceholder(this.shape.shape);
|
|
1507
|
+
result[key] = mergeValue(
|
|
1508
|
+
this.shape.shape,
|
|
1509
|
+
nativeJson[key],
|
|
1510
|
+
nestedPlaceholderValue
|
|
1511
|
+
);
|
|
1516
1512
|
}
|
|
1513
|
+
return result;
|
|
1517
1514
|
}
|
|
1518
|
-
return
|
|
1515
|
+
return serializeRefToJSON(this, this.keys());
|
|
1519
1516
|
}
|
|
1520
1517
|
};
|
|
1521
1518
|
|
|
@@ -1525,11 +1522,11 @@ var TextRef = class extends TypedRef {
|
|
|
1525
1522
|
}
|
|
1526
1523
|
// Text methods
|
|
1527
1524
|
insert(index, content) {
|
|
1528
|
-
|
|
1525
|
+
this.assertMutable();
|
|
1529
1526
|
this.container.insert(index, content);
|
|
1530
1527
|
}
|
|
1531
1528
|
delete(index, len) {
|
|
1532
|
-
|
|
1529
|
+
this.assertMutable();
|
|
1533
1530
|
this.container.delete(index, len);
|
|
1534
1531
|
}
|
|
1535
1532
|
toString() {
|
|
@@ -1539,22 +1536,22 @@ var TextRef = class extends TypedRef {
|
|
|
1539
1536
|
return this.toString();
|
|
1540
1537
|
}
|
|
1541
1538
|
update(text) {
|
|
1542
|
-
|
|
1539
|
+
this.assertMutable();
|
|
1543
1540
|
this.container.update(text);
|
|
1544
1541
|
}
|
|
1545
1542
|
mark(range, key, value) {
|
|
1546
|
-
|
|
1543
|
+
this.assertMutable();
|
|
1547
1544
|
this.container.mark(range, key, value);
|
|
1548
1545
|
}
|
|
1549
1546
|
unmark(range, key) {
|
|
1550
|
-
|
|
1547
|
+
this.assertMutable();
|
|
1551
1548
|
this.container.unmark(range, key);
|
|
1552
1549
|
}
|
|
1553
1550
|
toDelta() {
|
|
1554
1551
|
return this.container.toDelta();
|
|
1555
1552
|
}
|
|
1556
1553
|
applyDelta(delta) {
|
|
1557
|
-
|
|
1554
|
+
this.assertMutable();
|
|
1558
1555
|
this.container.applyDelta(delta);
|
|
1559
1556
|
}
|
|
1560
1557
|
get length() {
|
|
@@ -1567,15 +1564,15 @@ var TreeRef = class extends TypedRef {
|
|
|
1567
1564
|
absorbPlainValues() {
|
|
1568
1565
|
}
|
|
1569
1566
|
createNode(parent, index) {
|
|
1570
|
-
|
|
1567
|
+
this.assertMutable();
|
|
1571
1568
|
return this.container.createNode(parent, index);
|
|
1572
1569
|
}
|
|
1573
1570
|
move(target, parent, index) {
|
|
1574
|
-
|
|
1571
|
+
this.assertMutable();
|
|
1575
1572
|
this.container.move(target, parent, index);
|
|
1576
1573
|
}
|
|
1577
1574
|
delete(target) {
|
|
1578
|
-
|
|
1575
|
+
this.assertMutable();
|
|
1579
1576
|
this.container.delete(target);
|
|
1580
1577
|
}
|
|
1581
1578
|
has(target) {
|
|
@@ -1587,6 +1584,48 @@ var TreeRef = class extends TypedRef {
|
|
|
1587
1584
|
};
|
|
1588
1585
|
|
|
1589
1586
|
// src/typed-refs/utils.ts
|
|
1587
|
+
var containerConstructor = {
|
|
1588
|
+
counter: LoroCounter2,
|
|
1589
|
+
list: LoroList2,
|
|
1590
|
+
map: LoroMap2,
|
|
1591
|
+
movableList: LoroMovableList2,
|
|
1592
|
+
record: LoroMap2,
|
|
1593
|
+
// Records use LoroMap as their underlying container
|
|
1594
|
+
text: LoroText2,
|
|
1595
|
+
tree: LoroTree
|
|
1596
|
+
};
|
|
1597
|
+
function unwrapReadonlyPrimitive(ref, shape) {
|
|
1598
|
+
if (shape._type === "counter") {
|
|
1599
|
+
return ref.value;
|
|
1600
|
+
}
|
|
1601
|
+
if (shape._type === "text") {
|
|
1602
|
+
return ref.toString();
|
|
1603
|
+
}
|
|
1604
|
+
return ref;
|
|
1605
|
+
}
|
|
1606
|
+
function absorbCachedPlainValues(cache, getContainer) {
|
|
1607
|
+
let container;
|
|
1608
|
+
for (const [key, ref] of cache.entries()) {
|
|
1609
|
+
if (ref instanceof TypedRef) {
|
|
1610
|
+
ref.absorbPlainValues();
|
|
1611
|
+
} else {
|
|
1612
|
+
if (!container) container = getContainer();
|
|
1613
|
+
container.set(key, ref);
|
|
1614
|
+
}
|
|
1615
|
+
}
|
|
1616
|
+
}
|
|
1617
|
+
function serializeRefToJSON(ref, keys) {
|
|
1618
|
+
const result = {};
|
|
1619
|
+
for (const key of keys) {
|
|
1620
|
+
const value = ref[key];
|
|
1621
|
+
if (value && typeof value === "object" && "toJSON" in value) {
|
|
1622
|
+
result[key] = value.toJSON();
|
|
1623
|
+
} else {
|
|
1624
|
+
result[key] = value;
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1627
|
+
return result;
|
|
1628
|
+
}
|
|
1590
1629
|
function createContainerTypedRef(params) {
|
|
1591
1630
|
switch (params.shape._type) {
|
|
1592
1631
|
case "counter":
|
|
@@ -1618,23 +1657,23 @@ function createContainerTypedRef(params) {
|
|
|
1618
1657
|
);
|
|
1619
1658
|
}
|
|
1620
1659
|
}
|
|
1621
|
-
function assignPlainValueToTypedRef(
|
|
1622
|
-
const shapeType =
|
|
1660
|
+
function assignPlainValueToTypedRef(ref, value) {
|
|
1661
|
+
const shapeType = ref.shape._type;
|
|
1623
1662
|
if (shapeType === "map" || shapeType === "record") {
|
|
1624
1663
|
for (const k in value) {
|
|
1625
1664
|
;
|
|
1626
|
-
|
|
1665
|
+
ref[k] = value[k];
|
|
1627
1666
|
}
|
|
1628
1667
|
return true;
|
|
1629
1668
|
}
|
|
1630
1669
|
if (shapeType === "list" || shapeType === "movableList") {
|
|
1631
1670
|
if (Array.isArray(value)) {
|
|
1632
|
-
const
|
|
1633
|
-
if (
|
|
1634
|
-
|
|
1671
|
+
const listRef = ref;
|
|
1672
|
+
if (listRef.length > 0) {
|
|
1673
|
+
listRef.delete(0, listRef.length);
|
|
1635
1674
|
}
|
|
1636
1675
|
for (const item of value) {
|
|
1637
|
-
|
|
1676
|
+
listRef.push(item);
|
|
1638
1677
|
}
|
|
1639
1678
|
return true;
|
|
1640
1679
|
}
|
|
@@ -1684,20 +1723,15 @@ var DocRef = class extends TypedRef {
|
|
|
1684
1723
|
return this.requiredPlaceholder[key];
|
|
1685
1724
|
}
|
|
1686
1725
|
}
|
|
1687
|
-
let
|
|
1688
|
-
if (!
|
|
1689
|
-
|
|
1690
|
-
this.propertyCache.set(key,
|
|
1726
|
+
let ref = this.propertyCache.get(key);
|
|
1727
|
+
if (!ref) {
|
|
1728
|
+
ref = createContainerTypedRef(this.getTypedRefParams(key, shape));
|
|
1729
|
+
this.propertyCache.set(key, ref);
|
|
1691
1730
|
}
|
|
1692
1731
|
if (this.readonly) {
|
|
1693
|
-
|
|
1694
|
-
return node.value;
|
|
1695
|
-
}
|
|
1696
|
-
if (shape._type === "text") {
|
|
1697
|
-
return node.toString();
|
|
1698
|
-
}
|
|
1732
|
+
return unwrapReadonlyPrimitive(ref, shape);
|
|
1699
1733
|
}
|
|
1700
|
-
return
|
|
1734
|
+
return ref;
|
|
1701
1735
|
}
|
|
1702
1736
|
createLazyProperties() {
|
|
1703
1737
|
for (const key in this.shape.shapes) {
|
|
@@ -1709,20 +1743,14 @@ var DocRef = class extends TypedRef {
|
|
|
1709
1743
|
}
|
|
1710
1744
|
}
|
|
1711
1745
|
toJSON() {
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
result[key] = value.toJSON();
|
|
1717
|
-
} else {
|
|
1718
|
-
result[key] = value;
|
|
1719
|
-
}
|
|
1720
|
-
}
|
|
1721
|
-
return result;
|
|
1746
|
+
return serializeRefToJSON(
|
|
1747
|
+
this,
|
|
1748
|
+
Object.keys(this.shape.shapes)
|
|
1749
|
+
);
|
|
1722
1750
|
}
|
|
1723
1751
|
absorbPlainValues() {
|
|
1724
|
-
for (const [,
|
|
1725
|
-
|
|
1752
|
+
for (const [, ref] of this.propertyCache.entries()) {
|
|
1753
|
+
ref.absorbPlainValues();
|
|
1726
1754
|
}
|
|
1727
1755
|
}
|
|
1728
1756
|
};
|