UNPKG

@elephant-xyz/cli

Version:
137 lines 5.13 kB
import { createWriteStream } from 'fs'; import { dirname } from 'path'; import { mkdir } from 'fs/promises'; export class CsvReporterService { errorCsvPath; warningCsvPath; errorStream = null; warningStream = null; errorCount = 0; warningCount = 0; startTime; constructor(errorCsvPath, warningCsvPath) { this.errorCsvPath = errorCsvPath; this.warningCsvPath = warningCsvPath; this.startTime = new Date(); } async initialize() { await this.ensureDirectoriesExist(); // Initialize CSV streams and write headers, awaiting write completion this.errorStream = createWriteStream(this.errorCsvPath, { flags: 'w' }); await new Promise((resolve, reject) => { this.errorStream.write('property_cid,data_group_cid,file_path,error_path,error_message,timestamp\n', (err) => (err ? reject(err) : resolve())); }); this.warningStream = createWriteStream(this.warningCsvPath, { flags: 'w' }); await new Promise((resolve, reject) => { this.warningStream.write('property_cid,data_group_cid,file_path,reason,timestamp\n', (err) => (err ? reject(err) : resolve())); }); } async ensureDirectoriesExist() { const errorDir = dirname(this.errorCsvPath); const warningDir = dirname(this.warningCsvPath); await mkdir(errorDir, { recursive: true }); if (warningDir !== errorDir) { await mkdir(warningDir, { recursive: true }); } } async logError(entry) { if (!this.errorStream) { throw new Error('CSV reporter not initialized. Call initialize() first.'); } const escapedErrorPath = this.escapeCsvValue(entry.errorPath); const escapedErrorMessage = this.escapeCsvValue(entry.errorMessage); const escapedFilePath = this.escapeCsvValue(entry.filePath); const csvLine = `${entry.propertyCid},${entry.dataGroupCid},${escapedFilePath},${escapedErrorPath},${escapedErrorMessage},${entry.timestamp}\n`; return new Promise((resolve, reject) => { this.errorStream.write(csvLine, (error) => { if (error) { reject(error); } else { this.errorCount++; resolve(); } }); }); } async logWarning(entry) { if (!this.warningStream) { throw new Error('CSV reporter not initialized. Call initialize() first.'); } const escapedReason = this.escapeCsvValue(entry.reason); const escapedFilePath = this.escapeCsvValue(entry.filePath); const csvLine = `${entry.propertyCid},${entry.dataGroupCid},${escapedFilePath},${escapedReason},${entry.timestamp}\n`; return new Promise((resolve, reject) => { this.warningStream.write(csvLine, (error) => { if (error) { reject(error); } else { this.warningCount++; resolve(); } }); }); } escapeCsvValue(value) { // Escape double quotes by doubling them const escaped = value.replace(/"/g, '""'); // Wrap in quotes if contains comma, newline, or quotes if (escaped.includes(',') || escaped.includes('\n') || escaped.includes('"')) { return `"${escaped}"`; } return escaped; } async finalize() { const endTime = new Date(); // Close streams await this.closeStreams(); const summary = { totalFiles: 0, // Will be set by caller processedFiles: 0, // Will be set by caller errorCount: this.errorCount, warningCount: this.warningCount, uploadedFiles: 0, // Will be set by caller submittedBatches: 0, // Will be set by caller startTime: this.startTime, endTime, duration: endTime.getTime() - this.startTime.getTime(), }; return summary; } async closeStreams() { const promises = []; if (this.errorStream) { promises.push(new Promise((resolve, reject) => { this.errorStream.end((error) => { if (error) reject(error); else resolve(); }); })); } if (this.warningStream) { promises.push(new Promise((resolve, reject) => { this.warningStream.end((error) => { if (error) reject(error); else resolve(); }); })); } await Promise.all(promises); this.errorStream = null; this.warningStream = null; } getErrorCount() { return this.errorCount; } getWarningCount() { return this.warningCount; } } //# sourceMappingURL=csv-reporter.service.js.map