feat(archive): introduce ts_shared browser-compatible layer, refactor Node-specific tools to wrap/shared implementations, and modernize archive handling
This commit is contained in:
89
ts_shared/classes.tartools.ts
Normal file
89
ts_shared/classes.tartools.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import * as plugins from './plugins.js';
|
||||
import type { IArchiveEntry, ITarEntry, TCompressionLevel } from './interfaces.js';
|
||||
import { GzipTools } from './classes.gziptools.js';
|
||||
|
||||
/**
|
||||
* TAR archive creation and extraction utilities using modern-tar (browser-compatible)
|
||||
*/
|
||||
export class TarTools {
|
||||
/**
|
||||
* Pack files into a TAR buffer
|
||||
*/
|
||||
public async packFiles(files: IArchiveEntry[]): Promise<Uint8Array> {
|
||||
const entries: ITarEntry[] = [];
|
||||
|
||||
for (const file of files) {
|
||||
let data: Uint8Array;
|
||||
|
||||
if (typeof file.content === 'string') {
|
||||
data = new TextEncoder().encode(file.content);
|
||||
} else if (file.content instanceof Uint8Array) {
|
||||
data = file.content;
|
||||
} else if (file.content instanceof plugins.smartfile.SmartFile) {
|
||||
data = new Uint8Array(file.content.contents);
|
||||
} else if (file.content instanceof plugins.smartfile.StreamFile) {
|
||||
const buffer = await file.content.getContentAsBuffer();
|
||||
data = new Uint8Array(buffer);
|
||||
} else {
|
||||
throw new Error('Unsupported content type for TAR entry');
|
||||
}
|
||||
|
||||
entries.push({
|
||||
header: {
|
||||
name: file.archivePath,
|
||||
size: data.length,
|
||||
type: 'file',
|
||||
mode: file.mode,
|
||||
mtime: file.mtime,
|
||||
},
|
||||
body: data,
|
||||
});
|
||||
}
|
||||
|
||||
return plugins.modernTar.packTar(entries);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract a TAR buffer to an array of entries
|
||||
*/
|
||||
public async extractTar(data: Uint8Array): Promise<Array<{ path: string; content: Uint8Array; isDirectory: boolean }>> {
|
||||
const entries = await plugins.modernTar.unpackTar(data);
|
||||
const result: Array<{ path: string; content: Uint8Array; isDirectory: boolean }> = [];
|
||||
|
||||
for (const entry of entries) {
|
||||
const isDirectory = entry.header.type === 'directory' || entry.header.name.endsWith('/');
|
||||
|
||||
// modern-tar uses 'data' property, not 'body'
|
||||
const content = entry.data ?? new Uint8Array(0);
|
||||
|
||||
result.push({
|
||||
path: entry.header.name,
|
||||
content,
|
||||
isDirectory,
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pack files into a TAR.GZ buffer
|
||||
*/
|
||||
public async packFilesToTarGz(
|
||||
files: IArchiveEntry[],
|
||||
compressionLevel?: TCompressionLevel
|
||||
): Promise<Uint8Array> {
|
||||
const tarBuffer = await this.packFiles(files);
|
||||
const gzipTools = new GzipTools();
|
||||
return gzipTools.compress(tarBuffer, compressionLevel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract a TAR.GZ buffer to an array of entries
|
||||
*/
|
||||
public async extractTarGz(data: Uint8Array): Promise<Array<{ path: string; content: Uint8Array; isDirectory: boolean }>> {
|
||||
const gzipTools = new GzipTools();
|
||||
const tarBuffer = await gzipTools.decompress(data);
|
||||
return this.extractTar(tarBuffer);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user