@fluidframework/matrix 2.1.0-276985 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/.eslintrc.cjs +2 -5
  2. package/CHANGELOG.md +4 -0
  3. package/api-extractor/api-extractor.current.json +5 -0
  4. package/api-extractor/api-extractor.legacy.json +1 -1
  5. package/api-extractor.json +1 -1
  6. package/api-report/matrix.legacy.public.api.md +9 -0
  7. package/dist/handlecache.d.ts +7 -3
  8. package/dist/handlecache.d.ts.map +1 -1
  9. package/dist/handlecache.js +25 -7
  10. package/dist/handlecache.js.map +1 -1
  11. package/dist/handletable.d.ts +3 -1
  12. package/dist/handletable.d.ts.map +1 -1
  13. package/dist/handletable.js.map +1 -1
  14. package/dist/legacy.d.ts +1 -1
  15. package/dist/matrix.d.ts +2 -1
  16. package/dist/matrix.d.ts.map +1 -1
  17. package/dist/matrix.js +23 -9
  18. package/dist/matrix.js.map +1 -1
  19. package/dist/packageVersion.d.ts +1 -1
  20. package/dist/packageVersion.d.ts.map +1 -1
  21. package/dist/packageVersion.js +1 -1
  22. package/dist/packageVersion.js.map +1 -1
  23. package/dist/permutationvector.d.ts +5 -5
  24. package/dist/permutationvector.d.ts.map +1 -1
  25. package/dist/permutationvector.js +11 -4
  26. package/dist/permutationvector.js.map +1 -1
  27. package/dist/public.d.ts +1 -1
  28. package/dist/range.d.ts.map +1 -1
  29. package/dist/range.js.map +1 -1
  30. package/dist/runtime.d.ts.map +1 -1
  31. package/dist/runtime.js.map +1 -1
  32. package/dist/serialization.d.ts.map +1 -1
  33. package/dist/serialization.js.map +1 -1
  34. package/dist/sparsearray2d.d.ts +9 -5
  35. package/dist/sparsearray2d.d.ts.map +1 -1
  36. package/dist/sparsearray2d.js +27 -7
  37. package/dist/sparsearray2d.js.map +1 -1
  38. package/dist/undoprovider.d.ts.map +1 -1
  39. package/dist/undoprovider.js +10 -3
  40. package/dist/undoprovider.js.map +1 -1
  41. package/internal.d.ts +1 -1
  42. package/legacy.d.ts +1 -1
  43. package/lib/handlecache.d.ts +7 -3
  44. package/lib/handlecache.d.ts.map +1 -1
  45. package/lib/handlecache.js +25 -7
  46. package/lib/handlecache.js.map +1 -1
  47. package/lib/handletable.d.ts +3 -1
  48. package/lib/handletable.d.ts.map +1 -1
  49. package/lib/handletable.js.map +1 -1
  50. package/lib/legacy.d.ts +1 -1
  51. package/lib/matrix.d.ts +2 -1
  52. package/lib/matrix.d.ts.map +1 -1
  53. package/lib/matrix.js +23 -9
  54. package/lib/matrix.js.map +1 -1
  55. package/lib/packageVersion.d.ts +1 -1
  56. package/lib/packageVersion.d.ts.map +1 -1
  57. package/lib/packageVersion.js +1 -1
  58. package/lib/packageVersion.js.map +1 -1
  59. package/lib/permutationvector.d.ts +5 -5
  60. package/lib/permutationvector.d.ts.map +1 -1
  61. package/lib/permutationvector.js +11 -4
  62. package/lib/permutationvector.js.map +1 -1
  63. package/lib/public.d.ts +1 -1
  64. package/lib/range.d.ts.map +1 -1
  65. package/lib/range.js.map +1 -1
  66. package/lib/runtime.d.ts.map +1 -1
  67. package/lib/runtime.js.map +1 -1
  68. package/lib/serialization.d.ts.map +1 -1
  69. package/lib/serialization.js.map +1 -1
  70. package/lib/sparsearray2d.d.ts +9 -5
  71. package/lib/sparsearray2d.d.ts.map +1 -1
  72. package/lib/sparsearray2d.js +27 -7
  73. package/lib/sparsearray2d.js.map +1 -1
  74. package/lib/undoprovider.d.ts.map +1 -1
  75. package/lib/undoprovider.js +10 -3
  76. package/lib/undoprovider.js.map +1 -1
  77. package/package.json +36 -30
  78. package/src/handlecache.ts +31 -16
  79. package/src/handletable.ts +11 -9
  80. package/src/matrix.ts +80 -50
  81. package/src/packageVersion.ts +1 -1
  82. package/src/permutationvector.ts +38 -23
  83. package/src/range.ts +1 -1
  84. package/src/runtime.ts +5 -2
  85. package/src/serialization.ts +4 -2
  86. package/src/sparsearray2d.ts +55 -36
  87. package/src/undoprovider.ts +26 -18
  88. package/tsconfig.json +0 -1
