import { type ISubscriberRecord, type ICollectionSubscriber, type IndexMap, type Collection, } from './interfaces'; import type { IAnySubscriber } from './subscriber-collection'; type ValueBatchRecord = [ 1, unknown, // oldValue unknown, // newValue ]; type CollectionBatchRecord = [ 2, Collection, IndexMap, ]; type BatchRecord = ValueBatchRecord | CollectionBatchRecord; type Batch = Map, BatchRecord>; let currBatch: Batch | null = new Map(); // eslint-disable-next-line import/no-mutable-exports export let batching = false; export function batch(fn: () => unknown): void { const prevBatch = currBatch; const newBatch: Batch = currBatch = new Map(); batching = true; try { fn(); } finally { currBatch = null; batching = false; try { let pair: [ISubscriberRecord, BatchRecord]; let subs: ISubscriberRecord; let batchRecord: BatchRecord; let col: Collection; let indexMap: IndexMap; let hasChanges = false; let i: number; let ii: number; for (pair of newBatch) { subs = pair[0]; batchRecord = pair[1]; if (prevBatch?.has(subs)) { prevBatch.set(subs, batchRecord); } if (batchRecord[0] === 1) { subs.notify(batchRecord[1], batchRecord[2]); } else { col = batchRecord[1]; indexMap = batchRecord[2]; hasChanges = false; if (indexMap.deletedIndices.length > 0) { hasChanges = true; } else { for (i = 0, ii = indexMap.length; i < ii; ++i) { if (indexMap[i] !== i) { hasChanges = true; break; } } } if (hasChanges) { subs.notifyCollection(col, indexMap); } } } } finally { currBatch = prevBatch; } } } export function addCollectionBatch( subs: ISubscriberRecord, collection: Collection, indexMap: IndexMap, ) { if (!currBatch!.has(subs)) { currBatch!.set(subs, [2, collection, indexMap]); } else { currBatch!.get(subs)![2] = indexMap; } } export function addValueBatch( subs: ISubscriberRecord, newValue: unknown, oldValue: unknown, ) { const batchRecord = currBatch!.get(subs); if (batchRecord === void 0) { currBatch!.set(subs, [1, newValue, oldValue]); } else { batchRecord[1] = newValue; batchRecord[2] = oldValue; } }