// parser.mjs import { normDateStr, toUTCms } from '../../core/utils/dates.mjs'; import { cleanDoc, normTime } from '../../core/utils/docs.mjs'; /** * Parsea una línea con prioridad por TAB; si no hay, cae a espacios; * separa fecha/hora si vienen juntas. * Devuelve { doc, name, isoDate, time, dt_ms, mode } o null. */ export function parseLine(line) { const raw = String(line || '').replace(/\r/g, '').trim(); if (!raw) return null; // omitir encabezados comunes if (/^no[\t ]|^mchn[\t ]|^enno[\t ]|^name[\t ]|^datetime[\t ]/i.test(raw)) return null; let parts = raw.split(/\t+/); // Fallback: dos o más espacios + DateTime al final if (parts.length < 7) { const dtMatch = raw.match(/(\d{2,4}[\/-]\d{1,2}[\/-]\d{1,2})\s+(\d{1,2}:\d{2}:\d{2})$/); if (dtMatch) { const head = raw.slice(0, dtMatch.index).trim(); const headParts = head.split(/\t+|\s{2,}/).filter(Boolean); parts = [...headParts, dtMatch[1], dtMatch[2]]; } else { parts = raw.split(/\s{2,}/).filter(Boolean); } } if (parts.length < 7) return null; // Indices "normales": 0:No, 1:Mchn, 2:EnNo(doc), 3:Name, 4:Mode, 5:Fecha, 6:Hora const doc = cleanDoc(parts[2]); const name = String(parts[3] || '').trim(); const mode = String(parts[4] || '').trim(); let dateStr = String(parts[5] || '').trim(); let timeStr = String(parts[6] || '').trim(); // Caso: la última columna es "YYYY/MM/DD HH:MM:SS" const last = parts[parts.length - 1]; const dtBoth = /(\d{2,4}[\/-]\d{1,2}[\/-]\d{1,2})\s+(\d{1,2}:\d{2}:\d{2})/.exec(last); if (dtBoth) { dateStr = dtBoth[1]; timeStr = dtBoth[2]; } else if (!timeStr && /\d{1,2}:\d{2}:\d{2}/.test(dateStr)) { const m = dateStr.match(/^(.+?)\s+(\d{1,2}:\d{2}:\d{2})$/); if (m) { dateStr = m[1]; timeStr = m[2]; } } const iso = normDateStr(dateStr); const timeNorm = normTime(timeStr); if (!iso || !timeNorm) return null; return { doc, name, isoDate: iso, time: timeNorm, dt_ms: toUTCms(iso, timeNorm), mode }; }