UNPKG

roam-research-mcp

Version:
94 lines (93 loc) • 3.04 kB
/** * Action Generator * * Generates correctly ordered batch actions from a DiffResult. * The order is critical for Roam API correctness: * 1. Creates (top-down to ensure parents exist before children) * 2. Moves (reposition existing blocks) * 3. Updates (text/heading changes) * 4. Deletes (bottom-up; reverse order to delete children before parents) */ /** * Generate a correctly ordered array of batch actions from a DiffResult. * * The ordering ensures: * - Parent blocks are created before their children * - Blocks are moved before text updates (in case moves affect siblings) * - Children are deleted before their parents * * @param diff - The DiffResult containing categorized actions * @returns Ordered array of batch actions ready for Roam API */ export function generateBatchActions(diff) { const actions = []; // 1. Creates (in markdown order, parents before children) // The creates are already in the correct order from diffBlockTrees actions.push(...diff.creates); // 2. Moves (reposition existing blocks) actions.push(...diff.moves); // 3. Updates (text/heading changes) actions.push(...diff.updates); // 4. Deletes (reversed to delete children before parents) // This is important because Roam will fail if you try to delete // a parent block while it still has children actions.push(...[...diff.deletes].reverse()); return actions; } /** * Filter actions to only include specific action types. * Useful for dry-run analysis or debugging. */ export function filterActions(actions, types) { const typeSet = new Set(types); return actions.filter((a) => typeSet.has(a.action)); } /** * Group actions by their type for analysis. */ export function groupActionsByType(actions) { const creates = []; const updates = []; const moves = []; const deletes = []; for (const action of actions) { switch (action.action) { case 'create-block': creates.push(action); break; case 'update-block': updates.push(action); break; case 'move-block': moves.push(action); break; case 'delete-block': deletes.push(action); break; } } return { creates, updates, moves, deletes }; } /** * Summarize actions for logging purposes. */ export function summarizeActions(actions) { const grouped = groupActionsByType(actions); const parts = []; if (grouped.creates.length > 0) { parts.push(`${grouped.creates.length} create(s)`); } if (grouped.moves.length > 0) { parts.push(`${grouped.moves.length} move(s)`); } if (grouped.updates.length > 0) { parts.push(`${grouped.updates.length} update(s)`); } if (grouped.deletes.length > 0) { parts.push(`${grouped.deletes.length} delete(s)`); } if (parts.length === 0) { return 'No changes'; } return parts.join(', '); }