@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.
@@ -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
- if (local) {
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.handleInsertOp<SerializableTypeForSharedArray>(
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
- if (local) {
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
- if (local) {
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(_content: unknown): void {
833
- throw new Error("Not implemented");
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
  }
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/legacy-dds";
9
- export const pkgVersion = "2.52.0";
9
+ export const pkgVersion = "2.53.0";