diff --git a/packages/diffs/src/utils/parsePatchFiles.ts b/packages/diffs/src/utils/parsePatchFiles.ts index 2928f56da..cd866fad7 100644 --- a/packages/diffs/src/utils/parsePatchFiles.ts +++ b/packages/diffs/src/utils/parsePatchFiles.ts @@ -188,8 +188,17 @@ function _processFile( for (const line of lines) { if (line.startsWith('diff --git')) { - const [, , prevName, , name] = - line.trim().match(ALTERNATE_FILE_NAMES_GIT) ?? []; + const filenameMatch = line.trim().match(ALTERNATE_FILE_NAMES_GIT); + const prevName = filenameMatch?.[1] ?? filenameMatch?.[2]; + const name = filenameMatch?.[3] ?? filenameMatch?.[4]; + if (prevName == null || name == null) { + if (throwOnError) { + throw Error('parsePatchContent: invalid git diff header'); + } else { + console.error('parsePatchContent: invalid git diff header', line); + } + continue; + } currentFile.name = detachString(name.trim()); if (prevName !== name) { currentFile.prevName = detachString(prevName.trim()); diff --git a/packages/diffs/test/parsePatchFiles.test.ts b/packages/diffs/test/parsePatchFiles.test.ts index c82a67e05..de5ade736 100644 --- a/packages/diffs/test/parsePatchFiles.test.ts +++ b/packages/diffs/test/parsePatchFiles.test.ts @@ -2,7 +2,7 @@ import { afterAll, describe, expect, spyOn, test } from 'bun:test'; import { disposeHighlighter } from '../src/highlighter/shared_highlighter'; import { DiffHunksRenderer } from '../src/renderers/DiffHunksRenderer'; -import { parsePatchFiles } from '../src/utils/parsePatchFiles'; +import { parsePatchFiles, processFile } from '../src/utils/parsePatchFiles'; import { diffPatch, finalBlankLinePatch, @@ -117,6 +117,24 @@ describe('parsePatchFiles', () => { expect(file?.additionLines[0]).toBe('new\ud800\n'); }); + test('parses quoted git diff headers with escaped file names', () => { + const oldName = + 'test/integration/image-optimizer/app/public/\\303\\244\\303\\266\\303\\274\\305\\241\\304\\215\\305\\231\\303\\255.png'; + const newName = + 'test/e2e/image-optimizer/app/public/\\303\\244\\303\\266\\303\\274\\305\\241\\304\\215\\305\\231\\303\\255.png'; + const file = processFile( + [ + `diff --git "a/${oldName}" "b/${newName}"\n`, + 'similarity index 100%\n', + ].join(''), + { isGitDiff: true } + ); + + expect(file?.name).toBe(newName); + expect(file?.prevName).toBe(oldName); + expect(file?.type).toBe('rename-pure'); + }); + test( 'splitLineCount should match rendered line count in split mode', async () => {