ordered-baseline.ts 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243
  1. /**
  2. * Merge an authoritative baseline without moving identities already visible to
  3. * the client. Baseline-only identities are inserted relative to the nearest
  4. * following known identity; identities absent from the baseline are removed.
  5. *
  6. * @param current - the established client order.
  7. * @param baseline - the latest authoritative rows.
  8. * @param keyOf - stable identity selector.
  9. * @returns baseline-valued rows with the established relative order retained.
  10. */
  11. export function mergeOrderedBaseline<T>(
  12. current: readonly T[],
  13. baseline: readonly T[],
  14. keyOf: (value: T) => unknown,
  15. ): T[] {
  16. const baselineByKey = new Map<unknown, T>()
  17. for (const value of baseline) baselineByKey.set(keyOf(value), value)
  18. const merged = current
  19. .map(value => baselineByKey.get(keyOf(value)))
  20. .filter((value): value is T => value !== undefined)
  21. const mergedKeys = new Set(merged.map(keyOf))
  22. for (let index = 0; index < baseline.length; index++) {
  23. const value = baseline[index]
  24. /* v8 ignore next -- dense-array guard: index is bounded by baseline.length. */
  25. if (value === undefined || mergedKeys.has(keyOf(value))) continue
  26. let insertion = merged.length
  27. for (let following = index + 1; following < baseline.length; following++) {
  28. const candidate = baseline[following]
  29. /* v8 ignore next -- dense-array guard: following is bounded by baseline.length. */
  30. if (candidate === undefined) continue
  31. const known = merged.findIndex(item => keyOf(item) === keyOf(candidate))
  32. if (known !== -1) {
  33. insertion = known
  34. break
  35. }
  36. }
  37. merged.splice(insertion, 0, value)
  38. mergedKeys.add(keyOf(value))
  39. }
  40. return merged
  41. }