// Minimal, dependency-free unified line diff (LCS based). Config snapshots are // modest in size (hundreds of lines), so the O(n*m) table is fine here. export type DiffRowType = 'add' | 'del' | 'ctx'; export interface DiffRow { type: DiffRowType; text: string; } export function lineDiff(oldText: string, newText: string): DiffRow[] { const a = oldText.split('\n'); const b = newText.split('\n'); const n = a.length; const m = b.length; // dp[i][j] = length of LCS of a[i..] and b[j..] const dp: number[][] = Array.from({ length: n + 1 }, () => new Array(m + 1).fill(0)); for (let i = n - 1; i >= 0; i--) { for (let j = m - 1; j >= 0; j--) { dp[i][j] = a[i] === b[j] ? dp[i + 1][j + 1] + 1 : Math.max(dp[i + 1][j], dp[i][j + 1]); } } const rows: DiffRow[] = []; let i = 0; let j = 0; while (i < n && j < m) { if (a[i] === b[j]) { rows.push({ type: 'ctx', text: a[i] }); i++; j++; } else if (dp[i + 1][j] >= dp[i][j + 1]) { rows.push({ type: 'del', text: a[i] }); i++; } else { rows.push({ type: 'add', text: b[j] }); j++; } } while (i < n) rows.push({ type: 'del', text: a[i++] }); while (j < m) rows.push({ type: 'add', text: b[j++] }); return rows; }