import JSZip from 'jszip'; import colors from 'colors'; import { Log, formatBytes, logErrorAndExit } from '../core/index.js'; import { FileBinaryData, ZipCompressionLevel, ZipContext } from './file-processor.models.js'; interface IFileResult { data: T; filename: string; } export class ZipPackage { private readonly context: ZipContext = 'node.js'; private readonly compressionLevel: ZipCompressionLevel = 9; constructor(private readonly jsZip: JSZip, private readonly log: Log) {} addFile(filePath: string, data: any): void { this.jsZip.file(filePath, data); } addFolder(name: string): void { this.jsZip.folder(name); } async getAllFilesAsync(type: JSZip.OutputType): Promise[]> { const files: IFileResult[] = []; for (const file of Object.values(this.jsZip.files)) { if (!file?.name) { continue; } if (file?.name?.endsWith('/')) { continue; } files.push({ filename: file.name, data: await file.async(type) }); } return files; } async getFileContentAsync(filePath: string): Promise { return await this.jsZip.file(filePath)?.async('string'); } async getBinaryDataAsync(filePath: string): Promise { const binaryData = await this.jsZip.file(filePath)?.async(this.getZipOutputType(this.context)); return binaryData; } async generateZipAsync(): Promise { const zipOutputType = this.getZipOutputType(this.context); this.log.console({ type: 'info', message: `Creating zip file using '${zipOutputType}' with compression level '${this.compressionLevel.toString()}'` }); const result = await this.jsZip.generateAsync({ type: zipOutputType, compression: 'DEFLATE', compressionOptions: { level: this.compressionLevel }, streamFiles: true }); this.log.console({ type: 'info', message: `Zip successfully generated (${colors.yellow(formatBytes(this.getZipSizeInBytes(result)))})` }); return result; } private getZipOutputType(context: ZipContext): 'nodebuffer' | 'blob' { if (context === 'browser') { return 'blob'; } if (context === 'node.js') { return 'nodebuffer'; } logErrorAndExit({ message: `Unsupported context '${context}'` }); } private getZipSizeInBytes(zipData: any): number { if (zipData instanceof Blob) { return zipData.size; } else if (zipData instanceof Buffer) { return zipData.byteLength; } logErrorAndExit({ message: `Unrecognized zip data type '${typeof zipData}'` }); } }