/** * Work Order Report Parser * * Parses the TXT work order status reports from TS-XX/Reports/ folders. * * Format: * =================================================================== * WO#: 179257 * Date: 03-27-2026 * Work order status file for work order #: 179257 * Program: TEST8B1D.EXE * Version: B.19 2023.08.02 JL * Lib. Ver.: B.09 2019.02.08 MR * ------------------------------------------------------------------- * Status Serial# DS File Name Model Date Time * -------- --------- ------------ ------------- ---------- -------- * PASS 179257-1 H9257-1.TXT 8B47K-05 03-27-2026 10:25:56 * FAIL<<<< 179257-12 8B47K-05 03-27-2026 11:01:09 * ... */ const fs = require('fs'); const path = require('path'); /** * Extract test station from file path (e.g., C:\Shares\test\TS-4L\Reports\179257.TXT -> TS-4L) */ function extractStation(filePath) { const match = filePath.match(/[\\\/](TS-[^\\\/]+)[\\\/]/i); return match ? match[1].toUpperCase() : null; } /** * Extract work order number from filename (e.g., 179257.TXT -> 179257) */ function extractWoFromFilename(filePath) { const base = path.basename(filePath, path.extname(filePath)); return base; } /** * Parse a work order report TXT file * @param {string} filePath - Path to the report file * @returns {object} Parsed work order with header and lines */ function parseWoReport(filePath) { const content = fs.readFileSync(filePath, 'utf8'); const lines = content.split(/\r?\n/); const result = { wo_number: null, wo_date: null, program: null, version: null, lib_version: null, station: extractStation(filePath), source_file: filePath, lines: [], // test result lines ds_files: [], // datasheet files listed at bottom }; let inHeader = true; let inDsList = false; for (const line of lines) { const t = line.trim(); // Parse header fields const woMatch = t.match(/^WO#:\s*(\S+)/); if (woMatch) { result.wo_number = woMatch[1]; continue; } const dateMatch = t.match(/^Date:\s*(\d{2}-\d{2}-\d{4})/); if (dateMatch) { const [month, day, year] = dateMatch[1].split('-'); result.wo_date = `${year}-${month}-${day}`; continue; } const progMatch = t.match(/^Program:\s*(\S+)/); if (progMatch) { result.program = progMatch[1]; continue; } const verMatch = t.match(/^Version:\s*(.+)/); if (verMatch) { result.version = verMatch[1].trim(); continue; } const libMatch = t.match(/^Lib\. Ver\.:\s*(.+)/); if (libMatch) { result.lib_version = libMatch[1].trim(); continue; } // Detect separator lines if (t.match(/^-{20,}$/)) { inHeader = false; continue; } // Skip header row if (t.startsWith('Status') && t.includes('Serial#')) continue; // Detect datasheet file list section if (t.includes('datasheet files actually created')) { inDsList = true; continue; } if (inDsList) { if (t.match(/^-+$/)) continue; if (t.match(/^\S+\.TXT$/i)) { result.ds_files.push(t); } continue; } // Parse test result lines // PASS 179257-1 H9257-1.TXT 8B47K-05 03-27-2026 10:25:56 // FAIL<<<< 179257-12 8B47K-05 03-27-2026 11:01:09 if (!inHeader && t.length > 0) { const passMatch = t.match(/^(PASS)\s+(\S+)\s+(\S+\.TXT)\s+(\S+)\s+(\d{2}-\d{2}-\d{4})\s+(\d{2}:\d{2}:\d{2})/i); const failMatch = t.match(/^(FAIL[<]*)\s+(\S+)\s+(\S+)\s+(\d{2}-\d{2}-\d{4})\s+(\d{2}:\d{2}:\d{2})/i); if (passMatch) { const [, status, serial, dsFile, model, date, time] = passMatch; const [month, day, year] = date.split('-'); result.lines.push({ status: 'PASS', serial_number: serial, ds_filename: dsFile, model_number: model, test_date: `${year}-${month}-${day}`, test_time: time, }); } else if (failMatch) { const [, status, serial, model, date, time] = failMatch; const [month, day, year] = date.split('-'); result.lines.push({ status: 'FAIL', serial_number: serial, ds_filename: null, model_number: model, test_date: `${year}-${month}-${day}`, test_time: time, }); } } } // Fall back to filename for WO# if not found in content if (!result.wo_number) { result.wo_number = extractWoFromFilename(filePath); } return result; } module.exports = { parseWoReport, extractStation, extractWoFromFilename };