feat: remember project exclusions and merge selected people

This commit is contained in:
muena
2026-09-25 08:08:20 +02:00
parent 392db8601a
commit e7e21e9281
7 changed files with 366 additions and 38 deletions

View File

@@ -1,3 +1,7 @@
import type { PlaceholderMapping } from "../types";
import { whitelistKey } from "./project-whitelist";
import type { ProjectWhitelistEntry } from "./project-whitelist";
const SEPARATOR = "\n\n\n\n";
export const MAX_BATCH_CODEPOINTS = 24000;
@@ -64,3 +68,57 @@ export function groupReviewHits<T extends GroupableHit>(hits: T[]): ReviewGroup<
}
return [...groups.values()].sort((a, b) => a.type.localeCompare(b.type) || a.original.localeCompare(b.original));
}
export function withoutWhitelistedHits<T extends GroupableHit>(hits: T[], whitelist: ProjectWhitelistEntry[]): T[] {
const excluded = new Set(whitelist.map(whitelistKey));
return hits.filter((hit) => !excluded.has(whitelistKey(hit)));
}
export function withoutWhitelistedRules<T extends { type: string; value: string }>(
rules: T[], whitelist: ProjectWhitelistEntry[],
): T[] {
const excluded = new Set(whitelist.map(whitelistKey));
return rules.filter((rule) => !excluded.has(whitelistKey({ type: rule.type, original: rule.value })));
}
export function canonicalPerson(placeholder: string, merges: Record<string, string>): string {
const seen = new Set<string>();
let current = placeholder;
while (merges[current] && !seen.has(current)) {
seen.add(current);
current = merges[current];
}
return current;
}
export function mergePeople(merges: Record<string, string>, source: string, target: string): Record<string, string> {
const from = canonicalPerson(source, merges);
const into = canonicalPerson(target, merges);
if (from === into) return merges;
const next = { ...merges };
for (const person of new Set([...Object.keys(next), ...Object.values(next), from])) {
if (canonicalPerson(person, merges) === from && person !== into) next[person] = into;
}
delete next[into];
return next;
}
export function mappingForSelection(
preview: PlaceholderMapping, previous: PlaceholderMapping, accepted: GroupableHit[],
merges: Record<string, string>,
): PlaceholderMapping {
const keys = new Set([...Object.keys(previous), ...accepted.map((hit) => hit.placeholder)]);
const mapping: PlaceholderMapping = {};
for (const key of keys) {
const entry = preview[key] ?? previous[key];
if (entry) mapping[key] = { ...entry };
}
for (const [source, target] of Object.entries(merges)) {
const root = canonicalPerson(target, merges);
if (source === root || mapping[source]?.type !== "PERSON" || mapping[root]?.type !== "PERSON") {
throw new Error("Ungültige Personen-Zusammenführung.");
}
mapping[source] = { ...mapping[source], merged_into: root };
}
return mapping;
}