(
allMessages: Array<{ msg: MergerMessage; source: string; platform: string }>
)
| 116 | // ==================== Conflict detection ==================== |
| 117 | |
| 118 | export function detectConflictsInMessages( |
| 119 | allMessages: Array<{ msg: MergerMessage; source: string; platform: string }> |
| 120 | ): ConflictCheckResult { |
| 121 | const collidingIds = getCollidingPlatformIdsFromMessages(allMessages) |
| 122 | const conflicts: MergeConflict[] = [] |
| 123 | |
| 124 | const timeGroups = new Map<number, Array<{ msg: MergerMessage; source: string; platform: string }>>() |
| 125 | for (const item of allMessages) { |
| 126 | const ts = item.msg.timestamp |
| 127 | if (!timeGroups.has(ts)) timeGroups.set(ts, []) |
| 128 | timeGroups.get(ts)!.push(item) |
| 129 | } |
| 130 | |
| 131 | for (const [ts, items] of timeGroups) { |
| 132 | if (items.length < 2) continue |
| 133 | |
| 134 | const senderGroups = new Map<string, typeof items>() |
| 135 | for (const item of items) { |
| 136 | const sender = normalizePlatformId(item.msg.senderPlatformId, item.platform || 'unknown', collidingIds) |
| 137 | if (!senderGroups.has(sender)) senderGroups.set(sender, []) |
| 138 | senderGroups.get(sender)!.push(item) |
| 139 | } |
| 140 | |
| 141 | for (const [sender, senderItems] of senderGroups) { |
| 142 | if (senderItems.length < 2) continue |
| 143 | const sources = new Set(senderItems.map((it) => it.source)) |
| 144 | if (sources.size < 2) continue |
| 145 | |
| 146 | const contentGroups = new Map<string, typeof senderItems>() |
| 147 | for (const item of senderItems) { |
| 148 | const c = item.msg.content || '' |
| 149 | if (!contentGroups.has(c)) contentGroups.set(c, []) |
| 150 | contentGroups.get(c)!.push(item) |
| 151 | } |
| 152 | |
| 153 | if (contentGroups.size > 1) { |
| 154 | const entries = Array.from(contentGroups.entries()) |
| 155 | for (let i = 0; i < entries.length - 1; i++) { |
| 156 | for (let j = i + 1; j < entries.length; j++) { |
| 157 | const [c1, items1] = entries[i] |
| 158 | const [c2, items2] = entries[j] |
| 159 | const item1 = items1[0] |
| 160 | const item2 = items2.find((it) => it.source !== item1.source) |
| 161 | if (!item2) continue |
| 162 | if (isImageOnlyMessage(c1) && isImageOnlyMessage(c2)) continue |
| 163 | |
| 164 | conflicts.push({ |
| 165 | id: `conflict_${ts}_${sender}_${conflicts.length}`, |
| 166 | timestamp: ts, |
| 167 | sender: getDisplayName(item1.msg) || sender, |
| 168 | contentLength1: c1.length, |
| 169 | contentLength2: c2.length, |
| 170 | content1: c1, |
| 171 | content2: c2, |
| 172 | }) |
| 173 | } |
| 174 | } |
| 175 | } |
no test coverage detected