public
anord
read
Ledger
Why work hard when you can work easier?
Languages
Repository composition by tracked source files.
TypeScript
86%
CSS
10%
SQL
3%
Shell
1%
HTML
0%
Trace
apps/api/src/utils/markdown.ts
Trace helps you understand code history line by line. See who changed each line, when it changed, and which commit introduced it.
Author
Date
Commit
Line
Code
1
import matter from "gray-matter";
2
import { marked } from "marked";
3
import sanitizeHtml from "sanitize-html";
5
export interface RenderedMarkdown {
6
frontmatter: Record<string, unknown>;
7
bodyMarkdown: string;
8
bodyHtml: string;
9
toc: Array<{ id: string; text: string; level: number }>;
10
}
12
function headingId(text: string): string {
13
return text
14
.toLowerCase()
15
.replace(/[^a-z0-9]+/g, "-")
16
.replace(/(^-|-$)/g, "");
17
}
19
export function renderMarkdown(source: string): RenderedMarkdown {
20
const parsed = matter(source);
21
const headings: Array<{ id: string; text: string; level: number }> = [];
23
const lexer = marked.lexer(parsed.content);
24
for (const token of lexer) {
25
if (token.type === "heading") {
26
headings.push({
27
id: headingId(token.text),
28
text: token.text,
29
level: token.depth
30
});
31
}
32
}
34
const renderer = new marked.Renderer();
35
renderer.heading = ({ tokens, depth }) => {
36
const text = tokens.map((token) => ("text" in token ? token.text : "")).join("");
37
const id = headingId(text);
38
return `<h${depth} id="${id}">${text}</h${depth}>`;
39
};
41
const rawHtml = marked.parse(parsed.content, { renderer }) as string;
42
const safeHtml = sanitizeHtml(rawHtml, {
43
allowedTags: sanitizeHtml.defaults.allowedTags.concat([
44
"h1",
45
"h2",
46
"h3",
47
"h4",
48
"img",
49
"table",
50
"thead",
51
"tbody",
52
"tr",
53
"th",
54
"td"
55
]),
56
allowedAttributes: {
57
a: ["href", "name", "target", "rel"],
58
img: ["src", "alt", "title"],
59
"*": ["id"]
60
},
61
allowedSchemes: ["http", "https", "mailto"]
62
});
64
return {
65
frontmatter: parsed.data,
66
bodyMarkdown: parsed.content,
67
bodyHtml: safeHtml,
68
toc: headings
69
};
70
}