1function labelledRedaction(contents: string) {
2 return (
3 `<span class="dead">`
4 + (contents === "name"
5 ? "old name"
6 : contents === "username"
7 ? "old username"
8 : contents === "domain"
9 ? "old domain"
10 : null)
11 + `</span>`
12 );
13}
14
15function questionRef(id: string) {
16 if (id.length === 12) id = id.slice(0, 10);
17 const timestamp = questionIdToTimestamp(id);
18 if (!timestamp) {
19 console.error(`Invalid question ref: ${id}`);
20 return `<span class="question-ref">[Invalid Question Ref: #${string.escapeHtmlContent(id)}]</span>`;
21 }
22 return `<a class="custom question-ref" href="/q+a/${id}">${formatQuestionTimestamp(timestamp)}</a>`;
23}
24
25function artifactRef(id: string) {
26 const artifact = artifactMap[id];
27 if (!artifact) {
28 return `<span class="artifact">[Invalid Artifact Ref: @${string.escapeHtmlContent(id)}]</span>`;
29 }
30 const [title, url, type] = artifact;
31 if (!url) {
32 return `<span>${string.escapeHtmlContent(title)}</span>`;
33 }
34 return `<a class="custom artifact artifact-${type}" href="${url}">`
35 + string.escapeHtmlContent(title)
36 + `</a>`;
37}
38
39/** classic esbuild trick: use an impossible to guess key for string magic */
40const uniqueKey = crypto.randomUUID().replaceAll("-", "");
41
42const renderers = {
43 A: artifactRef,
44 Q: questionRef,
45 R: labelledRedaction,
46} as const;
47
48export function renderMarkdown(source: string) {
49 const tagNames: markodown.CloverQuestionExtensions = {
50 question: "q-",
51 artifactRef: uniqueKey + "_A",
52 questionRef: uniqueKey + "_Q",
53 labelledRedaction: uniqueKey + "_R",
54 };
55 const result = markodown.transform({
56 source,
57 markdownOnly: true,
58 cloverExtensions: tagNames,
59 });
60 if (!result.success) {
61 throw new Error(JSON.stringify(result.errors));
62 }
63 return result.text
64 .replace(
65 new RegExp(`<${uniqueKey}_([AQR])>([^<]*)<\\/${uniqueKey}_[AQR]>`, "g"),
66 (_, type: "A" | "Q" | "R", content: string) => {
67 return renderers[type](content);
68 },
69 );
70}
71
72import * as string from "@clo/lib/string";
73import * as markodown from "@clo/markodown";
74import { artifactMap } from "./artifacts.ts";
75import { formatQuestionTimestamp, questionIdToTimestamp } from "./format.ts";