@cr_docs_t/dts 0.0.3 → 0.0.4
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/CausalTree/CTNode.d.ts +8 -0
- package/dist/CausalTree/CTNode.d.ts.map +1 -0
- package/dist/CausalTree/CTNode.js +1 -6
- package/dist/CausalTree/CausalTree.d.ts +7 -0
- package/dist/CausalTree/CausalTree.d.ts.map +1 -0
- package/dist/CausalTree/CausalTree.js +1 -14
- package/dist/Fugue/FNode.d.ts +7 -0
- package/dist/Fugue/FNode.d.ts.map +1 -0
- package/dist/Fugue/FNode.js +1 -5
- package/dist/Fugue/FugueList.d.ts +25 -0
- package/dist/Fugue/FugueList.d.ts.map +1 -0
- package/dist/Fugue/FugueList.js +8 -14
- package/dist/Fugue/FugueTest.d.ts +2 -0
- package/dist/Fugue/FugueTest.d.ts.map +1 -0
- package/dist/Fugue/FugueTest.js +4 -9
- package/dist/Fugue/utils.d.ts +34 -0
- package/dist/Fugue/utils.d.ts.map +1 -0
- package/dist/Fugue/utils.js +3 -9
- package/{src/index.ts → dist/index.d.ts} +1 -1
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -2
- package/package.json +10 -1
- package/biome.jsonc +0 -12
- package/src/CausalTree/CTNode.ts +0 -12
- package/src/CausalTree/CausalTree.ts +0 -21
- package/src/Fugue/FNode.ts +0 -11
- package/src/Fugue/FugueList.ts +0 -82
- package/src/Fugue/FugueTest.ts +0 -25
- package/src/Fugue/utils.ts +0 -75
- package/tsconfig.json +0 -13
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CTNode.d.ts","sourceRoot":"","sources":["../../src/CausalTree/CTNode.ts"],"names":[],"mappings":"AAAA,cAAM,MAAM;IACR,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;gBAEH,GAAG,EAAE,MAAM;CAG1B;AAED,eAAe,MAAM,CAAC"}
|
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
1
|
class CTNode {
|
|
4
|
-
uid; //userId @ lamport timestamp
|
|
5
|
-
character;
|
|
6
|
-
cause; //the causal prior?
|
|
7
2
|
constructor(uid) {
|
|
8
3
|
this.uid = uid;
|
|
9
4
|
}
|
|
10
5
|
}
|
|
11
|
-
|
|
6
|
+
export default CTNode;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CausalTree.d.ts","sourceRoot":"","sources":["../../src/CausalTree/CausalTree.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,UAAU,CAAC;AAE9B,cAAM,UAAU;IAWZ,IAAI,EAAE,MAAM,CAAC;gBAED,IAAI,EAAE,MAAM;CAG3B;AAED,eAAe,UAAU,CAAC"}
|
|
@@ -1,19 +1,6 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
1
|
class CasualTree {
|
|
4
|
-
/*
|
|
5
|
-
This is the fug crdt
|
|
6
|
-
It is a tree
|
|
7
|
-
It has a root
|
|
8
|
-
|
|
9
|
-
We can insert into the tree
|
|
10
|
-
Delete from the tree
|
|
11
|
-
Display the characters...
|
|
12
|
-
Maybe add a build method from a list of operations...
|
|
13
|
-
*/
|
|
14
|
-
root;
|
|
15
2
|
constructor(root) {
|
|
16
3
|
this.root = root;
|
|
17
4
|
}
|
|
18
5
|
}
|
|
19
|
-
|
|
6
|
+
export default CasualTree;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FNode.d.ts","sourceRoot":"","sources":["../../src/Fugue/FNode.ts"],"names":[],"mappings":"AAAA,cAAM,KAAK,CAAC,CAAC;IACT,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,CAAC,CAAC;gBAEA,QAAQ,EAAE,CAAC,EAAE,KAAK,CAAC,EAAE,MAAM;CAI1C;AAED,eAAe,KAAK,CAAC"}
|
package/dist/Fugue/FNode.js
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
1
|
class FNode {
|
|
4
|
-
value;
|
|
5
|
-
position;
|
|
6
2
|
constructor(position, value) {
|
|
7
3
|
this.value = value;
|
|
8
4
|
this.position = position;
|
|
9
5
|
}
|
|
10
6
|
}
|
|
11
|
-
|
|
7
|
+
export default FNode;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import FNode from "./FNode";
|
|
2
|
+
import { UniquelyDenseTotalOrder } from "./utils";
|
|
3
|
+
/**
|
|
4
|
+
* A Fugue List CRDT, with insert and delete operations
|
|
5
|
+
*/
|
|
6
|
+
declare class FugueList<P> {
|
|
7
|
+
state: FNode<P>[][];
|
|
8
|
+
totalOrder: UniquelyDenseTotalOrder<P>;
|
|
9
|
+
positionCounter: number;
|
|
10
|
+
constructor(totalOrder: UniquelyDenseTotalOrder<P>);
|
|
11
|
+
/**
|
|
12
|
+
* Inserts new element with 'value' at 'index' in the list
|
|
13
|
+
* @param index - Index to insert 'value' at
|
|
14
|
+
* @param value - Value to insert
|
|
15
|
+
*/
|
|
16
|
+
insert(index: number, value: string): void;
|
|
17
|
+
/**
|
|
18
|
+
* Delete value in the list at index
|
|
19
|
+
* @param index - Index of the value to delete
|
|
20
|
+
*/
|
|
21
|
+
delete(index: number): void;
|
|
22
|
+
observe(): string;
|
|
23
|
+
}
|
|
24
|
+
export default FugueList;
|
|
25
|
+
//# sourceMappingURL=FugueList.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FugueList.d.ts","sourceRoot":"","sources":["../../src/Fugue/FugueList.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,SAAS,CAAC;AAC5B,OAAO,EAAoB,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAEpE;;GAEG;AACH,cAAM,SAAS,CAAC,CAAC;IACb,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAM;IACzB,UAAU,EAAE,uBAAuB,CAAC,CAAC,CAAC,CAAC;IACvC,eAAe,SAAK;gBAER,UAAU,EAAE,uBAAuB,CAAC,CAAC,CAAC;IAIlD;;;;OAIG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;IA+BnC;;;OAGG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM;IASpB,OAAO,IAAI,MAAM;CAepB;AAED,eAAe,SAAS,CAAC"}
|
package/dist/Fugue/FugueList.js
CHANGED
|
@@ -1,17 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const FNode_1 = __importDefault(require("./FNode"));
|
|
1
|
+
import FNode from "./FNode";
|
|
7
2
|
/**
|
|
8
3
|
* A Fugue List CRDT, with insert and delete operations
|
|
9
4
|
*/
|
|
10
5
|
class FugueList {
|
|
11
|
-
state = [];
|
|
12
|
-
totalOrder;
|
|
13
|
-
positionCounter = 0;
|
|
14
6
|
constructor(totalOrder) {
|
|
7
|
+
this.state = [];
|
|
8
|
+
this.positionCounter = 0;
|
|
15
9
|
this.totalOrder = totalOrder;
|
|
16
10
|
}
|
|
17
11
|
/**
|
|
@@ -32,20 +26,20 @@ class FugueList {
|
|
|
32
26
|
const before = this.state[index - 1];
|
|
33
27
|
const after = this.state[index + 1];
|
|
34
28
|
if (atIndex.length == 0) {
|
|
35
|
-
atIndex.push(new
|
|
29
|
+
atIndex.push(new FNode(this.totalOrder.createBetween(before[before.length - 1].position), value));
|
|
36
30
|
}
|
|
37
31
|
else {
|
|
38
32
|
const a = atIndex[atIndex.length - 1];
|
|
39
|
-
atIndex.push(new
|
|
33
|
+
atIndex.push(new FNode(this.totalOrder.createBetween(a.position, after[after.length - 1].position), value));
|
|
40
34
|
}
|
|
41
35
|
}
|
|
42
36
|
else {
|
|
43
37
|
if (atIndex.length == 0) {
|
|
44
|
-
atIndex.push(new
|
|
38
|
+
atIndex.push(new FNode(this.totalOrder.createBetween(), value));
|
|
45
39
|
}
|
|
46
40
|
else {
|
|
47
41
|
const a = atIndex[atIndex.length - 1];
|
|
48
|
-
atIndex.push(new
|
|
42
|
+
atIndex.push(new FNode(this.totalOrder.createBetween(a.position), value));
|
|
49
43
|
}
|
|
50
44
|
}
|
|
51
45
|
}
|
|
@@ -77,4 +71,4 @@ class FugueList {
|
|
|
77
71
|
return res.toString();
|
|
78
72
|
}
|
|
79
73
|
}
|
|
80
|
-
|
|
74
|
+
export default FugueList;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FugueTest.d.ts","sourceRoot":"","sources":["../../src/Fugue/FugueTest.ts"],"names":[],"mappings":""}
|
package/dist/Fugue/FugueTest.js
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const FugueList_1 = __importDefault(require("./FugueList"));
|
|
7
|
-
const utils_1 = require("./utils");
|
|
8
|
-
const test1 = new FugueList_1.default(new utils_1.StringTotalOrder((0, utils_1.randomString)(5)));
|
|
9
|
-
const test2 = new FugueList_1.default(new utils_1.StringTotalOrder((0, utils_1.randomString)(5)));
|
|
1
|
+
import FugueList from "./FugueList";
|
|
2
|
+
import { randomString, StringTotalOrder } from "./utils";
|
|
3
|
+
const test1 = new FugueList(new StringTotalOrder(randomString(5)));
|
|
4
|
+
const test2 = new FugueList(new StringTotalOrder(randomString(5)));
|
|
10
5
|
const word1 = "SHADOW WIZARD MONEY GANG";
|
|
11
6
|
const word2 = "BALLING";
|
|
12
7
|
// Randomly insert words into the list from different simulated users
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper interface for sorting and creating unique immutable positions,
|
|
3
|
+
* suitable for use in a List CRDT. Taken from mattweidner.com/2022/10/21/basic-list-crdt.html
|
|
4
|
+
*
|
|
5
|
+
* @type P The type of positions. Treated as immutable.
|
|
6
|
+
*/
|
|
7
|
+
export interface UniquelyDenseTotalOrder<P> {
|
|
8
|
+
/**
|
|
9
|
+
* Usual compare function for sorts: returns negative if a < b in
|
|
10
|
+
* their sort order, positive if a > b.
|
|
11
|
+
*/
|
|
12
|
+
compare(a: P, b: P): number;
|
|
13
|
+
/**
|
|
14
|
+
* Returns a globally unique new position c such that a < c < b.
|
|
15
|
+
*
|
|
16
|
+
* "Globally unique" means that the created position must be distinct
|
|
17
|
+
* from all other created positions, including ones created concurrently
|
|
18
|
+
* by other users.
|
|
19
|
+
*
|
|
20
|
+
* When a is undefined, it is treated as the start of the list, i.e.,
|
|
21
|
+
* this returns c such that c < b. Likewise, undefined b is treated
|
|
22
|
+
* as the end of the list.
|
|
23
|
+
*/
|
|
24
|
+
createBetween(a?: P, b?: P): P;
|
|
25
|
+
}
|
|
26
|
+
export declare class StringTotalOrder implements UniquelyDenseTotalOrder<string> {
|
|
27
|
+
readonly replicaID: string;
|
|
28
|
+
private counter;
|
|
29
|
+
compare(a: string, b: string): number;
|
|
30
|
+
constructor(replicaID: string);
|
|
31
|
+
createBetween(a?: string, b?: string): string;
|
|
32
|
+
}
|
|
33
|
+
export declare function randomString(length?: number): string;
|
|
34
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/Fugue/utils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,uBAAuB,CAAC,CAAC;IACtC;;;OAGG;IACH,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC;IAE5B;;;;;;;;;;OAUG;IACH,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;CAClC;AAED,qBAAa,gBAAiB,YAAW,uBAAuB,CAAC,MAAM,CAAC;IACpE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,OAAO,CAAC,OAAO,CAAK;IAEpB,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM;gBAIzB,SAAS,EAAE,MAAM;IAI7B,aAAa,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM;CA6BhD;AAED,wBAAgB,YAAY,CAAC,MAAM,GAAE,MAAW,GAAG,MAAM,CAIxD"}
|
package/dist/Fugue/utils.js
CHANGED
|
@@ -1,14 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.StringTotalOrder = void 0;
|
|
4
|
-
exports.randomString = randomString;
|
|
5
|
-
class StringTotalOrder {
|
|
6
|
-
replicaID;
|
|
7
|
-
counter = 0;
|
|
1
|
+
export class StringTotalOrder {
|
|
8
2
|
compare(a, b) {
|
|
9
3
|
return a.localeCompare(b);
|
|
10
4
|
}
|
|
11
5
|
constructor(replicaID) {
|
|
6
|
+
this.counter = 0;
|
|
12
7
|
this.replicaID = replicaID;
|
|
13
8
|
}
|
|
14
9
|
createBetween(a, b) {
|
|
@@ -38,8 +33,7 @@ class StringTotalOrder {
|
|
|
38
33
|
}
|
|
39
34
|
}
|
|
40
35
|
}
|
|
41
|
-
|
|
42
|
-
function randomString(length = 10) {
|
|
36
|
+
export function randomString(length = 10) {
|
|
43
37
|
let res = new Array(length);
|
|
44
38
|
for (let i = 0; i < length; i++)
|
|
45
39
|
res[i] = String.fromCharCode(97 + Math.floor(Math.random() * 26));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAC1C,OAAO,UAAU,MAAM,yBAAyB,CAAC;AAEjD,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import FugueList from "./Fugue/FugueList";
|
|
2
|
+
import CausalTree from "./CausalTree/CausalTree";
|
|
3
|
+
export { FugueList, CausalTree };
|
package/package.json
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cr_docs_t/dts",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"import": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
7
13
|
"keywords": [],
|
|
8
14
|
"author": [
|
|
9
15
|
"Madiba Hudson-Quansah",
|
|
@@ -14,6 +20,9 @@
|
|
|
14
20
|
"@types/node": "^24.10.1",
|
|
15
21
|
"typescript": "^5.9.3"
|
|
16
22
|
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist"
|
|
25
|
+
],
|
|
17
26
|
"scripts": {
|
|
18
27
|
"build": "tsc"
|
|
19
28
|
}
|
package/biome.jsonc
DELETED
package/src/CausalTree/CTNode.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import CTNode from "./CTNode";
|
|
2
|
-
|
|
3
|
-
class CasualTree {
|
|
4
|
-
/*
|
|
5
|
-
This is the fug crdt
|
|
6
|
-
It is a tree
|
|
7
|
-
It has a root
|
|
8
|
-
|
|
9
|
-
We can insert into the tree
|
|
10
|
-
Delete from the tree
|
|
11
|
-
Display the characters...
|
|
12
|
-
Maybe add a build method from a list of operations...
|
|
13
|
-
*/
|
|
14
|
-
root: CTNode;
|
|
15
|
-
|
|
16
|
-
constructor(root: CTNode) {
|
|
17
|
-
this.root = root;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export default CasualTree;
|
package/src/Fugue/FNode.ts
DELETED
package/src/Fugue/FugueList.ts
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import FNode from "./FNode";
|
|
2
|
-
import { StringTotalOrder, UniquelyDenseTotalOrder } from "./utils";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* A Fugue List CRDT, with insert and delete operations
|
|
6
|
-
*/
|
|
7
|
-
class FugueList<P> {
|
|
8
|
-
state: FNode<P>[][] = [];
|
|
9
|
-
totalOrder: UniquelyDenseTotalOrder<P>;
|
|
10
|
-
positionCounter = 0;
|
|
11
|
-
|
|
12
|
-
constructor(totalOrder: UniquelyDenseTotalOrder<P>) {
|
|
13
|
-
this.totalOrder = totalOrder;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Inserts new element with 'value' at 'index' in the list
|
|
18
|
-
* @param index - Index to insert 'value' at
|
|
19
|
-
* @param value - Value to insert
|
|
20
|
-
*/
|
|
21
|
-
insert(index: number, value: string) {
|
|
22
|
-
if (index >= this.state.length) this.state.push([]);
|
|
23
|
-
|
|
24
|
-
let i = this.state.length - 1;
|
|
25
|
-
while (i > index) {
|
|
26
|
-
this.state[i] = this.state[i - 1];
|
|
27
|
-
i--;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const atIndex = this.state[index];
|
|
31
|
-
if (index > 0 && index < this.state.length - 1) {
|
|
32
|
-
const before = this.state[index - 1];
|
|
33
|
-
const after = this.state[index + 1];
|
|
34
|
-
if (atIndex.length == 0) {
|
|
35
|
-
atIndex.push(new FNode<P>(this.totalOrder.createBetween(before[before.length - 1].position), value));
|
|
36
|
-
} else {
|
|
37
|
-
const a = atIndex[atIndex.length - 1];
|
|
38
|
-
atIndex.push(
|
|
39
|
-
new FNode<P>(this.totalOrder.createBetween(a.position, after[after.length - 1].position), value),
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
} else {
|
|
43
|
-
if (atIndex.length == 0) {
|
|
44
|
-
atIndex.push(new FNode<P>(this.totalOrder.createBetween(), value));
|
|
45
|
-
} else {
|
|
46
|
-
const a = atIndex[atIndex.length - 1];
|
|
47
|
-
atIndex.push(new FNode<P>(this.totalOrder.createBetween(a.position), value));
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Delete value in the list at index
|
|
54
|
-
* @param index - Index of the value to delete
|
|
55
|
-
*/
|
|
56
|
-
delete(index: number) {
|
|
57
|
-
let i = index;
|
|
58
|
-
while (i < this.state.length) {
|
|
59
|
-
this.state[i] = this.state[i + 1];
|
|
60
|
-
i++;
|
|
61
|
-
}
|
|
62
|
-
this.state.pop();
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
observe(): string {
|
|
66
|
-
let res = new String();
|
|
67
|
-
for (const idx of this.state) {
|
|
68
|
-
if (idx.length > 1) {
|
|
69
|
-
res += idx
|
|
70
|
-
.sort((a, b) => this.totalOrder.compare(a.position, b.position))
|
|
71
|
-
.map((node) => node?.value || "ð")
|
|
72
|
-
.join("");
|
|
73
|
-
} else {
|
|
74
|
-
res += idx[0]?.value || "ð";
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return res.toString();
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export default FugueList;
|
package/src/Fugue/FugueTest.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import FugueList from "./FugueList";
|
|
2
|
-
import { randomString, StringTotalOrder } from "./utils";
|
|
3
|
-
|
|
4
|
-
const test1 = new FugueList(new StringTotalOrder(randomString(5)));
|
|
5
|
-
const test2 = new FugueList(new StringTotalOrder(randomString(5)));
|
|
6
|
-
|
|
7
|
-
const word1 = "SHADOW WIZARD MONEY GANG";
|
|
8
|
-
const word2 = "BALLING";
|
|
9
|
-
|
|
10
|
-
// Randomly insert words into the list from different simulated users
|
|
11
|
-
async function simulateUser(list: FugueList<string>, word: string) {
|
|
12
|
-
for (let i = 0; i < word.length; i++) {
|
|
13
|
-
await new Promise((resolve) => setTimeout(resolve, Math.random() * 150));
|
|
14
|
-
list.insert(i, word.charAt(i));
|
|
15
|
-
console.log(list.observe());
|
|
16
|
-
console.log(list.state);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
Promise.all([
|
|
21
|
-
simulateUser(test1, word1), //
|
|
22
|
-
simulateUser(test2, word2),
|
|
23
|
-
])
|
|
24
|
-
.then(() => console.log(`Done:\t${test1.observe()}\n\t${test2.observe()}`))
|
|
25
|
-
.catch(console.error);
|
package/src/Fugue/utils.ts
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Helper interface for sorting and creating unique immutable positions,
|
|
3
|
-
* suitable for use in a List CRDT. Taken from mattweidner.com/2022/10/21/basic-list-crdt.html
|
|
4
|
-
*
|
|
5
|
-
* @type P The type of positions. Treated as immutable.
|
|
6
|
-
*/
|
|
7
|
-
export interface UniquelyDenseTotalOrder<P> {
|
|
8
|
-
/**
|
|
9
|
-
* Usual compare function for sorts: returns negative if a < b in
|
|
10
|
-
* their sort order, positive if a > b.
|
|
11
|
-
*/
|
|
12
|
-
compare(a: P, b: P): number;
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Returns a globally unique new position c such that a < c < b.
|
|
16
|
-
*
|
|
17
|
-
* "Globally unique" means that the created position must be distinct
|
|
18
|
-
* from all other created positions, including ones created concurrently
|
|
19
|
-
* by other users.
|
|
20
|
-
*
|
|
21
|
-
* When a is undefined, it is treated as the start of the list, i.e.,
|
|
22
|
-
* this returns c such that c < b. Likewise, undefined b is treated
|
|
23
|
-
* as the end of the list.
|
|
24
|
-
*/
|
|
25
|
-
createBetween(a?: P, b?: P): P;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export class StringTotalOrder implements UniquelyDenseTotalOrder<string> {
|
|
29
|
-
readonly replicaID: string;
|
|
30
|
-
private counter = 0;
|
|
31
|
-
|
|
32
|
-
compare(a: string, b: string): number {
|
|
33
|
-
return a.localeCompare(b);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
constructor(replicaID: string) {
|
|
37
|
-
this.replicaID = replicaID;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
createBetween(a?: string, b?: string): string {
|
|
41
|
-
// Create a wholly unique string using a causal dot, i.e. (replicaID, counter)
|
|
42
|
-
const uniqueStr = `${this.replicaID}${this.counter++}`;
|
|
43
|
-
|
|
44
|
-
// If node is the first ever position in the document
|
|
45
|
-
if (!a && !b) {
|
|
46
|
-
return uniqueStr + "R";
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// If node is the first position at that index
|
|
50
|
-
if (!a) {
|
|
51
|
-
return b + uniqueStr + "R";
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// If node is the last position at that index
|
|
55
|
-
if (!b) {
|
|
56
|
-
return a + uniqueStr + "R";
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const isAPrefixOfB = b.substring(0, a.length).localeCompare(a);
|
|
60
|
-
// If a is not a prefix of b append a globally unique new string to a and return that +R
|
|
61
|
-
if (!isAPrefixOfB) {
|
|
62
|
-
return a + uniqueStr + "R";
|
|
63
|
-
} else {
|
|
64
|
-
// If a is a prefix of b replace the R at the end of b with L.
|
|
65
|
-
// Then append a globally unique string to it and return it +R.
|
|
66
|
-
return b.slice(0, -1) + "L" + uniqueStr + "R";
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export function randomString(length: number = 10): string {
|
|
72
|
-
let res = new Array<string>(length);
|
|
73
|
-
for (let i = 0; i < length; i++) res[i] = String.fromCharCode(97 + Math.floor(Math.random() * 26));
|
|
74
|
-
return res.join("");
|
|
75
|
-
}
|
package/tsconfig.json
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
// Visit https://aka.ms/tsconfig to read more about this file
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"module": "nodenext",
|
|
5
|
-
"target": "esnext",
|
|
6
|
-
"rootDir": "./src",
|
|
7
|
-
"esModuleInterop": true,
|
|
8
|
-
"forceConsistentCasingInFileNames": true,
|
|
9
|
-
"strict": true,
|
|
10
|
-
"skipLibCheck": true,
|
|
11
|
-
"outDir": "./dist",
|
|
12
|
-
}
|
|
13
|
-
}
|