From 269c09267427746423c6bbe6d715ffd824befc64 Mon Sep 17 00:00:00 2001 From: claude code agent 227 Date: Wed, 24 Jun 2026 01:03:33 +0300 Subject: [PATCH] refactor(git-sync): extract shared buildLcsTable for the two block diffs (PR #119 review) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The two-way block diff (yjs-body-merge.diffBlocks) and the three-way merge planner (three-way-merge.lcsPairs) built the identical backward-filled LCS DP table inline. Extract it to lcs.ts (buildLcsTable); each caller keeps its own traceback. No behavior change — merge specs unchanged and green. Co-Authored-By: Claude Opus 4.8 --- .../src/integrations/git-sync/services/lcs.ts | 26 +++++++++++++++++++ .../git-sync/services/three-way-merge.ts | 14 +++------- .../git-sync/services/yjs-body-merge.ts | 13 ++-------- 3 files changed, 31 insertions(+), 22 deletions(-) create mode 100644 apps/server/src/integrations/git-sync/services/lcs.ts diff --git a/apps/server/src/integrations/git-sync/services/lcs.ts b/apps/server/src/integrations/git-sync/services/lcs.ts new file mode 100644 index 00000000..250de948 --- /dev/null +++ b/apps/server/src/integrations/git-sync/services/lcs.ts @@ -0,0 +1,26 @@ +/** + * Backward-filled LCS length table for sequences `a` and `b`: `dp[i][j]` is the + * length of the longest common subsequence of the suffixes `a[i:]` and `b[j:]`. + * O(n*m) time/space — fine for page block counts. + * + * Shared by the two-way block diff (`yjs-body-merge.diffBlocks`) and the + * three-way merge planner (`three-way-merge.lcsPairs`) so the (identical) table + * construction lives in ONE place; each caller does its own traceback over the + * returned table. + */ +export function buildLcsTable(a: string[], b: string[]): number[][] { + const n = a.length; + const m = b.length; + 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]); + } + } + return dp; +} diff --git a/apps/server/src/integrations/git-sync/services/three-way-merge.ts b/apps/server/src/integrations/git-sync/services/three-way-merge.ts index fd87e9ac..eb1d2126 100644 --- a/apps/server/src/integrations/git-sync/services/three-way-merge.ts +++ b/apps/server/src/integrations/git-sync/services/three-way-merge.ts @@ -19,21 +19,13 @@ * instances (and the human's in-flight edits) in place. */ +import { buildLcsTable } from './lcs'; + /** Matched index pairs of the longest common subsequence of `a` and `b`. */ function lcsPairs(a: string[], b: string[]): Array<[number, number]> { const n = a.length; const m = b.length; - 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 dp = buildLcsTable(a, b); const pairs: Array<[number, number]> = []; let i = 0; let j = 0; diff --git a/apps/server/src/integrations/git-sync/services/yjs-body-merge.ts b/apps/server/src/integrations/git-sync/services/yjs-body-merge.ts index c1dab666..2c459505 100644 --- a/apps/server/src/integrations/git-sync/services/yjs-body-merge.ts +++ b/apps/server/src/integrations/git-sync/services/yjs-body-merge.ts @@ -1,6 +1,7 @@ import * as Y from 'yjs'; import { diff3Plan } from './three-way-merge'; +import { buildLcsTable } from './lcs'; /** * Block-level merge of an incoming (git) page body into a LIVE Yjs document, @@ -90,17 +91,7 @@ type Op = export function diffBlocks(a: string[], b: string[]): Op[] { const n = a.length; const m = b.length; - 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 dp = buildLcsTable(a, b); const ops: Op[] = []; let i = 0; let j = 0;