Skip to content

Commit e5e128e

Browse files
angaryVarun-Sethu
andauthored
feat(cms): add string transformation functions (#232)
* Add non overlapping transformation cases * Complete non overlapping text transform functions * Add tests for overlapping text transform cases OMG TEST DRIVEN DEVELOPMENT * Complete delete overlapping cases * Correct delete tests to have expected output * Correct application function in the tests and comment out DeleteDeleteSame test * Everything working except for insertdelete overlap delete before insert * Add copier dependency * Complete go text transformation implementation and tests * Add claification comments for tests * Do not use copier library and remove from dependencies * Complete go text transformation functions for same location insert * Correct style and formatting of ts operation file * Complete ts implementation with tests * Remove console.logs * Complete implementation of atomic operation in ts client * Change interface variable names and add documentation on functions * Also include the code for applying atomic operations * Complete tests for path transform implementation * merging with main Co-authored-by: Varun Sethu <[email protected]>
1 parent b4b113f commit e5e128e

File tree

11 files changed

+2625
-177
lines changed

11 files changed

+2625
-177
lines changed

backend/editor/OT/OTClient/client.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@ const ACK_TIMEOUT_DURATION = 10_000;
2323
*/
2424

2525
export default class Client {
26+
private socket: Socket;
27+
28+
private queuedOperations: OperationQueue = new OperationQueue();
29+
private pendingAcknowledgement = false;
30+
private appliedOperations = 0;
31+
32+
private timeoutID: number = NaN;
33+
2634
// TODO: Handle destruction / closing of the websocket
2735
constructor(opCallback: (op: Operation) => void) {
2836
this.socket = io(`ws://localhost:8080/edit?document=${document}`);
@@ -94,12 +102,4 @@ export default class Client {
94102
"finish"
95103
);
96104
};
97-
98-
private socket: Socket;
99-
100-
private queuedOperations: OperationQueue = new OperationQueue();
101-
private pendingAcknowledgement = false;
102-
private appliedOperations = 0;
103-
104-
private timeoutID: number = NaN;
105105
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
2+
module.exports = {
3+
preset: 'ts-jest',
4+
testEnvironment: 'node',
5+
};
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
import { AtomicOperation, StringOperation } from "./operation";
2+
3+
describe("String transformation functions", () => {
4+
5+
const s = "abcde";
6+
7+
const apply = (o: AtomicOperation, s: string): string => {
8+
const strOp = o as StringOperation;
9+
const start = Math.min(s.length, strOp.start);
10+
const end = strOp.newValue == "" ? strOp.end : start;
11+
return s.substring(0, start) + strOp.newValue + s.substring(end);
12+
};
13+
14+
describe("insert insert", () => {
15+
test("non overlap", () => {
16+
const o1 = new StringOperation(1, 2, "1");
17+
const o2 = new StringOperation(2, 3, "2");
18+
expect(apply(o1, s)).toBe("a1bcde");
19+
expect(apply(o2, s)).toBe("ab2cde");
20+
21+
const [o1_t1, o2_t1] = o1.transformAgainst(o2);
22+
const [o1_t2, o2_t2] = o2.transformAgainst(o1);
23+
expect(apply(o1_t1, apply(o2_t1, s))).toBe("a1b2cde");
24+
expect(apply(o2_t2, apply(o1_t2, s))).toBe("a1b2cde");
25+
});
26+
27+
test("same location", () => {
28+
const o1 = new StringOperation(1, 2, "2");
29+
const o2 = new StringOperation(1, 2, "1");
30+
const [o1_t1, o2_t1] = o1.transformAgainst(o2);
31+
const [o1_t2, o2_t2] = o2.transformAgainst(o1);
32+
expect(apply(o1_t1, apply(o2_t1, s))).toBe("a12bcde");
33+
expect(apply(o2_t2, apply(o1_t2, s))).toBe("a12bcde");
34+
});
35+
36+
test("overlap", () => {
37+
const o1 = new StringOperation(1, 3, "11");
38+
const o2 = new StringOperation(2, 4, "22");
39+
const [o1_t1, o2_t1] = o1.transformAgainst(o2);
40+
const [o1_t2, o2_t2] = o2.transformAgainst(o1);
41+
expect(apply(o1_t1, apply(o2_t1, s))).toBe("a11b22cde");
42+
expect(apply(o2_t2, apply(o1_t2, s))).toBe("a11b22cde");
43+
});
44+
});
45+
46+
describe("insert delete", () => {
47+
test("non overlap", () => {
48+
const o1 = new StringOperation(1, 2, "1");
49+
const o2 = new StringOperation(2, 3, "");
50+
const [o1_t1, o2_t1] = o1.transformAgainst(o2);
51+
const [o1_t2, o2_t2] = o2.transformAgainst(o1);
52+
expect(apply(o1_t1, apply(o2_t1, s))).toBe("a1bde");
53+
expect(apply(o2_t2, apply(o1_t2, s))).toBe("a1bde");
54+
});
55+
56+
test("same location", () => {
57+
const o1 = new StringOperation(1, 2, "1");
58+
const o2 = new StringOperation(0, 1, "");
59+
const [o1_t1, o2_t1] = o1.transformAgainst(o2);
60+
const [o1_t2, o2_t2] = o2.transformAgainst(o1);
61+
expect(apply(o1_t1, apply(o2_t1, s))).toBe("1bcde");
62+
expect(apply(o2_t2, apply(o1_t2, s))).toBe("1bcde");
63+
});
64+
65+
test("overlap insert before delete", () => {
66+
const o1 = new StringOperation(1, 3, "12");
67+
const o2 = new StringOperation(0, 1, "");
68+
const [o1_t1, o2_t1] = o1.transformAgainst(o2);
69+
const [o1_t2, o2_t2] = o2.transformAgainst(o1);
70+
expect(apply(o1_t1, apply(o2_t1, s))).toBe("12bcde");
71+
expect(apply(o2_t2, apply(o1_t2, s))).toBe("12bcde");
72+
});
73+
74+
test("overlap delete before insert", () => {
75+
const o1 = new StringOperation(2, 3, "1");
76+
const o2 = new StringOperation(0, 3, "");
77+
const [o1_t1, o2_t1] = o1.transformAgainst(o2);
78+
const [o1_t2, o2_t2] = o2.transformAgainst(o1);
79+
expect(apply(o1_t1, apply(o2_t1, s))).toBe("1de");
80+
expect(apply(o2_t2, apply(o1_t2, s))).toBe("1de");
81+
});
82+
83+
test("overlap less insert than delete", () => {
84+
const o1 = new StringOperation(0, 1, "1");
85+
const o2 = new StringOperation(0, 5, "");
86+
const [o1_t1, o2_t1] = o1.transformAgainst(o2);
87+
const [o1_t2, o2_t2] = o2.transformAgainst(o1);
88+
expect(apply(o1_t1, apply(o2_t1, s))).toBe("1");
89+
expect(apply(o2_t2, apply(o1_t2, s))).toBe("1");
90+
});
91+
92+
test("overlap more insert than delete", () => {
93+
const o1 = new StringOperation(0, 5, "11111");
94+
const o2 = new StringOperation(0, 1, "");
95+
const [o1_t1, o2_t1] = o1.transformAgainst(o2);
96+
const [o1_t2, o2_t2] = o2.transformAgainst(o1);
97+
expect(apply(o1_t1, apply(o2_t1, s))).toBe("11111bcde");
98+
expect(apply(o2_t2, apply(o1_t2, s))).toBe("11111bcde");
99+
});
100+
});
101+
102+
describe("delete delete", () => {
103+
test("non overlap", () => {
104+
const o1 = new StringOperation(1, 2, "");
105+
const o2 = new StringOperation(2, 3, "");
106+
const [o1_t1, o2_t1] = o1.transformAgainst(o2);
107+
const [o1_t2, o2_t2] = o2.transformAgainst(o1);
108+
expect(apply(o1_t1, apply(o2_t1, s))).toBe("ade");
109+
expect(apply(o2_t2, apply(o1_t2, s))).toBe("ade");
110+
});
111+
112+
test("same operations", () => {
113+
const o1 = new StringOperation(1, 2, "");
114+
const o2 = new StringOperation(1, 2, "");
115+
const [o1_t1, o2_t1] = o1.transformAgainst(o2);
116+
const [o1_t2, o2_t2] = o2.transformAgainst(o1);
117+
expect(apply(o1_t1, apply(o2_t1, s))).toBe("acde");
118+
expect(apply(o2_t2, apply(o1_t2, s))).toBe("acde");
119+
});
120+
121+
test("overlap", () => {
122+
const o1 = new StringOperation(1, 3, "");
123+
const o2 = new StringOperation(2, 3, "");
124+
const [o1_t1, o2_t1] = o1.transformAgainst(o2);
125+
const [o1_t2, o2_t2] = o2.transformAgainst(o1);
126+
expect(apply(o1_t1, apply(o2_t1, s))).toBe("ade");
127+
expect(apply(o2_t2, apply(o1_t2, s))).toBe("ade");
128+
});
129+
});
130+
});

0 commit comments

Comments
 (0)