lib0 1.0.0-rc.30 → 1.0.0-rc.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/delta/delta.d.ts
CHANGED
|
@@ -85,6 +85,10 @@ export const $deltaMapChangeJson: s.Schema<DeltaAttrOpJSON>;
|
|
|
85
85
|
* fingerprint read (and any `diff` / equality check that relies on it) is
|
|
86
86
|
* wrong. Fields covered: insert, delete, retain, format, attribution,
|
|
87
87
|
* value, key.
|
|
88
|
+
* - **A `clone` copies `_fingerprint` when the copy is content-identical:** a full range and the
|
|
89
|
+
* same key. Freezing a nested value with `done()` is fingerprint-neutral (trailing plain retains
|
|
90
|
+
* are not fingerprinted), so nothing else can differ. The root delta returned by
|
|
91
|
+
* `clone`/`slice`/`cloneDeep` never inherits a fingerprint.
|
|
88
92
|
*
|
|
89
93
|
* @internal not part of the consumer API — a content op; build deltas via {@link create}/{@link DeltaBuilder}.
|
|
90
94
|
*/
|
|
@@ -433,9 +437,12 @@ export class SetAttrOp<V extends unknown = any, K extends string | number = any>
|
|
|
433
437
|
* Full (frozen) clone. A `move` apply reuses the source op instead of cloning, so there is no
|
|
434
438
|
* shared-mutable variant — see {@link DeltaBuilder#apply}.
|
|
435
439
|
*
|
|
436
|
-
* @
|
|
440
|
+
* @template {string|number} [K2=K]
|
|
441
|
+
* @param {K2} [key] retarget the clone to another attribute key (a transformer projecting or
|
|
442
|
+
* renaming an attribute); defaults to this op's key.
|
|
443
|
+
* @return {SetAttrOp<V,K2>}
|
|
437
444
|
*/
|
|
438
|
-
clone(): SetAttrOp<V,
|
|
445
|
+
clone<K2 extends string | number = K>(key?: K2): SetAttrOp<V, K2>;
|
|
439
446
|
$type: s.Schema<SetAttrOp<any, any>>;
|
|
440
447
|
/**
|
|
441
448
|
* @param {SetAttrOp<V>} other
|
|
@@ -475,9 +482,11 @@ export class DeleteAttrOp<V = any, K extends string | number = string | number>
|
|
|
475
482
|
/**
|
|
476
483
|
* Full (frozen) clone; a `move` apply reuses the source op instead — see {@link DeltaBuilder#apply}.
|
|
477
484
|
*
|
|
478
|
-
* @
|
|
485
|
+
* @template {string|number} [K2=K]
|
|
486
|
+
* @param {K2} [key] retarget the clone to another attribute key; defaults to this op's key.
|
|
487
|
+
* @return {DeleteAttrOp<V,K2>}
|
|
479
488
|
*/
|
|
480
|
-
clone(): DeleteAttrOp<V,
|
|
489
|
+
clone<K2 extends string | number = K>(key?: K2): DeleteAttrOp<V, K2>;
|
|
481
490
|
$type: s.Schema<DeleteAttrOp<any, string | number>>;
|
|
482
491
|
/**
|
|
483
492
|
* @param {DeleteAttrOp<V>} other
|
|
@@ -531,9 +540,11 @@ export class ModifyAttrOp<Modifier extends DeltaAny = DeltaAny, K extends string
|
|
|
531
540
|
/**
|
|
532
541
|
* Full (frozen) clone; a `move` apply reuses the source op instead — see {@link DeltaBuilder#apply}.
|
|
533
542
|
*
|
|
534
|
-
* @
|
|
543
|
+
* @template {string|number} [K2=K]
|
|
544
|
+
* @param {K2} [key] retarget the clone to another attribute key; defaults to this op's key.
|
|
545
|
+
* @return {ModifyAttrOp<Modifier,K2>}
|
|
535
546
|
*/
|
|
536
|
-
clone(): ModifyAttrOp<Modifier,
|
|
547
|
+
clone<K2 extends string | number = K>(key?: K2): ModifyAttrOp<Modifier, K2>;
|
|
537
548
|
$type: s.Schema<ModifyAttrOp<any, string>>;
|
|
538
549
|
/**
|
|
539
550
|
* @param {ModifyAttrOp<Modifier>} other
|
|
@@ -545,7 +556,7 @@ export const $modifyOp: s.Schema<ModifyOp<Delta<any>>>;
|
|
|
545
556
|
export const $textOp: s.Schema<TextOp>;
|
|
546
557
|
export const $deleteOp: s.Schema<DeleteOp<any>>;
|
|
547
558
|
export const $retainOp: s.Schema<RetainOp>;
|
|
548
|
-
export const $anyOp: s.Schema<
|
|
559
|
+
export const $anyOp: s.Schema<TextOp | InsertOp<any> | DeleteOp<any> | ModifyOp<Delta<any>>>;
|
|
549
560
|
export const $setAttrOp: s.Schema<SetAttrOp<any>>;
|
|
550
561
|
export const $modifyAttrOp: s.Schema<ModifyAttrOp<any>>;
|
|
551
562
|
export const $deleteAttrOp: s.Schema<DeleteAttrOp<any>>;
|
package/package.json
CHANGED
package/src/delta/delta.js
CHANGED
|
@@ -142,6 +142,29 @@ export const $deltaMapChangeJson = /* @__PURE__ */(() => s.$union(
|
|
|
142
142
|
* @return {Attrs}
|
|
143
143
|
*/
|
|
144
144
|
const _cloneAttrs = attrs => attrs == null ? attrs : { ...attrs }
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* A retain with neither format nor attribution — positional only, not content. `done()` trims a
|
|
148
|
+
* trailing run of them; fingerprint, equality and `isEmpty` ignore that run. (`format: null` is a
|
|
149
|
+
* clear instruction and therefore content — the same rule `done()` applies.)
|
|
150
|
+
*
|
|
151
|
+
* @param {ChildrenOpAny} op
|
|
152
|
+
*/
|
|
153
|
+
const _isPlainRetain = op => $retainOp.check(op) && op.format === undefined && op.attribution === undefined
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* The number of content ops in a children list: its length minus the trailing plain-retain run (found
|
|
157
|
+
* by walking from the right). The first `n` ops from `cs.start` are the content.
|
|
158
|
+
*
|
|
159
|
+
* @param {list.List<ChildrenOpAny>} cs
|
|
160
|
+
* @return {number}
|
|
161
|
+
*/
|
|
162
|
+
const _contentLen = cs => {
|
|
163
|
+
let n = cs.len
|
|
164
|
+
for (let end = cs.end; end !== null && _isPlainRetain(end); end = end.prev) n--
|
|
165
|
+
return n
|
|
166
|
+
}
|
|
167
|
+
|
|
145
168
|
/**
|
|
146
169
|
* Shallow per-key tri-state merge of `update` into `base` (the usual `format`-dimension semantics, also reused
|
|
147
170
|
* as the inner step of {@link mergeAttr}). Per key: `undefined` skips, `null` removes, anything else sets.
|
|
@@ -308,6 +331,10 @@ const combineData = (usedData, arg, deep) => {
|
|
|
308
331
|
return object.isEmpty(r) ? null : /** @type {{[k:string]:any}} */ (r)
|
|
309
332
|
}
|
|
310
333
|
/**
|
|
334
|
+
* Freeze a maybe-delta for a frozen clone (a scalar passes through untouched). `done()` is
|
|
335
|
+
* fingerprint-neutral (it only trims trailing plain retains, which are not fingerprinted), so the
|
|
336
|
+
* clone may carry the op's cached fingerprint over.
|
|
337
|
+
*
|
|
311
338
|
* @template {any} MaybeDelta
|
|
312
339
|
* @param {MaybeDelta} maybeDelta
|
|
313
340
|
* @return {MaybeDelta}
|
|
@@ -329,6 +356,10 @@ const _markMaybeDeltaAsDone = maybeDelta => $deltaAny.check(maybeDelta) ? /** @t
|
|
|
329
356
|
* fingerprint read (and any `diff` / equality check that relies on it) is
|
|
330
357
|
* wrong. Fields covered: insert, delete, retain, format, attribution,
|
|
331
358
|
* value, key.
|
|
359
|
+
* - **A `clone` copies `_fingerprint` when the copy is content-identical:** a full range and the
|
|
360
|
+
* same key. Freezing a nested value with `done()` is fingerprint-neutral (trailing plain retains
|
|
361
|
+
* are not fingerprinted), so nothing else can differ. The root delta returned by
|
|
362
|
+
* `clone`/`slice`/`cloneDeep` never inherits a fingerprint.
|
|
332
363
|
*
|
|
333
364
|
* @internal not part of the consumer API — a content op; build deltas via {@link create}/{@link DeltaBuilder}.
|
|
334
365
|
*/
|
|
@@ -419,7 +450,9 @@ export class TextOp extends list.ListNode {
|
|
|
419
450
|
* @return {TextOp}
|
|
420
451
|
*/
|
|
421
452
|
clone (start = 0, end = this.length, _markAsDone = true) {
|
|
422
|
-
|
|
453
|
+
const cpy = new TextOp(this.insert.slice(start, end), _cloneAttrs(this.format), _cloneAttrs(this.attribution))
|
|
454
|
+
if (start === 0 && end === this.length) cpy._fingerprint = this._fingerprint
|
|
455
|
+
return cpy
|
|
423
456
|
}
|
|
424
457
|
}
|
|
425
458
|
|
|
@@ -541,7 +574,9 @@ export class InsertOp extends list.ListNode {
|
|
|
541
574
|
*/
|
|
542
575
|
clone (start = 0, end = this.length, markAsDone = true) {
|
|
543
576
|
const insert = this.insert.slice(start, end)
|
|
544
|
-
|
|
577
|
+
const cpy = new InsertOp(markAsDone ? insert.map(_markMaybeDeltaAsDone) : insert, _cloneAttrs(this.format), _cloneAttrs(this.attribution))
|
|
578
|
+
if (start === 0 && end === this.length) cpy._fingerprint = this._fingerprint
|
|
579
|
+
return cpy
|
|
545
580
|
}
|
|
546
581
|
}
|
|
547
582
|
|
|
@@ -614,7 +649,9 @@ export class DeleteOp extends list.ListNode {
|
|
|
614
649
|
* @return {DeleteOp}
|
|
615
650
|
*/
|
|
616
651
|
clone (start = 0, end = this.delete, _markAsDone = true) {
|
|
617
|
-
|
|
652
|
+
const cpy = new DeleteOp(end - start)
|
|
653
|
+
if (end - start === this.delete) cpy._fingerprint = this._fingerprint
|
|
654
|
+
return cpy
|
|
618
655
|
}
|
|
619
656
|
}
|
|
620
657
|
|
|
@@ -712,7 +749,9 @@ export class RetainOp extends list.ListNode {
|
|
|
712
749
|
* @return {RetainOp}
|
|
713
750
|
*/
|
|
714
751
|
clone (start = 0, end = this.retain, _markAsDone = true) {
|
|
715
|
-
|
|
752
|
+
const cpy = new RetainOp(end - start, _cloneAttrs(this.format), _cloneAttrs(this.attribution))
|
|
753
|
+
if (end - start === this.retain) cpy._fingerprint = this._fingerprint
|
|
754
|
+
return cpy
|
|
716
755
|
}
|
|
717
756
|
}
|
|
718
757
|
|
|
@@ -829,7 +868,9 @@ export class ModifyOp extends list.ListNode {
|
|
|
829
868
|
// modify is never split (apply's `move ? op : op.clone(0, 1, keep)` evaluates the clone only when
|
|
830
869
|
// `keep` is true). Kept for the uniform children-op `clone` signature.
|
|
831
870
|
/* c8 ignore next */
|
|
832
|
-
|
|
871
|
+
const cpy = new ModifyOp(/** @type {DTypes} */ (markAsDone ? this.value.done() : this.value), _cloneAttrs(this.format), _cloneAttrs(this.attribution))
|
|
872
|
+
cpy._fingerprint = this._fingerprint
|
|
873
|
+
return cpy
|
|
833
874
|
}
|
|
834
875
|
}
|
|
835
876
|
|
|
@@ -916,10 +957,15 @@ export class SetAttrOp {
|
|
|
916
957
|
* Full (frozen) clone. A `move` apply reuses the source op instead of cloning, so there is no
|
|
917
958
|
* shared-mutable variant — see {@link DeltaBuilder#apply}.
|
|
918
959
|
*
|
|
919
|
-
* @
|
|
960
|
+
* @template {string|number} [K2=K]
|
|
961
|
+
* @param {K2} [key] retarget the clone to another attribute key (a transformer projecting or
|
|
962
|
+
* renaming an attribute); defaults to this op's key.
|
|
963
|
+
* @return {SetAttrOp<V,K2>}
|
|
920
964
|
*/
|
|
921
|
-
clone () {
|
|
922
|
-
|
|
965
|
+
clone (key = /** @type {any} */ (this.key)) {
|
|
966
|
+
const cpy = new SetAttrOp(key, _markMaybeDeltaAsDone(this.value), _cloneAttrs(this.attribution))
|
|
967
|
+
if (/** @type {string|number} */ (key) === this.key) cpy._fingerprint = this._fingerprint // the key is part of the fingerprint
|
|
968
|
+
return cpy
|
|
923
969
|
}
|
|
924
970
|
}
|
|
925
971
|
|
|
@@ -983,10 +1029,14 @@ export class DeleteAttrOp {
|
|
|
983
1029
|
/**
|
|
984
1030
|
* Full (frozen) clone; a `move` apply reuses the source op instead — see {@link DeltaBuilder#apply}.
|
|
985
1031
|
*
|
|
986
|
-
* @
|
|
1032
|
+
* @template {string|number} [K2=K]
|
|
1033
|
+
* @param {K2} [key] retarget the clone to another attribute key; defaults to this op's key.
|
|
1034
|
+
* @return {DeleteAttrOp<V,K2>}
|
|
987
1035
|
*/
|
|
988
|
-
clone () {
|
|
989
|
-
|
|
1036
|
+
clone (key = /** @type {any} */ (this.key)) {
|
|
1037
|
+
const cpy = new DeleteAttrOp(key, _cloneAttrs(this.attribution))
|
|
1038
|
+
if (/** @type {string|number} */ (key) === this.key) cpy._fingerprint = this._fingerprint // the key is part of the fingerprint
|
|
1039
|
+
return cpy
|
|
990
1040
|
}
|
|
991
1041
|
}
|
|
992
1042
|
|
|
@@ -1069,10 +1119,14 @@ export class ModifyAttrOp {
|
|
|
1069
1119
|
/**
|
|
1070
1120
|
* Full (frozen) clone; a `move` apply reuses the source op instead — see {@link DeltaBuilder#apply}.
|
|
1071
1121
|
*
|
|
1072
|
-
* @
|
|
1122
|
+
* @template {string|number} [K2=K]
|
|
1123
|
+
* @param {K2} [key] retarget the clone to another attribute key; defaults to this op's key.
|
|
1124
|
+
* @return {ModifyAttrOp<Modifier,K2>}
|
|
1073
1125
|
*/
|
|
1074
|
-
clone () {
|
|
1075
|
-
|
|
1126
|
+
clone (key = /** @type {any} */ (this.key)) {
|
|
1127
|
+
const cpy = new ModifyAttrOp(key, /** @type {Modifier} */ (this.value.done()), _cloneAttrs(this.attribution))
|
|
1128
|
+
if (/** @type {string|number} */ (key) === this.key) cpy._fingerprint = this._fingerprint // the key is part of the fingerprint
|
|
1129
|
+
return cpy
|
|
1076
1130
|
}
|
|
1077
1131
|
}
|
|
1078
1132
|
|
|
@@ -1443,8 +1497,13 @@ export class Delta extends DeltaData {
|
|
|
1443
1497
|
for (const key of keys) {
|
|
1444
1498
|
encoding.writeVarString(encoder, /** @type {any} */ (this.attrs[/** @type {keyof typeof this.attrs} */ (key)]).fingerprint)
|
|
1445
1499
|
}
|
|
1446
|
-
|
|
1447
|
-
|
|
1500
|
+
// trailing plain retains are not content: `done()` trims them, and the fingerprint must not
|
|
1501
|
+
// change when it does — so only the children up to the last content op are fingerprinted
|
|
1502
|
+
const cs = this.children
|
|
1503
|
+
let n = _contentLen(cs)
|
|
1504
|
+
encoding.writeVarUint(encoder, n)
|
|
1505
|
+
// non-null for the first `n` ops by construction (see _contentLen)
|
|
1506
|
+
for (let child = /** @type {ChildrenOpAny} */ (cs.start); n > 0; n--, child = /** @type {ChildrenOpAny} */ (child.next)) {
|
|
1448
1507
|
encoding.writeVarString(encoder, child.fingerprint)
|
|
1449
1508
|
}
|
|
1450
1509
|
}))))
|
|
@@ -1455,7 +1514,8 @@ export class Delta extends DeltaData {
|
|
|
1455
1514
|
}
|
|
1456
1515
|
|
|
1457
1516
|
isEmpty () {
|
|
1458
|
-
|
|
1517
|
+
// a children list holding only plain retains is empty (positional only — see _isPlainRetain)
|
|
1518
|
+
return object.isEmpty(this.attrs) && _contentLen(this.children) === 0 && (this.marks === null || this.marks.size === 0) && (this.deleteMarks === null || this.deleteMarks.size === 0)
|
|
1459
1519
|
}
|
|
1460
1520
|
|
|
1461
1521
|
/**
|
|
@@ -1500,10 +1560,20 @@ export class Delta extends DeltaData {
|
|
|
1500
1560
|
* @return {boolean}
|
|
1501
1561
|
*/
|
|
1502
1562
|
[equalityTrait.EqualityTraitSymbol] (other) {
|
|
1503
|
-
// @todo it is only necessary to compare finrerprints OR do a deep equality check (remove
|
|
1504
|
-
// childCnt as well)
|
|
1505
1563
|
// marks are local/ephemeral cursor state and intentionally NOT part of document identity
|
|
1506
|
-
|
|
1564
|
+
if (this.name !== other.name || !fun.equalityDeep(this.attrs, other.attrs)) return false
|
|
1565
|
+
// only the content ops count (a trailing plain-retain run is not content — see _isPlainRetain);
|
|
1566
|
+
// comparing the counts first also makes two retain-only lists equal. `childCnt` (Σ op.length)
|
|
1567
|
+
// needs no separate check: every content op's equality covers its length-bearing field.
|
|
1568
|
+
const n = _contentLen(this.children)
|
|
1569
|
+
if (n !== _contentLen(other.children)) return false
|
|
1570
|
+
// non-null for the first `n` ops by construction (see _contentLen)
|
|
1571
|
+
let a = /** @type {ChildrenOpAny} */ (this.children.start)
|
|
1572
|
+
let b = /** @type {ChildrenOpAny} */ (other.children.start)
|
|
1573
|
+
for (let i = 0; i < n; i++, a = /** @type {ChildrenOpAny} */ (a.next), b = /** @type {ChildrenOpAny} */ (b.next)) {
|
|
1574
|
+
if (!fun.equalityDeep(a, b)) return false
|
|
1575
|
+
}
|
|
1576
|
+
return true
|
|
1507
1577
|
}
|
|
1508
1578
|
|
|
1509
1579
|
// toString () {
|
|
@@ -1531,11 +1601,12 @@ export class Delta extends DeltaData {
|
|
|
1531
1601
|
done (markAsDone = true) {
|
|
1532
1602
|
if (!this.isDone) {
|
|
1533
1603
|
this.isDone = markAsDone
|
|
1604
|
+
// trim the trailing plain-retain run — fingerprint-neutral, as fingerprint/equality never counted
|
|
1605
|
+
// it (see _contentLen); any other cleanup added here must null `_fingerprint`
|
|
1534
1606
|
const cs = this.children
|
|
1535
|
-
for (let end = cs.end; end !== null &&
|
|
1607
|
+
for (let end = cs.end; end !== null && _isPlainRetain(end); end = cs.end) {
|
|
1536
1608
|
this.childCnt -= end.length
|
|
1537
1609
|
list.popEnd(cs)
|
|
1538
|
-
this._fingerprint = null
|
|
1539
1610
|
}
|
|
1540
1611
|
}
|
|
1541
1612
|
return this
|
|
@@ -1631,22 +1702,48 @@ export const clone = d => /** @type {any} */ (slice(d, 0, d.childCnt))
|
|
|
1631
1702
|
* @param {any} v
|
|
1632
1703
|
* @return {any}
|
|
1633
1704
|
*/
|
|
1634
|
-
const _cloneMaybeDeltaDeep = v => $deltaAny.check(v) ?
|
|
1705
|
+
const _cloneMaybeDeltaDeep = v => $deltaAny.check(v) ? _cloneDeepNested(v) : v
|
|
1706
|
+
|
|
1707
|
+
/**
|
|
1708
|
+
* Carry `src`'s cached fingerprint over to `cpy`, a content-identical copy of it. Only valid when
|
|
1709
|
+
* nothing about the copy differs from the source in fingerprinted fields (a full-range clone, the same
|
|
1710
|
+
* key, nested values cloned rather than `done()`-trimmed).
|
|
1711
|
+
*
|
|
1712
|
+
* @template {{ _fingerprint: string|null }} T
|
|
1713
|
+
* @param {{ _fingerprint: string|null }} src
|
|
1714
|
+
* @param {T} cpy
|
|
1715
|
+
* @return {T}
|
|
1716
|
+
*/
|
|
1717
|
+
const _copyFp = (src, cpy) => {
|
|
1718
|
+
cpy._fingerprint = src._fingerprint
|
|
1719
|
+
return cpy
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
/**
|
|
1723
|
+
* {@link cloneDeep} for a *nested* delta: content-identical, so the cached fingerprint rides along
|
|
1724
|
+
* (only the root returned by the exported `cloneDeep` starts without one).
|
|
1725
|
+
*
|
|
1726
|
+
* @template {DeltaConf} Conf
|
|
1727
|
+
* @param {Delta<Conf>} d
|
|
1728
|
+
* @return {DeltaBuilder<Conf>}
|
|
1729
|
+
*/
|
|
1730
|
+
const _cloneDeepNested = d => _copyFp(d, cloneDeep(d))
|
|
1635
1731
|
|
|
1636
1732
|
/**
|
|
1637
1733
|
* Deep-clone one content (child) op for {@link cloneDeep}: a fresh op whose nested deltas (an insert's
|
|
1638
1734
|
* delta content, a modify's value) are themselves deep-cloned. `format`/`attribution` objects are
|
|
1639
1735
|
* retained (shared) — they are always copied before being mutated (see {@link cloneDeep}). Ops without a
|
|
1640
|
-
* nested delta (`text`/`retain`/`delete`) use `op.clone()`.
|
|
1736
|
+
* nested delta (`text`/`retain`/`delete`) use `op.clone()`. Every copy is content-identical, so the
|
|
1737
|
+
* cached fingerprint is carried over.
|
|
1641
1738
|
*
|
|
1642
1739
|
* @param {ChildrenOpAny} op
|
|
1643
1740
|
* @return {ChildrenOpAny}
|
|
1644
1741
|
*/
|
|
1645
1742
|
const _cloneChildOpDeep = op =>
|
|
1646
1743
|
$insertOp.check(op)
|
|
1647
|
-
? new InsertOp(op.insert.map(_cloneMaybeDeltaDeep), op.format, op.attribution)
|
|
1744
|
+
? _copyFp(op, new InsertOp(op.insert.map(_cloneMaybeDeltaDeep), op.format, op.attribution))
|
|
1648
1745
|
: ($modifyOp.check(op)
|
|
1649
|
-
? new ModifyOp(
|
|
1746
|
+
? _copyFp(op, new ModifyOp(_cloneDeepNested(op.value), op.format, op.attribution))
|
|
1650
1747
|
: op.clone())
|
|
1651
1748
|
|
|
1652
1749
|
/**
|
|
@@ -1659,17 +1756,18 @@ const _cloneChildOpDeep = op =>
|
|
|
1659
1756
|
*/
|
|
1660
1757
|
const _cloneAttrOpDeep = op =>
|
|
1661
1758
|
$setAttrOp.check(op)
|
|
1662
|
-
? new SetAttrOp(op.key, _cloneMaybeDeltaDeep(op.value), op.attribution)
|
|
1759
|
+
? _copyFp(op, new SetAttrOp(op.key, _cloneMaybeDeltaDeep(op.value), op.attribution))
|
|
1663
1760
|
: ($modifyAttrOp.check(op)
|
|
1664
|
-
? new ModifyAttrOp(op.key,
|
|
1761
|
+
? _copyFp(op, new ModifyAttrOp(op.key, _cloneDeepNested(op.value), op.attribution))
|
|
1665
1762
|
// the only remaining attr op is a deleteAttr
|
|
1666
|
-
: new DeleteAttrOp(op.key, op.attribution))
|
|
1763
|
+
: _copyFp(op, new DeleteAttrOp(op.key, op.attribution)))
|
|
1667
1764
|
|
|
1668
1765
|
/**
|
|
1669
1766
|
* A **deep** clone of `d`: like {@link clone}, but every nested delta — an insert's delta content, a
|
|
1670
1767
|
* `modify`/`modifyAttr` value, a delta-valued attribute — is itself recursively cloned into a fresh,
|
|
1671
1768
|
* **mutable** node, instead of being frozen (`done`) and shared as {@link clone} does. The result and
|
|
1672
|
-
* its whole subtree are therefore independently editable.
|
|
1769
|
+
* its whole subtree are therefore independently editable. Cached fingerprints of the ops and nested
|
|
1770
|
+
* deltas ride along (they are content-identical); only the returned root starts without one.
|
|
1673
1771
|
*
|
|
1674
1772
|
* ## What is cloned, and when to reach for this
|
|
1675
1773
|
*
|
|
@@ -1773,7 +1871,7 @@ const modValue = op => {
|
|
|
1773
1871
|
* These are the ONLY sanctioned way to structurally edit `d.children` in place. Each keeps the cached
|
|
1774
1872
|
* invariant `d.childCnt === Σ op.length` correct and resets the op's `_fingerprint`. Never mutate
|
|
1775
1873
|
* `op.retain` / `op.delete` / `op.insert`, call `list.*`, or touch `d.childCnt` directly from outside
|
|
1776
|
-
* delta.js — go through these so the count (which `
|
|
1874
|
+
* delta.js — go through these so the count (which `slice`/`apply` position by) never drifts.
|
|
1777
1875
|
*
|
|
1778
1876
|
* Cursor pattern (used by {@link DeltaBuilder#apply}, {@link DeltaBuilder#rebase}, and
|
|
1779
1877
|
* `transformer/conform.js`): walk the target with `(op, offset)`; {@link _splitChildAt} before inserting
|
|
@@ -17,11 +17,9 @@ import { Transformer, Template, createTransformResult, attrsShapeOf } from './co
|
|
|
17
17
|
const attrTransformHelper = (outDelta, from, to, inDelta) => {
|
|
18
18
|
const attrOp = inDelta.attrs[from]
|
|
19
19
|
if (attrOp != null) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
// a mapped type over fixed conf keys, so
|
|
23
|
-
// @ts-ignore
|
|
24
|
-
c.key = to
|
|
20
|
+
// a clone retargeted to `to` (the clone skips the cached fingerprint, which covers the key)
|
|
21
|
+
const c = attrOp.clone(to)
|
|
22
|
+
// `attrs` is a mapped type over fixed conf keys, so the dynamic-key write needs the cast
|
|
25
23
|
const oattrs = /** @type {any} */ (outDelta.attrs)
|
|
26
24
|
oattrs[to] = c
|
|
27
25
|
}
|
|
@@ -21,12 +21,11 @@ const renameDeltaAttrs = (d, renames, revRenames) => {
|
|
|
21
21
|
const r = renames[key]
|
|
22
22
|
const rv = revRenames[key]
|
|
23
23
|
if (r != null) {
|
|
24
|
+
// a clone retargeted to `r` (the clone skips the cached fingerprint, which covers the key)
|
|
24
25
|
// @ts-ignore
|
|
25
|
-
forwardTransform.attrs[r] = attr
|
|
26
|
+
forwardTransform.attrs[r] = attr.clone(r)
|
|
26
27
|
// delete original
|
|
27
28
|
delete forwardTransform.attrs[key]
|
|
28
|
-
// @ts-ignore
|
|
29
|
-
attr.key = r
|
|
30
29
|
} else if (rv != null) {
|
|
31
30
|
// used in a rename, delete original
|
|
32
31
|
delete forwardTransform.attrs[key]
|