@monstermann/delta 0.0.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/LICENSE +21 -0
- package/README.md +695 -0
- package/dist/Delta/batch.d.mts +57 -0
- package/dist/Delta/batch.mjs +61 -0
- package/dist/Delta/chop.d.mts +56 -0
- package/dist/Delta/chop.mjs +60 -0
- package/dist/Delta/clean.d.mts +57 -0
- package/dist/Delta/clean.mjs +61 -0
- package/dist/Delta/compose.d.mts +58 -0
- package/dist/Delta/compose.mjs +100 -0
- package/dist/Delta/concat.d.mts +50 -0
- package/dist/Delta/concat.mjs +51 -0
- package/dist/Delta/diff.d.mts +73 -0
- package/dist/Delta/diff.mjs +124 -0
- package/dist/Delta/equals.d.mts +43 -0
- package/dist/Delta/equals.mjs +50 -0
- package/dist/Delta/index.d.mts +26 -0
- package/dist/Delta/index.mjs +37 -0
- package/dist/Delta/insert.d.mts +52 -0
- package/dist/Delta/insert.mjs +57 -0
- package/dist/Delta/invert.d.mts +54 -0
- package/dist/Delta/invert.mjs +77 -0
- package/dist/Delta/length.d.mts +51 -0
- package/dist/Delta/length.mjs +51 -0
- package/dist/Delta/push.d.mts +51 -0
- package/dist/Delta/push.mjs +87 -0
- package/dist/Delta/remove.d.mts +41 -0
- package/dist/Delta/remove.mjs +46 -0
- package/dist/Delta/retain.d.mts +70 -0
- package/dist/Delta/retain.mjs +76 -0
- package/dist/Delta/slice.d.mts +64 -0
- package/dist/Delta/slice.mjs +77 -0
- package/dist/Delta/transform.d.mts +63 -0
- package/dist/Delta/transform.mjs +91 -0
- package/dist/Op/index.d.mts +21 -0
- package/dist/OpAttributes/compose.d.mts +6 -0
- package/dist/OpAttributes/compose.mjs +25 -0
- package/dist/OpAttributes/diff.d.mts +6 -0
- package/dist/OpAttributes/diff.mjs +14 -0
- package/dist/OpAttributes/index.d.mts +15 -0
- package/dist/OpAttributes/invert.d.mts +6 -0
- package/dist/OpAttributes/invert.mjs +16 -0
- package/dist/OpAttributes/isEqual.d.mts +6 -0
- package/dist/OpAttributes/isEqual.mjs +16 -0
- package/dist/OpAttributes/transform.d.mts +6 -0
- package/dist/OpAttributes/transform.mjs +13 -0
- package/dist/OpIterator/create.mjs +11 -0
- package/dist/OpIterator/hasNext.mjs +9 -0
- package/dist/OpIterator/next.mjs +36 -0
- package/dist/OpIterator/peek.mjs +7 -0
- package/dist/OpIterator/peekLength.mjs +9 -0
- package/dist/OpIterator/peekType.mjs +7 -0
- package/dist/index.d.mts +2 -0
- package/dist/index.mjs +3 -0
- package/dist/internals/hasKeys.mjs +8 -0
- package/package.json +42 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { chop } from "./chop.mjs";
|
|
2
|
+
import { push } from "./push.mjs";
|
|
3
|
+
import { create } from "../OpIterator/create.mjs";
|
|
4
|
+
import { peekLength } from "../OpIterator/peekLength.mjs";
|
|
5
|
+
import { next } from "../OpIterator/next.mjs";
|
|
6
|
+
import { remove } from "./remove.mjs";
|
|
7
|
+
import { retain } from "./retain.mjs";
|
|
8
|
+
import { diff as diff$1 } from "../OpAttributes/diff.mjs";
|
|
9
|
+
import { dfdlT } from "@monstermann/dfdl";
|
|
10
|
+
import { endMutations, markAsMutable, startMutations } from "@monstermann/remmi";
|
|
11
|
+
import fastDiff from "fast-diff";
|
|
12
|
+
|
|
13
|
+
//#region src/Delta/diff.ts
|
|
14
|
+
/**
|
|
15
|
+
* # diff
|
|
16
|
+
*
|
|
17
|
+
* ```ts
|
|
18
|
+
* function Delta.diff<T>(a: Delta<T>, b: Delta<T>, cursor?: number): Delta<T>
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* Computes the difference between two document deltas, returning a delta that transforms `a` into `b`.
|
|
22
|
+
*
|
|
23
|
+
* The optional `cursor` parameter provides a hint about where the user's cursor is positioned. This helps produce more intuitive diffs when there are multiple valid ways to represent the same change.
|
|
24
|
+
*
|
|
25
|
+
* ## Example
|
|
26
|
+
*
|
|
27
|
+
* ```ts [data-first]
|
|
28
|
+
* import { Delta } from "@monstermann/delta";
|
|
29
|
+
*
|
|
30
|
+
* const a = Delta.insert([], "Hello");
|
|
31
|
+
* const b = Delta.insert([], "Hello world");
|
|
32
|
+
*
|
|
33
|
+
* Delta.diff(a, b);
|
|
34
|
+
* // [{ type: "retain", value: 5 },
|
|
35
|
+
* // { type: "insert", value: " world" }]
|
|
36
|
+
*
|
|
37
|
+
* const plain = Delta.insert([], "Hello");
|
|
38
|
+
* const bold = Delta.insert([], "Hello", { bold: true });
|
|
39
|
+
*
|
|
40
|
+
* Delta.diff(plain, bold);
|
|
41
|
+
* // [{ type: "retain", value: 5, attributes: { bold: true } }]
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
* ```ts [data-last]
|
|
45
|
+
* import { Delta } from "@monstermann/delta";
|
|
46
|
+
*
|
|
47
|
+
* const a = Delta.insert([], "Hello");
|
|
48
|
+
* const b = Delta.insert([], "Hello world");
|
|
49
|
+
*
|
|
50
|
+
* pipe(a, Delta.diff(b));
|
|
51
|
+
* // [{ type: "retain", value: 5 },
|
|
52
|
+
* // { type: "insert", value: " world" }]
|
|
53
|
+
* ```
|
|
54
|
+
*
|
|
55
|
+
* ## Cursor hint
|
|
56
|
+
*
|
|
57
|
+
* When text changes are ambiguous, the cursor position determines where the change is placed:
|
|
58
|
+
*
|
|
59
|
+
* ```ts
|
|
60
|
+
* import { Delta } from "@monstermann/delta";
|
|
61
|
+
*
|
|
62
|
+
* const a = Delta.insert([], "foo");
|
|
63
|
+
* const b = Delta.insert([], "foo bar foo");
|
|
64
|
+
*
|
|
65
|
+
* // cursor=3: user typed " bar foo" at the end
|
|
66
|
+
* Delta.diff(a, b, 3);
|
|
67
|
+
* // [{ type: "retain", value: 3 },
|
|
68
|
+
* // { type: "insert", value: " bar foo" }]
|
|
69
|
+
*
|
|
70
|
+
* // cursor=0: user typed "foo bar " at the beginning
|
|
71
|
+
* Delta.diff(a, b, 0);
|
|
72
|
+
* // [{ type: "insert", value: "foo bar " }]
|
|
73
|
+
* ```
|
|
74
|
+
*
|
|
75
|
+
*/
|
|
76
|
+
const diff = dfdlT((a, b, cursor) => {
|
|
77
|
+
if (a === b) return [];
|
|
78
|
+
const aString = toText(a, "Delta.diff(a, b): a is not a document");
|
|
79
|
+
const bString = toText(b, "Delta.diff(a, b): b is not a document");
|
|
80
|
+
startMutations();
|
|
81
|
+
let ops = markAsMutable([]);
|
|
82
|
+
const diffResult = fastDiff(aString, bString, cursor, true);
|
|
83
|
+
const aIter = create(a);
|
|
84
|
+
const bIter = create(b);
|
|
85
|
+
for (const component of diffResult) {
|
|
86
|
+
const [type, text] = component;
|
|
87
|
+
let length = text.length;
|
|
88
|
+
while (length > 0) {
|
|
89
|
+
let opLength = 0;
|
|
90
|
+
if (type === fastDiff.INSERT) {
|
|
91
|
+
opLength = Math.min(peekLength(bIter), length);
|
|
92
|
+
ops = push(ops, next(bIter, opLength));
|
|
93
|
+
} else if (type === fastDiff.DELETE) {
|
|
94
|
+
opLength = Math.min(length, peekLength(aIter));
|
|
95
|
+
next(aIter, opLength);
|
|
96
|
+
ops = remove(ops, opLength);
|
|
97
|
+
} else if (type === fastDiff.EQUAL) {
|
|
98
|
+
opLength = Math.min(peekLength(aIter), peekLength(bIter), length);
|
|
99
|
+
const aOp = next(aIter, opLength);
|
|
100
|
+
const bOp = next(bIter, opLength);
|
|
101
|
+
if (aOp.type === "insert" && bOp.type === "insert" && aOp.value === bOp.value) ops = retain(ops, opLength, diff$1(aOp.attributes, bOp.attributes));
|
|
102
|
+
else {
|
|
103
|
+
ops = push(ops, bOp);
|
|
104
|
+
ops = remove(ops, opLength);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
length -= opLength;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
ops = chop(ops);
|
|
111
|
+
endMutations();
|
|
112
|
+
return ops;
|
|
113
|
+
}, (args) => {
|
|
114
|
+
return Array.isArray(args[0]) && Array.isArray(args[1]);
|
|
115
|
+
});
|
|
116
|
+
function toText(ops, errMsg) {
|
|
117
|
+
return ops.map((op) => {
|
|
118
|
+
if (op.type === "insert") return op.value;
|
|
119
|
+
throw new Error(errMsg);
|
|
120
|
+
}).join("");
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
//#endregion
|
|
124
|
+
export { diff };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { OpAttributes } from "../OpAttributes/index.mjs";
|
|
2
|
+
import { Delta } from "./index.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/Delta/equals.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* # equals
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* function Delta.equals<T>(a: Delta<T>, b: Delta<T>): boolean
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* Checks if two deltas are equal by comparing their operations and attributes.
|
|
14
|
+
*
|
|
15
|
+
* ## Example
|
|
16
|
+
*
|
|
17
|
+
* ```ts [data-first]
|
|
18
|
+
* import { Delta } from "@monstermann/delta";
|
|
19
|
+
*
|
|
20
|
+
* const a = Delta.insert([], "Hello", { bold: true });
|
|
21
|
+
* const b = Delta.insert([], "Hello", { bold: true });
|
|
22
|
+
* const c = Delta.insert([], "Hello", { italic: true });
|
|
23
|
+
*
|
|
24
|
+
* Delta.equals(a, b); // true
|
|
25
|
+
* Delta.equals(a, c); // false
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* ```ts [data-last]
|
|
29
|
+
* import { Delta } from "@monstermann/delta";
|
|
30
|
+
*
|
|
31
|
+
* const a = Delta.insert([], "Hello", { bold: true });
|
|
32
|
+
* const b = Delta.insert([], "Hello", { bold: true });
|
|
33
|
+
*
|
|
34
|
+
* pipe(a, Delta.equals(b)); // true
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
*/
|
|
38
|
+
declare const equals: {
|
|
39
|
+
<T extends OpAttributes>(b: Delta<NoInfer<T>>): (a: Delta<T>) => boolean;
|
|
40
|
+
<T extends OpAttributes>(a: Delta<T>, b: Delta<NoInfer<T>>): boolean;
|
|
41
|
+
};
|
|
42
|
+
//#endregion
|
|
43
|
+
export { equals };
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { isEqual } from "../OpAttributes/isEqual.mjs";
|
|
2
|
+
import { dfdlT } from "@monstermann/dfdl";
|
|
3
|
+
|
|
4
|
+
//#region src/Delta/equals.ts
|
|
5
|
+
/**
|
|
6
|
+
* # equals
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* function Delta.equals<T>(a: Delta<T>, b: Delta<T>): boolean
|
|
10
|
+
* ```
|
|
11
|
+
*
|
|
12
|
+
* Checks if two deltas are equal by comparing their operations and attributes.
|
|
13
|
+
*
|
|
14
|
+
* ## Example
|
|
15
|
+
*
|
|
16
|
+
* ```ts [data-first]
|
|
17
|
+
* import { Delta } from "@monstermann/delta";
|
|
18
|
+
*
|
|
19
|
+
* const a = Delta.insert([], "Hello", { bold: true });
|
|
20
|
+
* const b = Delta.insert([], "Hello", { bold: true });
|
|
21
|
+
* const c = Delta.insert([], "Hello", { italic: true });
|
|
22
|
+
*
|
|
23
|
+
* Delta.equals(a, b); // true
|
|
24
|
+
* Delta.equals(a, c); // false
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* ```ts [data-last]
|
|
28
|
+
* import { Delta } from "@monstermann/delta";
|
|
29
|
+
*
|
|
30
|
+
* const a = Delta.insert([], "Hello", { bold: true });
|
|
31
|
+
* const b = Delta.insert([], "Hello", { bold: true });
|
|
32
|
+
*
|
|
33
|
+
* pipe(a, Delta.equals(b)); // true
|
|
34
|
+
* ```
|
|
35
|
+
*
|
|
36
|
+
*/
|
|
37
|
+
const equals = dfdlT((a, b) => {
|
|
38
|
+
if (a.length !== b.length) return false;
|
|
39
|
+
for (let i = 0; i < a.length; i++) {
|
|
40
|
+
const aOp = a[i];
|
|
41
|
+
const bOp = b[i];
|
|
42
|
+
if (aOp.type !== bOp.type) return false;
|
|
43
|
+
if (aOp.value !== bOp.value) return false;
|
|
44
|
+
if (!isEqual(aOp.attributes, bOp.attributes)) return false;
|
|
45
|
+
}
|
|
46
|
+
return true;
|
|
47
|
+
}, 2);
|
|
48
|
+
|
|
49
|
+
//#endregion
|
|
50
|
+
export { equals };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { OpAttributes } from "../OpAttributes/index.mjs";
|
|
2
|
+
import { batch } from "./batch.mjs";
|
|
3
|
+
import { chop } from "./chop.mjs";
|
|
4
|
+
import { clean } from "./clean.mjs";
|
|
5
|
+
import { compose } from "./compose.mjs";
|
|
6
|
+
import { concat } from "./concat.mjs";
|
|
7
|
+
import { diff } from "./diff.mjs";
|
|
8
|
+
import { equals } from "./equals.mjs";
|
|
9
|
+
import { insert } from "./insert.mjs";
|
|
10
|
+
import { invert } from "./invert.mjs";
|
|
11
|
+
import { length } from "./length.mjs";
|
|
12
|
+
import { Op } from "../Op/index.mjs";
|
|
13
|
+
import { push } from "./push.mjs";
|
|
14
|
+
import { remove } from "./remove.mjs";
|
|
15
|
+
import { retain } from "./retain.mjs";
|
|
16
|
+
import { slice } from "./slice.mjs";
|
|
17
|
+
import { transform } from "./transform.mjs";
|
|
18
|
+
|
|
19
|
+
//#region src/Delta/index.d.ts
|
|
20
|
+
|
|
21
|
+
type Delta<T extends OpAttributes = OpAttributes> = Op<T>[];
|
|
22
|
+
declare namespace Delta {
|
|
23
|
+
export { batch, chop, clean, compose, concat, diff, equals, insert, invert, length, push, remove, retain, slice, transform };
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
export { Delta };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { batch } from "./batch.mjs";
|
|
2
|
+
import { chop } from "./chop.mjs";
|
|
3
|
+
import { push } from "./push.mjs";
|
|
4
|
+
import { clean } from "./clean.mjs";
|
|
5
|
+
import { compose } from "./compose.mjs";
|
|
6
|
+
import { concat } from "./concat.mjs";
|
|
7
|
+
import { remove } from "./remove.mjs";
|
|
8
|
+
import { retain } from "./retain.mjs";
|
|
9
|
+
import { diff } from "./diff.mjs";
|
|
10
|
+
import { equals } from "./equals.mjs";
|
|
11
|
+
import { insert } from "./insert.mjs";
|
|
12
|
+
import { slice } from "./slice.mjs";
|
|
13
|
+
import { invert } from "./invert.mjs";
|
|
14
|
+
import { length } from "./length.mjs";
|
|
15
|
+
import { transform } from "./transform.mjs";
|
|
16
|
+
|
|
17
|
+
//#region src/Delta/index.js
|
|
18
|
+
const Delta = {
|
|
19
|
+
batch,
|
|
20
|
+
chop,
|
|
21
|
+
clean,
|
|
22
|
+
compose,
|
|
23
|
+
concat,
|
|
24
|
+
diff,
|
|
25
|
+
equals,
|
|
26
|
+
insert,
|
|
27
|
+
invert,
|
|
28
|
+
length,
|
|
29
|
+
push,
|
|
30
|
+
remove,
|
|
31
|
+
retain,
|
|
32
|
+
slice,
|
|
33
|
+
transform
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
//#endregion
|
|
37
|
+
export { Delta };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { NullableOpAttributes, OpAttributes } from "../OpAttributes/index.mjs";
|
|
2
|
+
import { Delta } from "./index.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/Delta/insert.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* # insert
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* function Delta.insert<T>(
|
|
11
|
+
* ops: Delta<T>,
|
|
12
|
+
* content: string,
|
|
13
|
+
* attributes?: T | null,
|
|
14
|
+
* ): Delta<T>
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* Adds an insert operation to the delta.
|
|
18
|
+
*
|
|
19
|
+
* ## Example
|
|
20
|
+
*
|
|
21
|
+
* ```ts [data-first]
|
|
22
|
+
* import { Delta } from "@monstermann/delta";
|
|
23
|
+
*
|
|
24
|
+
* Delta.insert([], "Hello");
|
|
25
|
+
* // [{ type: "insert", value: "Hello" }]
|
|
26
|
+
*
|
|
27
|
+
* Delta.insert([], "Hello", { bold: true });
|
|
28
|
+
* // [{ type: "insert", value: "Hello", attributes: { bold: true } }]
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* ```ts [data-last]
|
|
32
|
+
* import { Delta } from "@monstermann/delta";
|
|
33
|
+
*
|
|
34
|
+
* pipe([], Delta.insert("Hello"));
|
|
35
|
+
* // [{ type: "insert", value: "Hello" }]
|
|
36
|
+
*
|
|
37
|
+
* pipe(
|
|
38
|
+
* [],
|
|
39
|
+
* Delta.insert("Hello", { bold: true }),
|
|
40
|
+
* Delta.insert(" world", { italic: true }),
|
|
41
|
+
* );
|
|
42
|
+
* // [{ type: "insert", value: "Hello", attributes: { bold: true } },
|
|
43
|
+
* // { type: "insert", value: " world", attributes: { italic: true } }]
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
*/
|
|
47
|
+
declare const insert: {
|
|
48
|
+
<T extends OpAttributes>(content: string, attributes?: NullableOpAttributes<NoInfer<T>> | null): (ops: Delta<T>) => Delta<T>;
|
|
49
|
+
<T extends OpAttributes>(ops: Delta<T>, content: string, attributes?: NullableOpAttributes<NoInfer<T>> | null): Delta<T>;
|
|
50
|
+
};
|
|
51
|
+
//#endregion
|
|
52
|
+
export { insert };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { push } from "./push.mjs";
|
|
2
|
+
import { hasKeys } from "../internals/hasKeys.mjs";
|
|
3
|
+
import { dfdlT } from "@monstermann/dfdl";
|
|
4
|
+
|
|
5
|
+
//#region src/Delta/insert.ts
|
|
6
|
+
/**
|
|
7
|
+
* # insert
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* function Delta.insert<T>(
|
|
11
|
+
* ops: Delta<T>,
|
|
12
|
+
* content: string,
|
|
13
|
+
* attributes?: T | null,
|
|
14
|
+
* ): Delta<T>
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* Adds an insert operation to the delta.
|
|
18
|
+
*
|
|
19
|
+
* ## Example
|
|
20
|
+
*
|
|
21
|
+
* ```ts [data-first]
|
|
22
|
+
* import { Delta } from "@monstermann/delta";
|
|
23
|
+
*
|
|
24
|
+
* Delta.insert([], "Hello");
|
|
25
|
+
* // [{ type: "insert", value: "Hello" }]
|
|
26
|
+
*
|
|
27
|
+
* Delta.insert([], "Hello", { bold: true });
|
|
28
|
+
* // [{ type: "insert", value: "Hello", attributes: { bold: true } }]
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* ```ts [data-last]
|
|
32
|
+
* import { Delta } from "@monstermann/delta";
|
|
33
|
+
*
|
|
34
|
+
* pipe([], Delta.insert("Hello"));
|
|
35
|
+
* // [{ type: "insert", value: "Hello" }]
|
|
36
|
+
*
|
|
37
|
+
* pipe(
|
|
38
|
+
* [],
|
|
39
|
+
* Delta.insert("Hello", { bold: true }),
|
|
40
|
+
* Delta.insert(" world", { italic: true }),
|
|
41
|
+
* );
|
|
42
|
+
* // [{ type: "insert", value: "Hello", attributes: { bold: true } },
|
|
43
|
+
* // { type: "insert", value: " world", attributes: { italic: true } }]
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
*/
|
|
47
|
+
const insert = dfdlT((ops, content, attributes) => {
|
|
48
|
+
if (!content.length) return ops;
|
|
49
|
+
return push(ops, {
|
|
50
|
+
attributes: attributes && hasKeys(attributes) ? attributes : void 0,
|
|
51
|
+
type: "insert",
|
|
52
|
+
value: content
|
|
53
|
+
});
|
|
54
|
+
}, (args) => typeof args[0] !== "string");
|
|
55
|
+
|
|
56
|
+
//#endregion
|
|
57
|
+
export { insert };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { OpAttributes } from "../OpAttributes/index.mjs";
|
|
2
|
+
import { Delta } from "./index.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/Delta/invert.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* # invert
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* function Delta.invert<T>(a: Delta<T>, b: Delta<T>): Delta<T>
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* Returns the inverse of a delta against a base document. Applying the inverted delta undoes the original change.
|
|
14
|
+
*
|
|
15
|
+
* ## Example
|
|
16
|
+
*
|
|
17
|
+
* <!-- prettier-ignore -->
|
|
18
|
+
* ```ts [data-first]
|
|
19
|
+
* import { Delta } from "@monstermann/delta";
|
|
20
|
+
*
|
|
21
|
+
* const base = Delta.insert([], "Hello");
|
|
22
|
+
* const change = Delta.retain([], 5, { bold: true });
|
|
23
|
+
*
|
|
24
|
+
* Delta.invert(change, base);
|
|
25
|
+
* // [{ type: "retain", value: 5, attributes: { bold: null } }]
|
|
26
|
+
*
|
|
27
|
+
* const insert = pipe(
|
|
28
|
+
* [],
|
|
29
|
+
* Delta.retain(5),
|
|
30
|
+
* Delta.insert(" world")
|
|
31
|
+
* );
|
|
32
|
+
*
|
|
33
|
+
* Delta.invert(insert, base);
|
|
34
|
+
* // [{ type: "retain", value: 5 },
|
|
35
|
+
* // { type: "remove", value: 6 }]
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* ```ts [data-last]
|
|
39
|
+
* import { Delta } from "@monstermann/delta";
|
|
40
|
+
*
|
|
41
|
+
* const base = Delta.insert([], "Hello");
|
|
42
|
+
* const change = Delta.retain([], 5, { bold: true });
|
|
43
|
+
*
|
|
44
|
+
* pipe(change, Delta.invert(base));
|
|
45
|
+
* // [{ type: "retain", value: 5, attributes: { bold: null } }]
|
|
46
|
+
* ```
|
|
47
|
+
*
|
|
48
|
+
*/
|
|
49
|
+
declare const invert: {
|
|
50
|
+
<T extends OpAttributes>(b: Delta<NoInfer<T>>): (a: Delta<T>) => Delta<T>;
|
|
51
|
+
<T extends OpAttributes>(a: Delta<T>, b: Delta<NoInfer<T>>): Delta<T>;
|
|
52
|
+
};
|
|
53
|
+
//#endregion
|
|
54
|
+
export { invert };
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { chop } from "./chop.mjs";
|
|
2
|
+
import { push } from "./push.mjs";
|
|
3
|
+
import { remove } from "./remove.mjs";
|
|
4
|
+
import { retain } from "./retain.mjs";
|
|
5
|
+
import { slice } from "./slice.mjs";
|
|
6
|
+
import { invert as invert$1 } from "../OpAttributes/invert.mjs";
|
|
7
|
+
import { dfdlT } from "@monstermann/dfdl";
|
|
8
|
+
import { endMutations, markAsMutable, startMutations } from "@monstermann/remmi";
|
|
9
|
+
|
|
10
|
+
//#region src/Delta/invert.ts
|
|
11
|
+
/**
|
|
12
|
+
* # invert
|
|
13
|
+
*
|
|
14
|
+
* ```ts
|
|
15
|
+
* function Delta.invert<T>(a: Delta<T>, b: Delta<T>): Delta<T>
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* Returns the inverse of a delta against a base document. Applying the inverted delta undoes the original change.
|
|
19
|
+
*
|
|
20
|
+
* ## Example
|
|
21
|
+
*
|
|
22
|
+
* <!-- prettier-ignore -->
|
|
23
|
+
* ```ts [data-first]
|
|
24
|
+
* import { Delta } from "@monstermann/delta";
|
|
25
|
+
*
|
|
26
|
+
* const base = Delta.insert([], "Hello");
|
|
27
|
+
* const change = Delta.retain([], 5, { bold: true });
|
|
28
|
+
*
|
|
29
|
+
* Delta.invert(change, base);
|
|
30
|
+
* // [{ type: "retain", value: 5, attributes: { bold: null } }]
|
|
31
|
+
*
|
|
32
|
+
* const insert = pipe(
|
|
33
|
+
* [],
|
|
34
|
+
* Delta.retain(5),
|
|
35
|
+
* Delta.insert(" world")
|
|
36
|
+
* );
|
|
37
|
+
*
|
|
38
|
+
* Delta.invert(insert, base);
|
|
39
|
+
* // [{ type: "retain", value: 5 },
|
|
40
|
+
* // { type: "remove", value: 6 }]
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* ```ts [data-last]
|
|
44
|
+
* import { Delta } from "@monstermann/delta";
|
|
45
|
+
*
|
|
46
|
+
* const base = Delta.insert([], "Hello");
|
|
47
|
+
* const change = Delta.retain([], 5, { bold: true });
|
|
48
|
+
*
|
|
49
|
+
* pipe(change, Delta.invert(base));
|
|
50
|
+
* // [{ type: "retain", value: 5, attributes: { bold: null } }]
|
|
51
|
+
* ```
|
|
52
|
+
*
|
|
53
|
+
*/
|
|
54
|
+
const invert = dfdlT((a, b) => {
|
|
55
|
+
startMutations();
|
|
56
|
+
let newOps = markAsMutable([]);
|
|
57
|
+
let baseIndex = 0;
|
|
58
|
+
for (const aOp of a) if (aOp.type === "insert") newOps = remove(newOps, aOp.value.length);
|
|
59
|
+
else if (aOp.type === "retain" && aOp.attributes == null) {
|
|
60
|
+
newOps = retain(newOps, aOp.value);
|
|
61
|
+
baseIndex += aOp.value;
|
|
62
|
+
} else {
|
|
63
|
+
const length = aOp.value;
|
|
64
|
+
for (const bOp of slice(b, baseIndex, baseIndex + length)) if (aOp.type === "remove") newOps = push(newOps, bOp);
|
|
65
|
+
else if (aOp.attributes) {
|
|
66
|
+
const bOpLength = bOp.type === "insert" ? bOp.value.length : bOp.value;
|
|
67
|
+
newOps = retain(newOps, bOpLength, invert$1(aOp.attributes, bOp.attributes));
|
|
68
|
+
}
|
|
69
|
+
baseIndex += length;
|
|
70
|
+
}
|
|
71
|
+
newOps = chop(newOps);
|
|
72
|
+
endMutations();
|
|
73
|
+
return newOps;
|
|
74
|
+
}, 2);
|
|
75
|
+
|
|
76
|
+
//#endregion
|
|
77
|
+
export { invert };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { OpAttributes } from "../OpAttributes/index.mjs";
|
|
2
|
+
import { Delta } from "./index.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/Delta/length.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* # length
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* function Delta.length<T>(ops: Delta<T>): number
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* Returns the total length of the delta (sum of all operation lengths).
|
|
14
|
+
*
|
|
15
|
+
* ## Example
|
|
16
|
+
*
|
|
17
|
+
* <!-- prettier-ignore -->
|
|
18
|
+
* ```ts [data-first]
|
|
19
|
+
* import { Delta } from "@monstermann/delta";
|
|
20
|
+
*
|
|
21
|
+
* Delta.length(Delta.insert([], "Hello")); // 5
|
|
22
|
+
*
|
|
23
|
+
* Delta.length(pipe(
|
|
24
|
+
* [],
|
|
25
|
+
* Delta.insert("Hello"),
|
|
26
|
+
* Delta.retain(3),
|
|
27
|
+
* Delta.remove(2)
|
|
28
|
+
* )); // 10
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* ```ts [data-last]
|
|
32
|
+
* import { Delta } from "@monstermann/delta";
|
|
33
|
+
*
|
|
34
|
+
* pipe([], Delta.insert("Hello"), Delta.length()); // 5
|
|
35
|
+
*
|
|
36
|
+
* pipe(
|
|
37
|
+
* [],
|
|
38
|
+
* Delta.insert("Hello"),
|
|
39
|
+
* Delta.retain(3),
|
|
40
|
+
* Delta.remove(2),
|
|
41
|
+
* Delta.length(),
|
|
42
|
+
* ); // 10
|
|
43
|
+
* ```
|
|
44
|
+
*
|
|
45
|
+
*/
|
|
46
|
+
declare const length: {
|
|
47
|
+
(): <T extends OpAttributes>(ops: Delta<T>) => number;
|
|
48
|
+
<T extends OpAttributes>(ops: Delta<T>): number;
|
|
49
|
+
};
|
|
50
|
+
//#endregion
|
|
51
|
+
export { length };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { dfdlT } from "@monstermann/dfdl";
|
|
2
|
+
|
|
3
|
+
//#region src/Delta/length.ts
|
|
4
|
+
/**
|
|
5
|
+
* # length
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* function Delta.length<T>(ops: Delta<T>): number
|
|
9
|
+
* ```
|
|
10
|
+
*
|
|
11
|
+
* Returns the total length of the delta (sum of all operation lengths).
|
|
12
|
+
*
|
|
13
|
+
* ## Example
|
|
14
|
+
*
|
|
15
|
+
* <!-- prettier-ignore -->
|
|
16
|
+
* ```ts [data-first]
|
|
17
|
+
* import { Delta } from "@monstermann/delta";
|
|
18
|
+
*
|
|
19
|
+
* Delta.length(Delta.insert([], "Hello")); // 5
|
|
20
|
+
*
|
|
21
|
+
* Delta.length(pipe(
|
|
22
|
+
* [],
|
|
23
|
+
* Delta.insert("Hello"),
|
|
24
|
+
* Delta.retain(3),
|
|
25
|
+
* Delta.remove(2)
|
|
26
|
+
* )); // 10
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* ```ts [data-last]
|
|
30
|
+
* import { Delta } from "@monstermann/delta";
|
|
31
|
+
*
|
|
32
|
+
* pipe([], Delta.insert("Hello"), Delta.length()); // 5
|
|
33
|
+
*
|
|
34
|
+
* pipe(
|
|
35
|
+
* [],
|
|
36
|
+
* Delta.insert("Hello"),
|
|
37
|
+
* Delta.retain(3),
|
|
38
|
+
* Delta.remove(2),
|
|
39
|
+
* Delta.length(),
|
|
40
|
+
* ); // 10
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
*/
|
|
44
|
+
const length = dfdlT((ops) => {
|
|
45
|
+
return ops.reduce((acc, op) => {
|
|
46
|
+
return acc + (op.type === "insert" ? op.value.length : op.value);
|
|
47
|
+
}, 0);
|
|
48
|
+
}, 1);
|
|
49
|
+
|
|
50
|
+
//#endregion
|
|
51
|
+
export { length };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { OpAttributes } from "../OpAttributes/index.mjs";
|
|
2
|
+
import { Op } from "../Op/index.mjs";
|
|
3
|
+
import { Delta } from "./index.mjs";
|
|
4
|
+
|
|
5
|
+
//#region src/Delta/push.d.ts
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* # push
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* function Delta.push<T>(ops: Delta<T>, op: Op<T>): Delta<T>
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* Pushes an operation onto the delta, merging with the previous operation if possible.
|
|
15
|
+
*
|
|
16
|
+
* ## Example
|
|
17
|
+
*
|
|
18
|
+
* ```ts [data-first]
|
|
19
|
+
* import { Delta } from "@monstermann/delta";
|
|
20
|
+
*
|
|
21
|
+
* Delta.push([], { type: "insert", value: "Hello" });
|
|
22
|
+
* // [{ type: "insert", value: "Hello" }]
|
|
23
|
+
*
|
|
24
|
+
* Delta.push(Delta.push([], { type: "insert", value: "Hello" }), {
|
|
25
|
+
* type: "insert",
|
|
26
|
+
* value: " world",
|
|
27
|
+
* });
|
|
28
|
+
* // [{ type: "insert", value: "Hello world" }]
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* ```ts [data-last]
|
|
32
|
+
* import { Delta } from "@monstermann/delta";
|
|
33
|
+
*
|
|
34
|
+
* pipe([], Delta.push({ type: "insert", value: "Hello" }));
|
|
35
|
+
* // [{ type: "insert", value: "Hello" }]
|
|
36
|
+
*
|
|
37
|
+
* pipe(
|
|
38
|
+
* [],
|
|
39
|
+
* Delta.push({ type: "insert", value: "Hello" }),
|
|
40
|
+
* Delta.push({ type: "insert", value: " world" }),
|
|
41
|
+
* );
|
|
42
|
+
* // [{ type: "insert", value: "Hello world" }]
|
|
43
|
+
* ```
|
|
44
|
+
*
|
|
45
|
+
*/
|
|
46
|
+
declare const push: {
|
|
47
|
+
<T extends OpAttributes>(op: Op<NoInfer<T>>): (ops: Delta<T>) => Delta<T>;
|
|
48
|
+
<T extends OpAttributes>(ops: Delta<T>, op: Op<NoInfer<T>>): Delta<T>;
|
|
49
|
+
};
|
|
50
|
+
//#endregion
|
|
51
|
+
export { push };
|