lib0 0.2.115-1 → 0.2.115-3

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 (100) hide show
  1. package/coverage/tmp/{coverage-27668-1761218485882-0.json → coverage-32703-1763495370274-0.json} +1 -1
  2. package/delta/abstract.d.ts +2 -2
  3. package/delta/abstract.d.ts.map +1 -1
  4. package/delta/d2.d.ts +318 -112
  5. package/delta/d2.d.ts.map +1 -1
  6. package/delta/d2.js +837 -155
  7. package/delta/d2.test.d.ts +6 -1
  8. package/delta/d2.test.d.ts.map +1 -1
  9. package/delta/map.d.ts +19 -23
  10. package/delta/map.d.ts.map +1 -1
  11. package/delta/map.js +1 -1
  12. package/delta/node.d.ts +8 -10
  13. package/delta/node.d.ts.map +1 -1
  14. package/delta/ops.d.ts +26 -28
  15. package/delta/ops.d.ts.map +1 -1
  16. package/delta/t2.d.ts +184 -0
  17. package/delta/t2.d.ts.map +1 -0
  18. package/delta/t2.js +890 -0
  19. package/delta/t3.test.d.ts +19 -0
  20. package/delta/t3.test.d.ts.map +1 -0
  21. package/dist/aes-gcm.cjs +2 -2
  22. package/dist/binding.cjs +1 -1
  23. package/dist/{broadcastchannel-b4eaea6e.cjs → broadcastchannel-d0c108a2.cjs} +2 -2
  24. package/dist/{broadcastchannel-b4eaea6e.cjs.map → broadcastchannel-d0c108a2.cjs.map} +1 -1
  25. package/dist/broadcastchannel.cjs +4 -4
  26. package/dist/{buffer-adc4e6ea.cjs → buffer-7f6fa8fa.cjs} +3 -3
  27. package/dist/{buffer-adc4e6ea.cjs.map → buffer-7f6fa8fa.cjs.map} +1 -1
  28. package/dist/buffer.cjs +3 -3
  29. package/dist/component.cjs +1 -1
  30. package/dist/d2.cjs +845 -159
  31. package/dist/d2.cjs.map +1 -1
  32. package/dist/{decoding-50b9ce38.cjs → decoding-76e75827.cjs} +2 -2
  33. package/dist/{decoding-50b9ce38.cjs.map → decoding-76e75827.cjs.map} +1 -1
  34. package/dist/decoding.cjs +2 -2
  35. package/dist/delta/abstract.d.ts +2 -2
  36. package/dist/delta/abstract.d.ts.map +1 -1
  37. package/dist/delta/d2.d.ts +318 -112
  38. package/dist/delta/d2.d.ts.map +1 -1
  39. package/dist/delta/d2.test.d.ts +6 -1
  40. package/dist/delta/d2.test.d.ts.map +1 -1
  41. package/dist/delta/map.d.ts +19 -23
  42. package/dist/delta/map.d.ts.map +1 -1
  43. package/dist/delta/node.d.ts +8 -10
  44. package/dist/delta/node.d.ts.map +1 -1
  45. package/dist/delta/ops.d.ts +26 -28
  46. package/dist/delta/ops.d.ts.map +1 -1
  47. package/dist/delta/t2.d.ts +184 -0
  48. package/dist/delta/t2.d.ts.map +1 -0
  49. package/dist/delta/t3.test.d.ts +19 -0
  50. package/dist/delta/t3.test.d.ts.map +1 -0
  51. package/dist/{dom-2b123630.cjs → dom-f5047a64.cjs} +1 -1
  52. package/dist/{dom-2b123630.cjs.map → dom-f5047a64.cjs.map} +1 -1
  53. package/dist/dom.cjs +1 -1
  54. package/dist/{encoding-7f85922c.cjs → encoding-1a745c43.cjs} +10 -2
  55. package/dist/encoding-1a745c43.cjs.map +1 -0
  56. package/dist/encoding.cjs +1 -1
  57. package/dist/encoding.d.ts +5 -3
  58. package/dist/encoding.d.ts.map +1 -1
  59. package/dist/encoding.test.d.ts.map +1 -1
  60. package/dist/index.cjs +6 -6
  61. package/dist/jwt.cjs +3 -3
  62. package/dist/list.test.d.ts +1 -0
  63. package/dist/list.test.d.ts.map +1 -1
  64. package/dist/logging.cjs +1 -1
  65. package/dist/map.cjs +1 -1
  66. package/dist/map.cjs.map +1 -1
  67. package/dist/mutex.test.d.ts +3 -0
  68. package/dist/mutex.test.d.ts.map +1 -0
  69. package/dist/{prng-004c76e8.cjs → prng-99204216.cjs} +2 -2
  70. package/dist/{prng-004c76e8.cjs.map → prng-99204216.cjs.map} +1 -1
  71. package/dist/prng.cjs +4 -4
  72. package/dist/rabin-gf2-polynomial.cjs +3 -3
  73. package/dist/rabin-uncached.cjs +3 -3
  74. package/dist/rabin.cjs +3 -3
  75. package/dist/schema.cjs +72 -11
  76. package/dist/schema.cjs.map +1 -1
  77. package/dist/schema.d.ts +21 -13
  78. package/dist/schema.d.ts.map +1 -1
  79. package/dist/schema.test.d.ts +2 -0
  80. package/dist/schema.test.d.ts.map +1 -1
  81. package/dist/t2.cjs +932 -0
  82. package/dist/t2.cjs.map +1 -0
  83. package/dist/testing.cjs +4 -4
  84. package/encoding.d.ts +5 -3
  85. package/encoding.d.ts.map +1 -1
  86. package/encoding.js +9 -1
  87. package/encoding.test.d.ts.map +1 -1
  88. package/list.test.d.ts +1 -0
  89. package/list.test.d.ts.map +1 -1
  90. package/mutex.test.d.ts +3 -0
  91. package/mutex.test.d.ts.map +1 -0
  92. package/package.json +1 -1
  93. package/schema.d.ts +21 -13
  94. package/schema.d.ts.map +1 -1
  95. package/schema.js +68 -11
  96. package/schema.test.d.ts +2 -0
  97. package/schema.test.d.ts.map +1 -1
  98. package/test.js +3 -1
  99. package/coverage/tmp/coverage-27667-1761218530660-0.json +0 -1
  100. package/dist/encoding-7f85922c.cjs.map +0 -1
package/delta/d2.js CHANGED
@@ -1,5 +1,11 @@
1
1
  /**
2
2
  * @beta this API is about to change
3
+ *
4
+ * ## Mutability
5
+ *
6
+ * Deltas are mutable by default. But references are often shared, by marking a Delta as "done". You
7
+ * may only modify deltas by applying other deltas to them. Casting a Delta to a DeltaBuilder
8
+ * manually, will likely modify "shared" state.
3
9
  */
4
10
 
5
11
  import * as list from '../list.js'
@@ -10,6 +16,10 @@ import * as fun from '../function.js'
10
16
  import * as s from '../schema.js'
11
17
  import * as error from '../error.js'
12
18
  import * as math from '../math.js'
19
+ import * as rabin from '../hash/rabin.js'
20
+ import * as encoding from '../encoding.js'
21
+ import * as buffer from '../buffer.js'
22
+ import * as patience from '../diff/patience.js'
13
23
 
14
24
  /**
15
25
  * @typedef {{
@@ -44,8 +54,9 @@ export const $attribution = s.$object({
44
54
 
45
55
  /**
46
56
  * @typedef {{
47
- * name?: string
48
- * attrs?: { [Key in string|number|symbol]: DeltaAttrOpJSON },
57
+ * type: 'delta',
58
+ * name?: string,
59
+ * attrs?: { [Key in string|number]: DeltaAttrOpJSON },
49
60
  * children?: Array<DeltaListOpJSON>
50
61
  * }} DeltaJSON
51
62
  */
