feat(archive): add tar and tar.gz converters

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-01 12:51:34 +02:00
co-authored by Claude Sonnet 5
parent d68694ead8
commit c9251e66e2
4 changed files with 127 additions and 2 deletions
+39
View File
@@ -3,6 +3,7 @@ import fs from 'node:fs/promises';
import path from 'node:path';
import os from 'node:os';
import AdmZip from 'adm-zip';
import * as tar from 'tar';
import { registerArchiveConverters, assertNoPathEscape } from '../../src/converters/archive.js';
import { resolve, listTargetFormats } from '../../src/converters/registry.js';
@@ -94,3 +95,41 @@ describe('archive converters — zip-slip protection', () => {
await expect(entry.convert(maliciousPath, outputPath)).rejects.toThrow(/escapes/);
});
});
describe('archive converters — tar / tar.gz', () => {
it('registers tar and tar.gz as targets for each other', () => {
expect(listTargetFormats('tar')).toContain('tar.gz');
expect(listTargetFormats('tar.gz')).toContain('tar');
});
it('converts zip -> tar, preserving nested paths and content', async () => {
const inputPath = path.join(tmpDir, 'for-tar.zip');
buildZipFixture(inputPath);
const outputPath = path.join(tmpDir, 'output.tar');
const entry = resolve('zip', 'tar');
await entry.convert(inputPath, outputPath);
const listDir = await fs.mkdtemp(path.join(os.tmpdir(), 'tar-check-'));
await tar.extract({ file: outputPath, cwd: listDir });
expect(await fs.readFile(path.join(listDir, 'hello.txt'), 'utf8')).toBe('hello world');
expect(await fs.readFile(path.join(listDir, 'nested', 'inner.txt'), 'utf8')).toBe('nested content');
await fs.rm(listDir, { recursive: true, force: true });
});
it('converts tar -> tar.gz and back to tar, preserving content', async () => {
const tarPath = path.join(tmpDir, 'roundtrip.tar');
await tar.create({ file: tarPath, cwd: srcFixtureDir }, ['hello.txt', 'nested']);
const gzPath = path.join(tmpDir, 'roundtrip.tar.gz');
await resolve('tar', 'tar.gz').convert(tarPath, gzPath, { quality: 9 });
const backToTarPath = path.join(tmpDir, 'roundtrip-back.tar');
await resolve('tar.gz', 'tar').convert(gzPath, backToTarPath);
const listDir = await fs.mkdtemp(path.join(os.tmpdir(), 'tar-gz-check-'));
await tar.extract({ file: backToTarPath, cwd: listDir });
expect(await fs.readFile(path.join(listDir, 'hello.txt'), 'utf8')).toBe('hello world');
await fs.rm(listDir, { recursive: true, force: true });
});
});