refactor(hashline-edit): replace custom diff with diff library
🤖 Generated with assistance of [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)
This commit is contained in:
3
bun.lock
3
bun.lock
@@ -14,6 +14,7 @@
|
||||
"@opencode-ai/sdk": "^1.1.19",
|
||||
"commander": "^14.0.2",
|
||||
"detect-libc": "^2.0.0",
|
||||
"diff": "^8.0.3",
|
||||
"js-yaml": "^4.1.1",
|
||||
"jsonc-parser": "^3.3.1",
|
||||
"picocolors": "^1.1.1",
|
||||
@@ -138,6 +139,8 @@
|
||||
|
||||
"detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
|
||||
|
||||
"diff": ["diff@8.0.3", "", {}, "sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ=="],
|
||||
|
||||
"dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
|
||||
|
||||
"ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="],
|
||||
|
||||
@@ -60,6 +60,7 @@
|
||||
"@opencode-ai/sdk": "^1.1.19",
|
||||
"commander": "^14.0.2",
|
||||
"detect-libc": "^2.0.0",
|
||||
"diff": "^8.0.3",
|
||||
"js-yaml": "^4.1.1",
|
||||
"jsonc-parser": "^3.3.1",
|
||||
"picocolors": "^1.1.1",
|
||||
|
||||
71
src/tools/hashline-edit/diff-utils.test.ts
Normal file
71
src/tools/hashline-edit/diff-utils.test.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
/// <reference types="bun-types" />
|
||||
import { describe, expect, it } from "bun:test"
|
||||
import { generateUnifiedDiff } from "./diff-utils"
|
||||
|
||||
function createNumberedLines(totalLineCount: number): string {
|
||||
return Array.from({ length: totalLineCount }, (_, index) => `line ${index + 1}`).join("\n")
|
||||
}
|
||||
|
||||
describe("generateUnifiedDiff", () => {
|
||||
it("creates separate hunks for distant changes", () => {
|
||||
//#given
|
||||
const oldContent = createNumberedLines(60)
|
||||
const newLines = oldContent.split("\n")
|
||||
newLines[4] = "line 5 updated"
|
||||
newLines[49] = "line 50 updated"
|
||||
const newContent = newLines.join("\n")
|
||||
|
||||
//#when
|
||||
const diff = generateUnifiedDiff(oldContent, newContent, "sample.txt")
|
||||
|
||||
//#then
|
||||
const hunkHeaders = diff.match(/^@@/gm) ?? []
|
||||
expect(hunkHeaders.length).toBe(2)
|
||||
})
|
||||
|
||||
it("creates a single hunk for adjacent changes", () => {
|
||||
//#given
|
||||
const oldContent = createNumberedLines(20)
|
||||
const newLines = oldContent.split("\n")
|
||||
newLines[9] = "line 10 updated"
|
||||
newLines[10] = "line 11 updated"
|
||||
const newContent = newLines.join("\n")
|
||||
|
||||
//#when
|
||||
const diff = generateUnifiedDiff(oldContent, newContent, "sample.txt")
|
||||
|
||||
//#then
|
||||
const hunkHeaders = diff.match(/^@@/gm) ?? []
|
||||
expect(hunkHeaders.length).toBe(1)
|
||||
expect(diff).toContain(" line 8")
|
||||
expect(diff).toContain(" line 13")
|
||||
})
|
||||
|
||||
it("returns a diff string for identical content", () => {
|
||||
//#given
|
||||
const oldContent = "alpha\nbeta\ngamma"
|
||||
const newContent = "alpha\nbeta\ngamma"
|
||||
|
||||
//#when
|
||||
const diff = generateUnifiedDiff(oldContent, newContent, "sample.txt")
|
||||
|
||||
//#then
|
||||
expect(typeof diff).toBe("string")
|
||||
expect(diff).toContain("--- sample.txt")
|
||||
expect(diff).toContain("+++ sample.txt")
|
||||
})
|
||||
|
||||
it("returns a valid diff when old content is empty", () => {
|
||||
//#given
|
||||
const oldContent = ""
|
||||
const newContent = "first line\nsecond line"
|
||||
|
||||
//#when
|
||||
const diff = generateUnifiedDiff(oldContent, newContent, "sample.txt")
|
||||
|
||||
//#then
|
||||
expect(diff).toContain("--- sample.txt")
|
||||
expect(diff).toContain("+++ sample.txt")
|
||||
expect(diff).toContain("+first line")
|
||||
})
|
||||
})
|
||||
@@ -1,3 +1,4 @@
|
||||
import { createTwoFilesPatch } from "diff"
|
||||
import { computeLineHash } from "./hash-computation"
|
||||
|
||||
export function toHashlineContent(content: string): string {
|
||||
@@ -15,59 +16,7 @@ export function toHashlineContent(content: string): string {
|
||||
}
|
||||
|
||||
export function generateUnifiedDiff(oldContent: string, newContent: string, filePath: string): string {
|
||||
const oldLines = oldContent.split("\n")
|
||||
const newLines = newContent.split("\n")
|
||||
const maxLines = Math.max(oldLines.length, newLines.length)
|
||||
|
||||
let diff = `--- ${filePath}\n+++ ${filePath}\n`
|
||||
let inHunk = false
|
||||
let oldStart = 1
|
||||
let newStart = 1
|
||||
let oldCount = 0
|
||||
let newCount = 0
|
||||
let hunkLines: string[] = []
|
||||
|
||||
for (let i = 0; i < maxLines; i++) {
|
||||
const oldLine = oldLines[i] ?? ""
|
||||
const newLine = newLines[i] ?? ""
|
||||
|
||||
if (oldLine !== newLine) {
|
||||
if (!inHunk) {
|
||||
oldStart = i + 1
|
||||
newStart = i + 1
|
||||
oldCount = 0
|
||||
newCount = 0
|
||||
hunkLines = []
|
||||
inHunk = true
|
||||
}
|
||||
|
||||
if (oldLines[i] !== undefined) {
|
||||
hunkLines.push(`-${oldLine}`)
|
||||
oldCount++
|
||||
}
|
||||
if (newLines[i] !== undefined) {
|
||||
hunkLines.push(`+${newLine}`)
|
||||
newCount++
|
||||
}
|
||||
} else if (inHunk) {
|
||||
hunkLines.push(` ${oldLine}`)
|
||||
oldCount++
|
||||
newCount++
|
||||
|
||||
if (hunkLines.length > 6) {
|
||||
diff += `@@ -${oldStart},${oldCount} +${newStart},${newCount} @@\n`
|
||||
diff += hunkLines.join("\n") + "\n"
|
||||
inHunk = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (inHunk && hunkLines.length > 0) {
|
||||
diff += `@@ -${oldStart},${oldCount} +${newStart},${newCount} @@\n`
|
||||
diff += hunkLines.join("\n") + "\n"
|
||||
}
|
||||
|
||||
return diff || `--- ${filePath}\n+++ ${filePath}\n`
|
||||
return createTwoFilesPatch(filePath, filePath, oldContent, newContent)
|
||||
}
|
||||
|
||||
export function countLineDiffs(oldContent: string, newContent: string): { additions: number; deletions: number } {
|
||||
|
||||
Reference in New Issue
Block a user