Skip to content

Commit 8a23469

Browse files
committed
Remove redundant unzip dependency
1 parent 8cd9841 commit 8a23469

4 files changed

Lines changed: 102 additions & 32 deletions

File tree

bun.lock

Lines changed: 0 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@
7474
"gradle-to-js": "^2.0.1",
7575
"i18next": "^26.0.4",
7676
"isomorphic-git": "^1.37.5",
77-
"isomorphic-unzip": "^1.1.5",
7877
"node-fetch": "^2.6.1",
7978
"plist": "^3.1.0",
8079
"progress": "^2.0.3",

src/utils/app-info-parser/zip.ts

Lines changed: 41 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,12 @@
11
import path from 'path';
2-
import { decodeNullUnicode } from './utils';
3-
4-
const Unzip = require('isomorphic-unzip');
5-
62
import { enumZipEntries, readEntry } from '../zip-entries';
3+
import { decodeNullUnicode } from './utils';
74

85
export class Zip {
96
file: string | File;
10-
unzip: any;
117

128
constructor(file: string | File) {
139
this.file = typeof file === 'string' ? path.resolve(file) : file;
14-
this.unzip = new Unzip(this.file);
1510
}
1611

1712
/**
@@ -24,15 +19,7 @@ export class Zip {
2419
type: 'buffer' | 'blob' = 'buffer',
2520
) {
2621
const decoded = regexps.map((regex) => decodeNullUnicode(regex));
27-
return new Promise<Record<string, Buffer | Blob>>((resolve, reject) => {
28-
this.unzip.getBuffer(
29-
decoded,
30-
{ type },
31-
(err: Error | null, buffers: Record<string, Buffer | Blob>) => {
32-
err ? reject(err) : resolve(buffers);
33-
},
34-
);
35-
});
22+
return this.readEntries(decoded, type);
3623
}
3724

3825
/**
@@ -42,15 +29,9 @@ export class Zip {
4229
*/
4330
getEntry(regex: RegExp | string, type: 'buffer' | 'blob' = 'buffer') {
4431
const decoded = decodeNullUnicode(regex);
45-
return new Promise<Buffer | Blob | undefined>((resolve, reject) => {
46-
this.unzip.getBuffer(
47-
[decoded],
48-
{ type },
49-
(err: Error | null, buffers: Record<string, Buffer | Blob>) => {
50-
err ? reject(err) : resolve(buffers[decoded as any]);
51-
},
52-
);
53-
});
32+
return this.readEntries([decoded], type).then(
33+
(buffers) => buffers[decoded as any],
34+
);
5435
}
5536

5637
async getEntryFromHarmonyApp(
@@ -71,4 +52,40 @@ export class Zip {
7152
console.error('Error in getEntryFromHarmonyApp:', error);
7253
}
7354
}
55+
56+
private async readEntries(
57+
decoded: Array<RegExp | string>,
58+
type: 'buffer' | 'blob',
59+
): Promise<Record<string, Buffer | Blob>> {
60+
if (typeof this.file !== 'string') {
61+
throw new Error('Param error: [file] must be file path in Node.');
62+
}
63+
64+
const buffers: Record<string, Buffer | Blob> = {};
65+
await enumZipEntries(this.file, async (entry, zipFile) => {
66+
if (entry.fileName.endsWith('/')) {
67+
return;
68+
}
69+
70+
const entryName = decodeNullUnicode(entry.fileName).toString();
71+
const lowerEntryName = entryName.toLowerCase();
72+
const matched = decoded.find((pattern) => {
73+
if (typeof pattern === 'string') {
74+
return pattern === entryName || pattern === lowerEntryName;
75+
}
76+
pattern.lastIndex = 0;
77+
return pattern.test(lowerEntryName);
78+
});
79+
80+
if (!matched) {
81+
return;
82+
}
83+
84+
const buffer = await readEntry(entry, zipFile);
85+
buffers[matched as any] =
86+
type === 'blob' ? new Blob([buffer as any]) : buffer;
87+
});
88+
89+
return buffers;
90+
}
7491
}

tests/app-info-zip.test.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { afterEach, beforeEach, describe, expect, test } from 'bun:test';
2+
import fs from 'fs';
3+
import os from 'os';
4+
import path from 'path';
5+
import { ZipFile as YazlZipFile } from 'yazl';
6+
import { Zip } from '../src/utils/app-info-parser/zip';
7+
8+
function mkTempDir(prefix: string): string {
9+
return fs.mkdtempSync(path.join(os.tmpdir(), prefix));
10+
}
11+
12+
async function writeZip(
13+
zipPath: string,
14+
entries: Record<string, string>,
15+
): Promise<void> {
16+
await new Promise<void>((resolve, reject) => {
17+
const zipFile = new YazlZipFile();
18+
for (const [name, content] of Object.entries(entries)) {
19+
zipFile.addBuffer(Buffer.from(content), name);
20+
}
21+
zipFile.outputStream.on('error', reject);
22+
zipFile.outputStream.pipe(fs.createWriteStream(zipPath)).on('close', () => {
23+
resolve();
24+
});
25+
zipFile.end();
26+
});
27+
}
28+
29+
describe('app-info-parser Zip', () => {
30+
let tempRoot = '';
31+
32+
beforeEach(() => {
33+
tempRoot = mkTempDir('rn-update-app-info-zip-');
34+
});
35+
36+
afterEach(() => {
37+
if (tempRoot && fs.existsSync(tempRoot)) {
38+
fs.rmSync(tempRoot, { recursive: true, force: true });
39+
}
40+
});
41+
42+
test('reads entries by regex and string with compatible keys', async () => {
43+
const zipPath = path.join(tempRoot, 'app.zip');
44+
await writeZip(zipPath, {
45+
'AndroidManifest.xml': 'manifest',
46+
'res/icon.png': 'icon',
47+
});
48+
49+
const manifestRegex = /^androidmanifest\.xml$/;
50+
const buffers = await new Zip(zipPath).getEntries([
51+
manifestRegex,
52+
'res/icon.png',
53+
]);
54+
55+
expect(Buffer.isBuffer(buffers[manifestRegex as any])).toBe(true);
56+
expect((buffers[manifestRegex as any] as Buffer).toString()).toBe(
57+
'manifest',
58+
);
59+
expect((buffers['res/icon.png'] as Buffer).toString()).toBe('icon');
60+
});
61+
});

0 commit comments

Comments
 (0)