1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
|
import { fromMarkdown } from "mdast-util-from-markdown";
import { attribute } from "../lustre/lustre/attribute.mjs";
import { element, text } from "../lustre/lustre/element.mjs";
import { List } from "./gleam.mjs";
import * as Markdown from "./app/ui/markdown.mjs";
// Parsing markdown and then walking the AST is expensive so we're going to trade
// some memory for speed and cache the results.
const cache = new Map();
// fn parse_markdown(md: String) -> #(List(Element(msg)), List(Element(msg)))
export const parse_markdown = (md) => {
if (cache.has(md)) return cache.get(md);
const ast = fromMarkdown(md);
const summary = [];
const content = ast.children.map(function to_lustre_element(node) {
switch (node.type) {
case "code":
return Markdown.code(node.value);
case "emphasis":
return Markdown.emphasis(
List.fromArray(node.children.map(to_lustre_element))
);
case "heading": {
const [title, rest] = node.children[0].value.split("|");
const tags = List.fromArray(rest ? rest.trim().split(" ") : []);
const id =
/^[A-Z]/.test(title.trim()) && node.depth === 3
? `${title.toLowerCase().trim().replace(/\s/g, "-")}-type`
: `${title.toLowerCase().trim().replace(/\s/g, "-")}`;
if (node.depth > 1) {
summary.push(
element(
"a",
List.fromArray([
attribute("href", `#${id}`),
attribute("class", "text-sm text-gray-400 no-underline"),
attribute("class", "hover:text-gray-700 hover:underline"),
attribute(
"class",
node.depth === 2 ? `mt-4 first:mt-0` : `ml-2`
),
]),
List.fromArray([text(title.trim())])
)
);
}
return Markdown.heading(node.depth, title.trim(), tags, id);
}
case "inlineCode":
return Markdown.inline_code(node.value);
case "link":
return Markdown.link(node.url, List.fromArray(node.children));
case "list":
return Markdown.list(
!!node.ordered,
List.fromArray(node.children.map(to_lustre_element))
);
case "listItem":
return Markdown.list_item(
List.fromArray(node.children.map(to_lustre_element))
);
case "paragraph":
return Markdown.paragraph(
List.fromArray(node.children.map(to_lustre_element))
);
case "strong":
return Markdown.strong(
List.fromArray(node.children.map(to_lustre_element))
);
case "text":
return Markdown.text(node.value);
default:
return Markdown.text("");
}
});
const result = [List.fromArray(content), List.fromArray(summary)];
cache.set(md, result);
return result;
};
|