Archived
48 lines
1.8 KiB
TypeScript
48 lines
1.8 KiB
TypeScript
export interface SessionArchiveTreeCandidate {
|
|
id: string;
|
|
path: string;
|
|
archived: boolean;
|
|
parentSessionPath?: string;
|
|
}
|
|
|
|
export interface SessionArchiveTreePlan<T extends SessionArchiveTreeCandidate> {
|
|
targets: T[];
|
|
unarchivedTargets: T[];
|
|
skippedAlreadyArchivedCount: number;
|
|
}
|
|
|
|
export function findArchiveCandidateByIdOrPrefix<T extends SessionArchiveTreeCandidate>(candidates: readonly T[], sessionId: string): T | undefined {
|
|
return candidates.find((candidate) => candidate.id === sessionId) ?? candidates.find((candidate) => candidate.id.startsWith(sessionId));
|
|
}
|
|
|
|
export function planSessionArchiveTree<T extends SessionArchiveTreeCandidate>(root: T, candidates: readonly T[]): SessionArchiveTreePlan<T> {
|
|
const targets = sessionArchiveSubtree(root, candidates);
|
|
const unarchivedTargets = targets.filter((target) => !target.archived);
|
|
return {
|
|
targets,
|
|
unarchivedTargets,
|
|
skippedAlreadyArchivedCount: targets.length - unarchivedTargets.length,
|
|
};
|
|
}
|
|
|
|
function sessionArchiveSubtree<T extends SessionArchiveTreeCandidate>(root: T, candidates: readonly T[]): T[] {
|
|
const childrenByParentPath = new Map<string, T[]>();
|
|
for (const candidate of candidates) {
|
|
if (candidate.parentSessionPath === undefined) continue;
|
|
const children = childrenByParentPath.get(candidate.parentSessionPath) ?? [];
|
|
children.push(candidate);
|
|
childrenByParentPath.set(candidate.parentSessionPath, children);
|
|
}
|
|
|
|
const result: T[] = [];
|
|
const visit = (candidate: T, seenPaths: Set<string>) => {
|
|
if (seenPaths.has(candidate.path)) return;
|
|
result.push(candidate);
|
|
const nextSeenPaths = new Set(seenPaths);
|
|
nextSeenPaths.add(candidate.path);
|
|
for (const child of childrenByParentPath.get(candidate.path) ?? []) visit(child, nextSeenPaths);
|
|
};
|
|
visit(root, new Set());
|
|
return result;
|
|
}
|