(props: Props)
| 15 | } |
| 16 | |
| 17 | export function ContentDiff(props: Props) { |
| 18 | const rows = createMemo(() => { |
| 19 | const diffRows: DiffRow[] = [] |
| 20 | |
| 21 | try { |
| 22 | const patches = parsePatch(props.diff) |
| 23 | |
| 24 | for (const patch of patches) { |
| 25 | for (const hunk of patch.hunks) { |
| 26 | const lines = hunk.lines |
| 27 | let i = 0 |
| 28 | |
| 29 | while (i < lines.length) { |
| 30 | const line = lines[i] |
| 31 | const content = line.slice(1) |
| 32 | const prefix = line[0] |
| 33 | |
| 34 | if (prefix === "-") { |
| 35 | // Look ahead for consecutive additions to pair with removals |
| 36 | const removals: string[] = [content] |
| 37 | let j = i + 1 |
| 38 | |
| 39 | // Collect all consecutive removals |
| 40 | while (j < lines.length && lines[j][0] === "-") { |
| 41 | removals.push(lines[j].slice(1)) |
| 42 | j++ |
| 43 | } |
| 44 | |
| 45 | // Collect all consecutive additions that follow |
| 46 | const additions: string[] = [] |
| 47 | while (j < lines.length && lines[j][0] === "+") { |
| 48 | additions.push(lines[j].slice(1)) |
| 49 | j++ |
| 50 | } |
| 51 | |
| 52 | // Pair removals with additions |
| 53 | const maxLength = Math.max(removals.length, additions.length) |
| 54 | for (let k = 0; k < maxLength; k++) { |
| 55 | const hasLeft = k < removals.length |
| 56 | const hasRight = k < additions.length |
| 57 | |
| 58 | if (hasLeft && hasRight) { |
| 59 | // Replacement - left is removed, right is added |
| 60 | diffRows.push({ |
| 61 | left: removals[k], |
| 62 | right: additions[k], |
| 63 | type: "modified", |
| 64 | }) |
| 65 | } else if (hasLeft) { |
| 66 | // Pure removal |
| 67 | diffRows.push({ |
| 68 | left: removals[k], |
| 69 | right: "", |
| 70 | type: "removed", |
| 71 | }) |
| 72 | } else if (hasRight) { |
| 73 | // Pure addition - only create if we actually have content |
| 74 | diffRows.push({ |
nothing calls this directly
no test coverage detected