(oldStr, newStr, filePath, startLine)
| 102 | |
| 103 | // ---- Diff Rendering ---- |
| 104 | function buildDiffHtml(oldStr, newStr, filePath, startLine) { |
| 105 | const lineOffset = (startLine || 1) - 1; |
| 106 | const oldLines = (oldStr || '').split('\n'); |
| 107 | const newLines = (newStr || '').split('\n'); |
| 108 | const m = oldLines.length, n = newLines.length; |
| 109 | if (m * n > 500000) { |
| 110 | return buildDiffFallback(oldLines, newLines, filePath, lineOffset); |
| 111 | } |
| 112 | |
| 113 | const dp = Array.from({ length: m + 1 }, () => new Uint16Array(n + 1)); |
| 114 | for (let i = 1; i <= m; i++) |
| 115 | for (let j = 1; j <= n; j++) |
| 116 | dp[i][j] = oldLines[i - 1] === newLines[j - 1] |
| 117 | ? dp[i - 1][j - 1] + 1 |
| 118 | : Math.max(dp[i - 1][j], dp[i][j - 1]); |
| 119 | |
| 120 | const ops = []; |
| 121 | let i = m, j = n; |
| 122 | while (i > 0 || j > 0) { |
| 123 | if (i > 0 && j > 0 && oldLines[i - 1] === newLines[j - 1]) { |
| 124 | ops.push({ type: 'ctx', text: oldLines[i - 1], oldLn: i, newLn: j }); |
| 125 | i--; j--; |
| 126 | } else if (j > 0 && (i === 0 || dp[i][j - 1] >= dp[i - 1][j])) { |
| 127 | ops.push({ type: 'add', text: newLines[j - 1], newLn: j }); |
| 128 | j--; |
| 129 | } else { |
| 130 | ops.push({ type: 'del', text: oldLines[i - 1], oldLn: i }); |
| 131 | i--; |
| 132 | } |
| 133 | } |
| 134 | ops.reverse(); |
| 135 | return renderDiffOps(ops, filePath, lineOffset); |
| 136 | } |
| 137 | |
| 138 | function buildDiffFallback(oldLines, newLines, filePath, lineOffset) { |
| 139 | const ops = []; |
no test coverage detected