@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
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) Michael Ostermann
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,695 @@
1
+ <div align="center">
2
+
3
+ <h1>delta</h1>
4
+
5
+ ![Minified](https://img.shields.io/badge/Minified-16.09_KB-blue?style=flat-square&labelColor=%2315161D&color=%2369a1ff) ![Minzipped](https://img.shields.io/badge/Minzipped-5.15_KB-blue?style=flat-square&labelColor=%2315161D&color=%2369a1ff)
6
+
7
+ **Functional operational-transform.**
8
+
9
+ [Documentation](https://MichaelOstermann.github.io/delta)
10
+
11
+ </div>
12
+
13
+ > [!WARNING]
14
+ > Due to the many footguns and pitalls present in collaborative applications based on operational transform, this library should only be used for ad-hoc string manipulation. Please consider using [conflict-free replicated data types](https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type) for serious applications.
15
+
16
+ ## Differences from quill-delta
17
+
18
+ This library has been largely ported from [quill-delta](https://github.com/slab/delta), some differences:
19
+
20
+ - Immutable with optional transient mutations
21
+ - Functional data-first/data-last API acting upon plain arrays
22
+ - Higher fidelity type definitions
23
+ - Operations have been migrated to a monomorphic, tagged union
24
+ - The `delete` operation has been renamed to `remove`, as `delete` is a reserved keyword
25
+ - Support for embeds has been removed
26
+ - Support for nested attributes has been removed
27
+ - Cloning is only done when the data actually changes
28
+ - Deep-cloning has been replaced with shallow-cloning
29
+ - Around 50% smaller
30
+
31
+ ## Example
32
+
33
+ ## Installation
34
+
35
+ ```sh [npm]
36
+ npm install @monstermann/delta
37
+ ```
38
+
39
+ ```sh [pnpm]
40
+ pnpm add @monstermann/delta
41
+ ```
42
+
43
+ ```sh [yarn]
44
+ yarn add @monstermann/delta
45
+ ```
46
+
47
+ ```sh [bun]
48
+ bun add @monstermann/delta
49
+ ```
50
+
51
+ ## Delta
52
+
53
+ ### batch
54
+
55
+ ```ts
56
+ function Delta.batch<T>(
57
+ ops: Delta<T>,
58
+ transform: (delta: Delta<T>) => Delta<T>,
59
+ ): Delta<T>
60
+ ```
61
+
62
+ Batches multiple delta operations together for improved performance.
63
+
64
+ #### Example
65
+
66
+ ```ts [data-first]
67
+ import { Delta } from "@monstermann/delta";
68
+
69
+ Delta.batch([], (delta) => {
70
+ // First change copies:
71
+ delta = Delta.insert(delta, "Hello", { bold: true });
72
+ // Other changes mutate:
73
+ delta = Delta.insert(delta, " world");
74
+ return delta;
75
+ });
76
+ // [{ type: "insert", value: "Hello", attributes: { bold: true } },
77
+ // { type: "insert", value: " world" }]
78
+ ```
79
+
80
+ ```ts [data-last]
81
+ import { Delta } from "@monstermann/delta";
82
+
83
+ pipe(
84
+ [],
85
+ Delta.batch((delta) => {
86
+ // First change copies:
87
+ delta = Delta.insert(delta, "Hello", { bold: true });
88
+ // Other changes mutate:
89
+ delta = Delta.insert(delta, " world");
90
+ return delta;
91
+ }),
92
+ );
93
+ // [{ type: "insert", value: "Hello", attributes: { bold: true } },
94
+ // { type: "insert", value: " world" }]
95
+ ```
96
+
97
+ ### chop
98
+
99
+ ```ts
100
+ function Delta.chop<T>(ops: Delta<T>): Delta<T>
101
+ ```
102
+
103
+ Removes a trailing retain operation if it has no attributes.
104
+
105
+ #### Example
106
+
107
+ <!-- prettier-ignore -->
108
+ ```ts [data-first]
109
+ import { Delta } from "@monstermann/delta";
110
+
111
+ Delta.chop(pipe(
112
+ [],
113
+ Delta.insert("Hello"),
114
+ Delta.retain(5)
115
+ ));
116
+ // [{ type: "insert", value: "Hello" }]
117
+
118
+ Delta.chop(pipe(
119
+ [],
120
+ Delta.insert("Hello"),
121
+ Delta.retain(5, { bold: true })
122
+ ));
123
+ // [{ type: "insert", value: "Hello" },
124
+ // { type: "retain", value: 5, attributes: { bold: true } }]
125
+ ```
126
+
127
+ <!-- prettier-ignore -->
128
+ ```ts [data-last]
129
+ import { Delta } from "@monstermann/delta";
130
+
131
+ pipe(
132
+ [],
133
+ Delta.insert("Hello"),
134
+ Delta.retain(5),
135
+ Delta.chop()
136
+ );
137
+ // [{ type: "insert", value: "Hello" }]
138
+ ```
139
+
140
+ ### clean
141
+
142
+ ```ts
143
+ function Delta.clean<T>(ops: Delta<T>): Delta<T>
144
+ ```
145
+
146
+ Normalizes the delta by merging consecutive operations of the same type and attributes.
147
+
148
+ #### Example
149
+
150
+ <!-- prettier-ignore -->
151
+ ```ts [data-first]
152
+ import { Delta } from "@monstermann/delta";
153
+
154
+ Delta.clean(pipe(
155
+ [],
156
+ Delta.insert("Hello"),
157
+ Delta.insert(" world")
158
+ ));
159
+ // [{ type: "insert", value: "Hello world" }]
160
+
161
+ Delta.clean(
162
+ pipe(
163
+ [],
164
+ Delta.insert("Hello", { bold: true }),
165
+ Delta.insert(" world", { bold: true }),
166
+ ),
167
+ );
168
+ // [{ type: "insert", value: "Hello world", attributes: { bold: true } }]
169
+ ```
170
+
171
+ <!-- prettier-ignore -->
172
+ ```ts [data-last]
173
+ import { Delta } from "@monstermann/delta";
174
+
175
+ pipe(
176
+ [],
177
+ Delta.insert("Hello"),
178
+ Delta.insert(" world"),
179
+ Delta.clean()
180
+ );
181
+ // [{ type: "insert", value: "Hello world" }]
182
+ ```
183
+
184
+ ### compose
185
+
186
+ ```ts
187
+ function Delta.compose<T>(a: Delta<T>, b: Delta<T>): Delta<T>
188
+ ```
189
+
190
+ Composes two deltas into a single delta that represents applying `a` then `b`.
191
+
192
+ #### Example
193
+
194
+ <!-- prettier-ignore -->
195
+ ```ts [data-first]
196
+ import { Delta } from "@monstermann/delta";
197
+
198
+ const a = Delta.insert([], "Hello");
199
+ const b = pipe(
200
+ [],
201
+ Delta.retain(5),
202
+ Delta.insert(" world")
203
+ );
204
+
205
+ Delta.compose(a, b);
206
+ // [{ type: "insert", value: "Hello world" }]
207
+
208
+ const format = Delta.retain([], 5, { bold: true });
209
+
210
+ Delta.compose(a, format);
211
+ // [{ type: "insert", value: "Hello", attributes: { bold: true } }]
212
+ ```
213
+
214
+ <!-- prettier-ignore -->
215
+ ```ts [data-last]
216
+ import { Delta } from "@monstermann/delta";
217
+
218
+ const a = Delta.insert([], "Hello");
219
+ const b = pipe(
220
+ [],
221
+ Delta.retain(5),
222
+ Delta.insert(" world")
223
+ );
224
+
225
+ pipe(a, Delta.compose(b));
226
+ // [{ type: "insert", value: "Hello world" }]
227
+ ```
228
+
229
+ ### concat
230
+
231
+ ```ts
232
+ function Delta.concat<T>(a: Delta<T>, b: Delta<T>): Delta<T>
233
+ ```
234
+
235
+ Concatenates two deltas together, merging adjacent operations if possible.
236
+
237
+ #### Example
238
+
239
+ ```ts [data-first]
240
+ import { Delta } from "@monstermann/delta";
241
+
242
+ const a = Delta.insert([], "Hello");
243
+ const b = Delta.insert([], " world");
244
+
245
+ Delta.concat(a, b);
246
+ // [{ type: "insert", value: "Hello world" }]
247
+
248
+ const bold = Delta.insert([], "Hello", { bold: true });
249
+ const italic = Delta.insert([], " world", { italic: true });
250
+
251
+ Delta.concat(bold, italic);
252
+ // [{ type: "insert", value: "Hello", attributes: { bold: true } },
253
+ // { type: "insert", value: " world", attributes: { italic: true } }]
254
+ ```
255
+
256
+ ```ts [data-last]
257
+ import { Delta } from "@monstermann/delta";
258
+
259
+ const a = Delta.insert([], "Hello");
260
+ const b = Delta.insert([], " world");
261
+
262
+ pipe(a, Delta.concat(b));
263
+ // [{ type: "insert", value: "Hello world" }]
264
+ ```
265
+
266
+ ### diff
267
+
268
+ ```ts
269
+ function Delta.diff<T>(a: Delta<T>, b: Delta<T>, cursor?: number): Delta<T>
270
+ ```
271
+
272
+ Computes the difference between two document deltas, returning a delta that transforms `a` into `b`.
273
+
274
+ 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.
275
+
276
+ #### Example
277
+
278
+ ```ts [data-first]
279
+ import { Delta } from "@monstermann/delta";
280
+
281
+ const a = Delta.insert([], "Hello");
282
+ const b = Delta.insert([], "Hello world");
283
+
284
+ Delta.diff(a, b);
285
+ // [{ type: "retain", value: 5 },
286
+ // { type: "insert", value: " world" }]
287
+
288
+ const plain = Delta.insert([], "Hello");
289
+ const bold = Delta.insert([], "Hello", { bold: true });
290
+
291
+ Delta.diff(plain, bold);
292
+ // [{ type: "retain", value: 5, attributes: { bold: true } }]
293
+ ```
294
+
295
+ ```ts [data-last]
296
+ import { Delta } from "@monstermann/delta";
297
+
298
+ const a = Delta.insert([], "Hello");
299
+ const b = Delta.insert([], "Hello world");
300
+
301
+ pipe(a, Delta.diff(b));
302
+ // [{ type: "retain", value: 5 },
303
+ // { type: "insert", value: " world" }]
304
+ ```
305
+
306
+ #### Cursor hint
307
+
308
+ When text changes are ambiguous, the cursor position determines where the change is placed:
309
+
310
+ ```ts
311
+ import { Delta } from "@monstermann/delta";
312
+
313
+ const a = Delta.insert([], "foo");
314
+ const b = Delta.insert([], "foo bar foo");
315
+
316
+ // cursor=3: user typed " bar foo" at the end
317
+ Delta.diff(a, b, 3);
318
+ // [{ type: "retain", value: 3 },
319
+ // { type: "insert", value: " bar foo" }]
320
+
321
+ // cursor=0: user typed "foo bar " at the beginning
322
+ Delta.diff(a, b, 0);
323
+ // [{ type: "insert", value: "foo bar " }]
324
+ ```
325
+
326
+ ### equals
327
+
328
+ ```ts
329
+ function Delta.equals<T>(a: Delta<T>, b: Delta<T>): boolean
330
+ ```
331
+
332
+ Checks if two deltas are equal by comparing their operations and attributes.
333
+
334
+ #### Example
335
+
336
+ ```ts [data-first]
337
+ import { Delta } from "@monstermann/delta";
338
+
339
+ const a = Delta.insert([], "Hello", { bold: true });
340
+ const b = Delta.insert([], "Hello", { bold: true });
341
+ const c = Delta.insert([], "Hello", { italic: true });
342
+
343
+ Delta.equals(a, b); // true
344
+ Delta.equals(a, c); // false
345
+ ```
346
+
347
+ ```ts [data-last]
348
+ import { Delta } from "@monstermann/delta";
349
+
350
+ const a = Delta.insert([], "Hello", { bold: true });
351
+ const b = Delta.insert([], "Hello", { bold: true });
352
+
353
+ pipe(a, Delta.equals(b)); // true
354
+ ```
355
+
356
+ ### insert
357
+
358
+ ```ts
359
+ function Delta.insert<T>(
360
+ ops: Delta<T>,
361
+ content: string,
362
+ attributes?: T | null,
363
+ ): Delta<T>
364
+ ```
365
+
366
+ Adds an insert operation to the delta.
367
+
368
+ #### Example
369
+
370
+ ```ts [data-first]
371
+ import { Delta } from "@monstermann/delta";
372
+
373
+ Delta.insert([], "Hello");
374
+ // [{ type: "insert", value: "Hello" }]
375
+
376
+ Delta.insert([], "Hello", { bold: true });
377
+ // [{ type: "insert", value: "Hello", attributes: { bold: true } }]
378
+ ```
379
+
380
+ ```ts [data-last]
381
+ import { Delta } from "@monstermann/delta";
382
+
383
+ pipe([], Delta.insert("Hello"));
384
+ // [{ type: "insert", value: "Hello" }]
385
+
386
+ pipe(
387
+ [],
388
+ Delta.insert("Hello", { bold: true }),
389
+ Delta.insert(" world", { italic: true }),
390
+ );
391
+ // [{ type: "insert", value: "Hello", attributes: { bold: true } },
392
+ // { type: "insert", value: " world", attributes: { italic: true } }]
393
+ ```
394
+
395
+ ### invert
396
+
397
+ ```ts
398
+ function Delta.invert<T>(a: Delta<T>, b: Delta<T>): Delta<T>
399
+ ```
400
+
401
+ Returns the inverse of a delta against a base document. Applying the inverted delta undoes the original change.
402
+
403
+ #### Example
404
+
405
+ <!-- prettier-ignore -->
406
+ ```ts [data-first]
407
+ import { Delta } from "@monstermann/delta";
408
+
409
+ const base = Delta.insert([], "Hello");
410
+ const change = Delta.retain([], 5, { bold: true });
411
+
412
+ Delta.invert(change, base);
413
+ // [{ type: "retain", value: 5, attributes: { bold: null } }]
414
+
415
+ const insert = pipe(
416
+ [],
417
+ Delta.retain(5),
418
+ Delta.insert(" world")
419
+ );
420
+
421
+ Delta.invert(insert, base);
422
+ // [{ type: "retain", value: 5 },
423
+ // { type: "remove", value: 6 }]
424
+ ```
425
+
426
+ ```ts [data-last]
427
+ import { Delta } from "@monstermann/delta";
428
+
429
+ const base = Delta.insert([], "Hello");
430
+ const change = Delta.retain([], 5, { bold: true });
431
+
432
+ pipe(change, Delta.invert(base));
433
+ // [{ type: "retain", value: 5, attributes: { bold: null } }]
434
+ ```
435
+
436
+ ### length
437
+
438
+ ```ts
439
+ function Delta.length<T>(ops: Delta<T>): number
440
+ ```
441
+
442
+ Returns the total length of the delta (sum of all operation lengths).
443
+
444
+ #### Example
445
+
446
+ <!-- prettier-ignore -->
447
+ ```ts [data-first]
448
+ import { Delta } from "@monstermann/delta";
449
+
450
+ Delta.length(Delta.insert([], "Hello")); // 5
451
+
452
+ Delta.length(pipe(
453
+ [],
454
+ Delta.insert("Hello"),
455
+ Delta.retain(3),
456
+ Delta.remove(2)
457
+ )); // 10
458
+ ```
459
+
460
+ ```ts [data-last]
461
+ import { Delta } from "@monstermann/delta";
462
+
463
+ pipe([], Delta.insert("Hello"), Delta.length()); // 5
464
+
465
+ pipe(
466
+ [],
467
+ Delta.insert("Hello"),
468
+ Delta.retain(3),
469
+ Delta.remove(2),
470
+ Delta.length(),
471
+ ); // 10
472
+ ```
473
+
474
+ ### push
475
+
476
+ ```ts
477
+ function Delta.push<T>(ops: Delta<T>, op: Op<T>): Delta<T>
478
+ ```
479
+
480
+ Pushes an operation onto the delta, merging with the previous operation if possible.
481
+
482
+ #### Example
483
+
484
+ ```ts [data-first]
485
+ import { Delta } from "@monstermann/delta";
486
+
487
+ Delta.push([], { type: "insert", value: "Hello" });
488
+ // [{ type: "insert", value: "Hello" }]
489
+
490
+ Delta.push(Delta.push([], { type: "insert", value: "Hello" }), {
491
+ type: "insert",
492
+ value: " world",
493
+ });
494
+ // [{ type: "insert", value: "Hello world" }]
495
+ ```
496
+
497
+ ```ts [data-last]
498
+ import { Delta } from "@monstermann/delta";
499
+
500
+ pipe([], Delta.push({ type: "insert", value: "Hello" }));
501
+ // [{ type: "insert", value: "Hello" }]
502
+
503
+ pipe(
504
+ [],
505
+ Delta.push({ type: "insert", value: "Hello" }),
506
+ Delta.push({ type: "insert", value: " world" }),
507
+ );
508
+ // [{ type: "insert", value: "Hello world" }]
509
+ ```
510
+
511
+ ### remove
512
+
513
+ ```ts
514
+ function Delta.remove<T>(ops: Delta<T>, length: number): Delta<T>
515
+ ```
516
+
517
+ Adds a remove operation to the delta.
518
+
519
+ #### Example
520
+
521
+ ```ts [data-first]
522
+ import { Delta } from "@monstermann/delta";
523
+
524
+ Delta.remove([], 5);
525
+ // [{ type: "remove", value: 5 }]
526
+ ```
527
+
528
+ ```ts [data-last]
529
+ import { Delta } from "@monstermann/delta";
530
+
531
+ pipe([], Delta.remove(5));
532
+ // [{ type: "remove", value: 5 }]
533
+
534
+ pipe([], Delta.retain(3), Delta.remove(5));
535
+ // [{ type: "retain", value: 3 },
536
+ // { type: "remove", value: 5 }]
537
+ ```
538
+
539
+ ### retain
540
+
541
+ ```ts
542
+ function Delta.retain<T>(
543
+ ops: Delta<T>,
544
+ length: number,
545
+ attributes?: T | null,
546
+ ): Delta<T>
547
+ ```
548
+
549
+ Adds a retain operation to the delta, optionally with attributes to apply formatting.
550
+
551
+ #### Example
552
+
553
+ ```ts [data-first]
554
+ import { Delta } from "@monstermann/delta";
555
+
556
+ Delta.retain([], 5);
557
+ // [{ type: "retain", value: 5 }]
558
+
559
+ Delta.retain([], 5, { bold: true });
560
+ // [{ type: "retain", value: 5, attributes: { bold: true } }]
561
+ ```
562
+
563
+ <!-- prettier-ignore -->
564
+ ```ts [data-last]
565
+ import { Delta } from "@monstermann/delta";
566
+
567
+ pipe([], Delta.retain(5));
568
+ // [{ type: "retain", value: 5 }]
569
+
570
+ pipe(
571
+ [],
572
+ Delta.retain(3),
573
+ Delta.retain(2, { italic: true })
574
+ );
575
+ // [{ type: "retain", value: 3 },
576
+ // { type: "retain", value: 2, attributes: { italic: true } }]
577
+ ```
578
+
579
+ #### Removing attributes
580
+
581
+ Use `null` to remove an attribute when composing deltas:
582
+
583
+ ```ts
584
+ import { Delta } from "@monstermann/delta";
585
+
586
+ const doc = Delta.insert([], "Hello", { bold: true });
587
+ // [{ type: "insert", value: "Hello", attributes: { bold: true } }]
588
+
589
+ const removeBold = Delta.retain([], 5, { bold: null });
590
+ // [{ type: "retain", value: 5, attributes: { bold: null } }]
591
+
592
+ Delta.compose(doc, removeBold);
593
+ // [{ type: "insert", value: "Hello" }]
594
+ ```
595
+
596
+ ### slice
597
+
598
+ ```ts
599
+ function Delta.slice<T>(ops: Delta<T>, start: number, end?: number): Delta<T>
600
+ ```
601
+
602
+ Returns a portion of the delta from `start` to `end`.
603
+
604
+ #### Example
605
+
606
+ ```ts [data-first]
607
+ import { Delta } from "@monstermann/delta";
608
+
609
+ const delta = Delta.insert([], "Hello world");
610
+
611
+ Delta.slice(delta, 0, 5);
612
+ // [{ type: "insert", value: "Hello" }]
613
+
614
+ Delta.slice(delta, 6);
615
+ // [{ type: "insert", value: "world" }]
616
+
617
+ const formatted = pipe(
618
+ [],
619
+ Delta.insert("Hello", { bold: true }),
620
+ Delta.insert(" world", { italic: true }),
621
+ );
622
+
623
+ Delta.slice(formatted, 3, 8);
624
+ // [{ type: "insert", value: "lo", attributes: { bold: true } },
625
+ // { type: "insert", value: " wo", attributes: { italic: true } }]
626
+ ```
627
+
628
+ <!-- prettier-ignore -->
629
+ ```ts [data-last]
630
+ import { Delta } from "@monstermann/delta";
631
+
632
+ pipe(
633
+ [],
634
+ Delta.insert("Hello world"),
635
+ Delta.slice(0, 5)
636
+ );
637
+ // [{ type: "insert", value: "Hello" }]
638
+
639
+ pipe(
640
+ [],
641
+ Delta.insert("Hello world"),
642
+ Delta.slice(6)
643
+ );
644
+ // [{ type: "insert", value: "world" }]
645
+ ```
646
+
647
+ ### transform
648
+
649
+ ```ts
650
+ function Delta.transform<T>(
651
+ a: Delta<T>,
652
+ b: Delta<T>,
653
+ priority?: boolean,
654
+ ): Delta<T>
655
+ ```
656
+
657
+ Transforms delta `b` to account for delta `a` having been applied first. When both deltas insert at the same position, `priority` determines which insert comes first.
658
+
659
+ #### Example
660
+
661
+ <!-- prettier-ignore -->
662
+ ```ts [data-first]
663
+ import { Delta } from "@monstermann/delta";
664
+
665
+ const a = Delta.insert([], "Hello");
666
+ const b = Delta.insert([], "World");
667
+
668
+ Delta.transform(a, b, true);
669
+ // [{ type: "retain", value: 5 },
670
+ // { type: "insert", value: "World" }]
671
+
672
+ Delta.transform(a, b, false);
673
+ // [{ type: "insert", value: "World" }]
674
+
675
+ const format = Delta.retain([], 5, { bold: true });
676
+ const insert = pipe(
677
+ [],
678
+ Delta.retain(2),
679
+ Delta.insert("XXX")
680
+ );
681
+
682
+ Delta.transform(insert, format);
683
+ // [{ type: "retain", value: 8, attributes: { bold: true } }]
684
+ ```
685
+
686
+ ```ts [data-last]
687
+ import { Delta } from "@monstermann/delta";
688
+
689
+ const a = Delta.insert([], "Hello");
690
+ const b = Delta.insert([], "World");
691
+
692
+ pipe(a, Delta.transform(b, true));
693
+ // [{ type: "retain", value: 5 },
694
+ // { type: "insert", value: "World" }]
695
+ ```