@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.
Files changed (56) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +695 -0
  3. package/dist/Delta/batch.d.mts +57 -0
  4. package/dist/Delta/batch.mjs +61 -0
  5. package/dist/Delta/chop.d.mts +56 -0
  6. package/dist/Delta/chop.mjs +60 -0
  7. package/dist/Delta/clean.d.mts +57 -0
  8. package/dist/Delta/clean.mjs +61 -0
  9. package/dist/Delta/compose.d.mts +58 -0
  10. package/dist/Delta/compose.mjs +100 -0
  11. package/dist/Delta/concat.d.mts +50 -0
  12. package/dist/Delta/concat.mjs +51 -0
  13. package/dist/Delta/diff.d.mts +73 -0
  14. package/dist/Delta/diff.mjs +124 -0
  15. package/dist/Delta/equals.d.mts +43 -0
  16. package/dist/Delta/equals.mjs +50 -0
  17. package/dist/Delta/index.d.mts +26 -0
  18. package/dist/Delta/index.mjs +37 -0
  19. package/dist/Delta/insert.d.mts +52 -0
  20. package/dist/Delta/insert.mjs +57 -0
  21. package/dist/Delta/invert.d.mts +54 -0
  22. package/dist/Delta/invert.mjs +77 -0
  23. package/dist/Delta/length.d.mts +51 -0
  24. package/dist/Delta/length.mjs +51 -0
  25. package/dist/Delta/push.d.mts +51 -0
  26. package/dist/Delta/push.mjs +87 -0
  27. package/dist/Delta/remove.d.mts +41 -0
  28. package/dist/Delta/remove.mjs +46 -0
  29. package/dist/Delta/retain.d.mts +70 -0
  30. package/dist/Delta/retain.mjs +76 -0
  31. package/dist/Delta/slice.d.mts +64 -0
  32. package/dist/Delta/slice.mjs +77 -0
  33. package/dist/Delta/transform.d.mts +63 -0
  34. package/dist/Delta/transform.mjs +91 -0
  35. package/dist/Op/index.d.mts +21 -0
  36. package/dist/OpAttributes/compose.d.mts +6 -0
  37. package/dist/OpAttributes/compose.mjs +25 -0
  38. package/dist/OpAttributes/diff.d.mts +6 -0
  39. package/dist/OpAttributes/diff.mjs +14 -0
  40. package/dist/OpAttributes/index.d.mts +15 -0
  41. package/dist/OpAttributes/invert.d.mts +6 -0
  42. package/dist/OpAttributes/invert.mjs +16 -0
  43. package/dist/OpAttributes/isEqual.d.mts +6 -0
  44. package/dist/OpAttributes/isEqual.mjs +16 -0
  45. package/dist/OpAttributes/transform.d.mts +6 -0
  46. package/dist/OpAttributes/transform.mjs +13 -0
  47. package/dist/OpIterator/create.mjs +11 -0
  48. package/dist/OpIterator/hasNext.mjs +9 -0
  49. package/dist/OpIterator/next.mjs +36 -0
  50. package/dist/OpIterator/peek.mjs +7 -0
  51. package/dist/OpIterator/peekLength.mjs +9 -0
  52. package/dist/OpIterator/peekType.mjs +7 -0
  53. package/dist/index.d.mts +2 -0
  54. package/dist/index.mjs +3 -0
  55. package/dist/internals/hasKeys.mjs +8 -0
  56. package/package.json +42 -0
