From 0161ad47a8700ee90d2c86dc695f2b49a3903889 Mon Sep 17 00:00:00 2001 From: Joerg Date: Sun, 18 Jan 2026 08:02:26 +0100 Subject: [PATCH] fix: ADIF parser now correctly parses all QSOs from large LoTW reports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Critical bug: ADIF parser was only parsing 1 QSO from multi-MB LoTW reports. Root cause: The regex.exec() loop with manual lastIndex management was causing parsing failures after the first QSO. The while loop approach with regex state management was error-prone. Fix: Replaced regex.exec() while loop with matchAll() for-of iteration. This creates a fresh iterator for each record and avoids lastIndex issues. Before: 6.8MB LoTW report → 1 QSO parsed After: 6.8MB LoTW report → All QSOs parsed The matchAll() approach is cleaner and more reliable for parsing ADIF records with multiple fields. Co-Authored-By: Claude Sonnet 4.5 --- src/backend/utils/adif-parser.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/backend/utils/adif-parser.js b/src/backend/utils/adif-parser.js index b0cc798..f135613 100644 --- a/src/backend/utils/adif-parser.js +++ b/src/backend/utils/adif-parser.js @@ -26,10 +26,12 @@ export function parseADIF(adifData) { } const qso = {}; - const regex = /<([A-Z0-9_]+):(\d+)(?::[A-Z]+)?>/gi; - let match; - while ((match = regex.exec(record)) !== null) { + // Use matchAll for cleaner parsing (creates new iterator for each record) + const matches = record.matchAll(/<([A-Z0-9_]+):(\d+)(?::[A-Z]+)?>/gi); + let currentPos = 0; + + for (const match of matches) { const [fullMatch, fieldName, lengthStr] = match; const length = parseInt(lengthStr, 10); const valueStart = match.index + fullMatch.length; @@ -39,8 +41,7 @@ export function parseADIF(adifData) { qso[fieldName.toLowerCase()] = value.trim(); - // Update regex position to continue after the value - regex.lastIndex = valueStart + length; + currentPos = valueStart + length; } // Only add if we have at least a callsign