updated design
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
// LCS-based O(nm) diff algorithm — correct and simple for component-sized inputs.
|
||||
// Produces a minimal edit script as a sequence of equal/insert/delete operations.
|
||||
|
||||
export type EditType = 'equal' | 'insert' | 'delete';
|
||||
|
||||
export interface EditOp {
|
||||
type: EditType;
|
||||
lines: string[];
|
||||
}
|
||||
|
||||
export function computeEditScript(before: string[], after: string[]): EditOp[] {
|
||||
const n = before.length;
|
||||
const m = after.length;
|
||||
|
||||
if (n === 0 && m === 0) return [];
|
||||
if (n === 0) return [{ type: 'insert', lines: [...after] }];
|
||||
if (m === 0) return [{ type: 'delete', lines: [...before] }];
|
||||
|
||||
// Build LCS DP table
|
||||
const dp: number[][] = Array.from({ length: n + 1 }, () => new Array(m + 1).fill(0));
|
||||
for (let i = 1; i <= n; i++) {
|
||||
for (let j = 1; j <= m; j++) {
|
||||
dp[i]![j] =
|
||||
before[i - 1] === after[j - 1]
|
||||
? (dp[i - 1]![j - 1] ?? 0) + 1
|
||||
: Math.max(dp[i - 1]![j] ?? 0, dp[i]![j - 1] ?? 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Backtrack from (n, m) to (0, 0)
|
||||
type RawOp = { type: EditType; line: string };
|
||||
const raw: RawOp[] = [];
|
||||
let i = n, j = m;
|
||||
|
||||
while (i > 0 || j > 0) {
|
||||
if (i > 0 && j > 0 && before[i - 1] === after[j - 1]) {
|
||||
raw.push({ type: 'equal', line: before[i - 1]! });
|
||||
i--; j--;
|
||||
} else if (j > 0 && (i === 0 || (dp[i]![j - 1] ?? 0) >= (dp[i - 1]![j] ?? 0))) {
|
||||
raw.push({ type: 'insert', line: after[j - 1]! });
|
||||
j--;
|
||||
} else {
|
||||
raw.push({ type: 'delete', line: before[i - 1]! });
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
raw.reverse();
|
||||
|
||||
// Merge consecutive ops of the same type
|
||||
const ops: EditOp[] = [];
|
||||
for (const op of raw) {
|
||||
const last = ops[ops.length - 1];
|
||||
if (last && last.type === op.type) {
|
||||
last.lines.push(op.line);
|
||||
} else {
|
||||
ops.push({ type: op.type, lines: [op.line] });
|
||||
}
|
||||
}
|
||||
|
||||
return ops;
|
||||
}
|
||||
Reference in New Issue
Block a user