Files
clawdbot/extensions/msteams/src/attachments/html.ts
2026-01-16 02:59:43 +00:00

77 lines
2.4 KiB
TypeScript

import {
ATTACHMENT_TAG_RE,
extractHtmlFromAttachment,
extractInlineImageCandidates,
IMG_SRC_RE,
isLikelyImageAttachment,
safeHostForUrl,
} from "./shared.js";
import type { MSTeamsAttachmentLike, MSTeamsHtmlAttachmentSummary } from "./types.js";
export function summarizeMSTeamsHtmlAttachments(
attachments: MSTeamsAttachmentLike[] | undefined,
): MSTeamsHtmlAttachmentSummary | undefined {
const list = Array.isArray(attachments) ? attachments : [];
if (list.length === 0) return undefined;
let htmlAttachments = 0;
let imgTags = 0;
let dataImages = 0;
let cidImages = 0;
const srcHosts = new Set<string>();
let attachmentTags = 0;
const attachmentIds = new Set<string>();
for (const att of list) {
const html = extractHtmlFromAttachment(att);
if (!html) continue;
htmlAttachments += 1;
IMG_SRC_RE.lastIndex = 0;
let match: RegExpExecArray | null = IMG_SRC_RE.exec(html);
while (match) {
imgTags += 1;
const src = match[1]?.trim();
if (src) {
if (src.startsWith("data:")) dataImages += 1;
else if (src.startsWith("cid:")) cidImages += 1;
else srcHosts.add(safeHostForUrl(src));
}
match = IMG_SRC_RE.exec(html);
}
ATTACHMENT_TAG_RE.lastIndex = 0;
let attachmentMatch: RegExpExecArray | null = ATTACHMENT_TAG_RE.exec(html);
while (attachmentMatch) {
attachmentTags += 1;
const id = attachmentMatch[1]?.trim();
if (id) attachmentIds.add(id);
attachmentMatch = ATTACHMENT_TAG_RE.exec(html);
}
}
if (htmlAttachments === 0) return undefined;
return {
htmlAttachments,
imgTags,
dataImages,
cidImages,
srcHosts: Array.from(srcHosts).slice(0, 5),
attachmentTags,
attachmentIds: Array.from(attachmentIds).slice(0, 5),
};
}
export function buildMSTeamsAttachmentPlaceholder(
attachments: MSTeamsAttachmentLike[] | undefined,
): string {
const list = Array.isArray(attachments) ? attachments : [];
if (list.length === 0) return "";
const imageCount = list.filter(isLikelyImageAttachment).length;
const inlineCount = extractInlineImageCandidates(list).length;
const totalImages = imageCount + inlineCount;
if (totalImages > 0) {
return `<media:image>${totalImages > 1 ? ` (${totalImages} images)` : ""}`;
}
const count = list.length;
return `<media:document>${count > 1 ? ` (${count} files)` : ""}`;
}