Fix native diff row expansion (#940)

* Fix structured diff parsing for no-prefix paths

Git can emit diff --git path path when diff.noprefix is enabled. The structured diff parser only handled the default a/path b/path form, so checkout diff assembly could lose hunks for affected files and render expanded rows empty.

Normalize optional a/ and b/ prefixes in both app and server parsers, and cover the no-prefix header form with regression tests.

* Fix no-prefix diff path parsing

---------

Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
This commit is contained in:
c4605
2026-05-17 18:58:10 +08:00
committed by GitHub
co-authored by Mohamed Boudra
parent bb5c3dae00
commit b3c272f720
5 changed files with 195 additions and 16 deletions
@@ -185,6 +185,58 @@ describe("parseDiff", () => {
expect(hunk.lines[3].content).toBe("const bar = 3;");
});
it("parses no-prefix git diff headers", () => {
const files = parseDiff(
SIMPLE_DIFF.replace("a/example.ts b/example.ts", "example.ts example.ts")
.replace("--- a/example.ts", "--- example.ts")
.replace("+++ b/example.ts", "+++ example.ts"),
);
expect(files).toHaveLength(1);
expect(files[0].path).toBe("example.ts");
expect(files[0].additions).toBe(1);
expect(files[0].deletions).toBe(1);
expect(files[0].hunks).toHaveLength(1);
});
it("parses paths with spaces", () => {
const files = parseDiff(SIMPLE_DIFF.replaceAll("example.ts", "file with space.ts"));
expect(files).toHaveLength(1);
expect(files[0].path).toBe("file with space.ts");
expect(files[0].hunks).toHaveLength(1);
});
it("parses no-prefix paths with spaces", () => {
const files = parseDiff(
SIMPLE_DIFF.replaceAll("example.ts", "file with space.ts")
.replace(
"a/file with space.ts b/file with space.ts",
"file with space.ts file with space.ts",
)
.replace("--- a/file with space.ts", "--- file with space.ts")
.replace("+++ b/file with space.ts", "+++ file with space.ts"),
);
expect(files).toHaveLength(1);
expect(files[0].path).toBe("file with space.ts");
expect(files[0].hunks).toHaveLength(1);
});
it("preserves no-prefix paths that start with a or b", () => {
const files = parseDiff(
`${SIMPLE_DIFF.replace(
"diff --git a/example.ts b/example.ts",
"diff --git a/example.ts a/example.ts",
).replace("--- a/example.ts\n+++ b/example.ts", "--- a/example.ts\n+++ a/example.ts")}
${SIMPLE_DIFF.replaceAll("example.ts", "other.ts")
.replace("diff --git a/other.ts b/other.ts", "diff --git b/other.ts b/other.ts")
.replace("--- a/other.ts\n+++ b/other.ts", "--- b/other.ts\n+++ b/other.ts")}`,
);
expect(files.map((file) => file.path)).toEqual(["a/example.ts", "b/other.ts"]);
});
it("parses a diff with multiple hunks", () => {
const files = parseDiff(MULTI_HUNK_DIFF);