Skip to content

Commit 1de5fa8

Browse files
dwijbavisiCopilot
andcommitted
Custom Markdown Parser
Co-authored-by: Copilot <copilot@github.com>
1 parent b5c510a commit 1de5fa8

18 files changed

Lines changed: 2513 additions & 1820 deletions
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import React from "react";
2+
import type {
3+
BlockNode,
4+
HeadingNode,
5+
ParagraphNode,
6+
BlockquoteNode,
7+
ListNode,
8+
MathBlockNode,
9+
CodeBlockNode,
10+
} from "../types";
11+
import { RenderInline } from "./InlineNodes";
12+
13+
export function renderBlockNode(node: BlockNode, key: string | number): React.ReactNode {
14+
switch (node.type) {
15+
case "heading": {
16+
const n = node as HeadingNode;
17+
const inner = <RenderInline nodes={n.children} />;
18+
switch (n.level) {
19+
case 1: return <h1 key={key}>{inner}</h1>;
20+
case 2: return <h2 key={key}>{inner}</h2>;
21+
case 3: return <h3 key={key}>{inner}</h3>;
22+
case 4: return <h4 key={key}>{inner}</h4>;
23+
case 5: return <h5 key={key}>{inner}</h5>;
24+
case 6: return <h6 key={key}>{inner}</h6>;
25+
}
26+
break;
27+
}
28+
29+
case "paragraph":
30+
return (
31+
<p key={key}>
32+
<RenderInline nodes={(node as ParagraphNode).children} />
33+
</p>
34+
);
35+
36+
case "blockquote":
37+
return (
38+
<blockquote key={key}>
39+
{(node as BlockquoteNode).children.map((c, i) => renderBlockNode(c, i))}
40+
</blockquote>
41+
);
42+
43+
case "list": {
44+
const n = node as ListNode;
45+
const items = n.items.map((item, i) => (
46+
<li key={i}>
47+
<RenderInline nodes={item.children} />
48+
</li>
49+
));
50+
return n.ordered
51+
? <ol key={key}>{items}</ol>
52+
: <ul key={key}>{items}</ul>;
53+
}
54+
55+
case "hr":
56+
return <hr key={key} />;
57+
58+
case "math-block":
59+
return (
60+
<div key={key} className="math-block">
61+
{(node as MathBlockNode).source}
62+
</div>
63+
);
64+
65+
case "code-block": {
66+
const n = node as CodeBlockNode;
67+
return (
68+
<pre key={key}>
69+
<code className={n.lang ? `language-${n.lang}` : undefined}>{n.code}</code>
70+
</pre>
71+
);
72+
}
73+
74+
default: {
75+
const _: never = node;
76+
return null;
77+
}
78+
}
79+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import React from "react";
2+
import type {
3+
TextNode,
4+
BoldNode,
5+
ItalicNode,
6+
LinkNode,
7+
InlineCodeNode,
8+
MathInlineNode,
9+
SupNode,
10+
SubNode,
11+
BrNode,
12+
InlineNode,
13+
} from "../types";
14+
15+
export function renderInlineNode(node: InlineNode, key: string | number): React.ReactNode {
16+
switch (node.type) {
17+
case "text":
18+
return (node as TextNode).value;
19+
20+
case "bold":
21+
return (
22+
<strong key={key}>
23+
{(node as BoldNode).children.map((c, i) => renderInlineNode(c, i))}
24+
</strong>
25+
);
26+
27+
case "italic":
28+
return (
29+
<em key={key}>
30+
{(node as ItalicNode).children.map((c, i) => renderInlineNode(c, i))}
31+
</em>
32+
);
33+
34+
case "link": {
35+
const n = node as LinkNode;
36+
return (
37+
<a key={key} href={n.href}>
38+
{n.children.map((c, i) => renderInlineNode(c, i))}
39+
</a>
40+
);
41+
}
42+
43+
case "inline-code":
44+
return <code key={key}>{(node as InlineCodeNode).value}</code>;
45+
46+
case "math-inline":
47+
return (
48+
<span key={key} className="math-inline">
49+
{(node as MathInlineNode).source}
50+
</span>
51+
);
52+
53+
case "sup":
54+
return (
55+
<sup key={key}>
56+
{(node as SupNode).children.map((c, i) => renderInlineNode(c, i))}
57+
</sup>
58+
);
59+
60+
case "sub":
61+
return (
62+
<sub key={key}>
63+
{(node as SubNode).children.map((c, i) => renderInlineNode(c, i))}
64+
</sub>
65+
);
66+
67+
case "br":
68+
return <br key={key} />;
69+
70+
default: {
71+
const _: never = node;
72+
return null;
73+
}
74+
}
75+
}
76+
77+
export function RenderInline({ nodes }: { nodes: InlineNode[] }): JSX.Element {
78+
return <>{nodes.map((n, i) => renderInlineNode(n, i))}</>;
79+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import React from "react";
2+
import type { BlockNode } from "../types";
3+
import { renderBlockNode } from "./BlockNodes";
4+
5+
interface MarkdownRendererProps {
6+
nodes: BlockNode[];
7+
}
8+
9+
export function MarkdownRenderer({ nodes }: MarkdownRendererProps): JSX.Element {
10+
return <>{nodes.map((node, i) => renderBlockNode(node, i))}</>;
11+
}

site/modules/md/index.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
export type {
2+
BlockNode,
3+
InlineNode,
4+
HeadingNode,
5+
ParagraphNode,
6+
BlockquoteNode,
7+
ListNode,
8+
ListItem,
9+
HrNode,
10+
MathBlockNode,
11+
CodeBlockNode,
12+
TextNode,
13+
BoldNode,
14+
ItalicNode,
15+
LinkNode,
16+
InlineCodeNode,
17+
MathInlineNode,
18+
SupNode,
19+
SubNode,
20+
BrNode,
21+
ParsedMetadata,
22+
ParseResult,
23+
} from "./types";
24+
25+
export { parse, parseInline } from "./parser";

0 commit comments

Comments
 (0)