import { MatchableSource, MatchedPair, MatchedSources } from "./types"; import { groupEntriesByGroupId } from "./utils"; export function defaultMatchSources( expected: T[], actual: T[] ): MatchedSources { const expectedSourceById = new Map( expected.map((entry) => [entry.id, entry]) ); const actualSourceById = new Map(actual.map((entry) => [entry.id, entry])); const expectedSourceByGroupId = groupEntriesByGroupId(expected); const actualSourceByGroupId = groupEntriesByGroupId(actual); return { new: findNew( actual, expectedSourceById, expectedSourceByGroupId, actualSourceByGroupId ), removed: findRemoved( expected, actualSourceById, actualSourceByGroupId, expectedSourceByGroupId ), matching: findMatching( actual, expectedSourceById, expectedSourceByGroupId, actualSourceByGroupId ), }; } function findNew( actual: T[], expectedSourceById: Map, expectedSourceByGroupId: Map, actualSourceByGroupId: Map ): T[] { return actual.filter((entry) => { if (expectedSourceById.has(entry.id)) { return false; } // Fallback on groupId matching const matchingExpectedGroupIds = expectedSourceByGroupId.get(entry.groupId); const matchingActualGroupIds = actualSourceByGroupId.get(entry.groupId); if ( matchingExpectedGroupIds?.length === 1 && matchingActualGroupIds?.length === 1 ) { return false; } return true; }); } export function findRemoved( expected: T[], actualSourceById: Map, actualSourceByGroupId: Map, expectedSourceByGroupId: Map ): T[] { return expected.filter((entry) => { if (actualSourceById.has(entry.id)) { return false; } // Fallback on groupId matching const matchingExpectedGroupIds = expectedSourceByGroupId.get(entry.groupId); const matchingActualGroupIds = actualSourceByGroupId.get(entry.groupId); if ( matchingExpectedGroupIds?.length === 1 && matchingActualGroupIds?.length === 1 ) { return false; } return true; }); } export function findMatching( actual: T[], expectedSourceById: Map, expectedSourceByGroupId: Map, actualSourceByGroupId: Map ): MatchedPair[] { const pairs: MatchedPair[] = []; for (const entry of actual) { if (expectedSourceById.has(entry.id)) { pairs.push({ expected: expectedSourceById.get(entry.id)!, actual: entry, }); continue; } // Fallback on groupId matching const matchingExpectedGroupIds = expectedSourceByGroupId.get(entry.groupId); const matchingActualGroupIds = actualSourceByGroupId.get(entry.groupId); if ( matchingExpectedGroupIds?.length === 1 && matchingActualGroupIds?.length === 1 ) { pairs.push({ expected: matchingExpectedGroupIds[0], actual: entry, }); } } return pairs; }