Skip to content

Commit cb44c26

Browse files
committed
Add ul/ol support
1 parent 3deeba3 commit cb44c26

File tree

2 files changed

+129
-38
lines changed

2 files changed

+129
-38
lines changed

ui/markdown/index.js

Lines changed: 66 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const {
99
P,
1010
Blockquote,
1111
Ul,
12+
Ol,
1213
Li,
1314
} = require("../..")
1415

@@ -20,54 +21,81 @@ function Markdown(params, children) {
2021
.map((line) => line.trim())
2122
.filter(Boolean)
2223

24+
const items = lines.map((line) => {
25+
if (line.startsWith("- ") || line.startsWith("— ")) {
26+
return { type: "li", list: "ul", content: line.substring(2) }
27+
} else if (/^\d+\.\s/.test(line)) {
28+
return { type: "li", list: "ol", content: line.replace(/^\d+\.\s/, "") }
29+
} else if (line.startsWith("# ")) {
30+
return { type: "h1", content: line.substring(2) }
31+
} else if (line.startsWith("## ")) {
32+
return { type: "h2", content: line.substring(3) }
33+
} else if (line.startsWith("### ")) {
34+
return { type: "h3", content: line.substring(4) }
35+
} else if (line.startsWith("#### ")) {
36+
return { type: "h4", content: line.substring(5) }
37+
} else if (line.startsWith("##### ")) {
38+
return { type: "h5", content: line.substring(6) }
39+
} else if (line.startsWith("###### ")) {
40+
return { type: "h6", content: line.substring(7) }
41+
} else if (line.startsWith("> ")) {
42+
return { type: "blockquote", content: line.substring(2) }
43+
} else {
44+
return { type: "p", content: line }
45+
}
46+
})
47+
2348
const nodes = []
24-
let list = null
49+
let i = 0
2550

26-
for (let i = 0; i < lines.length; i++) {
27-
const line = lines[i]
51+
while (i < items.length) {
52+
const item = items[i]
2853

29-
if (line.startsWith("- ") || line.startsWith("— ")) {
30-
if (!list) {
31-
list = []
54+
if (item.type === "li") {
55+
const list = []
56+
const parent = item.list
57+
58+
while (i < items.length && items[i].type === "li" && items[i].list === parent) {
59+
list.push(Li(params, items[i].content))
60+
i++
3261
}
3362

34-
list.push(Li(params, line.substring(2)))
35-
} else {
36-
if (list) {
63+
if (parent === "ul") {
3764
nodes.push(Ul(params, list))
38-
list = null
65+
} else if (parent === "ol") {
66+
nodes.push(Ol(params, list))
3967
}
68+
} else {
69+
const { type, content } = item
4070

41-
if (line.startsWith("# ")) {
42-
const text = line.substring(2)
43-
nodes.push(H1(params, text))
44-
} else if (line.startsWith("## ")) {
45-
const text = line.substring(3)
46-
nodes.push(H2(params, text))
47-
} else if (line.startsWith("### ")) {
48-
const text = line.substring(4)
49-
nodes.push(H3(params, text))
50-
} else if (line.startsWith("#### ")) {
51-
const text = line.substring(5)
52-
nodes.push(H4(params, text))
53-
} else if (line.startsWith("##### ")) {
54-
const text = line.substring(6)
55-
nodes.push(H5(params, text))
56-
} else if (line.startsWith("###### ")) {
57-
const text = line.substring(7)
58-
nodes.push(H6(params, text))
59-
} else if (line.startsWith("> ")) {
60-
const text = line.substring(2)
61-
nodes.push(Blockquote(params, text))
62-
} else {
63-
nodes.push(P(params, line))
71+
switch (type) {
72+
case "h1":
73+
nodes.push(H1(params, content))
74+
break
75+
case "h2":
76+
nodes.push(H2(params, content))
77+
break
78+
case "h3":
79+
nodes.push(H3(params, content))
80+
break
81+
case "h4":
82+
nodes.push(H4(params, content))
83+
break
84+
case "h5":
85+
nodes.push(H5(params, content))
86+
break
87+
case "h6":
88+
nodes.push(H6(params, content))
89+
break
90+
case "blockquote":
91+
nodes.push(Blockquote(params, content))
92+
break
93+
default:
94+
nodes.push(P(params, content))
6495
}
65-
}
66-
}
6796

68-
// Close any remaining list
69-
if (list) {
70-
nodes.push(Ul(params, list))
97+
i++
98+
}
7199
}
72100

73101
return nodes

ui/markdown/index.test.js

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,66 @@ test("handles both dash types in same list", async () => {
9898
assert(html.includes("<li>Regular again</li>"))
9999
assert(html.includes("</ul>"))
100100
})
101+
102+
test("renders ordered list", async () => {
103+
const { template } = await compile(__dirname)
104+
const markdown = `
105+
1. First item
106+
2. Second item
107+
3. Third item
108+
`
109+
const html = template(markdown)
110+
assert(html.includes("<ol>"))
111+
assert(html.includes("<li>First item</li>"))
112+
assert(html.includes("<li>Second item</li>"))
113+
assert(html.includes("<li>Third item</li>"))
114+
assert(html.includes("</ol>"))
115+
})
116+
117+
test("renders mixed unordered and ordered lists", async () => {
118+
const { template } = await compile(__dirname)
119+
const markdown = `
120+
# Shopping List
121+
122+
Buy these items:
123+
124+
- Apples
125+
- Bananas
126+
- Oranges
127+
128+
Follow these steps:
129+
130+
1. Go to store
131+
2. Buy items
132+
3. Return home
133+
`
134+
const html = template(markdown)
135+
assert(html.includes("<h1>Shopping List</h1>"))
136+
assert(html.includes("<p>Buy these items:</p>"))
137+
assert(html.includes("<ul>"))
138+
assert(html.includes("<li>Apples</li>"))
139+
assert(html.includes("</ul>"))
140+
assert(html.includes("<p>Follow these steps:</p>"))
141+
assert(html.includes("<ol>"))
142+
assert(html.includes("<li>Go to store</li>"))
143+
assert(html.includes("</ol>"))
144+
})
145+
146+
test("handles transition from ordered to unordered list", async () => {
147+
const { template } = await compile(__dirname)
148+
const markdown = `
149+
1. First ordered
150+
2. Second ordered
151+
- First unordered
152+
- Second unordered
153+
`
154+
const html = template(markdown)
155+
assert(html.includes("<ol>"))
156+
assert(html.includes("<li>First ordered</li>"))
157+
assert(html.includes("<li>Second ordered</li>"))
158+
assert(html.includes("</ol>"))
159+
assert(html.includes("<ul>"))
160+
assert(html.includes("<li>First unordered</li>"))
161+
assert(html.includes("<li>Second unordered</li>"))
162+
assert(html.includes("</ul>"))
163+
})

0 commit comments

Comments
 (0)