@@ -0,0 +1,57 @@
1
+ import { OpAttributes } from "../OpAttributes/index.mjs";
2
+ import { Delta } from "./index.mjs";
3
+
4
+ //#region src/Delta/batch.d.ts
5
+
6
+ /**
7
+ * # batch
8
+ *
9
+ * ```ts
10
+ * function Delta.batch<T>(
11
+ * ops: Delta<T>,
12
+ * transform: (delta: Delta<T>) => Delta<T>,
13
+ * ): Delta<T>
14
+ * ```
15
+ *
16
+ * Batches multiple delta operations together for improved performance.
17
+ *
18
+ * ## Example
19
+ *
20
+ * ```ts [data-first]
21
+ * import { Delta } from "@monstermann/delta";
22
+ *
23
+ * Delta.batch([], (delta) => {
24
+ * // First change copies:
25
+ * delta = Delta.insert(delta, "Hello", { bold: true });
26
+ * // Other changes mutate:
27
+ * delta = Delta.insert(delta, " world");
28
+ * return delta;
29
+ * });
30
+ * // [{ type: "insert", value: "Hello", attributes: { bold: true } },
31
+ * // { type: "insert", value: " world" }]
32
+ * ```
33
+ *
34
+ * ```ts [data-last]
35
+ * import { Delta } from "@monstermann/delta";
36
+ *
37
+ * pipe(
38
+ * [],
39
+ * Delta.batch((delta) => {
40
+ * // First change copies:
41
+ * delta = Delta.insert(delta, "Hello", { bold: true });
42
+ * // Other changes mutate:
43
+ * delta = Delta.insert(delta, " world");
44
+ * return delta;
45
+ * }),
46
+ * );
47
+ * // [{ type: "insert", value: "Hello", attributes: { bold: true } },
48
+ * // { type: "insert", value: " world" }]
49
+ * ```
50
+ *
51
+ */
52
+ declare const batch: {
53
+ <T extends OpAttributes>(transform: (delta: Delta<NoInfer<T>>) => Delta<NoInfer<T>>): (ops: Delta<T>) => Delta<T>;
54
+ <T extends OpAttributes>(ops: Delta<T>, transform: (delta: Delta<NoInfer<T>>) => Delta<NoInfer<T>>): Delta<T>;
55
+ };
56
+ //#endregion
57
+ export { batch };
@@ -0,0 +1,61 @@
1
+ import { dfdlT } from "@monstermann/dfdl";
2
+ import { endMutations, startMutations } from "@monstermann/remmi";
3
+
4
+ //#region src/Delta/batch.ts
5
+ /**
6
+ * # batch
7
+ *
8
+ * ```ts
9
+ * function Delta.batch<T>(
10
+ * ops: Delta<T>,
11
+ * transform: (delta: Delta<T>) => Delta<T>,
12
+ * ): Delta<T>
13
+ * ```
14
+ *
15
+ * Batches multiple delta operations together for improved performance.
16
+ *
17
+ * ## Example
18
+ *
19
+ * ```ts [data-first]
20
+ * import { Delta } from "@monstermann/delta";
21
+ *
22
+ * Delta.batch([], (delta) => {
23
+ * // First change copies:
24
+ * delta = Delta.insert(delta, "Hello", { bold: true });
25
+ * // Other changes mutate:
26
+ * delta = Delta.insert(delta, " world");
27
+ * return delta;
28
+ * });
29
+ * // [{ type: "insert", value: "Hello", attributes: { bold: true } },
30
+ * // { type: "insert", value: " world" }]
31
+ * ```
32
+ *
33
+ * ```ts [data-last]
34
+ * import { Delta } from "@monstermann/delta";
35
+ *
36
+ * pipe(
37
+ * [],
38
+ * Delta.batch((delta) => {
39
+ * // First change copies:
40
+ * delta = Delta.insert(delta, "Hello", { bold: true });
41
+ * // Other changes mutate:
42
+ * delta = Delta.insert(delta, " world");
43
+ * return delta;
44
+ * }),
45
+ * );
46
+ * // [{ type: "insert", value: "Hello", attributes: { bold: true } },
47
+ * // { type: "insert", value: " world" }]
48
+ * ```
49
+ *
50
+ */
51
+ const batch = dfdlT((ops, transform) => {
52
+ startMutations();
53
+ try {
54
+ return transform(ops);
55
+ } finally {
56
+ endMutations();
57
+ }
58
+ }, 2);
59
+
60
+ //#endregion
61
+ export { batch };
@@ -0,0 +1,56 @@
1
+ import { OpAttributes } from "../OpAttributes/index.mjs";
2
+ import { Delta } from "./index.mjs";
3
+
4
+ //#region src/Delta/chop.d.ts
5
+
6
+ /**
7
+ * # chop
8
+ *
9
+ * ```ts
10
+ * function Delta.chop<T>(ops: Delta<T>): Delta<T>
11
+ * ```
12
+ *
13
+ * Removes a trailing retain operation if it has no attributes.
14
+ *
15
+ * ## Example
16
+ *
17
+ * <!-- prettier-ignore -->
18
+ * ```ts [data-first]
19
+ * import { Delta } from "@monstermann/delta";
20
+ *
21
+ * Delta.chop(pipe(
22
+ * [],
23
+ * Delta.insert("Hello"),
24
+ * Delta.retain(5)
25
+ * ));
26
+ * // [{ type: "insert", value: "Hello" }]
27
+ *
28
+ * Delta.chop(pipe(
29
+ * [],
30
+ * Delta.insert("Hello"),
31
+ * Delta.retain(5, { bold: true })
32
+ * ));
33
+ * // [{ type: "insert", value: "Hello" },
34
+ * // { type: "retain", value: 5, attributes: { bold: true } }]
35
+ * ```
36
+ *
37
+ * <!-- prettier-ignore -->
38
+ * ```ts [data-last]
39
+ * import { Delta } from "@monstermann/delta";
40
+ *
41
+ * pipe(
42
+ * [],
43
+ * Delta.insert("Hello"),
44
+ * Delta.retain(5),
45
+ * Delta.chop()
46
+ * );
47
+ * // [{ type: "insert", value: "Hello" }]
48
+ * ```
49
+ *
50
+ */
51
+ declare const chop: {
52
+ (): <T extends OpAttributes>(ops: Delta<T>) => Delta<T>;
53
+ <T extends OpAttributes>(ops: Delta<T>): Delta<T>;
54
+ };
55
+ //#endregion
56
+ export { chop };
@@ -0,0 +1,60 @@
1
+ import { dfdlT } from "@monstermann/dfdl";
2
+ import { cloneArray } from "@monstermann/remmi";
3
+
4
+ //#region src/Delta/chop.ts
5
+ /**
6
+ * # chop
7
+ *
8
+ * ```ts
9
+ * function Delta.chop<T>(ops: Delta<T>): Delta<T>
10
+ * ```
11
+ *
12
+ * Removes a trailing retain operation if it has no attributes.
13
+ *
14
+ * ## Example
15
+ *
16
+ * <!-- prettier-ignore -->
17
+ * ```ts [data-first]
18
+ * import { Delta } from "@monstermann/delta";
19
+ *
20
+ * Delta.chop(pipe(
21
+ * [],
22
+ * Delta.insert("Hello"),
23
+ * Delta.retain(5)
24
+ * ));
25
+ * // [{ type: "insert", value: "Hello" }]
26
+ *
27
+ * Delta.chop(pipe(
28
+ * [],
29
+ * Delta.insert("Hello"),
30
+ * Delta.retain(5, { bold: true })
31
+ * ));
32
+ * // [{ type: "insert", value: "Hello" },
33
+ * // { type: "retain", value: 5, attributes: { bold: true } }]
34
+ * ```
35
+ *
36
+ * <!-- prettier-ignore -->
37
+ * ```ts [data-last]
38
+ * import { Delta } from "@monstermann/delta";
39
+ *
40
+ * pipe(
41
+ * [],
42
+ * Delta.insert("Hello"),
43
+ * Delta.retain(5),
44
+ * Delta.chop()
45
+ * );
46
+ * // [{ type: "insert", value: "Hello" }]
47
+ * ```
48
+ *
49
+ */
50
+ const chop = dfdlT((ops) => {
51
+ const lastOp = ops[ops.length - 1];
52
+ if (lastOp?.type === "retain" && !lastOp.attributes) {
53
+ ops = cloneArray(ops);
54
+ ops.pop();
55
+ }
56
+ return ops;
57
+ }, 1);
58
+
59
+ //#endregion
60
+ export { chop };
@@ -0,0 +1,57 @@
1
+ import { OpAttributes } from "../OpAttributes/index.mjs";
2
+ import { Delta } from "./index.mjs";
3
+
4
+ //#region src/Delta/clean.d.ts
5
+
6
+ /**
7
+ * # clean
8
+ *
9
+ * ```ts
10
+ * function Delta.clean<T>(ops: Delta<T>): Delta<T>
11
+ * ```
12
+ *
13
+ * Normalizes the delta by merging consecutive operations of the same type and attributes.
14
+ *
15
+ * ## Example
16
+ *
17
+ * <!-- prettier-ignore -->
18
+ * ```ts [data-first]
19
+ * import { Delta } from "@monstermann/delta";
20
+ *
21
+ * Delta.clean(pipe(
22
+ * [],
23
+ * Delta.insert("Hello"),
24
+ * Delta.insert(" world")
25
+ * ));
26
+ * // [{ type: "insert", value: "Hello world" }]
27
+ *
28
+ * Delta.clean(
29
+ * pipe(
30
+ * [],
31
+ * Delta.insert("Hello", { bold: true }),
32
+ * Delta.insert(" world", { bold: true }),
33
+ * ),
34
+ * );
35
+ * // [{ type: "insert", value: "Hello world", attributes: { bold: true } }]
36
+ * ```
37
+ *
38
+ * <!-- prettier-ignore -->
39
+ * ```ts [data-last]
40
+ * import { Delta } from "@monstermann/delta";
41
+ *
42
+ * pipe(
43
+ * [],
44
+ * Delta.insert("Hello"),
45
+ * Delta.insert(" world"),
46
+ * Delta.clean()
47
+ * );
48
+ * // [{ type: "insert", value: "Hello world" }]
49
+ * ```
50
+ *
51
+ */
52
+ declare const clean: {
53
+ (): <T extends OpAttributes>(ops: Delta<T>) => Delta<T>;
54
+ <T extends OpAttributes>(ops: Delta<T>): Delta<T>;
55
+ };
56
+ //#endregion
57
+ export { clean };
@@ -0,0 +1,61 @@
1
+ import { push } from "./push.mjs";
2
+ import { dfdlT } from "@monstermann/dfdl";
3
+ import { endMutations, markAsMutable, startMutations } from "@monstermann/remmi";
4
+
5
+ //#region src/Delta/clean.ts
6
+ /**
7
+ * # clean
8
+ *
9
+ * ```ts
10
+ * function Delta.clean<T>(ops: Delta<T>): Delta<T>
11
+ * ```
12
+ *
13
+ * Normalizes the delta by merging consecutive operations of the same type and attributes.
14
+ *
15
+ * ## Example
16
+ *
17
+ * <!-- prettier-ignore -->
18
+ * ```ts [data-first]
19
+ * import { Delta } from "@monstermann/delta";
20
+ *
21
+ * Delta.clean(pipe(
22
+ * [],
23
+ * Delta.insert("Hello"),
24
+ * Delta.insert(" world")
25
+ * ));
26
+ * // [{ type: "insert", value: "Hello world" }]
27
+ *
28
+ * Delta.clean(
29
+ * pipe(
30
+ * [],
31
+ * Delta.insert("Hello", { bold: true }),
32
+ * Delta.insert(" world", { bold: true }),
33
+ * ),
34
+ * );
35
+ * // [{ type: "insert", value: "Hello world", attributes: { bold: true } }]
36
+ * ```
37
+ *
38
+ * <!-- prettier-ignore -->
39
+ * ```ts [data-last]
40
+ * import { Delta } from "@monstermann/delta";
41
+ *
42
+ * pipe(
43
+ * [],
44
+ * Delta.insert("Hello"),
45
+ * Delta.insert(" world"),
46
+ * Delta.clean()
47
+ * );
48
+ * // [{ type: "insert", value: "Hello world" }]
49
+ * ```
50
+ *
51
+ */
52
+ const clean = dfdlT((ops) => {
53
+ startMutations();
54
+ let newOps = markAsMutable([]);
55
+ for (const op of ops) newOps = push(newOps, op);
56
+ endMutations();
57
+ return newOps.length === ops.length ? ops : newOps;
58
+ }, 1);
59
+
60
+ //#endregion
61
+ export { clean };
@@ -0,0 +1,58 @@
1
+ import { OpAttributes } from "../OpAttributes/index.mjs";
2
+ import { Delta } from "./index.mjs";
3
+
4
+ //#region src/Delta/compose.d.ts
5
+
6
+ /**
7
+ * # compose
8
+ *
9
+ * ```ts
10
+ * function Delta.compose<T>(a: Delta<T>, b: Delta<T>): Delta<T>
11
+ * ```
12
+ *
13
+ * Composes two deltas into a single delta that represents applying `a` then `b`.
14
+ *
15
+ * ## Example
16
+ *
17
+ * <!-- prettier-ignore -->
18
+ * ```ts [data-first]
19
+ * import { Delta } from "@monstermann/delta";
20
+ *
21
+ * const a = Delta.insert([], "Hello");
22
+ * const b = pipe(
23
+ * [],
24
+ * Delta.retain(5),
25
+ * Delta.insert(" world")
26
+ * );
27
+ *
28
+ * Delta.compose(a, b);
29
+ * // [{ type: "insert", value: "Hello world" }]
30
+ *
31
+ * const format = Delta.retain([], 5, { bold: true });
32
+ *
33
+ * Delta.compose(a, format);
34
+ * // [{ type: "insert", value: "Hello", attributes: { bold: true } }]
35
+ * ```
36
+ *
37
+ * <!-- prettier-ignore -->
38
+ * ```ts [data-last]
39
+ * import { Delta } from "@monstermann/delta";
40
+ *
41
+ * const a = Delta.insert([], "Hello");
42
+ * const b = pipe(
43
+ * [],
44
+ * Delta.retain(5),
45
+ * Delta.insert(" world")
46
+ * );
47
+ *
48
+ * pipe(a, Delta.compose(b));
49
+ * // [{ type: "insert", value: "Hello world" }]
50
+ * ```
51
+ *
52
+ */
53
+ declare const compose: {
54
+ <T extends OpAttributes>(b: Delta<NoInfer<T>>): (a: Delta<T>) => Delta<T>;
55
+ <T extends OpAttributes>(a: Delta<T>, b: Delta<NoInfer<T>>): Delta<T>;
56
+ };
57
+ //#endregion
58
+ export { compose };
@@ -0,0 +1,100 @@
1
+ import { chop } from "./chop.mjs";
2
+ import { push } from "./push.mjs";
3
+ import { compose as compose$1 } from "../OpAttributes/compose.mjs";
4
+ import { create } from "../OpIterator/create.mjs";
5
+ import { peek } from "../OpIterator/peek.mjs";
6
+ import { peekType } from "../OpIterator/peekType.mjs";
7
+ import { peekLength } from "../OpIterator/peekLength.mjs";
8
+ import { next } from "../OpIterator/next.mjs";
9
+ import { hasNext } from "../OpIterator/hasNext.mjs";
10
+ import { dfdlT } from "@monstermann/dfdl";
11
+ import { endMutations, markAsMutable, startMutations } from "@monstermann/remmi";
12
+
13
+ //#region src/Delta/compose.ts
14
+ /**
15
+ * # compose
16
+ *
17
+ * ```ts
18
+ * function Delta.compose<T>(a: Delta<T>, b: Delta<T>): Delta<T>
19
+ * ```
20
+ *
21
+ * Composes two deltas into a single delta that represents applying `a` then `b`.
22
+ *
23
+ * ## Example
24
+ *
25
+ * <!-- prettier-ignore -->
26
+ * ```ts [data-first]
27
+ * import { Delta } from "@monstermann/delta";
28
+ *
29
+ * const a = Delta.insert([], "Hello");
30
+ * const b = pipe(
31
+ * [],
32
+ * Delta.retain(5),
33
+ * Delta.insert(" world")
34
+ * );
35
+ *
36
+ * Delta.compose(a, b);
37
+ * // [{ type: "insert", value: "Hello world" }]
38
+ *
39
+ * const format = Delta.retain([], 5, { bold: true });
40
+ *
41
+ * Delta.compose(a, format);
42
+ * // [{ type: "insert", value: "Hello", attributes: { bold: true } }]
43
+ * ```
44
+ *
45
+ * <!-- prettier-ignore -->
46
+ * ```ts [data-last]
47
+ * import { Delta } from "@monstermann/delta";
48
+ *
49
+ * const a = Delta.insert([], "Hello");
50
+ * const b = pipe(
51
+ * [],
52
+ * Delta.retain(5),
53
+ * Delta.insert(" world")
54
+ * );
55
+ *
56
+ * pipe(a, Delta.compose(b));
57
+ * // [{ type: "insert", value: "Hello world" }]
58
+ * ```
59
+ *
60
+ */
61
+ const compose = dfdlT((a, b) => {
62
+ const aIter = create(a);
63
+ const bIter = create(b);
64
+ const bHead = peek(bIter);
65
+ startMutations();
66
+ let ops = markAsMutable([]);
67
+ if (bHead?.type === "retain" && bHead.attributes == null) {
68
+ let bRetain = bHead.value;
69
+ while (peekType(aIter) === "insert" && peekLength(aIter) <= bRetain) {
70
+ bRetain -= peekLength(aIter);
71
+ ops.push(next(aIter));
72
+ }
73
+ if (bHead.value - bRetain > 0) next(bIter, bHead.value - bRetain);
74
+ }
75
+ while (hasNext(aIter) || hasNext(bIter)) if (peekType(bIter) === "insert") ops = push(ops, next(bIter));
76
+ else if (peekType(aIter) === "remove") ops = push(ops, next(aIter));
77
+ else {
78
+ const length = Math.min(peekLength(aIter), peekLength(bIter));
79
+ const aOp = next(aIter, length);
80
+ const bOp = next(bIter, length);
81
+ if (bOp.type === "retain") {
82
+ if (aOp.type === "retain") ops = push(ops, {
83
+ attributes: compose$1(aOp.attributes, bOp.attributes, true),
84
+ type: "retain",
85
+ value: length
86
+ });
87
+ else if (aOp.type === "insert") ops = push(ops, {
88
+ attributes: compose$1(aOp.attributes, bOp.attributes),
89
+ type: "insert",
90
+ value: aOp.value
91
+ });
92
+ } else if (bOp.type === "remove" && aOp.type === "retain") ops = push(ops, bOp);
93
+ }
94
+ ops = chop(ops);
95
+ endMutations();
96
+ return ops;
97
+ }, 2);
98
+
99
+ //#endregion
100
+ export { compose };
@@ -0,0 +1,50 @@
1
+ import { OpAttributes } from "../OpAttributes/index.mjs";
2
+ import { Delta } from "./index.mjs";
3
+
4
+ //#region src/Delta/concat.d.ts
5
+
6
+ /**
7
+ * # concat
8
+ *
9
+ * ```ts
10
+ * function Delta.concat<T>(a: Delta<T>, b: Delta<T>): Delta<T>
11
+ * ```
12
+ *
13
+ * Concatenates two deltas together, merging adjacent operations if possible.
14
+ *
15
+ * ## Example
16
+ *
17
+ * ```ts [data-first]
18
+ * import { Delta } from "@monstermann/delta";
19
+ *
20
+ * const a = Delta.insert([], "Hello");
21
+ * const b = Delta.insert([], " world");
22
+ *
23
+ * Delta.concat(a, b);
24
+ * // [{ type: "insert", value: "Hello world" }]
25
+ *
26
+ * const bold = Delta.insert([], "Hello", { bold: true });
27
+ * const italic = Delta.insert([], " world", { italic: true });
28
+ *
29
+ * Delta.concat(bold, italic);
30
+ * // [{ type: "insert", value: "Hello", attributes: { bold: true } },
31
+ * // { type: "insert", value: " world", attributes: { italic: true } }]
32
+ * ```
33
+ *
34
+ * ```ts [data-last]
35
+ * import { Delta } from "@monstermann/delta";
36
+ *
37
+ * const a = Delta.insert([], "Hello");
38
+ * const b = Delta.insert([], " world");
39
+ *
40
+ * pipe(a, Delta.concat(b));
41
+ * // [{ type: "insert", value: "Hello world" }]
42
+ * ```
43
+ *
44
+ */
45
+ declare const concat: {
46
+ <T extends OpAttributes>(b: Delta<NoInfer<T>>): (a: Delta<T>) => Delta<T>;
47
+ <T extends OpAttributes>(a: Delta<T>, b: Delta<NoInfer<T>>): Delta<T>;
48
+ };
49
+ //#endregion
50
+ export { concat };
@@ -0,0 +1,51 @@
1
+ import { push } from "./push.mjs";
2
+ import { dfdlT } from "@monstermann/dfdl";
3
+
4
+ //#region src/Delta/concat.ts
5
+ /**
6
+ * # concat
7
+ *
8
+ * ```ts
9
+ * function Delta.concat<T>(a: Delta<T>, b: Delta<T>): Delta<T>
10
+ * ```
11
+ *
12
+ * Concatenates two deltas together, merging adjacent operations if possible.
13
+ *
14
+ * ## Example
15
+ *
16
+ * ```ts [data-first]
17
+ * import { Delta } from "@monstermann/delta";
18
+ *
19
+ * const a = Delta.insert([], "Hello");
20
+ * const b = Delta.insert([], " world");
21
+ *
22
+ * Delta.concat(a, b);
23
+ * // [{ type: "insert", value: "Hello world" }]
24
+ *
25
+ * const bold = Delta.insert([], "Hello", { bold: true });
26
+ * const italic = Delta.insert([], " world", { italic: true });
27
+ *
28
+ * Delta.concat(bold, italic);
29
+ * // [{ type: "insert", value: "Hello", attributes: { bold: true } },
30
+ * // { type: "insert", value: " world", attributes: { italic: true } }]
31
+ * ```
32
+ *
33
+ * ```ts [data-last]
34
+ * import { Delta } from "@monstermann/delta";
35
+ *
36
+ * const a = Delta.insert([], "Hello");
37
+ * const b = Delta.insert([], " world");
38
+ *
39
+ * pipe(a, Delta.concat(b));
40
+ * // [{ type: "insert", value: "Hello world" }]
41
+ * ```
42
+ *
43
+ */
44
+ const concat = dfdlT((a, b) => {
45
+ if (!b.length) return a;
46
+ if (!a.length) return b;
47
+ return push(a, b[0]).concat(b.slice(1));
48
+ }, 2);
49
+
50
+ //#endregion
51
+ export { concat };
@@ -0,0 +1,73 @@
1
+ import { OpAttributes } from "../OpAttributes/index.mjs";
2
+ import { Delta } from "./index.mjs";
3
+
4
+ //#region src/Delta/diff.d.ts
5
+
6
+ /**
7
+ * # diff
8
+ *
9
+ * ```ts
10
+ * function Delta.diff<T>(a: Delta<T>, b: Delta<T>, cursor?: number): Delta<T>
11
+ * ```
12
+ *
13
+ * Computes the difference between two document deltas, returning a delta that transforms `a` into `b`.
14
+ *
15
+ * 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.
16
+ *
17
+ * ## Example
18
+ *
19
+ * ```ts [data-first]
20
+ * import { Delta } from "@monstermann/delta";
21
+ *
22
+ * const a = Delta.insert([], "Hello");
23
+ * const b = Delta.insert([], "Hello world");
24
+ *
25
+ * Delta.diff(a, b);
26
+ * // [{ type: "retain", value: 5 },
27
+ * // { type: "insert", value: " world" }]
28
+ *
29
+ * const plain = Delta.insert([], "Hello");
30
+ * const bold = Delta.insert([], "Hello", { bold: true });
31
+ *
32
+ * Delta.diff(plain, bold);
33
+ * // [{ type: "retain", value: 5, attributes: { bold: true } }]
34
+ * ```
35
+ *
36
+ * ```ts [data-last]
37
+ * import { Delta } from "@monstermann/delta";
38
+ *
39
+ * const a = Delta.insert([], "Hello");
40
+ * const b = Delta.insert([], "Hello world");
41
+ *
42
+ * pipe(a, Delta.diff(b));
43
+ * // [{ type: "retain", value: 5 },
44
+ * // { type: "insert", value: " world" }]
45
+ * ```
46
+ *
47
+ * ## Cursor hint
48
+ *
49
+ * When text changes are ambiguous, the cursor position determines where the change is placed:
50
+ *
51
+ * ```ts
52
+ * import { Delta } from "@monstermann/delta";
53
+ *
54
+ * const a = Delta.insert([], "foo");
55
+ * const b = Delta.insert([], "foo bar foo");
56
+ *
57
+ * // cursor=3: user typed " bar foo" at the end
58
+ * Delta.diff(a, b, 3);
59
+ * // [{ type: "retain", value: 3 },
60
+ * // { type: "insert", value: " bar foo" }]
61
+ *
62
+ * // cursor=0: user typed "foo bar " at the beginning
63
+ * Delta.diff(a, b, 0);
64
+ * // [{ type: "insert", value: "foo bar " }]
65
+ * ```
66
+ *
67
+ */
68
+ declare const diff: {
69
+ <T extends OpAttributes>(b: Delta<NoInfer<T>>, cursor?: number): (a: Delta<T>) => Delta<T>;
70
+ <T extends OpAttributes>(a: Delta<T>, b: Delta<NoInfer<T>>, cursor?: number): Delta<T>;
71
+ };
72
+ //#endregion
73
+ export { diff };