@fluidframework/legacy-dds 2.52.0 → 2.53.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/dist/array/sharedArray.d.ts +6 -2
- package/dist/array/sharedArray.d.ts.map +1 -1
- package/dist/array/sharedArray.js +115 -73
- package/dist/array/sharedArray.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/lib/array/sharedArray.d.ts +6 -2
- package/lib/array/sharedArray.d.ts.map +1 -1
- package/lib/array/sharedArray.js +116 -74
- package/lib/array/sharedArray.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/package.json +15 -14
- package/src/array/sharedArray.ts +134 -90
- package/src/packageVersion.ts +1 -1
package/src/array/sharedArray.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { assert } from "@fluidframework/core-utils/internal";
|
|
6
|
+
import { assert, unreachableCase } from "@fluidframework/core-utils/internal";
|
|
7
7
|
import type {
|
|
8
8
|
Serializable,
|
|
9
9
|
IChannelAttributes,
|
|
@@ -480,8 +480,6 @@ export class SharedArrayClass<T extends SerializableTypeForSharedArray>
|
|
|
480
480
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
|
|
481
481
|
if (message.type === MessageType.Operation) {
|
|
482
482
|
const op = message.contents as ISharedArrayOperation<T>;
|
|
483
|
-
const opEntry = this.getEntryForId(op.entryId);
|
|
484
|
-
|
|
485
483
|
switch (op.type) {
|
|
486
484
|
case OperationType.insertEntry: {
|
|
487
485
|
this.handleInsertOp<SerializableTypeForSharedArray>(
|
|
@@ -490,84 +488,22 @@ export class SharedArrayClass<T extends SerializableTypeForSharedArray>
|
|
|
490
488
|
local,
|
|
491
489
|
op.value,
|
|
492
490
|
);
|
|
493
|
-
|
|
494
491
|
break;
|
|
495
492
|
}
|
|
496
|
-
|
|
497
493
|
case OperationType.deleteEntry: {
|
|
498
|
-
|
|
499
|
-
// Decrementing local pending counter as op is already applied to local state
|
|
500
|
-
opEntry.isLocalPendingDelete -= 1;
|
|
501
|
-
} else {
|
|
502
|
-
// If local pending, then ignore else apply the remote op
|
|
503
|
-
if (!this.isLocalPending(op.entryId, "isLocalPendingDelete")) {
|
|
504
|
-
// last element in skip list is the most recent and live entry, so marking it deleted
|
|
505
|
-
this.getLiveEntry(op.entryId).isDeleted = true;
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
|
|
494
|
+
this.handleDeleteOp(op, local);
|
|
509
495
|
break;
|
|
510
496
|
}
|
|
511
|
-
|
|
512
497
|
case OperationType.moveEntry: {
|
|
513
|
-
this.
|
|
514
|
-
op.changedToEntryId,
|
|
515
|
-
op.insertAfterEntryId,
|
|
516
|
-
local,
|
|
517
|
-
opEntry.value,
|
|
518
|
-
);
|
|
519
|
-
if (local) {
|
|
520
|
-
// decrement the local pending move op as its already applied to local state
|
|
521
|
-
opEntry.isLocalPendingMove -= 1;
|
|
522
|
-
} else {
|
|
523
|
-
const newElementEntryId = op.changedToEntryId;
|
|
524
|
-
const newElement = this.getEntryForId(newElementEntryId);
|
|
525
|
-
// If local pending then simply mark the new location dead as finally the local op will win
|
|
526
|
-
if (
|
|
527
|
-
this.isLocalPending(op.entryId, "isLocalPendingDelete") ||
|
|
528
|
-
this.isLocalPending(op.entryId, "isLocalPendingMove")
|
|
529
|
-
) {
|
|
530
|
-
this.updateDeadEntry(op.entryId, newElementEntryId);
|
|
531
|
-
} else {
|
|
532
|
-
// move the element
|
|
533
|
-
const liveEntry = this.getLiveEntry(op.entryId);
|
|
534
|
-
const isDeleted = liveEntry.isDeleted;
|
|
535
|
-
this.updateLiveEntry(liveEntry.entryId, newElementEntryId);
|
|
536
|
-
// mark newly added element as deleted if existing live element was already deleted
|
|
537
|
-
if (isDeleted) {
|
|
538
|
-
newElement.isDeleted = isDeleted;
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
}
|
|
498
|
+
this.handleMoveOp(op, local);
|
|
542
499
|
break;
|
|
543
500
|
}
|
|
544
|
-
|
|
545
501
|
case OperationType.toggle: {
|
|
546
|
-
|
|
547
|
-
// decrement the local pending delete op as its already applied to local state
|
|
548
|
-
if (opEntry.isLocalPendingDelete) {
|
|
549
|
-
opEntry.isLocalPendingDelete -= 1;
|
|
550
|
-
}
|
|
551
|
-
} else {
|
|
552
|
-
if (!this.isLocalPending(op.entryId, "isLocalPendingDelete")) {
|
|
553
|
-
this.getLiveEntry(op.entryId).isDeleted = op.isDeleted;
|
|
554
|
-
}
|
|
555
|
-
}
|
|
502
|
+
this.handleToggleOp(op, local);
|
|
556
503
|
break;
|
|
557
504
|
}
|
|
558
|
-
|
|
559
505
|
case OperationType.toggleMove: {
|
|
560
|
-
|
|
561
|
-
// decrement the local pending move op as its already applied to local state
|
|
562
|
-
if (opEntry.isLocalPendingMove) {
|
|
563
|
-
opEntry.isLocalPendingMove -= 1;
|
|
564
|
-
}
|
|
565
|
-
} else if (
|
|
566
|
-
!this.isLocalPending(op.entryId, "isLocalPendingDelete") &&
|
|
567
|
-
!this.isLocalPending(op.entryId, "isLocalPendingMove")
|
|
568
|
-
) {
|
|
569
|
-
this.updateLiveEntry(this.getLiveEntry(op.entryId).entryId, op.entryId);
|
|
570
|
-
}
|
|
506
|
+
this.handleToggleMoveOp(op, local);
|
|
571
507
|
break;
|
|
572
508
|
}
|
|
573
509
|
|
|
@@ -581,6 +517,101 @@ export class SharedArrayClass<T extends SerializableTypeForSharedArray>
|
|
|
581
517
|
}
|
|
582
518
|
}
|
|
583
519
|
|
|
520
|
+
private handleInsertOp<TWrite>(
|
|
521
|
+
entryId: string,
|
|
522
|
+
insertAfterEntryId: string | undefined,
|
|
523
|
+
local: boolean,
|
|
524
|
+
value: Serializable<TWrite> & T,
|
|
525
|
+
): void {
|
|
526
|
+
let index = 0;
|
|
527
|
+
if (local) {
|
|
528
|
+
this.getEntryForId(entryId).isAckPending = false;
|
|
529
|
+
} else {
|
|
530
|
+
if (insertAfterEntryId !== undefined) {
|
|
531
|
+
index = this.findIndexOfEntryId(insertAfterEntryId) + 1;
|
|
532
|
+
}
|
|
533
|
+
const newEntry = this.createNewEntry(entryId, value);
|
|
534
|
+
newEntry.isAckPending = false;
|
|
535
|
+
this.addEntry(this.getInternalInsertIndexByIgnoringLocalPendingInserts(index), newEntry);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
private handleDeleteOp(op: IDeleteOperation, local: boolean): void {
|
|
540
|
+
const opEntry = this.getEntryForId(op.entryId);
|
|
541
|
+
if (local) {
|
|
542
|
+
// Decrementing local pending counter as op is already applied to local state
|
|
543
|
+
opEntry.isLocalPendingDelete -= 1;
|
|
544
|
+
} else {
|
|
545
|
+
// If local pending, then ignore else apply the remote op
|
|
546
|
+
if (!this.isLocalPending(op.entryId, "isLocalPendingDelete")) {
|
|
547
|
+
// last element in skip list is the most recent and live entry, so marking it deleted
|
|
548
|
+
this.getLiveEntry(op.entryId).isDeleted = true;
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
private handleMoveOp(op: IMoveOperation, local: boolean): void {
|
|
554
|
+
const opEntry = this.getEntryForId(op.entryId);
|
|
555
|
+
this.handleInsertOp<SerializableTypeForSharedArray>(
|
|
556
|
+
op.changedToEntryId,
|
|
557
|
+
op.insertAfterEntryId,
|
|
558
|
+
local,
|
|
559
|
+
opEntry.value,
|
|
560
|
+
);
|
|
561
|
+
if (local) {
|
|
562
|
+
// decrement the local pending move op as its already applied to local state
|
|
563
|
+
opEntry.isLocalPendingMove -= 1;
|
|
564
|
+
} else {
|
|
565
|
+
const newElementEntryId = op.changedToEntryId;
|
|
566
|
+
const newElement = this.getEntryForId(newElementEntryId);
|
|
567
|
+
// If local pending then simply mark the new location dead as finally the local op will win
|
|
568
|
+
if (
|
|
569
|
+
this.isLocalPending(op.entryId, "isLocalPendingDelete") ||
|
|
570
|
+
this.isLocalPending(op.entryId, "isLocalPendingMove")
|
|
571
|
+
) {
|
|
572
|
+
this.updateDeadEntry(op.entryId, newElementEntryId);
|
|
573
|
+
} else {
|
|
574
|
+
// move the element
|
|
575
|
+
const liveEntry = this.getLiveEntry(op.entryId);
|
|
576
|
+
const isDeleted = liveEntry.isDeleted;
|
|
577
|
+
this.updateLiveEntry(liveEntry.entryId, newElementEntryId);
|
|
578
|
+
// mark newly added element as deleted if existing live element was already deleted
|
|
579
|
+
if (isDeleted) {
|
|
580
|
+
newElement.isDeleted = isDeleted;
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
private handleToggleOp(op: IToggleOperation, local: boolean): void {
|
|
587
|
+
const opEntry = this.getEntryForId(op.entryId);
|
|
588
|
+
if (local) {
|
|
589
|
+
// decrement the local pending delete op as its already applied to local state
|
|
590
|
+
if (opEntry.isLocalPendingDelete) {
|
|
591
|
+
opEntry.isLocalPendingDelete -= 1;
|
|
592
|
+
}
|
|
593
|
+
} else {
|
|
594
|
+
if (!this.isLocalPending(op.entryId, "isLocalPendingDelete")) {
|
|
595
|
+
this.getLiveEntry(op.entryId).isDeleted = op.isDeleted;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
private handleToggleMoveOp(op: IToggleMoveOperation, local: boolean): void {
|
|
601
|
+
const opEntry = this.getEntryForId(op.entryId);
|
|
602
|
+
if (local) {
|
|
603
|
+
// decrement the local pending move op as its already applied to local state
|
|
604
|
+
if (opEntry.isLocalPendingMove) {
|
|
605
|
+
opEntry.isLocalPendingMove -= 1;
|
|
606
|
+
}
|
|
607
|
+
} else if (
|
|
608
|
+
!this.isLocalPending(op.entryId, "isLocalPendingDelete") &&
|
|
609
|
+
!this.isLocalPending(op.entryId, "isLocalPendingMove")
|
|
610
|
+
) {
|
|
611
|
+
this.updateLiveEntry(this.getLiveEntry(op.entryId).entryId, op.entryId);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
|
|
584
615
|
private findInternalIndex(countEntries: number): number {
|
|
585
616
|
if (countEntries < 0) {
|
|
586
617
|
throw new Error("Input count is zero");
|
|
@@ -723,25 +754,6 @@ export class SharedArrayClass<T extends SerializableTypeForSharedArray>
|
|
|
723
754
|
return localOpsIterator;
|
|
724
755
|
}
|
|
725
756
|
|
|
726
|
-
private handleInsertOp<TWrite>(
|
|
727
|
-
entryId: string,
|
|
728
|
-
insertAfterEntryId: string | undefined,
|
|
729
|
-
local: boolean,
|
|
730
|
-
value: Serializable<TWrite> & T,
|
|
731
|
-
): void {
|
|
732
|
-
let index = 0;
|
|
733
|
-
if (local) {
|
|
734
|
-
this.getEntryForId(entryId).isAckPending = false;
|
|
735
|
-
} else {
|
|
736
|
-
if (insertAfterEntryId !== undefined) {
|
|
737
|
-
index = this.findIndexOfEntryId(insertAfterEntryId) + 1;
|
|
738
|
-
}
|
|
739
|
-
const newEntry = this.createNewEntry(entryId, value);
|
|
740
|
-
newEntry.isAckPending = false;
|
|
741
|
-
this.addEntry(this.getInternalInsertIndexByIgnoringLocalPendingInserts(index), newEntry);
|
|
742
|
-
}
|
|
743
|
-
}
|
|
744
|
-
|
|
745
757
|
private findIndexOfEntryId(entryId: string | undefined): number {
|
|
746
758
|
for (let index = 0; index < this.sharedArray.length; index = index + 1) {
|
|
747
759
|
if (this.sharedArray[index]?.entryId === entryId) {
|
|
@@ -829,7 +841,39 @@ export class SharedArrayClass<T extends SerializableTypeForSharedArray>
|
|
|
829
841
|
deadEntry.isDeleted = true;
|
|
830
842
|
}
|
|
831
843
|
|
|
832
|
-
protected applyStashedOp(
|
|
833
|
-
|
|
844
|
+
protected applyStashedOp(content: unknown): void {
|
|
845
|
+
const op = content as ISharedArrayOperation<T>;
|
|
846
|
+
|
|
847
|
+
switch (op.type) {
|
|
848
|
+
case OperationType.insertEntry: {
|
|
849
|
+
this.handleInsertOp<SerializableTypeForSharedArray>(
|
|
850
|
+
op.entryId,
|
|
851
|
+
op.insertAfterEntryId,
|
|
852
|
+
false, // treat it as remote op
|
|
853
|
+
op.value,
|
|
854
|
+
);
|
|
855
|
+
break;
|
|
856
|
+
}
|
|
857
|
+
case OperationType.deleteEntry: {
|
|
858
|
+
this.handleDeleteOp(op, false /* local - treat as remote op */);
|
|
859
|
+
break;
|
|
860
|
+
}
|
|
861
|
+
case OperationType.moveEntry: {
|
|
862
|
+
this.handleMoveOp(op, false /* local - treat as remote op */);
|
|
863
|
+
break;
|
|
864
|
+
}
|
|
865
|
+
case OperationType.toggle: {
|
|
866
|
+
this.handleToggleOp(op, false /* local - treat as remote op */);
|
|
867
|
+
break;
|
|
868
|
+
}
|
|
869
|
+
case OperationType.toggleMove: {
|
|
870
|
+
this.handleToggleMoveOp(op, false /* local - treat as remote op */);
|
|
871
|
+
break;
|
|
872
|
+
}
|
|
873
|
+
default: {
|
|
874
|
+
unreachableCase(op);
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
this.submitLocalMessage(op);
|
|
834
878
|
}
|
|
835
879
|
}
|
package/src/packageVersion.ts
CHANGED