@pluv/crdt-loro 0.16.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/.eslintrc.js +4 -0
- package/.turbo/turbo-build.log +18 -0
- package/CHANGELOG.md +8 -0
- package/LICENSE +21 -0
- package/dist/index.d.mts +164 -0
- package/dist/index.d.ts +164 -0
- package/dist/index.js +701 -0
- package/dist/index.mjs +681 -0
- package/package.json +41 -0
- package/src/array/CrdtLoroArray.ts +102 -0
- package/src/array/array.ts +7 -0
- package/src/array/index.ts +2 -0
- package/src/doc/CrdtLoroDoc.ts +239 -0
- package/src/doc/CrdtLoroDocFactory.ts +65 -0
- package/src/doc/doc.ts +10 -0
- package/src/doc/index.ts +3 -0
- package/src/index.ts +1 -0
- package/src/loro.ts +6 -0
- package/src/map/CrdtLoroMap.ts +90 -0
- package/src/map/index.ts +2 -0
- package/src/map/map.ts +7 -0
- package/src/object/CrdtLoroObject.ts +79 -0
- package/src/object/index.ts +2 -0
- package/src/object/object.ts +7 -0
- package/src/shared/cloneType.ts +238 -0
- package/src/shared/getLoroContainerType.ts +22 -0
- package/src/shared/index.ts +5 -0
- package/src/shared/isWrapper.ts +19 -0
- package/src/shared/toLoroValue.ts +5 -0
- package/src/text/CrdtLoroText.ts +68 -0
- package/src/text/index.ts +2 -0
- package/src/text/text.ts +5 -0
- package/src/types.ts +40 -0
- package/tsconfig.json +8 -0
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import { AbstractCrdtType } from "@pluv/crdt";
|
|
2
|
+
import type { Container } from "loro-crdt";
|
|
3
|
+
import { LoroList, LoroMap, LoroText } from "loro-crdt";
|
|
4
|
+
import { CrdtLoroArray } from "../array";
|
|
5
|
+
import { CrdtLoroMap } from "../map";
|
|
6
|
+
import { CrdtLoroObject } from "../object";
|
|
7
|
+
import { CrdtLoroText } from "../text";
|
|
8
|
+
|
|
9
|
+
interface CloneArrayParams<T extends unknown> {
|
|
10
|
+
source: CrdtLoroArray<T>;
|
|
11
|
+
target: LoroList<T[]>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface CloneMapParams<T extends unknown> {
|
|
15
|
+
source: CrdtLoroMap<T>;
|
|
16
|
+
target: LoroMap<Record<string, T>>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface CloneObjectParams<T extends Record<string, any>> {
|
|
20
|
+
source: CrdtLoroObject<T>;
|
|
21
|
+
target: LoroMap<T>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface CloneTextParams {
|
|
25
|
+
source: CrdtLoroText;
|
|
26
|
+
target: LoroText;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
type SourceType<TType extends Container> =
|
|
30
|
+
TType extends LoroList<(infer I)[]>
|
|
31
|
+
? CrdtLoroArray<I>
|
|
32
|
+
: TType extends LoroMap<infer I>
|
|
33
|
+
? CrdtLoroMap<I[keyof I]> | CrdtLoroObject<I>
|
|
34
|
+
: TType extends LoroText
|
|
35
|
+
? CrdtLoroText
|
|
36
|
+
: never;
|
|
37
|
+
|
|
38
|
+
export interface CloneTypeParams<TType extends Container> {
|
|
39
|
+
source: SourceType<TType>;
|
|
40
|
+
target: TType;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function cloneArray<T extends unknown>(params: CloneArrayParams<T>): void {
|
|
44
|
+
const { source, target } = params;
|
|
45
|
+
|
|
46
|
+
const items = source.initialValue;
|
|
47
|
+
|
|
48
|
+
items.forEach((item, i) => {
|
|
49
|
+
if (!(item instanceof AbstractCrdtType)) {
|
|
50
|
+
target.insert(i, item);
|
|
51
|
+
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (item instanceof CrdtLoroArray) {
|
|
56
|
+
const list = target.insertContainer(i, "List");
|
|
57
|
+
|
|
58
|
+
item.value = list;
|
|
59
|
+
cloneArray({ source: item, target: list });
|
|
60
|
+
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (item instanceof CrdtLoroMap) {
|
|
65
|
+
const map = target.insertContainer(i, "Map");
|
|
66
|
+
|
|
67
|
+
item.value = map;
|
|
68
|
+
cloneMap({ source: item, target: map });
|
|
69
|
+
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (item instanceof CrdtLoroObject) {
|
|
74
|
+
const map = target.insertContainer(i, "Map");
|
|
75
|
+
|
|
76
|
+
item.value = map;
|
|
77
|
+
cloneObject({ source: item, target: map });
|
|
78
|
+
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (item instanceof CrdtLoroText) {
|
|
83
|
+
const text = target.insertContainer(i, "Text");
|
|
84
|
+
|
|
85
|
+
item.value = text;
|
|
86
|
+
cloneText({ source: item, target: text });
|
|
87
|
+
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
throw new Error("This type is not yet supported");
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function cloneMap<T extends unknown>(params: CloneMapParams<T>): void {
|
|
96
|
+
const { source, target } = params;
|
|
97
|
+
|
|
98
|
+
const items = source.initialValue;
|
|
99
|
+
|
|
100
|
+
items.forEach(([key, item]) => {
|
|
101
|
+
if (!(item instanceof AbstractCrdtType)) {
|
|
102
|
+
target.set(key, item);
|
|
103
|
+
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (item instanceof CrdtLoroArray) {
|
|
108
|
+
const list = target.setContainer(key, "List");
|
|
109
|
+
|
|
110
|
+
item.value = list;
|
|
111
|
+
cloneArray({ source: item, target: list });
|
|
112
|
+
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (item instanceof CrdtLoroMap) {
|
|
117
|
+
const map = target.setContainer(key, "Map");
|
|
118
|
+
|
|
119
|
+
item.value = map;
|
|
120
|
+
cloneMap({ source: item, target: map });
|
|
121
|
+
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (item instanceof CrdtLoroObject) {
|
|
126
|
+
const map = target.setContainer(key, "Map");
|
|
127
|
+
|
|
128
|
+
item.value = map;
|
|
129
|
+
cloneObject({ source: item, target: map });
|
|
130
|
+
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (item instanceof CrdtLoroText) {
|
|
135
|
+
const text = target.setContainer(key, "Text");
|
|
136
|
+
|
|
137
|
+
item.value = text;
|
|
138
|
+
cloneText({ source: item, target: text });
|
|
139
|
+
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
throw new Error("This type is not yet supported");
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function cloneObject<T extends Record<string, any>>(
|
|
148
|
+
params: CloneObjectParams<T>,
|
|
149
|
+
): void {
|
|
150
|
+
const { source, target } = params;
|
|
151
|
+
|
|
152
|
+
const items = source.initialValue;
|
|
153
|
+
|
|
154
|
+
items.forEach(([key, item]) => {
|
|
155
|
+
if (!(item instanceof AbstractCrdtType)) {
|
|
156
|
+
target.set(key, item);
|
|
157
|
+
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (item instanceof CrdtLoroArray) {
|
|
162
|
+
const list = target.setContainer(key, "List");
|
|
163
|
+
|
|
164
|
+
item.value = list;
|
|
165
|
+
cloneArray({ source: item, target: list });
|
|
166
|
+
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (item instanceof CrdtLoroMap) {
|
|
171
|
+
const map = target.setContainer(key, "Map");
|
|
172
|
+
|
|
173
|
+
item.value = map;
|
|
174
|
+
cloneMap({ source: item, target: map });
|
|
175
|
+
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (item instanceof CrdtLoroObject) {
|
|
180
|
+
const map = target.setContainer(key, "Map");
|
|
181
|
+
|
|
182
|
+
item.value = map;
|
|
183
|
+
cloneObject({ source: item, target: map });
|
|
184
|
+
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (item instanceof CrdtLoroText) {
|
|
189
|
+
const text = target.setContainer(key, "Text");
|
|
190
|
+
|
|
191
|
+
item.value = text;
|
|
192
|
+
cloneText({ source: item, target: text });
|
|
193
|
+
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
throw new Error("This type is not yet supported");
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function cloneText(params: CloneTextParams): void {
|
|
202
|
+
const { source, target } = params;
|
|
203
|
+
|
|
204
|
+
source.value = target;
|
|
205
|
+
source.insert(0, source.initalValue);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export const cloneType = <TType extends Container>(
|
|
209
|
+
params: CloneTypeParams<TType>,
|
|
210
|
+
) => {
|
|
211
|
+
const { source, target } = params;
|
|
212
|
+
|
|
213
|
+
if (source instanceof CrdtLoroArray) {
|
|
214
|
+
cloneArray({ source, target: target as LoroList });
|
|
215
|
+
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (source instanceof CrdtLoroMap) {
|
|
220
|
+
cloneMap({ source, target: target as LoroMap });
|
|
221
|
+
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (source instanceof CrdtLoroObject) {
|
|
226
|
+
cloneObject({ source, target: target as LoroMap });
|
|
227
|
+
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (source instanceof CrdtLoroText) {
|
|
232
|
+
cloneText({ source, target: target as LoroText });
|
|
233
|
+
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
throw new Error("This type is not yet supported");
|
|
238
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { AbstractCrdtType } from "@pluv/crdt";
|
|
2
|
+
import { CrdtLoroArray } from "../array";
|
|
3
|
+
import { CrdtLoroMap } from "../map";
|
|
4
|
+
import { CrdtLoroObject } from "../object";
|
|
5
|
+
import { CrdtLoroText } from "../text";
|
|
6
|
+
|
|
7
|
+
export const getLoroContainerType = <T extends AbstractCrdtType<any, any>>(
|
|
8
|
+
value: T,
|
|
9
|
+
): T extends CrdtLoroArray<any>
|
|
10
|
+
? "List"
|
|
11
|
+
: T extends CrdtLoroMap<any> | CrdtLoroObject<any>
|
|
12
|
+
? "Map"
|
|
13
|
+
: T extends CrdtLoroText
|
|
14
|
+
? "Text"
|
|
15
|
+
: never => {
|
|
16
|
+
if (value instanceof CrdtLoroArray) return "List" as any;
|
|
17
|
+
if (value instanceof CrdtLoroMap) return "Map" as any;
|
|
18
|
+
if (value instanceof CrdtLoroObject) return "Map" as any;
|
|
19
|
+
if (value instanceof CrdtLoroText) return "Text" as any;
|
|
20
|
+
|
|
21
|
+
throw new Error("This type is not yet supported");
|
|
22
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { CrdtLoroArray } from "../array/CrdtLoroArray";
|
|
2
|
+
import { CrdtLoroMap } from "../map/CrdtLoroMap";
|
|
3
|
+
import { CrdtLoroObject } from "../object/CrdtLoroObject";
|
|
4
|
+
import { CrdtLoroText } from "../text/CrdtLoroText";
|
|
5
|
+
|
|
6
|
+
export const isWrapper = (
|
|
7
|
+
item: any,
|
|
8
|
+
): item is
|
|
9
|
+
| CrdtLoroArray<any>
|
|
10
|
+
| CrdtLoroMap<any>
|
|
11
|
+
| CrdtLoroObject<any>
|
|
12
|
+
| CrdtLoroText => {
|
|
13
|
+
return (
|
|
14
|
+
item instanceof CrdtLoroArray ||
|
|
15
|
+
item instanceof CrdtLoroMap ||
|
|
16
|
+
item instanceof CrdtLoroObject ||
|
|
17
|
+
item instanceof CrdtLoroText
|
|
18
|
+
);
|
|
19
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { AbstractCrdtType } from "@pluv/crdt";
|
|
2
|
+
import { LoroText } from "loro-crdt";
|
|
3
|
+
import type { CrdtLoroDoc } from "../doc/CrdtLoroDoc";
|
|
4
|
+
import { cloneType } from "../shared";
|
|
5
|
+
|
|
6
|
+
export class CrdtLoroText extends AbstractCrdtType<LoroText, string> {
|
|
7
|
+
public initalValue: string;
|
|
8
|
+
|
|
9
|
+
private _doc: CrdtLoroDoc<any> | null = null;
|
|
10
|
+
private _initialized: boolean = false;
|
|
11
|
+
private _value: LoroText = new LoroText();
|
|
12
|
+
|
|
13
|
+
constructor(value: string = "") {
|
|
14
|
+
super();
|
|
15
|
+
|
|
16
|
+
this.initalValue = value;
|
|
17
|
+
this.value = new LoroText();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
public set doc(doc: CrdtLoroDoc<any>) {
|
|
21
|
+
if (this._doc) throw new Error("Cannot overwrite array doc");
|
|
22
|
+
|
|
23
|
+
this._doc = doc;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public get length(): number {
|
|
27
|
+
return this.value.length;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public get value(): LoroText {
|
|
31
|
+
return this._value;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public set value(value: LoroText) {
|
|
35
|
+
if (this._initialized) throw new Error("Cannot re-assign text");
|
|
36
|
+
|
|
37
|
+
this._initialized = true;
|
|
38
|
+
this._value = value;
|
|
39
|
+
|
|
40
|
+
cloneType({ source: this, target: this.value });
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
public delete(index: number, length: number = 1): this {
|
|
44
|
+
this._guardInitialized();
|
|
45
|
+
|
|
46
|
+
this.value.delete(index, length);
|
|
47
|
+
this._doc?.value.commit();
|
|
48
|
+
|
|
49
|
+
return this;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
public insert(index: number, text: string): this {
|
|
53
|
+
this._guardInitialized();
|
|
54
|
+
|
|
55
|
+
this.value.insert(index, text);
|
|
56
|
+
this._doc?.value.commit();
|
|
57
|
+
|
|
58
|
+
return this;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
public toJson(): string {
|
|
62
|
+
return this.value.toString();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
private _guardInitialized(): void {
|
|
66
|
+
if (!this._initialized) throw new Error("Array is not yet initialized");
|
|
67
|
+
}
|
|
68
|
+
}
|
package/src/text/text.ts
ADDED
package/src/types.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { Json } from "@pluv/types";
|
|
2
|
+
import type { LoroList, LoroMap, LoroText } from "loro-crdt";
|
|
3
|
+
import type { CrdtLoroArray } from "./array";
|
|
4
|
+
import type { CrdtLoroMap } from "./map";
|
|
5
|
+
import type { CrdtLoroObject } from "./object";
|
|
6
|
+
import type { CrdtLoroText } from "./text";
|
|
7
|
+
|
|
8
|
+
export type InferLoroType<T extends unknown> =
|
|
9
|
+
T extends CrdtLoroArray<infer IType>
|
|
10
|
+
? LoroList<IType[]>
|
|
11
|
+
: T extends CrdtLoroMap<infer IType>
|
|
12
|
+
? LoroMap<Record<string, IType>>
|
|
13
|
+
: T extends CrdtLoroObject<infer IType>
|
|
14
|
+
? LoroMap<IType>
|
|
15
|
+
: T extends CrdtLoroText
|
|
16
|
+
? LoroText
|
|
17
|
+
: T extends Json
|
|
18
|
+
? T
|
|
19
|
+
: never;
|
|
20
|
+
|
|
21
|
+
export type InferLoroJson<T extends unknown> =
|
|
22
|
+
T extends CrdtLoroArray<infer IType>
|
|
23
|
+
? InferLoroJson<IType>[]
|
|
24
|
+
: T extends CrdtLoroMap<infer IType>
|
|
25
|
+
? Record<string, InferLoroJson<IType>>
|
|
26
|
+
: T extends CrdtLoroObject<infer IType>
|
|
27
|
+
? { [P in keyof IType]: InferLoroJson<IType[P]> }
|
|
28
|
+
: T extends CrdtLoroText | LoroText
|
|
29
|
+
? string
|
|
30
|
+
: T extends LoroList<infer IType>
|
|
31
|
+
? InferLoroJson<IType>
|
|
32
|
+
: T extends LoroMap<infer IType>
|
|
33
|
+
? { [P in keyof IType]: InferLoroJson<IType[P]> }
|
|
34
|
+
: T extends (infer IType)[]
|
|
35
|
+
? InferLoroJson<IType>[]
|
|
36
|
+
: T extends Record<any, any>
|
|
37
|
+
? { [P in keyof T]: InferLoroJson<T[P]> }
|
|
38
|
+
: T extends Json
|
|
39
|
+
? T
|
|
40
|
+
: never;
|