loro-crdt 0.13.0 → 0.14.0
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/CHANGELOG.md +43 -0
- package/dist/loro.d.ts +206 -35
- package/dist/loro.js +0 -28
- package/dist/loro.js.map +1 -1
- package/dist/loro.mjs +0 -29
- package/dist/loro.mjs.map +1 -1
- package/dist/src/index.js +106 -0
- package/dist/tests/basic.test.js +415 -0
- package/dist/tests/checkout.test.js +76 -0
- package/dist/tests/event.test.js +345 -0
- package/dist/tests/issue.test.js +59 -0
- package/dist/tests/misc.test.js +245 -0
- package/dist/tests/richtext.test.js +197 -0
- package/dist/tests/type.test.js +22 -0
- package/dist/tests/version.test.js +185 -0
- package/dist/vite.config.js +14 -0
- package/package.json +3 -3
- package/src/index.ts +227 -72
- package/tsconfig.json +2 -2
package/src/index.ts
CHANGED
|
@@ -8,41 +8,11 @@ import {
|
|
|
8
8
|
LoroMap,
|
|
9
9
|
LoroText,
|
|
10
10
|
LoroTree,
|
|
11
|
-
LoroTreeNode,
|
|
12
11
|
OpId,
|
|
13
12
|
TreeID,
|
|
14
13
|
Value,
|
|
15
14
|
} from "loro-wasm";
|
|
16
15
|
|
|
17
|
-
Loro.prototype.getTypedMap = function (...args) {
|
|
18
|
-
return this.getMap(...args);
|
|
19
|
-
};
|
|
20
|
-
Loro.prototype.getTypedList = function (...args) {
|
|
21
|
-
return this.getList(...args);
|
|
22
|
-
};
|
|
23
|
-
LoroList.prototype.getTyped = function (loro, index) {
|
|
24
|
-
const value = this.get(index);
|
|
25
|
-
if (typeof value === "string" && isContainerId(value)) {
|
|
26
|
-
return loro.getContainerById(value);
|
|
27
|
-
} else {
|
|
28
|
-
return value;
|
|
29
|
-
}
|
|
30
|
-
};
|
|
31
|
-
LoroList.prototype.insertTyped = function (...args) {
|
|
32
|
-
return this.insert(...args);
|
|
33
|
-
};
|
|
34
|
-
LoroMap.prototype.getTyped = function (loro, key) {
|
|
35
|
-
const value = this.get(key);
|
|
36
|
-
if (typeof value === "string" && isContainerId(value)) {
|
|
37
|
-
return loro.getContainerById(value);
|
|
38
|
-
} else {
|
|
39
|
-
return value;
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
LoroMap.prototype.setTyped = function (...args) {
|
|
43
|
-
return this.set(...args);
|
|
44
|
-
};
|
|
45
|
-
|
|
46
16
|
export type Frontiers = OpId[];
|
|
47
17
|
|
|
48
18
|
/**
|
|
@@ -56,18 +26,21 @@ export type Path = (number | string | TreeID)[];
|
|
|
56
26
|
/**
|
|
57
27
|
* A batch of events that created by a single `import`/`transaction`/`checkout`.
|
|
58
28
|
*
|
|
59
|
-
* @prop
|
|
29
|
+
* @prop by - How the event is triggered.
|
|
60
30
|
* @prop origin - (Optional) Provides information about the origin of the event.
|
|
61
31
|
* @prop diff - Contains the differential information related to the event.
|
|
62
32
|
* @prop target - Identifies the container ID of the event's target.
|
|
63
33
|
* @prop path - Specifies the absolute path of the event's emitter, which can be an index of a list container or a key of a map container.
|
|
64
34
|
*/
|
|
65
35
|
export interface LoroEventBatch {
|
|
66
|
-
local: boolean;
|
|
67
36
|
/**
|
|
68
|
-
*
|
|
37
|
+
* How the event is triggered.
|
|
38
|
+
*
|
|
39
|
+
* - `local`: The event is triggered by a local transaction.
|
|
40
|
+
* - `import`: The event is triggered by an import operation.
|
|
41
|
+
* - `checkout`: The event is triggered by a checkout operation.
|
|
69
42
|
*/
|
|
70
|
-
|
|
43
|
+
by: "local" | "import" | "checkout";
|
|
71
44
|
origin?: string;
|
|
72
45
|
/**
|
|
73
46
|
* The container ID of the current event receiver.
|
|
@@ -180,12 +153,12 @@ export function isContainer(value: any): value is Container {
|
|
|
180
153
|
export function getType<T>(
|
|
181
154
|
value: T,
|
|
182
155
|
): T extends LoroText ? "Text"
|
|
183
|
-
: T extends LoroMap ? "Map"
|
|
184
|
-
: T extends LoroTree ? "Tree"
|
|
185
|
-
: T extends LoroList ? "List"
|
|
156
|
+
: T extends LoroMap<any> ? "Map"
|
|
157
|
+
: T extends LoroTree<any> ? "Tree"
|
|
158
|
+
: T extends LoroList<any> ? "List"
|
|
186
159
|
: "Json" {
|
|
187
160
|
if (isContainer(value)) {
|
|
188
|
-
return value.kind();
|
|
161
|
+
return value.kind() as unknown as any;
|
|
189
162
|
}
|
|
190
163
|
|
|
191
164
|
return "Json" as any;
|
|
@@ -196,52 +169,227 @@ declare module "loro-wasm" {
|
|
|
196
169
|
subscribe(listener: Listener): number;
|
|
197
170
|
}
|
|
198
171
|
|
|
199
|
-
interface Loro<
|
|
200
|
-
|
|
172
|
+
interface Loro<
|
|
173
|
+
T extends Record<string, Container> = Record<string, Container>,
|
|
174
|
+
> {
|
|
175
|
+
/**
|
|
176
|
+
* Get a LoroMap by container id
|
|
177
|
+
*
|
|
178
|
+
* The object returned is a new js object each time because it need to cross
|
|
179
|
+
* the WASM boundary.
|
|
180
|
+
*
|
|
181
|
+
* @example
|
|
182
|
+
* ```ts
|
|
183
|
+
* import { Loro } from "loro-crdt";
|
|
184
|
+
*
|
|
185
|
+
* const doc = new Loro();
|
|
186
|
+
* const map = doc.getMap("map");
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
getMap<Key extends keyof T>(
|
|
201
190
|
name: Key,
|
|
202
|
-
): T[Key] extends LoroMap ? T[Key] :
|
|
203
|
-
|
|
191
|
+
): T[Key] extends LoroMap ? T[Key] : LoroMap;
|
|
192
|
+
/**
|
|
193
|
+
* Get a LoroList by container id
|
|
194
|
+
*
|
|
195
|
+
* The object returned is a new js object each time because it need to cross
|
|
196
|
+
* the WASM boundary.
|
|
197
|
+
*
|
|
198
|
+
* @example
|
|
199
|
+
* ```ts
|
|
200
|
+
* import { Loro } from "loro-crdt";
|
|
201
|
+
*
|
|
202
|
+
* const doc = new Loro();
|
|
203
|
+
* const list = doc.getList("list");
|
|
204
|
+
* ```
|
|
205
|
+
*/
|
|
206
|
+
getList<Key extends keyof T>(
|
|
204
207
|
name: Key,
|
|
205
|
-
): T[Key] extends LoroList ? T[Key] :
|
|
208
|
+
): T[Key] extends LoroList ? T[Key] : LoroList;
|
|
209
|
+
/**
|
|
210
|
+
* Get a LoroTree by container id
|
|
211
|
+
*
|
|
212
|
+
* The object returned is a new js object each time because it need to cross
|
|
213
|
+
* the WASM boundary.
|
|
214
|
+
*
|
|
215
|
+
* @example
|
|
216
|
+
* ```ts
|
|
217
|
+
* import { Loro } from "loro-crdt";
|
|
218
|
+
*
|
|
219
|
+
* const doc = new Loro();
|
|
220
|
+
* const tree = doc.getTree("tree");
|
|
221
|
+
* ```
|
|
222
|
+
*/
|
|
223
|
+
getTree<Key extends keyof T>(
|
|
224
|
+
name: Key,
|
|
225
|
+
): T[Key] extends LoroTree ? T[Key] : LoroTree;
|
|
226
|
+
getText(key: string | ContainerID): LoroText;
|
|
206
227
|
}
|
|
207
228
|
|
|
208
|
-
interface LoroList<T
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
229
|
+
interface LoroList<T = unknown> {
|
|
230
|
+
new (): LoroList<T>;
|
|
231
|
+
/**
|
|
232
|
+
* Get elements of the list. If the value is a child container, the corresponding
|
|
233
|
+
* `Container` will be returned.
|
|
234
|
+
*
|
|
235
|
+
* @example
|
|
236
|
+
* ```ts
|
|
237
|
+
* import { Loro } from "loro-crdt";
|
|
238
|
+
*
|
|
239
|
+
* const doc = new Loro();
|
|
240
|
+
* const list = doc.getList("list");
|
|
241
|
+
* list.insert(0, 100);
|
|
242
|
+
* list.insert(1, "foo");
|
|
243
|
+
* list.insert(2, true);
|
|
244
|
+
* list.insertContainer(3, new LoroText());
|
|
245
|
+
* console.log(list.value); // [100, "foo", true, LoroText];
|
|
246
|
+
* ```
|
|
247
|
+
*/
|
|
248
|
+
toArray(): T[];
|
|
249
|
+
/**
|
|
250
|
+
* Insert a container at the index.
|
|
251
|
+
*
|
|
252
|
+
* @example
|
|
253
|
+
* ```ts
|
|
254
|
+
* import { Loro } from "loro-crdt";
|
|
255
|
+
*
|
|
256
|
+
* const doc = new Loro();
|
|
257
|
+
* const list = doc.getList("list");
|
|
258
|
+
* list.insert(0, 100);
|
|
259
|
+
* const text = list.insertContainer(1, new LoroText());
|
|
260
|
+
* text.insert(0, "Hello");
|
|
261
|
+
* console.log(list.getDeepValue()); // [100, "Hello"];
|
|
262
|
+
* ```
|
|
263
|
+
*/
|
|
264
|
+
insertContainer<C extends Container>(
|
|
265
|
+
pos: number,
|
|
266
|
+
child: C,
|
|
267
|
+
): T extends C ? T : C;
|
|
268
|
+
/**
|
|
269
|
+
* Get the value at the index. If the value is a container, the corresponding handler will be returned.
|
|
270
|
+
*
|
|
271
|
+
* @example
|
|
272
|
+
* ```ts
|
|
273
|
+
* import { Loro } from "loro-crdt";
|
|
274
|
+
*
|
|
275
|
+
* const doc = new Loro();
|
|
276
|
+
* const list = doc.getList("list");
|
|
277
|
+
* list.insert(0, 100);
|
|
278
|
+
* console.log(list.get(0)); // 100
|
|
279
|
+
* console.log(list.get(1)); // undefined
|
|
280
|
+
* ```
|
|
281
|
+
*/
|
|
282
|
+
get(index: number): T;
|
|
283
|
+
/**
|
|
284
|
+
* Insert a value at index.
|
|
285
|
+
*
|
|
286
|
+
* @example
|
|
287
|
+
* ```ts
|
|
288
|
+
* import { Loro } from "loro-crdt";
|
|
289
|
+
*
|
|
290
|
+
* const doc = new Loro();
|
|
291
|
+
* const list = doc.getList("list");
|
|
292
|
+
* list.insert(0, 100);
|
|
293
|
+
* list.insert(1, "foo");
|
|
294
|
+
* list.insert(2, true);
|
|
295
|
+
* console.log(list.value); // [100, "foo", true];
|
|
296
|
+
* ```
|
|
297
|
+
*/
|
|
298
|
+
insert(pos: number, value: Exclude<T, Container>): void;
|
|
216
299
|
delete(pos: number, len: number): void;
|
|
217
300
|
subscribe(txn: Loro, listener: Listener): number;
|
|
301
|
+
getAttached(): undefined | LoroList<T>;
|
|
218
302
|
}
|
|
219
303
|
|
|
220
|
-
interface LoroMap<
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
304
|
+
interface LoroMap<
|
|
305
|
+
T extends Record<string, unknown> = Record<string, unknown>,
|
|
306
|
+
> {
|
|
307
|
+
new (): LoroMap<T>;
|
|
308
|
+
/**
|
|
309
|
+
* Get the value of the key. If the value is a child container, the corresponding
|
|
310
|
+
* `Container` will be returned.
|
|
311
|
+
*
|
|
312
|
+
* The object returned is a new js object each time because it need to cross
|
|
313
|
+
*
|
|
314
|
+
* @example
|
|
315
|
+
* ```ts
|
|
316
|
+
* import { Loro } from "loro-crdt";
|
|
317
|
+
*
|
|
318
|
+
* const doc = new Loro();
|
|
319
|
+
* const map = doc.getMap("map");
|
|
320
|
+
* map.set("foo", "bar");
|
|
321
|
+
* const bar = map.get("foo");
|
|
322
|
+
* ```
|
|
323
|
+
*/
|
|
324
|
+
getOrCreateContainer<C extends Container>(key: string, child: C): C;
|
|
325
|
+
/**
|
|
326
|
+
* Set the key with a container.
|
|
327
|
+
*
|
|
328
|
+
* @example
|
|
329
|
+
* ```ts
|
|
330
|
+
* import { Loro } from "loro-crdt";
|
|
331
|
+
*
|
|
332
|
+
* const doc = new Loro();
|
|
333
|
+
* const map = doc.getMap("map");
|
|
334
|
+
* map.set("foo", "bar");
|
|
335
|
+
* const text = map.setContainer("text", new LoroText());
|
|
336
|
+
* const list = map.setContainer("list", new LoroText());
|
|
337
|
+
* ```
|
|
338
|
+
*/
|
|
339
|
+
setContainer<C extends Container, Key extends keyof T>(
|
|
340
|
+
key: Key,
|
|
341
|
+
child: C,
|
|
342
|
+
): NonNullableType<T[Key]> extends C ? NonNullableType<T[Key]> : C;
|
|
343
|
+
/**
|
|
344
|
+
* Get the value of the key. If the value is a child container, the corresponding
|
|
345
|
+
* `Container` will be returned.
|
|
346
|
+
*
|
|
347
|
+
* The object/value returned is a new js object/value each time because it need to cross
|
|
348
|
+
* the WASM boundary.
|
|
349
|
+
*
|
|
350
|
+
* @example
|
|
351
|
+
* ```ts
|
|
352
|
+
* import { Loro } from "loro-crdt";
|
|
353
|
+
*
|
|
354
|
+
* const doc = new Loro();
|
|
355
|
+
* const map = doc.getMap("map");
|
|
356
|
+
* map.set("foo", "bar");
|
|
357
|
+
* const bar = map.get("foo");
|
|
358
|
+
* ```
|
|
359
|
+
*/
|
|
360
|
+
get<Key extends keyof T>(key: Key): T[Key];
|
|
361
|
+
/**
|
|
362
|
+
* Set the key with the value.
|
|
363
|
+
*
|
|
364
|
+
* If the value of the key is exist, the old value will be updated.
|
|
365
|
+
*
|
|
366
|
+
* @example
|
|
367
|
+
* ```ts
|
|
368
|
+
* import { Loro } from "loro-crdt";
|
|
369
|
+
*
|
|
370
|
+
* const doc = new Loro();
|
|
371
|
+
* const map = doc.getMap("map");
|
|
372
|
+
* map.set("foo", "bar");
|
|
373
|
+
* map.set("foo", "baz");
|
|
374
|
+
* ```
|
|
375
|
+
*/
|
|
376
|
+
set<Key extends keyof T>(key: Key, value: Exclude<T[Key], Container>): void;
|
|
233
377
|
delete(key: string): void;
|
|
234
378
|
subscribe(txn: Loro, listener: Listener): number;
|
|
235
379
|
}
|
|
236
380
|
|
|
237
381
|
interface LoroText {
|
|
382
|
+
new (): LoroText;
|
|
238
383
|
insert(pos: number, text: string): void;
|
|
239
384
|
delete(pos: number, len: number): void;
|
|
240
385
|
subscribe(txn: Loro, listener: Listener): number;
|
|
241
386
|
}
|
|
242
387
|
|
|
243
|
-
interface LoroTree
|
|
244
|
-
|
|
388
|
+
interface LoroTree<
|
|
389
|
+
T extends Record<string, unknown> = Record<string, unknown>,
|
|
390
|
+
> {
|
|
391
|
+
new (): LoroTree<T>;
|
|
392
|
+
createNode(parent: TreeID | undefined): LoroTreeNode<T>;
|
|
245
393
|
move(target: TreeID, parent: TreeID | undefined): void;
|
|
246
394
|
delete(target: TreeID): void;
|
|
247
395
|
has(target: TreeID): boolean;
|
|
@@ -249,12 +397,19 @@ declare module "loro-wasm" {
|
|
|
249
397
|
subscribe(txn: Loro, listener: Listener): number;
|
|
250
398
|
}
|
|
251
399
|
|
|
252
|
-
interface LoroTreeNode
|
|
253
|
-
|
|
254
|
-
|
|
400
|
+
interface LoroTreeNode<
|
|
401
|
+
T extends Record<string, unknown> = Record<string, unknown>,
|
|
402
|
+
> {
|
|
403
|
+
/**
|
|
404
|
+
* Get the associated metadata map container of a tree node.
|
|
405
|
+
*/
|
|
406
|
+
readonly data: LoroMap<T>;
|
|
407
|
+
createNode(): LoroTreeNode<T>;
|
|
255
408
|
setAsRoot(): void;
|
|
256
|
-
moveTo(parent: LoroTreeNode): void;
|
|
257
|
-
parent(): LoroTreeNode | undefined;
|
|
258
|
-
children(): Array<LoroTreeNode
|
|
409
|
+
moveTo(parent: LoroTreeNode<T>): void;
|
|
410
|
+
parent(): LoroTreeNode<T> | undefined;
|
|
411
|
+
children(): Array<LoroTreeNode<T>>;
|
|
259
412
|
}
|
|
260
413
|
}
|
|
414
|
+
|
|
415
|
+
type NonNullableType<T> = Exclude<T, null | undefined>;
|
package/tsconfig.json
CHANGED
|
@@ -50,9 +50,9 @@
|
|
|
50
50
|
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
|
|
51
51
|
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
|
|
52
52
|
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
|
|
53
|
-
"outDir": "./dist"
|
|
53
|
+
"outDir": "./dist" /* Specify an output folder for all emitted files. */,
|
|
54
54
|
// "removeComments": true, /* Disable emitting comments. */
|
|
55
|
-
|
|
55
|
+
"noEmit": true /* Disable emitting files from a compilation. */,
|
|
56
56
|
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
|
|
57
57
|
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
|
|
58
58
|
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
|