





















@@ -14,6 +14,31 @@ type SlackResolvedMessageContent = {
1414const SLACK_MENTION_RESOLUTION_CONCURRENCY = 4;
1515const SLACK_MENTION_RESOLUTION_MAX_LOOKUPS_PER_MESSAGE = 20;
161617+type SlackTextObject = {
18+text?: unknown;
19+};
20+21+type SlackRichTextElement = {
22+type?: unknown;
23+text?: unknown;
24+url?: unknown;
25+user_id?: unknown;
26+channel_id?: unknown;
27+usergroup_id?: unknown;
28+name?: unknown;
29+range?: unknown;
30+elements?: unknown;
31+};
32+33+type SlackBlockLike = {
34+type?: unknown;
35+text?: unknown;
36+elements?: unknown;
37+fields?: unknown;
38+alt_text?: unknown;
39+title?: unknown;
40+};
41+1742type SlackMediaModule = typeof import("../media.js");
1843let slackMediaModulePromise: Promise<SlackMediaModule> | undefined;
1944@@ -54,6 +79,152 @@ function renderSlackUserMentions(
5479});
5580}
568182+function readString(value: unknown): string | undefined {
83+return typeof value === "string" ? value : undefined;
84+}
85+86+function readTextObject(value: unknown): string | undefined {
87+if (!value || typeof value !== "object") {
88+return undefined;
89+}
90+return normalizeOptionalString(readString((value as SlackTextObject).text));
91+}
92+93+function renderSlackRichTextLeaf(element: SlackRichTextElement): string {
94+switch (element.type) {
95+case "text":
96+return readString(element.text) ?? "";
97+case "link":
98+return readString(element.text) ?? readString(element.url) ?? "";
99+case "user": {
100+const userId = readString(element.user_id);
101+return userId ? `<@${userId}>` : "";
102+}
103+case "channel": {
104+const channelId = readString(element.channel_id);
105+return channelId ? `<#${channelId}>` : "";
106+}
107+case "usergroup": {
108+const usergroupId = readString(element.usergroup_id);
109+return usergroupId ? `<!subteam^${usergroupId}>` : "";
110+}
111+case "broadcast": {
112+const range = readString(element.range);
113+return range ? `<!${range}>` : "";
114+}
115+case "emoji": {
116+const name = readString(element.name);
117+return name ? `:${name}:` : "";
118+}
119+default:
120+return "";
121+}
122+}
123+124+function renderSlackRichTextElements(elements: unknown): string {
125+if (!Array.isArray(elements)) {
126+return "";
127+}
128+const parts: string[] = [];
129+for (const rawElement of elements) {
130+if (!rawElement || typeof rawElement !== "object") {
131+continue;
132+}
133+const element = rawElement as SlackRichTextElement;
134+switch (element.type) {
135+case "rich_text_section":
136+case "rich_text_preformatted":
137+case "rich_text_quote": {
138+parts.push(renderSlackRichTextElements(element.elements));
139+break;
140+}
141+case "rich_text_list": {
142+const listText = Array.isArray(element.elements)
143+ ? element.elements
144+.map((child) =>
145+child && typeof child === "object"
146+ ? renderSlackRichTextElements((child as SlackRichTextElement).elements)
147+ : "",
148+)
149+.filter(Boolean)
150+.join("\n")
151+ : "";
152+parts.push(listText);
153+break;
154+}
155+default:
156+parts.push(renderSlackRichTextLeaf(element));
157+break;
158+}
159+}
160+return parts.join("");
161+}
162+163+function readSlackBlockText(block: unknown): string | undefined {
164+if (!block || typeof block !== "object") {
165+return undefined;
166+}
167+const blockLike = block as SlackBlockLike;
168+switch (blockLike.type) {
169+case "rich_text":
170+return normalizeOptionalString(renderSlackRichTextElements(blockLike.elements));
171+case "section": {
172+const text = readTextObject(blockLike.text);
173+if (text) {
174+return text;
175+}
176+if (Array.isArray(blockLike.fields)) {
177+const fields = blockLike.fields.map(readTextObject).filter(Boolean);
178+return fields.length > 0 ? fields.join("\n") : undefined;
179+}
180+return undefined;
181+}
182+case "header":
183+return readTextObject(blockLike.text);
184+case "context": {
185+if (!Array.isArray(blockLike.elements)) {
186+return undefined;
187+}
188+const parts = blockLike.elements.map(readTextObject).filter(Boolean);
189+return parts.length > 0 ? parts.join(" ") : undefined;
190+}
191+case "image":
192+return (
193+normalizeOptionalString(readString(blockLike.alt_text)) ?? readTextObject(blockLike.title)
194+);
195+case "video":
196+return (
197+readTextObject(blockLike.title) ?? normalizeOptionalString(readString(blockLike.alt_text))
198+);
199+default:
200+return undefined;
201+}
202+}
203+204+function resolveSlackBlocksText(blocks: unknown[] | undefined): string | undefined {
205+if (!blocks?.length) {
206+return undefined;
207+}
208+const parts = blocks.map(readSlackBlockText).filter(Boolean);
209+return parts.length > 0 ? parts.join("\n") : undefined;
210+}
211+212+function chooseSlackPrimaryText(params: {
213+messageText: string | undefined;
214+blocksText: string | undefined;
215+}): string | undefined {
216+const { messageText, blocksText } = params;
217+if (!blocksText) {
218+return messageText;
219+}
220+if (!messageText) {
221+return blocksText;
222+}
223+return blocksText.length > messageText.length && blocksText.startsWith(messageText)
224+ ? blocksText
225+ : messageText;
226+}
227+57228function filterInheritedParentFiles(params: {
58229files: SlackFile[] | undefined;
59230isThreadReply: boolean;
@@ -143,11 +314,12 @@ export async function resolveSlackMessageContent(params: {
143314.join("\n")
144315 : undefined;
145316146-const textParts = [
147-normalizeOptionalString(params.message.text),
148-attachmentContent?.text,
149-botAttachmentText,
150-];
317+const blocksText = resolveSlackBlocksText(params.message.blocks);
318+const primaryText = chooseSlackPrimaryText({
319+messageText: normalizeOptionalString(params.message.text),
320+ blocksText,
321+});
322+const textParts = [primaryText, attachmentContent?.text, botAttachmentText];
151323const renderedMentions = new Map<string, string | null>();
152324const resolveUserName = params.resolveUserName;
153325if (resolveUserName) {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。