Repository navigation
Expand file tree
/
Copy pathpullRequestFilesViewed.logic.ts
More file actions
65 lines (56 loc) · 2.17 KB
/
Copy pathpullRequestFilesViewed.logic.ts
File metadata and controls
65 lines (56 loc) · 2.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import type { PullRequestFileViewedState, PullRequestFilesViewedResult } from "@t3tools/contracts";
export type FileViewedStates = ReadonlyMap<string, PullRequestFileViewedState>;
export type FileViewedOverlay = ReadonlyMap<string, boolean>;
export function toFileViewedStates(
result: PullRequestFilesViewedResult | null,
): FileViewedStates | null {
if (result === null) return null;
return new Map(result.files.map((file) => [file.path, file.state]));
}
function isViewedState(state: PullRequestFileViewedState | undefined): boolean {
return state === "viewed";
}
export function isStaleViewedState(state: PullRequestFileViewedState | undefined): boolean {
return state === "dismissed";
}
export function isFileViewed(
path: string,
states: FileViewedStates | null,
overlay: FileViewedOverlay,
): boolean {
const pressed = overlay.get(path);
return pressed ?? isViewedState(states?.get(path));
}
/** Retain presses until a read could have observed the write. */
export function settleFileViewedOverlay(
overlay: FileViewedOverlay,
states: FileViewedStates | null,
pending: ReadonlySet<string>,
answered: ReadonlySet<string>,
): FileViewedOverlay {
if (states === null || overlay.size === 0) return overlay;
const next = new Map(overlay);
for (const [path, pressed] of overlay) {
if (pending.has(path)) continue;
if (answered.has(path) || isViewedState(states.get(path)) === pressed) next.delete(path);
}
return next.size === overlay.size ? overlay : next;
}
/** Revert only owned paths; later presses belong to other requests. */
export function revertFileViewedOverlay(
overlay: FileViewedOverlay,
batch: ReadonlyArray<{ readonly path: string; readonly viewed: boolean }>,
owned: ReadonlySet<string>,
): FileViewedOverlay {
const next = new Map(overlay);
for (const { path, viewed } of batch) {
if (!owned.has(path)) continue;
if (next.get(path) === viewed) next.delete(path);
}
return next.size === overlay.size ? overlay : next;
}
export function toFileViewedBatch(
overlay: FileViewedOverlay,
): ReadonlyArray<{ readonly path: string; readonly viewed: boolean }> {
return [...overlay].map(([path, viewed]) => ({ path, viewed }));
}