Skip to content

Commit ca5816e

Browse files
sunnylqmclaude
andauthored
feat: print parse* results as JSON without the bundle bytes (#100)
parseApk / parseIpa / parseApp / parseAab now print the package info as pretty JSON and drop the raw bundleFile Buffer, so the bundleHash content fingerprint is easy to read and copy. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
1 parent b86803b commit ca5816e

2 files changed

Lines changed: 56 additions & 4 deletions

File tree

‎src/package.ts‎

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,15 @@ import { t } from './utils/i18n';
2727
import { getBooleanOption, getStringListOption } from './utils/options';
2828
import { bundleLocationFields, locateZipEntry } from './utils/zip-range';
2929

30+
// parse* output is JSON so the bundleHash (content fingerprint) can be piped
31+
// into jq; the raw bundle bytes are dropped — a Buffer preview is just noise.
32+
function printPackageInfo({
33+
bundleFile: _bundleFile,
34+
...info
35+
}: Record<string, unknown>) {
36+
console.log(JSON.stringify(info, null, 2));
37+
}
38+
3039
type PackageCommandOptions = Record<string, unknown> & {
3140
appId?: string;
3241
appKey?: string;
@@ -386,28 +395,28 @@ export const packageCommands = {
386395
if (!fn?.endsWith('.app')) {
387396
throw new Error(t('usageParseApp'));
388397
}
389-
console.log(await getAppInfo(fn));
398+
printPackageInfo(await getAppInfo(fn));
390399
},
391400
parseIpa: async ({ args }: { args: string[] }) => {
392401
const fn = args[0];
393402
if (!fn?.endsWith('.ipa')) {
394403
throw new Error(t('usageParseIpa'));
395404
}
396-
console.log(await getIpaInfo(fn));
405+
printPackageInfo(await getIpaInfo(fn));
397406
},
398407
parseApk: async ({ args }: { args: string[] }) => {
399408
const fn = args[0];
400409
if (!fn?.endsWith('.apk')) {
401410
throw new Error(t('usageParseApk'));
402411
}
403-
console.log(await getApkInfo(fn));
412+
printPackageInfo(await getApkInfo(fn));
404413
},
405414
parseAab: async ({ args }: { args: string[] }) => {
406415
const fn = args[0];
407416
if (!fn?.endsWith('.aab')) {
408417
throw new Error(t('usageParseAab'));
409418
}
410-
console.log(await getAabInfo(fn));
419+
printPackageInfo(await getAabInfo(fn));
411420
},
412421
extractApk: async ({
413422
args,

‎tests/package.test.ts‎

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { afterEach, beforeEach, describe, expect, spyOn, test } from 'bun:test';
2+
import { createHash } from 'crypto';
23
import fs from 'fs';
34
import os from 'os';
45
import path from 'path';
@@ -179,6 +180,48 @@ describe('packageCommands native upload', () => {
179180
});
180181
});
181182

183+
describe('packageCommands parse*', () => {
184+
let tempDir: string;
185+
let consoleSpy: ReturnType<typeof spyOn>;
186+
187+
beforeEach(() => {
188+
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'rnu-parse-'));
189+
consoleSpy = spyOn(console, 'log').mockImplementation(() => {});
190+
});
191+
192+
afterEach(() => {
193+
consoleSpy.mockRestore();
194+
fs.rmSync(tempDir, { recursive: true, force: true });
195+
});
196+
197+
test('prints JSON with bundleHash and without the bundle bytes', async () => {
198+
const appPath = path.join(tempDir, 'demo.app');
199+
await createZip(appPath, {
200+
'resources/rawfile/bundle.harmony.js': 'console.log("hi");',
201+
'resources/rawfile/meta.json': JSON.stringify({
202+
versionName: '1.2.3',
203+
pushy_build_time: 1700000000000,
204+
}),
205+
'resources/rawfile/update.json': JSON.stringify({
206+
harmony: { appId: 7, appKey: 'k' },
207+
}),
208+
});
209+
210+
await packageCommands.parseApp({ args: [appPath] });
211+
212+
expect(consoleSpy).toHaveBeenCalledTimes(1);
213+
expect(JSON.parse(consoleSpy.mock.calls[0][0])).toEqual({
214+
versionName: '1.2.3',
215+
buildTime: 1700000000000,
216+
bundleHash: createHash('sha256')
217+
.update('console.log("hi");')
218+
.digest('hex'),
219+
appId: 7,
220+
appKey: 'k',
221+
});
222+
});
223+
});
224+
182225
describe('choosePackage', () => {
183226
afterEach(() => {
184227
global.NO_INTERACTIVE = undefined;

0 commit comments

Comments
 (0)