diff --git a/src/types/custom/ArraySchema.ts b/src/types/custom/ArraySchema.ts index d4ba5699..acec08f9 100644 --- a/src/types/custom/ArraySchema.ts +++ b/src/types/custom/ArraySchema.ts @@ -286,12 +286,11 @@ export class ArraySchema implements Array, Collection, IR // decoding only protected $setAt(index: number, value: V, operation: OPERATION) { if ( - index === 0 && operation === OPERATION.ADD && this.items[index] !== undefined ) { - // handle decoding unshift - this.items.unshift(value); + // handle decoding unshift / insert at position + this.items.splice(index, 0, value); } else if (operation === OPERATION.DELETE_AND_MOVE) { this.items.splice(index, 1); @@ -520,6 +519,18 @@ export class ArraySchema implements Array, Collection, IR this.tmpItems.unshift(...items); + // Sort operations by ascending index to ensure correct encoding order. + // When consecutive unshifts occur, the decoder uses splice to insert at + // each index — this only works if lower indices are processed first. + // (See test "consecutive unshift calls should not break 'encodeAll'") + const changeSet = changeTree.isFiltered ? changeTree.filteredChanges : changeTree.changes; + changeSet.operations.sort((a, b) => a - b); + const newIndexes: { [index: number]: number } = {}; + for (let i = 0; i < changeSet.operations.length; i++) { + newIndexes[changeSet.operations[i]] = i; + } + changeSet.indexes = newIndexes; + return this.items.unshift(...items); } diff --git a/test/ArraySchema.test.ts b/test/ArraySchema.test.ts index 4d5003b6..a61f2369 100644 --- a/test/ArraySchema.test.ts +++ b/test/ArraySchema.test.ts @@ -700,7 +700,7 @@ describe("ArraySchema Tests", () => { assertDeepStrictEqualEncodeAll(state); }); - xit("consecutive unshift calls should not break 'encodeAll'", () => { + it("consecutive unshift calls should not break 'encodeAll'", () => { class State extends Schema { @type(["number"]) arrayOfNumbers = new ArraySchema(); }