package/src/matrix.ts CHANGED
@@ -46,6 +46,7 @@ import {
46
46
  } from "@tiny-calc/nano";
47
47
  import Deque from "double-ended-queue";
48
48
 
49
+ import type { HandleCache } from "./handlecache.js";
49
50
  import { Handle, isHandleValid } from "./handletable.js";
50
51
  import {
51
52
  ISetOp,
@@ -58,7 +59,7 @@ import {
58
59
  import { PermutationVector, reinsertSegmentIntoVector } from "./permutationvector.js";
59
60
  import { ensureRange } from "./range.js";
60
61
  import { deserializeBlob } from "./serialization.js";
61
- import { SparseArray2D } from "./sparsearray2d.js";
62
+ import { SparseArray2D, type RecurArray } from "./sparsearray2d.js";
62
63
  import { IUndoConsumer } from "./types.js";
63
64
  import { MatrixUndoProvider } from "./undoprovider.js";
64
65
 
@@ -120,6 +121,9 @@ interface CellLastWriteTrackerItem {
120
121
  * @legacy
121
122
  * @alpha
122
123
  */
124
+ // Changing this to `unknown` would be a breaking change.
125
+ // TODO: if possible, transition ISharedMatrix to not use `any`.
126
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
123
127
  export interface ISharedMatrix<T = any>
124
128
  extends IEventProvider<ISharedMatrixEvents<T>>,
125
129
  IMatrixProducer<MatrixItem<T>>,
@@ -215,6 +219,9 @@ export interface ISharedMatrix<T = any>
215
219
  * @legacy
216
220
  * @alpha
217
221
  */
222
+ // Changing this to `unknown` would be a breaking change.
223
+ // TODO: if possible, transition SharedMatrix to not use `any`.
224
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
218
225
  export class SharedMatrix<T = any>
219
226
  extends SharedObject<ISharedMatrixEvents<T> & ISharedObjectEvents>
220
227
  implements ISharedMatrix<T>
@@ -231,6 +238,7 @@ export class SharedMatrix<T = any>
231
238
  * on the SharedMatrix op is 11.
232
239
  */
233
240
  private readonly inFlightRefSeqs = new Deque<number>();
241
+ readonly getMinInFlightRefSeq = (): number | undefined => this.inFlightRefSeqs.get(0);
234
242
 
235
243
  private readonly rows: PermutationVector; // Map logical row to storage handle (if any)
236
244
  private readonly cols: PermutationVector; // Map logical col to storage handle (if any)
@@ -261,14 +269,13 @@ export class SharedMatrix<T = any>
261
269
  super(id, runtime, attributes, "fluid_matrix_");
262
270
 
263
271
  this.setCellLwwToFwwPolicySwitchOpSeqNumber = -1;
264
- const getMinInFlightRefSeq = () => this.inFlightRefSeqs.get(0);
265
272
  this.rows = new PermutationVector(
266
273
  SnapshotPath.rows,
267
274
  this.logger,
268
275
  runtime,
269
276
  this.onRowDelta,
270
277
  this.onRowHandlesRecycled,
271
- getMinInFlightRefSeq,
278
+ this.getMinInFlightRefSeq,
272
279
  );
273
280
 
274
281
  this.cols = new PermutationVector(
@@ -277,7 +284,7 @@ export class SharedMatrix<T = any>
277
284
  runtime,
278
285
  this.onColDelta,
279
286
  this.onColHandlesRecycled,
280
- getMinInFlightRefSeq,
287
+ this.getMinInFlightRefSeq,
281
288
  );
282
289
  }
283
290
 
@@ -286,7 +293,7 @@ export class SharedMatrix<T = any>
286
293
  /**
287
294
  * Subscribes the given IUndoConsumer to the matrix.
288
295
  */
289
- public openUndo(consumer: IUndoConsumer) {
296
+ public openUndo(consumer: IUndoConsumer): void {
290
297
  assert(
291
298
  this.undo === undefined,
292
299
  0x019 /* "SharedMatrix.openUndo() supports at most a single IUndoConsumer." */,
@@ -297,10 +304,10 @@ export class SharedMatrix<T = any>
297
304
 
298
305
  // TODO: closeUndo()?
299
306
 
300
- private get rowHandles() {
307
+ private get rowHandles(): HandleCache {
301
308
  return this.rows.handleCache;
302
309
  }
303
- private get colHandles() {
310
+ private get colHandles(): HandleCache {
304
311
  return this.cols.handleCache;
305
312
  }
306
313
 
@@ -319,14 +326,14 @@ export class SharedMatrix<T = any>
319
326
 
320
327
  // #region IMatrixReader
321
328
 
322
- public get rowCount() {
329
+ public get rowCount(): number {
323
330
  return this.rows.getLength();
324
331
  }
325
- public get colCount() {
332
+ public get colCount(): number {
326
333
  return this.cols.getLength();
327
334
  }
328
335
 
329
- public isSetCellConflictResolutionPolicyFWW() {
336
+ public isSetCellConflictResolutionPolicyFWW(): boolean {
330
337
  return this.setCellLwwToFwwPolicySwitchOpSeqNumber > -1 || this.userSwitchedSetCellPolicy;
331
338
  }
332
339
 
@@ -357,7 +364,7 @@ export class SharedMatrix<T = any>
357
364
 
358
365
  // #endregion IMatrixReader
359
366
 
360
- public setCell(row: number, col: number, value: MatrixItem<T>) {
367
+ public setCell(row: number, col: number, value: MatrixItem<T>): void {
361
368
  if (row < 0 || row >= this.rowCount || col < 0 || col >= this.colCount) {
362
369
  throw new UsageError("Trying to set out-of-bounds cell.");
363
370
  }
@@ -370,7 +377,7 @@ export class SharedMatrix<T = any>
370
377
  colStart: number,
371
378
  colCount: number,
372
379
  values: readonly MatrixItem<T>[],
373
- ) {
380
+ ): void {
374
381
  const rowCount = Math.ceil(values.length / colCount);
375
382
 
376
383
  assert(
@@ -404,7 +411,7 @@ export class SharedMatrix<T = any>
404
411
  value: MatrixItem<T>,
405
412
  rowHandle = this.rows.getAllocatedHandle(row),
406
413
  colHandle = this.cols.getAllocatedHandle(col),
407
- ) {
414
+ ): void {
408
415
  this.protectAgainstReentrancy(() => {
409
416
  if (this.undo !== undefined) {
410
417
  let oldValue = this.cells.getCell(rowHandle, colHandle);
@@ -428,7 +435,11 @@ export class SharedMatrix<T = any>
428
435
  });
429
436
  }
430
437
 
431
- private createOpMetadataLocalRef(vector: PermutationVector, pos: number, localSeq: number) {
438
+ private createOpMetadataLocalRef(
439
+ vector: PermutationVector,
440
+ pos: number,
441
+ localSeq: number,
442
+ ): LocalReferencePosition {
432
443
  const segoff = vector.getContainingSegment(pos, undefined, localSeq);
433
444
  assert(
434
445
  segoff.segment !== undefined && segoff.offset !== undefined,
@@ -449,7 +460,7 @@ export class SharedMatrix<T = any>
449
460
  rowHandle: Handle,
450
461
  colHandle: Handle,
451
462
  localSeq = this.nextLocalSeq(),
452
- ) {
463
+ ): void {
453
464
  assert(
454
465
  this.isAttached(),
455
466
  0x1e2 /* "Caller must ensure 'isAttached()' before calling 'sendSetCellOp'." */,
@@ -487,7 +498,7 @@ export class SharedMatrix<T = any>
487
498
  * a deleted row/col.
488
499
  * @param callback - code that needs to protected against reentrancy.
489
500
  */
490
- private protectAgainstReentrancy(callback: () => void) {
501
+ private protectAgainstReentrancy(callback: () => void): void {
491
502
  if (this.reentrantCount !== 0) {
492
503
  // Validate that applications don't submit edits in response to matrix change notifications. This is unsupported.
493
504
  throw new UsageError("Reentrancy detected in SharedMatrix.");
@@ -509,7 +520,7 @@ export class SharedMatrix<T = any>
509
520
  oppositeVector: PermutationVector,
510
521
  target: SnapshotPath.rows | SnapshotPath.cols,
511
522
  message: IMergeTreeOp,
512
- ) {
523
+ ): void {
513
524
  // Ideally, we would have a single 'localSeq' counter that is shared between both PermutationVectors
514
525
  // and the SharedMatrix's cell data. Instead, we externally advance each MergeTree's 'localSeq' counter
515
526
  // for each submitted op it not aware of to keep them synchronized.
@@ -540,11 +551,11 @@ export class SharedMatrix<T = any>
540
551
  }
541
552
  }
542
553
 
543
- private submitColMessage(message: IMergeTreeOp) {
554
+ private submitColMessage(message: IMergeTreeOp): void {
544
555
  this.submitVectorMessage(this.cols, this.rows, SnapshotPath.cols, message);
545
556
  }
546
557
 
547
- public insertCols(colStart: number, count: number) {
558
+ public insertCols(colStart: number, count: number): void {
548
559
  if (count === 0) {
549
560
  return;
550
561
  }
@@ -558,7 +569,7 @@ export class SharedMatrix<T = any>
558
569
  });
559
570
  }
560
571
 
561
- public removeCols(colStart: number, count: number) {
572
+ public removeCols(colStart: number, count: number): void {
562
573
  if (count === 0) {
563
574
  return;
564
575
  }
@@ -570,11 +581,11 @@ export class SharedMatrix<T = any>
570
581
  );
571
582
  }
572
583
 
573
- private submitRowMessage(message: IMergeTreeOp) {
584
+ private submitRowMessage(message: IMergeTreeOp): void {
574
585
  this.submitVectorMessage(this.rows, this.cols, SnapshotPath.rows, message);
575
586
  }
576
587
 
577
- public insertRows(rowStart: number, count: number) {
588
+ public insertRows(rowStart: number, count: number): void {
578
589
  if (count === 0) {
579
590
  return;
580
591
  }
@@ -588,7 +599,7 @@ export class SharedMatrix<T = any>
588
599
  });
589
600
  }
590
601
 
591
- public removeRows(rowStart: number, count: number) {
602
+ public removeRows(rowStart: number, count: number): void {
592
603
  if (count === 0) {
593
604
  return;
594
605
  }
@@ -600,7 +611,7 @@ export class SharedMatrix<T = any>
600
611
  );
601
612
  }
602
613
 
603
- public _undoRemoveRows(rowStart: number, spec: IJSONSegment) {
614
+ public _undoRemoveRows(rowStart: number, spec: IJSONSegment): void {
604
615
  const { op, inserted } = reinsertSegmentIntoVector(this.rows, rowStart, spec);
605
616
  assert(op !== undefined, 0x8b6 /* must be defined */);
606
617
  this.submitRowMessage(op);
@@ -610,7 +621,9 @@ export class SharedMatrix<T = any>
610
621
  const rowCount = inserted.cachedLength;
611
622
  for (let row = rowStart; row < rowStart + rowCount; row++, rowHandle++) {
612
623
  for (let col = 0; col < this.colCount; col++) {
613
- const colHandle = this.colHandles.getHandle(col);
624
+ // TODO Non null asserting, why is this not null?
625
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
626
+ const colHandle = this.colHandles.getHandle(col)!;
614
627
  const value = this.cells.getCell(rowHandle, colHandle);
615
628
  if (this.isAttached() && value !== undefined && value !== null) {
616
629
  this.sendSetCellOp(row, col, value, rowHandle, colHandle);
@@ -624,7 +637,7 @@ export class SharedMatrix<T = any>
624
637
  }
625
638
  }
626
639
 
627
- /***/ public _undoRemoveCols(colStart: number, spec: IJSONSegment) {
640
+ /***/ public _undoRemoveCols(colStart: number, spec: IJSONSegment): void {
628
641
  const { op, inserted } = reinsertSegmentIntoVector(this.cols, colStart, spec);
629
642
  assert(op !== undefined, 0x8b7 /* must be defined */);
630
643
  this.submitColMessage(op);
@@ -634,7 +647,9 @@ export class SharedMatrix<T = any>
634
647
  const colCount = inserted.cachedLength;
635
648
  for (let col = colStart; col < colStart + colCount; col++, colHandle++) {
636
649
  for (let row = 0; row < this.rowCount; row++) {
637
- const rowHandle = this.rowHandles.getHandle(row);
650
+ // TODO Non null asserting, why is this not null?
651
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
652
+ const rowHandle = this.rowHandles.getHandle(row)!;
638
653
  const value = this.cells.getCell(rowHandle, colHandle);
639
654
  if (this.isAttached() && value !== undefined && value !== null) {
640
655
  this.sendSetCellOp(row, col, value, rowHandle, colHandle);
@@ -679,7 +694,7 @@ export class SharedMatrix<T = any>
679
694
  * Runs serializer on the GC data for this SharedMatrix.
680
695
  * All the IFluidHandle's stored in the cells represent routes to other objects.
681
696
  */
682
- protected processGCDataCore(serializer: IFluidSerializer) {
697
+ protected processGCDataCore(serializer: IFluidSerializer): void {
683
698
  for (let row = 0; row < this.rowCount; row++) {
684
699
  for (let col = 0; col < this.colCount; col++) {
685
700
  serializer.stringify(this.getCell(row, col), this.handle);
@@ -693,7 +708,7 @@ export class SharedMatrix<T = any>
693
708
  * Do not use with 'submitColMessage()/submitRowMessage()' as these helpers + the MergeTree will
694
709
  * automatically advance 'localSeq'.
695
710
  */
696
- private nextLocalSeq() {
711
+ private nextLocalSeq(): number {
697
712
  // Ideally, we would have a single 'localSeq' counter that is shared between both PermutationVectors
698
713
  // and the SharedMatrix's cell data. Instead, we externally bump each MergeTree's 'localSeq' counter
699
714
  // for SharedMatrix ops it's not aware of to keep them synchronized. (For cell data operations, we
@@ -703,7 +718,7 @@ export class SharedMatrix<T = any>
703
718
  return ++this.rows.getCollabWindow().localSeq;
704
719
  }
705
720
 
706
- protected submitLocalMessage(message: any, localOpMetadata?: any) {
721
+ protected submitLocalMessage(message: unknown, localOpMetadata?: unknown): void {
707
722
  // TODO: Recommend moving this assertion into SharedObject
708
723
  // (See https://github.com/microsoft/FluidFramework/issues/2559)
709
724
  assert(
@@ -721,7 +736,7 @@ export class SharedMatrix<T = any>
721
736
  );
722
737
  }
723
738
 
724
- protected didAttach() {
739
+ protected didAttach(): void {
725
740
  // We've attached we need to start generating and sending ops.
726
741
  // so start collaboration and provide a default client id incase we are not connected
727
742
  if (this.isAttached()) {
@@ -730,7 +745,7 @@ export class SharedMatrix<T = any>
730
745
  }
731
746
  }
732
747
 
733
- protected onConnect() {
748
+ protected onConnect(): void {
734
749
  assert(
735
750
  this.rows.getCollabWindow().collaborating === this.cols.getCollabWindow().collaborating,
736
751
  0x01f /* "Row and col collab window 'collaborating' status desynchronized!" */,
@@ -763,7 +778,7 @@ export class SharedMatrix<T = any>
763
778
  return client.findReconnectionPosition(segment, localSeq) + offset;
764
779
  }
765
780
 
766
- protected reSubmitCore(incoming: unknown, localOpMetadata: unknown) {
781
+ protected reSubmitCore(incoming: unknown, localOpMetadata: unknown): void {
767
782
  const originalRefSeq = this.inFlightRefSeqs.shift();
768
783
  assert(
769
784
  originalRefSeq !== undefined,
@@ -805,7 +820,7 @@ export class SharedMatrix<T = any>
805
820
  }
806
821
  } else {
807
822
  switch (content.target) {
808
- case SnapshotPath.cols:
823
+ case SnapshotPath.cols: {
809
824
  this.submitColMessage(
810
825
  this.cols.regeneratePendingOp(
811
826
  content,
@@ -814,7 +829,8 @@ export class SharedMatrix<T = any>
814
829
  ),
815
830
  );
816
831
  break;
817
- case SnapshotPath.rows:
832
+ }
833
+ case SnapshotPath.rows: {
818
834
  this.submitRowMessage(
819
835
  this.rows.regeneratePendingOp(
820
836
  content,
@@ -823,6 +839,7 @@ export class SharedMatrix<T = any>
823
839
  ),
824
840
  );
825
841
  break;
842
+ }
826
843
  default: {
827
844
  unreachableCase(content);
828
845
  }
@@ -830,12 +847,12 @@ export class SharedMatrix<T = any>
830
847
  }
831
848
  }
832
849
 
833
- protected onDisconnect() {}
850
+ protected onDisconnect(): void {}
834
851
 
835
852
  /**
836
853
  * {@inheritDoc @fluidframework/shared-object-base#SharedObject.loadCore}
837
854
  */
838
- protected async loadCore(storage: IChannelStorageService) {
855
+ protected async loadCore(storage: IChannelStorageService): Promise<void> {
839
856
  try {
840
857
  await this.rows.load(
841
858
  this.runtime,
@@ -852,7 +869,13 @@ export class SharedMatrix<T = any>
852
869
  _pendingCliSeqData,
853
870
  setCellLwwToFwwPolicySwitchOpSeqNumber,
854
871
  cellLastWriteTracker,
855
- ] = await deserializeBlob(storage, SnapshotPath.cells, this.serializer);
872
+ // Cast is needed since the (de)serializer returns content of type `any`.
873
+ ] = (await deserializeBlob(storage, SnapshotPath.cells, this.serializer)) as [
874
+ RecurArray<MatrixItem<T>>,
875
+ unknown,
876
+ number,
877
+ RecurArray<CellLastWriteTrackerItem>,
878
+ ];
856
879
 
857
880
  this.cells = SparseArray2D.load(cellData);
858
881
  this.setCellLwwToFwwPolicySwitchOpSeqNumber =
@@ -873,7 +896,7 @@ export class SharedMatrix<T = any>
873
896
  rowHandle: Handle,
874
897
  colHandle: Handle,
875
898
  message: ISequencedDocumentMessage,
876
- ) {
899
+ ): boolean {
877
900
  assert(
878
901
  this.setCellLwwToFwwPolicySwitchOpSeqNumber > -1,
879
902
  0x85f /* should be in Fww mode when calling this method */,
@@ -896,7 +919,7 @@ export class SharedMatrix<T = any>
896
919
  msg: ISequencedDocumentMessage,
897
920
  local: boolean,
898
921
  localOpMetadata: unknown,
899
- ) {
922
+ ): void {
900
923
  if (local) {
901
924
  const recordedRefSeq = this.inFlightRefSeqs.shift();
902
925
  assert(recordedRefSeq !== undefined, 0x8ba /* No pending recorded refSeq found */);
@@ -913,12 +936,14 @@ export class SharedMatrix<T = any>
913
936
  const target = contents.target;
914
937
 
915
938
  switch (target) {
916
- case SnapshotPath.cols:
939
+ case SnapshotPath.cols: {
917
940
  this.cols.applyMsg(msg, local);
918
941
  break;
919
- case SnapshotPath.rows:
942
+ }
943
+ case SnapshotPath.rows: {
920
944
  this.rows.applyMsg(msg, local);
921
945
  break;
946
+ }
922
947
  case undefined: {
923
948
  assert(
924
949
  contents.type === MatrixOp.set,
@@ -1018,8 +1043,9 @@ export class SharedMatrix<T = any>
1018
1043
  }
1019
1044
  break;
1020
1045
  }
1021
- default:
1046
+ default: {
1022
1047
  unreachableCase(target, "unknown target");
1048
+ }
1023
1049
  }
1024
1050
  }
1025
1051
 
@@ -1028,7 +1054,7 @@ export class SharedMatrix<T = any>
1028
1054
  position: number,
1029
1055
  removedCount: number,
1030
1056
  insertedCount: number,
1031
- ) => {
1057
+ ): void => {
1032
1058
  for (const consumer of this.consumers) {
1033
1059
  consumer.rowsChanged(position, removedCount, insertedCount, this);
1034
1060
  }
@@ -1039,13 +1065,13 @@ export class SharedMatrix<T = any>
1039
1065
  position: number,
1040
1066
  removedCount: number,
1041
1067
  insertedCount: number,
1042
- ) => {
1068
+ ): void => {
1043
1069
  for (const consumer of this.consumers) {
1044
1070
  consumer.colsChanged(position, removedCount, insertedCount, this);
1045
1071
  }
1046
1072
  };
1047
1073
 
1048
- private readonly onRowHandlesRecycled = (rowHandles: Handle[]) => {
1074
+ private readonly onRowHandlesRecycled = (rowHandles: Handle[]): void => {
1049
1075
  for (const rowHandle of rowHandles) {
1050
1076
  this.cells.clearRows(/* rowStart: */ rowHandle, /* rowCount: */ 1);
1051
1077
  this.pending.clearRows(/* rowStart: */ rowHandle, /* rowCount: */ 1);
@@ -1053,7 +1079,7 @@ export class SharedMatrix<T = any>
1053
1079
  }
1054
1080
  };
1055
1081
 
1056
- private readonly onColHandlesRecycled = (colHandles: Handle[]) => {
1082
+ private readonly onColHandlesRecycled = (colHandles: Handle[]): void => {
1057
1083
  for (const colHandle of colHandles) {
1058
1084
  this.cells.clearCols(/* colStart: */ colHandle, /* colCount: */ 1);
1059
1085
  this.pending.clearCols(/* colStart: */ colHandle, /* colCount: */ 1);
@@ -1061,7 +1087,7 @@ export class SharedMatrix<T = any>
1061
1087
  }
1062
1088
  };
1063
1089
 
1064
- public switchSetCellPolicy() {
1090
+ public switchSetCellPolicy(): void {
1065
1091
  if (this.setCellLwwToFwwPolicySwitchOpSeqNumber === -1) {
1066
1092
  if (this.isAttached()) {
1067
1093
  this.userSwitchedSetCellPolicy = true;
@@ -1079,7 +1105,11 @@ export class SharedMatrix<T = any>
1079
1105
  * clobber the write op at the given 'localSeq'. This includes later ops that overwrite the cell
1080
1106
  * with a different value as well as row/col removals that might recycled the given row/col handles.
1081
1107
  */
1082
- private isLatestPendingWrite(rowHandle: Handle, colHandle: Handle, localSeq: number) {
1108
+ private isLatestPendingWrite(
1109
+ rowHandle: Handle,
1110
+ colHandle: Handle,
1111
+ localSeq: number,
1112
+ ): boolean {
1083
1113
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
1084
1114
  const pendingLocalSeq = this.pending.getCell(rowHandle, colHandle)!;
1085
1115
 
@@ -1096,7 +1126,7 @@ export class SharedMatrix<T = any>
1096
1126
  return pendingLocalSeq === localSeq;
1097
1127
  }
1098
1128
 
1099
- public toString() {
1129
+ public toString(): string {
1100
1130
  let s = `client:${
1101
1131
  this.runtime.clientId
1102
1132
  }\nrows: ${this.rows.toString()}\ncols: ${this.cols.toString()}\n\n`;
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/matrix";
9
- export const pkgVersion = "2.1.0-276985";
9
+ export const pkgVersion = "2.1.0";
@@ -20,6 +20,8 @@ import {
20
20
  ISegment,
21
21
  MergeTreeDeltaType,
22
22
  MergeTreeMaintenanceType,
23
+ type IMergeTreeInsertMsg,
24
+ type IMergeTreeRemoveMsg,
23
25
  } from "@fluidframework/merge-tree/internal";
24
26
  import { ISummaryTreeWithStats } from "@fluidframework/runtime-definitions/internal";
25
27
  import {
@@ -45,7 +47,7 @@ export class PermutationSegment extends BaseSegment {
45
47
  public static readonly typeString: string = "PermutationSegment";
46
48
  private _start = Handle.unallocated;
47
49
 
48
- public static fromJSONObject(spec: any) {
50
+ public static fromJSONObject(spec: IJSONSegment): PermutationSegment {
49
51
  const [length, start] = spec as PermutationSegmentSpec;
50
52
  return new PermutationSegment(length, start);
51
53
  }
@@ -58,7 +60,7 @@ export class PermutationSegment extends BaseSegment {
58
60
  this.cachedLength = length;
59
61
  }
60
62
 
61
- public get start() {
63
+ public get start(): Handle {
62
64
  return this._start;
63
65
  }
64
66
  public set start(value: Handle) {
@@ -74,15 +76,15 @@ export class PermutationSegment extends BaseSegment {
74
76
  this._start = value;
75
77
  }
76
78
 
77
- public reset() {
79
+ public reset(): void {
78
80
  this._start = Handle.unallocated;
79
81
  }
80
82
 
81
- public toJSONObject() {
83
+ public toJSONObject(): number[] {
82
84
  return [this.cachedLength, this.start];
83
85
  }
84
86
 
85
- public clone(start = 0, end = this.cachedLength) {
87
+ public clone(start = 0, end = this.cachedLength): PermutationSegment {
86
88
  const b = new PermutationSegment(
87
89
  /* length: */ end - start,
88
90
  /* start: */ this.start + start,
@@ -91,7 +93,7 @@ export class PermutationSegment extends BaseSegment {
91
93
  return b;
92
94
  }
93
95
 
94
- public canAppend(segment: ISegment) {
96
+ public canAppend(segment: ISegment): boolean {
95
97
  const asPerm = segment as PermutationSegment;
96
98
 
97
99
  return this.start === Handle.unallocated
@@ -99,7 +101,7 @@ export class PermutationSegment extends BaseSegment {
99
101
  : asPerm.start === this.start + this.cachedLength;
100
102
  }
101
103
 
102
- protected createSplitSegmentAt(pos: number) {
104
+ protected createSplitSegmentAt(pos: number): PermutationSegment {
103
105
  assert(
104
106
  0 < pos && pos < this.cachedLength,
105
107
  0x026 /* "Trying to split segment at out-of-bounds position!" */,
@@ -115,7 +117,7 @@ export class PermutationSegment extends BaseSegment {
115
117
  return leafSegment;
116
118
  }
117
119
 
118
- public toString() {
120
+ public toString(): string {
119
121
  return this.start === Handle.unallocated
120
122
  ? `<${this.cachedLength} empty>`
121
123
  : `<${this.cachedLength}: ${this.start}..${this.start + this.cachedLength - 1}>`;
@@ -154,11 +156,11 @@ export class PermutationVector extends Client {
154
156
  this.on("maintenance", this.onMaintenance);
155
157
  }
156
158
 
157
- public insert(start: number, length: number) {
159
+ public insert(start: number, length: number): IMergeTreeInsertMsg | undefined {
158
160
  return this.insertSegmentLocal(start, new PermutationSegment(length));
159
161
  }
160
162
 
161
- public remove(start: number, length: number) {
163
+ public remove(start: number, length: number): IMergeTreeRemoveMsg {
162
164
  return this.removeRangeLocal(start, start + length);
163
165
  }
164
166
 
@@ -168,7 +170,9 @@ export class PermutationVector extends Client {
168
170
  0x027 /* "Trying to get handle of out-of-bounds position!" */,
169
171
  );
170
172
 
171
- return this.handleCache.getHandle(pos);
173
+ // TODO Non null asserting, why is this not null?
174
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
175
+ return this.handleCache.getHandle(pos)!;
172
176
  }
173
177
 
174
178
  public getAllocatedHandle(pos: number): Handle {
@@ -197,7 +201,7 @@ export class PermutationVector extends Client {
197
201
  public adjustPosition(
198
202
  pos: number,
199
203
  op: Pick<ISequencedDocumentMessage, "referenceSequenceNumber" | "clientId">,
200
- ) {
204
+ ): number | undefined {
201
205
  const { segment, offset } = this.getContainingSegment(pos, {
202
206
  referenceSequenceNumber: op.referenceSequenceNumber,
203
207
  clientId: op.clientId,
@@ -214,7 +218,7 @@ export class PermutationVector extends Client {
214
218
  return this.getPosition(segment) + offset!;
215
219
  }
216
220
 
217
- public handleToPosition(handle: Handle, localSeq = this.getCollabWindow().localSeq) {
221
+ public handleToPosition(handle: Handle, localSeq = this.getCollabWindow().localSeq): number {
218
222
  assert(
219
223
  localSeq <= this.getCollabWindow().localSeq,
220
224
  0x028 /* "'localSeq' for op being resubmitted must be <= the 'localSeq' of the last submitted op." */,
@@ -296,12 +300,15 @@ export class PermutationVector extends Client {
296
300
  runtime: IFluidDataStoreRuntime,
297
301
  storage: IChannelStorageService,
298
302
  serializer: IFluidSerializer,
299
- ) {
300
- const handleTableData = await deserializeBlob(
303
+ ): Promise<{
304
+ catchupOpsP: Promise<ISequencedDocumentMessage[]>;
305
+ }> {
306
+ const handleTableData = (await deserializeBlob(
301
307
  storage,
302
308
  SnapshotPath.handleTable,
303
309
  serializer,
304
- );
310
+ // Cast is needed since the (de)serializer returns content of type `any`.
311
+ )) as Handle[];
305
312
 
306
313
  this.handleTable = HandleTable.load<never>(handleTableData);
307
314
 
@@ -315,7 +322,7 @@ export class PermutationVector extends Client {
315
322
  private readonly onDelta = (
316
323
  opArgs: IMergeTreeDeltaOpArgs,
317
324
  deltaArgs: IMergeTreeDeltaCallbackArgs,
318
- ) => {
325
+ ): void => {
319
326
  // Apply deltas in descending order to prevent positions from shifting.
320
327
  const ranges = deltaArgs.deltaSegments
321
328
  .map(({ segment }) => ({
@@ -332,7 +339,7 @@ export class PermutationVector extends Client {
332
339
  }
333
340
 
334
341
  switch (deltaArgs.operation) {
335
- case MergeTreeDeltaType.INSERT:
342
+ case MergeTreeDeltaType.INSERT: {
336
343
  // Pass 1: Perform any internal maintenance first to avoid reentrancy.
337
344
  for (const { segment, position } of ranges) {
338
345
  // HACK: We need to include the allocated handle in the segment's JSON representation
@@ -356,6 +363,7 @@ export class PermutationVector extends Client {
356
363
  );
357
364
  }
358
365
  break;
366
+ }
359
367
 
360
368
  case MergeTreeDeltaType.REMOVE: {
361
369
  // Pass 1: Perform any internal maintenance first to avoid reentrancy.
@@ -378,12 +386,13 @@ export class PermutationVector extends Client {
378
386
  break;
379
387
  }
380
388
 
381
- default:
389
+ default: {
382
390
  throw new Error("Unhandled MergeTreeDeltaType");
391
+ }
383
392
  }
384
393
  };
385
394
 
386
- private readonly onMaintenance = (args: IMergeTreeMaintenanceCallbackArgs) => {
395
+ private readonly onMaintenance = (args: IMergeTreeMaintenanceCallbackArgs): void => {
387
396
  if (args.operation === MergeTreeMaintenanceType.UNLINK) {
388
397
  let freed: number[] = [];
389
398
 
@@ -391,8 +400,11 @@ export class PermutationVector extends Client {
391
400
  const asPerm = segment as PermutationSegment;
392
401
  if (isHandleValid(asPerm.start)) {
393
402
  // Note: Using the spread operator with `.splice()` can exhaust the stack.
403
+ // eslint-disable-next-line unicorn/prefer-spread
394
404
  freed = freed.concat(
395
- new Array(asPerm.cachedLength).fill(0).map((value, index) => index + asPerm.start),
405
+ Array.from({ length: asPerm.cachedLength })
406
+ .fill(0)
407
+ .map((value, index) => index + asPerm.start),
396
408
  );
397
409
  }
398
410
  }
@@ -408,7 +420,7 @@ export class PermutationVector extends Client {
408
420
  }
409
421
  };
410
422
 
411
- public toString() {
423
+ public toString(): string {
412
424
  const s: string[] = [];
413
425
 
414
426
  this.walkSegments((segment) => {
@@ -425,7 +437,10 @@ export function reinsertSegmentIntoVector(
425
437
  vector: PermutationVector,
426
438
  pos: number,
427
439
  spec: IJSONSegment,
428
- ) {
440
+ ): {
441
+ op: IMergeTreeInsertMsg | undefined;
442
+ inserted: PermutationSegment;
443
+ } {
429
444
  const original = PermutationSegment.fromJSONObject(spec);
430
445
 
431
446
  // (Re)insert the removed number of rows at the original position.
package/src/range.ts CHANGED
@@ -6,7 +6,7 @@
6
6
  /**
7
7
  * Ensures that 0 \<= 'value' \< 'limit'. Throws a RangeError otherwise.
8
8
  */
9
- export function ensureRange(value: number, limit: number) {
9
+ export function ensureRange(value: number, limit: number): void {
10
10
  // Coerce 'value' to Uint32 so that we can range check with a single branch.
11
11
  const _value = value >>> 0; // eslint-disable-line no-bitwise
12
12