apps/web/src/lib/agendaEmail.ts

1/** Convert the server-built agenda's small Markdown subset to email-safe HTML. */
2const escapeHtml = (text: string) =>
3	text.replace(
4		/[&<>"']/g,
5		(char) =>
6			({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' })[
7				char
8			] || char,
9	)
10
11export function agendaEmailHtml(markdown: string): string {
12	const inline = (line: string) => {
13		let html = '',
14			end = 0
15		for (const match of line.matchAll(/\[([^\]]+)\]\(([^)]+)\)/g)) {
16			html += escapeHtml(line.slice(end, match.index))
17			let url: URL | undefined
18			try {
19				url = new URL(match[2], 'https://www.unleash.ai')
20			} catch {
21				/* Invalid links remain plain text. */
22			}
23			html +=
24				url && (url.protocol === 'https:' || url.protocol === 'http:')
25					? `<a href="${escapeHtml(url.href)}">${escapeHtml(match[1])}</a>`
26					: escapeHtml(match[1])
27			end = match.index + match[0].length
28		}
29		return html + escapeHtml(line.slice(end))
30	}
31	return markdown
32		.split(/\n+/)
33		.filter((line) => line.trim())
34		.map((line) => `<p>${inline(line.replace(/^[-*] /, ''))}</p>`)
35		.join('\n')
36}
37