-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathchain.ts
More file actions
104 lines (84 loc) · 3.26 KB
/
Copy pathchain.ts
File metadata and controls
104 lines (84 loc) · 3.26 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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/*
* Vencord, a Discord client mod
* Copyright (c) 2026 KernelSpecter
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import { Message } from "@vencord/discord-types";
import { MessageStore } from "@webpack/common";
import { ChainMode } from "./settings";
/**
* A reply never expands into more than this many deletions. An unbounded walk can
* sweep up an unrelated conversation that happens to sit beside the reply.
*/
export const MAX_CHAIN = 25;
/** MessageStore.getMessage is typed as always returning a Message. It does not. */
export function getMessage(channelId: string, messageId: string): Message | undefined {
try {
return MessageStore.getMessage(channelId, messageId) ?? undefined;
} catch {
return undefined;
}
}
function cachedMessages(channelId: string): Message[] {
try {
return MessageStore.getMessages(channelId)?._array ?? [];
} catch {
return [];
}
}
/**
* The run of consecutive messages by you that `rootId` belongs to, stopping dead at
* the first message by anyone else in either direction. This is what "delete the
* whole burst" should have meant.
*/
export function collectBurst(channelId: string, rootId: string, selfId: string): Message[] {
const all = cachedMessages(channelId);
const index = all.findIndex(m => m.id === rootId);
if (index === -1) {
const only = getMessage(channelId, rootId);
return only?.author?.id === selfId ? [only] : [];
}
// If the root is not yours, there is no burst of yours to collect. Without this the
// walk would step straight past it and sweep up whoever's messages sit either side.
if (all[index].author?.id !== selfId) return [];
const run: Message[] = [];
for (let i = index; i >= 0 && run.length < MAX_CHAIN; i--) {
if (all[i].author?.id !== selfId) break;
run.unshift(all[i]);
}
for (let i = index + 1; i < all.length && run.length < MAX_CHAIN; i++) {
if (all[i].author?.id !== selfId) break;
run.push(all[i]);
}
return run;
}
/**
* `rootId` plus the messages it was itself replying to, following message_reference
* upward while the author is still you and the reference stays in this channel.
*/
export function collectReplyLineage(channelId: string, rootId: string, selfId: string): Message[] {
const seen = new Set<string>();
const lineage: Message[] = [];
let cursor: string | undefined = rootId;
while (cursor && lineage.length < MAX_CHAIN && !seen.has(cursor)) {
seen.add(cursor);
const message = getMessage(channelId, cursor);
if (!message || message.author?.id !== selfId) break;
lineage.push(message);
const reference = message.messageReference;
cursor = reference?.channel_id === channelId ? reference.message_id : undefined;
}
return lineage;
}
export function expandTrigger(mode: ChainMode, channelId: string, rootId: string, selfId: string): Message[] {
switch (mode) {
case "burst":
return collectBurst(channelId, rootId, selfId);
case "chain":
return collectReplyLineage(channelId, rootId, selfId);
default: {
const only = getMessage(channelId, rootId);
return only?.author?.id === selfId ? [only] : [];
}
}
}