Skip to content

Commit 5a28750

Browse files
authored
feat: support binary file diff (fixes #17) (#18)
1 parent 468b932 commit 5a28750

11 files changed

+158
-1
lines changed

src/__fixtures__/changed-binary-file

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
diff --git a/file1 b/file1
2+
index 21be030..9443748 100644
3+
Binary files a/file1 and b/file1 differ

src/__fixtures__/deleted-binary-file

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
diff --git a/file1 b/file1
2+
deleted file mode 100644
3+
index 21be030..0000000
4+
Binary files a/file1 and /dev/null differ

src/__fixtures__/new-binary-file

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
diff --git a/file1 b/file1
2+
new file mode 100644
3+
index 0000000..21be030
4+
Binary files /dev/null and b/file1 differ
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`changed binary file parse \`changed-binary-file\` 1`] = `
4+
{
5+
"files": [
6+
{
7+
"chunks": [
8+
{
9+
"pathAfter": "file1",
10+
"pathBefore": "file1",
11+
"type": "BinaryFilesChunk",
12+
},
13+
],
14+
"path": "file1",
15+
"type": "ChangedFile",
16+
},
17+
],
18+
"type": "GitDiff",
19+
}
20+
`;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`deleted binary file parse \`deleted-binary-file\` 1`] = `
4+
{
5+
"files": [
6+
{
7+
"chunks": [
8+
{
9+
"pathAfter": "/dev/null",
10+
"pathBefore": "file1",
11+
"type": "BinaryFilesChunk",
12+
},
13+
],
14+
"path": "file1",
15+
"type": "DeletedFile",
16+
},
17+
],
18+
"type": "GitDiff",
19+
}
20+
`;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`new-binary-file parse \`new-binary-file\` 1`] = `
4+
{
5+
"files": [
6+
{
7+
"chunks": [
8+
{
9+
"pathAfter": "file1",
10+
"pathBefore": "/dev/null",
11+
"type": "BinaryFilesChunk",
12+
},
13+
],
14+
"path": "file1",
15+
"type": "AddedFile",
16+
},
17+
],
18+
"type": "GitDiff",
19+
}
20+
`;
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { getFixture } from './test-utils';
2+
import parseGitDiff from '../parse-git-diff';
3+
4+
describe('changed binary file', () => {
5+
const fixture = getFixture('changed-binary-file');
6+
7+
it('parse `changed-binary-file`', () => {
8+
expect(parseGitDiff(fixture)).toMatchSnapshot();
9+
});
10+
});
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { getFixture } from './test-utils';
2+
import parseGitDiff from '../parse-git-diff';
3+
4+
describe('deleted binary file', () => {
5+
const fixture = getFixture('deleted-binary-file');
6+
7+
it('parse `deleted-binary-file`', () => {
8+
expect(parseGitDiff(fixture)).toMatchSnapshot();
9+
});
10+
});

src/__tests__/new-binary-file.test.ts

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { getFixture } from './test-utils';
2+
import parseGitDiff from '../parse-git-diff';
3+
4+
describe('new-binary-file', () => {
5+
const fixture = getFixture('new-binary-file');
6+
7+
it('parse `new-binary-file`', () => {
8+
expect(parseGitDiff(fixture)).toMatchSnapshot();
9+
});
10+
});

src/parse-git-diff.ts

+51
Original file line numberDiff line numberDiff line change
@@ -74,12 +74,28 @@ function parseFileChange(ctx: Context): AnyFileChange | undefined {
7474
chunks,
7575
path: changeMarkers.deleted,
7676
};
77+
} else if (
78+
isDeleted &&
79+
chunks.length &&
80+
chunks[0].type === 'BinaryFilesChunk'
81+
) {
82+
return {
83+
type: FileType.Deleted,
84+
chunks,
85+
path: chunks[0].pathBefore,
86+
};
7787
} else if (isNew && changeMarkers) {
7888
return {
7989
type: FileType.Added,
8090
chunks,
8191
path: changeMarkers.added,
8292
};
93+
} else if (isNew && chunks.length && chunks[0].type === 'BinaryFilesChunk') {
94+
return {
95+
type: FileType.Added,
96+
chunks,
97+
path: chunks[0].pathAfter,
98+
};
8399
} else if (isRename) {
84100
return {
85101
type: FileType.Renamed,
@@ -93,7 +109,18 @@ function parseFileChange(ctx: Context): AnyFileChange | undefined {
93109
chunks,
94110
path: changeMarkers.added,
95111
};
112+
} else if (
113+
chunks.length &&
114+
chunks[0].type === 'BinaryFilesChunk' &&
115+
chunks[0].pathAfter === chunks[0].pathBefore
116+
) {
117+
return {
118+
type: FileType.Changed,
119+
chunks,
120+
path: chunks[0].pathAfter,
121+
};
96122
}
123+
97124
return;
98125
}
99126

@@ -148,6 +175,16 @@ function parseChunk(context: Context): AnyChunk | undefined {
148175
type: 'CombinedChunk',
149176
changes,
150177
};
178+
} else if (
179+
chunkHeader.type === 'BinaryFiles' &&
180+
chunkHeader.fileA &&
181+
chunkHeader.fileB
182+
) {
183+
return {
184+
type: 'BinaryFilesChunk',
185+
pathBefore: chunkHeader.fileA,
186+
pathAfter: chunkHeader.fileB,
187+
};
151188
}
152189
}
153190

@@ -184,6 +221,19 @@ function parseChunkHeader(ctx: Context) {
184221
);
185222

186223
if (!combinedChunkExec) {
224+
const binaryChunkExec = /^Binary\sfiles\s(.*)\sand\s(.*)\sdiffer$/.exec(
225+
line
226+
);
227+
if (binaryChunkExec) {
228+
const [all, fileA, fileB] = binaryChunkExec;
229+
ctx.nextLine();
230+
return {
231+
type: 'BinaryFiles',
232+
fileA: fileA.replace('a/', ''),
233+
fileB: fileB.replace('b/', ''),
234+
} as const;
235+
}
236+
187237
return null;
188238
}
189239

@@ -206,6 +256,7 @@ function parseChunkHeader(ctx: Context) {
206256
toFileRange: getRange(addStart, addLines),
207257
} as const;
208258
}
259+
209260
const [all, delStart, delLines, addStart, addLines, context] =
210261
normalChunkExec;
211262
ctx.nextLine();

src/types.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,12 @@ export interface CombinedChunk extends Base<'CombinedChunk'> {
5151
context: string | undefined;
5252
}
5353

54-
export type AnyChunk = Chunk | CombinedChunk;
54+
export interface BinaryFilesChunk extends Base<'BinaryFilesChunk'> {
55+
pathBefore: string;
56+
pathAfter: string;
57+
}
58+
59+
export type AnyChunk = Chunk | CombinedChunk | BinaryFilesChunk;
5560

5661
export interface ChangedFile extends Base<typeof FileType.Changed> {
5762
path: string;

0 commit comments

Comments
 (0)