function mergeChecklistConflict({ baseBody, localBody, remoteBody }) { const taskPattern = /^(\s*[-*+]\s+\[)([ xX])(\]\s+)(.*)$/; function tasks(body) { const entries = []; String(body || '').split('\n').forEach((line, lineIndex) => { const match = line.match(taskPattern); if (!match) return; const label = match[4].trim(); const key = label.replace(/\s+/g, ' ').toLocaleLowerCase(); if (!key) return; entries.push({ key, label, checked: match[2].toLowerCase() === 'x', lineIndex, match }); }); return entries; } function grouped(entries) { const result = new Map(); entries.forEach(entry => result.set(entry.key, [...(result.get(entry.key) || []), entry])); return result; } const base = grouped(tasks(baseBody)); const local = grouped(tasks(localBody)); const remoteEntries = tasks(remoteBody); const remote = grouped(remoteEntries); const changes = []; const conflicts = []; for (const [key, baseMatches] of base) { const localMatches = local.get(key) || []; if (baseMatches.length !== 1 || localMatches.length !== 1) continue; if (baseMatches[0].checked === localMatches[0].checked) continue; const remoteMatches = remote.get(key) || []; if (remoteMatches.length !== 1) { conflicts.push({ label: baseMatches[0].label, reason: remoteMatches.length ? 'ambiguous' : 'missing', }); continue; } changes.push({ label: remoteMatches[0].label, checked: localMatches[0].checked }); } if (conflicts.length) return { body: null, changes, conflicts }; const desired = new Map(changes.map(change => [ change.label.replace(/\s+/g, ' ').toLocaleLowerCase(), change.checked, ])); const lines = String(remoteBody || '').split('\n'); remoteEntries.forEach(entry => { if (!desired.has(entry.key)) return; const marker = desired.get(entry.key) ? 'x' : ' '; lines[entry.lineIndex] = entry.match[1] + marker + entry.match[3] + entry.match[4]; }); return { body: lines.join('\n'), changes, conflicts: [] }; } if (typeof module !== 'undefined') module.exports = mergeChecklistConflict;