Functional Weave
Code in TypeScript

todo.merge@1.0.0

impl/typescript.ts

1,301 bytes · the TypeScript implementation · view raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

import { type Todo } from "./todo_item.ts";  ← from todo.item ^1.0.0 · built alongside by fune

/** Manual order: order ascending, ties by position in the array (a stable sort). */
function inManualOrder(todos: readonly Todo[], which: string): Todo[] {
  const seen = new Set<string>();
  for (const todo of todos) {
    if (seen.has(todo.id)) throw new Error(`duplicate id "${todo.id}" in the ${which} list`);
    seen.add(todo.id);
  }
  return [...todos].sort((a, b) => a.order - b.order);
}

/**
 * Merge by id. A todo in both lists is taken from `incoming` (the newer
 * copy: todo.item keeps no edit time to compare), in the place the current
 * one had, because that is where the person put it. Todos only in `incoming`
 * follow, in their own manual order. Todos only in `current` stay. The
 * result is in manual order, renumbered 0 to n-1.
 */
export function mergeTodos(current: readonly Todo[], incoming: readonly Todo[]): readonly Todo[] {
  const mine = inManualOrder(current, "current");
  const theirs = inManualOrder(incoming, "incoming");
  const byId = new Map(theirs.map((todo) => [todo.id, todo]));
  const kept = new Set(mine.map((todo) => todo.id));
  const merged = [...mine.map((todo) => byId.get(todo.id) ?? todo), ...theirs.filter((todo) => !kept.has(todo.id))];
  return merged.map((todo, order) => ({ ...todo, order }));
}