@@ -58,6 +69,18 @@ export const $attribution = s.$object({
58
69
  * @typedef {{ type: 'insert', value: any, prevValue?: any, attribution?: Attribution } | { type: 'delete', prevValue?: any, attribution?: Attribution } | { type: 'modify', value: DeltaJSON }} DeltaAttrOpJSON
59
70
  */
60
71
 
72
+ /**
73
+ * @typedef {TextOp|InsertOp<any>|DeleteOp|RetainOp|ModifyOp<any>} ChildrenOpAny
74
+ */
75
+
76
+ /**
77
+ * @typedef {AttrInsertOp<any>|AttrDeleteOp<any>|AttrModifyOp} AttrOpAny
78
+ */
79
+
80
+ /**
81
+ * @typedef {ChildrenOpAny|AttrOpAny} _OpAny
82
+ */
83
+
61
84
  /**
62
85
  * @type {s.Schema<DeltaAttrOpJSON>}
63
86
  */
@@ -78,7 +101,11 @@ const _cloneAttrs = attrs => attrs == null ? attrs : { ...attrs }
78
101
  * @param {MaybeDelta} maybeDelta
79
102
  * @return {MaybeDelta}
80
103
  */
81
- const _cloneMaybeDelta = maybeDelta => $deltaAny.check(maybeDelta) ? maybeDelta.clone() : maybeDelta
104
+ const _markMaybeDeltaAsDone = maybeDelta => $deltaAny.check(maybeDelta) ? /** @type {MaybeDelta} */ (maybeDelta.done()) : maybeDelta
105
+
106
+ /**
107
+ * @typedef {unknown & DeltaAny} Q
108
+ */
82
109
 
83
110
  export class TextOp extends list.ListNode {
84
111
  /**
@@ -88,9 +115,31 @@ export class TextOp extends list.ListNode {
88
115
  */
89
116
  constructor (insert, format, attribution) {
90
117
  super()
118
+ // Whenever this is modified, make sure to clear _fingerprint
119
+ /**
120
+ * @readonly
121
+ * @type {string}
122
+ */
91
123
  this.insert = insert
124
+ /**
125
+ * @readonly
126
+ * @type {FormattingAttributes|null}
127
+ */
92
128
  this.format = format
93
129
  this.attribution = attribution
130
+ /**
131
+ * @type {string?}
132
+ */
133
+ this._fingerprint = null
134
+ }
135
+
136
+ /**
137
+ * @param {string} newVal
138
+ */
139
+ _updateInsert (newVal) {
140
+ // @ts-ignore
141
+ this.insert = newVal
142
+ this._fingerprint = null
94
143
  }
95
144
 
96
145
  /**
@@ -104,6 +153,14 @@ export class TextOp extends list.ListNode {
104
153
  return this.insert.length
105
154
  }
106
155
 
156
+ get fingerprint () {
157
+ return this._fingerprint || (this._fingerprint = buffer.toBase64(encoding.encode(encoder => {
158
+ encoding.writeVarUint(encoder, 0) // textOp type: 0
159
+ encoding.writeVarString(encoder, this.insert)
160
+ encoding.writeAny(encoder, this.format)
161
+ })))
162
+ }
163
+
107
164
  /**
108
165
  * Remove a part of the operation (similar to Array.splice)
109
166
  *
@@ -111,7 +168,10 @@ export class TextOp extends list.ListNode {
111
168
  * @param {number} len
112
169
  */
113
170
  _splice (offset, len) {
171
+ this._fingerprint = null
172
+ // @ts-ignore
114
173
  this.insert = this.insert.slice(0, offset) + this.insert.slice(offset + len)
174
+ return this
115
175
  }
116
176
 
117
177
  /**
@@ -132,13 +192,13 @@ export class TextOp extends list.ListNode {
132
192
  /**
133
193
  * @return {TextOp}
134
194
  */
135
- clone () {
136
- return new TextOp(this.insert, _cloneAttrs(this.format), _cloneAttrs(this.attribution))
195
+ clone (start = 0, end = this.length) {
196
+ return new TextOp(this.insert.slice(start, end), _cloneAttrs(this.format), _cloneAttrs(this.attribution))
137
197
  }
138
198
  }
139
199
 
140
200
  /**
141
- * @template ArrayContent
201
+ * @template {encoding.AnyEncodable|DeltaAny} ArrayContent
142
202
  */
143
203
  export class InsertOp extends list.ListNode {
144
204
  /**
@@ -148,9 +208,34 @@ export class InsertOp extends list.ListNode {
148
208
  */
149
209
  constructor (insert, format, attribution) {
150
210
  super()
211
+ /**
212
+ * @readonly
213
+ * @type {Array<ArrayContent>}
214
+ */
151
215
  this.insert = insert
216
+ /**
217
+ * @readonly
218
+ * @type {FormattingAttributes?}
219
+ */
152
220
  this.format = format
221
+ /**
222
+ * @readonly
223
+ * @type {Attribution?}
224
+ */
153
225
  this.attribution = attribution
226
+ /**
227
+ * @type {string?}
228
+ */
229
+ this._fingerprint = null
230
+ }
231
+
232
+ /**
233
+ * @param {ArrayContent} newVal
234
+ */
235
+ _updateInsert (newVal) {
236
+ // @ts-ignore
237
+ this.insert = newVal
238
+ this._fingerprint = null
154
239
  }
155
240
 
156
241
  /**
@@ -164,6 +249,42 @@ export class InsertOp extends list.ListNode {
164
249
  return this.insert.length
165
250
  }
166
251
 
252
+ /**
253
+ * @param {number} i
254
+ * @return {Extract<ArrayContent,DeltaAny>}
255
+ */
256
+ _modValue (i) {
257
+ /**
258
+ * @type {any}
259
+ */
260
+ let d = this.insert[i]
261
+ this._fingerprint = null
262
+ $deltaAny.expect(d)
263
+ if (d.isDone) {
264
+ // @ts-ignore
265
+ this.insert[i] = (d = clone(d))
266
+ return d
267
+ }
268
+ return d
269
+ }
270
+
271
+ get fingerprint () {
272
+ return this._fingerprint || (this._fingerprint = buffer.toBase64(encoding.encode(encoder => {
273
+ encoding.writeVarUint(encoder, 1) // insertOp type: 1
274
+ encoding.writeVarUint(encoder, this.insert.length)
275
+ this.insert.forEach(ins => {
276
+ if ($deltaAny.check(ins)) {
277
+ encoding.writeUint8(encoder, 0)
278
+ encoding.writeVarString(encoder, ins.fingerprint)
279
+ } else {
280
+ encoding.writeUint8(encoder, 1)
281
+ encoding.writeAny(encoder, ins)
282
+ }
283
+ })
284
+ encoding.writeAny(encoder, this.format)
285
+ })))
286
+ }
287
+
167
288
  /**
168
289
  * Remove a part of the operation (similar to Array.splice)
169
290
  *
@@ -171,7 +292,9 @@ export class InsertOp extends list.ListNode {
171
292
  * @param {number} len
172
293
  */
173
294
  _splice (offset, len) {
295
+ this._fingerprint = null
174
296
  this.insert.splice(offset, len)
297
+ return this
175
298
  }
176
299
 
177
300
  /**
@@ -192,11 +315,15 @@ export class InsertOp extends list.ListNode {
192
315
  /**
193
316
  * @return {InsertOp<ArrayContent>}
194
317
  */
195
- clone () {
196
- return new InsertOp(this.insert.slice(), _cloneAttrs(this.format), _cloneAttrs(this.attribution))
318
+ clone (start = 0, end = this.length) {
319
+ return new InsertOp(this.insert.slice(start, end).map(_markMaybeDeltaAsDone), _cloneAttrs(this.format), _cloneAttrs(this.attribution))
197
320
  }
198
321
  }
199
322
 
323
+ /**
324
+ * @template {encoding.AnyEncodable|DeltaAny} [Children=never]
325
+ * @template {string} [Text=never]
326
+ */
200
327
  export class DeleteOp extends list.ListNode {
201
328
  /**
202
329
  * @param {number} len
@@ -204,6 +331,14 @@ export class DeleteOp extends list.ListNode {
204
331
  constructor (len) {
205
332
  super()
206
333
  this.delete = len
334
+ /**
335
+ * @type {(Children|Text) extends never ? null : (Delta<any,{},Children,Text>?)}
336
+ */
337
+ this.prevValue = null
338
+ /**
339
+ * @type {string|null}
340
+ */
341
+ this._fingerprint = null
207
342
  }
208
343
 
209
344
  /**
@@ -217,6 +352,13 @@ export class DeleteOp extends list.ListNode {
217
352
  return 0
218
353
  }
219
354
 
355
+ get fingerprint () {
356
+ return this._fingerprint || (this._fingerprint = buffer.toBase64(encoding.encode(encoder => {
357
+ encoding.writeVarUint(encoder, 2) // deleteOp type: 2
358
+ encoding.writeVarUint(encoder, this.delete)
359
+ })))
360
+ }
361
+
220
362
  /**
221
363
  * Remove a part of the operation (similar to Array.splice)
222
364
  *
@@ -224,7 +366,10 @@ export class DeleteOp extends list.ListNode {
224
366
  * @param {number} len
225
367
  */
226
368
  _splice (_offset, len) {
369
+ this.prevValue = /** @type {any} */ (this.prevValue?.slice(_offset, len) || null)
370
+ this._fingerprint = null
227
371
  this.delete -= len
372
+ return this
228
373
  }
229
374
 
230
375
  /**
@@ -241,8 +386,8 @@ export class DeleteOp extends list.ListNode {
241
386
  return this.delete === other.delete
242
387
  }
243
388
 
244
- clone () {
245
- return new DeleteOp(this.delete)
389
+ clone (start = 0, end = this.delete) {
390
+ return new DeleteOp(end - start)
246
391
  }
247
392
  }
248
393
 
@@ -254,9 +399,25 @@ export class RetainOp extends list.ListNode {
254
399
  */
255
400
  constructor (retain, format, attribution) {
256
401
  super()
402
+ /**
403
+ * @readonly
404
+ * @type {number}
405
+ */
257
406
  this.retain = retain
407
+ /**
408
+ * @readonly
409
+ * @type {FormattingAttributes?}
410
+ */
258
411
  this.format = format
412
+ /**
413
+ * @readonly
414
+ * @type {Attribution?}
415
+ */
259
416
  this.attribution = attribution
417
+ /**
418
+ * @type {string|null}
419
+ */
420
+ this._fingerprint = null
260
421
  }
261
422
 
262
423
  /**
@@ -270,6 +431,14 @@ export class RetainOp extends list.ListNode {
270
431
  return this.retain
271
432
  }
272
433
 
434
+ get fingerprint () {
435
+ return this._fingerprint || (this._fingerprint = buffer.toBase64(encoding.encode(encoder => {
436
+ encoding.writeVarUint(encoder, 3) // retainOp type: 3
437
+ encoding.writeVarUint(encoder, this.retain)
438
+ encoding.writeAny(encoder, this.format)
439
+ })))
440
+ }
441
+
273
442
  /**
274
443
  * Remove a part of the operation (similar to Array.splice)
275
444
  *
@@ -277,7 +446,10 @@ export class RetainOp extends list.ListNode {
277
446
  * @param {number} len
278
447
  */
279
448
  _splice (_offset, len) {
449
+ // @ts-ignore
280
450
  this.retain -= len
451
+ this._fingerprint = null
452
+ return this
281
453
  }
282
454
 
283
455
  /**
@@ -295,15 +467,15 @@ export class RetainOp extends list.ListNode {
295
467
  return this.retain === other.retain && fun.equalityDeep(this.format, other.format) && fun.equalityDeep(this.attribution, other.attribution)
296
468
  }
297
469
 
298
- clone () {
299
- return new RetainOp(this.retain, _cloneAttrs(this.format), _cloneAttrs(this.attribution))
470
+ clone (start = 0, end = this.retain) {
471
+ return new RetainOp(end - start, _cloneAttrs(this.format), _cloneAttrs(this.attribution))
300
472
  }
301
473
  }
302
474
 
303
475
  /**
304
476
  * Delta that can be applied on a YType Embed
305
477
  *
306
- * @template {Delta<any,any,any,any,any>} DTypes
478
+ * @template {DeltaAny} [DTypes=DeltaAny]
307
479
  */
308
480
  export class ModifyOp extends list.ListNode {
309
481
  /**
@@ -313,9 +485,25 @@ export class ModifyOp extends list.ListNode {
313
485
  */
314
486
  constructor (delta, format, attribution) {
315
487
  super()
488
+ /**
489
+ * @readonly
490
+ * @type {DTypes}
491
+ */
316
492
  this.value = delta
493
+ /**
494
+ * @readonly
495
+ * @type {FormattingAttributes?}
496
+ */
317
497
  this.format = format
498
+ /**
499
+ * @readonly
500
+ * @type {Attribution?}
501
+ */
318
502
  this.attribution = attribution
503
+ /**
504
+ * @type {string|null}
505
+ */
506
+ this._fingerprint = null
319
507
  }
320
508
 
321
509
  /**
@@ -329,6 +517,31 @@ export class ModifyOp extends list.ListNode {
329
517
  return 1
330
518
  }
331
519
 
520
+ /**
521
+ * @type {DeltaBuilderAny}
522
+ */
523
+ get _modValue () {
524
+ /**
525
+ * @type {any}
526
+ */
527
+ const d = this.value
528
+ this._fingerprint = null
529
+ if (d.isDone) {
530
+ // @ts-ignore
531
+ return (this.value = clone(d))
532
+ }
533
+ return d
534
+ }
535
+
536
+ get fingerprint () {
537
+ // don't cache fingerprint because we don't know when delta changes
538
+ return this._fingerprint || (this._fingerprint = buffer.toBase64(encoding.encode(encoder => {
539
+ encoding.writeVarUint(encoder, 4) // modifyOp type: 4
540
+ encoding.writeVarString(encoder, this.value.fingerprint)
541
+ encoding.writeAny(encoder, this.format)
542
+ })))
543
+ }
544
+
332
545
  /**
333
546
  * Remove a part of the operation (similar to Array.splice)
334
547
  *
@@ -336,6 +549,7 @@ export class ModifyOp extends list.ListNode {
336
549
  * @param {number} _len
337
550
  */
338
551
  _splice (_offset, _len) {
552
+ return this
339
553
  }
340
554
 
341
555
  /**
@@ -357,15 +571,15 @@ export class ModifyOp extends list.ListNode {
357
571
  * @return {ModifyOp<DTypes>}
358
572
  */
359
573
  clone () {
360
- return new ModifyOp(this.value.clone(), _cloneAttrs(this.format), _cloneAttrs(this.attribution))
574
+ return new ModifyOp(/** @type {DTypes} */ (this.value.done()), _cloneAttrs(this.format), _cloneAttrs(this.attribution))
361
575
  }
362
576
  }
363
577
 
364
578
  /**
365
- * @template V
366
- * @template {string|number|symbol} [K=any]
579
+ * @template {encoding.AnyEncodable|DeltaAny} V
580
+ * @template {string|number} [K=any]
367
581
  */
368
- export class MapInsertOp {
582
+ export class AttrInsertOp {
369
583
  /**
370
584
  * @param {K} key
371
585
  * @param {V} value
@@ -374,18 +588,29 @@ export class MapInsertOp {
374
588
  */
375
589
  constructor (key, value, prevValue, attribution) {
376
590
  /**
591
+ * @readonly
377
592
  * @type {K}
378
593
  */
379
594
  this.key = key
380
595
  /**
596
+ * @readonly
381
597
  * @type {V}
382
598
  */
383
599
  this.value = value
384
600
  /**
601
+ * @readonly
385
602
  * @type {V|undefined}
386
603
  */
387
604
  this.prevValue = prevValue
605
+ /**
606
+ * @readonly
607
+ * @type {Attribution?}
608
+ */
388
609
  this.attribution = attribution
610
+ /**
611
+ * @type {string|null}
612
+ */
613
+ this._fingerprint = null
389
614
  }
390
615
 
391
616
  /**
@@ -393,6 +618,36 @@ export class MapInsertOp {
393
618
  */
394
619
  get type () { return 'insert' }
395
620
 
621
+ /**
622
+ * @type {DeltaBuilderAny}
623
+ */
624
+ get _modValue () {
625
+ /**
626
+ * @type {any}
627
+ */
628
+ const v = this.value
629
+ this._fingerprint = null
630
+ if ($deltaAny.check(v) && v.isDone) {
631
+ // @ts-ignore
632
+ return (this.value = clone(v))
633
+ }
634
+ return v
635
+ }
636
+
637
+ get fingerprint () {
638
+ return this._fingerprint || (this._fingerprint = buffer.toBase64(encoding.encode(encoder => {
639
+ encoding.writeVarUint(encoder, 5) // map insert type: 5
640
+ encoding.writeAny(encoder, this.key)
641
+ if ($deltaAny.check(this.value)) {
642
+ encoding.writeUint8(encoder, 0)
643
+ encoding.writeVarString(encoder, this.value.fingerprint)
644
+ } else {
645
+ encoding.writeUint8(encoder, 1)
646
+ encoding.writeAny(encoder, this.value)
647
+ }
648
+ })))
649
+ }
650
+
396
651
  toJSON () {
397
652
  const v = this.value
398
653
  const prevValue = this.prevValue
@@ -404,25 +659,25 @@ export class MapInsertOp {
404
659
  }
405
660
 
406
661
  /**
407
- * @param {MapInsertOp<V>} other
662
+ * @param {AttrInsertOp<V>} other
408
663
  */
409
664
  [traits.EqualityTraitSymbol] (other) {
410
665
  return this.key === other.key && fun.equalityDeep(this.value, other.value) && fun.equalityDeep(this.attribution, other.attribution)
411
666
  }
412
667
 
413
668
  /**
414
- * @return {MapInsertOp<V,K>}
669
+ * @return {AttrInsertOp<V,K>}
415
670
  */
416
671
  clone () {
417
- return new MapInsertOp(this.key, _cloneMaybeDelta(this.value), _cloneMaybeDelta(this.prevValue), _cloneAttrs(this.attribution))
672
+ return new AttrInsertOp(this.key, _markMaybeDeltaAsDone(this.value), _markMaybeDeltaAsDone(this.prevValue), _cloneAttrs(this.attribution))
418
673
  }
419
674
  }
420
675
 
421
676
  /**
422
677
  * @template V
423
- * @template [K=string]
678
+ * @template {string|number} [K=string]
424
679
  */
425
- export class MapDeleteOp {
680
+ export class AttrDeleteOp {
426
681
  /**
427
682
  * @param {K} key
428
683
  * @param {V|undefined} prevValue
@@ -438,6 +693,10 @@ export class MapDeleteOp {
438
693
  */
439
694
  this.prevValue = prevValue
440
695
  this.attribution = attribution
696
+ /**
697
+ * @type {string|null}
698
+ */
699
+ this._fingerprint = null
441
700
  }
442
701
 
443
702
  get value () { return undefined }
@@ -447,6 +706,13 @@ export class MapDeleteOp {
447
706
  */
448
707
  get type () { return 'delete' }
449
708
 
709
+ get fingerprint () {
710
+ return this._fingerprint || (this._fingerprint = buffer.toBase64(encoding.encode(encoder => {
711
+ encoding.writeVarUint(encoder, 6) // map delete type: 6
712
+ encoding.writeAny(encoder, this.key)
713
+ })))
714
+ }
715
+
450
716
  /**
451
717
  * @return {DeltaAttrOpJSON}
452
718
  */
@@ -458,35 +724,41 @@ export class MapDeleteOp {
458
724
  }
459
725
 
460
726
  /**
461
- * @param {MapDeleteOp<V>} other
727
+ * @param {AttrDeleteOp<V>} other
462
728
  */
463
729
  [traits.EqualityTraitSymbol] (other) {
464
730
  return this.key === other.key && fun.equalityDeep(this.attribution, other.attribution)
465
731
  }
466
732
 
467
733
  clone () {
468
- return new MapDeleteOp(this.key, _cloneMaybeDelta(this.prevValue), _cloneAttrs(this.attribution))
734
+ return new AttrDeleteOp(this.key, _markMaybeDeltaAsDone(this.prevValue), _cloneAttrs(this.attribution))
469
735
  }
470
736
  }
471
737
 
472
738
  /**
473
- * @template {DeltaAny} Modifier
474
- * @template [K=string]
739
+ * @template {DeltaAny} [Modifier=DeltaAny]
740
+ * @template {string|number} [K=string]
475
741
  */
476
- export class MapModifyOp {
742
+ export class AttrModifyOp {
477
743
  /**
478
744
  * @param {K} key
479
745
  * @param {Modifier} delta
480
746
  */
481
747
  constructor (key, delta) {
482
748
  /**
749
+ * @readonly
483
750
  * @type {K}
484
751
  */
485
752
  this.key = key
486
753
  /**
754
+ * @readonly
487
755
  * @type {Modifier}
488
756
  */
489
757
  this.value = delta
758
+ /**
759
+ * @type {string|null}
760
+ */
761
+ this._fingerprint = null
490
762
  }
491
763
 
492
764
  /**
@@ -494,6 +766,27 @@ export class MapModifyOp {
494
766
  */
495
767
  get type () { return 'modify' }
496
768
 
769
+ get fingerprint () {
770
+ return this._fingerprint || (this._fingerprint = buffer.toBase64(encoding.encode(encoder => {
771
+ encoding.writeVarUint(encoder, 7) // map modify type: 7
772
+ encoding.writeAny(encoder, this.key)
773
+ encoding.writeVarString(encoder, this.value.fingerprint)
774
+ })))
775
+ }
776
+
777
+ /**
778
+ * @return {DeltaBuilder}
779
+ */
780
+ get _modValue () {
781
+ this._fingerprint = null
782
+ if (this.value.isDone) {
783
+ // @ts-ignore
784
+ this.value = /** @type {any} */ (clone(this.value))
785
+ }
786
+ // @ts-ignore
787
+ return this.value
788
+ }
789
+
497
790
  /**
498
791
  * @return {DeltaAttrOpJSON}
499
792
  */
@@ -505,38 +798,38 @@ export class MapModifyOp {
505
798
  }
506
799
 
507
800
  /**
508
- * @param {MapModifyOp<Modifier>} other
801
+ * @param {AttrModifyOp<Modifier>} other
509
802
  */
510
803
  [traits.EqualityTraitSymbol] (other) {
511
804
  return this.key === other.key && this.value[traits.EqualityTraitSymbol](other.value)
512
805
  }
513
806
 
514
807
  /**
515
- * @return {MapModifyOp<Modifier,K>}
808
+ * @return {AttrModifyOp<Modifier,K>}
516
809
  */
517
810
  clone () {
518
- return new MapModifyOp(this.key, this.value.clone())
811
+ return new AttrModifyOp(this.key, /** @type {Modifier} */ (this.value.done()))
519
812
  }
520
813
  }
521
814
 
522
815
  /**
523
- * @type {s.Schema<MapDeleteOp<any> | DeleteOp>}
816
+ * @type {s.Schema<AttrDeleteOp<any> | DeleteOp>}
524
817
  */
525
- export const $deleteOp = s.$custom(o => o != null && (o.constructor === DeleteOp || o.constructor === MapDeleteOp))
818
+ export const $deleteOp = s.$custom(o => o != null && (o.constructor === DeleteOp || o.constructor === AttrDeleteOp))
526
819
 
527
820
  /**
528
- * @type {s.Schema<MapInsertOp<any> | InsertOp<any>>}
821
+ * @type {s.Schema<AttrInsertOp<any> | InsertOp<any>>}
529
822
  */
530
- export const $insertOp = s.$custom(o => o != null && (o.constructor === MapInsertOp || o.constructor === InsertOp))
823
+ export const $insertOp = s.$custom(o => o != null && (o.constructor === AttrInsertOp || o.constructor === InsertOp))
531
824
 
532
825
  /**
533
- * @template Content
826
+ * @template {encoding.AnyEncodable|DeltaAny} Content
534
827
  * @param {s.Schema<Content>} $content
535
- * @return {s.Schema<MapInsertOp<Content> | InsertOp<Content>>}
828
+ * @return {s.Schema<AttrInsertOp<Content> | InsertOp<Content>>}
536
829
  */
537
830
  export const $insertOpWith = $content => s.$custom(o =>
538
831
  o != null && (
539
- (o.constructor === MapInsertOp && $content.check(/** @type {MapInsertOp<Content>} */ (o).value)) ||
832
+ (o.constructor === AttrInsertOp && $content.check(/** @type {AttrInsertOp<Content>} */ (o).value)) ||
540
833
  (o.constructor === InsertOp && /** @type {InsertOp<Content>} */ (o).insert.every(ins => $content.check(ins)))
541
834
  )
542
835
  )
@@ -552,18 +845,18 @@ export const $textOp = s.$constructedBy(TextOp)
552
845
  export const $retainOp = s.$constructedBy(RetainOp)
553
846
 
554
847
  /**
555
- * @type {s.Schema<MapModifyOp<any> | ModifyOp<any>>}
848
+ * @type {s.Schema<AttrModifyOp | ModifyOp>}
556
849
  */
557
- export const $modifyOp = s.$custom(o => o != null && (o.constructor === MapModifyOp || o.constructor === ModifyOp))
850
+ export const $modifyOp = s.$custom(o => o != null && (o.constructor === AttrModifyOp || o.constructor === ModifyOp))
558
851
 
559
852
  /**
560
853
  * @template {DeltaAny} Modify
561
854
  * @param {s.Schema<Modify>} $content
562
- * @return {s.Schema<MapModifyOp<Modify> | ModifyOp<Modify>>}
855
+ * @return {s.Schema<AttrModifyOp<Modify> | ModifyOp<Modify>>}
563
856
  */
564
857
  export const $modifyOpWith = $content => s.$custom(o =>
565
858
  o != null && (
566
- (o.constructor === MapModifyOp && $content.check(/** @type {MapModifyOp<Modify>} */ (o).value)) ||
859
+ (o.constructor === AttrModifyOp && $content.check(/** @type {AttrModifyOp<Modify>} */ (o).value)) ||
567
860
  (o.constructor === ModifyOp && $content.check(/** @type {ModifyOp<Modify>} */ (o).value))
568
861
  )
569
862
  )
@@ -579,8 +872,8 @@ export const $anyOp = s.$union($insertOp, $deleteOp, $textOp, $modifyOp)
579
872
  */
580
873
 
581
874
  /**
582
- * @template {{[Key in string|number|symbol]: any}} Attrs
583
- * @template {string|number|symbol} Key
875
+ * @template {{[Key in string|number]: any}} Attrs
876
+ * @template {string|number} Key
584
877
  * @template {any} Val
585
878
  * @typedef {{ [K in (Key | keyof Attrs)]: (unknown extends Attrs[K] ? never : Attrs[K]) | (Key extends K ? Val : never) }} AddToAttrs
586
879
  */
@@ -598,29 +891,20 @@ export const $anyOp = s.$union($insertOp, $deleteOp, $textOp, $modifyOp)
598
891
 
599
892
  /**
600
893
  * @template {s.Schema<Delta<any,any,any,any,any>>|null} Schema
601
- * @typedef {_AnyToNull<Schema> extends null ? Delta<any,{[key:string|number|symbol]:any},any,string> : (Schema extends s.Schema<infer D> ? D : never)} AllowedDeltaFromSchema
894
+ * @typedef {_AnyToNull<Schema> extends null ? Delta<any,{[key:string|number]:any},any,string> : (Schema extends s.Schema<infer D> ? D : never)} AllowedDeltaFromSchema
602
895
  */
603
896
 
604
897
  /**
605
- * @typedef {Delta<any,{ [k:string]: any },any,any,any>} DeltaAny
898
+ * @typedef {Delta<any,{ [k:string|number]: any },any,any,any>} DeltaAny
606
899
  */
607
-
608
- // note: simply copy the values from Delta.attrs as the parameter of the function
609
900
  /**
610
- * @template {{[key:string|number|symbol]:any}} [Attrs={}]
611
- * @param {Delta<any,Attrs,any,any,any>} d
612
- * @param {(v:{ [K in keyof Attrs]: MapInsertOp<Attrs[K],K>|MapDeleteOp<Attrs[K],K>|(Delta extends Attrs[K] ? MapModifyOp<Extract<Attrs[K],Delta>,K> : never) }[keyof Attrs])=>any} handler
901
+ * @typedef {DeltaBuilder<any,{ [k:string|number]: any },any,any,any>} DeltaBuilderAny
613
902
  */
614
- export const forEachAttr = (d, handler) => {
615
- for (const k in d.attrs) {
616
- handler(/** @type {any} */ (d.attrs[k]))
617
- }
618
- }
619
903
 
620
904
  /**
621
905
  * @template {string} [NodeName=any]
622
- * @template {{[key:string|number|symbol]:any}} [Attrs={}]
623
- * @template {any} [Children=never]
906
+ * @template {{[k:string|number]:any}} [Attrs={}]
907
+ * @template {encoding.AnyEncodable|DeltaAny|never} [Children=never]
624
908
  * @template {string|never} [Text=never]
625
909
  * @template {s.Schema<Delta<any,any,any,any,any>>|null} [Schema=any]
626
910
  */
@@ -633,7 +917,9 @@ export class Delta {
633
917
  this.name = name || null
634
918
  this.$schema = $schema || null
635
919
  /**
636
- * @type {{ [K in keyof Attrs]?: MapInsertOp<Attrs[K],K>|MapDeleteOp<Attrs[K],K>|(Delta extends Attrs[K] ? MapModifyOp<Extract<Attrs[K],Delta>,K> : never) } & { [Symbol.iterator]: () => Iterator<{ [K in keyof Attrs]: MapInsertOp<Attrs[K],K>|MapDeleteOp<Attrs[K],K>|(Delta extends Attrs[K] ? MapModifyOp<Extract<Attrs[K],Delta>,K> : never) }[keyof Attrs]> }}
920
+ * @type {{ [K in keyof Attrs]?: K extends string|number ? (AttrInsertOp<Attrs[K],K>|AttrDeleteOp<Attrs[K],K>|(Delta extends Attrs[K] ? AttrModifyOp<Extract<Attrs[K],DeltaAny>,K> : never)) : never }
921
+ * & { [Symbol.iterator]: () => Iterator<{ [K in keyof Attrs]: K extends string|number ? (AttrInsertOp<Attrs[K],K>|AttrDeleteOp<Attrs[K],K>|(Delta extends Attrs[K] ? AttrModifyOp<Extract<Attrs[K],DeltaAny>,K> : never)) : never }[keyof Attrs]> }
922
+ * }
637
923
  */
638
924
  this.attrs = /** @type {any} */ ({
639
925
  * [Symbol.iterator] () {
@@ -653,10 +939,50 @@ export class Delta {
653
939
  * >}
654
940
  */
655
941
  this.children = /** @type {any} */ (list.create())
942
+ this.childCnt = 0
656
943
  /**
657
944
  * @type {any}
658
945
  */
659
946
  this.origin = null
947
+ /**
948
+ * @type {string|null}
949
+ */
950
+ this._fingerprint = null
951
+ this.isDone = false
952
+ }
953
+
954
+ /**
955
+ * @type {string}
956
+ */
957
+ get fingerprint () {
958
+ return this._fingerprint || (this._fingerprint = buffer.toBase64(encoding.encode(encoder => {
959
+ encoding.writeAny(encoder, this.name)
960
+ /**
961
+ * @type {Array<number|string>}
962
+ */
963
+ const keys = []
964
+ for (const attr of this.attrs) {
965
+ keys.push(attr.key)
966
+ }
967
+ keys.sort((a, b) => {
968
+ const aIsString = s.$string.check(a)
969
+ const bIsString = s.$string.check(b)
970
+ // numbers first
971
+ // in ascending order
972
+ return (aIsString && bIsString)
973
+ ? a.localeCompare(b)
974
+ : (aIsString ? 1 : (bIsString ? -1 : (a - b)))
975
+ })
976
+ encoding.writeVarUint(encoder, keys.length)
977
+ for (const key of keys) {
978
+ encoding.writeVarString(encoder, /** @type {any} */ (this.attrs[/** @type {keyof Attrs} */ (key)]).fingerprint)
979
+ }
980
+ encoding.writeVarUint(encoder, this.children.len)
981
+ for (const child of this.children) {
982
+ encoding.writeVarString(encoder, child.fingerprint)
983
+ }
984
+ return buffer.toBase64(rabin.fingerprint(rabin.StandardIrreducible128, encoding.toUint8Array(encoder)))
985
+ })))
660
986
  }
661
987
 
662
988
  isEmpty () {
@@ -667,6 +993,7 @@ export class Delta {
667
993
  * @return {DeltaJSON}
668
994
  */
669
995
  toJSON () {
996
+ const name = this.name
670
997
  /**
671
998
  * @type {any}
672
999
  */
@@ -675,14 +1002,15 @@ export class Delta {
675
1002
  * @type {any}
676
1003
  */
677
1004
  const children = []
678
- forEachAttr(this, attr => {
1005
+ for (const attr of this.attrs) {
679
1006
  attrs[attr.key] = attr.toJSON()
680
- })
1007
+ }
681
1008
  this.children.forEach(val => {
682
1009
  children.push(val.toJSON())
683
1010
  })
684
1011
  return object.assign(
685
- (this.name != null ? { name: this.name } : {}),
1012
+ { type: /** @type {'delta'} */ ('delta') },
1013
+ (name != null ? { name } : {}),
686
1014
  (object.isEmpty(attrs) ? {} : { attrs }),
687
1015
  (children.length > 0 ? { children } : {})
688
1016
  )
@@ -697,36 +1025,139 @@ export class Delta {
697
1025
  }
698
1026
 
699
1027
  /**
700
- * @return {this}
1028
+ * @param {any} other
1029
+ * @return {boolean}
701
1030
  */
702
- clone () {
1031
+ [traits.EqualityTraitSymbol] (other) {
1032
+ // @todo it is only necessary to compare finrerprints OR do a deep equality check
1033
+ return this.name === other.name && fun.equalityDeep(this.attrs, other.attrs) && fun.equalityDeep(this.children, other.children) && this.childCnt === other.childCnt && this.fingerprint === other.fingerprint
1034
+ }
1035
+
1036
+ /**
1037
+ * @param {number} start
1038
+ * @param {number} end
1039
+ * @return {Delta<NodeName,Attrs,Children,Text,Schema>}
1040
+ */
1041
+ slice (start = 0, end = this.childCnt) {
1042
+ const cpy = /** @type {DeltaAny} */ (new DeltaBuilder(/** @type {any} */ (this.name), this.$schema))
1043
+ cpy.origin = this.origin
1044
+ // copy attrs
1045
+ for (const op of this.attrs) {
1046
+ cpy.attrs[op.key] = /** @type {any} */ (op.clone())
1047
+ }
1048
+ // copy children
1049
+ const slicedLen = end - start
1050
+ let remainingLen = slicedLen
703
1051
  /**
704
- * @type {Delta<any,Attrs,any,any,any>}
1052
+ * @type {ChildrenOpAny?}
705
1053
  */
706
- const d = new DeltaBuilder(/** @type {any} */ (this.name), this.$schema)
707
- d.origin = this.origin
708
- for (const op of this.attrs) {
709
- d.attrs[op.key] = /** @type {any} */ (op)
1054
+ let currNode = this.children.start
1055
+ let currNodeOffset = 0
1056
+ while (start > 0 && currNode != null) {
1057
+ if (currNode.length <= start) {
1058
+ start -= currNode.length
1059
+ currNode = currNode.next
1060
+ } else {
1061
+ currNodeOffset = start
1062
+ start = 0
1063
+ }
710
1064
  }
711
- this.children.forEach(op => {
712
- list.pushEnd(d.children, op.clone())
713
- })
714
- return /** @type {any} */ (d)
1065
+ if (currNodeOffset > 0 && currNode) {
1066
+ const ncpy = currNode.clone(currNodeOffset, currNodeOffset + math.min(remainingLen, currNode.length - currNodeOffset))
1067
+ list.pushEnd(cpy.children, ncpy)
1068
+ remainingLen -= ncpy.length
1069
+ currNode = currNode.next
1070
+ }
1071
+ while (currNode != null && currNode.length <= remainingLen) {
1072
+ list.pushEnd(cpy.children, currNode.clone())
1073
+ currNode = currNode.next
1074
+ }
1075
+ if (currNode != null && remainingLen > 0) {
1076
+ list.pushEnd(cpy.children, currNode.clone(0, remainingLen))
1077
+ }
1078
+ cpy.childCnt = slicedLen - remainingLen
1079
+ // @ts-ignore
1080
+ return cpy
715
1081
  }
716
1082
 
717
1083
  /**
718
- * @param {any} other
719
- * @return {boolean}
1084
+ * Mark this delta as done and perform some cleanup (e.g. remove appended retains without
1085
+ * formats&attributions). In the future, there might be additional merge operations that can be
1086
+ * performed to result in smaller deltas. Set `markAsDone=false` to only perform the cleanup.
1087
+ *
1088
+ * @return {Delta<NodeName,Attrs,Children,Text,Schema>}
720
1089
  */
721
- [traits.EqualityTraitSymbol] (other) {
722
- return this.name === other.name && fun.equalityDeep(this.attrs, other.attrs) && fun.equalityDeep(this.children, other.children)
1090
+ done (markAsDone = true) {
1091
+ if (!this.isDone) {
1092
+ this.isDone = markAsDone
1093
+ const cs = this.children
1094
+ for (let end = cs.end; end !== null && $retainOp.check(end) && end.format == null && end.attribution == null; end = cs.end) {
1095
+ this.childCnt -= end.length
1096
+ list.popEnd(cs)
1097
+ }
1098
+ }
1099
+ return this
723
1100
  }
724
1101
  }
725
1102
 
1103
+ /**
1104
+ * @template {DeltaAny} D
1105
+ * @param {D} d
1106
+ * @return {D extends Delta<infer NodeName,infer Attrs,infer Children,infer Text,infer Schema> ? DeltaBuilder<NodeName,Attrs,Children,Text,Schema> : never}
1107
+ */
1108
+ export const clone = d => /** @type {any} */ (d.slice(0, d.childCnt))
1109
+
1110
+ /**
1111
+ * Try merging this op with the previous op
1112
+ * @param {list.List<any>} parent
1113
+ * @param {InsertOp<any>|RetainOp|DeleteOp|TextOp|ModifyOp<any>} op
1114
+ */
1115
+ const tryMergeWithPrev = (parent, op) => {
1116
+ const prevOp = op.prev
1117
+ if (
1118
+ prevOp?.constructor !== op.constructor ||
1119
+ (
1120
+ (!$deleteOp.check(op) && !$modifyOp.check(op)) && (!fun.equalityDeep(op.format, /** @type {InsertOp<any>} */ (prevOp).format) || !fun.equalityDeep(op.attribution, /** @type {InsertOp<any>} */ (prevOp).attribution))
1121
+ )
1122
+ ) {
1123
+ // constructor mismatch or format/attribution mismatch
1124
+ return
1125
+ }
1126
+ // can be merged
1127
+ if ($insertOp.check(op)) {
1128
+ /** @type {InsertOp<any>} */ (prevOp).insert.push(...op.insert)
1129
+ } else if ($retainOp.check(op)) {
1130
+ // @ts-ignore
1131
+ /** @type {RetainOp} */ (prevOp).retain += op.retain
1132
+ } else if ($deleteOp.check(op)) {
1133
+ /** @type {DeleteOp} */ (prevOp).delete += op.delete
1134
+ } else if ($textOp.check(op)) {
1135
+ /** @type {TextOp} */ (prevOp)._updateInsert(/** @type {TextOp} */ (prevOp).insert + op.insert)
1136
+ } else {
1137
+ error.unexpectedCase()
1138
+ }
1139
+ list.remove(parent, op)
1140
+ }
1141
+
1142
+ /**
1143
+ * Ensures that the delta can be edited. clears _fingerprint cache.
1144
+ *
1145
+ * @param {any} d
1146
+ */
1147
+ const modDeltaCheck = d => {
1148
+ if (d.isDone) {
1149
+ /**
1150
+ * You tried to modify a delta after it has been marked as "done".
1151
+ */
1152
+ throw error.create("Readonly Delta can't be modified")
1153
+ }
1154
+ d._fingerprint = null
1155
+ }
1156
+
726
1157
  /**
727
1158
  * @template {string} [NodeName=any]
728
- * @template {{[key:string|number|symbol]:any}} [Attrs={}]
729
- * @template {any} [Children=never]
1159
+ * @template {{[key:string|number]:any}} [Attrs={}]
1160
+ * @template {encoding.AnyEncodable|DeltaAny|never} [Children=never]
730
1161
  * @template {string|never} [Text=never]
731
1162
  * @template {s.Schema<Delta<any,any,any,any,any>>|null} [Schema=any]
732
1163
  * @extends {Delta<NodeName,Attrs,Children,Text,Schema>}
@@ -752,6 +1183,7 @@ export class DeltaBuilder extends Delta {
752
1183
  * @param {Attribution?} attribution
753
1184
  */
754
1185
  useAttribution (attribution) {
1186
+ modDeltaCheck(this)
755
1187
  this.usedAttribution = attribution
756
1188
  return this
757
1189
  }
@@ -761,6 +1193,7 @@ export class DeltaBuilder extends Delta {
761
1193
  * @return {this}
762
1194
  */
763
1195
  useAttributes (attributes) {
1196
+ modDeltaCheck(this)
764
1197
  this.usedAttributes = attributes
765
1198
  return this
766
1199
  }
@@ -770,6 +1203,7 @@ export class DeltaBuilder extends Delta {
770
1203
  * @param {any} value
771
1204
  */
772
1205
  updateUsedAttributes (name, value) {
1206
+ modDeltaCheck(this)
773
1207
  if (value == null) {
774
1208
  this.usedAttributes = object.assign({}, this.usedAttributes)
775
1209
  delete this.usedAttributes?.[name]
@@ -789,6 +1223,7 @@ export class DeltaBuilder extends Delta {
789
1223
  * @param {Attribution[NAME]?} value
790
1224
  */
791
1225
  updateUsedAttribution (name, value) {
1226
+ modDeltaCheck(this)
792
1227
  if (value == null) {
793
1228
  this.usedAttribution = object.assign({}, this.usedAttribution)
794
1229
  delete this.usedAttribution?.[name]
@@ -811,11 +1246,12 @@ export class DeltaBuilder extends Delta {
811
1246
  * NodeName,
812
1247
  * Attrs,
813
1248
  * Exclude<NewContent,string>[number]|Children,
814
- * (Extract<NewContent,string>|Text) extends string ? string : never,
1249
+ * (Extract<NewContent,string>|Text) extends never ? never : string,
815
1250
  * Schema
816
1251
  * >}
817
1252
  */
818
1253
  insert (insert, formatting = null, attribution = null) {
1254
+ modDeltaCheck(this)
819
1255
  const mergedAttributes = mergeAttrs(this.usedAttributes, formatting)
820
1256
  const mergedAttribution = mergeAttrs(this.usedAttribution, attribution)
821
1257
  /**
@@ -825,16 +1261,20 @@ export class DeltaBuilder extends Delta {
825
1261
  const end = this.children.end
826
1262
  if (s.$string.check(insert)) {
827
1263
  if ($textOp.check(end) && checkMergedEquals(end)) {
828
- end.insert += insert
1264
+ end._updateInsert(end.insert + insert)
829
1265
  } else if (insert.length > 0) {
830
1266
  list.pushEnd(this.children, new TextOp(insert, object.isEmpty(mergedAttributes) ? null : mergedAttributes, object.isEmpty(mergedAttribution) ? null : mergedAttribution))
831
1267
  }
1268
+ this.childCnt += insert.length
832
1269
  } else if (arr.isArray(insert)) {
833
1270
  if ($insertOp.check(end) && checkMergedEquals(end)) {
1271
+ // @ts-ignore
834
1272
  end.insert.push(...insert)
1273
+ end._fingerprint = null
835
1274
  } else if (insert.length > 0) {
836
1275
  list.pushEnd(this.children, new InsertOp(insert, object.isEmpty(mergedAttributes) ? null : mergedAttributes, object.isEmpty(mergedAttribution) ? null : mergedAttribution))
837
1276
  }
1277
+ this.childCnt += insert.length
838
1278
  }
839
1279
  return /** @type {any} */ (this)
840
1280
  }
@@ -853,9 +1293,11 @@ export class DeltaBuilder extends Delta {
853
1293
  * >}
854
1294
  */
855
1295
  modify (modify, formatting = null, attribution = null) {
1296
+ modDeltaCheck(this)
856
1297
  const mergedAttributes = mergeAttrs(this.usedAttributes, formatting)
857
1298
  const mergedAttribution = mergeAttrs(this.usedAttribution, attribution)
858
1299
  list.pushEnd(this.children, new ModifyOp(modify, object.isEmpty(mergedAttributes) ? null : mergedAttributes, object.isEmpty(mergedAttribution) ? null : mergedAttribution))
1300
+ this.childCnt += 1
859
1301
  return /** @type {any} */ (this)
860
1302
  }
861
1303
 
@@ -865,14 +1307,17 @@ export class DeltaBuilder extends Delta {
865
1307
  * @param {Attribution?} [attribution]
866
1308
  */
867
1309
  retain (len, format = null, attribution = null) {
1310
+ modDeltaCheck(this)
868
1311
  const mergedFormats = mergeAttrs(this.usedAttributes, format)
869
1312
  const mergedAttribution = mergeAttrs(this.usedAttribution, attribution)
870
1313
  const lastOp = /** @type {RetainOp|InsertOp<any>} */ (this.children.end)
871
1314
  if (lastOp instanceof RetainOp && fun.equalityDeep(mergedFormats, lastOp.format) && fun.equalityDeep(mergedAttribution, lastOp.attribution)) {
1315
+ // @ts-ignore
872
1316
  lastOp.retain += len
873
1317
  } else if (len > 0) {
874
1318
  list.pushEnd(this.children, new RetainOp(len, mergedFormats, mergedAttribution))
875
1319
  }
1320
+ this.childCnt += len
876
1321
  return this
877
1322
  }
878
1323
 
@@ -880,12 +1325,14 @@ export class DeltaBuilder extends Delta {
880
1325
  * @param {number} len
881
1326
  */
882
1327
  delete (len) {
1328
+ modDeltaCheck(this)
883
1329
  const lastOp = /** @type {DeleteOp|InsertOp<any>} */ (this.children.end)
884
1330
  if (lastOp instanceof DeleteOp) {
885
1331
  lastOp.delete += len
886
1332
  } else if (len > 0) {
887
1333
  list.pushEnd(this.children, new DeleteOp(len))
888
1334
  }
1335
+ this.childCnt += len
889
1336
  return this
890
1337
  }
891
1338
 
@@ -905,7 +1352,8 @@ export class DeltaBuilder extends Delta {
905
1352
  * >}
906
1353
  */
907
1354
  set (key, val, attribution = null, prevValue) {
908
- this.attrs[key] = /** @type {any} */ (new MapInsertOp(key, val, prevValue, mergeAttrs(this.usedAttribution, attribution)))
1355
+ modDeltaCheck(this)
1356
+ this.attrs[key] = /** @type {any} */ (new AttrInsertOp(key, val, prevValue, mergeAttrs(this.usedAttribution, attribution)))
909
1357
  return /** @type {any} */ (this)
910
1358
  }
911
1359
 
@@ -922,6 +1370,7 @@ export class DeltaBuilder extends Delta {
922
1370
  * >}
923
1371
  */
924
1372
  setMany (attrs, attribution = null) {
1373
+ modDeltaCheck(this)
925
1374
  for (const k in attrs) {
926
1375
  this.set(/** @type {any} */ (k), attrs[k], attribution)
927
1376
  }
@@ -942,7 +1391,8 @@ export class DeltaBuilder extends Delta {
942
1391
  * >}
943
1392
  */
944
1393
  unset (key, attribution = null, prevValue) {
945
- this.attrs[key] = /** @type {any} */ (new MapDeleteOp(key, prevValue, mergeAttrs(this.usedAttribution, attribution)))
1394
+ modDeltaCheck(this)
1395
+ this.attrs[key] = /** @type {any} */ (new AttrDeleteOp(key, prevValue, mergeAttrs(this.usedAttribution, attribution)))
946
1396
  return /** @type {any} */ (this)
947
1397
  }
948
1398
 
@@ -960,7 +1410,8 @@ export class DeltaBuilder extends Delta {
960
1410
  * >}
961
1411
  */
962
1412
  update (key, modify) {
963
- this.attrs[key] = /** @type {any} */ (new MapModifyOp(key, modify))
1413
+ modDeltaCheck(this)
1414
+ this.attrs[key] = /** @type {any} */ (new AttrModifyOp(key, modify))
964
1415
  return /** @type {any} */ (this)
965
1416
  }
966
1417
 
@@ -968,37 +1419,64 @@ export class DeltaBuilder extends Delta {
968
1419
  * @param {Delta<NodeName,Attrs,Children,Text,any>} other
969
1420
  */
970
1421
  apply (other) {
1422
+ modDeltaCheck(this)
971
1423
  this.$schema?.expect(other)
972
- forEachAttr(/** @type {Delta<NodeName,Attrs,Children,Text,any>} */ (/** @type {any} */ (other)), op => {
973
- const c = this.attrs[op.key]
1424
+ // apply attrs
1425
+ for (let op of other.attrs) {
1426
+ const c = /** @type {AttrInsertOp<any,any>|AttrDeleteOp<any>|AttrModifyOp<any,any>} */ (this.attrs[op.key])
974
1427
  if ($modifyOp.check(op)) {
975
1428
  if ($deltaAny.check(c?.value)) {
976
- /** @type {DeltaBuilder} */ (c.value).apply(op.value)
1429
+ c._modValue.apply(op.value)
977
1430
  } else {
978
1431
  // then this is a simple modify
979
- this.attrs[op.key] = /** @type {any} */ (op)
1432
+ // @ts-ignore
1433
+ this.attrs[op.key] = op.clone()
980
1434
  }
981
1435
  } else {
982
- /** @type {MapInsertOp<any>} */ (op).prevValue = c?.value
983
- this.attrs[op.key] = /** @type {any} */ (op)
1436
+ op = /** @type {any} */ (op.clone())
1437
+ // @ts-ignore
1438
+ op.prevValue = c?.value
1439
+ // @ts-ignore
1440
+ this.attrs[op.key] = op
984
1441
  }
985
- })
1442
+ }
986
1443
  // apply children
1444
+ /**
1445
+ * @type {ChildrenOpAny?}
1446
+ */
987
1447
  let opsI = this.children.start
988
1448
  let offset = 0
1449
+ /**
1450
+ * At the end, we will try to merge this op, and op.next op with their respective previous op.
1451
+ *
1452
+ * Hence, anytime an op is cloned, deleted, or inserted (anytime list.* api is used) we must add
1453
+ * an op to maybeMergeable.
1454
+ *
1455
+ * @type {Array<InsertOp<any>|RetainOp|DeleteOp|TextOp|ModifyOp<any>>}
1456
+ */
1457
+ const maybeMergeable = []
1458
+ /**
1459
+ * @template {InsertOp<any>|RetainOp|DeleteOp|TextOp|ModifyOp<any>|null} OP
1460
+ * @param {OP} op
1461
+ * @return {OP}
1462
+ */
1463
+ const scheduleForMerge = op => {
1464
+ op && maybeMergeable.push(op)
1465
+ return op
1466
+ }
989
1467
  other.children.forEach(op => {
990
1468
  if ($textOp.check(op) || $insertOp.check(op)) {
991
1469
  if (offset === 0) {
992
- list.insertBetween(this.children, opsI == null ? this.children.end : opsI.prev, opsI, op.clone())
1470
+ list.insertBetween(this.children, opsI == null ? this.children.end : opsI.prev, opsI, scheduleForMerge(op.clone()))
993
1471
  } else {
994
1472
  if (opsI == null) error.unexpectedCase()
995
- const cpy = opsI.clone()
996
- cpy._splice(0, offset)
1473
+ const cpy = scheduleForMerge(opsI.clone(offset))
997
1474
  opsI._splice(offset, opsI.length - offset)
998
1475
  list.insertBetween(this.children, opsI, opsI.next || null, cpy)
999
- list.insertBetween(this.children, opsI, cpy || null, op)
1476
+ list.insertBetween(this.children, opsI, cpy || null, scheduleForMerge(op.clone()))
1000
1477
  offset = 0
1001
1478
  }
1479
+ this.childCnt += op.insert.length
1002
1480
  } else if ($retainOp.check(op)) {
1003
1481
  let skipLen = op.length
1004
1482
  while (opsI != null && opsI.length - offset <= skipLen) {
@@ -1009,13 +1487,15 @@ export class DeltaBuilder extends Delta {
1009
1487
  if (opsI != null) {
1010
1488
  offset += skipLen
1011
1489
  } else {
1012
- list.pushEnd(this.children, new RetainOp(skipLen, op.format, op.attribution))
1490
+ list.pushEnd(this.children, scheduleForMerge(new RetainOp(skipLen, op.format, op.attribution)))
1491
+ this.childCnt += skipLen
1013
1492
  }
1014
1493
  } else if ($deleteOp.check(op)) {
1015
1494
  let remainingLen = op.delete
1016
1495
  while (remainingLen > 0) {
1017
1496
  if (opsI == null) {
1018
- list.pushEnd(this.children, new DeleteOp(remainingLen))
1497
+ list.pushEnd(this.children, scheduleForMerge(new DeleteOp(remainingLen)))
1498
+ this.childCnt += remainingLen
1019
1499
  break
1020
1500
  } else if (opsI instanceof DeleteOp) {
1021
1501
  const delLen = opsI.length - offset
@@ -1033,9 +1513,11 @@ export class DeltaBuilder extends Delta {
1033
1513
  // case3: delete some part of end
1034
1514
  // case4: delete some part of center
1035
1515
  const delLen = math.min(opsI.length - offset, remainingLen)
1516
+ this.childCnt -= delLen
1036
1517
  if (opsI.length === delLen) {
1037
1518
  // case 1
1038
1519
  offset = 0
1520
+ scheduleForMerge(opsI.next)
1039
1521
  list.remove(this.children, opsI)
1040
1522
  } else if (offset === 0) {
1041
1523
  // case 2
@@ -1056,32 +1538,26 @@ export class DeltaBuilder extends Delta {
1056
1538
  } else if ($modifyOp.check(op)) {
1057
1539
  if (opsI == null) {
1058
1540
  list.pushEnd(this.children, op.clone())
1541
+ this.childCnt += 1
1059
1542
  return
1060
1543
  }
1061
1544
  if ($modifyOp.check(opsI)) {
1062
- /** @type {any} */ (opsI.value).apply(op.value)
1063
- } else if ($textOp.check(opsI) || $insertOp.check(opsI)) {
1064
- const d = opsI.insert[offset]
1065
- if (!$deltaAny.check(d)) {
1066
- // probably incompatible delta. can only modify deltas
1067
- error.unexpectedCase()
1068
- }
1069
- /** @type {any} */ (d).apply(op.value)
1545
+ opsI._modValue.apply(op.value)
1546
+ } else if ($insertOp.check(opsI)) {
1547
+ opsI._modValue(offset).apply(op.value)
1070
1548
  } else if ($retainOp.check(opsI)) {
1071
1549
  if (offset > 0) {
1072
- const cpy = opsI.clone()
1073
- cpy._splice(offset, opsI.length - offset) // skipped len
1550
+ const cpy = scheduleForMerge(opsI.clone(0, offset)) // skipped len
1074
1551
  opsI._splice(0, offset) // new remainder
1075
1552
  list.insertBetween(this.children, opsI.prev, opsI, cpy) // insert skipped len
1076
1553
  offset = 0
1077
1554
  }
1078
- // not deleting opsI, because current idea is that modify should not
1079
- // advance content
1080
- list.insertBetween(this.children, opsI.prev, opsI, op.clone()) // insert skipped len
1555
+ list.insertBetween(this.children, opsI.prev, opsI, scheduleForMerge(op.clone())) // insert skipped len
1081
1556
  if (opsI.length === 1) {
1082
1557
  list.remove(this.children, opsI)
1083
1558
  } else {
1084
1559
  opsI._splice(0, 1)
1560
+ scheduleForMerge(opsI)
1085
1561
  }
1086
1562
  } else if ($deleteOp.check(opsI)) {
1087
1563
  // nop
@@ -1092,15 +1568,22 @@ export class DeltaBuilder extends Delta {
1092
1568
  error.unexpectedCase()
1093
1569
  }
1094
1570
  })
1571
+ maybeMergeable.forEach(op => {
1572
+ // check if this is still integrated
1573
+ if (op.prev?.next === op) {
1574
+ tryMergeWithPrev(this.children, op)
1575
+ op.next && tryMergeWithPrev(this.children, op.next)
1576
+ }
1577
+ })
1095
1578
  return this
1096
1579
  }
1097
1580
 
1098
1581
  /**
1099
- * @param {Delta<any,any,any,any,any>} other
1582
+ * @param {DeltaAny} other
1100
1583
  * @param {boolean} priority
1101
1584
  */
1102
1585
  rebase (other, priority) {
1103
- // @todo rebase children
1586
+ modDeltaCheck(this)
1104
1587
  /**
1105
1588
  * Rebase attributes
1106
1589
  *
@@ -1111,7 +1594,7 @@ export class DeltaBuilder extends Delta {
1111
1594
  * - delete vs delete ⇒ current delete op is removed because item has already been deleted
1112
1595
  * - modify vs modify ⇒ rebase using priority
1113
1596
  */
1114
- forEachAttr(this, op => {
1597
+ for (const op of this.attrs) {
1115
1598
  if ($insertOp.check(op)) {
1116
1599
  if ($insertOp.check(other.attrs[op.key]) && !priority) {
1117
1600
  delete this.attrs[op.key]
@@ -1126,77 +1609,182 @@ export class DeltaBuilder extends Delta {
1126
1609
  if (otherOp == null) {
1127
1610
  // nop
1128
1611
  } else if ($modifyOp.check(otherOp)) {
1129
- op.value.rebase(otherOp.value, priority)
1612
+ op._modValue.rebase(otherOp.value, priority)
1130
1613
  } else {
1131
1614
  delete this.attrs[otherOp.key]
1132
1615
  }
1133
1616
  }
1134
- })
1617
+ }
1618
+ /**
1619
+ * Rebase children.
1620
+ *
1621
+ * Precedence: insert with higher priority comes first. Op with less priority is transformed to
1622
+ * be inserted later.
1623
+ *
1624
+ * @todo always check if inser OR text
1625
+ */
1626
+ /**
1627
+ * @type {ChildrenOpAny?}
1628
+ */
1629
+ let currChild = this.children.start
1630
+ let currOffset = 0
1631
+ /**
1632
+ * @type {ChildrenOpAny?}
1633
+ */
1634
+ let otherChild = other.children.start
1635
+ let otherOffset = 0
1636
+ while (currChild != null && otherChild != null) {
1637
+ if ($insertOp.check(currChild) || $textOp.check(currChild)) {
1638
+ /**
1639
+ * Transforming *insert*. If other is..
1640
+ * - insert: transform based on priority
1641
+ * - retain/delete/modify: transform next op against other
1642
+ */
1643
+ if ($insertOp.check(otherChild) || $modifyOp.check(otherChild) || $textOp.check(otherChild)) {
1644
+ if (!priority) {
1645
+ list.insertBetween(this.children, currChild.prev, currChild, new RetainOp(otherChild.length, null, null))
1646
+ this.childCnt += otherChild.length
1647
+ // curr is transformed against other, transform curr against next
1648
+ otherOffset = otherChild.length
1649
+ } else {
1650
+ // curr stays as is, transform next op
1651
+ currOffset = currChild.length
1652
+ }
1653
+ } else { // otherChild = delete | retain | modify - curr stays as is, transform next op
1654
+ currOffset = currChild.length
1655
+ }
1656
+ } else if ($modifyOp.check(currChild)) {
1657
+ /**
1658
+ * Transforming *modify*. If other is..
1659
+ * - insert: adjust position
1660
+ * - modify: rebase curr modify on other modify
1661
+ * - delete: remove modify
1662
+ * - retain: adjust offset
1663
+ */
1664
+ if ($insertOp.check(otherChild) || $textOp.check(otherChild)) {
1665
+ // @todo: with all list changes (retain insertions, removal), try to merge the surrounding
1666
+ // ops later
1667
+ list.insertBetween(this.children, currChild.prev, currChild, new RetainOp(otherChild.length, null, null))
1668
+ this.childCnt += otherChild.length
1669
+ // curr is transformed against other, transform curr against next
1670
+ otherOffset = otherChild.length
1671
+ } else {
1672
+ if ($modifyOp.check(otherChild)) {
1673
+ /** @type {any} */ (currChild.value).rebase(otherChild, priority)
1674
+ } else if ($deleteOp.check(otherChild)) {
1675
+ list.remove(this.children, currChild)
1676
+ this.childCnt -= 1
1677
+ }
1678
+ currOffset += 1
1679
+ otherOffset += 1
1680
+ }
1681
+ } else { // DeleteOp | RetainOp
1682
+ const maxCommonLen = math.min(currChild.length - currOffset, otherChild.length - otherOffset)
1683
+ /**
1684
+ * Transforming *retain* OR *delete*. If other is..
1685
+ * - retain / modify: adjust offsets
1686
+ * - delete: shorten curr op
1687
+ * - insert: split curr op and insert retain
1688
+ */
1689
+ if ($retainOp.check(otherChild) || $modifyOp.check(otherChild)) {
1690
+ currOffset += maxCommonLen
1691
+ otherOffset += maxCommonLen
1692
+ } else if ($deleteOp.check(otherChild)) {
1693
+ if ($retainOp.check(currChild)) {
1694
+ // @ts-ignore
1695
+ currChild.retain -= maxCommonLen
1696
+ } else if ($deleteOp.check(currChild)) {
1697
+ currChild.delete -= maxCommonLen
1698
+ }
1699
+ this.childCnt -= maxCommonLen
1700
+ } else { // insert/text.check(currOp)
1701
+ if (currOffset > 0) {
1702
+ const leftPart = currChild.clone(currOffset)
1703
+ list.insertBetween(this.children, currChild.prev, currChild, leftPart)
1704
+ currChild._splice(currOffset, currChild.length - currOffset)
1705
+ currOffset = 0
1706
+ }
1707
+ list.insertBetween(this.children, currChild.prev, currChild, new RetainOp(otherChild.length, null, null))
1708
+ this.childCnt += otherChild.length
1709
+ otherOffset = otherChild.length
1710
+ }
1711
+ }
1712
+ if (currOffset >= currChild.length) {
1713
+ currChild = currChild.next
1714
+ currOffset = 0
1715
+ }
1716
+ if (otherOffset >= otherChild.length) {
1717
+ otherChild = otherChild.next
1718
+ otherOffset = 0
1719
+ }
1720
+ }
1135
1721
  return this
1136
1722
  }
1137
1723
 
1138
1724
  /**
1139
- * @return {Delta<NodeName,Attrs,Children,Text,Schema>}
1725
+ * Same as doing `delta.rebase(other.inverse())`, without creating a temporary delta.
1726
+ *
1727
+ * @param {DeltaAny} other
1728
+ * @param {boolean} priority
1140
1729
  */
1141
- done () {
1142
- const cs = this.children
1143
- for (let end = cs.end; end !== null && $retainOp.check(end) && end.format == null; end = cs.end) {
1144
- list.popEnd(cs)
1145
- }
1730
+ rebaseOnInverse (other, priority) {
1731
+ modDeltaCheck(this)
1732
+ // @todo
1733
+ console.info('method rebaseOnInverse unimplemented')
1146
1734
  return this
1147
1735
  }
1148
1736
  }
1149
1737
 
1150
1738
  /**
1151
1739
  * @template {string} NodeName
1152
- * @template {{ [key: string|number|symbol]: any }} [Attrs={}]
1153
- * @template {any} [Children=never]
1740
+ * @template {{ [key: string|number]: any }} [Attrs={}]
1741
+ * @template {encoding.AnyEncodable|DeltaAny|never} [Children=never]
1154
1742
  * @template {string|never} [Text=never]
1155
1743
  * @typedef {Delta<NodeName,Attrs,Children|Delta<NodeName,Attrs,Children,Text>|RecursiveDelta<NodeName,Attrs,Children,Text>,Text>} RecursiveDelta
1156
1744
  */
1157
1745
 
1158
1746
  /**
1159
- * @template {string} [NodeName=any]
1160
- * @template {{ [key: string|number|symbol]: any }} [Attrs={}]
1161
- * @template {any} [Children=never]
1747
+ * @template {s.Schema<string>|string|Array<string>} [NodeNameSchema=s.Schema<any>]
1748
+ * @template {s.Schema<{ [key: string|number]: any }>|{ [key:string|number]:any }} [AttrsSchema=s.Schema<{}>]
1749
+ * @template {any} [ChildrenSchema=s.Schema<never>]
1162
1750
  * @template {boolean} [HasText=false]
1163
1751
  * @template {boolean} [Recursive=false]
1164
1752
  * @param {object} opts
1165
- * @param {s.Schema<NodeName>?} [opts.name]
1166
- * @param {s.Schema<Attrs>?} [opts.attrs]
1167
- * @param {s.Schema<Children>?} [opts.children]
1168
- * @param {HasText} [opts.hasText]
1753
+ * @param {NodeNameSchema?} [opts.name]
1754
+ * @param {AttrsSchema?} [opts.attrs]
1755
+ * @param {ChildrenSchema?} [opts.children]
1756
+ * @param {HasText} [opts.text]
1169
1757
  * @param {Recursive} [opts.recursive]
1170
- * @return {s.Schema<Delta<
1758
+ * @return {[s.Unwrap<s.ReadSchema<NodeNameSchema>>,s.Unwrap<s.ReadSchema<AttrsSchema>>,s.Unwrap<s.ReadSchema<ChildrenSchema>>] extends [infer NodeName, infer Attrs, infer Children] ? s.Schema<Delta<
1171
1759
  * NodeName,
1172
1760
  * Attrs,
1173
1761
  * Children|(Recursive extends true ? RecursiveDelta<NodeName,Attrs,Children,HasText extends true ? string : never> : never),
1174
1762
  * HasText extends true ? string : never
1175
- * >>}
1763
+ * >> : never}
1176
1764
  */
1177
- export const $delta = ({ name, attrs, children, hasText, recursive }) => {
1178
- name = name == null ? s.$any : name
1765
+ export const $delta = ({ name, attrs, children, text, recursive }) => {
1179
1766
  /**
1180
1767
  * @type {s.Schema<Array<any>>}
1181
1768
  */
1182
- let $arrContent = children == null ? s.$never : s.$array(children)
1183
- const $attrsPartial = attrs == null ? s.$object({}) : (s.$$object.check(attrs) ? attrs.partial : attrs)
1769
+ let $arrContent = children == null ? s.$never : s.$array(s.$(children))
1770
+ const $name = name == null ? s.$any : s.$(name)
1771
+ const $attrsPartial = attrs == null ? s.$object({}) : (s.$$record.check(attrs) ? attrs : /** @type {any} */ (s.$(attrs)).partial)
1184
1772
  const $d = s.$instanceOf(Delta, /** @param {Delta<any,any,any,any,any>} d */ d => {
1185
1773
  if (
1186
- !name.check(d.name) ||
1774
+ !$name.check(d.name) ||
1187
1775
  object.some(d.attrs,
1188
1776
  (op, k) => $insertOp.check(op) && !$attrsPartial.check({ [k]: op.value })
1189
1777
  )
1190
1778
  ) return false
1191
1779
  for (const op of d.children) {
1192
- if ((!hasText && $textOp.check(op)) || ($insertOp.check(op) && !$arrContent.check(op.insert))) {
1780
+ if ((!text && $textOp.check(op)) || ($insertOp.check(op) && !$arrContent.check(op.insert))) {
1193
1781
  return false
1194
1782
  }
1195
1783
  }
1196
1784
  return true
1197
1785
  })
1198
1786
  if (recursive) {
1199
- $arrContent = children == null ? s.$array($d) : s.$array(children, $d)
1787
+ $arrContent = children == null ? s.$array($d) : s.$array(s.$(children), $d)
1200
1788
  }
1201
1789
  return /** @type {any} */ ($d)
1202
1790
  }
@@ -1216,16 +1804,16 @@ export const $deltaAny = /** @type {any} */ (s.$instanceOf(Delta))
1216
1804
  export const mergeAttrs = (a, b) => object.isEmpty(a) ? b : (object.isEmpty(b) ? a : object.assign({}, a, b))
1217
1805
 
1218
1806
  /**
1219
- * @template {DeltaBuilder?} D
1807
+ * @template {DeltaAny|null} D
1220
1808
  * @param {D} a
1221
1809
  * @param {D} b
1222
1810
  * @return {D}
1223
1811
  */
1224
1812
  export const mergeDeltas = (a, b) => {
1225
1813
  if (a != null && b != null) {
1226
- const c = /** @type {Exclude<D,null>} */ (a.clone())
1814
+ const c = clone(a)
1227
1815
  c.apply(b)
1228
- return c
1816
+ return /** @type {any} */ (c)
1229
1817
  }
1230
1818
  return a == null ? b : (a || null)
1231
1819
  }
@@ -1256,8 +1844,8 @@ export const mergeDeltas = (a, b) => {
1256
1844
  */
1257
1845
  /**
1258
1846
  * @template {string|null} NodeName
1259
- * @template {{[k:string|number|symbol]:any}|null} Attrs
1260
- * @template {Array<any>|string} Children
1847
+ * @template {{[k:string|number]:any}|null} Attrs
1848
+ * @template {Array<any>|string} [Children=never]
1261
1849
  * @overload
1262
1850
  * @param {NodeName} nodeName
1263
1851
  * @param {Attrs} attrs
@@ -1272,7 +1860,7 @@ export const mergeDeltas = (a, b) => {
1272
1860
  */
1273
1861
  /**
1274
1862
  * @param {string|s.Schema<DeltaAny>} [nodeNameOrSchema]
1275
- * @param {{[K:string|number|symbol]:any}|s.Schema<DeltaAny>} [attrsOrSchema]
1863
+ * @param {{[K:string|number]:any}|s.Schema<DeltaAny>} [attrsOrSchema]
1276
1864
  * @param {(Array<any>|string)} [children]
1277
1865
  * @return {DeltaBuilder<any,any,any,any,any>}
1278
1866
  */
@@ -1290,12 +1878,12 @@ export const create = (nodeNameOrSchema, attrsOrSchema, children) => {
1290
1878
  // DELTA TEXT
1291
1879
 
1292
1880
  /**
1293
- * @template [Embeds=never]
1881
+ * @template {encoding.AnyEncodable|DeltaAny} [Embeds=never]
1294
1882
  * @typedef {Delta<any,{},Embeds,string>} TextDelta
1295
1883
  */
1296
1884
 
1297
1885
  /**
1298
- * @template [Embeds=never]
1886
+ * @template {encoding.AnyEncodable|DeltaAny} [Embeds=never]
1299
1887
  * @typedef {DeltaBuilder<any,{},Embeds,string>} TextDeltaBuilder
1300
1888
  */
1301
1889
 
@@ -1304,7 +1892,7 @@ export const create = (nodeNameOrSchema, attrsOrSchema, children) => {
1304
1892
  * @param {$Embeds} $embeds
1305
1893
  * @return {s.Schema<TextDelta<_AnyToNull<$Embeds> extends null ? never : ($Embeds extends Array<s.Schema<infer $C>> ? $C : never)>>}
1306
1894
  */
1307
- export const $text = (...$embeds) => /** @type {any} */ ($delta({ children: s.$union(...$embeds), hasText: true }))
1895
+ export const $text = (...$embeds) => /** @type {any} */ ($delta({ children: s.$union(...$embeds), text: true }))
1308
1896
  export const $textOnly = $text()
1309
1897
 
1310
1898
  /**
@@ -1315,21 +1903,21 @@ export const $textOnly = $text()
1315
1903
  export const text = $schema => /** @type {any} */ (create($schema || $textOnly))
1316
1904
 
1317
1905
  /**
1318
- * @template {any} Children
1906
+ * @template {encoding.AnyEncodable|DeltaAny} Children
1319
1907
  * @typedef {Delta<any,{},Children,never>} ArrayDelta
1320
1908
  */
1321
1909
 
1322
1910
  /**
1323
- * @template {any} Children
1911
+ * @template {encoding.AnyEncodable|DeltaAny} Children
1324
1912
  * @typedef {DeltaBuilder<any,{},Children,never>} ArrayDeltaBuilder
1325
1913
  */
1326
1914
 
1327
1915
  /**
1328
- * @template {s.Schema<any>} $Children
1916
+ * @template {any|s.Schema<any>} $Children
1329
1917
  * @param {$Children} [$children]
1330
- * @return {s.Schema<ArrayDelta<$Children>>}
1918
+ * @return {s.Schema<ArrayDelta<s.Unwrap<s.ReadSchema<$Children>>>>}
1331
1919
  */
1332
- export const $array = $children => $delta({ children: $children })
1920
+ export const $array = $children => /** @type {any} */ ($delta({ children: $children }))
1333
1921
 
1334
1922
  /**
1335
1923
  * @template {s.Schema<ArrayDelta<any>>} [$Schema=never]
@@ -1339,17 +1927,17 @@ export const $array = $children => $delta({ children: $children })
1339
1927
  export const array = $schema => /** @type {any} */ ($schema ? create($schema) : create())
1340
1928
 
1341
1929
  /**
1342
- * @template {{ [K: string|number|symbol]: any }} Attrs
1930
+ * @template {{ [K: string|number]: any }} Attrs
1343
1931
  * @typedef {Delta<any,Attrs,never,never>} MapDelta
1344
1932
  */
1345
1933
 
1346
1934
  /**
1347
- * @template {{ [K: string|number|symbol]: any }} Attrs
1935
+ * @template {{ [K: string|number]: any }} Attrs
1348
1936
  * @typedef {DeltaBuilder<any,Attrs,never,never>} MapDeltaBuilder
1349
1937
  */
1350
1938
 
1351
1939
  /**
1352
- * @template {{ [K: string|number|symbol]: any }} $Attrs
1940
+ * @template {{ [K: string|number]: any }} $Attrs
1353
1941
  * @param {s.Schema<$Attrs>} $attrs
1354
1942
  * @return {s.Schema<MapDelta<$Attrs>>}
1355
1943
  */
@@ -1361,3 +1949,97 @@ export const $map = $attrs => /** @type {any} */ ($delta({ attrs: $attrs }))
1361
1949
  * @return {$Schema extends s.Schema<MapDelta<infer Attrs>> ? DeltaBuilder<any,Attrs,never,never,$Schema> : MapDeltaBuilder<{}>}
1362
1950
  */
1363
1951
  export const map = $schema => /** @type {any} */ (create(/** @type {any} */ ($schema)))
1952
+
1953
+ /**
1954
+ * @template {DeltaAny} D
1955
+ * @param {D} d1
1956
+ * @param {NoInfer<D>} d2
1957
+ * @return {D}
1958
+ */
1959
+ export const diff = (d1, d2) => {
1960
+ /**
1961
+ * @type {DeltaBuilderAny}
1962
+ */
1963
+ const d = create()
1964
+ if (d1.fingerprint !== d2.fingerprint) {
1965
+ let left1 = d1.children.start
1966
+ let left2 = d2.children.start
1967
+ let right1 = d1.children.end
1968
+ let right2 = d2.children.end
1969
+ let commonPrefixOffset = 0
1970
+ // perform a patience sort
1971
+ // 1) remove common prefix and suffix
1972
+ while (left1 != null && left1.fingerprint === left2?.fingerprint) {
1973
+ if (!$deleteOp.check(left1)) {
1974
+ commonPrefixOffset += left1.length
1975
+ }
1976
+ left1 = left1.next
1977
+ left2 = left2.next
1978
+ }
1979
+ while (right1 !== null && right1 !== left1 && right1.fingerprint === right2?.fingerprint) {
1980
+ right1 = right1.prev
1981
+ right2 = right2.prev
1982
+ }
1983
+ /**
1984
+ * @type {Array<ChildrenOpAny>}
1985
+ */
1986
+ const ops1 = []
1987
+ /**
1988
+ * @type {Array<ChildrenOpAny>}
1989
+ */
1990
+ const ops2 = []
1991
+ while (left1 !== null && left1 !== right1?.next) {
1992
+ ops1.push(left1)
1993
+ left1 = left1.next
1994
+ }
1995
+ while (left2 !== null && left2 !== right2?.next) {
1996
+ ops2.push(left2)
1997
+ left2 = left2.next
1998
+ }
1999
+ const fprints1 = ops1.map(op => op.fingerprint)
2000
+ const fprints2 = ops2.map(op => op.fingerprint)
2001
+ const changeset = patience.diff(fprints1, fprints2)
2002
+ d.retain(commonPrefixOffset)
2003
+ for (let i = 0, lastIndex1 = 0, currIndexOffset2 = 0; i < changeset.length; i++) {
2004
+ const change = changeset[i]
2005
+ d.retain(change.index - lastIndex1)
2006
+ // insert minimal diff at curred position in d
2007
+ /**
2008
+ * @param {DeltaBuilderAny} d
2009
+ * @param {ChildrenOpAny[]} opsIs
2010
+ * @param {ChildrenOpAny[]} opsShould
2011
+ *
2012
+ */
2013
+ const diffAndApply = (d, opsIs, opsShould) => {
2014
+ // naive implementation
2015
+ d.delete(opsIs.reduce((currLen, op) => currLen + op.length, 0))
2016
+ opsShould.forEach(newIns => {
2017
+ if ($insertOp.check(newIns) || $textOp.check(newIns)) {
2018
+ d.insert(newIns.insert)
2019
+ } else {
2020
+ error.unexpectedCase()
2021
+ }
2022
+ })
2023
+ }
2024
+ diffAndApply(d, ops1.slice(change.index, change.index + change.remove.length), ops2.slice(change.index + currIndexOffset2, change.insert.length))
2025
+ lastIndex1 = change.index + change.remove.length
2026
+ currIndexOffset2 += change.insert.length - change.remove.length
2027
+ }
2028
+ for (const attr2 of d2.attrs) {
2029
+ const attr1 = d1.attrs[attr2.key]
2030
+ if (attr1 == null || (attr1.fingerprint !== attr2.fingerprint)) {
2031
+ if ($insertOp.check(attr2)) {
2032
+ d.set(attr2.key, attr2.value)
2033
+ } else {
2034
+ error.unexpectedCase()
2035
+ }
2036
+ }
2037
+ }
2038
+ for (const attr1 of d1.attrs) {
2039
+ if (d2.attrs[attr1.key] == null) {
2040
+ d.unset(attr1.key)
2041
+ }
2042
+ }
2043
+ }
2044
+ return /** @type {D} */ (d.done())
2045
+ }