Skip to content

Commit 41461b2

Browse files
sunnylqmclaude
andcommitted
feat: support async customDiff implementations
The customDiff option now accepts functions returning Promise<Buffer> (e.g. node-hdiffpatch's callback-based async diff), so servers can run diffs off the event loop. Sync implementations keep working unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent e6c55ca commit 41461b2

2 files changed

Lines changed: 40 additions & 3 deletions

File tree

src/diff.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ import {
1919
zipOptionsForPayloadEntry,
2020
} from './utils/zip-options';
2121

22-
type Diff = (oldSource?: Buffer, newSource?: Buffer) => Buffer;
22+
type Diff = (
23+
oldSource?: Buffer,
24+
newSource?: Buffer,
25+
) => Buffer | Promise<Buffer>;
2326
type HdiffModule = {
2427
diff?: Diff;
2528
};
@@ -83,7 +86,7 @@ async function addBundlePatch(
8386
) {
8487
const newSource = await readEntry(entry, nextZipfile);
8588
zipfile.addBuffer(
86-
diffFn(originSource, newSource),
89+
await diffFn(originSource, newSource),
8790
`${entry.fileName}.patch`,
8891
zipOptionsForPatchEntry(),
8992
);

tests/diff.test.ts

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ type ZipContent = {
2222

2323
type DiffContextOptions = {
2424
output?: unknown;
25-
customDiff?: (oldSource?: Buffer, newSource?: Buffer) => Buffer;
25+
customDiff?: (
26+
oldSource?: Buffer,
27+
newSource?: Buffer,
28+
) => Buffer | Promise<Buffer>;
2629
customHdiffModule?: {
2730
diff?: (oldSource?: Buffer, newSource?: Buffer) => Buffer;
2831
};
@@ -185,6 +188,37 @@ describe('diff commands', () => {
185188
expect(diffMeta.deletes['old-only.txt']).toBe(1);
186189
});
187190

191+
test('hdiff supports an async customDiff implementation', async () => {
192+
const originPath = path.join(tempRoot, 'origin.ppk');
193+
const nextPath = path.join(tempRoot, 'next.ppk');
194+
const outputPath = path.join(tempRoot, 'out', 'diff-async.ppk');
195+
196+
await createZip(originPath, {
197+
'index.bundlejs': 'old-bundle',
198+
});
199+
200+
await createZip(nextPath, {
201+
'index.bundlejs': 'new-bundle',
202+
});
203+
204+
await diffCommands.hdiff(
205+
createContext([originPath, nextPath], {
206+
output: outputPath,
207+
customDiff: async (oldSource, newSource) => {
208+
await new Promise((resolve) => setTimeout(resolve, 1));
209+
return Buffer.from(
210+
`async-patch:${oldSource?.toString('utf-8')}:${newSource?.toString('utf-8')}`,
211+
);
212+
},
213+
}),
214+
);
215+
216+
const result = await readZipContent(outputPath);
217+
expect(result.files['index.bundlejs.patch']?.toString('utf-8')).toBe(
218+
'async-patch:old-bundle:new-bundle',
219+
);
220+
});
221+
188222
test('hdiff compresses large manifest entries', async () => {
189223
const originPath = path.join(tempRoot, 'origin-large-manifest.ppk');
190224
const nextPath = path.join(tempRoot, 'next-large-manifest.ppk');

0 commit comments

Comments
 (0)