@automerge/automerge-repo-solid-primitives 2.5.0 → 2.5.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.js +1426 -859
- package/dist/index.js.map +1 -0
- package/package.json +3 -3
- package/vite.config.ts +2 -0
package/dist/index.js
CHANGED
|
@@ -1,912 +1,1479 @@
|
|
|
1
|
-
import { onCleanup
|
|
2
|
-
import { createStore
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
1
|
+
import { onCleanup, createMemo, createContext, useContext, createResource, createEffect } from 'solid-js';
|
|
2
|
+
import { createStore, produce, reconcile } from 'solid-js/store';
|
|
3
|
+
|
|
4
|
+
// Properties of the document root object
|
|
5
|
+
const STATE = Symbol.for("_am_meta"); // symbol used to hide application metadata on automerge objects
|
|
6
|
+
const TRACE = Symbol.for("_am_trace"); // used for debugging
|
|
7
|
+
const OBJECT_ID = Symbol.for("_am_objectId"); // symbol used to hide the object id on automerge objects
|
|
8
|
+
const IS_PROXY = Symbol.for("_am_isProxy"); // symbol used to test if the document is a proxy object
|
|
9
|
+
const CLEAR_CACHE = Symbol.for("_am_clearCache"); // symbol used to tell a proxy object to clear its cache
|
|
10
|
+
const UINT = Symbol.for("_am_uint");
|
|
11
|
+
const INT = Symbol.for("_am_int");
|
|
12
|
+
const F64 = Symbol.for("_am_f64");
|
|
13
|
+
const COUNTER = Symbol.for("_am_counter");
|
|
14
|
+
const IMMUTABLE_STRING = Symbol.for("_am_immutableString");
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The most basic CRDT: an integer value that can be changed only by
|
|
18
|
+
* incrementing and decrementing. Since addition of integers is commutative,
|
|
19
|
+
* the value trivially converges.
|
|
20
|
+
*/
|
|
21
|
+
class Counter {
|
|
22
|
+
constructor(value) {
|
|
23
|
+
this.value = value || 0;
|
|
24
|
+
Reflect.defineProperty(this, COUNTER, { value: true });
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* A peculiar JavaScript language feature from its early days: if the object
|
|
28
|
+
* `x` has a `valueOf()` method that returns a number, you can use numerical
|
|
29
|
+
* operators on the object `x` directly, such as `x + 1` or `x < 4`.
|
|
30
|
+
* This method is also called when coercing a value to a string by
|
|
31
|
+
* concatenating it with another string, as in `x + ''`.
|
|
32
|
+
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/valueOf
|
|
33
|
+
*/
|
|
34
|
+
valueOf() {
|
|
35
|
+
return this.value;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Returns the counter value as a decimal string. If `x` is a counter object,
|
|
39
|
+
* this method is called e.g. when you do `['value: ', x].join('')` or when
|
|
40
|
+
* you use string interpolation: `value: ${x}`.
|
|
41
|
+
*/
|
|
42
|
+
toString() {
|
|
43
|
+
return this.valueOf().toString();
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Returns the counter value, so that a JSON serialization of an Automerge
|
|
47
|
+
* document represents the counter simply as an integer.
|
|
48
|
+
*/
|
|
49
|
+
toJSON() {
|
|
50
|
+
return this.value;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Increases the value of the counter by `delta`. If `delta` is not given,
|
|
54
|
+
* increases the value of the counter by 1.
|
|
55
|
+
*
|
|
56
|
+
* Will throw an error if used outside of a change callback.
|
|
57
|
+
*/
|
|
58
|
+
increment(_delta) {
|
|
59
|
+
throw new Error("Counters should not be incremented outside of a change callback");
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Decreases the value of the counter by `delta`. If `delta` is not given,
|
|
63
|
+
* decreases the value of the counter by 1.
|
|
64
|
+
*
|
|
65
|
+
* Will throw an error if used outside of a change callback.
|
|
66
|
+
*/
|
|
67
|
+
decrement(_delta) {
|
|
68
|
+
throw new Error("Counters should not be decremented outside of a change callback");
|
|
69
|
+
}
|
|
71
70
|
}
|
|
72
|
-
|
|
73
|
-
|
|
71
|
+
/**
|
|
72
|
+
* An instance of this class is used when a counter is accessed within a change
|
|
73
|
+
* callback.
|
|
74
|
+
*/
|
|
75
|
+
class WriteableCounter extends Counter {
|
|
76
|
+
constructor(value, context, path, objectId, key) {
|
|
77
|
+
super(value);
|
|
78
|
+
this.context = context;
|
|
79
|
+
this.path = path;
|
|
80
|
+
this.objectId = objectId;
|
|
81
|
+
this.key = key;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Increases the value of the counter by `delta`. If `delta` is not given,
|
|
85
|
+
* increases the value of the counter by 1.
|
|
86
|
+
*/
|
|
87
|
+
increment(delta) {
|
|
88
|
+
delta = typeof delta === "number" ? delta : 1;
|
|
89
|
+
this.context.increment(this.objectId, this.key, delta);
|
|
90
|
+
this.value += delta;
|
|
91
|
+
return this.value;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Decreases the value of the counter by `delta`. If `delta` is not given,
|
|
95
|
+
* decreases the value of the counter by 1.
|
|
96
|
+
*/
|
|
97
|
+
decrement(delta) {
|
|
98
|
+
return this.increment(typeof delta === "number" ? -delta : -1);
|
|
99
|
+
}
|
|
74
100
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
return this.val;
|
|
85
|
-
}
|
|
86
|
-
toJSON() {
|
|
87
|
-
return this.val;
|
|
88
|
-
}
|
|
101
|
+
/**
|
|
102
|
+
* Returns an instance of `WriteableCounter` for use in a change callback.
|
|
103
|
+
* `context` is the proxy context that keeps track of the mutations.
|
|
104
|
+
* `objectId` is the ID of the object containing the counter, and `key` is
|
|
105
|
+
* the property name (key in map, or index in list) where the counter is
|
|
106
|
+
* located.
|
|
107
|
+
*/
|
|
108
|
+
function getWriteableCounter(value, context, path, objectId, key) {
|
|
109
|
+
return new WriteableCounter(value, context, path, objectId, key);
|
|
89
110
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
case "list":
|
|
109
|
-
return _(r, u, [...s, e]);
|
|
110
|
-
case "text":
|
|
111
|
-
return r.text(u);
|
|
112
|
-
case "str":
|
|
113
|
-
return new ce(u);
|
|
114
|
-
case "uint":
|
|
115
|
-
return u;
|
|
116
|
-
case "int":
|
|
117
|
-
return u;
|
|
118
|
-
case "f64":
|
|
119
|
-
return u;
|
|
120
|
-
case "boolean":
|
|
121
|
-
return u;
|
|
122
|
-
case "null":
|
|
123
|
-
return null;
|
|
124
|
-
case "bytes":
|
|
125
|
-
return u;
|
|
126
|
-
case "timestamp":
|
|
127
|
-
return u;
|
|
128
|
-
case "counter":
|
|
129
|
-
return ae(u, r, s, o, e);
|
|
130
|
-
default:
|
|
131
|
-
throw RangeError(`datatype ${i} unimplemented`);
|
|
132
|
-
}
|
|
111
|
+
//module.exports = { Counter, getWriteableCounter }
|
|
112
|
+
|
|
113
|
+
var _a;
|
|
114
|
+
class ImmutableString {
|
|
115
|
+
constructor(val) {
|
|
116
|
+
// Used to detect whether a value is a ImmutableString object rather than using an instanceof check
|
|
117
|
+
this[_a] = true;
|
|
118
|
+
this.val = val;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Returns the content of the ImmutableString object as a simple string
|
|
122
|
+
*/
|
|
123
|
+
toString() {
|
|
124
|
+
return this.val;
|
|
125
|
+
}
|
|
126
|
+
toJSON() {
|
|
127
|
+
return this.val;
|
|
128
|
+
}
|
|
133
129
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
if (t[T])
|
|
147
|
-
return [t.value, "counter"];
|
|
148
|
-
if (t instanceof Date)
|
|
149
|
-
return [t.getTime(), "timestamp"];
|
|
150
|
-
if (pe(t))
|
|
151
|
-
return [t.toString(), "str"];
|
|
152
|
-
if (t instanceof Uint8Array)
|
|
153
|
-
return [t, "bytes"];
|
|
154
|
-
if (t instanceof Array)
|
|
155
|
-
return [t, "list"];
|
|
156
|
-
if (Object.prototype.toString.call(t) === "[object Object]")
|
|
157
|
-
return [t, "map"];
|
|
158
|
-
throw E(t, r) ? new RangeError("Cannot create a reference to an existing document object") : new RangeError(`Cannot assign unknown object: ${t}`);
|
|
159
|
-
case "boolean":
|
|
160
|
-
return [t, "boolean"];
|
|
161
|
-
case "number":
|
|
162
|
-
return Number.isInteger(t) ? [t, "int"] : [t, "f64"];
|
|
163
|
-
case "string":
|
|
164
|
-
return [t, "text"];
|
|
165
|
-
case "undefined":
|
|
166
|
-
throw new RangeError([
|
|
167
|
-
`Cannot assign undefined value at ${M(e)}, `,
|
|
168
|
-
"because `undefined` is not a valid JSON data type. ",
|
|
169
|
-
"You might consider setting the property's value to `null`, ",
|
|
170
|
-
"or using `delete` to remove it altogether."
|
|
171
|
-
].join(""));
|
|
172
|
-
default:
|
|
173
|
-
throw new RangeError([
|
|
174
|
-
`Cannot assign ${o} value at ${M(e)}. `,
|
|
175
|
-
"All JSON primitive datatypes (object, array, string, number, boolean, null) ",
|
|
176
|
-
`are supported in an Automerge document; ${o} values are not. `
|
|
177
|
-
].join(""));
|
|
178
|
-
}
|
|
130
|
+
_a = IMMUTABLE_STRING;
|
|
131
|
+
|
|
132
|
+
function parseListIndex(key) {
|
|
133
|
+
if (typeof key === "string" && /^[0-9]+$/.test(key))
|
|
134
|
+
key = parseInt(key, 10);
|
|
135
|
+
if (typeof key !== "number") {
|
|
136
|
+
return key;
|
|
137
|
+
}
|
|
138
|
+
if (key < 0 || isNaN(key) || key === Infinity || key === -Infinity) {
|
|
139
|
+
throw new RangeError("A list index must be positive, but you passed " + key);
|
|
140
|
+
}
|
|
141
|
+
return key;
|
|
179
142
|
}
|
|
180
|
-
function
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
const fe = {
|
|
185
|
-
get(t, e) {
|
|
186
|
-
const { context: r, objectId: o, cache: s } = t;
|
|
187
|
-
return e === Symbol.toStringTag ? t[Symbol.toStringTag] : e === y ? o : e === O ? !0 : e === w ? t.trace : e === m ? { handle: r } : (s[e] || (s[e] = p(t, e)), s[e]);
|
|
188
|
-
},
|
|
189
|
-
set(t, e, r) {
|
|
190
|
-
const { context: o, objectId: s, path: n } = t;
|
|
191
|
-
if (t.cache = {}, E(r, o))
|
|
192
|
-
throw new RangeError("Cannot create a reference to an existing document object");
|
|
193
|
-
if (e === w)
|
|
194
|
-
return t.trace = r, !0;
|
|
195
|
-
if (e === A)
|
|
196
|
-
return !0;
|
|
197
|
-
const [i, u] = S(r, [...n, e], o);
|
|
198
|
-
switch (u) {
|
|
199
|
-
case "list": {
|
|
200
|
-
const a = o.putObject(s, e, []), f = _(o, a, [...n, e]);
|
|
201
|
-
for (let c = 0; c < i.length; c++)
|
|
202
|
-
f[c] = i[c];
|
|
203
|
-
break;
|
|
204
|
-
}
|
|
205
|
-
case "text": {
|
|
206
|
-
o.putObject(s, e, i);
|
|
207
|
-
break;
|
|
208
|
-
}
|
|
209
|
-
case "map": {
|
|
210
|
-
const a = o.putObject(s, e, {}), f = P(o, a, [...n, e]);
|
|
211
|
-
for (const c in i)
|
|
212
|
-
f[c] = i[c];
|
|
213
|
-
break;
|
|
214
|
-
}
|
|
215
|
-
default:
|
|
216
|
-
o.put(s, e, i, u);
|
|
217
|
-
}
|
|
218
|
-
return !0;
|
|
219
|
-
},
|
|
220
|
-
deleteProperty(t, e) {
|
|
221
|
-
const { context: r, objectId: o } = t;
|
|
222
|
-
return t.cache = {}, r.delete(o, e), !0;
|
|
223
|
-
},
|
|
224
|
-
has(t, e) {
|
|
225
|
-
return this.get(t, e) !== void 0;
|
|
226
|
-
},
|
|
227
|
-
getOwnPropertyDescriptor(t, e) {
|
|
228
|
-
const r = this.get(t, e);
|
|
229
|
-
if (typeof r < "u")
|
|
230
|
-
return {
|
|
231
|
-
configurable: !0,
|
|
232
|
-
enumerable: !0,
|
|
233
|
-
value: r
|
|
234
|
-
};
|
|
235
|
-
},
|
|
236
|
-
ownKeys(t) {
|
|
237
|
-
const { context: e, objectId: r } = t, o = e.keys(r);
|
|
238
|
-
return [...new Set(o)];
|
|
239
|
-
}
|
|
240
|
-
}, F = {
|
|
241
|
-
get(t, e) {
|
|
242
|
-
const { context: r, objectId: o } = t;
|
|
243
|
-
return e = h(e), e === Symbol.hasInstance ? (s) => Array.isArray(s) : e === Symbol.toStringTag ? t[Symbol.toStringTag] : e === y ? o : e === O ? !0 : e === w ? t.trace : e === m ? { handle: r } : e === "length" ? r.length(o) : typeof e == "number" ? p(t, e) : C(t)[e];
|
|
244
|
-
},
|
|
245
|
-
set(t, e, r) {
|
|
246
|
-
const { context: o, objectId: s, path: n } = t;
|
|
247
|
-
if (e = h(e), E(r, o))
|
|
248
|
-
throw new RangeError("Cannot create a reference to an existing document object");
|
|
249
|
-
if (e === A)
|
|
250
|
-
return !0;
|
|
251
|
-
if (e === w)
|
|
252
|
-
return t.trace = r, !0;
|
|
253
|
-
if (typeof e == "string")
|
|
254
|
-
throw new RangeError("list index must be a number");
|
|
255
|
-
const [i, u] = S(r, [...n, e], o);
|
|
256
|
-
switch (u) {
|
|
257
|
-
case "list": {
|
|
258
|
-
let a;
|
|
259
|
-
e >= o.length(s) ? a = o.insertObject(s, e, []) : a = o.putObject(s, e, []), _(o, a, [...n, e]).splice(0, 0, ...i);
|
|
260
|
-
break;
|
|
261
|
-
}
|
|
262
|
-
case "text": {
|
|
263
|
-
e >= o.length(s) ? o.insertObject(s, e, i) : o.putObject(s, e, i);
|
|
264
|
-
break;
|
|
265
|
-
}
|
|
266
|
-
case "map": {
|
|
267
|
-
let a;
|
|
268
|
-
e >= o.length(s) ? a = o.insertObject(s, e, {}) : a = o.putObject(s, e, {});
|
|
269
|
-
const f = P(o, a, [...n, e]);
|
|
270
|
-
for (const c in i)
|
|
271
|
-
f[c] = i[c];
|
|
272
|
-
break;
|
|
273
|
-
}
|
|
274
|
-
default:
|
|
275
|
-
e >= o.length(s) ? o.insert(s, e, i, u) : o.put(s, e, i, u);
|
|
276
|
-
}
|
|
277
|
-
return !0;
|
|
278
|
-
},
|
|
279
|
-
deleteProperty(t, e) {
|
|
280
|
-
const { context: r, objectId: o } = t;
|
|
281
|
-
e = h(e);
|
|
282
|
-
const s = r.get(o, e);
|
|
283
|
-
if (s != null && s[0] == "counter")
|
|
284
|
-
throw new TypeError("Unsupported operation: deleting a counter from a list");
|
|
285
|
-
return r.delete(o, e), !0;
|
|
286
|
-
},
|
|
287
|
-
has(t, e) {
|
|
288
|
-
const { context: r, objectId: o } = t;
|
|
289
|
-
return e = h(e), typeof e == "number" ? e < r.length(o) : e === "length";
|
|
290
|
-
},
|
|
291
|
-
getOwnPropertyDescriptor(t, e) {
|
|
292
|
-
const { context: r, objectId: o } = t;
|
|
293
|
-
return e === "length" ? { writable: !0, value: r.length(o) } : e === y ? { configurable: !1, enumerable: !1, value: o } : (e = h(e), { configurable: !0, enumerable: !0, value: p(t, e) });
|
|
294
|
-
},
|
|
295
|
-
getPrototypeOf(t) {
|
|
296
|
-
return Object.getPrototypeOf(t);
|
|
297
|
-
},
|
|
298
|
-
ownKeys() {
|
|
299
|
-
const t = [];
|
|
300
|
-
return t.push("length"), t;
|
|
301
|
-
}
|
|
302
|
-
};
|
|
303
|
-
Object.assign({}, F, {
|
|
304
|
-
get(t, e) {
|
|
305
|
-
const { context: r, objectId: o } = t;
|
|
306
|
-
return e = h(e), e === Symbol.hasInstance ? (s) => Array.isArray(s) : e === Symbol.toStringTag ? t[Symbol.toStringTag] : e === y ? o : e === O ? !0 : e === w ? t.trace : e === m ? { handle: r } : e === "length" ? r.length(o) : typeof e == "number" ? p(t, e) : le(t)[e] || C(t)[e];
|
|
307
|
-
},
|
|
308
|
-
getPrototypeOf() {
|
|
309
|
-
return Object.getPrototypeOf(new Text());
|
|
310
|
-
}
|
|
311
|
-
});
|
|
312
|
-
function P(t, e, r) {
|
|
313
|
-
const o = {
|
|
314
|
-
context: t,
|
|
315
|
-
objectId: e,
|
|
316
|
-
path: r || [],
|
|
317
|
-
cache: {}
|
|
318
|
-
}, s = {};
|
|
319
|
-
return Object.assign(s, o), new Proxy(s, fe);
|
|
320
|
-
}
|
|
321
|
-
function _(t, e, r) {
|
|
322
|
-
const o = {
|
|
323
|
-
context: t,
|
|
324
|
-
objectId: e,
|
|
325
|
-
path: r || [],
|
|
326
|
-
cache: {}
|
|
327
|
-
}, s = [];
|
|
328
|
-
return Object.assign(s, o), new Proxy(s, F);
|
|
329
|
-
}
|
|
330
|
-
function C(t) {
|
|
331
|
-
const { context: e, objectId: r, path: o } = t;
|
|
332
|
-
return {
|
|
333
|
-
at(n) {
|
|
334
|
-
return p(t, n);
|
|
335
|
-
},
|
|
336
|
-
deleteAt(n, i) {
|
|
337
|
-
return typeof i == "number" ? e.splice(r, n, i) : e.delete(r, n), this;
|
|
338
|
-
},
|
|
339
|
-
fill(n, i, u) {
|
|
340
|
-
const [a, f] = S(n, [...o, i], e), c = e.length(r);
|
|
341
|
-
i = h(i || 0), u = h(u || c);
|
|
342
|
-
for (let l = i; l < Math.min(u, c); l++)
|
|
343
|
-
f === "list" || f === "map" || f === "text" ? e.putObject(r, l, a) : e.put(r, l, a, f);
|
|
344
|
-
return this;
|
|
345
|
-
},
|
|
346
|
-
indexOf(n, i = 0) {
|
|
347
|
-
const u = e.length(r);
|
|
348
|
-
for (let a = i; a < u; a++) {
|
|
349
|
-
const f = e.getWithType(r, a);
|
|
350
|
-
if (!f)
|
|
351
|
-
continue;
|
|
352
|
-
const [c, l] = f;
|
|
353
|
-
if (!["map", "list", "text"].includes(c)) {
|
|
354
|
-
if (l === n)
|
|
355
|
-
return a;
|
|
356
|
-
continue;
|
|
357
|
-
}
|
|
358
|
-
if (c === "text" && typeof n == "string" && n === p(t, a) || n[y] === l)
|
|
359
|
-
return a;
|
|
360
|
-
}
|
|
361
|
-
return -1;
|
|
362
|
-
},
|
|
363
|
-
insertAt(n, ...i) {
|
|
364
|
-
return this.splice(n, 0, ...i), this;
|
|
365
|
-
},
|
|
366
|
-
pop() {
|
|
367
|
-
const n = e.length(r);
|
|
368
|
-
if (n == 0)
|
|
369
|
-
return;
|
|
370
|
-
const i = p(t, n - 1);
|
|
371
|
-
return e.delete(r, n - 1), i;
|
|
372
|
-
},
|
|
373
|
-
push(...n) {
|
|
374
|
-
const i = e.length(r);
|
|
375
|
-
return this.splice(i, 0, ...n), e.length(r);
|
|
376
|
-
},
|
|
377
|
-
shift() {
|
|
378
|
-
if (e.length(r) == 0)
|
|
143
|
+
function valueAt(target, prop) {
|
|
144
|
+
const { context, objectId, path } = target;
|
|
145
|
+
const value = context.getWithType(objectId, prop);
|
|
146
|
+
if (value === null) {
|
|
379
147
|
return;
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
148
|
+
}
|
|
149
|
+
const datatype = value[0];
|
|
150
|
+
const val = value[1];
|
|
151
|
+
switch (datatype) {
|
|
152
|
+
case undefined:
|
|
153
|
+
return;
|
|
154
|
+
case "map":
|
|
155
|
+
return mapProxy(context, val, [...path, prop]);
|
|
156
|
+
case "list":
|
|
157
|
+
return listProxy(context, val, [...path, prop]);
|
|
158
|
+
case "text":
|
|
159
|
+
return context.text(val);
|
|
160
|
+
case "str":
|
|
161
|
+
return new ImmutableString(val);
|
|
162
|
+
case "uint":
|
|
163
|
+
return val;
|
|
164
|
+
case "int":
|
|
165
|
+
return val;
|
|
166
|
+
case "f64":
|
|
167
|
+
return val;
|
|
168
|
+
case "boolean":
|
|
169
|
+
return val;
|
|
170
|
+
case "null":
|
|
171
|
+
return null;
|
|
172
|
+
case "bytes":
|
|
173
|
+
return val;
|
|
174
|
+
case "timestamp":
|
|
175
|
+
return val;
|
|
176
|
+
case "counter": {
|
|
177
|
+
const counter = getWriteableCounter(val, context, path, objectId, prop);
|
|
178
|
+
return counter;
|
|
398
179
|
}
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
180
|
+
default:
|
|
181
|
+
throw RangeError(`datatype ${datatype} unimplemented`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
function import_value(value, path, context) {
|
|
185
|
+
const type = typeof value;
|
|
186
|
+
switch (type) {
|
|
187
|
+
case "object":
|
|
188
|
+
if (value == null) {
|
|
189
|
+
return [null, "null"];
|
|
190
|
+
}
|
|
191
|
+
else if (value[UINT]) {
|
|
192
|
+
return [value.value, "uint"];
|
|
193
|
+
}
|
|
194
|
+
else if (value[INT]) {
|
|
195
|
+
return [value.value, "int"];
|
|
196
|
+
}
|
|
197
|
+
else if (value[F64]) {
|
|
198
|
+
return [value.value, "f64"];
|
|
199
|
+
}
|
|
200
|
+
else if (value[COUNTER]) {
|
|
201
|
+
return [value.value, "counter"];
|
|
202
|
+
}
|
|
203
|
+
else if (value instanceof Date) {
|
|
204
|
+
return [value.getTime(), "timestamp"];
|
|
205
|
+
}
|
|
206
|
+
else if (isImmutableString(value)) {
|
|
207
|
+
return [value.toString(), "str"];
|
|
208
|
+
}
|
|
209
|
+
else if (value instanceof Uint8Array) {
|
|
210
|
+
return [value, "bytes"];
|
|
211
|
+
}
|
|
212
|
+
else if (value instanceof Array) {
|
|
213
|
+
return [value, "list"];
|
|
214
|
+
}
|
|
215
|
+
else if (Object.prototype.toString.call(value) === "[object Object]") {
|
|
216
|
+
return [value, "map"];
|
|
217
|
+
}
|
|
218
|
+
else if (isSameDocument(value, context)) {
|
|
219
|
+
throw new RangeError("Cannot create a reference to an existing document object");
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
throw new RangeError(`Cannot assign unknown object: ${value}`);
|
|
223
|
+
}
|
|
224
|
+
case "boolean":
|
|
225
|
+
return [value, "boolean"];
|
|
226
|
+
case "number":
|
|
227
|
+
if (Number.isInteger(value)) {
|
|
228
|
+
return [value, "int"];
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
return [value, "f64"];
|
|
232
|
+
}
|
|
233
|
+
case "string":
|
|
234
|
+
return [value, "text"];
|
|
235
|
+
case "undefined":
|
|
236
|
+
throw new RangeError([
|
|
237
|
+
`Cannot assign undefined value at ${printPath(path)}, `,
|
|
238
|
+
"because `undefined` is not a valid JSON data type. ",
|
|
239
|
+
"You might consider setting the property's value to `null`, ",
|
|
240
|
+
"or using `delete` to remove it altogether.",
|
|
241
|
+
].join(""));
|
|
242
|
+
default:
|
|
243
|
+
throw new RangeError([
|
|
244
|
+
`Cannot assign ${type} value at ${printPath(path)}. `,
|
|
245
|
+
`All JSON primitive datatypes (object, array, string, number, boolean, null) `,
|
|
246
|
+
`are supported in an Automerge document; ${type} values are not. `,
|
|
247
|
+
].join(""));
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
// When we assign a value to a property in a proxy we recursively walk through
|
|
251
|
+
// the value we are assigning and copy it into the document. This is generally
|
|
252
|
+
// desirable behaviour. However, a very common bug is to accidentally assign a
|
|
253
|
+
// value which is already in the document to another key within the same
|
|
254
|
+
// document, this often leads to surprising behaviour where users expected to
|
|
255
|
+
// _move_ the object, but it is instead copied. To avoid this we check if the
|
|
256
|
+
// value is from the same document and if it is we throw an error, this means
|
|
257
|
+
// we require an explicit Object.assign call to copy the object, thus avoiding
|
|
258
|
+
// the footgun
|
|
259
|
+
function isSameDocument(val, context) {
|
|
260
|
+
var _b, _c;
|
|
261
|
+
// Date is technically an object, but immutable, so allowing people to assign
|
|
262
|
+
// a date from one place in the document to another place in the document is
|
|
263
|
+
// not likely to be a bug
|
|
264
|
+
if (val instanceof Date) {
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
// this depends on __wbg_ptr being the wasm pointer
|
|
268
|
+
// a new version of wasm-bindgen will break this
|
|
269
|
+
// but the tests should expose the break
|
|
270
|
+
if (val && ((_c = (_b = val[STATE]) === null || _b === void 0 ? void 0 : _b.handle) === null || _c === void 0 ? void 0 : _c.__wbg_ptr) === context.__wbg_ptr) {
|
|
271
|
+
return true;
|
|
272
|
+
}
|
|
273
|
+
return false;
|
|
274
|
+
}
|
|
275
|
+
const MapHandler = {
|
|
276
|
+
get(target, key) {
|
|
277
|
+
const { context, objectId, cache } = target;
|
|
278
|
+
if (key === Symbol.toStringTag) {
|
|
279
|
+
return target[Symbol.toStringTag];
|
|
419
280
|
}
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
next: () => {
|
|
431
|
-
const u = p(t, n);
|
|
432
|
-
return u === void 0 ? { value: void 0, done: !0 } : { value: [n++, u], done: !1 };
|
|
433
|
-
},
|
|
434
|
-
[Symbol.iterator]() {
|
|
435
|
-
return this;
|
|
281
|
+
if (key === OBJECT_ID)
|
|
282
|
+
return objectId;
|
|
283
|
+
if (key === IS_PROXY)
|
|
284
|
+
return true;
|
|
285
|
+
if (key === TRACE)
|
|
286
|
+
return target.trace;
|
|
287
|
+
if (key === STATE)
|
|
288
|
+
return { handle: context };
|
|
289
|
+
if (!cache[key]) {
|
|
290
|
+
cache[key] = valueAt(target, key);
|
|
436
291
|
}
|
|
437
|
-
|
|
292
|
+
return cache[key];
|
|
438
293
|
},
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
[Symbol.iterator]() {
|
|
445
|
-
return this;
|
|
446
|
-
}
|
|
447
|
-
};
|
|
448
|
-
},
|
|
449
|
-
values() {
|
|
450
|
-
let n = 0;
|
|
451
|
-
return {
|
|
452
|
-
next: () => {
|
|
453
|
-
const u = p(t, n++);
|
|
454
|
-
return u === void 0 ? { value: void 0, done: !0 } : { value: u, done: !1 };
|
|
455
|
-
},
|
|
456
|
-
[Symbol.iterator]() {
|
|
457
|
-
return this;
|
|
294
|
+
set(target, key, val) {
|
|
295
|
+
const { context, objectId, path } = target;
|
|
296
|
+
target.cache = {}; // reset cache on set
|
|
297
|
+
if (isSameDocument(val, context)) {
|
|
298
|
+
throw new RangeError("Cannot create a reference to an existing document object");
|
|
458
299
|
}
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
let i = 0;
|
|
493
|
-
for (const u of this) {
|
|
494
|
-
if (n(u, i))
|
|
495
|
-
return u;
|
|
496
|
-
i += 1;
|
|
497
|
-
}
|
|
300
|
+
if (key === TRACE) {
|
|
301
|
+
target.trace = val;
|
|
302
|
+
return true;
|
|
303
|
+
}
|
|
304
|
+
if (key === CLEAR_CACHE) {
|
|
305
|
+
return true;
|
|
306
|
+
}
|
|
307
|
+
const [value, datatype] = import_value(val, [...path, key], context);
|
|
308
|
+
switch (datatype) {
|
|
309
|
+
case "list": {
|
|
310
|
+
const list = context.putObject(objectId, key, []);
|
|
311
|
+
const proxyList = listProxy(context, list, [...path, key]);
|
|
312
|
+
for (let i = 0; i < value.length; i++) {
|
|
313
|
+
proxyList[i] = value[i];
|
|
314
|
+
}
|
|
315
|
+
break;
|
|
316
|
+
}
|
|
317
|
+
case "text": {
|
|
318
|
+
context.putObject(objectId, key, value);
|
|
319
|
+
break;
|
|
320
|
+
}
|
|
321
|
+
case "map": {
|
|
322
|
+
const map = context.putObject(objectId, key, {});
|
|
323
|
+
const proxyMap = mapProxy(context, map, [...path, key]);
|
|
324
|
+
for (const key in value) {
|
|
325
|
+
proxyMap[key] = value[key];
|
|
326
|
+
}
|
|
327
|
+
break;
|
|
328
|
+
}
|
|
329
|
+
default:
|
|
330
|
+
context.put(objectId, key, value, datatype);
|
|
331
|
+
}
|
|
332
|
+
return true;
|
|
498
333
|
},
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
i += 1;
|
|
505
|
-
}
|
|
506
|
-
return -1;
|
|
334
|
+
deleteProperty(target, key) {
|
|
335
|
+
const { context, objectId } = target;
|
|
336
|
+
target.cache = {}; // reset cache on delete
|
|
337
|
+
context.delete(objectId, key);
|
|
338
|
+
return true;
|
|
507
339
|
},
|
|
508
|
-
|
|
509
|
-
|
|
340
|
+
has(target, key) {
|
|
341
|
+
const value = this.get(target, key);
|
|
342
|
+
return value !== undefined;
|
|
510
343
|
},
|
|
511
|
-
|
|
512
|
-
|
|
344
|
+
getOwnPropertyDescriptor(target, key) {
|
|
345
|
+
// const { context, objectId } = target
|
|
346
|
+
const value = this.get(target, key);
|
|
347
|
+
if (typeof value !== "undefined") {
|
|
348
|
+
return {
|
|
349
|
+
configurable: true,
|
|
350
|
+
enumerable: true,
|
|
351
|
+
value,
|
|
352
|
+
};
|
|
353
|
+
}
|
|
513
354
|
},
|
|
514
|
-
|
|
515
|
-
|
|
355
|
+
ownKeys(target) {
|
|
356
|
+
const { context, objectId } = target;
|
|
357
|
+
// FIXME - this is a tmp workaround until fix the dupe key bug in keys()
|
|
358
|
+
const keys = context.keys(objectId);
|
|
359
|
+
return [...new Set(keys)];
|
|
516
360
|
},
|
|
517
|
-
|
|
518
|
-
|
|
361
|
+
};
|
|
362
|
+
const ListHandler = {
|
|
363
|
+
get(target, index) {
|
|
364
|
+
const { context, objectId } = target;
|
|
365
|
+
index = parseListIndex(index);
|
|
366
|
+
if (index === Symbol.hasInstance) {
|
|
367
|
+
return (instance) => {
|
|
368
|
+
return Array.isArray(instance);
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
if (index === Symbol.toStringTag) {
|
|
372
|
+
return target[Symbol.toStringTag];
|
|
373
|
+
}
|
|
374
|
+
if (index === OBJECT_ID)
|
|
375
|
+
return objectId;
|
|
376
|
+
if (index === IS_PROXY)
|
|
377
|
+
return true;
|
|
378
|
+
if (index === TRACE)
|
|
379
|
+
return target.trace;
|
|
380
|
+
if (index === STATE)
|
|
381
|
+
return { handle: context };
|
|
382
|
+
if (index === "length")
|
|
383
|
+
return context.length(objectId);
|
|
384
|
+
if (typeof index === "number") {
|
|
385
|
+
return valueAt(target, index);
|
|
386
|
+
}
|
|
387
|
+
else {
|
|
388
|
+
return listMethods(target)[index];
|
|
389
|
+
}
|
|
519
390
|
},
|
|
520
|
-
|
|
521
|
-
|
|
391
|
+
set(target, index, val) {
|
|
392
|
+
const { context, objectId, path } = target;
|
|
393
|
+
index = parseListIndex(index);
|
|
394
|
+
if (isSameDocument(val, context)) {
|
|
395
|
+
throw new RangeError("Cannot create a reference to an existing document object");
|
|
396
|
+
}
|
|
397
|
+
if (index === CLEAR_CACHE) {
|
|
398
|
+
return true;
|
|
399
|
+
}
|
|
400
|
+
if (index === TRACE) {
|
|
401
|
+
target.trace = val;
|
|
402
|
+
return true;
|
|
403
|
+
}
|
|
404
|
+
if (typeof index == "string") {
|
|
405
|
+
throw new RangeError("list index must be a number");
|
|
406
|
+
}
|
|
407
|
+
const [value, datatype] = import_value(val, [...path, index], context);
|
|
408
|
+
switch (datatype) {
|
|
409
|
+
case "list": {
|
|
410
|
+
let list;
|
|
411
|
+
if (index >= context.length(objectId)) {
|
|
412
|
+
list = context.insertObject(objectId, index, []);
|
|
413
|
+
}
|
|
414
|
+
else {
|
|
415
|
+
list = context.putObject(objectId, index, []);
|
|
416
|
+
}
|
|
417
|
+
const proxyList = listProxy(context, list, [...path, index]);
|
|
418
|
+
proxyList.splice(0, 0, ...value);
|
|
419
|
+
break;
|
|
420
|
+
}
|
|
421
|
+
case "text": {
|
|
422
|
+
if (index >= context.length(objectId)) {
|
|
423
|
+
context.insertObject(objectId, index, value);
|
|
424
|
+
}
|
|
425
|
+
else {
|
|
426
|
+
context.putObject(objectId, index, value);
|
|
427
|
+
}
|
|
428
|
+
break;
|
|
429
|
+
}
|
|
430
|
+
case "map": {
|
|
431
|
+
let map;
|
|
432
|
+
if (index >= context.length(objectId)) {
|
|
433
|
+
map = context.insertObject(objectId, index, {});
|
|
434
|
+
}
|
|
435
|
+
else {
|
|
436
|
+
map = context.putObject(objectId, index, {});
|
|
437
|
+
}
|
|
438
|
+
const proxyMap = mapProxy(context, map, [...path, index]);
|
|
439
|
+
for (const key in value) {
|
|
440
|
+
proxyMap[key] = value[key];
|
|
441
|
+
}
|
|
442
|
+
break;
|
|
443
|
+
}
|
|
444
|
+
default:
|
|
445
|
+
if (index >= context.length(objectId)) {
|
|
446
|
+
context.insert(objectId, index, value, datatype);
|
|
447
|
+
}
|
|
448
|
+
else {
|
|
449
|
+
context.put(objectId, index, value, datatype);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
return true;
|
|
522
453
|
},
|
|
523
|
-
|
|
524
|
-
|
|
454
|
+
deleteProperty(target, index) {
|
|
455
|
+
const { context, objectId } = target;
|
|
456
|
+
index = parseListIndex(index);
|
|
457
|
+
const elem = context.get(objectId, index);
|
|
458
|
+
if (elem != null && elem[0] == "counter") {
|
|
459
|
+
throw new TypeError("Unsupported operation: deleting a counter from a list");
|
|
460
|
+
}
|
|
461
|
+
context.delete(objectId, index);
|
|
462
|
+
return true;
|
|
525
463
|
},
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
if (
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
return !1;
|
|
464
|
+
has(target, index) {
|
|
465
|
+
const { context, objectId } = target;
|
|
466
|
+
index = parseListIndex(index);
|
|
467
|
+
if (typeof index === "number") {
|
|
468
|
+
return index < context.length(objectId);
|
|
469
|
+
}
|
|
470
|
+
return index === "length";
|
|
534
471
|
},
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
return {
|
|
545
|
-
set(s, n) {
|
|
546
|
-
return this[s] = n;
|
|
472
|
+
getOwnPropertyDescriptor(target, index) {
|
|
473
|
+
const { context, objectId } = target;
|
|
474
|
+
if (index === "length")
|
|
475
|
+
return { writable: true, value: context.length(objectId) };
|
|
476
|
+
if (index === OBJECT_ID)
|
|
477
|
+
return { configurable: false, enumerable: false, value: objectId };
|
|
478
|
+
index = parseListIndex(index);
|
|
479
|
+
const value = valueAt(target, index);
|
|
480
|
+
return { configurable: true, enumerable: true, value };
|
|
547
481
|
},
|
|
548
|
-
|
|
549
|
-
|
|
482
|
+
getPrototypeOf(target) {
|
|
483
|
+
return Object.getPrototypeOf(target);
|
|
550
484
|
},
|
|
551
|
-
|
|
552
|
-
|
|
485
|
+
ownKeys( /*target*/) {
|
|
486
|
+
const keys = [];
|
|
487
|
+
// uncommenting this causes assert.deepEqual() to fail when comparing to a pojo array
|
|
488
|
+
// but not uncommenting it causes for (i in list) {} to not enumerate values properly
|
|
489
|
+
//const {context, objectId } = target
|
|
490
|
+
//for (let i = 0; i < target.context.length(objectId); i++) { keys.push(i.toString()) }
|
|
491
|
+
keys.push("length");
|
|
492
|
+
return keys;
|
|
553
493
|
},
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
494
|
+
};
|
|
495
|
+
Object.assign({}, ListHandler, {
|
|
496
|
+
get(target, index) {
|
|
497
|
+
const { context, objectId } = target;
|
|
498
|
+
index = parseListIndex(index);
|
|
499
|
+
if (index === Symbol.hasInstance) {
|
|
500
|
+
return (instance) => {
|
|
501
|
+
return Array.isArray(instance);
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
if (index === Symbol.toStringTag) {
|
|
505
|
+
return target[Symbol.toStringTag];
|
|
506
|
+
}
|
|
507
|
+
if (index === OBJECT_ID)
|
|
508
|
+
return objectId;
|
|
509
|
+
if (index === IS_PROXY)
|
|
510
|
+
return true;
|
|
511
|
+
if (index === TRACE)
|
|
512
|
+
return target.trace;
|
|
513
|
+
if (index === STATE)
|
|
514
|
+
return { handle: context };
|
|
515
|
+
if (index === "length")
|
|
516
|
+
return context.length(objectId);
|
|
517
|
+
if (typeof index === "number") {
|
|
518
|
+
return valueAt(target, index);
|
|
519
|
+
}
|
|
520
|
+
else {
|
|
521
|
+
return textMethods(target)[index] || listMethods(target)[index];
|
|
522
|
+
}
|
|
566
523
|
},
|
|
567
|
-
|
|
568
|
-
|
|
524
|
+
getPrototypeOf( /*target*/) {
|
|
525
|
+
return Object.getPrototypeOf(new Text());
|
|
569
526
|
},
|
|
570
|
-
|
|
571
|
-
|
|
527
|
+
});
|
|
528
|
+
function mapProxy(context, objectId, path) {
|
|
529
|
+
const target = {
|
|
530
|
+
context,
|
|
531
|
+
objectId,
|
|
532
|
+
path: path || [],
|
|
533
|
+
cache: {},
|
|
534
|
+
};
|
|
535
|
+
const proxied = {};
|
|
536
|
+
Object.assign(proxied, target);
|
|
537
|
+
const result = new Proxy(proxied, MapHandler);
|
|
538
|
+
// conversion through unknown is necessary because the types are so different
|
|
539
|
+
return result;
|
|
540
|
+
}
|
|
541
|
+
function listProxy(context, objectId, path) {
|
|
542
|
+
const target = {
|
|
543
|
+
context,
|
|
544
|
+
objectId,
|
|
545
|
+
path: path || [],
|
|
546
|
+
cache: {},
|
|
547
|
+
};
|
|
548
|
+
const proxied = [];
|
|
549
|
+
Object.assign(proxied, target);
|
|
550
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
551
|
+
// @ts-ignore
|
|
552
|
+
return new Proxy(proxied, ListHandler);
|
|
553
|
+
}
|
|
554
|
+
function listMethods(target) {
|
|
555
|
+
const { context, objectId, path } = target;
|
|
556
|
+
const methods = {
|
|
557
|
+
at(index) {
|
|
558
|
+
return valueAt(target, index);
|
|
559
|
+
},
|
|
560
|
+
deleteAt(index, numDelete) {
|
|
561
|
+
if (typeof numDelete === "number") {
|
|
562
|
+
context.splice(objectId, index, numDelete);
|
|
563
|
+
}
|
|
564
|
+
else {
|
|
565
|
+
context.delete(objectId, index);
|
|
566
|
+
}
|
|
567
|
+
return this;
|
|
568
|
+
},
|
|
569
|
+
fill(val, start, end) {
|
|
570
|
+
const [value, datatype] = import_value(val, [...path, start], context);
|
|
571
|
+
const length = context.length(objectId);
|
|
572
|
+
start = parseListIndex(start || 0);
|
|
573
|
+
end = parseListIndex(end || length);
|
|
574
|
+
for (let i = start; i < Math.min(end, length); i++) {
|
|
575
|
+
if (datatype === "list" || datatype === "map") {
|
|
576
|
+
context.putObject(objectId, i, value);
|
|
577
|
+
}
|
|
578
|
+
else if (datatype === "text") {
|
|
579
|
+
context.putObject(objectId, i, value);
|
|
580
|
+
}
|
|
581
|
+
else {
|
|
582
|
+
context.put(objectId, i, value, datatype);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
return this;
|
|
586
|
+
},
|
|
587
|
+
indexOf(searchElement, start = 0) {
|
|
588
|
+
const length = context.length(objectId);
|
|
589
|
+
for (let i = start; i < length; i++) {
|
|
590
|
+
const valueWithType = context.getWithType(objectId, i);
|
|
591
|
+
if (!valueWithType) {
|
|
592
|
+
continue;
|
|
593
|
+
}
|
|
594
|
+
const [valType, value] = valueWithType;
|
|
595
|
+
// Either the target element is an object, and we return if we have found
|
|
596
|
+
// the same object or it is a primitive value and we return if it matches
|
|
597
|
+
// the current value
|
|
598
|
+
const isObject = ["map", "list", "text"].includes(valType);
|
|
599
|
+
if (!isObject) {
|
|
600
|
+
// If the element is not an object, then check if the value is equal to the target
|
|
601
|
+
if (value === searchElement) {
|
|
602
|
+
return i;
|
|
603
|
+
}
|
|
604
|
+
else {
|
|
605
|
+
continue;
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
// if it's an object, but the type of the search element is a string, then we
|
|
609
|
+
// need to check if the object is a text object with the same value as the search element
|
|
610
|
+
if (valType === "text" && typeof searchElement === "string") {
|
|
611
|
+
if (searchElement === valueAt(target, i)) {
|
|
612
|
+
return i;
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
// The only possible match now is if the searchElement is an object already in the
|
|
616
|
+
// automerge document with the same object ID as the value
|
|
617
|
+
if (searchElement[OBJECT_ID] === value) {
|
|
618
|
+
return i;
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
return -1;
|
|
622
|
+
},
|
|
623
|
+
insertAt(index, ...values) {
|
|
624
|
+
this.splice(index, 0, ...values);
|
|
625
|
+
return this;
|
|
626
|
+
},
|
|
627
|
+
pop() {
|
|
628
|
+
const length = context.length(objectId);
|
|
629
|
+
if (length == 0) {
|
|
630
|
+
return undefined;
|
|
631
|
+
}
|
|
632
|
+
const last = valueAt(target, length - 1);
|
|
633
|
+
context.delete(objectId, length - 1);
|
|
634
|
+
return last;
|
|
635
|
+
},
|
|
636
|
+
push(...values) {
|
|
637
|
+
const len = context.length(objectId);
|
|
638
|
+
this.splice(len, 0, ...values);
|
|
639
|
+
return context.length(objectId);
|
|
640
|
+
},
|
|
641
|
+
shift() {
|
|
642
|
+
if (context.length(objectId) == 0)
|
|
643
|
+
return;
|
|
644
|
+
const first = valueAt(target, 0);
|
|
645
|
+
context.delete(objectId, 0);
|
|
646
|
+
return first;
|
|
647
|
+
},
|
|
648
|
+
splice(index, del, ...vals) {
|
|
649
|
+
index = parseListIndex(index);
|
|
650
|
+
// if del is undefined, delete until the end of the list
|
|
651
|
+
if (typeof del !== "number") {
|
|
652
|
+
del = context.length(objectId) - index;
|
|
653
|
+
}
|
|
654
|
+
del = parseListIndex(del);
|
|
655
|
+
for (const val of vals) {
|
|
656
|
+
if (isSameDocument(val, context)) {
|
|
657
|
+
throw new RangeError("Cannot create a reference to an existing document object");
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
const result = [];
|
|
661
|
+
for (let i = 0; i < del; i++) {
|
|
662
|
+
const value = valueAt(target, index);
|
|
663
|
+
if (value !== undefined) {
|
|
664
|
+
result.push(value);
|
|
665
|
+
}
|
|
666
|
+
context.delete(objectId, index);
|
|
667
|
+
}
|
|
668
|
+
const values = vals.map((val, index) => {
|
|
669
|
+
try {
|
|
670
|
+
return import_value(val, [...path], context);
|
|
671
|
+
}
|
|
672
|
+
catch (e) {
|
|
673
|
+
if (e instanceof RangeError) {
|
|
674
|
+
throw new RangeError(`${e.message} (at index ${index} in the input)`);
|
|
675
|
+
}
|
|
676
|
+
else {
|
|
677
|
+
throw e;
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
});
|
|
681
|
+
for (const [value, datatype] of values) {
|
|
682
|
+
switch (datatype) {
|
|
683
|
+
case "list": {
|
|
684
|
+
const list = context.insertObject(objectId, index, []);
|
|
685
|
+
const proxyList = listProxy(context, list, [...path, index]);
|
|
686
|
+
proxyList.splice(0, 0, ...value);
|
|
687
|
+
break;
|
|
688
|
+
}
|
|
689
|
+
case "text": {
|
|
690
|
+
context.insertObject(objectId, index, value);
|
|
691
|
+
break;
|
|
692
|
+
}
|
|
693
|
+
case "map": {
|
|
694
|
+
const map = context.insertObject(objectId, index, {});
|
|
695
|
+
const proxyMap = mapProxy(context, map, [...path, index]);
|
|
696
|
+
for (const key in value) {
|
|
697
|
+
proxyMap[key] = value[key];
|
|
698
|
+
}
|
|
699
|
+
break;
|
|
700
|
+
}
|
|
701
|
+
default:
|
|
702
|
+
context.insert(objectId, index, value, datatype);
|
|
703
|
+
}
|
|
704
|
+
index += 1;
|
|
705
|
+
}
|
|
706
|
+
return result;
|
|
707
|
+
},
|
|
708
|
+
unshift(...values) {
|
|
709
|
+
this.splice(0, 0, ...values);
|
|
710
|
+
return context.length(objectId);
|
|
711
|
+
},
|
|
712
|
+
entries() {
|
|
713
|
+
let i = 0;
|
|
714
|
+
const iterator = {
|
|
715
|
+
next: () => {
|
|
716
|
+
const value = valueAt(target, i);
|
|
717
|
+
if (value === undefined) {
|
|
718
|
+
return { value: undefined, done: true };
|
|
719
|
+
}
|
|
720
|
+
else {
|
|
721
|
+
return { value: [i++, value], done: false };
|
|
722
|
+
}
|
|
723
|
+
},
|
|
724
|
+
[Symbol.iterator]() {
|
|
725
|
+
return this;
|
|
726
|
+
},
|
|
727
|
+
};
|
|
728
|
+
return iterator;
|
|
729
|
+
},
|
|
730
|
+
keys() {
|
|
731
|
+
let i = 0;
|
|
732
|
+
const len = context.length(objectId);
|
|
733
|
+
const iterator = {
|
|
734
|
+
next: () => {
|
|
735
|
+
if (i < len) {
|
|
736
|
+
return { value: i++, done: false };
|
|
737
|
+
}
|
|
738
|
+
return { value: undefined, done: true };
|
|
739
|
+
},
|
|
740
|
+
[Symbol.iterator]() {
|
|
741
|
+
return this;
|
|
742
|
+
},
|
|
743
|
+
};
|
|
744
|
+
return iterator;
|
|
745
|
+
},
|
|
746
|
+
values() {
|
|
747
|
+
let i = 0;
|
|
748
|
+
const iterator = {
|
|
749
|
+
next: () => {
|
|
750
|
+
const value = valueAt(target, i++);
|
|
751
|
+
if (value === undefined) {
|
|
752
|
+
return { value: undefined, done: true };
|
|
753
|
+
}
|
|
754
|
+
else {
|
|
755
|
+
return { value, done: false };
|
|
756
|
+
}
|
|
757
|
+
},
|
|
758
|
+
[Symbol.iterator]() {
|
|
759
|
+
return this;
|
|
760
|
+
},
|
|
761
|
+
};
|
|
762
|
+
return iterator;
|
|
763
|
+
},
|
|
764
|
+
toArray() {
|
|
765
|
+
const list = [];
|
|
766
|
+
let value;
|
|
767
|
+
do {
|
|
768
|
+
value = valueAt(target, list.length);
|
|
769
|
+
if (value !== undefined) {
|
|
770
|
+
list.push(value);
|
|
771
|
+
}
|
|
772
|
+
} while (value !== undefined);
|
|
773
|
+
return list;
|
|
774
|
+
},
|
|
775
|
+
map(f) {
|
|
776
|
+
return this.toArray().map(f);
|
|
777
|
+
},
|
|
778
|
+
toString() {
|
|
779
|
+
return this.toArray().toString();
|
|
780
|
+
},
|
|
781
|
+
toLocaleString() {
|
|
782
|
+
return this.toArray().toLocaleString();
|
|
783
|
+
},
|
|
784
|
+
forEach(f) {
|
|
785
|
+
return this.toArray().forEach(f);
|
|
786
|
+
},
|
|
787
|
+
// todo: real concat function is different
|
|
788
|
+
concat(other) {
|
|
789
|
+
return this.toArray().concat(other);
|
|
790
|
+
},
|
|
791
|
+
every(f) {
|
|
792
|
+
return this.toArray().every(f);
|
|
793
|
+
},
|
|
794
|
+
filter(f) {
|
|
795
|
+
return this.toArray().filter(f);
|
|
796
|
+
},
|
|
797
|
+
find(f) {
|
|
798
|
+
let index = 0;
|
|
799
|
+
for (const v of this) {
|
|
800
|
+
if (f(v, index)) {
|
|
801
|
+
return v;
|
|
802
|
+
}
|
|
803
|
+
index += 1;
|
|
804
|
+
}
|
|
805
|
+
},
|
|
806
|
+
findIndex(f) {
|
|
807
|
+
let index = 0;
|
|
808
|
+
for (const v of this) {
|
|
809
|
+
if (f(v, index)) {
|
|
810
|
+
return index;
|
|
811
|
+
}
|
|
812
|
+
index += 1;
|
|
813
|
+
}
|
|
814
|
+
return -1;
|
|
815
|
+
},
|
|
816
|
+
includes(elem) {
|
|
817
|
+
return this.find(e => e === elem) !== undefined;
|
|
818
|
+
},
|
|
819
|
+
join(sep) {
|
|
820
|
+
return this.toArray().join(sep);
|
|
821
|
+
},
|
|
822
|
+
reduce(f, initialValue) {
|
|
823
|
+
return this.toArray().reduce(f, initialValue);
|
|
824
|
+
},
|
|
825
|
+
reduceRight(f, initialValue) {
|
|
826
|
+
return this.toArray().reduceRight(f, initialValue);
|
|
827
|
+
},
|
|
828
|
+
lastIndexOf(search, fromIndex = +Infinity) {
|
|
829
|
+
// this can be faster
|
|
830
|
+
return this.toArray().lastIndexOf(search, fromIndex);
|
|
831
|
+
},
|
|
832
|
+
slice(index, num) {
|
|
833
|
+
return this.toArray().slice(index, num);
|
|
834
|
+
},
|
|
835
|
+
some(f) {
|
|
836
|
+
let index = 0;
|
|
837
|
+
for (const v of this) {
|
|
838
|
+
if (f(v, index)) {
|
|
839
|
+
return true;
|
|
840
|
+
}
|
|
841
|
+
index += 1;
|
|
842
|
+
}
|
|
843
|
+
return false;
|
|
844
|
+
},
|
|
845
|
+
[Symbol.iterator]: function* () {
|
|
846
|
+
let i = 0;
|
|
847
|
+
let value = valueAt(target, i);
|
|
848
|
+
while (value !== undefined) {
|
|
849
|
+
yield value;
|
|
850
|
+
i += 1;
|
|
851
|
+
value = valueAt(target, i);
|
|
852
|
+
}
|
|
853
|
+
},
|
|
854
|
+
};
|
|
855
|
+
return methods;
|
|
856
|
+
}
|
|
857
|
+
function textMethods(target) {
|
|
858
|
+
const { context, objectId } = target;
|
|
859
|
+
const methods = {
|
|
860
|
+
set(index, value) {
|
|
861
|
+
return (this[index] = value);
|
|
862
|
+
},
|
|
863
|
+
get(index) {
|
|
864
|
+
return this[index];
|
|
865
|
+
},
|
|
866
|
+
toString() {
|
|
867
|
+
return context.text(objectId).replace(//g, "");
|
|
868
|
+
},
|
|
869
|
+
toSpans() {
|
|
870
|
+
const spans = [];
|
|
871
|
+
let chars = "";
|
|
872
|
+
const length = context.length(objectId);
|
|
873
|
+
for (let i = 0; i < length; i++) {
|
|
874
|
+
const value = this[i];
|
|
875
|
+
if (typeof value === "string") {
|
|
876
|
+
chars += value;
|
|
877
|
+
}
|
|
878
|
+
else {
|
|
879
|
+
if (chars.length > 0) {
|
|
880
|
+
spans.push(chars);
|
|
881
|
+
chars = "";
|
|
882
|
+
}
|
|
883
|
+
spans.push(value);
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
if (chars.length > 0) {
|
|
887
|
+
spans.push(chars);
|
|
888
|
+
}
|
|
889
|
+
return spans;
|
|
890
|
+
},
|
|
891
|
+
toJSON() {
|
|
892
|
+
return this.toString();
|
|
893
|
+
},
|
|
894
|
+
indexOf(o, start = 0) {
|
|
895
|
+
const text = context.text(objectId);
|
|
896
|
+
return text.indexOf(o, start);
|
|
897
|
+
},
|
|
898
|
+
insertAt(index, ...values) {
|
|
899
|
+
if (values.every(v => typeof v === "string")) {
|
|
900
|
+
context.splice(objectId, index, 0, values.join(""));
|
|
901
|
+
}
|
|
902
|
+
else {
|
|
903
|
+
listMethods(target).insertAt(index, ...values);
|
|
904
|
+
}
|
|
905
|
+
},
|
|
906
|
+
};
|
|
907
|
+
return methods;
|
|
908
|
+
}
|
|
909
|
+
function printPath(path) {
|
|
910
|
+
// print the path as a json pointer
|
|
911
|
+
const jsonPointerComponents = path.map(component => {
|
|
912
|
+
// if its a number just turn it into a string
|
|
913
|
+
if (typeof component === "number") {
|
|
914
|
+
return component.toString();
|
|
915
|
+
}
|
|
916
|
+
else if (typeof component === "string") {
|
|
917
|
+
// otherwise we have to escape `/` and `~` characters
|
|
918
|
+
return component.replace(/~/g, "~0").replace(/\//g, "~1");
|
|
919
|
+
}
|
|
920
|
+
});
|
|
921
|
+
if (path.length === 0) {
|
|
922
|
+
return "";
|
|
923
|
+
}
|
|
924
|
+
else {
|
|
925
|
+
return "/" + jsonPointerComponents.join("/");
|
|
572
926
|
}
|
|
573
|
-
};
|
|
574
927
|
}
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
} };
|
|
598
|
-
|
|
599
|
-
typeof
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
function
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
928
|
+
/*
|
|
929
|
+
* Check if an object is a {@link ImmutableString}
|
|
930
|
+
*/
|
|
931
|
+
function isImmutableString(obj) {
|
|
932
|
+
// We used to determine whether something was a ImmutableString by doing an instanceof check, but
|
|
933
|
+
// this doesn't work if the automerge module is loaded twice somehow. Instead, use the presence
|
|
934
|
+
// of a symbol to determine if something is a ImmutableString
|
|
935
|
+
return (typeof obj === "object" &&
|
|
936
|
+
obj !== null &&
|
|
937
|
+
Object.prototype.hasOwnProperty.call(obj, IMMUTABLE_STRING));
|
|
938
|
+
}
|
|
939
|
+
function isCounter(obj) {
|
|
940
|
+
// We used to determine whether something was a Counter by doing an instanceof check, but
|
|
941
|
+
// this doesn't work if the automerge module is loaded twice somehow. Instead, use the presence
|
|
942
|
+
// of a symbol to determine if something is a Counter
|
|
943
|
+
return (typeof obj === "object" &&
|
|
944
|
+
obj !== null &&
|
|
945
|
+
Object.prototype.hasOwnProperty.call(obj, COUNTER));
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
let wasm;
|
|
949
|
+
|
|
950
|
+
const cachedTextEncoder = (typeof TextEncoder !== 'undefined' ? new TextEncoder('utf-8') : { encode: () => { throw Error('TextEncoder not available') } } );
|
|
951
|
+
|
|
952
|
+
(typeof cachedTextEncoder.encodeInto === 'function'
|
|
953
|
+
? function (arg, view) {
|
|
954
|
+
return cachedTextEncoder.encodeInto(arg, view);
|
|
955
|
+
}
|
|
956
|
+
: function (arg, view) {
|
|
957
|
+
const buf = cachedTextEncoder.encode(arg);
|
|
958
|
+
view.set(buf);
|
|
959
|
+
return {
|
|
960
|
+
read: arg.length,
|
|
961
|
+
written: buf.length
|
|
962
|
+
};
|
|
963
|
+
});
|
|
964
|
+
|
|
965
|
+
const cachedTextDecoder = (typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }) : { decode: () => { throw Error('TextDecoder not available') } } );
|
|
966
|
+
|
|
967
|
+
if (typeof TextDecoder !== 'undefined') { cachedTextDecoder.decode(); }
|
|
968
|
+
(typeof FinalizationRegistry === 'undefined')
|
|
969
|
+
? { }
|
|
970
|
+
: new FinalizationRegistry(ptr => wasm.__wbg_automerge_free(ptr >>> 0, 1));
|
|
971
|
+
|
|
972
|
+
(typeof FinalizationRegistry === 'undefined')
|
|
973
|
+
? { }
|
|
974
|
+
: new FinalizationRegistry(ptr => wasm.__wbg_syncstate_free(ptr >>> 0, 1));
|
|
975
|
+
|
|
976
|
+
function _state(doc, checkroot = true) {
|
|
977
|
+
if (typeof doc !== "object") {
|
|
978
|
+
throw new RangeError("must be the document root");
|
|
979
|
+
}
|
|
980
|
+
const state = Reflect.get(doc, STATE);
|
|
981
|
+
if (state === undefined ||
|
|
982
|
+
state == null ||
|
|
983
|
+
(checkroot && _obj(doc) !== "_root")) {
|
|
984
|
+
throw new RangeError("must be the document root");
|
|
985
|
+
}
|
|
986
|
+
return state;
|
|
987
|
+
}
|
|
988
|
+
function _clear_cache(doc) {
|
|
989
|
+
Reflect.set(doc, CLEAR_CACHE, true);
|
|
990
|
+
}
|
|
991
|
+
function _obj(doc) {
|
|
992
|
+
if (!(typeof doc === "object") || doc === null) {
|
|
993
|
+
return null;
|
|
994
|
+
}
|
|
995
|
+
return Reflect.get(doc, OBJECT_ID);
|
|
996
|
+
}
|
|
997
|
+
function _is_proxy(doc) {
|
|
998
|
+
return !!Reflect.get(doc, IS_PROXY);
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
function applyPatch(doc, patch) {
|
|
1002
|
+
let path = resolvePath(doc, patch.path);
|
|
1003
|
+
if (patch.action === "put") {
|
|
1004
|
+
applyPutPatch(doc, path, patch);
|
|
1005
|
+
}
|
|
1006
|
+
else if (patch.action === "insert") {
|
|
1007
|
+
applyInsertPatch(doc, path, patch);
|
|
1008
|
+
}
|
|
1009
|
+
else if (patch.action === "del") {
|
|
1010
|
+
applyDelPatch(doc, path, patch);
|
|
1011
|
+
}
|
|
1012
|
+
else if (patch.action === "splice") {
|
|
1013
|
+
applySplicePatch(doc, path, patch);
|
|
1014
|
+
}
|
|
1015
|
+
else if (patch.action === "inc") {
|
|
1016
|
+
applyIncPatch(doc, path, patch);
|
|
1017
|
+
}
|
|
1018
|
+
else if (patch.action === "mark") {
|
|
1019
|
+
applyMarkPatch(doc, path, patch);
|
|
1020
|
+
}
|
|
1021
|
+
else if (patch.action === "unmark") {
|
|
1022
|
+
applyUnmarkPatch(doc, path, patch);
|
|
1023
|
+
}
|
|
1024
|
+
else if (patch.action === "conflict") ;
|
|
657
1025
|
else {
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
throw new RangeError("index is not a number for patch");
|
|
661
|
-
let a = i[u];
|
|
662
|
-
if (a == null || typeof a != "string")
|
|
663
|
-
throw new RangeError("target is not a string for patch");
|
|
664
|
-
let f = a.slice(0, s) + a.slice(s + (r.length || 1));
|
|
665
|
-
i[u] = f;
|
|
666
|
-
}
|
|
667
|
-
else
|
|
668
|
-
throw new RangeError("target is not an array or string for patch");
|
|
669
|
-
}
|
|
670
|
-
function je(t, e, r) {
|
|
671
|
-
if (R(t)) {
|
|
672
|
-
let { obj: o, prop: s, parentPath: n } = b(e, -1);
|
|
673
|
-
if (typeof s != "number")
|
|
674
|
-
throw new RangeError("index is not a number for patch");
|
|
675
|
-
K(t, n, s, 0, r.value);
|
|
676
|
-
} else {
|
|
677
|
-
let { obj: o, prop: s } = b(e, -1), { obj: n, prop: i } = b(e, -2);
|
|
678
|
-
if (typeof s != "number")
|
|
679
|
-
throw new RangeError("index is not a number for patch");
|
|
680
|
-
let u = n[i];
|
|
681
|
-
if (u == null || typeof u != "string")
|
|
682
|
-
throw new RangeError("target is not a string for patch");
|
|
683
|
-
let a = u.slice(0, s) + r.value + u.slice(s);
|
|
684
|
-
n[i] = a;
|
|
685
|
-
}
|
|
1026
|
+
throw new RangeError(`unsupported patch: ${patch}`);
|
|
1027
|
+
}
|
|
686
1028
|
}
|
|
687
|
-
function
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
1029
|
+
function applyPutPatch(doc, path, patch) {
|
|
1030
|
+
let { obj: parent, prop } = pathElemAt(path, -1);
|
|
1031
|
+
parent[prop] = patch.value;
|
|
1032
|
+
}
|
|
1033
|
+
function applyInsertPatch(doc, path, patch) {
|
|
1034
|
+
let { obj: parent, prop } = pathElemAt(path, -1);
|
|
1035
|
+
if (!Array.isArray(parent)) {
|
|
1036
|
+
throw new RangeError(`target is not an array for patch`);
|
|
1037
|
+
}
|
|
1038
|
+
if (!(typeof prop === "number")) {
|
|
1039
|
+
throw new RangeError(`index is not a number for patch`);
|
|
1040
|
+
}
|
|
1041
|
+
parent.splice(prop, 0, ...patch.values);
|
|
1042
|
+
}
|
|
1043
|
+
function applyDelPatch(doc, path, patch) {
|
|
1044
|
+
let { obj: parent, prop, parentPath } = pathElemAt(path, -1);
|
|
1045
|
+
if (!(typeof prop === "number")) {
|
|
1046
|
+
throw new RangeError(`index is not a number for patch`);
|
|
1047
|
+
}
|
|
1048
|
+
if (Array.isArray(parent)) {
|
|
1049
|
+
parent.splice(prop, patch.length || 1);
|
|
1050
|
+
}
|
|
1051
|
+
else if (typeof parent === "string") {
|
|
1052
|
+
if (isAutomerge(doc)) {
|
|
1053
|
+
splice(doc, parentPath, prop, patch.length || 1);
|
|
1054
|
+
}
|
|
1055
|
+
else {
|
|
1056
|
+
let { obj: grandParent, prop: grandParentProp } = pathElemAt(path, -2);
|
|
1057
|
+
if (typeof prop !== "number") {
|
|
1058
|
+
throw new RangeError(`index is not a number for patch`);
|
|
1059
|
+
}
|
|
1060
|
+
let target = grandParent[grandParentProp];
|
|
1061
|
+
if (target == null || typeof target !== "string") {
|
|
1062
|
+
throw new RangeError(`target is not a string for patch`);
|
|
1063
|
+
}
|
|
1064
|
+
let newString = target.slice(0, prop) + target.slice(prop + (patch.length || 1));
|
|
1065
|
+
grandParent[grandParentProp] = newString;
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
else {
|
|
1069
|
+
throw new RangeError(`target is not an array or string for patch`);
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
function applySplicePatch(doc, path, patch) {
|
|
1073
|
+
if (isAutomerge(doc)) {
|
|
1074
|
+
let { obj: parent, prop, parentPath } = pathElemAt(path, -1);
|
|
1075
|
+
if (!(typeof prop === "number")) {
|
|
1076
|
+
throw new RangeError(`index is not a number for patch`);
|
|
1077
|
+
}
|
|
1078
|
+
splice(doc, parentPath, prop, 0, patch.value);
|
|
1079
|
+
}
|
|
1080
|
+
else {
|
|
1081
|
+
let { obj: parent, prop } = pathElemAt(path, -1);
|
|
1082
|
+
let { obj: grandParent, prop: grandParentProp } = pathElemAt(path, -2);
|
|
1083
|
+
if (typeof prop !== "number") {
|
|
1084
|
+
throw new RangeError(`index is not a number for patch`);
|
|
1085
|
+
}
|
|
1086
|
+
let target = grandParent[grandParentProp];
|
|
1087
|
+
if (target == null || typeof target !== "string") {
|
|
1088
|
+
throw new RangeError(`target is not a string for patch`);
|
|
1089
|
+
}
|
|
1090
|
+
let newString = target.slice(0, prop) + patch.value + target.slice(prop);
|
|
1091
|
+
grandParent[grandParentProp] = newString;
|
|
1092
|
+
}
|
|
699
1093
|
}
|
|
700
|
-
function
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
1094
|
+
function applyIncPatch(doc, path, patch) {
|
|
1095
|
+
let { obj: parent, prop } = pathElemAt(path, -1);
|
|
1096
|
+
const counter = parent[prop];
|
|
1097
|
+
if (isAutomerge(doc)) {
|
|
1098
|
+
if (!isCounter(counter)) {
|
|
1099
|
+
throw new RangeError(`target is not a counter for patch`);
|
|
1100
|
+
}
|
|
1101
|
+
counter.increment(patch.value);
|
|
1102
|
+
}
|
|
1103
|
+
else {
|
|
1104
|
+
if (!(typeof counter === "number")) {
|
|
1105
|
+
throw new RangeError(`target is not a number for patch`);
|
|
1106
|
+
}
|
|
1107
|
+
parent[prop] = counter + patch.value;
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
function applyMarkPatch(doc, path, patch) {
|
|
1111
|
+
let { obj: parent, prop } = pathElemAt(path, -1);
|
|
1112
|
+
if (!isAutomerge(doc)) {
|
|
1113
|
+
return;
|
|
1114
|
+
}
|
|
1115
|
+
for (const markSpec of patch.marks) {
|
|
1116
|
+
mark(doc, patch.path,
|
|
707
1117
|
// TODO: add mark expansion to patches. This will require emitting
|
|
708
1118
|
// the expand values in patches.
|
|
709
|
-
{ start:
|
|
710
|
-
|
|
711
|
-
n.value
|
|
712
|
-
);
|
|
713
|
-
}
|
|
714
|
-
function Oe(t, e, r) {
|
|
715
|
-
R(t) && Te(t, r.path, { start: r.start, end: r.end, expand: "none" }, r.name);
|
|
716
|
-
}
|
|
717
|
-
function q(t, e) {
|
|
718
|
-
for (const r of e)
|
|
719
|
-
ye(t, r);
|
|
720
|
-
}
|
|
721
|
-
function Ee(t, e) {
|
|
722
|
-
const r = [];
|
|
723
|
-
let o = t, s = [];
|
|
724
|
-
for (const [n, i] of e.entries())
|
|
725
|
-
if (r.push({ obj: o, prop: i, parentPath: s.slice() }), s.push(i), n !== e.length - 1) {
|
|
726
|
-
if (o == null || typeof o != "object")
|
|
727
|
-
throw new Error(`Invalid path: ${e}`);
|
|
728
|
-
o = o[i];
|
|
729
|
-
} else
|
|
730
|
-
break;
|
|
731
|
-
return r;
|
|
732
|
-
}
|
|
733
|
-
function b(t, e) {
|
|
734
|
-
let r = t.at(e);
|
|
735
|
-
if (r == null)
|
|
736
|
-
throw new Error("invalid path");
|
|
737
|
-
return r;
|
|
738
|
-
}
|
|
739
|
-
function Pe(t, e, r) {
|
|
740
|
-
if (typeof r == "string") {
|
|
741
|
-
if (/^-?[0-9]+@[0-9a-zA-Z]+$|^[se]$/.test(r))
|
|
742
|
-
return t.handle.getCursorPosition(e, r);
|
|
743
|
-
throw new RangeError("index must be a number or cursor");
|
|
744
|
-
} else
|
|
745
|
-
return r;
|
|
746
|
-
}
|
|
747
|
-
function _e(t, e) {
|
|
748
|
-
return x(t);
|
|
749
|
-
}
|
|
750
|
-
function ve(t, e, r) {
|
|
751
|
-
N(e, "before"), N(r, "after");
|
|
752
|
-
const o = j(t);
|
|
753
|
-
return o.mostRecentPatch && I(o.mostRecentPatch.before, e) && I(o.mostRecentPatch.after, r) ? o.mostRecentPatch.patches : o.handle.diff(e, r);
|
|
754
|
-
}
|
|
755
|
-
function N(t, e) {
|
|
756
|
-
if (!Array.isArray(t))
|
|
757
|
-
throw new Error(`${e} must be an array`);
|
|
758
|
-
}
|
|
759
|
-
function I(t, e) {
|
|
760
|
-
if (!U(t) || !U(e))
|
|
761
|
-
return t === e;
|
|
762
|
-
const r = Object.keys(t).sort(), o = Object.keys(e).sort();
|
|
763
|
-
if (r.length !== o.length)
|
|
764
|
-
return !1;
|
|
765
|
-
for (let s = 0; s < r.length; s++)
|
|
766
|
-
if (r[s] !== o[s] || !I(t[r[s]], e[o[s]]))
|
|
767
|
-
return !1;
|
|
768
|
-
return !0;
|
|
769
|
-
}
|
|
770
|
-
function Ie(t) {
|
|
771
|
-
const e = j(t);
|
|
772
|
-
return e.heads || e.handle.getHeads();
|
|
773
|
-
}
|
|
774
|
-
function R(t) {
|
|
775
|
-
return typeof t == "object" && t !== null ? _e(t) === "_root" && !!Reflect.get(t, m) : !1;
|
|
776
|
-
}
|
|
777
|
-
function U(t) {
|
|
778
|
-
return typeof t == "object" && t !== null;
|
|
779
|
-
}
|
|
780
|
-
function K(t, e, r, o, s) {
|
|
781
|
-
const n = $(t, e, "splice");
|
|
782
|
-
if (!k(t))
|
|
783
|
-
throw new RangeError("object cannot be modified outside of a change block");
|
|
784
|
-
const i = j(t, !1);
|
|
785
|
-
ge(t), r = Pe(i, n, r);
|
|
786
|
-
try {
|
|
787
|
-
return i.handle.splice(n, r, o, s);
|
|
788
|
-
} catch (u) {
|
|
789
|
-
throw new RangeError(`Cannot splice: ${u}`);
|
|
790
|
-
}
|
|
1119
|
+
{ start: markSpec.start, end: markSpec.end, expand: "none" }, markSpec.name, markSpec.value);
|
|
1120
|
+
}
|
|
791
1121
|
}
|
|
792
|
-
function
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
try {
|
|
798
|
-
return i.handle.mark(n, r, o, s);
|
|
799
|
-
} catch (u) {
|
|
800
|
-
throw new RangeError(`Cannot mark: ${u}`);
|
|
801
|
-
}
|
|
1122
|
+
function applyUnmarkPatch(doc, path, patch) {
|
|
1123
|
+
if (!isAutomerge(doc)) {
|
|
1124
|
+
return;
|
|
1125
|
+
}
|
|
1126
|
+
unmark(doc, patch.path, { start: patch.start, end: patch.end, expand: "none" }, patch.name);
|
|
802
1127
|
}
|
|
803
|
-
function
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
1128
|
+
function applyPatches(doc, patches) {
|
|
1129
|
+
for (const patch of patches) {
|
|
1130
|
+
applyPatch(doc, patch);
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
/**
|
|
1134
|
+
* Walk through a path with an object and for each element in the path return a resolved path element.
|
|
1135
|
+
*
|
|
1136
|
+
* A resolved path element looks like this:
|
|
1137
|
+
*
|
|
1138
|
+
* ```typescript
|
|
1139
|
+
* {
|
|
1140
|
+
* obj: any, // The object that this element in the path is a property of
|
|
1141
|
+
* prop: Prop, // The property within `obj` that this path element points at
|
|
1142
|
+
* parentPath: Prop[] // The path to `obj` within the original `doc` passed to `resolvePath`
|
|
1143
|
+
* }
|
|
1144
|
+
* ````
|
|
1145
|
+
*
|
|
1146
|
+
* For example, given an object like this:
|
|
1147
|
+
*
|
|
1148
|
+
* ```typescript
|
|
1149
|
+
* {
|
|
1150
|
+
* todos: [{ task: "remember the milk"}]
|
|
1151
|
+
* }
|
|
1152
|
+
* ```
|
|
1153
|
+
*
|
|
1154
|
+
* Then `resolvePath(doc, ["todos", 0, "task"])` would return:
|
|
1155
|
+
*
|
|
1156
|
+
* ```typescript
|
|
1157
|
+
* [
|
|
1158
|
+
* { obj: { todos: [{ task: "remember the milk"}] }, prop: "todos", parentPath: [] },
|
|
1159
|
+
* { obj: [{ task: "remember the milk"}], prop: 0, parentPath: ["todos"] },
|
|
1160
|
+
* { obj: { task: "remember the milk" }, prop: "task", parentPath: ["todos", 0] }
|
|
1161
|
+
* ]
|
|
1162
|
+
* ```
|
|
1163
|
+
*/
|
|
1164
|
+
function resolvePath(doc, path) {
|
|
1165
|
+
const result = [];
|
|
1166
|
+
let current = doc;
|
|
1167
|
+
let currentPath = [];
|
|
1168
|
+
for (const [index, prop] of path.entries()) {
|
|
1169
|
+
result.push({ obj: current, prop, parentPath: currentPath.slice() });
|
|
1170
|
+
currentPath.push(prop);
|
|
1171
|
+
if (index !== path.length - 1) {
|
|
1172
|
+
if (current == null || typeof current != "object") {
|
|
1173
|
+
// If we're not the last item in the path then we need the current
|
|
1174
|
+
// object to be an object so we can access it in the next iteration
|
|
1175
|
+
throw new Error(`Invalid path: ${path}`);
|
|
1176
|
+
}
|
|
1177
|
+
current = current[prop];
|
|
1178
|
+
}
|
|
1179
|
+
else {
|
|
1180
|
+
break;
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
return result;
|
|
1184
|
+
}
|
|
1185
|
+
/**
|
|
1186
|
+
* Get an element from a resolved path, throwing an exception if the element does not exist
|
|
1187
|
+
*
|
|
1188
|
+
* @param resolved - The path to lookup in
|
|
1189
|
+
* @param index - The index of the element to lookup, negative indices search backwards
|
|
1190
|
+
*/
|
|
1191
|
+
function pathElemAt(resolved, index) {
|
|
1192
|
+
let result = resolved.at(index);
|
|
1193
|
+
if (result == undefined) {
|
|
1194
|
+
throw new Error("invalid path");
|
|
1195
|
+
}
|
|
1196
|
+
return result;
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
(undefined && undefined.__rest) || function (s, e) {
|
|
1200
|
+
var t = {};
|
|
1201
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
1202
|
+
t[p] = s[p];
|
|
1203
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
1204
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
1205
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
1206
|
+
t[p[i]] = s[p[i]];
|
|
1207
|
+
}
|
|
1208
|
+
return t;
|
|
1209
|
+
};
|
|
1210
|
+
function cursorToIndex(state, value, index) {
|
|
1211
|
+
if (typeof index == "string") {
|
|
1212
|
+
if (/^-?[0-9]+@[0-9a-zA-Z]+$|^[se]$/.test(index)) {
|
|
1213
|
+
return state.handle.getCursorPosition(value, index);
|
|
1214
|
+
}
|
|
1215
|
+
else {
|
|
1216
|
+
throw new RangeError("index must be a number or cursor");
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
else {
|
|
1220
|
+
return index;
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
/**
|
|
1224
|
+
* Return the object ID of an arbitrary javascript value
|
|
1225
|
+
*
|
|
1226
|
+
* This is useful to determine if something is actually an automerge document,
|
|
1227
|
+
* if `doc` is not an automerge document this will return null.
|
|
1228
|
+
*/
|
|
1229
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1230
|
+
function getObjectId(doc, prop) {
|
|
1231
|
+
{
|
|
1232
|
+
return _obj(doc);
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
/**
|
|
1236
|
+
* Create a set of patches representing the change from one set of heads to another
|
|
1237
|
+
*
|
|
1238
|
+
* If either of the heads are missing from the document the returned set of patches will be empty
|
|
1239
|
+
*/
|
|
1240
|
+
function diff(doc, before, after) {
|
|
1241
|
+
checkHeads(before, "before");
|
|
1242
|
+
checkHeads(after, "after");
|
|
1243
|
+
const state = _state(doc);
|
|
1244
|
+
if (state.mostRecentPatch &&
|
|
1245
|
+
equals(state.mostRecentPatch.before, before) &&
|
|
1246
|
+
equals(state.mostRecentPatch.after, after)) {
|
|
1247
|
+
return state.mostRecentPatch.patches;
|
|
1248
|
+
}
|
|
1249
|
+
return state.handle.diff(before, after);
|
|
1250
|
+
}
|
|
1251
|
+
function checkHeads(heads, fieldname) {
|
|
1252
|
+
if (!Array.isArray(heads)) {
|
|
1253
|
+
throw new Error(`${fieldname} must be an array`);
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
/** @hidden */
|
|
1257
|
+
// FIXME : no tests
|
|
1258
|
+
// FIXME can we just use deep equals now?
|
|
1259
|
+
function equals(val1, val2) {
|
|
1260
|
+
if (!isObject(val1) || !isObject(val2))
|
|
1261
|
+
return val1 === val2;
|
|
1262
|
+
const keys1 = Object.keys(val1).sort(), keys2 = Object.keys(val2).sort();
|
|
1263
|
+
if (keys1.length !== keys2.length)
|
|
1264
|
+
return false;
|
|
1265
|
+
for (let i = 0; i < keys1.length; i++) {
|
|
1266
|
+
if (keys1[i] !== keys2[i])
|
|
1267
|
+
return false;
|
|
1268
|
+
if (!equals(val1[keys1[i]], val2[keys2[i]]))
|
|
1269
|
+
return false;
|
|
1270
|
+
}
|
|
1271
|
+
return true;
|
|
1272
|
+
}
|
|
1273
|
+
/**
|
|
1274
|
+
* Get the hashes of the heads of this document
|
|
1275
|
+
*/
|
|
1276
|
+
function getHeads(doc) {
|
|
1277
|
+
const state = _state(doc);
|
|
1278
|
+
return state.heads || state.handle.getHeads();
|
|
1279
|
+
}
|
|
1280
|
+
function isAutomerge(doc) {
|
|
1281
|
+
if (typeof doc == "object" && doc !== null) {
|
|
1282
|
+
return getObjectId(doc) === "_root" && !!Reflect.get(doc, STATE);
|
|
1283
|
+
}
|
|
1284
|
+
else {
|
|
1285
|
+
return false;
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
function isObject(obj) {
|
|
1289
|
+
return typeof obj === "object" && obj !== null;
|
|
1290
|
+
}
|
|
1291
|
+
/**
|
|
1292
|
+
* Modify a string
|
|
1293
|
+
*
|
|
1294
|
+
* @typeParam T - The type of the value contained in the document
|
|
1295
|
+
* @param doc - The document to modify
|
|
1296
|
+
* @param path - The path to the string to modify
|
|
1297
|
+
* @param index - The position (as a {@link Cursor} or index) to edit.
|
|
1298
|
+
* If a cursor is used then the edit happens such that the cursor will
|
|
1299
|
+
* now point to the end of the newText, so you can continue to reuse
|
|
1300
|
+
* the same cursor for multiple calls to splice.
|
|
1301
|
+
* @param del - The number of code units to delete, a positive number
|
|
1302
|
+
* deletes N characters after the cursor, a negative number deletes
|
|
1303
|
+
* N characters before the cursor.
|
|
1304
|
+
* @param newText - The string to insert (if any).
|
|
1305
|
+
*/
|
|
1306
|
+
function splice(doc, path, index, del, newText) {
|
|
1307
|
+
const objPath = absoluteObjPath(doc, path, "splice");
|
|
1308
|
+
if (!_is_proxy(doc)) {
|
|
1309
|
+
throw new RangeError("object cannot be modified outside of a change block");
|
|
1310
|
+
}
|
|
1311
|
+
const state = _state(doc, false);
|
|
1312
|
+
_clear_cache(doc);
|
|
1313
|
+
index = cursorToIndex(state, objPath, index);
|
|
1314
|
+
try {
|
|
1315
|
+
return state.handle.splice(objPath, index, del, newText);
|
|
1316
|
+
}
|
|
1317
|
+
catch (e) {
|
|
1318
|
+
throw new RangeError(`Cannot splice: ${e}`);
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
function mark(doc, path, range, name, value) {
|
|
1322
|
+
const objPath = absoluteObjPath(doc, path, "mark");
|
|
1323
|
+
if (!_is_proxy(doc)) {
|
|
1324
|
+
throw new RangeError("object cannot be modified outside of a change block");
|
|
1325
|
+
}
|
|
1326
|
+
const state = _state(doc, false);
|
|
1327
|
+
try {
|
|
1328
|
+
return state.handle.mark(objPath, range, name, value);
|
|
1329
|
+
}
|
|
1330
|
+
catch (e) {
|
|
1331
|
+
throw new RangeError(`Cannot mark: ${e}`);
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
function unmark(doc, path, range, name) {
|
|
1335
|
+
const objPath = absoluteObjPath(doc, path, "unmark");
|
|
1336
|
+
if (!_is_proxy(doc)) {
|
|
1337
|
+
throw new RangeError("object cannot be modified outside of a change block");
|
|
1338
|
+
}
|
|
1339
|
+
const state = _state(doc, false);
|
|
1340
|
+
try {
|
|
1341
|
+
return state.handle.unmark(objPath, range, name);
|
|
1342
|
+
}
|
|
1343
|
+
catch (e) {
|
|
1344
|
+
throw new RangeError(`Cannot unmark: ${e}`);
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
function absoluteObjPath(doc, path, functionName) {
|
|
1348
|
+
path = path.slice();
|
|
1349
|
+
const objectId = _obj(doc);
|
|
1350
|
+
if (!objectId) {
|
|
1351
|
+
throw new RangeError(`invalid object for ${functionName}`);
|
|
1352
|
+
}
|
|
1353
|
+
path.unshift(objectId);
|
|
1354
|
+
return path.join("/");
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
function autoproduce(payload) {
|
|
1358
|
+
return (doc) => applyPatches(doc, payload.patches);
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
const cache = /* @__PURE__ */ new WeakMap();
|
|
1362
|
+
function initial(handle) {
|
|
1363
|
+
const template = {};
|
|
1364
|
+
applyPatches(template, diff(handle.doc(), [], getHeads(handle.doc())));
|
|
1365
|
+
return template;
|
|
813
1366
|
}
|
|
814
|
-
function
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
}
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
const e = {};
|
|
827
|
-
return q(e, ve(t.doc(), [], Ie(t.doc()))), e;
|
|
828
|
-
}
|
|
829
|
-
function ke(t) {
|
|
830
|
-
if (Y(() => {
|
|
831
|
-
const n = d.get(t);
|
|
832
|
-
n && (n.refs-- || n.cleanup());
|
|
833
|
-
}), d.has(t)) {
|
|
834
|
-
const n = d.get(t);
|
|
835
|
-
return n.refs++, n.store;
|
|
1367
|
+
function makeDocumentProjection(handle) {
|
|
1368
|
+
onCleanup(() => {
|
|
1369
|
+
const item = cache.get(handle);
|
|
1370
|
+
if (!item) return;
|
|
1371
|
+
if (!item.refs--) {
|
|
1372
|
+
item.cleanup();
|
|
1373
|
+
}
|
|
1374
|
+
});
|
|
1375
|
+
if (cache.has(handle)) {
|
|
1376
|
+
const item = cache.get(handle);
|
|
1377
|
+
item.refs++;
|
|
1378
|
+
return item.store;
|
|
836
1379
|
}
|
|
837
|
-
const [
|
|
838
|
-
|
|
1380
|
+
const [doc, set] = createStore(initial(handle));
|
|
1381
|
+
cache.set(handle, {
|
|
839
1382
|
refs: 0,
|
|
840
|
-
store:
|
|
1383
|
+
store: doc,
|
|
841
1384
|
cleanup() {
|
|
842
|
-
|
|
1385
|
+
handle.off("change", patch);
|
|
1386
|
+
handle.off("delete", ondelete);
|
|
1387
|
+
cache.delete(handle);
|
|
843
1388
|
}
|
|
844
1389
|
});
|
|
845
|
-
function
|
|
846
|
-
|
|
1390
|
+
function patch(payload) {
|
|
1391
|
+
set(produce(autoproduce(payload)));
|
|
847
1392
|
}
|
|
848
|
-
function
|
|
849
|
-
|
|
1393
|
+
function ondelete() {
|
|
1394
|
+
set(reconcile({}));
|
|
850
1395
|
}
|
|
851
|
-
|
|
1396
|
+
handle.on("change", patch);
|
|
1397
|
+
handle.on("delete", ondelete);
|
|
1398
|
+
return doc;
|
|
852
1399
|
}
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
1400
|
+
|
|
1401
|
+
function createDocumentProjection(handle) {
|
|
1402
|
+
const projection = createMemo(() => {
|
|
1403
|
+
const unwrappedHandle = typeof handle == "function" ? handle() : handle;
|
|
1404
|
+
return unwrappedHandle && makeDocumentProjection(unwrappedHandle);
|
|
857
1405
|
});
|
|
1406
|
+
return projection;
|
|
858
1407
|
}
|
|
859
|
-
|
|
1408
|
+
|
|
1409
|
+
const RepoContext = createContext(
|
|
860
1410
|
null
|
|
861
|
-
)
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
1411
|
+
);
|
|
1412
|
+
|
|
1413
|
+
const readyStates = ["ready", "deleted", "unavailable"];
|
|
1414
|
+
const badStates = ["deleted", "unavailable"];
|
|
1415
|
+
function useDocHandle(url, options) {
|
|
1416
|
+
const contextRepo = useContext(RepoContext);
|
|
1417
|
+
if (!options?.repo && !contextRepo) {
|
|
865
1418
|
throw new Error("use outside <RepoContext> requires options.repo");
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
1419
|
+
}
|
|
1420
|
+
const repo = options?.repo || contextRepo;
|
|
1421
|
+
function getExistingHandle() {
|
|
1422
|
+
if (options?.["~skipInitialValue"]) return void 0;
|
|
1423
|
+
const unwrappedURL = typeof url == "function" ? url() : url;
|
|
1424
|
+
if (!unwrappedURL) return void 0;
|
|
1425
|
+
try {
|
|
1426
|
+
const documentId = new URL(unwrappedURL).pathname;
|
|
1427
|
+
const existingHandle = repo.handles[documentId];
|
|
1428
|
+
if (existingHandle?.isReady()) {
|
|
1429
|
+
return existingHandle;
|
|
877
1430
|
}
|
|
1431
|
+
} catch (error) {
|
|
1432
|
+
console.error("Error parsing URL:", error);
|
|
1433
|
+
}
|
|
878
1434
|
}
|
|
879
|
-
const [
|
|
880
|
-
|
|
881
|
-
async (
|
|
882
|
-
const
|
|
883
|
-
allowableStates:
|
|
884
|
-
})
|
|
885
|
-
|
|
1435
|
+
const [handle, { mutate }] = createResource(
|
|
1436
|
+
url,
|
|
1437
|
+
async (url2) => {
|
|
1438
|
+
const handle2 = await repo.find(url2, {
|
|
1439
|
+
allowableStates: readyStates
|
|
1440
|
+
});
|
|
1441
|
+
const reject = (state) => Promise.reject(new Error(`document not available: [${state}]`));
|
|
1442
|
+
if (handle2.isReady()) {
|
|
1443
|
+
return handle2;
|
|
1444
|
+
} else if (handle2.inState(badStates)) {
|
|
1445
|
+
return reject(handle2.state);
|
|
1446
|
+
}
|
|
1447
|
+
return handle2.whenReady(readyStates).then(() => {
|
|
1448
|
+
if (handle2.isReady()) {
|
|
1449
|
+
return handle2;
|
|
1450
|
+
}
|
|
1451
|
+
return reject(handle2.state);
|
|
1452
|
+
});
|
|
886
1453
|
},
|
|
887
1454
|
{
|
|
888
|
-
initialValue:
|
|
1455
|
+
initialValue: getExistingHandle()
|
|
889
1456
|
}
|
|
890
1457
|
);
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
return
|
|
898
|
-
}
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
return
|
|
903
|
-
}
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
1458
|
+
createEffect(() => {
|
|
1459
|
+
const unwrappedURL = typeof url == "function" ? url() : url;
|
|
1460
|
+
if (!unwrappedURL) {
|
|
1461
|
+
mutate();
|
|
1462
|
+
}
|
|
1463
|
+
});
|
|
1464
|
+
return handle;
|
|
1465
|
+
}
|
|
1466
|
+
|
|
1467
|
+
function useDocument(url, options) {
|
|
1468
|
+
const handle = useDocHandle(url, options);
|
|
1469
|
+
return [createDocumentProjection(handle), handle];
|
|
1470
|
+
}
|
|
1471
|
+
|
|
1472
|
+
function useRepo() {
|
|
1473
|
+
const repo = useContext(RepoContext);
|
|
1474
|
+
if (!repo) throw new Error("Please wrap me in a <RepoContext value={repo}>");
|
|
1475
|
+
return repo;
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
export { RepoContext, autoproduce, createDocumentProjection, makeDocumentProjection, useDocHandle, useDocument, useRepo };
|
|
1479
|
+
//# sourceMappingURL=index.js.map
|