1import type { PullRequestBodySegment } from "@t3tools/client-runtime/pull-request-markdown";
2import type { MarkdownNode } from "../../lib/markdownDocument";
3
4/** Read media from the parsed document so code examples never become attachments. */
5export function pullRequestDescriptionContent(
6 document: MarkdownNode,
7 media: readonly PullRequestBodySegment[] = [],
8) {
9 const attachments = new Map<
10 string,
11 { readonly uri: string; readonly caption: string; readonly kind: "image" | "video" | "unknown" }
12 >();
13 const text: string[] = [];
14 const visit = (node: MarkdownNode) => {
15 if (node.type === "image") {
16 if (node.url && /^https?:\/\//i.test(node.url) && !attachments.has(node.url)) {
17 attachments.set(node.url, {
18 uri: node.url,
19 caption: node.alt || node.title || "Image",
20 kind: "image",
21 });
22 }
23 return;
24 }
25 if (node.type === "html") return;
26 if ("value" in node) text.push(node.value);
27 if ("children" in node) node.children.forEach(visit);
28 if (["paragraph", "heading", "listItem", "code"].includes(node.type)) text.push("\n");
29 if (node.type === "break") text.push(" ");
30 };
31 visit(document);
32 for (const segment of media) {
33 if (segment.kind === "attachment" && !attachments.has(segment.url)) {
34 const name = new URL(segment.url).pathname.split("/").pop();
35 attachments.set(segment.url, {
36 uri: segment.url,
37 caption: segment.media === "video" ? "Video" : name || "Image",
38 kind: segment.media,
39 });
40 }
41 }
42 return { preview: text.join("").trim(), attachments: [...attachments.values()] };
43}