Skip to content

Commit a9ae042

Browse files
committed
feat: split modules
1 parent f4354f4 commit a9ae042

File tree

7 files changed

+408
-388
lines changed

7 files changed

+408
-388
lines changed

y-octo-node/src/array.ts

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
import * as Y from "./yocto";
2+
import { Doc } from "./doc";
3+
import { Map } from "./map";
4+
import type { ArrayType, ListItem } from "./types";
5+
6+
export class Array {
7+
private ytype?: { doc: Doc; array: Y.YArray };
8+
private preliminary: any[] = [];
9+
10+
get itemId() {
11+
return this.ytype?.array.itemId;
12+
}
13+
14+
static from<T extends ArrayType>(items: T[]): Array {
15+
return new Array(items);
16+
}
17+
18+
static from_ytype(ytype?: { doc: Doc; array: Y.YArray }) {
19+
const array = new Array();
20+
array.ytype = ytype;
21+
return array;
22+
}
23+
24+
constructor(items: ArrayType[] = [], ydoc?: Doc, yarray?: Y.YArray) {
25+
this.preliminary = items;
26+
if (ydoc) this.integrate(ydoc, yarray);
27+
}
28+
29+
integrate(ydoc: Doc, yarray?: Y.YArray): Y.YArray {
30+
if (!this.ytype) {
31+
this.ytype = { doc: ydoc, array: yarray || ydoc.createArray() };
32+
for (const item of this.preliminary) {
33+
if (item instanceof Array) {
34+
this.ytype.array.push(item.integrate(ydoc));
35+
} else {
36+
this.ytype.array.push(item);
37+
}
38+
}
39+
this.preliminary = [];
40+
this.ytype.doc.triggerDiff();
41+
}
42+
return this.ytype.array;
43+
}
44+
45+
get length(): number {
46+
return this.ytype ? this.ytype.array.length : this.preliminary.length;
47+
}
48+
49+
get isEmpty(): boolean {
50+
return this.ytype
51+
? this.ytype.array.isEmpty
52+
: this.preliminary.length === 0;
53+
}
54+
55+
get<T = unknown>(index: number): T {
56+
return this.ytype ? this.ytype.array.get(index) : this.preliminary[index];
57+
}
58+
59+
slice<T = unknown>(start: number, end?: number): T[] {
60+
return this.ytype
61+
? this.ytype.array.slice(start, end)
62+
: this.preliminary.slice(start, end);
63+
}
64+
65+
map<T = unknown>(callback: (...args: any[]) => any): T[] {
66+
return this.ytype
67+
? this.ytype.array.map(callback)
68+
: this.preliminary.map(callback);
69+
}
70+
71+
insert(index: number, value: ListItem): void {
72+
if (this.ytype) {
73+
if (value instanceof Array || value instanceof Map) {
74+
this.ytype.array.insert(index, value.integrate(this.ytype.doc));
75+
} else {
76+
this.ytype.array.insert(index, value);
77+
}
78+
this.ytype.doc.triggerDiff();
79+
} else {
80+
this.preliminary.splice(index, 0, value);
81+
}
82+
}
83+
84+
push(value?: ListItem): void {
85+
if (this.ytype) {
86+
this.ytype.array.push(value);
87+
this.ytype.doc.triggerDiff();
88+
} else {
89+
this.preliminary.push(value);
90+
}
91+
}
92+
93+
unshift(value?: ListItem): void {
94+
if (this.ytype) {
95+
this.ytype.array.unshift(value);
96+
this.ytype.doc.triggerDiff();
97+
} else {
98+
this.preliminary.unshift(value);
99+
}
100+
}
101+
102+
delete(index: number, len?: number): void {
103+
if (this.ytype) {
104+
this.ytype.array.delete(index, len);
105+
this.ytype.doc.triggerDiff();
106+
} else {
107+
this.preliminary.splice(index, len);
108+
}
109+
}
110+
111+
iter(): Y.YArrayIterator {
112+
return this.ytype
113+
? this.ytype.array.iter()
114+
: this.preliminary[Symbol.iterator]();
115+
}
116+
117+
toArray(): any[] {
118+
return this.ytype ? this.ytype.array.toArray() : this.preliminary;
119+
}
120+
121+
toJSON(): any[] {
122+
return this.ytype ? this.ytype.array.toJSON() : this.preliminary;
123+
}
124+
125+
observe(callback: (...args: any[]) => any): void {
126+
if (this.ytype) {
127+
this.ytype.array.observe(callback);
128+
} else {
129+
throw new Error("Not implemented");
130+
}
131+
}
132+
133+
observeDeep(callback: (...args: any[]) => any): void {
134+
if (this.ytype) {
135+
this.ytype.array.observeDeep(callback);
136+
} else {
137+
throw new Error("Not implemented");
138+
}
139+
}
140+
}

y-octo-node/src/doc.ts

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import * as Y from "./yocto";
2+
import { Array } from "./array";
3+
import { Map } from "./map";
4+
import type { Text } from "./text";
5+
6+
export class Doc extends Y.Doc {
7+
private cachedArray: globalThis.Map<string, Array> = new globalThis.Map();
8+
private cachedMap: globalThis.Map<string, Map> = new globalThis.Map();
9+
private subscribers: Set<(result: Uint8Array, origin?: unknown) => void> =
10+
new Set();
11+
private lastState: Buffer | null = null;
12+
13+
getArray(key: string): Array {
14+
if (this.cachedArray.has(key)) {
15+
return this.cachedArray.get(key)!;
16+
}
17+
const yarray = new Array([], this, this.getOrCreateArray(key));
18+
this.cachedArray.set(key, yarray);
19+
return yarray;
20+
}
21+
22+
getMap(key: string): Map {
23+
if (this.cachedMap.has(key)) {
24+
return this.cachedMap.get(key)!;
25+
}
26+
const ymap = new Map({}, this, this.getOrCreateMap(key));
27+
this.cachedMap.set(key, ymap);
28+
return ymap;
29+
}
30+
31+
getText(key: string): Text {
32+
return this.getOrCreateText(key);
33+
}
34+
35+
triggerDiff(origin?: unknown): void {
36+
let diff: Buffer | null = null;
37+
if (this.lastState) {
38+
diff = this.diff(this.lastState);
39+
const state = this.encodeStateAsUpdateV1();
40+
if (!this.lastState.equals(state)) {
41+
this.lastState = state;
42+
} else {
43+
return;
44+
}
45+
} else {
46+
this.lastState = this.encodeStateAsUpdateV1();
47+
diff = this.diff(this.lastState);
48+
}
49+
50+
// skip empty diffs
51+
if (!diff || diff.equals(new Uint8Array([0, 0]))) {
52+
return;
53+
}
54+
55+
if (this.lastState?.length && diff?.length) {
56+
this.subscribers.forEach((callback) =>
57+
callback(new Uint8Array(diff!), origin || this),
58+
);
59+
}
60+
}
61+
62+
transact(callback: (...args: any[]) => any, origin?: unknown): void {
63+
try {
64+
callback();
65+
} finally {
66+
this.triggerDiff(origin);
67+
}
68+
}
69+
70+
override applyUpdate(update: Buffer): void {
71+
this.transact(() => {
72+
super.applyUpdate(update);
73+
});
74+
}
75+
76+
override onUpdate(
77+
callback: (result: Uint8Array, origin?: unknown) => void,
78+
): void {
79+
this.subscribers.add(callback);
80+
}
81+
82+
override offUpdate(): void {
83+
this.subscribers.clear();
84+
}
85+
}

0 commit comments

Comments
 (0)